Linux and Android share the kernel, but not the C library, so sysconf constants are different. For example, _SC_PAGESIZE is 30 on Linux, but 39 on Android.
This patch
* splits sysconf constants to sysconf module
* merges non-MIPS and MIPS sysconf constants (they are same)
* adds Android sysconf constants
This patch also lets mmap tests to pass on Android.
make_dir $h/test/doc-tutorial-ffi
make_dir $h/test/doc-tutorial-macros
make_dir $h/test/doc-tutorial-borrowed-ptr
+ make_dir $h/test/doc-tutorial-container
make_dir $h/test/doc-tutorial-tasks
+ make_dir $h/test/doc-tutorial-conditions
make_dir $h/test/doc-rust
done
--- /dev/null
+# Japanese translations for Rust package
+# Copyright (C) 2013 The Rust Project Developers
+# This file is distributed under the same license as the Rust package.
+# Automatically generated, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Rust 0.8-pre\n"
+"POT-Creation-Date: 2013-08-12 02:06+0900\n"
+"PO-Revision-Date: 2013-08-05 19:40+0900\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: none\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#. type: Plain text
+#: doc/rust.md:2
+msgid "% Rust Reference Manual"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
+#: doc/tutorial-borrowed-ptr.md:4 doc/tutorial-ffi.md:4
+#: doc/tutorial-macros.md:4 doc/tutorial-tasks.md:4
+msgid "# Introduction"
+msgstr "# イントロダクション"
+
+#. type: Plain text
+#: doc/rust.md:7
+msgid ""
+"This document is the reference manual for the Rust programming language. It "
+"provides three kinds of material:"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:15
+msgid ""
+"Chapters that formally define the language grammar and, for each construct, "
+"informally describe its semantics and give examples of its use."
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:15
+msgid ""
+"Chapters that informally describe the memory model, concurrency model, "
+"runtime services, linkage model and debugging facilities."
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:15
+msgid ""
+"Appendix chapters providing rationale and references to languages that "
+"influenced the design."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:19
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:24
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:28
+msgid ""
+"[tutorial]: tutorial.html [standard]: std/index.html [extra]: extra/index."
+"html"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:30 doc/rustpkg.md:8
+msgid "## Disclaimer"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:34
+msgid ""
+"Rust is a work in progress. The language continues to evolve as the design "
+"shifts and is fleshed out in working code. Certain parts work, certain parts "
+"do not, certain parts will be removed or changed."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:39
+msgid ""
+"This manual is a snapshot written in the present tense. All features "
+"described exist in working code unless otherwise noted, but some are quite "
+"primitive or remain to be further modified by planned work. Some may be "
+"temporary. It is a *draft*, and we ask that you not take anything you read "
+"here as final."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:43
+msgid ""
+"If you have suggestions to make, please try to focus them on *reductions* to "
+"the language: possible features that can be combined or omitted. We aim to "
+"keep the size and complexity of the language under control."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:52
+msgid ""
+"> **Note:** The grammar for Rust given in this document is rough and > very "
+"incomplete; only a modest number of sections have accompanying grammar > "
+"rules. Formalizing the grammar accepted by the Rust parser is ongoing work, "
+"> but future versions of this document will contain a complete > grammar. "
+"Moreover, we hope that this grammar will be extracted and verified > as "
+"LL(1) by an automated grammar-analysis tool, and further tested against the "
+"> Rust sources. Preliminary versions of this automation exist, but are not "
+"yet > complete."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:54
+msgid "# Notation"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:62
+msgid ""
+"Rust's grammar is defined over Unicode codepoints, each conventionally "
+"denoted `U+XXXX`, for 4 or more hexadecimal digits `X`. _Most_ of Rust's "
+"grammar is confined to the ASCII range of Unicode, and is described in this "
+"document by a dialect of Extended Backus-Naur Form (EBNF), specifically a "
+"dialect of EBNF supported by common automated LL(k) parsing tools such as "
+"`llgen`, rather than the dialect given in ISO 14977. The dialect can be "
+"defined self-referentially as follows:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:64
+msgid "~~~~~~~~ {.ebnf .notation}"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:72
+#, no-wrap
+msgid ""
+"grammar : rule + ;\n"
+"rule : nonterminal ':' productionrule ';' ;\n"
+"productionrule : production [ '|' production ] * ;\n"
+"production : term * ;\n"
+"term : element repeats ;\n"
+"element : LITERAL | IDENTIFIER | '[' productionrule ']' ;\n"
+"repeats : [ '*' | '+' ] NUMBER ? | NUMBER ? | '?' ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:74 doc/rust.md:416 doc/rust.md:486
+msgid "~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:76
+msgid "Where:"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:89
+msgid "Whitespace in the grammar is ignored."
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:89
+msgid "Square brackets are used to group rules."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:89
+#, no-wrap
+msgid ""
+" - `LITERAL` is a single printable ASCII character, or an escaped hexadecimal\n"
+" ASCII code of the form `\\xQQ`, in single quotes, denoting the corresponding\n"
+" Unicode codepoint `U+00QQ`.\n"
+" - `IDENTIFIER` is a nonempty string of ASCII letters and underscores.\n"
+" - The `repeat` forms apply to the adjacent `element`, and are as follows:\n"
+" - `?` means zero or one repetition\n"
+" - `*` means zero or more repetitions\n"
+" - `+` means one or more repetitions\n"
+" - NUMBER trailing a repeat symbol gives a maximum repetition count\n"
+" - NUMBER on its own gives an exact repetition count\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:91
+msgid "This EBNF dialect should hopefully be familiar to many readers."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:93
+msgid "## Unicode productions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:98
+msgid ""
+"A few productions in Rust's grammar permit Unicode codepoints outside the "
+"ASCII range. We define these productions in terms of character properties "
+"specified in the Unicode standard, rather than in terms of ASCII-range "
+"codepoints. The section [Special Unicode Productions](#special-unicode-"
+"productions) lists these productions."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:100
+msgid "## String table productions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:109
+msgid ""
+"Some rules in the grammar -- notably [unary operators](#unary-operator-"
+"expressions), [binary operators](#binary-operator-expressions), and "
+"[keywords](#keywords) -- are given in a simplified form: as a listing of a "
+"table of unquoted, printable whitespace-separated strings. These cases form "
+"a subset of the rules regarding the [token](#tokens) rule, and are assumed "
+"to be the result of a lexical-analysis phase feeding the parser, driven by a "
+"DFA, operating over the disjunction of all such string table entries."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:113
+msgid ""
+"When such a string enclosed in double-quotes (`\"`) occurs inside the "
+"grammar, it is an implicit reference to a single member of such a string "
+"table production. See [tokens](#tokens) for more information."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:116
+msgid "# Lexical structure"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:118
+msgid "## Input format"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:124
+msgid ""
+"Rust input is interpreted as a sequence of Unicode codepoints encoded in "
+"UTF-8, normalized to Unicode normalization form NFKC. Most Rust grammar "
+"rules are defined in terms of printable ASCII-range codepoints, but a small "
+"number are defined in terms of Unicode properties or explicit codepoint "
+"lists. ^[Substitute definitions for the special Unicode productions are "
+"provided to the grammar verifier, restricted to ASCII range, when verifying "
+"the grammar in this document.]"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:126
+msgid "## Special Unicode Productions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:129
+msgid ""
+"The following productions in the Rust grammar are defined in terms of "
+"Unicode properties: `ident`, `non_null`, `non_star`, `non_eol`, "
+"`non_slash_or_star`, `non_single_quote` and `non_double_quote`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:131
+msgid "### Identifiers"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:133
+msgid ""
+"The `ident` production is any nonempty Unicode string of the following form:"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:136
+msgid "The first character has property `XID_start`"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:136
+msgid "The remaining characters have property `XID_continue`"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:138
+msgid "that does _not_ occur in the set of [keywords](#keywords)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:142
+msgid ""
+"Note: `XID_start` and `XID_continue` as character properties cover the "
+"character ranges used to form the more familiar C and Java language-family "
+"identifiers."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:144
+msgid "### Delimiter-restricted productions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:146
+msgid ""
+"Some productions are defined by exclusion of particular Unicode characters:"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:153
+msgid "`non_null` is any single Unicode character aside from `U+0000` (null)"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:153
+msgid "`non_eol` is `non_null` restricted to exclude `U+000A` (`'\\n'`)"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:153
+msgid "`non_star` is `non_null` restricted to exclude `U+002A` (`*`)"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:153
+msgid ""
+"`non_slash_or_star` is `non_null` restricted to exclude `U+002F` (`/`) and `U"
+"+002A` (`*`)"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:153
+msgid "`non_single_quote` is `non_null` restricted to exclude `U+0027` (`'`)"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:153
+msgid "`non_double_quote` is `non_null` restricted to exclude `U+0022` (`\"`)"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:155
+msgid "## Comments"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:162
+msgid ""
+"~~~~~~~~ {.ebnf .gram} comment : block_comment | line_comment ; "
+"block_comment : \"/*\" block_comment_body * '*' + '/' ; block_comment_body : "
+"non_star * | '*' + non_slash_or_star ; line_comment : \"//\" non_eol * ; "
+"~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:165
+msgid ""
+"Comments in Rust code follow the general C++ style of line and block-comment "
+"forms, with no nesting of block-comment delimiters."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:170
+msgid ""
+"Line comments beginning with _three_ slashes (`///`), and block comments "
+"beginning with a repeated asterisk in the block-open sequence (`/**`), are "
+"interpreted as a special syntax for `doc` [attributes](#attributes). That "
+"is, they are equivalent to writing `#[doc \"...\"]` around the comment's "
+"text."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:172
+msgid "Non-doc comments are interpreted as a form of whitespace."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:174
+msgid "## Whitespace"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:179
+msgid ""
+"~~~~~~~~ {.ebnf .gram} whitespace_char : '\\x20' | '\\x09' | '\\x0a' | "
+"'\\x0d' ; whitespace : [ whitespace_char | comment ] + ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:183
+msgid ""
+"The `whitespace_char` production is any nonempty Unicode string consisting "
+"of any of the following Unicode characters: `U+0020` (space, `' '`), `U"
+"+0009` (tab, `'\\t'`), `U+000A` (LF, `'\\n'`), `U+000D` (CR, `'\\r'`)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:186
+msgid ""
+"Rust is a \"free-form\" language, meaning that all forms of whitespace serve "
+"only to separate _tokens_ in the grammar, and have no semantic significance."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:189
+msgid ""
+"A Rust program has identical meaning if each whitespace element is replaced "
+"with any other legal whitespace element, such as a single space character."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:191
+msgid "## Tokens"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:196
+msgid ""
+"~~~~~~~~ {.ebnf .gram} simple_token : keyword | unop | binop ; token : "
+"simple_token | ident | literal | symbol | whitespace token ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:201
+msgid ""
+"Tokens are primitive productions in the grammar defined by regular (non-"
+"recursive) languages. \"Simple\" tokens are given in [string table "
+"production](#string-table-productions) form, and occur in the rest of the "
+"grammar as double-quoted strings. Other tokens have exact rules given."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:203
+msgid "### Keywords"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:205
+msgid "The keywords are the following strings:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:222
+msgid ""
+"~~~~~~~~ {.keyword} as break do else enum extern false fn for if impl let "
+"loop match mod mut priv pub ref return self static struct super true trait "
+"type unsafe use while ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:225
+msgid ""
+"Each of these keywords has special meaning in its grammar, and all of them "
+"are excluded from the `ident` rule."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:227
+msgid "### Literals"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:233
+msgid ""
+"A literal is an expression consisting of a single token, rather than a "
+"sequence of tokens, that immediately and directly denotes the value it "
+"evaluates to, rather than referring to it by name or some other evaluation "
+"rule. A literal is a form of constant expression, so is evaluated "
+"(primarily) at compile time."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:237
+msgid ""
+"~~~~~~~~ {.ebnf .gram} literal : string_lit | char_lit | num_lit ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:239
+msgid "#### Character and string literals"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:243
+msgid ""
+"~~~~~~~~ {.ebnf .gram} char_lit : '\\x27' char_body '\\x27' ; string_lit : "
+"'\"' string_body * '\"' ;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:246
+#, no-wrap
+msgid ""
+"char_body : non_single_quote\n"
+" | '\\x5c' [ '\\x27' | common_escape ] ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:249
+#, no-wrap
+msgid ""
+"string_body : non_double_quote\n"
+" | '\\x5c' [ '\\x22' | common_escape ] ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:255
+#, no-wrap
+msgid ""
+"common_escape : '\\x5c'\n"
+" | 'n' | 'r' | 't'\n"
+" | 'x' hex_digit 2\n"
+" | 'u' hex_digit 4\n"
+" | 'U' hex_digit 8 ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:263
+#, no-wrap
+msgid ""
+"hex_digit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f'\n"
+" | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'\n"
+" | dec_digit ;\n"
+"dec_digit : '0' | nonzero_dec ;\n"
+"nonzero_dec: '1' | '2' | '3' | '4'\n"
+" | '5' | '6' | '7' | '8' | '9' ;\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:267
+msgid ""
+"A _character literal_ is a single Unicode character enclosed within two `U"
+"+0027` (single-quote) characters, with the exception of `U+0027` itself, "
+"which must be _escaped_ by a preceding U+005C character (`\\`)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:271
+msgid ""
+"A _string literal_ is a sequence of any Unicode characters enclosed within "
+"two `U+0022` (double-quote) characters, with the exception of `U+0022` "
+"itself, which must be _escaped_ by a preceding `U+005C` character (`\\`)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:275
+msgid ""
+"Some additional _escapes_ are available in either character or string "
+"literals. An escape starts with a `U+005C` (`\\`) and continues with one of "
+"the following forms:"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:290
+msgid ""
+"An _8-bit codepoint escape_ escape starts with `U+0078` (`x`) and is "
+"followed by exactly two _hex digits_. It denotes the Unicode codepoint equal "
+"to the provided hex value."
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:290
+msgid ""
+"A _16-bit codepoint escape_ starts with `U+0075` (`u`) and is followed by "
+"exactly four _hex digits_. It denotes the Unicode codepoint equal to the "
+"provided hex value."
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:290
+msgid ""
+"A _32-bit codepoint escape_ starts with `U+0055` (`U`) and is followed by "
+"exactly eight _hex digits_. It denotes the Unicode codepoint equal to the "
+"provided hex value."
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:290
+msgid ""
+"A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072` "
+"(`r`), or `U+0074` (`t`), denoting the unicode values `U+000A` (LF), `U"
+"+000D` (CR) or `U+0009` (HT) respectively."
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:290
+msgid ""
+"The _backslash escape_ is the character U+005C (`\\`) which must be escaped "
+"in order to denote *itself*."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:292
+msgid "#### Number literals"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:294 doc/rust.md:406 doc/rust.md:473
+msgid "~~~~~~~~ {.ebnf .gram}"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:299
+#, no-wrap
+msgid ""
+"num_lit : nonzero_dec [ dec_digit | '_' ] * num_suffix ?\n"
+" | '0' [ [ dec_digit | '_' ] + num_suffix ?\n"
+" | 'b' [ '1' | '0' | '_' ] + int_suffix ?\n"
+" | 'x' [ hex_digit | '_' ] + int_suffix ? ] ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:301
+msgid "num_suffix : int_suffix | float_suffix ;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:305
+#, no-wrap
+msgid ""
+"int_suffix : 'u' int_suffix_size ?\n"
+" | 'i' int_suffix_size ? ;\n"
+"int_suffix_size : [ '8' | '1' '6' | '3' '2' | '6' '4' ] ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:311
+msgid ""
+"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 | '_' ] + ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:315
+msgid ""
+"A _number literal_ is either an _integer literal_ or a _floating-point "
+"literal_. The grammar for recognizing the two kinds of literals is mixed, as "
+"they are differentiated by suffixes."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:317
+msgid "##### Integer literals"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:319
+msgid "An _integer literal_ has one of three forms:"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:326
+msgid ""
+"A _decimal literal_ starts with a *decimal digit* and continues with any "
+"mixture of *decimal digits* and _underscores_."
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:326
+msgid ""
+"A _hex literal_ starts with the character sequence `U+0030` `U+0078` (`0x`) "
+"and continues as any mixture hex digits and underscores."
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:326
+msgid ""
+"A _binary literal_ starts with the character sequence `U+0030` `U+0062` "
+"(`0b`) and continues as any mixture binary digits and underscores."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:330
+msgid ""
+"An integer literal may be followed (immediately, without any spaces) by an "
+"_integer suffix_, which changes the type of the literal. There are two kinds "
+"of integer literal suffix:"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:336
+msgid ""
+"The `i` and `u` suffixes give the literal type `int` or `uint`, respectively."
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:336
+msgid ""
+"Each of the signed and unsigned machine types `u8`, `i8`, `u16`, `i16`, "
+"`u32`, `i32`, `u64` and `i64` give the literal the corresponding machine "
+"type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:343
+msgid ""
+"The type of an _unsuffixed_ integer literal is determined by type "
+"inference. If a integer type can be _uniquely_ determined from the "
+"surrounding program context, the unsuffixed integer literal has that type. "
+"If the program context underconstrains the type, the unsuffixed integer "
+"literal's type is `int`; if the program context overconstrains the type, it "
+"is considered a static type error."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:345
+msgid "Examples of integer literals of various forms:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:350
+#, no-wrap
+msgid ""
+"~~~~\n"
+"123; 0xff00; // type determined by program context\n"
+" // defaults to int in absence of type\n"
+" // information\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:356
+#, no-wrap
+msgid ""
+"123u; // type uint\n"
+"123_u; // type uint\n"
+"0xff_u8; // type u8\n"
+"0b1111_1111_1001_0000_i32; // type i32\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:358
+msgid "##### Floating-point literals"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:360
+msgid "A _floating-point literal_ has one of two forms:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:365
+msgid ""
+"Two _decimal literals_ separated by a period character `U+002E` (`.`), with "
+"an optional _exponent_ trailing after the second decimal literal."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:365
+msgid "A single _decimal literal_ followed by an _exponent_."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:372
+msgid ""
+"By default, a floating-point literal is of type `float`. A floating-point "
+"literal may be followed (immediately, without any spaces) by a _floating-"
+"point suffix_, which changes the type of the literal. There are three "
+"floating-point suffixes: `f` (for the base `float` type), `f32`, and `f64` "
+"(the 32-bit and 64-bit floating point types)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:374
+msgid "Examples of floating-point literals of various forms:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:382
+#, no-wrap
+msgid ""
+"~~~~\n"
+"123.0; // type float\n"
+"0.1; // type float\n"
+"3f; // type float\n"
+"0.1f32; // type f32\n"
+"12E+99_f64; // type f64\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:384
+msgid "##### Unit and boolean literals"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:387
+msgid ""
+"The _unit value_, the only value of the type that has the same name, is "
+"written as `()`. The two values of the boolean type are written `true` and "
+"`false`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:389
+msgid "### Symbols"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:395
+#, no-wrap
+msgid ""
+"~~~~~~~~ {.ebnf .gram}\n"
+"symbol : \"::\" \"->\"\n"
+" | '#' | '[' | ']' | '(' | ')' | '{' | '}'\n"
+" | ',' | ';' ;\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:401
+msgid ""
+"Symbols are a general class of printable [token](#tokens) that play "
+"structural roles in a variety of grammar productions. They are catalogued "
+"here for completeness as the set of remaining miscellaneous printable tokens "
+"that do not otherwise appear as [unary operators](#unary-operator-"
+"expressions), [binary operators](#binary-operator-expressions), or [keywords]"
+"(#keywords)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:404
+msgid "## Paths"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:410
+#, no-wrap
+msgid ""
+"expr_path : ident [ \"::\" expr_path_tail ] + ;\n"
+"expr_path_tail : '<' type_expr [ ',' type_expr ] + '>'\n"
+" | expr_path ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:414
+#, no-wrap
+msgid ""
+"type_path : ident [ type_path_tail ] + ;\n"
+"type_path_tail : '<' type_expr [ ',' type_expr ] + '>'\n"
+" | \"::\" type_path ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:421
+msgid ""
+"A _path_ is a sequence of one or more path components _logically_ separated "
+"by a namespace qualifier (`::`). If a path consists of only one component, "
+"it may refer to either an [item](#items) or a [slot](#memory-slots) in a "
+"local control scope. If a path has multiple components, it refers to an item."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:425
+msgid ""
+"Every item has a _canonical path_ within its crate, but the path naming an "
+"item is only meaningful within a given crate. There is no global namespace "
+"across crates; an item's canonical path merely identifies it within the "
+"crate."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:427
+msgid "Two examples of simple paths consisting of only identifier components:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:432
+msgid "~~~~{.ignore} x; x::y::z; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:439
+msgid ""
+"Path components are usually [identifiers](#identifiers), but the trailing "
+"component of a path may be an angle-bracket-enclosed list of type arguments. "
+"In [expression](#expressions) context, the type argument list is given after "
+"a final (`::`) namespace qualifier in order to disambiguate it from a "
+"relational expression involving the less-than symbol (`<`). In type "
+"expression context, the final namespace qualifier is omitted."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:441
+msgid "Two examples of paths with type arguments:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:450
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# use std::hashmap::HashMap;\n"
+"# fn f() {\n"
+"# fn id<T>(t: T) -> T { t }\n"
+"type t = HashMap<int,~str>; // Type arguments used in a type expression\n"
+"let x = id::<int>(10); // Type arguments used in a call expression\n"
+"# }\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:452
+msgid "# Syntax extensions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:457
+msgid ""
+"A number of minor features of Rust are not central enough to have their own "
+"syntax, and yet are not implementable as functions. Instead, they are given "
+"names, and invoked through a consistent syntax: `name!(...)`. Examples "
+"include:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:466
+msgid "`fmt!` : format data into a string"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:466
+msgid "`env!` : look up an environment variable's value at compile time"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:466
+msgid "`stringify!` : pretty-print the Rust expression given as an argument"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:466
+msgid "`proto!` : define a protocol for inter-task communication"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:466
+msgid "`include!` : include the Rust expression in the given file"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:466
+msgid "`include_str!` : include the contents of the given file as a string"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:466
+msgid ""
+"`include_bin!` : include the contents of the given file as a binary blob"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:466
+msgid "`error!`, `warn!`, `info!`, `debug!` : provide diagnostic information."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:469
+msgid ""
+"All of the above extensions, with the exception of `proto!`, are expressions "
+"with values. `proto!` is an item, defining a new name."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:471
+msgid "## Macros"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:484
+#, no-wrap
+msgid ""
+"expr_macro_rules : \"macro_rules\" '!' ident '(' macro_rule * ')'\n"
+"macro_rule : '(' matcher * ')' \"=>\" '(' transcriber * ')' ';'\n"
+"matcher : '(' matcher * ')' | '[' matcher * ']'\n"
+" | '{' matcher * '}' | '$' ident ':' ident\n"
+" | '$' '(' matcher * ')' sep_token? [ '*' | '+' ]\n"
+" | non_special_token\n"
+"transcriber : '(' transcriber * ')' | '[' transcriber * ']'\n"
+" | '{' transcriber * '}' | '$' ident\n"
+" | '$' '(' transcriber * ')' sep_token? [ '*' | '+' ]\n"
+" | non_special_token\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:490
+msgid ""
+"User-defined syntax extensions are called \"macros\", and the `macro_rules` "
+"syntax extension defines them. Currently, user-defined macros can expand to "
+"expressions, statements, or items."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:493
+msgid ""
+"(A `sep_token` is any token other than `*` and `+`. A `non_special_token` "
+"is any token other than a delimiter or `$`.)"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:499
+msgid ""
+"The macro expander looks up macro invocations by name, and tries each macro "
+"rule in turn. It transcribes the first successful match. Matching and "
+"transcription are closely related to each other, and we will describe them "
+"together."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:501
+msgid "### Macro By Example"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:504
+msgid ""
+"The macro expander matches and transcribes every token that does not begin "
+"with a `$` literally, including delimiters. For parsing reasons, delimiters "
+"must be balanced, but they are otherwise not special."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:510
+msgid ""
+"In the matcher, `$` _name_ `:` _designator_ matches the nonterminal in the "
+"Rust syntax named by _designator_. Valid designators are `item`, `block`, "
+"`stmt`, `pat`, `expr`, `ty` (type), `ident`, `path`, `matchers` (lhs of the "
+"`=>` in macro rules), `tt` (rhs of the `=>` in macro rules). In the "
+"transcriber, the designator is already known, and so only the name of a "
+"matched nonterminal comes after the dollar sign."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:519
+msgid ""
+"In both the matcher and transcriber, the Kleene star-like operator indicates "
+"repetition. The Kleene star operator consists of `$` and parens, optionally "
+"followed by a separator token, followed by `*` or `+`. `*` means zero or "
+"more repetitions, `+` means at least one repetition. The parens are not "
+"matched or transcribed. On the matcher side, a name is bound to _all_ of "
+"the names it matches, in a structure that mimics the structure of the "
+"repetition encountered on a successful match. The job of the transcriber is "
+"to sort that structure out."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:525
+msgid ""
+"The rules for transcription of these repetitions are called \"Macro By "
+"Example\". Essentially, one \"layer\" of repetition is discharged at a "
+"time, and all of them must be discharged by the time a name is transcribed. "
+"Therefore, `( $( $i:ident ),* ) => ( $i )` is an invalid macro, but `( $( $i:"
+"ident ),* ) => ( $( $i:ident ),* )` is acceptable (if trivial)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:533
+msgid ""
+"When Macro By Example encounters a repetition, it examines all of the `$` "
+"_name_ s that occur in its body. At the \"current layer\", they all must "
+"repeat the same number of times, so ` ( $( $i:ident ),* ; $( $j:ident ),* ) "
+"=> ( $( ($i,$j) ),* )` is valid if given the argument `(a,b,c ; d,e,f)`, but "
+"not `(a,b,c ; d,e)`. The repetition walks through the choices at that layer "
+"in lockstep, so the former input transcribes to `( (a,d), (b,e), (c,f) )`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:535
+msgid "Nested repetitions are allowed."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:537
+msgid "### Parsing limitations"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:540
+msgid ""
+"The parser used by the macro system is reasonably powerful, but the parsing "
+"of Rust syntax is restricted in two ways:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:546
+#, no-wrap
+msgid ""
+"1. The parser will always parse as much as possible. If it attempts to match\n"
+"`$i:expr [ , ]` against `8 [ , ]`, it will attempt to parse `i` as an array\n"
+"index operation and fail. Adding a separator can solve this problem.\n"
+"2. The parser must have eliminated all ambiguity by the time it reaches a `$` _name_ `:` _designator_.\n"
+"This requirement most often affects name-designator pairs when they occur at the beginning of, or immediately after, a `$(...)*`; requiring a distinctive token in front can solve the problem.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:549
+msgid "## Syntax extensions useful for the macro author"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:554
+msgid "`log_syntax!` : print out the arguments at compile time"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:554
+msgid ""
+"`trace_macros!` : supply `true` or `false` to enable or disable macro "
+"expansion logging"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:554
+msgid "`stringify!` : turn the identifier argument into a string literal"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:554
+msgid ""
+"`concat_idents!` : create a new identifier by concatenating the arguments"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:556
+msgid "# Crates and source files"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:563
+msgid ""
+"Rust is a *compiled* language. Its semantics obey a *phase distinction* "
+"between compile-time and run-time. Those semantic rules that have a *static "
+"interpretation* govern the success or failure of compilation. We refer to "
+"these rules as \"static semantics\". Semantic rules called \"dynamic "
+"semantics\" govern the behavior of programs at run-time. A program that "
+"fails to compile due to violation of a compile-time rule has no defined "
+"dynamic semantics; the compiler should halt with an error report, and "
+"produce no executable artifact."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:569
+msgid ""
+"The compilation model centres on artifacts called _crates_. Each "
+"compilation processes a single crate in source form, and if successful, "
+"produces a single crate in binary form: either an executable or a library."
+"^[A crate is somewhat analogous to an *assembly* in the ECMA-335 CLI model, "
+"a *library* in the SML/NJ Compilation Manager, a *unit* in the Owens and "
+"Flatt module system, or a *configuration* in Mesa.]"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:573
+msgid ""
+"A _crate_ is a unit of compilation and linking, as well as versioning, "
+"distribution and runtime loading. A crate contains a _tree_ of nested "
+"[module](#modules) scopes. The top level of this tree is a module that is "
+"anonymous (from the point of view of paths within the module) and any item "
+"within a crate has a canonical [module path](#paths) denoting its location "
+"within the crate's module tree."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:577
+msgid ""
+"The Rust compiler is always invoked with a single source file as input, and "
+"always produces a single output crate. The processing of that source file "
+"may result in other source files being loaded as modules. Source files have "
+"the extension `.rs`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:582
+msgid ""
+"A Rust source file describes a module, the name and location of which -- in "
+"the module tree of the current crate -- are defined from outside the source "
+"file: either by an explicit `mod_item` in a referencing source file, or by "
+"the name of the crate itself."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:587
+msgid ""
+"Each source file contains a sequence of zero or more `item` definitions, and "
+"may optionally begin with any number of `attributes` that apply to the "
+"containing module. Atributes on the anonymous crate module define important "
+"metadata that influences the behavior of the compiler."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:593
+#, no-wrap
+msgid ""
+"~~~~~~~~\n"
+"// Linkage attributes\n"
+"#[ link(name = \"projx\",\n"
+" vers = \"2.5\",\n"
+" uuid = \"9cccc5d5-aceb-4af5-8285-811211826b82\") ];\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:598
+msgid ""
+"// Additional metadata attributes #[ desc = \"Project X\" ]; #[ license = "
+"\"BSD\" ]; #[ author = \"Jane Doe\" ];"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:601
+msgid "// Specify the output type #[ crate_type = \"lib\" ];"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:605
+msgid "// Turn on a warning #[ warn(non_camel_case_types) ]; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:608
+msgid ""
+"A crate that contains a `main` function can be compiled to an executable. "
+"If a `main` function is present, its return type must be [`unit`](#primitive-"
+"types) and it must take no arguments."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:611
+msgid "# Items and attributes"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:614
+msgid ""
+"Crates contain [items](#items), each of which may have some number of "
+"[attributes](#attributes) attached to it."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:616
+msgid "## Items"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:621
+#, no-wrap
+msgid ""
+"~~~~~~~~ {.ebnf .gram}\n"
+"item : mod_item | fn_item | type_item | struct_item | enum_item\n"
+" | static_item | trait_item | impl_item | extern_block ;\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:627
+msgid ""
+"An _item_ is a component of a crate; some module items can be defined in "
+"crate files, but most are defined in source files. Items are organized "
+"within a crate by a nested set of [modules](#modules). Every crate has a "
+"single \"outermost\" anonymous module; all further items within the crate "
+"have [paths](#paths) within the module tree of the crate."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:630
+msgid ""
+"Items are entirely determined at compile-time, generally remain fixed during "
+"execution, and may reside in read-only memory."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:632
+msgid "There are several kinds of item:"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:641
+msgid "[modules](#modules)"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:641
+msgid "[functions](#functions)"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:641
+msgid "[type definitions](#type-definitions)"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:641
+msgid "[structures](#structures)"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:641
+msgid "[enumerations](#enumerations)"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:641
+msgid "[static items](#static-items)"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:641
+msgid "[traits](#traits)"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:641
+msgid "[implementations](#implementations)"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:651
+msgid ""
+"Some items form an implicit scope for the declaration of sub-items. In other "
+"words, within a function or module, declarations of items can (in many "
+"cases) be mixed with the statements, control blocks, and similar artifacts "
+"that otherwise compose the item body. The meaning of these scoped items is "
+"the same as if the item was declared outside the scope -- it is still a "
+"static item -- except that the item's *path name* within the module "
+"namespace is qualified by the name of the enclosing item, or is private to "
+"the enclosing item (in the case of functions). The grammar specifies the "
+"exact locations in which sub-item declarations may appear."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:653
+msgid "### Type Parameters"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:662
+msgid ""
+"All items except modules may be *parameterized* by type. Type parameters are "
+"given as a comma-separated list of identifiers enclosed in angle brackets "
+"(`<...>`), after the name of the item and before its definition. The type "
+"parameters of an item are considered \"part of the name\", not part of the "
+"type of the item. A referencing [path](#paths) must (in principle) provide "
+"type arguments as a list of comma-separated types enclosed within angle "
+"brackets, in order to refer to the type-parameterized item. In practice, "
+"the type-inference system can usually infer such argument types from "
+"context. There are no general type-parametric types, only type-parametric "
+"items. That is, Rust has no notion of type abstraction: there are no first-"
+"class \"forall\" types."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:664
+msgid "### Modules"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:669
+msgid ""
+"~~~~~~~~ {.ebnf .gram} mod_item : \"mod\" ident ( ';' | '{' mod '}' ); mod : "
+"[ view_item | item ] * ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:674
+msgid ""
+"A module is a container for zero or more [view items](#view-items) and zero "
+"or more [items](#items). The view items manage the visibility of the items "
+"defined within the module, as well as the visibility of names from outside "
+"the module when referenced from inside the module."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:678
+msgid ""
+"A _module item_ is a module, surrounded in braces, named, and prefixed with "
+"the keyword `mod`. A module item introduces a new, named module into the "
+"tree of modules making up a crate. Modules can nest arbitrarily."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:680
+msgid "An example of a module:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:698
+#, no-wrap
+msgid ""
+"~~~~~~~~\n"
+"mod math {\n"
+" type complex = (f64, f64);\n"
+" fn sin(f: f64) -> f64 {\n"
+" ...\n"
+"# fail!();\n"
+" }\n"
+" fn cos(f: f64) -> f64 {\n"
+" ...\n"
+"# fail!();\n"
+" }\n"
+" fn tan(f: f64) -> f64 {\n"
+" ...\n"
+"# fail!();\n"
+" }\n"
+"}\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:703
+msgid ""
+"Modules and types share the same namespace. Declaring a named type that has "
+"the same name as a module in scope is forbidden: that is, a type definition, "
+"trait, struct, enumeration, or type parameter can't shadow the name of a "
+"module in scope, or vice versa."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:708
+msgid ""
+"A module without a body is loaded from an external file, by default with the "
+"same name as the module, plus the `.rs` extension. When a nested submodule "
+"is loaded from an external file, it is loaded from a subdirectory path that "
+"mirrors the module hierarchy."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:712
+msgid "~~~ {.xfail-test} // Load the `vec` module from `vec.rs` mod vec;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:718
+#, no-wrap
+msgid ""
+"mod task {\n"
+" // Load the `local_data` module from `task/local_data.rs`\n"
+" mod local_data;\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:721
+msgid ""
+"The directories and files used for loading external file modules can be "
+"influenced with the `path` attribute."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:730
+#, no-wrap
+msgid ""
+"~~~ {.xfail-test}\n"
+"#[path = \"task_files\"]\n"
+"mod task {\n"
+" // Load the `local_data` module from `task_files/tls.rs`\n"
+" #[path = \"tls.rs\"]\n"
+" mod local_data;\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:732
+msgid "#### View items"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:736
+msgid ""
+"~~~~~~~~ {.ebnf .gram} view_item : extern_mod_decl | use_decl ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:740
+msgid ""
+"A view item manages the namespace of a module. View items do not define new "
+"items, but rather, simply change other items' visibility. There are several "
+"kinds of view item:"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:743
+msgid "[`extern mod` declarations](#extern-mod-declarations)"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:743
+msgid "[`use` declarations](#use-declarations)"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:745
+msgid "##### Extern mod declarations"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:751
+msgid ""
+"~~~~~~~~ {.ebnf .gram} extern_mod_decl : \"extern\" \"mod\" ident [ '(' "
+"link_attrs ')' ] ? [ '=' string_lit ] ? ; link_attrs : link_attr [ ',' "
+"link_attrs ] + ; link_attr : ident '=' literal ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:755
+msgid ""
+"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`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:765
+msgid ""
+"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 "
+"crate when it was compiled. If no `link_attrs` are provided, a default "
+"`name` attribute is assumed, equal to the `ident` given in the `use_decl`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:775
+msgid ""
+"Optionally, an identifier in an `extern mod` declaration may be followed by "
+"an equals sign, then a string literal denoting a relative path on the "
+"filesystem. This path should exist in one of the directories in the Rust "
+"path, which by default contains the `.rust` subdirectory of the current "
+"directory and each of its parents, as well as any directories in the colon-"
+"separated (or semicolon-separated on Windows) list of paths that is the "
+"`RUST_PATH` environment variable. The meaning of `extern mod a = \"b/c/d\";"
+"`, supposing that `/a` is in the RUST_PATH, is that the name `a` should be "
+"taken as a reference to the crate whose absolute location is `/a/b/c/d`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:777
+msgid "Four examples of `extern mod` declarations:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:780
+msgid ""
+"~~~~~~~~{.xfail-test} extern mod pcre (uuid = \"54aba0f8-"
+"a7b1-4beb-92f1-4cf625264841\");"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:782
+msgid ""
+"extern mod extra; // equivalent to: extern mod extra ( name = \"extra\" );"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:784
+msgid ""
+"extern mod rustextra (name = \"extra\"); // linking to 'extra' under another "
+"name"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:787
+msgid "extern mod complicated_mod = \"some-file/in/the-rust/path\"; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:789
+msgid "##### Use declarations"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:793
+#, no-wrap
+msgid ""
+"~~~~~~~~ {.ebnf .gram}\n"
+"use_decl : \"pub\"? \"use\" ident [ '=' path\n"
+" | \"::\" path_glob ] ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:798
+#, no-wrap
+msgid ""
+"path_glob : ident [ \"::\" path_glob ] ?\n"
+" | '*'\n"
+" | '{' ident [ ',' ident ] * '}'\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:802
+msgid ""
+"A _use declaration_ creates one or more local name bindings synonymous with "
+"some other [path](#paths). Usually a `use` declaration is used to shorten "
+"the path required to refer to a module item."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:806
+#, no-wrap
+msgid ""
+"*Note*: Unlike in many languages,\n"
+"`use` declarations in Rust do *not* declare linkage dependency with external crates.\n"
+"Rather, [`extern mod` declarations](#extern-mod-declarations) declare linkage dependencies.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:808
+msgid "Use declarations support a number of convenient shortcuts:"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:813
+msgid ""
+"Rebinding the target name as a new local name, using the syntax `use x = p::"
+"q::r;`."
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:813
+msgid ""
+"Simultaneously binding a list of paths differing only in their final "
+"element, using the glob-like brace syntax `use a::b::{c,d,e,f};`"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:813
+msgid ""
+"Binding all paths matching a given prefix, using the asterisk wildcard "
+"syntax `use a::b::*;`"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:815
+msgid "An example of `use` declarations:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:819
+msgid "~~~~ use std::num::sin; use std::option::{Some, None};"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:823
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" // Equivalent to 'info!(std::num::sin(1.0));'\n"
+" info!(sin(1.0));\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:828
+#, no-wrap
+msgid ""
+" // Equivalent to 'info!(~[std::option::Some(1.0), std::option::None]);'\n"
+" info!(~[Some(1.0), None]);\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:836
+msgid ""
+"Like items, `use` declarations are private to the containing module, by "
+"default. Also like items, a `use` declaration can be public, if qualified "
+"by the `pub` keyword. Such a `use` declaration serves to _re-export_ a "
+"name. A public `use` declaration can therefore _redirect_ some public name "
+"to a different target definition: even a definition with a private canonical "
+"path, inside a different module. If a sequence of such redirections form a "
+"cycle or cannot be resolved unambiguously, they represent a compile-time "
+"error."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:842
+#, no-wrap
+msgid ""
+"An example of re-exporting:\n"
+"~~~~\n"
+"# fn main() { }\n"
+"mod quux {\n"
+" pub use quux::foo::*;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:849
+#, no-wrap
+msgid ""
+" pub mod foo {\n"
+" pub fn bar() { }\n"
+" pub fn baz() { }\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:851
+msgid ""
+"In this example, the module `quux` re-exports all of the public names "
+"defined in `foo`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:854
+msgid ""
+"Also note that the paths contained in `use` items are relative to the crate "
+"root. So, in the previous example, the `use` refers to `quux::foo::*`, and "
+"not simply to `foo::*`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:856
+msgid "### Functions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:860
+msgid ""
+"A _function item_ defines a sequence of [statements](#statements) and an "
+"optional final [expression](#expressions), along with a name and a set of "
+"parameters. Functions are declared with the keyword `fn`. Functions "
+"declare a set of *input* [*slots*](#memory-slots) as parameters, through "
+"which the caller passes arguments into the function, and an *output* [*slot*]"
+"(#memory-slots) through which the function passes results back to the caller."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:865
+msgid ""
+"A function may also be copied into a first class *value*, in which case the "
+"value has the corresponding [*function type*](#function-types), and can be "
+"used otherwise exactly as a function item (with a minor additional cost of "
+"calling the function indirectly)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:871
+msgid ""
+"Every control path in a function logically ends with a `return` expression "
+"or a diverging expression. If the outermost block of a function has a value-"
+"producing expression in its final-expression position, that expression is "
+"interpreted as an implicit `return` expression applied to the final-"
+"expression."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:873
+msgid "An example of a function:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:879
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn add(x: int, y: int) -> int {\n"
+" return x + y;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:882
+msgid ""
+"As with `let` bindings, function arguments are irrefutable patterns, so any "
+"pattern that is valid in a let binding is also valid as an argument."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:886
+msgid "~~~ fn first((value, _): (int, int)) -> int { value } ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:889
+msgid "#### Generic functions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:894
+msgid ""
+"A _generic function_ allows one or more _parameterized types_ to appear in "
+"its signature. Each type parameter must be explicitly declared, in an angle-"
+"bracket-enclosed, comma-separated list following the function name."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:905
+#, no-wrap
+msgid ""
+"~~~~ {.xfail-test}\n"
+"fn iter<T>(seq: &[T], f: &fn(T)) {\n"
+" for elt in seq.iter() { f(elt); }\n"
+"}\n"
+"fn map<T, U>(seq: &[T], f: &fn(T) -> U) -> ~[U] {\n"
+" let mut acc = ~[];\n"
+" for elt in seq.iter() { acc.push(f(elt)); }\n"
+" acc\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:908
+msgid ""
+"Inside the function signature and body, the name of the type parameter can "
+"be used as a type name."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:914
+msgid ""
+"When a generic function is referenced, its type is instantiated based on the "
+"context of the reference. For example, calling the `iter` function defined "
+"above on `[1, 2]` will instantiate type parameter `T` with `int`, and "
+"require the closure parameter to have type `fn(int)`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:919
+msgid ""
+"The type parameters can also be explicitly supplied in a trailing [path]"
+"(#paths) component after the function name. This might be necessary if there "
+"is not sufficient context to determine the type parameters. For example, "
+"`sys::size_of::<u32>() == 4`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:923
+msgid ""
+"Since a parameter type is opaque to the generic function, the set of "
+"operations that can be performed on it is limited. Values of parameter type "
+"can only be moved, not copied."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:927
+msgid "~~~~ fn id<T>(x: T) -> T { x } ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:931
+msgid ""
+"Similarly, [trait](#traits) bounds can be specified for type parameters to "
+"allow methods with that trait to be called on values of that type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:934
+msgid "#### Unsafe functions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:937
+msgid ""
+"Unsafe functions are those containing unsafe operations that are not "
+"contained in an [`unsafe` block](#unsafe-blocks). Such a function must be "
+"prefixed with the keyword `unsafe`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:940
+msgid ""
+"Unsafe operations are those that potentially violate the memory-safety "
+"guarantees of Rust's static semantics. Specifically, the following "
+"operations are considered unsafe:"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:944
+msgid "Dereferencing a [raw pointer](#pointer-types)."
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:944
+msgid "Casting a [raw pointer](#pointer-types) to a safe pointer type."
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:944
+msgid "Calling an unsafe function."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:946
+msgid "##### Unsafe blocks"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:950
+msgid ""
+"A block of code can also be prefixed with the `unsafe` keyword, to permit a "
+"sequence of unsafe operations in an otherwise-safe function. This facility "
+"exists because the static semantics of Rust are a necessary approximation of "
+"the dynamic semantics. When a programmer has sufficient conviction that a "
+"sequence of unsafe operations is actually safe, they can encapsulate that "
+"sequence (taken as a whole) within an `unsafe` block. The compiler will "
+"consider uses of such code \"safe\", to the surrounding context."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:953
+msgid "#### Diverging functions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:956
+msgid ""
+"A special kind of function can be declared with a `!` character where the "
+"output slot type would normally be. For example:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:963
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn my_err(s: &str) -> ! {\n"
+" info!(s);\n"
+" fail!();\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:970
+msgid ""
+"We call such functions \"diverging\" because they never return a value to "
+"the caller. Every control path in a diverging function must end with a `fail!"
+"()` or a call to another diverging function on every control path. The `!` "
+"annotation does *not* denote a type. Rather, the result type of a diverging "
+"function is a special type called $\\bot$ (\"bottom\") that unifies with any "
+"type. Rust has no syntax for $\\bot$."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:976
+msgid ""
+"It might be necessary to declare a diverging function because as mentioned "
+"previously, the typechecker checks that every control path in a function "
+"ends with a [`return`](#return-expressions) or diverging expression. So, if "
+"`my_err` were declared without the `!` annotation, the following code would "
+"not typecheck:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:979
+msgid "~~~~ # fn my_err(s: &str) -> ! { fail!() }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:989
+#, no-wrap
+msgid ""
+"fn f(i: int) -> int {\n"
+" if i == 42 {\n"
+" return 42;\n"
+" }\n"
+" else {\n"
+" my_err(\"Bad number!\");\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:997
+msgid ""
+"This will not compile without the `!` annotation on `my_err`, since the "
+"`else` branch of the conditional in `f` does not return an `int`, as "
+"required by the signature of `f`. Adding the `!` annotation to `my_err` "
+"informs the typechecker that, should control ever enter `my_err`, no further "
+"type judgments about `f` need to hold, since control will never resume in "
+"any context that relies on those judgments. Thus the return type on `f` "
+"only needs to reflect the `if` branch of the conditional."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1000
+msgid "#### Extern functions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1007
+msgid ""
+"Extern functions are part of Rust's foreign function interface, 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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1011
+msgid "~~~ extern fn new_vec() -> ~[int] { ~[] } ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1014
+msgid ""
+"Extern functions may not be called from Rust code, but Rust code may take "
+"their value as a raw `u8` pointer."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1019
+msgid ""
+"~~~ # extern fn new_vec() -> ~[int] { ~[] } let fptr: *u8 = new_vec; ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1023
+msgid ""
+"The primary motivation for extern functions is to create callbacks for "
+"foreign functions that expect to receive function pointers."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1025
+msgid "### Type definitions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1029
+msgid ""
+"A _type definition_ defines a new name for an existing [type](#types). Type "
+"definitions are declared with the keyword `type`. Every value has a single, "
+"specific type; the type-specified aspects of a value include:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1035
+msgid "Whether the value is composed of sub-values or is indivisible."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1035
+msgid "Whether the value represents textual or numerical information."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1035
+msgid "Whether the value represents integral or floating-point information."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1035
+msgid "The sequence of memory operations required to access the value."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1035
+msgid "The [kind](#type-kinds) of the type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1038
+msgid ""
+"For example, the type `(u8, u8)` defines the set of immutable values that "
+"are composite pairs, each containing two unsigned 8-bit integers accessed by "
+"pattern-matching and laid out in memory with the `x` component preceding the "
+"`y` component."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1040
+msgid "### Structures"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1042
+msgid ""
+"A _structure_ is a nominal [structure type](#structure-types) defined with "
+"the keyword `struct`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1044
+msgid "An example of a `struct` item and its use:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1050
+msgid ""
+"~~~~ struct Point {x: int, y: int} let p = Point {x: 10, y: 11}; let px: int "
+"= p.x; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1053
+msgid ""
+"A _tuple structure_ is a nominal [tuple type](#tuple-types), also defined "
+"with the keyword `struct`. For example:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1059
+msgid ""
+"~~~~ struct Point(int, int); let p = Point(10, 11); let px: int = match p "
+"{ Point(x, _) => x }; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1063
+msgid ""
+"A _unit-like struct_ is a structure without any fields, defined by leaving "
+"off the list of fields entirely. Such types will have a single value, just "
+"like the [unit value `()`](#unit-and-boolean-literals) of the unit type. "
+"For example:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1068
+msgid "~~~~ struct Cookie; let c = [Cookie, Cookie, Cookie, Cookie]; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1070
+msgid "### Enumerations"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1073
+msgid ""
+"An _enumeration_ is a simultaneous definition of a nominal [enumerated type]"
+"(#enumerated-types) as well as a set of *constructors*, that can be used to "
+"create or pattern-match values of the corresponding enumerated type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1075
+msgid "Enumerations are declared with the keyword `enum`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1077
+msgid "An example of an `enum` item and its use:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1083
+#, no-wrap
+msgid ""
+"~~~~\n"
+"enum Animal {\n"
+" Dog,\n"
+" Cat\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1087
+msgid "let mut a: Animal = Dog; a = Cat; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1094
+#, no-wrap
+msgid ""
+"Enumeration constructors can have either named or unnamed fields:\n"
+"~~~~\n"
+"enum Animal {\n"
+" Dog (~str, float),\n"
+" Cat { name: ~str, weight: float }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1098
+msgid ""
+"let mut a: Animal = Dog(~\"Cocoa\", 37.2); a = Cat{ name: ~\"Spotty\", "
+"weight: 2.7 }; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1101
+msgid ""
+"In this example, `Cat` is a _struct-like enum variant_, whereas `Dog` is "
+"simply called an enum variant."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1103
+msgid "### Static items"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1107
+msgid ""
+"~~~~~~~~ {.ebnf .gram} static_item : \"static\" ident ':' type '=' expr "
+"';' ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1114
+msgid ""
+"A *static item* is a named _constant value_ stored in the global data "
+"section of a crate. Immutable static items are stored in the read-only data "
+"section. The constant value bound to a static item is, like all constant "
+"values, evaluated at compile time. Static items have the `static` lifetime, "
+"which outlives all other lifetimes in a Rust program. Static items are "
+"declared with the `static` keyword. A static item must have a _constant "
+"expression_ giving its definition."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1119
+msgid ""
+"Static items must be explicitly typed. The type may be ```bool```, "
+"```char```, a number, or a type derived from those primitive types. The "
+"derived types are borrowed pointers with the `'static` lifetime, fixed-size "
+"arrays, tuples, and structs."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1123
+msgid "~~~~ static BIT1: uint = 1 << 0; static BIT2: uint = 1 << 1;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1126
+msgid ""
+"static BITS: [uint, ..2] = [BIT1, BIT2]; static STRING: &'static str = "
+"\"bitstring\";"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1131
+#, no-wrap
+msgid ""
+"struct BitsNStrings<'self> {\n"
+" mybits: [uint, ..2],\n"
+" mystring: &'self str\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1137
+#, no-wrap
+msgid ""
+"static bits_n_strings: BitsNStrings<'static> = BitsNStrings {\n"
+" mybits: BITS,\n"
+" mystring: STRING\n"
+"};\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1139
+msgid "#### Mutable statics"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1147
+msgid ""
+"If a static item is declared with the ```mut``` keyword, then it is allowed "
+"to be modified by the program. One of Rust's goals is to make concurrency "
+"bugs hard to run into, and this is obviously a very large source of race "
+"conditions or other bugs. For this reason, an ```unsafe``` block is required "
+"when either reading or writing a mutable static variable. Care should be "
+"taken to ensure that modifications to a mutable static are safe with respect "
+"to other tasks running in the same process."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1150
+msgid ""
+"Mutable statics are still very useful, however. They can be used with C "
+"libraries and can also be bound from C libraries (in an ```extern``` block)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1153
+msgid "~~~ # fn atomic_add(_: &mut uint, _: uint) -> uint { 2 }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1155
+msgid "static mut LEVELS: uint = 0;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1163
+#, no-wrap
+msgid ""
+"// This violates the idea of no shared state, and this doesn't internally\n"
+"// protect against races, so this function is `unsafe`\n"
+"unsafe fn bump_levels_unsafe1() -> uint {\n"
+" let ret = LEVELS;\n"
+" LEVELS += 1;\n"
+" return ret;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1170
+#, no-wrap
+msgid ""
+"// Assuming that we have an atomic_add function which returns the old value,\n"
+"// this function is \"safe\" but the meaning of the return value may not be what\n"
+"// callers expect, so it's still marked as `unsafe`\n"
+"unsafe fn bump_levels_unsafe2() -> uint {\n"
+" return atomic_add(&mut LEVELS, 1);\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1172
+msgid "~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1174
+msgid "### Traits"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1176
+msgid "A _trait_ describes a set of method types."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1181
+msgid ""
+"Traits can include default implementations of methods, written in terms of "
+"some unknown [`self` type](#self-types); the `self` type may either be "
+"completely unspecified, or constrained by some other trait."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1183
+msgid ""
+"Traits are implemented for specific types through separate [implementations]"
+"(#implementations)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1187
+msgid "~~~~ # type Surface = int; # type BoundingBox = int;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1193
+#, no-wrap
+msgid ""
+"trait Shape {\n"
+" fn draw(&self, Surface);\n"
+" fn bounding_box(&self) -> BoundingBox;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1197
+msgid ""
+"This defines a trait with two methods. All values that have "
+"[implementations](#implementations) of this trait in scope can have their "
+"`draw` and `bounding_box` methods called, using `value.bounding_box()` "
+"[syntax](#method-call-expressions)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1200
+msgid ""
+"Type parameters can be specified for a trait to make it generic. These "
+"appear after the trait name, using the same syntax used in [generic "
+"functions](#generic-functions)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1208
+#, no-wrap
+msgid ""
+"~~~~\n"
+"trait Seq<T> {\n"
+" fn len(&self) -> uint;\n"
+" fn elt_at(&self, n: uint) -> T;\n"
+" fn iter(&self, &fn(T));\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1214
+msgid ""
+"Generic functions may use traits as _bounds_ on their type parameters. This "
+"will have two effects: only types that have the trait may instantiate the "
+"parameter, and within the generic function, the methods of the trait can be "
+"called on values that have the parameter's type. For example:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1218
+msgid "~~~~ # type Surface = int; # trait Shape { fn draw(&self, Surface); }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1224
+#, no-wrap
+msgid ""
+"fn draw_twice<T: Shape>(surface: Surface, sh: T) {\n"
+" sh.draw(surface);\n"
+" sh.draw(surface);\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1229
+msgid ""
+"Traits also define an [object type](#object-types) with the same name as the "
+"trait. Values of this type are created by [casting](#type-cast-expressions) "
+"pointer values (pointing to a type for which an implementation of the given "
+"trait is in scope) to pointers to the trait name, used as a type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1234
+msgid "~~~~ # trait Shape { } # impl Shape for int { } # let mycircle = 0;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1237
+msgid "let myshape: @Shape = @mycircle as @Shape; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1243
+msgid ""
+"The resulting value is a managed box containing the value that was cast, "
+"along with information that identifies the methods of the implementation "
+"that was used. Values with a trait type can have [methods called](#method-"
+"call-expressions) on them, for any method in the trait, and can be used to "
+"instantiate type parameters that are bounded by the trait."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1251
+msgid ""
+"Trait methods may be static, which means that they lack a `self` argument. "
+"This means that they can only be called with function call syntax (`f(x)`) "
+"and not method call syntax (`obj.f()`). The way to refer to the name of a "
+"static method is to qualify it with the trait name, treating the trait name "
+"like a module. For example:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1261
+#, no-wrap
+msgid ""
+"~~~~\n"
+"trait Num {\n"
+" fn from_int(n: int) -> Self;\n"
+"}\n"
+"impl Num for float {\n"
+" fn from_int(n: int) -> float { n as float }\n"
+"}\n"
+"let x: float = Num::from_int(42);\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1263
+msgid "Traits may inherit from other traits. For example, in"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1268
+msgid ""
+"~~~~ trait Shape { fn area() -> float; } trait Circle : Shape { fn radius() -"
+"> float; } ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1273
+msgid ""
+"the syntax `Circle : Shape` means that types that implement `Circle` must "
+"also have an implementation for `Shape`. Multiple supertraits are separated "
+"by spaces, `trait Circle : Shape Eq { }`. In an implementation of `Circle` "
+"for a given type `T`, methods can refer to `Shape` methods, since the "
+"typechecker checks that any type with an implementation of `Circle` also has "
+"an implementation of `Shape`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1277 doc/tutorial.md:2176
+msgid ""
+"In type-parameterized functions, methods of the supertrait may be called on "
+"values of subtrait-bound type parameters. Refering to the previous example "
+"of `trait Circle : Shape`:"
+msgstr ""
+"型パラメータを持つ関数では、サブトレイトの境界型パラメータの値によりスーパー"
+"トレイトのメソッドを呼び出すことになります。前の例の `trait Circle : Shape` "
+"を参照してください。"
+
+#. type: Plain text
+#: doc/rust.md:1286 doc/tutorial.md:2185
+#, no-wrap
+msgid ""
+"~~~\n"
+"# trait Shape { fn area(&self) -> float; }\n"
+"# trait Circle : Shape { fn radius(&self) -> float; }\n"
+"fn radius_times_area<T: Circle>(c: T) -> float {\n"
+" // `c` is both a Circle and a Shape\n"
+" c.radius() * c.area()\n"
+"}\n"
+"~~~\n"
+msgstr ""
+"~~~\n"
+"# trait Shape { fn area(&self) -> float; }\n"
+"# trait Circle : Shape { fn radius(&self) -> float; }\n"
+"fn radius_times_area<T: Circle>(c: T) -> float {\n"
+" // `c` は Circle でもあり、Shape でもある\n"
+" c.radius() * c.area()\n"
+"}\n"
+"~~~\n"
+
+#. type: Plain text
+#: doc/rust.md:1288 doc/tutorial.md:2187
+msgid "Likewise, supertrait methods may also be called on trait objects."
+msgstr ""
+"同様に、スーパートレイトのメソッドは、トレイトオブジェクトについても呼び出す"
+"ことが可能です。"
+
+#. type: Plain text
+#: doc/rust.md:1295
+msgid ""
+"~~~ {.xfail-test} # trait Shape { fn area(&self) -> float; } # trait "
+"Circle : Shape { fn radius(&self) -> float; } # impl Shape for int { fn "
+"area(&self) -> float { 0.0 } } # impl Circle for int { fn radius(&self) -> "
+"float { 0.0 } } # let mycircle = 0;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1299
+msgid ""
+"let mycircle: Circle = @mycircle as @Circle; let nonsense = mycircle."
+"radius() * mycircle.area(); ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1301
+msgid "### Implementations"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1303
+msgid ""
+"An _implementation_ is an item that implements a [trait](#traits) for a "
+"specific type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1305
+msgid "Implementations are defined with the keyword `impl`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1312
+msgid ""
+"~~~~ # struct Point {x: float, y: float}; # type Surface = int; # struct "
+"BoundingBox {x: float, y: float, width: float, height: float}; # trait Shape "
+"{ fn draw(&self, Surface); fn bounding_box(&self) -> BoundingBox; } # fn "
+"do_draw_circle(s: Surface, c: Circle) { }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1317
+#, no-wrap
+msgid ""
+"struct Circle {\n"
+" radius: float,\n"
+" center: Point,\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1327
+#, no-wrap
+msgid ""
+"impl Shape for Circle {\n"
+" fn draw(&self, s: Surface) { do_draw_circle(s, *self); }\n"
+" fn bounding_box(&self) -> BoundingBox {\n"
+" let r = self.radius;\n"
+" BoundingBox{x: self.center.x - r, y: self.center.y - r,\n"
+" width: 2.0 * r, height: 2.0 * r}\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1334
+msgid ""
+"It is possible to define an implementation without referring to a trait. "
+"The methods in such an implementation can only be used as direct calls on "
+"the values of the type that the implementation targets. In such an "
+"implementation, the trait type and `for` after `impl` are omitted. Such "
+"implementations are limited to nominal types (enums, structs), and the "
+"implementation must appear in the same module or a sub-module as the `self` "
+"type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1338
+msgid ""
+"When a trait _is_ specified in an `impl`, all methods declared as part of "
+"the trait must be implemented, with matching types and type parameter counts."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1342
+msgid ""
+"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 the `impl` keyword."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1345
+msgid "~~~~ # trait Seq<T> { }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1353
+#, no-wrap
+msgid ""
+"impl<T> Seq<T> for ~[T] {\n"
+" ...\n"
+"}\n"
+"impl Seq<bool> for u32 {\n"
+" /* Treat the integer as a sequence of bits */\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1355
+msgid "### External blocks"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1360
+msgid ""
+"~~~ {.ebnf .gram} extern_block_item : \"extern\" '{' extern_block '} ; "
+"extern_block : [ foreign_fn ] * ; ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1364
+msgid ""
+"External blocks form the basis for Rust's foreign function interface. "
+"Declarations in an external block describe symbols in external, non-Rust "
+"libraries."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1369
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1373
+msgid "~~~ # use std::libc::{c_char, FILE}; # #[nolink]"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1378
+#, no-wrap
+msgid ""
+"extern {\n"
+" fn fopen(filename: *c_char, mode: *c_char) -> *FILE;\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1383
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1386
+msgid ""
+"A number of [attributes](#attributes) control the behavior of external "
+"blocks."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1390
+msgid ""
+"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"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1396
+msgid ""
+"~~~{.xfail-test} // Interface to the Windows API #[abi = \"stdcall\"] extern "
+"{ } ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1398
+msgid ""
+"The `link_name` attribute allows the name of the library to be specified."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1403
+msgid "~~~{.xfail-test} #[link_name = \"crypto\"] extern { } ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1409
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1411
+msgid "## Attributes"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1418
+#, no-wrap
+msgid ""
+"~~~~~~~~{.ebnf .gram}\n"
+"attribute : '#' '[' attr_list ']' ;\n"
+"attr_list : attr [ ',' attr_list ]*\n"
+"attr : ident [ '=' literal\n"
+" | '(' attr_list ')' ] ? ;\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1424
+msgid ""
+"Static entities in Rust -- crates, modules and items -- may have "
+"_attributes_ applied to them. ^[Attributes in Rust are modeled on Attributes "
+"in ECMA-335, C#] An attribute is a general, free-form metadatum that is "
+"interpreted according to name, convention, and language and compiler "
+"version. Attributes may appear as any of"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1428
+msgid "A single identifier, the attribute name"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1428
+msgid ""
+"An identifier followed by the equals sign '=' and a literal, providing a key/"
+"value pair"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1428
+msgid ""
+"An identifier followed by a parenthesized list of sub-attribute arguments"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1431
+msgid ""
+"Attributes terminated by a semi-colon apply to the entity that the attribute "
+"is declared within. Attributes that are not terminated by a semi-colon apply "
+"to the next entity."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1433
+msgid "An example of attributes:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1437
+msgid ""
+"~~~~~~~~{.xfail-test} // General metadata applied to the enclosing module or "
+"crate. #[license = \"BSD\"];"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1443
+#, no-wrap
+msgid ""
+"// A function marked as a unit test\n"
+"#[test]\n"
+"fn test_foo() {\n"
+" ...\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1449
+#, no-wrap
+msgid ""
+"// A conditionally-compiled module\n"
+"#[cfg(target_os=\"linux\")]\n"
+"mod bar {\n"
+" ...\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1454
+msgid ""
+"// A lint attribute used to suppress a warning/error "
+"#[allow(non_camel_case_types)] pub type int8_t = i8; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1457
+msgid ""
+"> **Note:** In future versions of Rust, user-provided extensions to the "
+"compiler will be able to interpret attributes. > When this facility is "
+"provided, the compiler will distinguish between language-reserved and user-"
+"available attributes."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1460
+msgid ""
+"At present, only the Rust compiler interprets attributes, so all attribute "
+"names are effectively reserved. Some significant attributes include:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1471
+msgid "The `doc` attribute, for documenting code in-place."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1471
+msgid ""
+"The `cfg` attribute, for conditional-compilation by build-configuration."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1471
+msgid ""
+"The `lang` attribute, for custom definitions of traits and functions that "
+"are known to the Rust compiler (see [Language items](#language-items))."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1471
+msgid "The `link` attribute, for describing linkage metadata for a crate."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1471
+msgid "The `test` attribute, for marking functions as unit tests."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1471
+msgid ""
+"The `allow`, `warn`, `forbid`, and `deny` attributes, for controlling lint "
+"checks (see [Lint check attributes](#lint-check-attributes))."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1471
+msgid ""
+"The `deriving` attribute, for automatically generating implementations of "
+"certain traits."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1471
+msgid ""
+"The `static_assert` attribute, for asserting that a static bool is true at "
+"compiletime"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1473
+msgid ""
+"Other attributes may be added or removed during development of the language."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1475
+msgid "### Lint check attributes"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1479
+msgid ""
+"A lint check names a potentially undesirable coding pattern, such as "
+"unreachable code or omitted documentation, for the static entity to which "
+"the attribute applies."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1481
+msgid "For any lint check `C`:"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:1488
+msgid "`warn(C)` warns about violations of `C` but continues compilation,"
+msgstr ""
+
+#. type: Bullet: ' * '
+#: doc/rust.md:1488
+msgid "`deny(C)` signals an error after encountering a violation of `C`,"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1488
+#, no-wrap
+msgid ""
+" * `allow(C)` overrides the check for `C` so that violations will go\n"
+" unreported,\n"
+" * `forbid(C)` is the same as `deny(C)`, but also forbids uses of\n"
+" `allow(C)` within the entity.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1491
+msgid ""
+"The lint checks supported by the compiler can be found via `rustc -W help`, "
+"along with their default settings."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1497
+#, no-wrap
+msgid ""
+"~~~{.xfail-test}\n"
+"mod m1 {\n"
+" // Missing documentation is ignored here\n"
+" #[allow(missing_doc)]\n"
+" pub fn undocumented_one() -> int { 1 }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1501
+#, no-wrap
+msgid ""
+" // Missing documentation signals a warning here\n"
+" #[warn(missing_doc)]\n"
+" pub fn undocumented_too() -> int { 2 }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1507
+#, no-wrap
+msgid ""
+" // Missing documentation signals an error here\n"
+" #[deny(missing_doc)]\n"
+" pub fn undocumented_end() -> int { 3 }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1510
+msgid ""
+"This example shows how one can use `allow` and `warn` to toggle a particular "
+"check on and off."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1518
+#, no-wrap
+msgid ""
+"~~~{.xfail-test}\n"
+"#[warn(missing_doc)]\n"
+"mod m2{\n"
+" #[allow(missing_doc)]\n"
+" mod nested {\n"
+" // Missing documentation is ignored here\n"
+" pub fn undocumented_one() -> int { 1 }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1524
+#, no-wrap
+msgid ""
+" // Missing documentation signals a warning here,\n"
+" // despite the allow above.\n"
+" #[warn(missing_doc)]\n"
+" pub fn undocumented_two() -> int { 2 }\n"
+" }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1529
+#, no-wrap
+msgid ""
+" // Missing documentation signals a warning here\n"
+" pub fn undocumented_too() -> int { 3 }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1532
+msgid ""
+"This example shows how one can use `forbid` to disallow uses of `allow` for "
+"that lint check."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1542
+#, no-wrap
+msgid ""
+"~~~{.xfail-test}\n"
+"#[forbid(missing_doc)]\n"
+"mod m3 {\n"
+" // Attempting to toggle warning signals an error here\n"
+" #[allow(missing_doc)]\n"
+" /// Returns 2.\n"
+" pub fn undocumented_too() -> int { 2 }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1544
+msgid "### Language items"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1550
+msgid ""
+"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 standard library defines the string equality function:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1557
+#, no-wrap
+msgid ""
+"~~~ {.xfail-test}\n"
+"#[lang=\"str_eq\"]\n"
+"pub fn eq_slice(a: &str, b: &str) -> bool {\n"
+" // details elided\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1561
+msgid ""
+"The name `str_eq` has a special meaning to the Rust compiler, and the "
+"presence of this definition means that it will use this definition when "
+"generating calls to the string equality function."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1563
+msgid "A complete list of the built-in language items follows:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1565
+msgid "#### Traits"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1604
+#, no-wrap
+msgid ""
+"`const`\n"
+" : Cannot be mutated.\n"
+"`owned`\n"
+" : Are uniquely owned.\n"
+"`durable`\n"
+" : Contain borrowed pointers.\n"
+"`drop`\n"
+" : Have finalizers.\n"
+"`add`\n"
+" : Elements can be added (for example, integers and floats).\n"
+"`sub`\n"
+" : Elements can be subtracted.\n"
+"`mul`\n"
+" : Elements can be multiplied.\n"
+"`div`\n"
+" : Elements have a division operation.\n"
+"`rem`\n"
+" : Elements have a remainder operation.\n"
+"`neg`\n"
+" : Elements can be negated arithmetically.\n"
+"`not`\n"
+" : Elements can be negated logically.\n"
+"`bitxor`\n"
+" : Elements have an exclusive-or operation.\n"
+"`bitand`\n"
+" : Elements have a bitwise `and` operation.\n"
+"`bitor`\n"
+" : Elements have a bitwise `or` operation.\n"
+"`shl`\n"
+" : Elements have a left shift operation.\n"
+"`shr`\n"
+" : Elements have a right shift operation.\n"
+"`index`\n"
+" : Elements can be indexed.\n"
+"`eq`\n"
+" : Elements can be compared for equality.\n"
+"`ord`\n"
+" : Elements have a partial ordering.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1606
+msgid "#### Operations"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1636
+#, no-wrap
+msgid ""
+"`str_eq`\n"
+" : Compare two strings for equality.\n"
+"`uniq_str_eq`\n"
+" : Compare two owned strings for equality.\n"
+"`annihilate`\n"
+" : Destroy a box before freeing it.\n"
+"`log_type`\n"
+" : Generically print a string representation of any type.\n"
+"`fail_`\n"
+" : Abort the program with an error.\n"
+"`fail_bounds_check`\n"
+" : Abort the program with a bounds check error.\n"
+"`exchange_malloc`\n"
+" : Allocate memory on the exchange heap.\n"
+"`exchange_free`\n"
+" : Free memory that was allocated on the exchange heap.\n"
+"`malloc`\n"
+" : Allocate memory on the managed heap.\n"
+"`free`\n"
+" : Free memory that was allocated on the managed heap.\n"
+"`borrow_as_imm`\n"
+" : Create an immutable borrowed pointer to a mutable value.\n"
+"`return_to_mut`\n"
+" : Release a borrowed pointer created with `return_to_mut`\n"
+"`check_not_borrowed`\n"
+" : Fail if a value has existing borrowed pointers to it.\n"
+"`strdup_uniq`\n"
+" : Return a new unique string\n"
+" containing a copy of the contents of a unique string.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1639
+msgid ""
+"> **Note:** This list is likely to become out of date. We should auto-"
+"generate it > from `librustc/middle/lang_items.rs`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1641
+msgid "### Deriving"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1647
+msgid ""
+"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`:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1655
+#, no-wrap
+msgid ""
+"~~~\n"
+"#[deriving(Eq, Clone)]\n"
+"struct Foo<T> {\n"
+" a: int,\n"
+" b: T\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1657
+msgid "The generated `impl` for `Eq` is equivalent to"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1664
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Foo<T> { a: int, b: T }\n"
+"impl<T: Eq> Eq for Foo<T> {\n"
+" fn eq(&self, other: &Foo<T>) -> bool {\n"
+" self.a == other.a && self.b == other.b\n"
+" }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1670
+#, no-wrap
+msgid ""
+" fn ne(&self, other: &Foo<T>) -> bool {\n"
+" self.a != other.a || self.b != other.b\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1672
+msgid "Supported traits for `deriving` are:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1683
+msgid "Comparison traits: `Eq`, `TotalEq`, `Ord`, `TotalOrd`."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1683
+msgid "Serialization: `Encodable`, `Decodable`. These require `extra`."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1683
+msgid "`Clone` and `DeepClone`, to perform (deep) copies."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1683
+msgid "`IterBytes`, to iterate over the bytes in a data type."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1683
+msgid "`Rand`, to create a random instance of a data type."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1683
+msgid "`Zero`, to create an zero (or empty) instance of a data type."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:1683
+msgid ""
+"`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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1685
+msgid "# Statements and expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1692
+msgid ""
+"Rust is _primarily_ an expression language. This means that most forms of "
+"value-producing or effect-causing evaluation are directed by the uniform "
+"syntax category of _expressions_. Each kind of expression can typically "
+"_nest_ within each other kind of expression, and rules for evaluation of "
+"expressions involve specifying both the value produced by the expression and "
+"the order in which its sub-expressions are themselves evaluated."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1695
+msgid ""
+"In contrast, statements in Rust serve _mostly_ to contain and explicitly "
+"sequence expression evaluation."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1697
+msgid "## Statements"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1700
+msgid ""
+"A _statement_ is a component of a block, which is in turn a component of an "
+"outer [expression](#expressions) or [function](#functions)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1704
+msgid ""
+"Rust has two kinds of statement: [declaration statements](#declaration-"
+"statements) and [expression statements](#expression-statements)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1706
+msgid "### Declaration statements"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1709
+msgid ""
+"A _declaration statement_ is one that introduces one or more *names* into "
+"the enclosing statement block. The declared names may denote new slots or "
+"new items."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1711
+msgid "#### Item declarations"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1718
+msgid ""
+"An _item declaration statement_ has a syntactic form identical to an [item]"
+"(#items) declaration within a module. Declaring an item -- a function, "
+"enumeration, structure, type, static, trait, implementation or module -- "
+"locally within a statement block is simply a way of restricting its scope to "
+"a narrow region containing all of its uses; it is otherwise identical in "
+"meaning to declaring the item outside the statement block."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1721
+msgid ""
+"Note: there is no implicit capture of the function's dynamic environment "
+"when declaring a function-local item."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1724
+msgid "#### Slot declarations"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1729
+msgid ""
+"~~~~~~~~{.ebnf .gram} let_decl : \"let\" pat [':' type ] ? [ init ] ? ';' ; "
+"init : [ '=' ] expr ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1735
+msgid ""
+"A _slot declaration_ introduces a new set of slots, given by a pattern. The "
+"pattern may be followed by a type annotation, and/or an initializer "
+"expression. When no type annotation is given, the compiler will infer the "
+"type, or signal an error if insufficient type information is available for "
+"definite inference. Any slots introduced by a slot declaration are visible "
+"from the point of declaration until the end of the enclosing block scope."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1737
+msgid "### Expression statements"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1742
+msgid ""
+"An _expression statement_ is one that evaluates an [expression]"
+"(#expressions) and ignores its result. The type of an expression statement "
+"`e;` is always `()`, regardless of the type of `e`. As a rule, an "
+"expression statement's purpose is to trigger the effects of evaluating its "
+"expression."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1744
+msgid "## Expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1753
+#, no-wrap
+msgid ""
+"An expression may have two roles: it always produces a *value*, and it may have *effects*\n"
+"(otherwise known as \"side effects\").\n"
+"An expression *evaluates to* a value, and has effects during *evaluation*.\n"
+"Many expressions contain sub-expressions (operands).\n"
+"The meaning of each kind of expression dictates several things:\n"
+" * Whether or not to evaluate the sub-expressions when evaluating the expression\n"
+" * The order in which to evaluate the sub-expressions\n"
+" * How to combine the sub-expressions' values to obtain the value of the expression.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1758
+msgid ""
+"In this way, the structure of expressions dictates the structure of "
+"execution. Blocks are just another kind of expression, so blocks, "
+"statements, expressions, and blocks again can recursively nest inside each "
+"other to an arbitrary depth."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1760
+msgid "#### Lvalues, rvalues and temporaries"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1764
+msgid ""
+"Expressions are divided into two main categories: _lvalues_ and _rvalues_. "
+"Likewise within each expression, sub-expressions may occur in _lvalue "
+"context_ or _rvalue context_. The evaluation of an expression depends both "
+"on its own category and the context it occurs within."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1767
+msgid ""
+"[Path](#path-expressions), [field](#field-expressions) and [index](#index-"
+"expressions) expressions are lvalues. All other expressions are rvalues."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1775
+msgid ""
+"The left operand of an [assignment](#assignment-expressions), [binary move]"
+"(#binary-move-expressions) or [compound-assignment](#compound-assignment-"
+"expressions) expression is an lvalue context, as is the single operand of a "
+"unary [borrow](#unary-operator-expressions), or [move](#unary-move-"
+"expressions) expression, and _both_ operands of a [swap](#swap-expressions) "
+"expression. All other expression contexts are rvalue contexts."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1778
+msgid ""
+"When an lvalue is evaluated in an _lvalue context_, it denotes a memory "
+"location; when evaluated in an _rvalue context_, it denotes the value held "
+"_in_ that memory location."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1781
+msgid ""
+"When an rvalue is used in lvalue context, a temporary un-named lvalue is "
+"created and used instead. A temporary's lifetime equals the largest "
+"lifetime of any borrowed pointer that points to it."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1783
+msgid "#### Moved and copied types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1792
+msgid ""
+"When a [local variable](#memory-slots) is used as an [rvalue](#lvalues-"
+"rvalues-and-temporaries) the variable will either be [moved](#move-"
+"expressions) or copied, depending on its type. For types that contain "
+"[owning pointers](#owning-pointers) or values that implement the special "
+"trait `Drop`, the variable is moved. All other types are copied."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1795
+msgid "### Literal expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1799
+msgid ""
+"A _literal expression_ consists of one of the [literal](#literals) forms "
+"described earlier. It directly describes a number, character, string, "
+"boolean value, or the unit value."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1806
+#, no-wrap
+msgid ""
+"~~~~~~~~ {.literals}\n"
+"(); // unit type\n"
+"\"hello\"; // string type\n"
+"'5'; // character type\n"
+"5; // integer type\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1808
+msgid "### Path expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1811
+msgid ""
+"A [path](#paths) used as an expression context denotes either a local "
+"variable or an item. Path expressions are [lvalues](#lvalues-rvalues-and-"
+"temporaries)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1813
+msgid "### Tuple expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1817
+msgid ""
+"Tuples are written by enclosing one or more comma-separated expressions in "
+"parentheses. They are used to create [tuple-typed](#tuple-types) values."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1823
+msgid "~~~~~~~~ {.tuple} (0,); (0f, 4.5f); (\"a\", 4u, true); ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1825
+msgid "### Structure expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1834
+#, no-wrap
+msgid ""
+"~~~~~~~~{.ebnf .gram}\n"
+"struct_expr : expr_path '{' ident ':' expr\n"
+" [ ',' ident ':' expr ] *\n"
+" [ \"..\" expr ] '}' |\n"
+" expr_path '(' expr\n"
+" [ ',' expr ] * ')' |\n"
+" expr_path\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1841
+msgid ""
+"There are several forms of structure expressions. A _structure expression_ "
+"consists of the [path](#paths) of a [structure item](#structures), followed "
+"by a brace-enclosed list of one or more comma-separated name-value pairs, "
+"providing the field values of a new instance of the structure. A field name "
+"can be any identifier, and is separated from its value expression by a "
+"colon. The location denoted by a structure field is mutable if and only if "
+"the enclosing structure is mutable."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1846
+msgid ""
+"A _tuple structure expression_ consists of the [path](#paths) of a "
+"[structure item](#structures), followed by a parenthesized list of one or "
+"more comma-separated expressions (in other words, the path of a structure "
+"item followed by a tuple expression). The structure item must be a tuple "
+"structure item."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1848
+msgid ""
+"A _unit-like structure expression_ consists only of the [path](#paths) of a "
+"[structure item](#structures)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1850
+msgid "The following are examples of structure expressions:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1861
+msgid ""
+"~~~~ # struct Point { x: float, y: float } # struct TuplePoint(float, "
+"float); # mod game { pub struct User<'self> { name: &'self str, age: uint, "
+"score: uint } } # struct Cookie; fn some_fn<T>(t: T) {} Point {x: 10f, y: "
+"20f}; TuplePoint(10f, 20f); let u = game::User {name: \"Joe\", age: 35, "
+"score: 100_000}; some_fn::<Cookie>(Cookie); ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1864
+msgid ""
+"A structure expression forms a new value of the named structure type. Note "
+"that for a given *unit-like* structure type, this will always be the same "
+"value."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1871
+msgid ""
+"A structure expression can terminate with the syntax `..` followed by an "
+"expression to denote a functional update. The expression following `..` "
+"(the base) must have the same structure type as the new structure type being "
+"formed. The entire expression denotes the result of allocating a new "
+"structure (with the same type as the base expression) with the given values "
+"for the fields that were explicitly specified and the values in the base "
+"record for all other fields."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1877
+msgid ""
+"~~~~ # struct Point3d { x: int, y: int, z: int } let base = Point3d {x: 1, "
+"y: 2, z: 3}; Point3d {y: 0, z: 10, .. base}; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1879
+msgid "### Record expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1885
+#, no-wrap
+msgid ""
+"~~~~~~~~{.ebnf .gram}\n"
+"rec_expr : '{' ident ':' expr\n"
+" [ ',' ident ':' expr ] *\n"
+" [ \"..\" expr ] '}'\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1887
+msgid "### Method-call expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1891
+msgid ""
+"~~~~~~~~{.ebnf .gram} method_call_expr : expr '.' ident paren_expr_list ; "
+"~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1896
+msgid ""
+"A _method call_ consists of an expression followed by a single dot, an "
+"identifier, and a parenthesized expression-list. Method calls are resolved "
+"to methods on specific traits, either statically dispatching to a method if "
+"the exact `self`-type of the left-hand-side is known, or dynamically "
+"dispatching if the left-hand-side expression is an indirect [object type]"
+"(#object-types)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1899
+msgid "### Field expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1903
+msgid "~~~~~~~~{.ebnf .gram} field_expr : expr '.' ident ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1907
+msgid ""
+"A _field expression_ consists of an expression followed by a single dot and "
+"an identifier, when not immediately followed by a parenthesized expression-"
+"list (the latter is a [method call expression](#method-call-expressions)). "
+"A field expression denotes a field of a [structure](#structure-types)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1912
+msgid "~~~~~~~~ {.field} myrecord.myfield; {a: 10, b: 20}.a; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1915
+msgid ""
+"A field access on a record is an [lvalue](#lvalues-rvalues-and-temporaries) "
+"referring to the value of that field. When the field is mutable, it can be "
+"[assigned](#assignment-expressions) to."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1918
+msgid ""
+"When the type of the expression to the left of the dot is a pointer to a "
+"record or structure, it is automatically derferenced to make the field "
+"access possible."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1921
+msgid "### Vector expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1924
+msgid "~~~~~~~~{.ebnf .gram} vec_expr : '[' \"mut\"? vec_elems? ']'"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1927
+msgid "vec_elems : [expr [',' expr]*] | [expr ',' \"..\" expr] ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1930
+msgid ""
+"A [_vector_](#vector-types) _expression_ is written by enclosing zero or "
+"more comma-separated expressions of uniform type in square brackets."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1934
+msgid ""
+"In the `[expr ',' \"..\" expr]` form, the expression after the `\"..\"` must "
+"be a constant expression that can be evaluated at compile time, such as a "
+"[literal](#literals) or a [static item](#static-items)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1941
+#, no-wrap
+msgid ""
+"~~~~\n"
+"[1, 2, 3, 4];\n"
+"[\"a\", \"b\", \"c\", \"d\"];\n"
+"[0, ..128]; // vector with 128 zeros\n"
+"[0u8, 0u8, 0u8, 0u8];\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1943
+msgid "### Index expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1947
+msgid "~~~~~~~~{.ebnf .gram} idx_expr : expr '[' expr ']' ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1952
+msgid ""
+"[Vector](#vector-types)-typed expressions can be indexed by writing a square-"
+"bracket-enclosed expression (the index) after them. When the vector is "
+"mutable, the resulting [lvalue](#lvalues-rvalues-and-temporaries) can be "
+"assigned to."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1956
+msgid ""
+"Indices are zero-based, and may be of any integral type. Vector access is "
+"bounds-checked at run-time. When the check fails, it will put the task in a "
+"_failing state_."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1960
+msgid "~~~~ # use std::task; # do task::spawn_unlinked {"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1963
+msgid "([1, 2, 3, 4])[0]; ([\"a\", \"b\"])[10]; // fails"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1966 doc/tutorial-tasks.md:648
+msgid "# } ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1968
+msgid "### Unary operator expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1972
+msgid ""
+"Rust defines six symbolic unary operators. They are all written as prefix "
+"operators, before the expression they apply to."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1991
+#, no-wrap
+msgid ""
+"`-`\n"
+" : Negation. May only be applied to numeric types.\n"
+"`*`\n"
+" : Dereference. When applied to a [pointer](#pointer-types) it denotes the pointed-to location.\n"
+" For pointers to mutable locations, the resulting [lvalue](#lvalues-rvalues-and-temporaries) can be assigned to.\n"
+" For [enums](#enumerated-types) that have only a single variant, containing a single parameter,\n"
+" the dereference operator accesses this parameter.\n"
+"`!`\n"
+" : Logical negation. On the boolean type, this flips between `true` and\n"
+" `false`. On integer types, this inverts the individual bits in the\n"
+" two's complement representation of the value.\n"
+"`@` and `~`\n"
+" : [Boxing](#pointer-types) operators. Allocate a box to hold the value they are applied to,\n"
+" and store the value in it. `@` creates a managed box, whereas `~` creates an owned box.\n"
+"`&`\n"
+" : Borrow operator. Returns a borrowed pointer, pointing to its operand.\n"
+" The operand of a borrowed pointer is statically proven to outlive the resulting pointer.\n"
+" If the borrow-checker cannot prove this, it is a compilation error.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1993
+msgid "### Binary operator expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1997
+msgid "~~~~~~~~{.ebnf .gram} binop_expr : expr binop expr ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2000
+msgid ""
+"Binary operators expressions are given in terms of [operator precedence]"
+"(#operator-precedence)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2002
+msgid "#### Arithmetic operators"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2007
+msgid ""
+"Binary arithmetic expressions are syntactic sugar for calls to built-in "
+"traits, 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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2023
+#, no-wrap
+msgid ""
+"`+`\n"
+" : Addition and vector/string concatenation.\n"
+" Calls the `add` method on the `std::ops::Add` trait.\n"
+"`-`\n"
+" : Subtraction.\n"
+" Calls the `sub` method on the `std::ops::Sub` trait.\n"
+"`*`\n"
+" : Multiplication.\n"
+" Calls the `mul` method on the `std::ops::Mul` trait.\n"
+"`/`\n"
+" : Quotient.\n"
+" Calls the `div` method on the `std::ops::Div` trait.\n"
+"`%`\n"
+" : Remainder.\n"
+" Calls the `rem` method on the `std::ops::Rem` trait.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2025
+msgid "#### Bitwise operators"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2030
+msgid ""
+"Like the [arithmetic operators](#arithmetic-operators), bitwise operators "
+"are syntactic sugar for calls to methods of built-in traits. This means "
+"that bitwise operators can be overridden for user-defined types. The "
+"default meaning of the operators on standard types is given here."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2046
+#, no-wrap
+msgid ""
+"`&`\n"
+" : And.\n"
+" Calls the `bitand` method of the `std::ops::BitAnd` trait.\n"
+"`|`\n"
+" : Inclusive or.\n"
+" Calls the `bitor` method of the `std::ops::BitOr` trait.\n"
+"`^`\n"
+" : Exclusive or.\n"
+" Calls the `bitxor` method of the `std::ops::BitXor` trait.\n"
+"`<<`\n"
+" : Logical left shift.\n"
+" Calls the `shl` method of the `std::ops::Shl` trait.\n"
+"`>>`\n"
+" : Logical right shift.\n"
+" Calls the `shr` method of the `std::ops::Shr` trait.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2048
+msgid "#### Lazy boolean operators"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2055
+msgid ""
+"The operators `||` and `&&` may be applied to operands of boolean type. The "
+"`||` operator denotes logical 'or', and the `&&` operator denotes logical "
+"'and'. They differ from `|` and `&` in that the right-hand operand is only "
+"evaluated when the left-hand operand does not already determine the result "
+"of the expression. That is, `||` only evaluates its right-hand operand when "
+"the left-hand operand evaluates to `false`, and `&&` only when it evaluates "
+"to `true`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2057
+msgid "#### Comparison operators"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2063
+msgid ""
+"Comparison operators are, like the [arithmetic operators](#arithmetic-"
+"operators), and [bitwise operators](#bitwise-operators), syntactic sugar for "
+"calls to built-in traits. This means that comparison operators can be "
+"overridden for user-defined types. The default meaning of the operators on "
+"standard types is given here."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2082
+#, no-wrap
+msgid ""
+"`==`\n"
+" : Equal to.\n"
+" Calls the `eq` method on the `std::cmp::Eq` trait.\n"
+"`!=`\n"
+" : Unequal to.\n"
+" Calls the `ne` method on the `std::cmp::Eq` trait.\n"
+"`<`\n"
+" : Less than.\n"
+" Calls the `lt` method on the `std::cmp::Ord` trait.\n"
+"`>`\n"
+" : Greater than.\n"
+" Calls the `gt` method on the `std::cmp::Ord` trait.\n"
+"`<=`\n"
+" : Less than or equal.\n"
+" Calls the `le` method on the `std::cmp::Ord` trait.\n"
+"`>=`\n"
+" : Greater than or equal.\n"
+" Calls the `ge` method on the `std::cmp::Ord` trait.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2085
+msgid "#### Type cast expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2087
+msgid "A type cast expression is denoted with the binary operator `as`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2090
+msgid ""
+"Executing an `as` expression casts the value on the left-hand side to the "
+"type on the right-hand side."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2094
+msgid ""
+"A numeric value can be cast to any numeric type. A raw pointer value can be "
+"cast to or from any integral type or raw pointer type. Any other cast is "
+"unsupported and will fail to compile."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2096
+msgid "An example of an `as` expression:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2100
+msgid ""
+"~~~~ # fn sum(v: &[float]) -> float { 0.0 } # fn len(v: &[float]) -> int "
+"{ 0 }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2107
+#, no-wrap
+msgid ""
+"fn avg(v: &[float]) -> float {\n"
+" let sum: float = sum(v);\n"
+" let sz: float = len(v) as float;\n"
+" return sum / sz;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2109
+msgid "#### Assignment expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2112
+msgid ""
+"An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-"
+"temporaries) expression followed by an equals sign (`=`) and an [rvalue]"
+"(#lvalues-rvalues-and-temporaries) expression."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2114
+msgid ""
+"Evaluating an assignment expression [either copies or moves](#moved-and-"
+"copied-types) its right-hand operand to its left-hand operand."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2118
+msgid "~~~~ # let mut x = 0; # let y = 0;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2121
+msgid "x = y; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2123
+msgid "#### Compound assignment expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2128
+msgid ""
+"The `+`, `-`, `*`, `/`, `%`, `&`, `|`, `^`, `<<`, and `>>` operators may be "
+"composed with the `=` operator. The expression `lval OP= val` is equivalent "
+"to `lval = lval OP val`. For example, `x = x + 1` may be written as `x += 1`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2130
+msgid "Any such expression always has the [`unit`](#primitive-types) type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2132
+msgid "#### Operator precedence"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2135
+msgid ""
+"The precedence of Rust binary operators is ordered as follows, going from "
+"strong to weak:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2148
+#, no-wrap
+msgid ""
+"~~~~ {.precedence}\n"
+"* / %\n"
+"as\n"
+"+ -\n"
+"<< >>\n"
+"&\n"
+"^\n"
+"|\n"
+"< > <= >=\n"
+"== !=\n"
+"&&\n"
+"||\n"
+"=\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2150 doc/rust.md:2237 doc/tutorial-macros.md:323
+msgid "~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2153
+msgid ""
+"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'."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2155
+msgid "### Grouped expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2159
+msgid ""
+"An expression enclosed in parentheses evaluates to the result of the "
+"enclosed expression. Parentheses can be used to explicitly specify "
+"evaluation order within an expression."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2163
+msgid "~~~~~~~~{.ebnf .gram} paren_expr : '(' expr ')' ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2165
+msgid "An example of a parenthesized expression:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2169
+msgid "~~~~ let x = (2 + 3) * 4; ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2172
+msgid "### Call expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2178
+msgid ""
+"~~~~~~~~ {.abnf .gram} expr_list : [ expr [ ',' expr ]* ] ? ; "
+"paren_expr_list : '(' expr_list ')' ; call_expr : expr paren_expr_list ; "
+"~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2183
+msgid ""
+"A _call expression_ invokes a function, providing zero or more input slots "
+"and an optional reference slot to serve as the function's output, bound to "
+"the `lval` on the right hand side of the call. If the function eventually "
+"returns, then the expression completes."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2185
+msgid "Some examples of call expressions:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2189
+msgid ""
+"~~~~ # use std::from_str::FromStr; # fn add(x: int, y: int) -> int { 0 }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2193
+msgid ""
+"let x: int = add(1, 2); let pi = FromStr::from_str::<f32>(\"3.14\"); ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2195
+msgid "### Lambda expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2200
+msgid ""
+"~~~~~~~~ {.abnf .gram} ident_list : [ ident [ ',' ident ]* ] ? ; "
+"lambda_expr : '|' ident_list '|' expr ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2204
+msgid ""
+"A _lambda expression_ (sometimes called an \"anonymous function expression"
+"\") defines a function and denotes it as a value, in a single expression. A "
+"lambda expression is a pipe-symbol-delimited (`|`) list of identifiers "
+"followed by an expression."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2209
+msgid ""
+"A lambda expression denotes a function that maps a list of parameters "
+"(`ident_list`) onto the expression that follows the `ident_list`. The "
+"identifiers in the `ident_list` are the parameters to the function. These "
+"parameters' types need not be specified, as the compiler infers them from "
+"context."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2212
+msgid ""
+"Lambda expressions are most useful when passing functions as arguments to "
+"other functions, as an abbreviation for defining and capturing a separate "
+"function."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2221
+msgid ""
+"Significantly, lambda expressions _capture their environment_, which regular "
+"[function definitions](#functions) do not. The exact type of capture "
+"depends on the [function type](#function-types) inferred for the lambda "
+"expression. In the simplest and least-expensive form (analogous to a "
+"```&fn() { }``` expression), the lambda expression captures its environment "
+"by reference, effectively borrowing pointers to all outer variables "
+"mentioned inside the function. Alternately, the compiler may infer that a "
+"lambda expression should copy or move values (depending on their type.) "
+"from the environment into the lambda expression's captured environment."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2224
+msgid ""
+"In this example, we define a function `ten_times` that takes a higher-order "
+"function argument, and call it with a lambda expression as an argument."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2233
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn ten_times(f: &fn(int)) {\n"
+" let mut i = 0;\n"
+" while i < 10 {\n"
+" f(i);\n"
+" i += 1;\n"
+" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2235
+msgid "ten_times(|j| println(fmt!(\"hello, %d\", j)));"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2239
+msgid "### While loops"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2243
+msgid ""
+"~~~~~~~~{.ebnf .gram} while_expr : \"while\" expr '{' block '}' ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2248
+msgid ""
+"A `while` loop begins by evaluating the boolean loop conditional "
+"expression. If the loop conditional expression evaluates to `true`, the "
+"loop body block executes and control returns to the loop conditional "
+"expression. If the loop conditional expression evaluates to `false`, the "
+"`while` expression completes."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2250
+msgid "An example:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2253
+msgid "~~~~ let mut i = 0;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2259
+#, no-wrap
+msgid ""
+"while i < 10 {\n"
+" println(\"hello\\n\");\n"
+" i = i + 1;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2261
+msgid "### Infinite loops"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2265
+msgid ""
+"The keyword `loop` in Rust appears both in _loop expressions_ and in "
+"_continue expressions_. A loop expression denotes an infinite loop; see "
+"[Continue expressions](#continue-expressions) for continue expressions."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2269
+msgid ""
+"~~~~~~~~{.ebnf .gram} loop_expr : [ lifetime ':' ] \"loop\" '{' block '}'; "
+"~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2274
+msgid ""
+"A `loop` expression may optionally have a _label_. If a label is present, "
+"then labeled `break` and `loop` expressions nested within this loop may exit "
+"out of this loop or return control to its head. See [Break expressions]"
+"(#break-expressions)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2276
+msgid "### Break expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2280
+msgid "~~~~~~~~{.ebnf .gram} break_expr : \"break\" [ lifetime ]; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2287
+msgid ""
+"A `break` expression has an optional `label`. If the label is absent, then "
+"executing a `break` expression immediately terminates the innermost loop "
+"enclosing it. It is only permitted in the body of a loop. If the label is "
+"present, then `break foo` terminates the loop with label `foo`, which need "
+"not be the innermost label enclosing the `break` expression, but must "
+"enclose it."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2289
+msgid "### Continue expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2293
+msgid "~~~~~~~~{.ebnf .gram} continue_expr : \"loop\" [ lifetime ]; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2304
+msgid ""
+"A continue expression, written `loop`, also has an optional `label`. If the "
+"label is absent, then executing a `loop` expression immediately terminates "
+"the current iteration of the innermost loop enclosing it, returning control "
+"to the loop *head*. In the case of a `while` loop, the head is the "
+"conditional expression controlling the loop. In the case of a `for` loop, "
+"the head is the call-expression controlling the loop. If the label is "
+"present, then `loop foo` returns control to the head of the loop with label "
+"`foo`, which need not be the innermost label enclosing the `break` "
+"expression, but must enclose it."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2306
+msgid "A `loop` expression is only permitted in the body of a loop."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2309
+msgid "### Do expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2313
+msgid ""
+"~~~~~~~~{.ebnf .gram} do_expr : \"do\" expr [ '|' ident_list '|' ] ? '{' "
+"block '}' ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2316
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2324
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2327
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2333
+msgid ""
+"The lambda expression is then provided as a _trailing argument_ to the "
+"outermost [call](#call-expressions) or [method call](#method-call-"
+"expressions) expression in the `expr` following `do`. If the `expr` is a "
+"[path expression](#path-expressions), it is parsed as though it is a call "
+"expression. If the `expr` is a [field expression](#field-expressions), it "
+"is parsed as though it is a method call expression."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2335
+msgid "In this example, both calls to `f` are equivalent:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2339
+msgid "~~~~ # fn f(f: &fn(int)) { } # fn g(i: int) { }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2341
+msgid "f(|j| g(j));"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2346
+#, no-wrap
+msgid ""
+"do f |j| {\n"
+" g(j);\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2348
+msgid ""
+"In this example, both calls to the (binary) function `k` are equivalent:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2352
+msgid "~~~~ # fn k(x:int, f: &fn(int)) { } # fn l(i: int) { }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2354
+msgid "k(3, |j| l(j));"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2359
+#, no-wrap
+msgid ""
+"do k(3) |j| {\n"
+" l(j);\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2362
+msgid "### For expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2366
+msgid ""
+"~~~~~~~~{.ebnf .gram} for_expr : \"for\" expr [ '|' ident_list '|' ] ? '{' "
+"block '}' ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2370
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2376
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2383
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2385
+msgid "An example of a for loop over the contents of a vector:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2392
+msgid ""
+"~~~~ # type foo = int; # fn bar(f: foo) { } # let a = 0; # let b = 0; # let "
+"c = 0;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2394
+msgid "let v: &[foo] = &[a, b, c];"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2399
+#, no-wrap
+msgid ""
+"for e in v.iter() {\n"
+" bar(*e);\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2401
+msgid "An example of a for loop over a series of integers:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2408
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# fn bar(b:uint) { }\n"
+"for i in range(0u, 256) {\n"
+" bar(i);\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2410
+msgid "### If expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2414
+#, no-wrap
+msgid ""
+"~~~~~~~~{.ebnf .gram}\n"
+"if_expr : \"if\" expr '{' block '}'\n"
+" else_tail ? ;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2418
+#, no-wrap
+msgid ""
+"else_tail : \"else\" [ if_expr\n"
+" | '{' block '}' ] ;\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2429
+msgid ""
+"An `if` expression is a conditional branch in program control. The form of "
+"an `if` expression is a condition expression, followed by a consequent "
+"block, any number of `else if` conditions and blocks, and an optional "
+"trailing `else` block. The condition expressions must have type `bool`. If a "
+"condition expression evaluates to `true`, the consequent block is executed "
+"and any subsequent `else if` or `else` block is skipped. If a condition "
+"expression evaluates to `false`, the consequent block is skipped and any "
+"subsequent `else if` condition is evaluated. If all `if` and `else if` "
+"conditions evaluate to `false` then any `else` block is executed."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2432
+msgid "### Match expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2435
+msgid ""
+"~~~~~~~~{.ebnf .gram} match_expr : \"match\" expr '{' match_arm [ '|' "
+"match_arm ] * '}' ;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2437
+msgid "match_arm : match_pat '=>' [ expr \",\" | '{' block '}' ] ;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2440
+msgid "match_pat : pat [ \"..\" pat ] ? [ \"if\" expr ] ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2448
+msgid ""
+"A `match` expression branches on a *pattern*. The exact form of matching "
+"that occurs depends on the pattern. Patterns consist of some combination of "
+"literals, destructured enum constructors, structures, records and tuples, "
+"variable binding specifications, wildcards (`*`), and placeholders (`_`). A "
+"`match` expression has a *head expression*, which is the value to compare to "
+"the patterns. The type of the patterns must equal the type of the head "
+"expression."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2452
+msgid ""
+"In a pattern whose head expression has an `enum` type, a placeholder (`_`) "
+"stands for a *single* data field, whereas a wildcard `*` stands for *all* "
+"the fields of a particular variant. For example:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2455
+msgid "~~~~ enum List<X> { Nil, Cons(X, @List<X>) }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2457 doc/rust.md:2486
+msgid "let x: List<int> = Cons(10, @Cons(11, @Nil));"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2464
+#, no-wrap
+msgid ""
+"match x {\n"
+" Cons(_, @Nil) => fail!(\"singleton list\"),\n"
+" Cons(*) => return,\n"
+" Nil => fail!(\"empty list\")\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2469
+msgid ""
+"The first pattern matches lists constructed by applying `Cons` to any head "
+"value, and a tail value of `@Nil`. The second pattern matches _any_ list "
+"constructed with `Cons`, ignoring the values of its arguments. The "
+"difference between `_` and `*` is that the pattern `C(_)` is only type-"
+"correct if `C` has exactly one argument, while the pattern `C(*)` is type-"
+"correct for any enum variant `C`, regardless of how many arguments `C` has."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2475
+msgid ""
+"To execute an `match` expression, first the head expression is evaluated, "
+"then its value is sequentially compared to the patterns in the arms until a "
+"match is found. The first arm with a matching pattern is chosen as the "
+"branch target of the `match`, any variables bound by the pattern are "
+"assigned to local variables in the arm's block, and control enters the block."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2477
+msgid "An example of an `match` expression:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2482
+msgid "~~~~ # fn process_pair(a: int, b: int) { } # fn process_ten() { }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2484
+msgid "enum List<X> { Nil, Cons(X, @List<X>) }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2502
+#, no-wrap
+msgid ""
+"match x {\n"
+" Cons(a, @Cons(b, _)) => {\n"
+" process_pair(a,b);\n"
+" }\n"
+" Cons(10, _) => {\n"
+" process_ten();\n"
+" }\n"
+" Nil => {\n"
+" return;\n"
+" }\n"
+" _ => {\n"
+" fail!();\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2509
+msgid ""
+"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 changed "
+"to bind to a borrowed pointer by using the ```ref``` keyword, or to a "
+"mutable borrowed pointer using ```ref mut```."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2520
+msgid ""
+"A pattern that's just an identifier, like `Nil` in the previous answer, "
+"could either refer to an enum variant that's in scope, or bind a new "
+"variable. The compiler resolves this ambiguity by forbidding variable "
+"bindings that occur in ```match``` patterns from shadowing names of variants "
+"that are in scope. For example, wherever ```List``` is in scope, a "
+"```match``` pattern would not be able to bind ```Nil``` as a new name. The "
+"compiler interprets a variable pattern `x` as a binding _only_ if there is "
+"no variant named `x` in scope. A convention you can use to avoid conflicts "
+"is simply to name variants with upper-case letters, and local variables with "
+"lower-case letters."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2524
+msgid ""
+"Multiple match patterns may be joined with the `|` operator. A range of "
+"values may be specified with `..`. For example:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2527
+msgid "~~~~ # let x = 2;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2534
+#, no-wrap
+msgid ""
+"let message = match x {\n"
+" 0 | 1 => \"not many\",\n"
+" 2 .. 9 => \"a few\",\n"
+" _ => \"lots\"\n"
+"};\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2538
+msgid ""
+"Range patterns only work on scalar types (like integers and characters; not "
+"like vectors and structs, which have sub-components). A range pattern may "
+"not be a sub-range of another range pattern inside the same `match`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2543
+msgid ""
+"Finally, match patterns can accept *pattern guards* to further refine the "
+"criteria for matching a case. Pattern guards appear after the pattern and "
+"consist of a bool-typed expression following the `if` keyword. A pattern "
+"guard may refer to the variables bound within the pattern they follow."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2548
+msgid ""
+"~~~~ # let maybe_digit = Some(0); # fn process_digit(i: int) { } # fn "
+"process_other(i: int) { }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2555
+#, no-wrap
+msgid ""
+"let message = match maybe_digit {\n"
+" Some(x) if x < 10 => process_digit(x),\n"
+" Some(x) => process_other(x),\n"
+" None => fail!()\n"
+"};\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2557
+msgid "### Return expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2561
+msgid "~~~~~~~~{.ebnf .gram} return_expr : \"return\" expr ? ; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2566
+msgid ""
+"Return expressions are denoted with the keyword `return`. Evaluating a "
+"`return` expression moves its argument into the output slot of the current "
+"function, destroys the current function activation frame, and transfers "
+"control to the caller frame."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2568
+msgid "An example of a `return` expression:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2577
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn max(a: int, b: int) -> int {\n"
+" if a > b {\n"
+" return a;\n"
+" }\n"
+" return b;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2580
+msgid "# Type system"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2582
+msgid "## Types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2585
+msgid ""
+"Every slot, item and value in a Rust program has a type. The _type_ of a "
+"*value* defines the interpretation of the memory holding it."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2589
+msgid ""
+"Built-in types and type-constructors are tightly integrated into the "
+"language, in nontrivial ways that are not possible to emulate in user-"
+"defined types. User-defined types have limited capabilities."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2591
+msgid "### Primitive types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2593
+msgid "The primitive types are the following:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:2599
+msgid ""
+"The \"unit\" type `()`, having the single \"unit\" value `()` (occasionally "
+"called \"nil\"). ^[The \"unit\" value `()` is *not* a sentinel \"null "
+"pointer\" value for reference slots; the \"unit\" type is the implicit "
+"return type from functions otherwise lacking a return type, and can be used "
+"in other contexts (such as message-sending or type-parametric code) as a "
+"zero-size type.]"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:2599
+msgid "The boolean type `bool` with values `true` and `false`."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:2599
+msgid "The machine types."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:2599
+msgid "The machine-dependent integer and floating-point types."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2601
+msgid "#### Machine types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2603
+msgid "The machine types are the following:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:2608
+msgid ""
+"The unsigned word types `u8`, `u16`, `u32` and `u64`, with values drawn from "
+"the integer intervals $[0, 2^8 - 1]$, $[0, 2^{16} - 1]$, $[0, 2^{32} - 1]$ "
+"and $[0, 2^{64} - 1]$ respectively."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:2613
+msgid ""
+"The signed two's complement word types `i8`, `i16`, `i32` and `i64`, with "
+"values drawn from the integer intervals $[-(2^7), 2^7 - 1]$, $[-(2^{15}), "
+"2^{15} - 1]$, $[-(2^{31}), 2^{31} - 1]$, $[-(2^{63}), 2^{63} - 1]$ "
+"respectively."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:2616
+msgid ""
+"The IEEE 754-2008 `binary32` and `binary64` floating-point types: `f32` and "
+"`f64`, respectively."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2618
+msgid "#### Machine-dependent integer types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2623
+msgid ""
+"The Rust type `uint`^[A Rust `uint` is analogous to a C99 `uintptr_t`.] is "
+"an unsigned integer type with target-machine-dependent size. Its size, in "
+"bits, is equal to the number of bits required to hold any memory address on "
+"the target machine."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2628
+msgid ""
+"The Rust type `int`^[A Rust `int` is analogous to a C99 `intptr_t`.] is a "
+"two's complement signed integer type with target-machine-dependent size. Its "
+"size, in bits, is equal to the size of the rust type `uint` on the same "
+"target machine."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2631
+msgid "#### Machine-dependent floating point type"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2638
+msgid ""
+"The Rust type `float` is a machine-specific type equal to one of the "
+"supported Rust floating-point machine types (`f32` or `f64`). It is the "
+"largest floating-point type that is directly supported by hardware on the "
+"target machine, or if the target machine has no floating-point hardware "
+"support, the largest floating-point type supported by the software floating-"
+"point library used to support the other floating-point machine types."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2641
+msgid ""
+"Note that due to the preference for hardware-supported floating-point, the "
+"type `float` may not be equal to the largest *supported* floating-point type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2644
+msgid "### Textual types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2646
+msgid "The types `char` and `str` hold textual data."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2649
+msgid ""
+"A value of type `char` is a Unicode character, represented as a 32-bit "
+"unsigned word holding a UCS-4 codepoint."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2655
+msgid ""
+"A value of type `str` is a Unicode string, represented as a vector of 8-bit "
+"unsigned bytes holding a sequence of UTF-8 codepoints. Since `str` is of "
+"unknown size, it is not a _first class_ type, but can only be instantiated "
+"through a pointer type, such as `&str`, `@str` or `~str`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2658
+msgid "### Tuple types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2661
+msgid ""
+"The tuple type-constructor forms a new heterogeneous product of values "
+"similar to the record type-constructor. The differences are as follows:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:2664
+msgid "tuple elements cannot be mutable, unlike record fields"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:2664
+msgid ""
+"tuple elements are not named and can be accessed only by pattern-matching"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2668
+msgid ""
+"Tuple types and values are denoted by listing the types or values of their "
+"elements, respectively, in a parenthesized, comma-separated list."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2671
+msgid ""
+"The members of a tuple are laid out in memory contiguously, like a record, "
+"in order specified by the tuple type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2673
+msgid "An example of a tuple type and its use:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2680
+msgid ""
+"~~~~ type Pair<'self> = (int,&'self str); let p: Pair<'static> = (10,\"hello"
+"\"); let (a, b) = p; assert!(b != \"world\"); ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2683
+msgid "### Vector types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2696
+msgid ""
+"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.) 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. A vector without such a size is said to be of "
+"_indefinite_ size, and is therefore not a _first-class_ type. An indefinite-"
+"size vector can only be instantiated through a pointer type, such as `&[T]`, "
+"`@[T]` or `~[T]`. The kind of a vector type depends on the kind of its "
+"element type, as with other simple structural types."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2700
+msgid ""
+"Expressions producing vectors of definite size cannot be evaluated in a "
+"context expecting a vector of indefinite size; one must copy the definite-"
+"sized vector contents into a distinct vector of indefinite size."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2702
+msgid "An example of a vector type and its use:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2708
+msgid ""
+"~~~~ let v: &[int] = &[7, 5, 3]; let i: int = v[2]; assert!(i == 3); ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2711
+msgid ""
+"All in-bounds elements of a vector are always initialized, and access to a "
+"vector is always bounds-checked."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2714
+msgid "### Structure types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2719
+msgid ""
+"A `struct` *type* is a heterogeneous product of other types, called the "
+"*fields* of the type. ^[`struct` types are analogous `struct` types in C, "
+"the *record* types of the ML family, or the *structure* types of the Lisp "
+"family.]"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2721
+msgid ""
+"New instances of a `struct` can be constructed with a [struct expression]"
+"(#struct-expressions)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2725
+msgid ""
+"The memory order of fields in a `struct` is given by the item defining it. "
+"Fields may be given in any order in a corresponding struct *expression*; the "
+"resulting `struct` value will always be laid out in memory in the order "
+"specified by the corresponding *item*."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2728
+msgid ""
+"The fields of a `struct` may be qualified by [visibility modifiers]"
+"(#visibility-modifiers), to restrict access to implementation-private data "
+"in a structure."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2730
+msgid ""
+"A _tuple struct_ type is just like a structure type, except that the fields "
+"are anonymous."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2733
+msgid ""
+"A _unit-like struct_ type is like a structure type, except that it has no "
+"fields. The one value constructed by the associated [structure expression]"
+"(#structure-expression) is the only value that inhabits such a type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2735
+msgid "### Enumerated types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2740
+msgid ""
+"An *enumerated type* is a nominal, heterogeneous disjoint union type, "
+"denoted by the name of an [`enum` item](#enumerations). ^[The `enum` type "
+"is analogous to a `data` constructor declaration in ML, or a *pick ADT* in "
+"Limbo.]"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2743
+msgid ""
+"An [`enum` item](#enumerations) declares both the type and a number of "
+"*variant constructors*, each of which is independently named and takes an "
+"optional tuple of arguments."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2746
+msgid ""
+"New instances of an `enum` can be constructed by calling one of the variant "
+"constructors, in a [call expression](#call-expressions)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2748
+msgid ""
+"Any `enum` value consumes as much memory as the largest variant constructor "
+"for its corresponding `enum` type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2751
+msgid ""
+"Enum types cannot be denoted *structurally* as types, but must be denoted by "
+"named reference to an [`enum` item](#enumerations)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2754
+msgid "### Recursive types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2758
+msgid ""
+"Nominal types -- [enumerations](#enumerated-types) and [structures]"
+"(#structure-types) -- may be recursive. That is, each `enum` constructor or "
+"`struct` field may refer, directly or indirectly, to the enclosing `enum` or "
+"`struct` type itself. Such recursion has restrictions:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2768
+#, no-wrap
+msgid ""
+"* Recursive types must include a nominal type in the recursion\n"
+" (not mere [type definitions](#type-definitions),\n"
+" or other structural types such as [vectors](#vector-types) or [tuples](#tuple-types)).\n"
+"* A recursive `enum` item must have at least one non-recursive constructor\n"
+" (in order to give the recursion a basis case).\n"
+"* The size of a recursive type must be finite;\n"
+" in other words the recursive fields of the type must be [pointer types](#pointer-types).\n"
+"* Recursive type definitions can cross module boundaries, but not module *visibility* boundaries,\n"
+" or crate boundaries (in order to simplify the module system and type checker).\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2770
+msgid "An example of a *recursive* type and its use:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2776
+#, no-wrap
+msgid ""
+"~~~~\n"
+"enum List<T> {\n"
+" Nil,\n"
+" Cons(T, @List<T>)\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2779
+msgid "let a: List<int> = Cons(7, @Cons(13, @Nil)); ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2782
+msgid "### Pointer types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2786
+msgid ""
+"All pointers in Rust are explicit first-class values. They can be copied, "
+"stored into data structures, and returned from functions. There are four "
+"varieties of pointer in Rust:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2796
+#, no-wrap
+msgid ""
+"Managed pointers (`@`)\n"
+" : These point to managed heap allocations (or \"boxes\") in the task-local, managed heap.\n"
+" Managed pointers are written `@content`,\n"
+" for example `@int` means a managed pointer to a managed box containing an integer.\n"
+" Copying a managed pointer is a \"shallow\" operation:\n"
+" it involves only copying the pointer itself\n"
+" (as well as any reference-count or GC-barriers required by the managed heap).\n"
+" Dropping a managed pointer does not necessarily release the box it points to;\n"
+" the lifecycles of managed boxes are subject to an unspecified garbage collection algorithm.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2805
+#, no-wrap
+msgid ""
+"Owning pointers (`~`)\n"
+" : These point to owned heap allocations (or \"boxes\") in the shared, inter-task heap.\n"
+" Each owned box has a single owning pointer; pointer and pointee retain a 1:1 relationship at all times.\n"
+" Owning pointers are written `~content`,\n"
+" for example `~int` means an owning pointer to an owned box containing an integer.\n"
+" Copying an owned box is a \"deep\" operation:\n"
+" it involves allocating a new owned box and copying the contents of the old box into the new box.\n"
+" Releasing an owning pointer immediately releases its corresponding owned box.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2818
+#, no-wrap
+msgid ""
+"Borrowed pointers (`&`)\n"
+" : These point to memory _owned by some other value_.\n"
+" Borrowed pointers arise by (automatic) conversion from owning pointers, managed pointers,\n"
+" or by applying the borrowing operator `&` to some other value,\n"
+" including [lvalues, rvalues or temporaries](#lvalues-rvalues-and-temporaries).\n"
+" Borrowed pointers are written `&content`, or in some cases `&f/content` for some lifetime-variable `f`,\n"
+" for example `&int` means a borrowed pointer to an integer.\n"
+" Copying a borrowed pointer is a \"shallow\" operation:\n"
+" it involves only copying the pointer itself.\n"
+" Releasing a borrowed pointer typically has no effect on the value it points to,\n"
+" with the exception of temporary values,\n"
+" which are released when the last borrowed pointer to them is released.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2828
+#, no-wrap
+msgid ""
+"Raw pointers (`*`)\n"
+" : Raw pointers are pointers without safety or liveness guarantees.\n"
+" Raw pointers are written `*content`,\n"
+" for example `*int` means a raw pointer to an integer.\n"
+" Copying or dropping a raw pointer is has no effect on the lifecycle of any other value.\n"
+" Dereferencing a raw pointer or converting it to any other pointer type is an [`unsafe` operation](#unsafe-functions).\n"
+" Raw pointers are generally discouraged in Rust code;\n"
+" they exist to support interoperability with foreign code,\n"
+" and writing performance-critical or low-level functions.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2831
+msgid "### Function types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2835
+msgid ""
+"The function type constructor `fn` forms new function types. A function "
+"type consists of a possibly-empty set of function-type modifiers (such as "
+"`unsafe` or `extern`), a sequence of input types and an output type."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2837
+msgid "An example of a `fn` type:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2842
+#, no-wrap
+msgid ""
+"~~~~~~~~\n"
+"fn add(x: int, y: int) -> int {\n"
+" return x + y;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2844
+msgid "let mut x = add(5,7);"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2849
+msgid ""
+"type Binop<'self> = &'self fn(int,int) -> int; let bo: Binop = add; x = "
+"bo(5,7); ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2851
+msgid "### Object types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2858
+msgid ""
+"Every trait item (see [traits](#traits)) defines a type with the same name "
+"as the trait. This type is called the _object type_ of the trait. Object "
+"types permit \"late binding\" of methods, dispatched using _virtual method "
+"tables_ (\"vtables\"). Whereas most calls to trait methods are \"early bound"
+"\" (statically resolved) to specific implementations at compile time, a call "
+"to a method on an object type is only resolved to a vtable entry at compile "
+"time. The actual implementation for each vtable entry can vary on an object-"
+"by-object basis."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2863
+msgid ""
+"Given a pointer-typed expression `E` of type `&T`, `~T` or `@T`, where `T` "
+"implements trait `R`, casting `E` to the corresponding pointer type `&R`, "
+"`~R` or `@R` results in a value of the _object type_ `R`. This result is "
+"represented as a pair of pointers: the vtable pointer for the `T` "
+"implementation of `R`, and the pointer value of `E`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2865
+msgid "An example of an object type:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2871
+#, no-wrap
+msgid ""
+"~~~~~~~~\n"
+"# use std::int;\n"
+"trait Printable {\n"
+" fn to_str(&self) -> ~str;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2875
+#, no-wrap
+msgid ""
+"impl Printable for int {\n"
+" fn to_str(&self) -> ~str { int::to_str(*self) }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2879
+#, no-wrap
+msgid ""
+"fn print(a: @Printable) {\n"
+" println(a.to_str());\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2884
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" print(@10 as @Printable);\n"
+"}\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2887
+msgid ""
+"In this example, the trait `Printable` occurs as an object type in both the "
+"type signature of `print`, and the cast expression in `main`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2889
+msgid "### Type parameters"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2891
+msgid ""
+"Within the body of an item that has type parameter declarations, the names "
+"of its type parameters are types:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2902
+#, no-wrap
+msgid ""
+"~~~~~~~\n"
+"fn map<A: Clone, B: Clone>(f: &fn(A) -> B, xs: &[A]) -> ~[B] {\n"
+" if xs.len() == 0 {\n"
+" return ~[];\n"
+" }\n"
+" let first: B = f(xs[0].clone());\n"
+" let rest: ~[B] = map(f, xs.slice(1, xs.len()));\n"
+" return ~[first] + rest;\n"
+"}\n"
+"~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2905
+msgid ""
+"Here, `first` has type `B`, referring to `map`'s `B` type parameter; and "
+"`rest` has type `~[B]`, a vector type with element type `B`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2907
+msgid "### Self types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2911
+msgid ""
+"The special type `self` has a meaning within methods inside an impl item. It "
+"refers to the type of the implicit `self` argument. For example, in:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2916
+#, no-wrap
+msgid ""
+"~~~~~~~~\n"
+"trait Printable {\n"
+" fn make_string(&self) -> ~str;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2923
+#, no-wrap
+msgid ""
+"impl Printable for ~str {\n"
+" fn make_string(&self) -> ~str {\n"
+" (*self).clone()\n"
+" }\n"
+"}\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2926
+msgid ""
+"`self` refers to the value of type `~str` that is the receiver for a call to "
+"the method `make_string`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2928
+msgid "## Type kinds"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2931
+msgid ""
+"Types in Rust are categorized into kinds, based on various properties of the "
+"components of the type. The kinds are:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2957
+#, no-wrap
+msgid ""
+"`Freeze`\n"
+" : Types of this kind are deeply immutable;\n"
+" they contain no mutable memory locations\n"
+" directly or indirectly via pointers.\n"
+"`Send`\n"
+" : Types of this kind can be safely sent between tasks.\n"
+" This kind includes scalars, owning pointers, owned closures, and\n"
+" structural types containing only other owned types.\n"
+" All `Send` types are `'static`.\n"
+"`'static`\n"
+" : Types of this kind do not contain any borrowed pointers;\n"
+" this can be a useful guarantee for code\n"
+" that breaks borrowing assumptions\n"
+" using [`unsafe` operations](#unsafe-functions).\n"
+"`Drop`\n"
+" : This is not strictly a kind,\n"
+" but its presence interacts with kinds:\n"
+" the `Drop` trait provides a single method `drop`\n"
+" that takes no parameters,\n"
+" and is run when values of the type are dropped.\n"
+" Such a method is called a \"destructor\",\n"
+" and are always executed in \"top-down\" order:\n"
+" a value is completely destroyed\n"
+" before any of the values it owns run their destructors.\n"
+" Only `Send` types can implement `Drop`.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2964
+#, no-wrap
+msgid ""
+"_Default_\n"
+" : Types with destructors, closure environments,\n"
+" and various other _non-first-class_ types,\n"
+" are not copyable at all.\n"
+" Such types can usually only be accessed through pointers,\n"
+" or in some cases, moved between mutable locations.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2967
+msgid ""
+"Kinds can be supplied as _bounds_ on type parameters, like traits, in which "
+"case the parameter is constrained to types satisfying that kind."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2973
+msgid ""
+"By default, type parameters do not carry any assumed kind-bounds at all. "
+"When instantiating a type parameter, the kind bounds on the parameter are "
+"checked to be the same or narrower than the kind of the type that it is "
+"instantiated with."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2978
+msgid ""
+"Sending operations are not part of the Rust language, but are implemented in "
+"the library. Generic functions that send values bound the kind of these "
+"values to sendable."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2980
+msgid "# Memory and concurrency models"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2985
+msgid ""
+"Rust has a memory model centered around concurrently-executing _tasks_. Thus "
+"its memory model and its concurrency model are best discussed "
+"simultaneously, as parts of each only make sense when considered from the "
+"perspective of the other."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2990
+msgid ""
+"When reading about the memory model, keep in mind that it is partitioned in "
+"order to support tasks; and when reading about tasks, keep in mind that "
+"their isolation and communication mechanisms are only possible due to the "
+"ownership and lifetime semantics of the memory model."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2992
+msgid "## Memory model"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2996
+msgid ""
+"A Rust program's memory consists of a static set of *items*, a set of [tasks]"
+"(#tasks) each with its own *stack*, and a *heap*. Immutable portions of the "
+"heap may be shared between tasks, mutable portions may not."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:2999
+msgid ""
+"Allocations in the stack consist of *slots*, and allocations in the heap "
+"consist of *boxes*."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3002
+msgid "### Memory allocation and lifetime"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3007
+msgid ""
+"The _items_ of a program are those functions, modules and types that have "
+"their value calculated at compile-time and stored uniquely in the memory "
+"image of the rust process. Items are neither dynamically allocated nor freed."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3011
+msgid ""
+"A task's _stack_ consists of activation frames automatically allocated on "
+"entry to each function as the task executes. A stack allocation is reclaimed "
+"when control leaves the frame containing it."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3018
+msgid ""
+"The _heap_ is a general term that describes two separate sets of boxes: "
+"managed boxes -- which may be subject to garbage collection -- and owned "
+"boxes. The lifetime of an allocation in the heap depends on the lifetime of "
+"the box values pointing to it. Since box values may themselves be passed in "
+"and out of frames, or stored in the heap, heap allocations may outlive the "
+"frame they are allocated within."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3020
+msgid "### Memory ownership"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3023
+msgid ""
+"A task owns all memory it can *safely* reach through local variables, as "
+"well as managed, owning and borrowed pointers."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3030
+msgid ""
+"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 `Send` trait: it is only instantiated for "
+"(transitively) sendable kinds of data constructor and pointers, never "
+"including managed or borrowed pointers."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3033
+msgid ""
+"When a stack frame is exited, its local allocations are all released, and "
+"its references to boxes (both managed and owned) are dropped."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3039
+msgid ""
+"A managed box may (in the case of a recursive, mutable managed type) be "
+"cyclic; in this case the release of memory inside the managed structure may "
+"be deferred until task-local garbage collection can reclaim it. Code can "
+"ensure no such delayed deallocation occurs by restricting itself to owned "
+"boxes and similar unmanaged kinds of data."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3042
+msgid ""
+"When a task finishes, its stack is necessarily empty and it therefore has no "
+"references to any boxes; the remainder of its heap is immediately freed."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3045
+msgid "### Memory slots"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3047
+msgid "A task's stack contains slots."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3050
+msgid ""
+"A _slot_ is a component of a stack frame, either a function parameter, a "
+"[temporary](#lvalues-rvalues-and-temporaries), or a local variable."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3053
+msgid ""
+"A _local variable_ (or *stack-local* allocation) holds a value directly, "
+"allocated within the stack's memory. The value is a part of the stack frame."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3058
+msgid ""
+"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 `y`)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3063
+msgid ""
+"Function parameters are immutable unless declared with `mut`. The `mut` "
+"keyword applies only to the following parameter (so `|mut x, y|` and `fn "
+"f(mut x: ~int, y: ~int)` declare one mutable variable `x` and one immutable "
+"variable `y`)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3069
+msgid ""
+"Local variables are not initialized when allocated; the entire frame worth "
+"of local variables are allocated at once, on frame-entry, in an "
+"uninitialized state. Subsequent statements within a function may or may not "
+"initialize the local variables. Local variables can be used only after they "
+"have been initialized; this is enforced by the compiler."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3072
+msgid "### Memory boxes"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3075
+msgid ""
+"A _box_ is a reference to a heap allocation holding another value. There are "
+"two kinds of boxes: *managed boxes* and *owned boxes*."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3077
+msgid ""
+"A _managed box_ type or value is constructed by the prefix *at* sigil `@`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3079
+msgid ""
+"An _owned box_ type or value is constructed by the prefix *tilde* sigil `~`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3084
+msgid ""
+"Multiple managed box values can point to the same heap allocation; copying a "
+"managed box value makes a shallow copy of the pointer (optionally "
+"incrementing a reference count, if the managed box is implemented through "
+"reference-counting)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3086
+msgid ""
+"Owned box values exist in 1:1 correspondence with their heap allocation."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3089
+msgid ""
+"An example of constructing one managed box type and value, and one owned box "
+"type and value:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3094
+msgid "~~~~~~~~ let x: @int = @10; let x: ~int = ~10; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3097
+msgid ""
+"Some operations (such as field selection) implicitly dereference boxes. An "
+"example of an _implicit dereference_ operation performed on box values:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3103
+msgid ""
+"~~~~~~~~ struct Foo { y: int } let x = @Foo{y: 10}; assert!(x.y == 10); "
+"~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3109
+msgid ""
+"Other operations act on box values as single-word-sized address values. For "
+"these operations, to access the value held in the box requires an explicit "
+"dereference of the box value. Explicitly dereferencing a box is indicated "
+"with the unary *star* operator `*`. Examples of such _explicit dereference_ "
+"operations are:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3112
+msgid "copying box values (`x = y`)"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3112
+msgid "passing box values to functions (`f(x,y)`)"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3115
+msgid ""
+"An example of an explicit-dereference operation performed on box values:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3119
+msgid "~~~~~~~~ fn takes_boxed(b: @int) { }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3122
+msgid "fn takes_unboxed(b: int) { }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3129
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" let x: @int = @10;\n"
+" takes_boxed(x);\n"
+" takes_unboxed(*x);\n"
+"}\n"
+"~~~~~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3131
+msgid "## Tasks"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3139
+msgid ""
+"An executing Rust program consists of a tree of tasks. A Rust _task_ "
+"consists of an entry function, a stack, a set of outgoing communication "
+"channels and incoming communication ports, and ownership of some portion of "
+"the heap of a single operating-system process. (We expect that many "
+"programs will not use channels and ports directly, but will instead use "
+"higher-level abstractions provided in standard libraries, such as pipes.)"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3154
+msgid ""
+"Multiple Rust tasks may coexist in a single operating-system process. The "
+"runtime scheduler maps tasks to a certain number of operating-system "
+"threads. By default, the scheduler chooses the number of threads based on "
+"the number of concurrent physical CPUs detected at startup. It's also "
+"possible to override this choice at runtime. When the number of tasks "
+"exceeds the number of threads -- which is likely -- the scheduler "
+"multiplexes the tasks onto threads.^[ This is an M:N scheduler, which is "
+"known to give suboptimal results for CPU-bound concurrency problems. In "
+"such cases, running with the same number of threads and tasks can yield "
+"better results. Rust has M:N scheduling in order to support very large "
+"numbers of tasks in contexts where threads are too resource-intensive to use "
+"in large number. The cost of threads varies substantially per operating "
+"system, and is sometimes quite low, so this flexibility is not always worth "
+"exploiting.]"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3157
+msgid "### Communication between tasks"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3162
+msgid ""
+"Rust tasks are isolated and generally unable to interfere with one another's "
+"memory directly, except through [`unsafe` code](#unsafe-functions). All "
+"contact between tasks is mediated by safe forms of ownership transfer, and "
+"data races on memory are prohibited by the type system."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3165
+msgid ""
+"Inter-task communication and co-ordination facilities are provided in the "
+"standard library. These include:"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:3169
+msgid ""
+"synchronous and asynchronous communication channels with various "
+"communication topologies"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:3169
+msgid ""
+"read-only and read-write shared variables with various safe mutual exclusion "
+"patterns"
+msgstr ""
+
+#. type: Bullet: ' - '
+#: doc/rust.md:3169
+msgid "simple locks and semaphores"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3174
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3177
+msgid "### Task lifecycle"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3180
+msgid ""
+"The _lifecycle_ of a task consists of a finite set of states and events that "
+"cause transitions between the states. The lifecycle states of a task are:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3185
+msgid "running"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3185
+msgid "blocked"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3185
+msgid "failing"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3185
+msgid "dead"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3189
+msgid ""
+"A task begins its lifecycle -- once it has been spawned -- in the *running* "
+"state. In this state it executes the statements of its entry function, and "
+"any functions called by the entry function."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3195
+msgid ""
+"A task may transition from the *running* state to the *blocked* state any "
+"time it makes a blocking communication call. When the call can be completed "
+"-- when a message arrives at a sender, or a buffer opens to receive a "
+"message -- then the blocked task will unblock and transition back to "
+"*running*."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3214
+msgid ""
+"A task may transition to the *failing* state at any time, due being killed "
+"by some external event or internally, from the evaluation of a `fail!()` "
+"macro. Once *failing*, a task unwinds its stack and transitions to the "
+"*dead* state. Unwinding the stack of a task is done by the task itself, on "
+"its own control stack. If a value with a destructor is freed during "
+"unwinding, the code for the destructor is run, also on the task's control "
+"stack. Running the destructor code causes a temporary transition to a "
+"*running* state, and allows the destructor code to cause any subsequent "
+"state transitions. The original task of unwinding and failing thereby may "
+"suspend temporarily, and may involve (recursive) unwinding of the stack of a "
+"failed destructor. Nonetheless, the outermost unwinding activity will "
+"continue until the stack is unwound and the task transitions to the *dead* "
+"state. There is no way to \"recover\" from task failure. Once a task has "
+"temporarily suspended its unwinding in the *failing* state, failure "
+"occurring from within this destructor results in *hard* failure. The "
+"unwinding procedure of hard failure frees resources but does not execute "
+"destructors. The original (soft) failure is still resumed at the point "
+"where it was temporarily suspended."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3218
+msgid ""
+"A task in the *dead* state cannot transition to other states; it exists only "
+"to have its termination status inspected by other tasks, and/or to await "
+"reclamation when the last reference to it drops."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3221
+msgid "### Task scheduling"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3225
+msgid ""
+"The currently scheduled task is given a finite *time slice* in which to "
+"execute, after which it is *descheduled* at a loop-edge or similar "
+"preemption point, and another task within is scheduled, pseudo-randomly."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3229
+msgid ""
+"An executing task can yield control at any time, by making a library call to "
+"`std::task::yield`, which deschedules it immediately. Entering any other non-"
+"executing state (blocked, dead) similarly deschedules the task."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3232
+msgid "# Runtime services, linkage and debugging"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3239
+msgid ""
+"The Rust _runtime_ is a relatively compact collection of C++ and Rust code "
+"that provides fundamental services and datatypes to all Rust tasks at 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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3241
+msgid ""
+"> **Note:** The runtime library will merge with the `std` library in future "
+"versions of Rust."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3243
+msgid "### Memory allocation"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3249
+msgid ""
+"The runtime memory-management system is based on a _service-provider "
+"interface_, through which the runtime requests blocks of memory from its "
+"environment and releases them back to its environment when they are no "
+"longer needed. The default implementation of the service-provider interface "
+"consists of the C runtime functions `malloc` and `free`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3253
+msgid ""
+"The runtime memory-management system, in turn, supplies Rust tasks with "
+"facilities for allocating, extending and releasing stacks, as well as "
+"allocating and freeing heap data."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3255
+msgid "### Built in types"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3259
+msgid ""
+"The runtime provides C and Rust code to assist with various built-in types, "
+"such as vectors, strings, and the low level communication system (ports, "
+"channels, tasks)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3262
+msgid ""
+"Support for other built-in types such as simple types, tuples, records, and "
+"enums is open-coded by the Rust compiler."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3266
+msgid "### Task scheduling and communication"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3272
+msgid ""
+"The runtime provides code to manage inter-task communication. This includes "
+"the system of task-lifecycle state transitions depending on the contents of "
+"queues, as well as code to copy values between queues and their recipients "
+"and to serialize values for transmission over operating-system inter-process "
+"communication facilities."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3275
+msgid "### Logging system"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3279
+msgid ""
+"The runtime contains a system for directing [logging expressions](#log-"
+"expressions) to a logging console and/or internal logging buffers. Logging "
+"can be enabled per module."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3286
+msgid ""
+"Logging output is enabled by setting the `RUST_LOG` environment variable. "
+"`RUST_LOG` accepts a logging specification made up of a comma-separated list "
+"of paths, with optional log levels. For each module containing log "
+"expressions, if `RUST_LOG` contains the path to that module or a parent of "
+"that module, then logs of the appropriate level will be output to the "
+"console."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3294
+msgid ""
+"The path to a module consists of the crate name, any parent modules, then "
+"the module itself, all separated by double colons (`::`). The optional log "
+"level can be appended to the module path with an equals sign (`=`) followed "
+"by the log level, from 1 to 4, inclusive. Level 1 is the error level, 2 is "
+"warning, 3 info, and 4 debug. Any logs less than or equal to the specified "
+"level will be output. If not specified then log level 4 is assumed."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3300
+msgid ""
+"As an example, to see all the logs generated by the compiler, you would set "
+"`RUST_LOG` to `rustc`, which is the crate name (as specified in its `link` "
+"[attribute](#attributes)). To narrow down the logs to just crate resolution, "
+"you would set it to `rustc::metadata::creader`. To see just error logging "
+"use `rustc=0`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3305
+msgid ""
+"Note that when compiling source files that don't specify a crate name the "
+"crate is given a default name that matches the source file, with the "
+"extension removed. In that case, to turn on logging for a program compiled "
+"from, e.g. `helloworld.rs`, `RUST_LOG` should be set to `helloworld`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3309
+msgid ""
+"As a convenience, the logging spec can also be set to a special pseudo-"
+"crate, `::help`. In this case, when the application starts, the runtime will "
+"simply output a list of loaded modules containing log expressions, then exit."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3314
+msgid ""
+"The Rust runtime itself generates logging information. The runtime's logs "
+"are generated for a number of artificial modules in the `::rt` pseudo-crate, "
+"and can be enabled just like the logs for any standard module. The full list "
+"of runtime logging modules follows."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::mem` Memory management"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::comm` Messaging and task communication"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::task` Task management"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::dom` Task scheduling"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::trace` Unused"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::cache` Type descriptor cache"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::upcall` Compiler-generated runtime calls"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::timer` The scheduler timer"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::gc` Garbage collection"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::stdlib` Functions used directly by the standard library"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::kern` The runtime kernel"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::backtrace` Log a backtrace on task failure"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3328
+msgid "`::rt::callback` Unused"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3330
+msgid "#### Logging Expressions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3333
+msgid ""
+"Rust provides several macros to log information. Here's a simple Rust "
+"program that demonstrates all four of them:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3342
+#, no-wrap
+msgid ""
+"```rust\n"
+"fn main() {\n"
+" error!(\"This is an error log\")\n"
+" warn!(\"This is a warn log\")\n"
+" info!(\"this is an info log\")\n"
+" debug!(\"This is a debug log\")\n"
+"}\n"
+"```\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3344
+msgid ""
+"These four log levels correspond to levels 1-4, as controlled by `RUST_LOG`:"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3351
+msgid ""
+"```bash $ RUST_LOG=rust=3 ./rust rust: ~\"\\\"This is an error log\\\"\" "
+"rust: ~\"\\\"This is a warn log\\\"\" rust: ~\"\\\"this is an info log\\\"\" "
+"```"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3353
+msgid "# Appendix: Rationales and design tradeoffs"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3355
+#, no-wrap
+msgid "*TODO*.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3357
+msgid "# Appendix: Influences and further references"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3359
+msgid "## Influences"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3368
+msgid ""
+"> The essential problem that must be solved in making a fault-tolerant > "
+"software system is therefore that of fault-isolation. Different programmers "
+"> will write different modules, some modules will be correct, others will "
+"have > errors. We do not want the errors in one module to adversely affect "
+"the > behaviour of a module which does not have any errors. > > — Joe "
+"Armstrong"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3380
+msgid ""
+"> In our approach, all data is private to some process, and processes can > "
+"only communicate through communications channels. *Security*, as used > in "
+"this paper, is the property which guarantees that processes in a system > "
+"cannot affect each other except by explicit communication. > > When "
+"security is absent, nothing which can be proven about a single module > in "
+"isolation can be guaranteed to hold when that module is embedded in a > "
+"system [...] > > — Robert Strom and Shaula Yemini"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3388
+msgid ""
+"> Concurrent and applicative programming complement each other. The > "
+"ability to send messages on channels provides I/O without side effects, > "
+"while the avoidance of shared data helps keep concurrent processes from > "
+"colliding. > > — Rob Pike"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3395
+msgid ""
+"Rust is not a particularly original language. It may however appear unusual "
+"by contemporary standards, as its design elements are drawn from a number of "
+"\"historical\" languages that have, with a few exceptions, fallen out of "
+"favour. Five prominent lineages contribute the most, though their influences "
+"have come and gone during the course of Rust's development:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3399
+msgid ""
+"The NIL (1981) and Hermes (1990) family. These languages were developed by "
+"Robert Strom, Shaula Yemini, David Bacon and others in their group at IBM "
+"Watson Research Center (Yorktown Heights, NY, USA)."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3403
+msgid ""
+"The Erlang (1987) language, developed by Joe Armstrong, Robert Virding, "
+"Claes Wikström, Mike Williams and others in their group at the Ericsson "
+"Computer Science Laboratory (Älvsjö, Stockholm, Sweden) ."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3408
+msgid ""
+"The Sather (1990) language, developed by Stephen Omohundro, Chu-Cheow Lim, "
+"Heinz Schmidt and others in their group at The International Computer "
+"Science Institute of the University of California, Berkeley (Berkeley, CA, "
+"USA)."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3413
+msgid ""
+"The Newsqueak (1988), Alef (1995), and Limbo (1996) family. These languages "
+"were developed by Rob Pike, Phil Winterbottom, Sean Dorward and others in "
+"their group at Bell Labs Computing Sciences Research Center (Murray Hill, "
+"NJ, USA)."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3417
+msgid ""
+"The Napier (1985) and Napier88 (1988) family. These languages were developed "
+"by Malcolm Atkinson, Ron Morrison and others in their group at the "
+"University of St. Andrews (St. Andrews, Fife, UK)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:3419
+msgid ""
+"Additional specific influences can be seen from the following languages:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3427
+msgid "The stack-growth implementation of Go."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3427
+msgid "The structural algebraic types and compilation manager of SML."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3427
+msgid "The attribute and assembly systems of C#."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3427
+msgid "The references and deterministic destructor system of C++."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3427
+msgid "The memory region systems of the ML Kit and Cyclone."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3427
+msgid "The typeclass system of Haskell."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3427
+msgid "The lexical identifier rule of Python."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rust.md:3427
+msgid "The block syntax of Ruby."
+msgstr ""
--- /dev/null
+# Japanese translations for Rust package
+# Copyright (C) 2013 The Rust Project Developers
+# This file is distributed under the same license as the Rust package.
+# Automatically generated, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Rust 0.8-pre\n"
+"POT-Creation-Date: 2013-07-30 07:07+0900\n"
+"PO-Revision-Date: 2013-07-28 20:32+0900\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: none\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#. type: Plain text
+#: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
+#: doc/tutorial-borrowed-ptr.md:4 doc/tutorial-ffi.md:4
+#: doc/tutorial-macros.md:4 doc/tutorial-tasks.md:4
+msgid "# Introduction"
+msgstr "# イントロダクション"
+
+#. type: Plain text
+#: doc/rust.md:30 doc/rustpkg.md:8
+msgid "## Disclaimer"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:2
+msgid "% Rustpkg Reference Manual"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:6
+msgid ""
+"This document is the reference manual for the Rustpkg packaging and build "
+"tool for the Rust programming language."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:12
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:14
+msgid "# Package searching"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:17
+msgid ""
+"rustpkg searches for packages using the `RUST_PATH` environment variable, "
+"which is a colon-separated list (semicolon-separated on Windows) of "
+"directories."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:19
+msgid "Each directory in this list is a *workspace* for rustpkg."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:30
+msgid ""
+"`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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:32
+msgid "Each workspace may contain one or more packages."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:38
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:40
+msgid "# Package structure"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:42
+msgid "A valid workspace must contain each of the following subdirectories:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rustpkg.md:44
+msgid ""
+"'src/': contains one subdirectory per package. Each subdirectory contains "
+"source files for a given package."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:49
+#, no-wrap
+msgid ""
+" For example, if `foo` is a workspace containing the package `bar`,\n"
+" then `foo/src/bar/main.rs` could be the `main` entry point for\n"
+" building a `bar` executable.\n"
+"* 'lib/': `rustpkg install` installs libraries into a target-specific subdirectory of this directory.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:56
+#, no-wrap
+msgid ""
+" For example, on a 64-bit machine running Mac OS X,\n"
+" if `foo` is a workspace containing the package `bar`,\n"
+" rustpkg will install libraries for bar to `foo/lib/x86_64-apple-darwin/`.\n"
+" The libraries will have names of the form `foo/lib/x86_64-apple-darwin/libbar-[hash].dylib`,\n"
+" where [hash] is a hash of the package ID.\n"
+"* 'bin/': `rustpkg install` installs executable binaries into a target-specific subdirectory of this directory.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:63
+#, no-wrap
+msgid ""
+" For example, on a 64-bit machine running Mac OS X,\n"
+" if `foo` is a workspace, containing the package `bar`,\n"
+" rustpkg will install executables for `bar` to\n"
+" `foo/bin/x86_64-apple-darwin/`.\n"
+" The executables will have names of the form `foo/bin/x86_64-apple-darwin/bar`.\n"
+"* 'build/': `rustpkg build` stores temporary build artifacts in a target-specific subdirectory of this directory.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:67
+#, no-wrap
+msgid ""
+" For example, on a 64-bit machine running Mac OS X,\n"
+" if `foo` is a workspace containing the package `bar` and `foo/src/bar/main.rs` exists,\n"
+" then `rustpkg build` will create `foo/build/x86_64-apple-darwin/bar/main.o`.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:69
+msgid "# Package identifiers"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:87
+msgid ""
+"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. A package ID can also specify a particular revision of a "
+"repository, like: `github.com/mozilla/rust#release-0.7`. When the refspec "
+"(portion of the package ID after the `#`) can't be parsed as a decimal "
+"number, rustpkg passes the refspec along to the version control system "
+"without interpreting it. rustpkg also interprets any dependencies on such a "
+"package ID literally (as opposed to versions, where a newer version "
+"satisfies a dependency on an older version). Thus, `github.com/mozilla/"
+"rust#5c4cd30f80` is also a valid package ID, since git can deduce that "
+"5c4cd30f80 refers to a revision of the desired repository."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:89
+msgid "## Source files"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:91
+msgid ""
+"rustpkg searches for four different fixed filenames in order to determine "
+"the crates to build:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rustpkg.md:96
+msgid "`main.rs`: Assumed to be a main entry point for building an executable."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rustpkg.md:96
+msgid "`lib.rs`: Assumed to be a library crate."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rustpkg.md:96
+msgid ""
+"`test.rs`: Assumed to contain tests declared with the `#[test]` attribute."
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/rustpkg.md:96
+msgid ""
+"`bench.rs`: Assumed to contain benchmarks declared with the `#[bench]` "
+"attribute."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:98
+msgid "## Versions"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:105
+msgid ""
+"`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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:107
+msgid "# Dependencies"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:111
+msgid ""
+"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.)"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:113
+msgid "# Custom build scripts"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:117
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:121
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:123
+msgid "# Command reference"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:125
+msgid "## build"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:131
+msgid ""
+"`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."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:133
+msgid "## clean"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:135
+msgid "`rustpkg clean foo` deletes the contents of `foo`'s `build` directory."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:137
+msgid "## install"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:141
+msgid ""
+"`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`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:143
+msgid "## test"
+msgstr ""
+
+#. type: Plain text
+#: doc/rustpkg.md:145
+msgid ""
+"`rustpkg test foo` builds `foo`'s `test.rs` file if necessary, then runs the "
+"resulting test executable."
+msgstr ""
--- /dev/null
+# Japanese translations for Rust package
+# Copyright (C) 2013 The Rust Project Developers
+# This file is distributed under the same license as the Rust package.
+# Automatically generated, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Rust 0.8-pre\n"
+"POT-Creation-Date: 2013-07-22 23:37+0900\n"
+"PO-Revision-Date: 2013-07-28 20:32+0900\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: none\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#. type: Plain text
+#: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
+#: doc/tutorial-borrowed-ptr.md:4 doc/tutorial-ffi.md:4
+#: doc/tutorial-macros.md:4 doc/tutorial-tasks.md:4
+msgid "# Introduction"
+msgstr "# イントロダクション"
+
+#. type: Plain text
+#: doc/tutorial.md:1108 doc/tutorial-borrowed-ptr.md:72
+msgid "Now we can call `compute_distance()` in various ways:"
+msgstr ""
+"上記の `compute_distance()` 関数は、様々な方法で呼び出すことができます。"
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:2
+msgid "% Rust Borrowed Pointers Tutorial"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:14
+msgid ""
+"Borrowed pointers are one of the more flexible and powerful tools available "
+"in Rust. A borrowed pointer can point anywhere: into the managed or exchange "
+"heap, into the stack, and even into the interior of another data structure. "
+"A borrowed pointer is as flexible as a C pointer or C++ reference. However, "
+"unlike C and C++ compilers, the Rust compiler includes special static checks "
+"that ensure that programs use borrowed pointers safely. Another advantage of "
+"borrowed pointers is that they are invisible to the garbage collector, so "
+"working with borrowed pointers helps reduce the overhead of automatic memory "
+"management."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:18
+msgid ""
+"Despite their complete safety, a borrowed pointer's representation at "
+"runtime is the same as that of an ordinary pointer in a C program. They "
+"introduce zero overhead. The compiler does all safety checks at compile time."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:24
+msgid ""
+"Although borrowed pointers have rather elaborate theoretical underpinnings "
+"(region pointers), the core concepts will be familiar to anyone who has "
+"worked with C or C++. Therefore, the best way to explain how they are used—"
+"and their limitations—is probably just to work through several examples."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:26
+msgid "# By example"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:31
+msgid ""
+"Borrowed pointers are called *borrowed* because they are only valid for a "
+"limited duration. Borrowed pointers never claim any kind of ownership over "
+"the data that they point to: instead, they are used for cases where you "
+"would like to use data for a short time."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:33
+msgid "As an example, consider a simple struct type `Point`:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:37
+msgid "~~~ struct Point {x: float, y: float} ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:41
+msgid ""
+"We can use this simple definition to allocate points in many different ways. "
+"For example, in this code, each of these three local variables contains a "
+"point, but allocated in a different place:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:48
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point {x: float, y: float}\n"
+"let on_the_stack : Point = Point {x: 3.0, y: 4.0};\n"
+"let managed_box : @Point = @Point {x: 5.0, y: 1.0};\n"
+"let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:60
+msgid ""
+"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 `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 "
+"expensive. Worse, if the data type contains mutable fields, copying can "
+"change the semantics of your program in unexpected ways. So we'd like to "
+"define a function that takes the points by pointer. We can use borrowed "
+"pointers to do this:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:70
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point {x: float, y: float}\n"
+"# fn sqrt(f: float) -> float { 0f }\n"
+"fn compute_distance(p1: &Point, p2: &Point) -> float {\n"
+" let x_d = p1.x - p2.x;\n"
+" let y_d = p1.y - p2.y;\n"
+" sqrt(x_d * x_d + y_d * y_d)\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:82
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point {x: float, y: float}\n"
+"# let on_the_stack : Point = Point{x: 3.0, y: 4.0};\n"
+"# let managed_box : @Point = @Point{x: 5.0, y: 1.0};\n"
+"# let owned_box : ~Point = ~Point{x: 7.0, y: 9.0};\n"
+"# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }\n"
+"compute_distance(&on_the_stack, managed_box);\n"
+"compute_distance(managed_box, owned_box);\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:89
+msgid ""
+"Here, the `&` operator takes the address of the variable `on_the_stack`; "
+"this is because `on_the_stack` has the type `Point` (that is, a struct "
+"value) and we have to take its address to get a 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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:95
+msgid ""
+"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 "
+"managed or owned box to the callee."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:105
+msgid ""
+"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 "
+"variable have been lent out, you cannot send that variable to another task. "
+"In addition, the compiler will reject any code that might cause the borrowed "
+"value to be freed or overwrite its component fields with values of different "
+"types (I'll get into what kinds of actions those are shortly). This rule "
+"should make intuitive sense: you must wait for a borrower to return the "
+"value that you lent it (that is, wait for the borrowed pointer to go out of "
+"scope) before you can make full use of it again."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:107
+msgid "# Other uses for the & operator"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:109
+msgid "In the previous example, the value `on_the_stack` was defined like so:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:114
+msgid ""
+"~~~ # struct Point {x: float, y: float} let on_the_stack: Point = Point {x: "
+"3.0, y: 4.0}; ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:119
+msgid ""
+"This declaration means that code can only pass `Point` by value to other "
+"functions. As a consequence, we had to explicitly take the address of "
+"`on_the_stack` to get a borrowed pointer. Sometimes however it is more "
+"convenient to move the & operator into the definition of `on_the_stack`:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:124
+msgid ""
+"~~~ # struct Point {x: float, y: float} let on_the_stack2: &Point = &Point "
+"{x: 3.0, y: 4.0}; ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:128
+msgid ""
+"Applying `&` to an rvalue (non-assignable location) is just a convenient "
+"shorthand for creating a temporary and taking its address. A more verbose "
+"way to write the same code is:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:134
+msgid ""
+"~~~ # struct Point {x: float, y: float} let tmp = Point {x: 3.0, y: 4.0}; "
+"let on_the_stack2 : &Point = &tmp; ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:136
+msgid "# Taking the address of fields"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:141
+msgid ""
+"As in C, the `&` operator is not limited to taking the address of local "
+"variables. It can also take the address of fields or individual array "
+"elements. For example, consider this type definition for `rectangle`:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:147
+msgid ""
+"~~~ struct Point {x: float, y: float} // as before struct Size {w: float, h: "
+"float} // as before struct Rectangle {origin: Point, size: Size} ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:149
+msgid "Now, as before, we can define rectangles in a few different ways:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:161
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point {x: float, y: float}\n"
+"# struct Size {w: float, h: float} // as before\n"
+"# struct Rectangle {origin: Point, size: Size}\n"
+"let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f},\n"
+" size: Size {w: 3f, h: 4f}};\n"
+"let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f},\n"
+" size: Size {w: 3f, h: 4f}};\n"
+"let rect_owned = ~Rectangle {origin: Point {x: 5f, y: 6f},\n"
+" size: Size {w: 3f, h: 4f}};\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:164
+msgid ""
+"In each case, we can extract out individual subcomponents with the `&` "
+"operator. For example, I could write:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:175
+msgid ""
+"~~~ # struct Point {x: float, y: float} // as before # struct Size {w: "
+"float, h: float} // as before # 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_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); ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:178
+msgid ""
+"which would borrow the field `origin` from the rectangle on the stack as "
+"well as from the managed box, and then compute the distance between them."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:180
+msgid "# Borrowing managed boxes and rooting"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:186
+msgid ""
+"We’ve seen a few examples so far of borrowing heap boxes, both managed 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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:197
+msgid ""
+"The basis for the check is the notion of _lifetimes_. A lifetime is a static "
+"approximation of the span of execution during which the pointer is valid: it "
+"always corresponds to some expression or block within the program. Code "
+"inside that expression can use the pointer without restrictions. But if the "
+"pointer escapes from that expression (for example, if the expression "
+"contains an assignment expression that assigns the pointer to a mutable "
+"field of a data structure with a broader scope than the pointer itself), the "
+"compiler reports an error. We'll be discussing lifetimes more in the "
+"examples to come, and a more thorough introduction is also available."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:202
+msgid ""
+"When the `&` operator creates a borrowed pointer, the compiler must ensure "
+"that the pointer remains valid for its entire lifetime. Sometimes this is "
+"relatively easy, such as when taking the address of a local variable or a "
+"field that is stored on the stack:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:211
+#, no-wrap
+msgid ""
+"~~~\n"
+"struct X { f: int }\n"
+"fn example1() {\n"
+" let mut x = X { f: 3 };\n"
+" let y = &mut x.f; // -+ L\n"
+" ... // |\n"
+"} // -+\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:216
+msgid ""
+"Here, the lifetime of the borrowed pointer `y` is simply L, the remainder of "
+"the function body. The compiler need not do any other work to prove that "
+"code will not free `x.f`. This is true even if the code mutates `x`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:218
+msgid "The situation gets more complex when borrowing data inside heap boxes:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:227
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct X { f: int }\n"
+"fn example2() {\n"
+" let mut x = @X { f: 3 };\n"
+" let y = &x.f; // -+ L\n"
+" ... // |\n"
+"} // -+\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:238
+msgid ""
+"In this example, the value `x` is a heap box, and `y` is therefore a pointer "
+"into that heap box. Again the lifetime of `y` is L, the remainder of the "
+"function body. But there is a crucial difference: suppose `x` were to be "
+"reassigned during the lifetime L? If the compiler isn't careful, the managed "
+"box could become *unrooted*, and 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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:241
+msgid ""
+"> ***Note:*** Our current implementation implements the garbage collector > "
+"using reference counting and cycle detection."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:247
+msgid ""
+"For this reason, whenever an `&` expression borrows the interior of a "
+"managed box stored in a mutable location, the compiler inserts a temporary "
+"that ensures that the managed box remains live for the entire lifetime. So, "
+"the above example would be compiled as if it were written"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:257
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct X { f: int }\n"
+"fn example2() {\n"
+" let mut x = @X {f: 3};\n"
+" let x1 = x;\n"
+" let y = &x1.f; // -+ L\n"
+" ... // |\n"
+"} // -+\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:260
+msgid ""
+"Now if `x` is reassigned, the pointer `y` will still remain valid. This "
+"process is called *rooting*."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:262
+msgid "# Borrowing owned boxes"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:268
+msgid ""
+"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 owned boxes, "
+"because it is not possible to have two references to a owned box."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:274
+msgid ""
+"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 "
+"owned box is stored in immutable memory. For example, the following function "
+"is legal:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:289
+#, no-wrap
+msgid ""
+"~~~\n"
+"# fn some_condition() -> bool { true }\n"
+"# struct Foo { f: int }\n"
+"fn example3() -> int {\n"
+" let mut x = ~Foo {f: 3};\n"
+" if some_condition() {\n"
+" let y = &x.f; // -+ L\n"
+" return *y; // |\n"
+" } // -+\n"
+" x = ~Foo {f: 4};\n"
+" ...\n"
+"# return 0;\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:295
+msgid ""
+"Here, as before, the interior of the variable `x` is being borrowed and `x` "
+"is declared as mutable. However, the compiler can prove that `x` is not "
+"assigned anywhere in the lifetime L of the variable `y`. Therefore, it "
+"accepts the function, even though `x` is mutable and in fact is mutated "
+"later in the function."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:301
+msgid ""
+"It may not be clear why we are so concerned about mutating a borrowed "
+"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):"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:310
+#, no-wrap
+msgid ""
+"~~~ {.xfail-test}\n"
+"fn example3() -> int {\n"
+" let mut x = ~X {f: 3};\n"
+" let y = &x.f;\n"
+" x = ~X {f: 4}; // Error reported here.\n"
+" *y\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:313
+msgid ""
+"To make this clearer, consider this diagram showing the state of memory "
+"immediately before the re-assignment of `x`:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:316 doc/tutorial-borrowed-ptr.md:330
+#, no-wrap
+msgid ""
+"~~~ {.notrust}\n"
+" Stack Exchange Heap\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:325
+#, no-wrap
+msgid ""
+" x +----------+\n"
+" | ~{f:int} | ----+\n"
+" y +----------+ |\n"
+" | &int | ----+\n"
+" +----------+ | +---------+\n"
+" +--> | f: 3 |\n"
+" +---------+\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:327
+msgid "Once the reassignment occurs, the memory will look like this:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:339
+#, no-wrap
+msgid ""
+" x +----------+ +---------+\n"
+" | ~{f:int} | -------> | f: 4 |\n"
+" y +----------+ +---------+\n"
+" | &int | ----+\n"
+" +----------+ | +---------+\n"
+" +--> | (freed) |\n"
+" +---------+\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:342
+msgid ""
+"Here you can see that the variable `y` still points at the old box, which "
+"has been freed."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:348
+msgid ""
+"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 owned pointers and structs, and the "
+"compiler will still be able to detect possible mutations:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:353
+#, no-wrap
+msgid ""
+"~~~ {.xfail-test}\n"
+"fn example3() -> int {\n"
+" struct R { g: int }\n"
+" struct S { f: ~R }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:361
+#, no-wrap
+msgid ""
+" let mut x = ~S {f: ~R {g: 3}};\n"
+" let y = &x.f.g;\n"
+" x = ~S {f: ~R {g: 4}}; // Error reported here.\n"
+" x.f = ~R {g: 5}; // Error reported here.\n"
+" *y\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:365
+msgid ""
+"In this case, two errors are reported, one when the variable `x` is modified "
+"and another when `x.f` is modified. Either modification would invalidate the "
+"pointer `y`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:367
+msgid "# Borrowing and enums"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:373
+msgid ""
+"The previous example showed that the type system forbids any borrowing 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`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:376
+msgid ""
+"As an example, let’s look at the following `shape` type that can represent "
+"both rectangles and circles:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:385
+#, no-wrap
+msgid ""
+"~~~\n"
+"struct Point {x: float, y: float}; // as before\n"
+"struct Size {w: float, h: float}; // as before\n"
+"enum Shape {\n"
+" Circle(Point, float), // origin, radius\n"
+" Rectangle(Point, Size) // upper-left, dimensions\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:389
+msgid ""
+"Now we might write a function to compute the area of a shape. This function "
+"takes a borrowed pointer to a shape, to avoid the need for copying."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:405
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point {x: float, y: float}; // as before\n"
+"# struct Size {w: float, h: float}; // as before\n"
+"# enum Shape {\n"
+"# Circle(Point, float), // origin, radius\n"
+"# Rectangle(Point, Size) // upper-left, dimensions\n"
+"# }\n"
+"# static tau: float = 6.28f;\n"
+"fn compute_area(shape: &Shape) -> float {\n"
+" match *shape {\n"
+" Circle(_, radius) => 0.5 * tau * radius * radius,\n"
+" Rectangle(_, ref size) => size.w * size.h\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:410
+msgid ""
+"The first case matches against circles. Here, the pattern extracts the "
+"radius from the shape variant and the action uses it to compute the area of "
+"the circle. (Like any up-to-date engineer, we use the [tau circle constant]"
+"[tau] and not that dreadfully outdated notion of pi)."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:412
+msgid "[tau]: http://www.math.utah.edu/~palais/pi.html"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:418
+msgid ""
+"The second match is more interesting. Here we match against a rectangle and "
+"extract its size: but rather than copy the `size` struct, we use a by-"
+"reference binding to create a pointer to it. In other words, a pattern "
+"binding like `ref size` binds the name `size` to a pointer of type `&size` "
+"into the _interior of the enum_."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:421
+msgid ""
+"To make this more clear, let's look at a diagram of memory layout in the "
+"case where `shape` points at a rectangle:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:424 doc/tutorial-borrowed-ptr.md:449
+#, no-wrap
+msgid ""
+"~~~ {.notrust}\n"
+"Stack Memory\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:433
+#, no-wrap
+msgid ""
+"+-------+ +---------------+\n"
+"| shape | ------> | rectangle( |\n"
+"+-------+ | {x: float, |\n"
+"| size | -+ | y: float}, |\n"
+"+-------+ +----> | {w: float, |\n"
+" | h: float}) |\n"
+" +---------------+\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:440
+msgid ""
+"Here you can see that rectangular shapes are composed of five words of "
+"memory. The first is a tag indicating which variant this enum is "
+"(`rectangle`, in this case). The next two words are the `x` and `y` fields "
+"for the point and the remaining two are the `w` and `h` fields for the size. "
+"The binding `size` is then a pointer into the inside of the shape."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:446
+msgid ""
+"Perhaps you can see where the danger lies: if the shape were somehow to be "
+"reassigned, perhaps to a circle, then although the memory used to store that "
+"shape value would still be valid, _it would have a different type_! The "
+"following diagram shows what memory would look like if code overwrote "
+"`shape` with a circle:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:458
+#, no-wrap
+msgid ""
+"+-------+ +---------------+\n"
+"| shape | ------> | circle( |\n"
+"+-------+ | {x: float, |\n"
+"| size | -+ | y: float}, |\n"
+"+-------+ +----> | float) |\n"
+" | |\n"
+" +---------------+\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:463
+msgid ""
+"As you can see, the `size` pointer would be pointing at a `float` instead of "
+"a struct. This is not good: dereferencing the second field of a `float` as "
+"if it were a struct with two fields would be a memory safety violation."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:475
+msgid ""
+"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 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 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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:477
+msgid "# Returning borrowed pointers"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:483
+msgid ""
+"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 as we'll see, doing so "
+"requires some explicit annotation."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:485
+msgid "For example, we could write a subroutine like this:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:490
+msgid ""
+"~~~ struct Point {x: float, y: float} fn get_x<'r>(p: &'r Point) -> &'r "
+"float { &p.x } ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:498
+msgid ""
+"Here, the function `get_x()` returns a pointer into the structure it was "
+"given. The type of the parameter (`&'r Point`) and return type (`&'r float`) "
+"both use a new syntactic form that we have not seen so far. Here the "
+"identifier `r` names the lifetime of the pointer explicitly. So in effect, "
+"this function declares that it takes a pointer with lifetime `r` and returns "
+"a pointer with that same lifetime."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:504
+msgid ""
+"In general, it is only possible to return borrowed pointers if they are "
+"derived from a parameter to the procedure. In that case, the pointer result "
+"will always have the same lifetime as one of the parameters; named lifetimes "
+"indicate which parameter that is."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:510
+msgid ""
+"In the previous examples, function parameter types did not include a "
+"lifetime name. In those examples, the compiler simply creates a fresh name "
+"for the lifetime automatically: that is, the lifetime name is guaranteed to "
+"refer to a distinct lifetime from the lifetimes of all other parameters."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:518
+msgid ""
+"Named lifetimes that appear in function signatures are conceptually 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 by the caller to "
+"`get_x()`, just as the value for the parameter `p` is defined by that caller."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:523
+msgid ""
+"In any case, whatever the lifetime of `r` is, the pointer produced by `&p.x` "
+"always has the same lifetime as `p` itself: a pointer to a field of a struct "
+"is valid as long as the struct is valid. Therefore, the compiler accepts the "
+"function `get_x()`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:526
+msgid ""
+"To emphasize this point, let’s look at a variation on the example, this time "
+"one that does not compile:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:533
+#, no-wrap
+msgid ""
+"~~~ {.xfail-test}\n"
+"struct Point {x: float, y: float}\n"
+"fn get_x_sh(p: @Point) -> &float {\n"
+" &p.x // Error reported here\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:541
+msgid ""
+"Here, the function `get_x_sh()` takes a managed box as input and returns a "
+"borrowed pointer. As before, the lifetime of the borrowed pointer that will "
+"be returned is a parameter (specified by the caller). That means that "
+"`get_x_sh()` promises to return a borrowed pointer that is valid for as long "
+"as the caller would like: this is subtly different from the first example, "
+"which promised to return a pointer that was valid for as long as its pointer "
+"argument was valid."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:552
+msgid ""
+"Within `get_x_sh()`, we see the expression `&p.x` which takes the address of "
+"a field of a managed box. The presence of this expression implies that the "
+"compiler must guarantee that, so long as the resulting pointer is valid, the "
+"managed box will not be reclaimed by the garbage collector. But recall that "
+"`get_x_sh()` also promised to return a pointer that was valid for as long as "
+"the caller wanted it to be. Clearly, `get_x_sh()` is not in a position to "
+"make both of these 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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:559
+msgid ""
+"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 which it can be legal to "
+"return a borrowed pointer is if the pointer points at a static constant)."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:561
+msgid "# Named lifetimes"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:565
+msgid ""
+"Let's look at named lifetimes in more detail. Named lifetimes allow for "
+"grouping of parameters by lifetime. For example, consider this function:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:579
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point {x: float, y: float}; // as before\n"
+"# struct Size {w: float, h: float}; // as before\n"
+"# enum Shape {\n"
+"# Circle(Point, float), // origin, radius\n"
+"# Rectangle(Point, Size) // upper-left, dimensions\n"
+"# }\n"
+"# fn compute_area(shape: &Shape) -> float { 0f }\n"
+"fn select<'r, T>(shape: &'r Shape, threshold: float,\n"
+" a: &'r T, b: &'r T) -> &'r T {\n"
+" if compute_area(shape) > threshold {a} else {b}\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:585
+msgid ""
+"This function takes three borrowed pointers and assigns each the same "
+"lifetime `r`. In practice, this means that, in the caller, the lifetime `r` "
+"will be the *intersection of the lifetime of the three region parameters*. "
+"This may be overly conservative, as in this example:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:607
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point {x: float, y: float}; // as before\n"
+"# struct Size {w: float, h: float}; // as before\n"
+"# enum Shape {\n"
+"# Circle(Point, float), // origin, radius\n"
+"# Rectangle(Point, Size) // upper-left, dimensions\n"
+"# }\n"
+"# fn compute_area(shape: &Shape) -> float { 0f }\n"
+"# fn select<'r, T>(shape: &Shape, threshold: float,\n"
+"# a: &'r T, b: &'r T) -> &'r T {\n"
+"# if compute_area(shape) > threshold {a} else {b}\n"
+"# }\n"
+" // -+ r\n"
+"fn select_based_on_unit_circle<'r, T>( // |-+ B\n"
+" threshold: float, a: &'r T, b: &'r T) -> &'r T { // | |\n"
+" // | |\n"
+" let shape = Circle(Point {x: 0., y: 0.}, 1.); // | |\n"
+" select(&shape, threshold, a, b) // | |\n"
+"} // |-+\n"
+" // -+\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:617
+msgid ""
+"In this call to `select()`, the lifetime of the first parameter shape is B, "
+"the function body. Both of the second two parameters `a` and `b` share the "
+"same lifetime, `r`, which is a lifetime parameter of "
+"`select_based_on_unit_circle()`. The caller will infer the intersection of "
+"these two lifetimes as the lifetime of the returned value, and hence the "
+"return value of `select()` will be assigned a lifetime of B. This will in "
+"turn lead to a compilation error, because `select_based_on_unit_circle()` is "
+"supposed to return a value with the lifetime `r`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:622
+msgid ""
+"To address this, we can modify the definition of `select()` to distinguish "
+"the lifetime of the first parameter from the lifetime of the latter two. "
+"After all, the first parameter is not being returned. Here is how the new "
+"`select()` might look:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:636
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point {x: float, y: float}; // as before\n"
+"# struct Size {w: float, h: float}; // as before\n"
+"# enum Shape {\n"
+"# Circle(Point, float), // origin, radius\n"
+"# Rectangle(Point, Size) // upper-left, dimensions\n"
+"# }\n"
+"# fn compute_area(shape: &Shape) -> float { 0f }\n"
+"fn select<'r, 'tmp, T>(shape: &'tmp Shape, threshold: float,\n"
+" a: &'r T, b: &'r T) -> &'r T {\n"
+" if compute_area(shape) > threshold {a} else {b}\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:641
+msgid ""
+"Here you can see that `shape`'s lifetime is now named `tmp`. The parameters "
+"`a`, `b`, and the return value all have the lifetime `r`. However, since "
+"the lifetime `tmp` is not returned, it would be more concise to just omit "
+"the named lifetime for `shape` altogether:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:655
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point {x: float, y: float}; // as before\n"
+"# struct Size {w: float, h: float}; // as before\n"
+"# enum Shape {\n"
+"# Circle(Point, float), // origin, radius\n"
+"# Rectangle(Point, Size) // upper-left, dimensions\n"
+"# }\n"
+"# fn compute_area(shape: &Shape) -> float { 0f }\n"
+"fn select<'r, T>(shape: &Shape, threshold: float,\n"
+" a: &'r T, b: &'r T) -> &'r T {\n"
+" if compute_area(shape) > threshold {a} else {b}\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:657
+msgid "This is equivalent to the previous definition."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:659
+msgid "# Conclusion"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-borrowed-ptr.md:663
+msgid ""
+"So there you have it: a (relatively) brief tour of the borrowed pointer "
+"system. For more details, we refer to the (yet to be written) reference "
+"document on borrowed pointers, which will explain the full notation and give "
+"more examples."
+msgstr ""
--- /dev/null
+# Japanese translations for Rust package
+# Copyright (C) 2013 The Rust Project Developers
+# This file is distributed under the same license as the Rust package.
+# Automatically generated, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Rust 0.8-pre\n"
+"POT-Creation-Date: 2013-08-05 19:40+0900\n"
+"PO-Revision-Date: 2013-07-28 20:32+0900\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: none\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#. type: Plain text
+#: doc/tutorial-container.md:2
+msgid "% Containers and iterators"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:4
+msgid "# Containers"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:6
+msgid "The container traits are defined in the `std::container` module."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:8
+msgid "## Unique and managed vectors"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:12
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:16
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:18
+msgid "## Maps and sets"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:22
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:24
+msgid "The standard library provides three owned map/set types:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-container.md:30
+msgid ""
+"`std::hashmap::HashMap` and `std::hashmap::HashSet`, requiring the keys to "
+"implement `Eq` and `Hash`"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-container.md:30
+msgid ""
+"`std::trie::TrieMap` and `std::trie::TrieSet`, requiring the keys to be "
+"`uint`"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-container.md:30
+msgid ""
+"`extra::treemap::TreeMap` and `extra::treemap::TreeSet`, requiring the keys "
+"to implement `TotalOrd`"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:34
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:37
+msgid ""
+"The `TrieMap` and `TreeMap` maps are ordered, while `HashMap` uses an "
+"arbitrary order."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:42
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:44
+msgid "## Double-ended queues"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:49
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:51
+msgid "## Priority queues"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:55
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:61
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:63
+msgid "# Iterators"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:65
+msgid "## Iteration protocol"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:69
+msgid ""
+"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:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:73
+msgid "~~~ /// An infinite stream of zeroes struct ZeroStream;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:80
+#, no-wrap
+msgid ""
+"impl Iterator<int> for ZeroStream {\n"
+" fn next(&mut self) -> Option<int> {\n"
+" Some(0)\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:83
+msgid ""
+"Reaching the end of the iterator is signalled by returning `None` instead of "
+"`Some(item)`:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:89 doc/tutorial-container.md:262
+#, no-wrap
+msgid ""
+"~~~\n"
+"/// A stream of N zeroes\n"
+"struct ZeroStream {\n"
+" priv remaining: uint\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:95
+#, no-wrap
+msgid ""
+"impl ZeroStream {\n"
+" fn new(n: uint) -> ZeroStream {\n"
+" ZeroStream { remaining: n }\n"
+" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:107 doc/tutorial-container.md:284
+#, no-wrap
+msgid ""
+"impl Iterator<int> for ZeroStream {\n"
+" fn next(&mut self) -> Option<int> {\n"
+" if self.remaining == 0 {\n"
+" None\n"
+" } else {\n"
+" self.remaining -= 1;\n"
+" Some(0)\n"
+" }\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:109
+msgid "## Container iterators"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:112
+msgid ""
+"Containers implement iteration over the contained elements by returning an "
+"iterator object. For example, vector slices several iterators available:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-container.md:116
+msgid "`iter()` and `rev_iter()`, for immutable references to the elements"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-container.md:116
+msgid ""
+"`mut_iter()` and `mut_rev_iter()`, for mutable references to the elements"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-container.md:116
+msgid ""
+"`consume_iter()` and `consume_rev_iter`, to move the elements out by-value"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:119
+msgid ""
+"A typical mutable container will implement at least `iter()`, `mut_iter()` "
+"and `consume_iter()` along with the reverse variants if it maintains an "
+"order."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:121
+msgid "### Freezing"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:125
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:130
+#, no-wrap
+msgid ""
+"~~~\n"
+"let mut xs = [1, 2, 3];\n"
+"{\n"
+" let _it = xs.iter();\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:136
+#, no-wrap
+msgid ""
+" // the vector is frozen for this scope, the compiler will statically\n"
+" // prevent modification\n"
+"}\n"
+"// the vector becomes unfrozen again at the end of the scope\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:139
+msgid ""
+"These semantics are due to most container iterators being implemented with "
+"`&` and `&mut`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:141
+msgid "## Iterator adaptors"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:145
+msgid ""
+"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:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:151
+msgid ""
+"~~~ let xs = [1, 9, 2, 3, 14, 12]; let result = xs.iter().fold(0, |"
+"accumulator, item| accumulator - *item); assert_eq!(result, -41); ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:153
+msgid ""
+"Some adaptors return an adaptor object implementing the `Iterator` trait "
+"itself:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:160
+msgid ""
+"~~~ 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); ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:164
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:166
+msgid "## For loops"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:168
+msgid ""
+"The `for` keyword can be used as sugar for iterating through any iterator:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:171
+msgid "~~~ let xs = [2, 3, 5, 7, 11, 13, 17];"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:176
+#, no-wrap
+msgid ""
+"// print out all the elements in the vector\n"
+"for x in xs.iter() {\n"
+" println(x.to_str())\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:182
+#, no-wrap
+msgid ""
+"// print out all but the first 3 elements in the vector\n"
+"for x in xs.iter().skip(3) {\n"
+" println(x.to_str())\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:185
+msgid ""
+"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:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:189
+msgid ""
+"~~~ let xs = [1, 2, 3, 4, 5]; let ys = [\"foo\", \"bar\", \"baz\", \"foobar"
+"\"];"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:192
+msgid ""
+"// create an iterator yielding tuples of elements from both vectors let mut "
+"it = xs.iter().zip(ys.iter());"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:196
+#, no-wrap
+msgid ""
+"// print out the pairs of elements up to (&3, &\"baz\")\n"
+"for (x, y) in it {\n"
+" printfln!(\"%d %s\", *x, *y);\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:201
+#, no-wrap
+msgid ""
+" if *x == 3 {\n"
+" break;\n"
+" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:204
+msgid ""
+"// yield and print the last pair from the iterator printfln!(\"last: %?\", "
+"it.next());"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:208
+msgid "// the iterator is now fully consumed assert!(it.next().is_none()); ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:210
+msgid "## Conversion"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:212
+msgid ""
+"Iterators offer generic conversion to containers with the `collect` adaptor:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:218
+msgid ""
+"~~~ let xs = [0, 1, 1, 2, 3, 5, 8]; let ys = xs.rev_iter().skip(1)."
+"transform(|&x| x * 2).collect::<~[int]>(); assert_eq!(ys, ~[10, 6, 4, 2, 2, "
+"0]); ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:221
+msgid ""
+"The method requires a type hint for the container type, if the surrounding "
+"code does not provide sufficient information."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:225
+msgid ""
+"Containers can provide conversion from iterators through `collect` by "
+"implementing the `FromIterator` trait. For example, the implementation for "
+"vectors is as follows:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:238
+#, no-wrap
+msgid ""
+"~~~\n"
+"impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {\n"
+" pub fn from_iterator(iterator: &mut T) -> ~[A] {\n"
+" let (lower, _) = iterator.size_hint();\n"
+" let mut xs = with_capacity(lower);\n"
+" for x in iterator {\n"
+" xs.push(x);\n"
+" }\n"
+" xs\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:240
+msgid "### Size hints"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:243
+msgid ""
+"The `Iterator` trait provides a `size_hint` default method, returning a "
+"lower bound and optionally on upper bound on the length of the iterator:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:247
+msgid "~~~ fn size_hint(&self) -> (uint, Option<uint>) { (0, None) } ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:251
+msgid ""
+"The vector implementation of `FromIterator` from above uses the lower bound "
+"to pre-allocate enough space to hold the minimum number of elements the "
+"iterator will yield."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:254
+msgid ""
+"The default implementation is always correct, but it should be overridden if "
+"the iterator can provide better information."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:256
+msgid ""
+"The `ZeroStream` from earlier can provide an exact lower and upper bound:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:267
+#, no-wrap
+msgid ""
+"impl ZeroStream {\n"
+" fn new(n: uint) -> ZeroStream {\n"
+" ZeroStream { remaining: n }\n"
+" }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:272
+#, no-wrap
+msgid ""
+" fn size_hint(&self) -> (uint, Option<uint>) {\n"
+" (self.remaining, Some(self.remaining))\n"
+" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:286
+msgid "## Double-ended iterators"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:290
+msgid ""
+"The `DoubleEndedIterator` trait represents an iterator able to yield "
+"elements from either end of a range. It inherits from the `Iterator` trait "
+"and extends it with the `next_back` function."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:293
+msgid ""
+"A `DoubleEndedIterator` can be flipped with the `invert` adaptor, returning "
+"another `DoubleEndedIterator` with `next` and `next_back` exchanged."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:300
+msgid ""
+"~~~ let xs = [1, 2, 3, 4, 5, 6]; let mut it = xs.iter(); printfln!(\"%?\", "
+"it.next()); // prints `Some(&1)` printfln!(\"%?\", it.next()); // prints "
+"`Some(&2)` printfln!(\"%?\", it.next_back()); // prints `Some(&6)`"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:306
+#, no-wrap
+msgid ""
+"// prints `5`, `4` and `3`\n"
+"for &x in it.invert() {\n"
+" printfln!(\"%?\", x)\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:309
+msgid ""
+"The `rev_iter` and `mut_rev_iter` methods on vectors just return an inverted "
+"version of the standard immutable and mutable vector iterators."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:312
+msgid ""
+"The `chain_`, `transform`, `filter`, `filter_map` and `peek` adaptors are "
+"`DoubleEndedIterator` implementations if the underlying iterators are."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:317
+msgid ""
+"~~~ let xs = [1, 2, 3, 4]; let ys = [5, 6, 7, 8]; let mut it = xs.iter()."
+"chain_(ys.iter()).transform(|&x| x * 2);"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:319
+msgid "printfln!(\"%?\", it.next()); // prints `Some(2)`"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:325
+#, no-wrap
+msgid ""
+"// prints `16`, `14`, `12`, `10`, `8`, `6`, `4`\n"
+"for x in it.invert() {\n"
+" printfln!(\"%?\", x);\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:327
+msgid "## Random-access iterators"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:331
+msgid ""
+"The `RandomAccessIterator` trait represents an iterator offering random "
+"access to the whole range. The `indexable` method retrieves the number of "
+"elements accessible with the `idx` method."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:334
+msgid ""
+"The `chain_` adaptor is an implementation of `RandomAccessIterator` if the "
+"underlying iterators are."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:343
+msgid ""
+"~~~ let xs = [1, 2, 3, 4, 5]; let ys = ~[7, 9, 11]; let mut it = xs.iter()."
+"chain_(ys.iter()); printfln!(\"%?\", it.idx(0)); // prints `Some(&1)` "
+"printfln!(\"%?\", it.idx(5)); // prints `Some(&7)` printfln!(\"%?\", it."
+"idx(7)); // prints `Some(&11)` printfln!(\"%?\", it.idx(8)); // prints `None`"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:348
+msgid ""
+"// yield two elements from the beginning, and one from the end it.next(); it."
+"next(); it.next_back();"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:352
+msgid ""
+"printfln!(\"%?\", it.idx(0)); // prints `Some(&3)` printfln!(\"%?\", it."
+"idx(4)); // prints `Some(&9)` printfln!(\"%?\", it.idx(6)); // prints `None` "
+"~~~"
+msgstr ""
--- /dev/null
+# Japanese translations for Rust package
+# Copyright (C) 2013 The Rust Project Developers
+# This file is distributed under the same license as the Rust package.
+# Automatically generated, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Rust 0.8-pre\n"
+"POT-Creation-Date: 2013-08-10 07:44+0900\n"
+"PO-Revision-Date: 2013-07-22 23:37+0900\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: none\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#. type: Plain text
+#: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
+#: doc/tutorial-borrowed-ptr.md:4 doc/tutorial-ffi.md:4
+#: doc/tutorial-macros.md:4 doc/tutorial-tasks.md:4
+msgid "# Introduction"
+msgstr "# イントロダクション"
+
+#. type: Plain text
+#: doc/tutorial.md:868 doc/tutorial-ffi.md:143
+msgid "# Destructors"
+msgstr "# デストラクタ"
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:2
+msgid "% Rust Foreign Function Interface Tutorial"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:10
+msgid ""
+"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))."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:13
+msgid ""
+"The following is a minimal example of calling a foreign function which will "
+"compile if snappy is installed:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:16
+msgid "~~~~ {.xfail-test} use std::libc::size_t;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:21
+#, no-wrap
+msgid ""
+"#[link_args = \"-lsnappy\"]\n"
+"extern {\n"
+" fn snappy_max_compressed_length(source_length: size_t) -> size_t;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:27
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" let x = unsafe { snappy_max_compressed_length(100) };\n"
+" println(fmt!(\"max compressed length of a 100 byte buffer: %?\", x));\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:31
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:37
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:41
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:43
+msgid "The `extern` block can be extended to cover the entire snappy API:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:46
+msgid "~~~~ {.xfail-test} use std::libc::{c_int, size_t};"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:65
+#, no-wrap
+msgid ""
+"#[link_args = \"-lsnappy\"]\n"
+"extern {\n"
+" fn snappy_compress(input: *u8,\n"
+" input_length: size_t,\n"
+" compressed: *mut u8,\n"
+" compressed_length: *mut size_t) -> c_int;\n"
+" fn snappy_uncompress(compressed: *u8,\n"
+" compressed_length: size_t,\n"
+" uncompressed: *mut u8,\n"
+" uncompressed_length: *mut size_t) -> c_int;\n"
+" fn snappy_max_compressed_length(source_length: size_t) -> size_t;\n"
+" fn snappy_uncompressed_length(compressed: *u8,\n"
+" compressed_length: size_t,\n"
+" result: *mut size_t) -> c_int;\n"
+" fn snappy_validate_compressed_buffer(compressed: *u8,\n"
+" compressed_length: size_t) -> c_int;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:67
+msgid "# Creating a safe interface"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:71
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:76
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:84
+#, no-wrap
+msgid ""
+"~~~~ {.xfail-test}\n"
+"pub fn validate_compressed_buffer(src: &[u8]) -> bool {\n"
+" unsafe {\n"
+" snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:88
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:91
+msgid ""
+"The `snappy_compress` and `snappy_uncompress` functions are more complex, "
+"since a buffer has to be allocated to hold the output too."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:96
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:102
+#, no-wrap
+msgid ""
+"~~~~ {.xfail-test}\n"
+"pub fn compress(src: &[u8]) -> ~[u8] {\n"
+" unsafe {\n"
+" let srclen = src.len() as size_t;\n"
+" let psrc = vec::raw::to_ptr(src);\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:106
+#, no-wrap
+msgid ""
+" let mut dstlen = snappy_max_compressed_length(srclen);\n"
+" let mut dst = vec::with_capacity(dstlen as uint);\n"
+" let pdst = vec::raw::to_mut_ptr(dst);\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:113
+#, no-wrap
+msgid ""
+" snappy_compress(psrc, srclen, pdst, &mut dstlen);\n"
+" vec::raw::set_len(&mut dst, dstlen as uint);\n"
+" dst\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:116
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:122
+#, no-wrap
+msgid ""
+"~~~~ {.xfail-test}\n"
+"pub fn uncompress(src: &[u8]) -> Option<~[u8]> {\n"
+" unsafe {\n"
+" let srclen = src.len() as size_t;\n"
+" let psrc = vec::raw::to_ptr(src);\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:125
+#, no-wrap
+msgid ""
+" let mut dstlen: size_t = 0;\n"
+" snappy_uncompressed_length(psrc, srclen, &mut dstlen);\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:128
+#, no-wrap
+msgid ""
+" let mut dst = vec::with_capacity(dstlen as uint);\n"
+" let pdst = vec::raw::to_mut_ptr(dst);\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:138
+#, no-wrap
+msgid ""
+" if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {\n"
+" vec::raw::set_len(&mut dst, dstlen as uint);\n"
+" Some(dst)\n"
+" } else {\n"
+" None // SNAPPY_INVALID_INPUT\n"
+" }\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:141
+msgid ""
+"For reference, the examples used here are also available as an [library on "
+"GitHub](https://github.com/thestinger/rust-snappy)."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:147
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:150
+msgid ""
+"A type with the same functionality as owned boxes can be implemented by "
+"wrapping `malloc` and `free`:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:156
+msgid ""
+"~~~~ use std::cast; use std::libc::{c_void, size_t, malloc, free}; use std::"
+"ptr; use std::unstable::intrinsics;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:161
+#, no-wrap
+msgid ""
+"// a wrapper around the handle returned by the foreign code\n"
+"pub struct Unique<T> {\n"
+" priv ptr: *mut T\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:172
+#, no-wrap
+msgid ""
+"impl<T: Send> Unique<T> {\n"
+" pub fn new(value: T) -> Unique<T> {\n"
+" unsafe {\n"
+" let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T;\n"
+" assert!(!ptr::is_null(ptr));\n"
+" // `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it\n"
+" intrinsics::move_val_init(&mut *ptr, value);\n"
+" Unique{ptr: ptr}\n"
+" }\n"
+" }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:177
+#, no-wrap
+msgid ""
+" // the 'r lifetime results in the same semantics as `&*x` with ~T\n"
+" pub fn borrow<'r>(&'r self) -> &'r T {\n"
+" unsafe { cast::copy_lifetime(self, &*self.ptr) }\n"
+" }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:183
+#, no-wrap
+msgid ""
+" // the 'r lifetime results in the same semantics as `&mut *x` with ~T\n"
+" pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T {\n"
+" unsafe { cast::copy_mut_lifetime(self, &mut *self.ptr) }\n"
+" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:195
+#, no-wrap
+msgid ""
+"#[unsafe_destructor]\n"
+"impl<T: Send> Drop for Unique<T> {\n"
+" fn drop(&self) {\n"
+" unsafe {\n"
+" let x = intrinsics::init(); // dummy value to swap in\n"
+" // moving the object out is needed to call the destructor\n"
+" ptr::replace_ptr(self.ptr, x);\n"
+" free(self.ptr as *c_void)\n"
+" }\n"
+" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:202
+#, no-wrap
+msgid ""
+"// A comparison between the built-in ~ and this reimplementation\n"
+"fn main() {\n"
+" {\n"
+" let mut x = ~5;\n"
+" *x = 10;\n"
+" } // `x` is freed here\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:209
+#, no-wrap
+msgid ""
+" {\n"
+" let mut y = Unique::new(5);\n"
+" *y.borrow_mut() = 10;\n"
+" } // `y` is freed here\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:211
+msgid "# Linking"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:215
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:217
+msgid "# Unsafe blocks"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:221
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:224
+msgid ""
+"Unsafe functions, on the other hand, advertise it to the world. An unsafe "
+"function is written like this:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:228
+msgid "~~~~ unsafe fn kaboom(ptr: *int) -> int { *ptr } ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:230
+msgid ""
+"This function can only be called from an `unsafe` block or another `unsafe` "
+"function."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:232
+msgid "# Accessing foreign globals"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:236
+msgid ""
+"Foreign APIs often export a global variable which could do something like "
+"track global state. In order to access these variables, you declare them in "
+"`extern` blocks with the `static` keyword:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:239
+msgid "~~~{.xfail-test} use std::libc;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:244
+#, no-wrap
+msgid ""
+"#[link_args = \"-lreadline\"]\n"
+"extern {\n"
+" static rl_readline_version: libc::c_int;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:250
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" println(fmt!(\"You have readline version %d installed.\",\n"
+" rl_readline_version as int));\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:254
+msgid ""
+"Alternatively, you may need to alter global state provided by a foreign "
+"interface. To do this, statics can be declared with `mut` so rust can mutate "
+"them."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:258
+msgid "~~~{.xfail-test} use std::libc; use std::ptr;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:263
+#, no-wrap
+msgid ""
+"#[link_args = \"-lreadline\"]\n"
+"extern {\n"
+" static mut rl_prompt: *libc::c_char;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:272
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" do \"[my-awesome-shell] $\".as_c_str |buf| {\n"
+" unsafe { rl_prompt = buf; }\n"
+" // get a line, process it\n"
+" unsafe { rl_prompt = ptr::null(); }\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:274
+msgid "# Foreign calling conventions"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:279
+msgid ""
+"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:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:288
+#, no-wrap
+msgid ""
+"~~~~\n"
+"#[cfg(target_os = \"win32\")]\n"
+"#[abi = \"stdcall\"]\n"
+"#[link_name = \"kernel32\"]\n"
+"extern {\n"
+" fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:292
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:294
+msgid "# Interoperability with foreign code"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:298
+msgid ""
+"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`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:305
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:310
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:312
+msgid ""
+"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."
+msgstr ""
--- /dev/null
+# Japanese translations for Rust package
+# Copyright (C) 2013 The Rust Project Developers
+# This file is distributed under the same license as the Rust package.
+# Automatically generated, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Rust 0.8-pre\n"
+"POT-Creation-Date: 2013-07-28 20:32+0900\n"
+"PO-Revision-Date: 2013-07-28 20:32+0900\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: none\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#. type: Plain text
+#: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
+#: doc/tutorial-borrowed-ptr.md:4 doc/tutorial-ffi.md:4
+#: doc/tutorial-macros.md:4 doc/tutorial-tasks.md:4
+msgid "# Introduction"
+msgstr "# イントロダクション"
+
+#. type: Plain text
+#: doc/rust.md:2136 doc/rust.md:2223 doc/tutorial-macros.md:323
+msgid "~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:2
+msgid "% Rust Macros Tutorial"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:12
+msgid ""
+"Functions are the primary tool that programmers can use to build "
+"abstractions. Sometimes, however, programmers want to abstract over compile-"
+"time syntax rather than run-time values. Macros provide syntactic "
+"abstraction. For an example of how this can be useful, consider the "
+"following two code fragments, which both pattern-match on their input and "
+"both return early in one case, doing nothing otherwise:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:30
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# enum t { special_a(uint), special_b(uint) };\n"
+"# fn f() -> uint {\n"
+"# let input_1 = special_a(0);\n"
+"# let input_2 = special_a(0);\n"
+"match input_1 {\n"
+" special_a(x) => { return x; }\n"
+" _ => {}\n"
+"}\n"
+"// ...\n"
+"match input_2 {\n"
+" special_b(x) => { return x; }\n"
+" _ => {}\n"
+"}\n"
+"# return 0u;\n"
+"# }\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:38
+msgid ""
+"This code could become tiresome if repeated many times. However, no "
+"function can capture its functionality to make it possible to abstract the "
+"repetition away. Rust's macro system, however, can eliminate the "
+"repetition. Macros are lightweight custom syntax extensions, themselves "
+"defined using the `macro_rules!` syntax extension. The following "
+"`early_return` macro captures the pattern in the above code:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:59
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# enum t { special_a(uint), special_b(uint) };\n"
+"# fn f() -> uint {\n"
+"# let input_1 = special_a(0);\n"
+"# let input_2 = special_a(0);\n"
+"macro_rules! early_return(\n"
+" ($inp:expr $sp:ident) => ( // invoke it like `(input_5 special_e)`\n"
+" match $inp {\n"
+" $sp(x) => { return x; }\n"
+" _ => {}\n"
+" }\n"
+" );\n"
+")\n"
+"// ...\n"
+"early_return!(input_1 special_a);\n"
+"// ...\n"
+"early_return!(input_2 special_b);\n"
+"# return 0;\n"
+"# }\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:65
+msgid ""
+"Macros are defined in pattern-matching style: in the above example, the text "
+"`($inp:expr $sp:ident)` that appears on the left-hand side of the `=>` is "
+"the *macro invocation syntax*, a pattern denoting how to write a call to the "
+"macro. The text on the right-hand side of the `=>`, beginning with `match "
+"$inp`, is the *macro transcription syntax*: what the macro expands to."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:67
+msgid "# Invocation syntax"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:71
+msgid ""
+"The macro invocation syntax specifies the syntax for the arguments to the "
+"macro. It appears on the left-hand side of the `=>` in a macro definition. "
+"It conforms to the following rules:"
+msgstr ""
+
+#. type: Bullet: '1. '
+#: doc/tutorial-macros.md:76
+msgid "It must be surrounded by parentheses."
+msgstr ""
+
+#. type: Bullet: '2. '
+#: doc/tutorial-macros.md:76
+msgid "`$` has special meaning (described below)."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:76
+#, no-wrap
+msgid ""
+"3. The `()`s, `[]`s, and `{}`s it contains must balance. For example, `([)` is\n"
+"forbidden.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:78
+msgid "Otherwise, the invocation syntax is free-form."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:83
+#, no-wrap
+msgid ""
+"To take as an argument a fragment of Rust code, write `$` followed by a name\n"
+" (for use on the right-hand side), followed by a `:`, followed by a *fragment\n"
+" specifier*. The fragment specifier denotes the sort of fragment to match. The\n"
+" most common fragment specifiers are:\n"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-macros.md:92
+msgid ""
+"`ident` (an identifier, referring to a variable or item. Examples: `f`, `x`, "
+"`foo`.)"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-macros.md:92
+msgid ""
+"`expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; "
+"`f(42)`.)"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-macros.md:92
+msgid "`ty` (a type. Examples: `int`, `~[(char, ~str)]`, `&T`.)"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-macros.md:92
+msgid ""
+"`pat` (a pattern, usually appearing in a `match` or on the left-hand side of "
+"a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-macros.md:92
+msgid ""
+"`block` (a sequence of actions. Example: `{ log(error, \"hi\"); return 12; }"
+"`)"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:95
+msgid ""
+"The parser interprets any token that's not preceded by a `$` literally. "
+"Rust's usual rules of tokenization apply,"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:98
+msgid ""
+"So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a "
+"macro that could be invoked like: `my_macro!(i->(( 2+2 )))`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:100
+msgid "## Invocation location"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:105
+msgid ""
+"A macro invocation may take the place of (and therefore expand to) an "
+"expression, an item, or a statement. The Rust parser will parse the macro "
+"invocation as a \"placeholder\" for whichever of those three nonterminals is "
+"appropriate for the location."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:112
+msgid ""
+"At expansion time, the output of the macro will be parsed as whichever of "
+"the three nonterminals it stands in for. This means that a single macro "
+"might, for example, expand to an item or an expression, depending on its "
+"arguments (and cause a syntax error if it is called with the wrong argument "
+"for its location). Although this behavior sounds excessively dynamic, it is "
+"known to be useful under some circumstances."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:115
+msgid "# Transcription syntax"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:119
+msgid ""
+"The right-hand side of the `=>` follows the same rules as the left-hand "
+"side, except that a `$` need only be followed by the name of the syntactic "
+"fragment to transcribe into the macro expansion; its type need not be "
+"repeated."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:126
+msgid ""
+"The right-hand side must be enclosed by delimiters, which the transcriber "
+"ignores. Therefore `() => ((1,2,3))` is a macro that expands to a tuple "
+"expression, `() => (let $x=$val)` is a macro that expands to a statement, "
+"and `() => (1,2,3)` is a macro that expands to a syntax error (since the "
+"transcriber interprets the parentheses on the right-hand-size as delimiters, "
+"and `1,2,3` is not a valid Rust expression on its own)."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:133
+msgid ""
+"Except for permissibility of `$name` (and `$(...)*`, discussed below), the "
+"right-hand side of a macro definition is ordinary Rust syntax. In "
+"particular, macro invocations (including invocations of the macro currently "
+"being defined) are permitted in expression, statement, and item locations. "
+"However, nothing else about the code is examined or executed by the macro "
+"system; execution still has to wait until run-time."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:135
+msgid "## Interpolation location"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:139
+msgid ""
+"The interpolation `$argument_name` may appear in any location consistent "
+"with its fragment specifier (i.e., if it is specified as `ident`, it may be "
+"used anywhere an identifier is permitted)."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:141
+msgid "# Multiplicity"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:143
+msgid "## Invocation"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:150
+msgid ""
+"Going back to the motivating example, recall that `early_return` expanded "
+"into a `match` that would `return` if the `match`'s scrutinee matched the "
+"\"special case\" identifier provided as the second argument to "
+"`early_return`, and do nothing otherwise. Now suppose that we wanted to "
+"write a version of `early_return` that could handle a variable number of "
+"\"special\" cases."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:156
+msgid ""
+"The syntax `$(...)*` on the left-hand side of the `=>` in a macro definition "
+"accepts zero or more occurrences of its contents. It works much like the `*` "
+"operator in regular expressions. It also supports a separator token (a comma-"
+"separated list could be written `$(...),*`), and `+` instead of `*` to mean "
+"\"at least one\"."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:179
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# enum t { special_a(uint),special_b(uint),special_c(uint),special_d(uint)};\n"
+"# fn f() -> uint {\n"
+"# let input_1 = special_a(0);\n"
+"# let input_2 = special_a(0);\n"
+"macro_rules! early_return(\n"
+" ($inp:expr, [ $($sp:ident)|+ ]) => (\n"
+" match $inp {\n"
+" $(\n"
+" $sp(x) => { return x; }\n"
+" )+\n"
+" _ => {}\n"
+" }\n"
+" );\n"
+")\n"
+"// ...\n"
+"early_return!(input_1, [special_a|special_c|special_d]);\n"
+"// ...\n"
+"early_return!(input_2, [special_b]);\n"
+"# return 0;\n"
+"# }\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:181
+msgid "### Transcription"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:191
+msgid ""
+"As the above example demonstrates, `$(...)*` is also valid on the right-hand "
+"side of a macro definition. The behavior of `*` in transcription, especially "
+"in cases where multiple `*`s are nested, and multiple different names are "
+"involved, can seem somewhat magical and intuitive at first. The system that "
+"interprets them is called \"Macro By Example\". The two rules to keep in "
+"mind are (1) the behavior of `$(...)*` is to walk through one \"layer\" of "
+"repetitions for all of the `$name`s it contains in lockstep, and (2) each `"
+"$name` must be under at least as many `$(...)*`s as it was matched against. "
+"If it is under more, it'll be repeated, as appropriate."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:193
+msgid "## Parsing limitations"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:197
+msgid ""
+"For technical reasons, there are two limitations to the treatment of syntax "
+"fragments by the macro parser:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:210
+#, no-wrap
+msgid ""
+"1. The parser will always parse as much as possible of a Rust syntactic\n"
+"fragment. For example, if the comma were omitted from the syntax of\n"
+"`early_return!` above, `input_1 [` would've been interpreted as the beginning\n"
+"of an array index. In fact, invoking the macro would have been impossible.\n"
+"2. The parser must have eliminated all ambiguity by the time it reaches a\n"
+"`$name:fragment_specifier` declaration. This limitation can result in parse\n"
+"errors when declarations occur at the beginning of, or immediately after,\n"
+"a `$(...)*`. For example, the grammar `$($t:ty)* $e:expr` will always fail to\n"
+"parse because the parser would be forced to choose between parsing `t` and\n"
+"parsing `e`. Changing the invocation syntax to require a distinctive token in\n"
+"front can solve the problem. In the above example, `$(T $t:ty)* E $e:exp`\n"
+"solves the problem.\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:212
+msgid "# Macro argument pattern matching"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:214
+msgid "Now consider code like the following:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:216
+msgid "## Motivation"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:236
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# enum t1 { good_1(t2, uint), bad_1 };\n"
+"# pub struct t2 { body: t3 }\n"
+"# enum t3 { good_2(uint), bad_2};\n"
+"# fn f(x: t1) -> uint {\n"
+"match x {\n"
+" good_1(g1, val) => {\n"
+" match g1.body {\n"
+" good_2(result) => {\n"
+" // complicated stuff goes here\n"
+" return result + val;\n"
+" },\n"
+" _ => fail!(\"Didn't get good_2\")\n"
+" }\n"
+" }\n"
+" _ => return 0 // default value\n"
+"}\n"
+"# }\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:241
+msgid ""
+"All the complicated stuff is deeply indented, and the error-handling code is "
+"separated from matches that fail. We'd like to write a macro that performs a "
+"match, but with a syntax that suits the problem better. The following macro "
+"can solve the problem:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:263
+#, no-wrap
+msgid ""
+"~~~~\n"
+"macro_rules! biased_match (\n"
+" // special case: `let (x) = ...` is illegal, so use `let x = ...` instead\n"
+" ( ($e:expr) ~ ($p:pat) else $err:stmt ;\n"
+" binds $bind_res:ident\n"
+" ) => (\n"
+" let $bind_res = match $e {\n"
+" $p => ( $bind_res ),\n"
+" _ => { $err }\n"
+" };\n"
+" );\n"
+" // more than one name; use a tuple\n"
+" ( ($e:expr) ~ ($p:pat) else $err:stmt ;\n"
+" binds $( $bind_res:ident ),*\n"
+" ) => (\n"
+" let ( $( $bind_res ),* ) = match $e {\n"
+" $p => ( $( $bind_res ),* ),\n"
+" _ => { $err }\n"
+" };\n"
+" )\n"
+")\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:277
+#, no-wrap
+msgid ""
+"# enum t1 { good_1(t2, uint), bad_1 };\n"
+"# pub struct t2 { body: t3 }\n"
+"# enum t3 { good_2(uint), bad_2};\n"
+"# fn f(x: t1) -> uint {\n"
+"biased_match!((x) ~ (good_1(g1, val)) else { return 0 };\n"
+" binds g1, val )\n"
+"biased_match!((g1.body) ~ (good_2(result) )\n"
+" else { fail!(\"Didn't get good_2\") };\n"
+" binds result )\n"
+"// complicated stuff goes here\n"
+"return result + val;\n"
+"# }\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:288
+#, no-wrap
+msgid ""
+"This solves the indentation problem. But if we have a lot of chained matches\n"
+"like this, we might prefer to write a single macro invocation. The input\n"
+"pattern we want is clear:\n"
+"~~~~\n"
+"# macro_rules! b(\n"
+" ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*\n"
+" binds $( $bind_res:ident ),*\n"
+" )\n"
+"# => (0))\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:291
+msgid ""
+"However, it's not possible to directly expand to nested match statements. "
+"But there is a solution."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:293
+msgid "## The recursive approach to macro writing"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:297
+msgid ""
+"A macro may accept multiple different input grammars. The first one to "
+"successfully match the actual argument to a macro invocation is the one that "
+"\"wins\"."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:301
+msgid ""
+"In the case of the example above, we want to write a recursive macro to "
+"process the semicolon-terminated lines, one-by-one. So, we want the "
+"following input patterns:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:308
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# macro_rules! b(\n"
+" ( binds $( $bind_res:ident ),* )\n"
+"# => (0))\n"
+"~~~~\n"
+"...and:\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:317
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# macro_rules! b(\n"
+" ( ($e :expr) ~ ($p :pat) else $err :stmt ;\n"
+" $( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*\n"
+" binds $( $bind_res:ident ),*\n"
+" )\n"
+"# => (0))\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:321
+msgid ""
+"The resulting macro looks like this. Note that the separation into "
+"`biased_match!` and `biased_match_rec!` occurs only because we have an outer "
+"piece of syntax (the `let`) which we only want to transcribe once."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:342
+#, no-wrap
+msgid ""
+"macro_rules! biased_match_rec (\n"
+" // Handle the first layer\n"
+" ( ($e :expr) ~ ($p :pat) else $err :stmt ;\n"
+" $( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*\n"
+" binds $( $bind_res:ident ),*\n"
+" ) => (\n"
+" match $e {\n"
+" $p => {\n"
+" // Recursively handle the next layer\n"
+" biased_match_rec!($( ($e_rest) ~ ($p_rest) else $err_rest ; )*\n"
+" binds $( $bind_res ),*\n"
+" )\n"
+" }\n"
+" _ => { $err }\n"
+" }\n"
+" );\n"
+" ( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )\n"
+")\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:364
+#, no-wrap
+msgid ""
+"// Wrap the whole thing in a `let`.\n"
+"macro_rules! biased_match (\n"
+" // special case: `let (x) = ...` is illegal, so use `let x = ...` instead\n"
+" ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*\n"
+" binds $bind_res:ident\n"
+" ) => (\n"
+" let ( $( $bind_res ),* ) = biased_match_rec!(\n"
+" $( ($e) ~ ($p) else $err ; )*\n"
+" binds $bind_res\n"
+" );\n"
+" );\n"
+" // more than one name: use a tuple\n"
+" ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*\n"
+" binds $( $bind_res:ident ),*\n"
+" ) => (\n"
+" let ( $( $bind_res ),* ) = biased_match_rec!(\n"
+" $( ($e) ~ ($p) else $err ; )*\n"
+" binds $( $bind_res ),*\n"
+" );\n"
+" )\n"
+")\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:378
+#, no-wrap
+msgid ""
+"# enum t1 { good_1(t2, uint), bad_1 };\n"
+"# pub struct t2 { body: t3 }\n"
+"# enum t3 { good_2(uint), bad_2};\n"
+"# fn f(x: t1) -> uint {\n"
+"biased_match!(\n"
+" (x) ~ (good_1(g1, val)) else { return 0 };\n"
+" (g1.body) ~ (good_2(result) ) else { fail!(\"Didn't get good_2\") };\n"
+" binds val, result )\n"
+"// complicated stuff goes here\n"
+"return result + val;\n"
+"# }\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:382
+msgid ""
+"This technique applies to many cases where transcribing a result all at once "
+"is not possible. The resulting code resembles ordinary functional "
+"programming in some respects, but has some important differences from "
+"functional programming."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:390
+msgid ""
+"The first difference is important, but also easy to forget: the "
+"transcription (right-hand) side of a `macro_rules!` rule is literal syntax, "
+"which can only be executed at run-time. If a piece of transcription syntax "
+"does not itself appear inside another macro invocation, it will become part "
+"of the final program. If it is inside a macro invocation (for example, the "
+"recursive invocation of `biased_match_rec!`), it does have the opportunity "
+"to affect transcription, but only through the process of attempted pattern "
+"matching."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:398
+msgid ""
+"The second, related, difference is that the evaluation order of macros feels "
+"\"backwards\" compared to ordinary programming. Given an invocation `m1!(m2!"
+"())`, the expander first expands `m1!`, giving it as input the literal "
+"syntax `m2!()`. If it transcribes its argument unchanged into an appropriate "
+"position (in particular, not as an argument to yet another macro "
+"invocation), the expander will then proceed to evaluate `m2!()` (along with "
+"any other macro invocations `m1!(m2!())` produced)."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:400
+msgid "# A final note"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-macros.md:407
+msgid ""
+"Macros, as currently implemented, are not for the faint of heart. Even "
+"ordinary syntax errors can be more difficult to debug when they occur inside "
+"a macro, and errors caused by parse problems in generated code can be very "
+"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."
+msgstr ""
--- /dev/null
+# Japanese translations for Rust package
+# Copyright (C) 2013 The Rust Project Developers
+# This file is distributed under the same license as the Rust package.
+# Automatically generated, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Rust 0.8-pre\n"
+"POT-Creation-Date: 2013-08-08 22:27+0900\n"
+"PO-Revision-Date: 2013-07-28 20:32+0900\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: none\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#. type: Plain text
+#: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
+#: doc/tutorial-borrowed-ptr.md:4 doc/tutorial-ffi.md:4
+#: doc/tutorial-macros.md:4 doc/tutorial-tasks.md:4
+msgid "# Introduction"
+msgstr "# イントロダクション"
+
+#. type: Plain text
+#: doc/rust.md:1952 doc/tutorial-tasks.md:648
+msgid "# } ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:2
+msgid "% Rust Tasks and Communication Tutorial"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:10
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:19
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:26
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:32
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:37
+msgid ""
+"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_."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:39
+msgid "## A note about the libraries"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:44
+msgid ""
+"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 "
+"standard and extra libraries, which are still under development and do not "
+"always present a consistent or complete interface."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:47
+msgid ""
+"For your reference, these are the standard modules involved in Rust "
+"concurrency at this writing:"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-tasks.md:56
+msgid "[`std::task`] - All code relating to tasks and task scheduling,"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-tasks.md:56
+msgid "[`std::comm`] - The message passing interface,"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-tasks.md:56
+msgid "[`std::pipes`] - The underlying messaging infrastructure,"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-tasks.md:56
+msgid "[`extra::comm`] - Additional messaging types based on `std::pipes`,"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-tasks.md:56
+msgid "[`extra::sync`] - More exotic synchronization tools, including locks,"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-tasks.md:56
+msgid ""
+"[`extra::arc`] - The Arc (atomically reference counted) type, for safely "
+"sharing immutable data,"
+msgstr ""
+
+#. type: Bullet: '* '
+#: doc/tutorial-tasks.md:56
+msgid ""
+"[`extra::future`] - A type representing values that may be computed "
+"concurrently and retrieved at a later time."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:64
+msgid ""
+"[`std::task`]: std/task.html [`std::comm`]: std/comm.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"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:66
+msgid "# Basics"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:72
+msgid ""
+"The programming interface for creating and managing tasks lives 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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:76
+msgid "~~~~ # use std::io::println; # use std::task::spawn;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:80
+msgid ""
+"// Print something profound in a different task using a named function fn "
+"print_message() { println(\"I am running in a different task!\"); } "
+"spawn(print_message);"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:83
+msgid ""
+"// Print something more profound in a different task using a lambda "
+"expression spawn( || println(\"I am also running in a different task!\") );"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:89
+#, no-wrap
+msgid ""
+"// The canonical way to spawn is using `do` notation\n"
+"do spawn {\n"
+" println(\"I too am running in a different task!\");\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:95
+msgid ""
+"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 standard library."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:102
+msgid ""
+"The `spawn` function has a very simple type signature: `fn spawn(f: ~fn())`. "
+"Because it accepts only owned closures, and owned closures contain only "
+"owned data, `spawn` can safely move the entire closure and all its "
+"associated state into an entirely different task for execution. Like any "
+"closure, the function passed to `spawn` may capture an environment that it "
+"carries across tasks."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:109
+msgid ""
+"~~~ # 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();"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:115
+#, no-wrap
+msgid ""
+"do spawn {\n"
+" // Capture it in the remote task\n"
+" println(fmt!(\"I am child number %d\", child_task_number));\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:119
+msgid ""
+"By default, the scheduler multiplexes tasks across the available cores, "
+"running in parallel. Thus, on a multicore machine, running the following "
+"code should interleave the output in vaguely random order."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:123
+msgid "~~~ # use std::io::print; # use std::task::spawn;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:130
+#, no-wrap
+msgid ""
+"for child_task_number in range(0, 20) {\n"
+" do spawn {\n"
+" print(fmt!(\"I am child number %d\\n\", child_task_number));\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:132
+msgid "## Communication"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:137
+msgid ""
+"Now that we have spawned a new task, it would be nice if we could "
+"communicate with it. Recall that Rust does not have shared mutable state, so "
+"one task may not manipulate variables owned by another task. Instead we use "
+"*pipes*."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:142
+msgid ""
+"A pipe is simply a pair of endpoints: one for sending messages and another "
+"for receiving messages. Pipes are low-level communication building-blocks "
+"and so come in a variety of forms, each one appropriate for a different use "
+"case. In what follows, we cover the most commonly used varieties."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:148
+msgid ""
+"The simplest way to create a pipe is to use the `pipes::stream` function to "
+"create a `(Port, Chan)` pair. In Rust parlance, a *channel* is a sending "
+"endpoint of a pipe, and a *port* is the receiving endpoint. Consider the "
+"following example of calculating two results concurrently:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:152
+msgid "~~~~ # use std::task::spawn; # use std::comm::{stream, Port, Chan};"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:154
+msgid "let (port, chan): (Port<int>, Chan<int>) = stream();"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:159
+#, no-wrap
+msgid ""
+"do spawn || {\n"
+" let result = some_expensive_computation();\n"
+" chan.send(result);\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:165
+msgid ""
+"some_other_expensive_computation(); let result = port.recv(); # fn "
+"some_expensive_computation() -> int { 42 } # fn "
+"some_other_expensive_computation() {} ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:170
+msgid ""
+"Let's examine this example in detail. First, the `let` statement creates a "
+"stream for sending and receiving integers (the left-hand side of the `let`, "
+"`(chan, port)`, is an example of a *destructuring let*: the pattern "
+"separates a tuple into its component parts)."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:175
+msgid ""
+"~~~~ # use std::comm::{stream, Chan, Port}; let (port, chan): (Port<int>, "
+"Chan<int>) = stream(); ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:179
+msgid ""
+"The child task will use the channel to send data to the parent task, which "
+"will wait to receive the data on the port. The next statement spawns the "
+"child task."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:190
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# use std::task::spawn;\n"
+"# use std::comm::stream;\n"
+"# fn some_expensive_computation() -> int { 42 }\n"
+"# let (port, chan) = stream();\n"
+"do spawn || {\n"
+" let result = some_expensive_computation();\n"
+" chan.send(result);\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:196
+msgid ""
+"Notice that the creation of the task closure transfers `chan` to the child "
+"task implicitly: the closure captures `chan` in its environment. Both `Chan` "
+"and `Port` are sendable types and may be captured into tasks or otherwise "
+"transferred between them. In the example, the child task runs an expensive "
+"computation, then sends the result over the captured channel."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:200
+msgid ""
+"Finally, the parent continues with some other expensive computation, then "
+"waits for the child's result to arrive on the port:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:209
+msgid ""
+"~~~~ # use std::comm::{stream}; # fn some_other_expensive_computation() {} # "
+"let (port, chan) = stream::<int>(); # chan.send(0); "
+"some_other_expensive_computation(); let result = port.recv(); ~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:215
+msgid ""
+"The `Port` and `Chan` pair created by `stream` enables efficient "
+"communication between a single sender and a single receiver, but multiple "
+"senders cannot use a single `Chan`, and multiple receivers cannot use a "
+"single `Port`. What if our example needed to compute multiple results "
+"across a number of tasks? The following program is ill-typed:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:221
+msgid ""
+"~~~ {.xfail-test} # use std::task::{spawn}; # use std::comm::{stream, Port, "
+"Chan}; # fn some_expensive_computation() -> int { 42 } let (port, chan) = "
+"stream();"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:225
+#, no-wrap
+msgid ""
+"do spawn {\n"
+" chan.send(some_expensive_computation());\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:232
+#, no-wrap
+msgid ""
+"// ERROR! The previous spawn statement already owns the channel,\n"
+"// so the compiler will not allow it to be captured again\n"
+"do spawn {\n"
+" chan.send(some_expensive_computation());\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:235
+msgid ""
+"Instead we can use a `SharedChan`, a type that allows a single `Chan` to be "
+"shared by multiple senders."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:239
+msgid "~~~ # use std::task::spawn; # use std::comm::{stream, SharedChan};"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:242
+msgid "let (port, chan) = stream(); let chan = SharedChan::new(chan);"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:250
+#, no-wrap
+msgid ""
+"for init_val in range(0u, 3) {\n"
+" // Create a new channel handle to distribute to the child task\n"
+" let child_chan = chan.clone();\n"
+" do spawn {\n"
+" child_chan.send(some_expensive_computation(init_val));\n"
+" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:254
+msgid ""
+"let result = port.recv() + port.recv() + port.recv(); # fn "
+"some_expensive_computation(_i: uint) -> int { 42 } ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:263
+msgid ""
+"Here we transfer ownership of the channel into a new `SharedChan` value. "
+"Like `Chan`, `SharedChan` is a non-copyable, owned type (sometimes also "
+"referred to as an *affine* or *linear* type). Unlike with `Chan`, though, "
+"the programmer may duplicate a `SharedChan`, with the `clone()` method. A "
+"cloned `SharedChan` produces a new handle to the same channel, allowing "
+"multiple tasks to send data to a single port. Between `spawn`, `stream` and "
+"`SharedChan`, we have enough tools to implement many useful concurrency "
+"patterns."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:268
+msgid ""
+"Note that the above `SharedChan` example is somewhat contrived since you "
+"could also simply use three `stream` pairs, but it serves to illustrate the "
+"point. For reference, written with multiple streams, it might look like the "
+"example below."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:273
+msgid "~~~ # use std::task::spawn; # use std::comm::stream; # use std::vec;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:282
+#, no-wrap
+msgid ""
+"// Create a vector of ports, one for each child task\n"
+"let ports = do vec::from_fn(3) |init_val| {\n"
+" let (port, chan) = stream();\n"
+" do spawn {\n"
+" chan.send(some_expensive_computation(init_val));\n"
+" }\n"
+" port\n"
+"};\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:287
+msgid ""
+"// Wait on each port, accumulating the results let result = ports.iter()."
+"fold(0, |accum, port| accum + port.recv() ); # fn "
+"some_expensive_computation(_i: uint) -> int { 42 } ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:291
+msgid ""
+"## Backgrounding computations: Futures With `extra::future`, rust has a "
+"mechanism for requesting a computation and getting the result later."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:299
+#, no-wrap
+msgid ""
+"The basic example below illustrates this.\n"
+"~~~\n"
+"# fn make_a_sandwich() {};\n"
+"fn fib(n: uint) -> uint {\n"
+" // lengthy computation returning an uint\n"
+" 12586269025\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:304
+msgid ""
+"let mut delayed_fib = extra::future::spawn (|| fib(50) ); make_a_sandwich(); "
+"println(fmt!(\"fib(50) = %?\", delayed_fib.get())) ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:310
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:322
+#, no-wrap
+msgid ""
+"Here is another example showing how futures allow you to background computations. The workload will\n"
+"be distributed on the available cores.\n"
+"~~~\n"
+"# use std::vec;\n"
+"fn partial_sum(start: uint) -> f64 {\n"
+" let mut local_sum = 0f64;\n"
+" for num in range(start*100000, (start+1)*100000) {\n"
+" local_sum += (num as f64 + 1.0).pow(&-2.0);\n"
+" }\n"
+" local_sum\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:325
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" let mut futures = vec::from_fn(1000, |ind| do extra::future::spawn { partial_sum(ind) });\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:333
+#, no-wrap
+msgid ""
+" let mut final_res = 0f64;\n"
+" for ft in futures.mut_iter() {\n"
+" final_res += ft.get();\n"
+" }\n"
+" println(fmt!(\"π^2/6 is not far from : %?\", final_res));\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:335
+msgid "## Sharing immutable data without copy: Arc"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:340
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:344
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:351
+msgid ""
+"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::rand; use "
+"extra::arc::Arc;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:355
+#, no-wrap
+msgid ""
+"fn pnorm(nums: &~[float], p: uint) -> float {\n"
+" nums.iter().fold(0.0, |a,b| a+(*b).pow(&(p as float)) ).pow(&(1f / (p as float)))\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:359
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" let numbers = vec::from_fn(1000000, |_| rand::random::<float>());\n"
+" println(fmt!(\"Inf-norm = %?\", *numbers.iter().max().unwrap()));\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:361
+#, no-wrap
+msgid " let numbers_arc = Arc::new(numbers);\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:365
+#, no-wrap
+msgid ""
+" for num in range(1u, 10) {\n"
+" let (port, chan) = stream();\n"
+" chan.send(numbers_arc.clone());\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:374
+#, no-wrap
+msgid ""
+" do spawn {\n"
+" let local_arc : Arc<~[float]> = port.recv();\n"
+" let task_numbers = local_arc.get();\n"
+" println(fmt!(\"%u-norm = %?\", num, pnorm(task_numbers, num)));\n"
+" }\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:396
+msgid ""
+"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::"
+"new(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::"
+"new(numbers); # let (port, chan) = stream(); chan.send(numbers_arc."
+"clone()); ~~~ copying only the wrapper and not its contents."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:410
+msgid ""
+"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::new(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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:412
+msgid ""
+"The `arc` module also implements Arcs around mutable data that are not "
+"covered here."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:414
+msgid "# Handling task failure"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:423
+msgid ""
+"Rust has a built-in mechanism for raising exceptions. The `fail!()` macro "
+"(which can also be written with an error string as an argument: `fail!"
+"( ~reason)`) and the `assert!` construct (which effectively calls `fail!()` "
+"if a boolean expression is false) are both ways to raise exceptions. When a "
+"task raises an exception the task unwinds its stack---running destructors "
+"and freeing memory along the way---and then exits. Unlike exceptions in C++, "
+"exceptions in Rust are unrecoverable within a single task: once a task "
+"fails, there is no way to \"catch\" the exception."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:426
+msgid ""
+"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."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:434
+msgid ""
+"~~~{.xfail-test .linked-failure} # use std::task::spawn; # use std::task; # "
+"fn do_some_work() { loop { task::yield() } } # do task::try { // Create a "
+"child task that fails do spawn { fail!() }"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:439
+msgid ""
+"// This will also fail because the task we spawned failed do_some_work(); "
+"# }; ~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:449
+msgid ""
+"While it isn't possible for a task to recover from failure, tasks may notify "
+"each other of failure. The simplest way of handling task failure is with the "
+"`try` function, which is similar to `spawn`, but immediately blocks waiting "
+"for the child task to finish. `try` returns a value of type `Result<int, "
+"()>`. `Result` is an `enum` type with two variants: `Ok` and `Err`. In this "
+"case, because the type arguments to `Result` are `int` and `()`, callers can "
+"pattern-match on a result to check whether it's an `Ok` result with an `int` "
+"field (representing a successful result) or an `Err` result (representing "
+"termination with an error)."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:463
+#, no-wrap
+msgid ""
+"~~~{.xfail-test .linked-failure}\n"
+"# use std::task;\n"
+"# fn some_condition() -> bool { false }\n"
+"# fn calculate_result() -> int { 0 }\n"
+"let result: Result<int, ()> = do task::try {\n"
+" if some_condition() {\n"
+" calculate_result()\n"
+" } else {\n"
+" fail!(\"oops!\");\n"
+" }\n"
+"};\n"
+"assert!(result.is_err());\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:469
+msgid ""
+"Unlike `spawn`, the function spawned using `try` may return a value, which "
+"`try` will dutifully propagate back to the caller in a [`Result`] enum. If "
+"the child task terminates successfully, `try` will return an `Ok` result; if "
+"the child task fails, `try` will return an `Error` result."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:471
+msgid "[`Result`]: std/result.html"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:476
+msgid ""
+"> ***Note:*** A failed task does not currently produce a useful error > "
+"value (`try` always returns `Err(())`). In the > future, it may be possible "
+"for tasks to intercept the value passed to > `fail!()`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:479
+msgid ""
+"TODO: Need discussion of `future_result` in order to make failure modes "
+"useful."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:487
+msgid ""
+"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 small piece of "
+"input from the outside world, which you happen to be processing in parallel, "
+"is malformed and its processing task can't proceed). Hence, you will need "
+"different _linked failure modes_."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:489
+msgid "## Failure modes"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:492
+msgid ""
+"By default, task failure is _bidirectionally linked_, which means that if "
+"either task fails, it kills the other one."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:507
+#, no-wrap
+msgid ""
+"~~~{.xfail-test .linked-failure}\n"
+"# use std::task;\n"
+"# use std::comm::oneshot;\n"
+"# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }\n"
+"# do task::try {\n"
+"do spawn {\n"
+" do spawn {\n"
+" fail!(); // All three tasks will fail.\n"
+" }\n"
+" sleep_forever(); // Will get woken up by force, then fail\n"
+"}\n"
+"sleep_forever(); // Will get woken up by force, then fail\n"
+"# };\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:514
+msgid ""
+"If you want parent tasks to be able to kill their children, but do not want "
+"a parent to fail automatically if one of its child task fails, you can call "
+"`task::spawn_supervised` for _unidirectionally linked_ failure. The function "
+"`task::try`, which we saw previously, uses `spawn_supervised` internally, "
+"with additional logic to wait for the child task to finish before returning. "
+"Hence:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:536
+#, no-wrap
+msgid ""
+"~~~{.xfail-test .linked-failure}\n"
+"# use std::comm::{stream, Chan, Port};\n"
+"# use std::comm::oneshot;\n"
+"# use std::task::{spawn, try};\n"
+"# use std::task;\n"
+"# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }\n"
+"# do task::try {\n"
+"let (receiver, sender): (Port<int>, Chan<int>) = stream();\n"
+"do spawn { // Bidirectionally linked\n"
+" // Wait for the supervised child task to exist.\n"
+" let message = receiver.recv();\n"
+" // Kill both it and the parent task.\n"
+" assert!(message != 42);\n"
+"}\n"
+"do try { // Unidirectionally linked\n"
+" sender.send(42);\n"
+" sleep_forever(); // Will get woken up by force\n"
+"}\n"
+"// Flow never reaches here -- parent task was killed too.\n"
+"# };\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:542
+msgid ""
+"Supervised failure is useful in any situation where one task manages "
+"multiple fallible child tasks, and the parent task can recover if any child "
+"fails. On the other hand, if the _parent_ (supervisor) fails, then there is "
+"nothing the children can do to recover, so they should also fail."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:545
+msgid ""
+"Supervised task failure propagates across multiple generations even if an "
+"intermediate generation has already exited:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:562
+#, no-wrap
+msgid ""
+"~~~{.xfail-test .linked-failure}\n"
+"# use std::task;\n"
+"# use std::comm::oneshot;\n"
+"# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }\n"
+"# fn wait_for_a_while() { for _ in range(0, 1000u) { task::yield() } }\n"
+"# do task::try::<int> {\n"
+"do task::spawn_supervised {\n"
+" do task::spawn_supervised {\n"
+" sleep_forever(); // Will get woken up by force, then fail\n"
+" }\n"
+" // Intermediate task immediately exits\n"
+"}\n"
+"wait_for_a_while();\n"
+"fail!(); // Will kill grandchild even if child has already exited\n"
+"# };\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:565
+msgid ""
+"Finally, tasks can be configured to not propagate failure to each other at "
+"all, using `task::spawn_unlinked` for _isolated failure_."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:581
+#, no-wrap
+msgid ""
+"~~~{.xfail-test .linked-failure}\n"
+"# use std::task;\n"
+"# fn random() -> uint { 100 }\n"
+"# fn sleep_for(i: uint) { for _ in range(0, i) { task::yield() } }\n"
+"# do task::try::<()> {\n"
+"let (time1, time2) = (random(), random());\n"
+"do task::spawn_unlinked {\n"
+" sleep_for(time2); // Won't get forced awake\n"
+" fail!();\n"
+"}\n"
+"sleep_for(time1); // Won't get forced awake\n"
+"fail!();\n"
+"// It will take MAX(time1,time2) for the program to finish.\n"
+"# };\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:583
+msgid "## Creating a task with a bi-directional communication path"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:588
+msgid ""
+"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 `extra::"
+"comm::DuplexStream()` supports this pattern. We'll look briefly at how to "
+"use it."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:593
+msgid ""
+"To see how `DuplexStream()` works, we will create a child task that "
+"repeatedly receives a `uint` message, converts it to a string, and sends the "
+"string in response. The child terminates when it receives `0`. Here is the "
+"function that implements the child task:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:606
+#, no-wrap
+msgid ""
+"~~~{.xfail-test .linked-failure}\n"
+"# use extra::comm::DuplexStream;\n"
+"# use std::uint;\n"
+"fn stringifier(channel: &DuplexStream<~str, uint>) {\n"
+" let mut value: uint;\n"
+" loop {\n"
+" value = channel.recv();\n"
+" channel.send(uint::to_str(value));\n"
+" if value == 0 { break; }\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:614
+msgid ""
+"The implementation of `DuplexStream` supports both sending and receiving. "
+"The `stringifier` function takes a `DuplexStream` that can send strings (the "
+"first type parameter) and receive `uint` messages (the second type "
+"parameter). The body itself simply loops, reading from the channel and then "
+"sending its response back. The actual response itself is simply the "
+"stringified version of the received value, `uint::to_str(value)`."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:616
+msgid "Here is the code for the parent task:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:630
+#, no-wrap
+msgid ""
+"~~~{.xfail-test .linked-failure}\n"
+"# use std::task::spawn;\n"
+"# use std::uint;\n"
+"# use extra::comm::DuplexStream;\n"
+"# fn stringifier(channel: &DuplexStream<~str, uint>) {\n"
+"# let mut value: uint;\n"
+"# loop {\n"
+"# value = channel.recv();\n"
+"# channel.send(uint::to_str(value));\n"
+"# if value == 0u { break; }\n"
+"# }\n"
+"# }\n"
+"# fn main() {\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:632
+msgid "let (from_child, to_child) = DuplexStream();"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:636
+#, no-wrap
+msgid ""
+"do spawn {\n"
+" stringifier(&to_child);\n"
+"};\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:639
+msgid "from_child.send(22); assert!(from_child.recv() == ~\"22\");"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:642
+msgid "from_child.send(23); from_child.send(0);"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:645
+msgid ""
+"assert!(from_child.recv() == ~\"23\"); assert!(from_child.recv() == ~\"0\");"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-tasks.md:652
+msgid ""
+"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."
+msgstr ""
--- /dev/null
+# Japanese translations for Rust package
+# Copyright (C) 2013 The Rust Project Developers
+# This file is distributed under the same license as the Rust package.
+# Automatically generated, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Rust 0.8-pre\n"
+"POT-Creation-Date: 2013-08-12 02:06+0900\n"
+"PO-Revision-Date: 2013-08-08 22:27+0900\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: none\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: UTF-8\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#. type: Plain text
+#: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
+#: doc/tutorial-borrowed-ptr.md:4 doc/tutorial-ffi.md:4
+#: doc/tutorial-macros.md:4 doc/tutorial-tasks.md:4
+msgid "# Introduction"
+msgstr "# イントロダクション"
+
+#. type: Plain text
+#: doc/rust.md:1277 doc/tutorial.md:2176
+msgid ""
+"In type-parameterized functions, methods of the supertrait may be called on "
+"values of subtrait-bound type parameters. Refering to the previous example "
+"of `trait Circle : Shape`:"
+msgstr ""
+"型パラメータを持つ関数では、サブトレイトの境界型パラメータの値によりスーパー"
+"トレイトのメソッドを呼び出すことになります。前の例の `trait Circle : Shape` "
+"を参照してください。"
+
+#. type: Plain text
+#: doc/rust.md:1286 doc/tutorial.md:2185
+#, no-wrap
+msgid ""
+"~~~\n"
+"# trait Shape { fn area(&self) -> float; }\n"
+"# trait Circle : Shape { fn radius(&self) -> float; }\n"
+"fn radius_times_area<T: Circle>(c: T) -> float {\n"
+" // `c` is both a Circle and a Shape\n"
+" c.radius() * c.area()\n"
+"}\n"
+"~~~\n"
+msgstr ""
+"~~~\n"
+"# trait Shape { fn area(&self) -> float; }\n"
+"# trait Circle : Shape { fn radius(&self) -> float; }\n"
+"fn radius_times_area<T: Circle>(c: T) -> float {\n"
+" // `c` は Circle でもあり、Shape でもある\n"
+" c.radius() * c.area()\n"
+"}\n"
+"~~~\n"
+
+#. type: Plain text
+#: doc/rust.md:1288 doc/tutorial.md:2187
+msgid "Likewise, supertrait methods may also be called on trait objects."
+msgstr ""
+"同様に、スーパートレイトのメソッドは、トレイトオブジェクトについても呼び出す"
+"ことが可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:2
+msgid "% The Rust Language Tutorial"
+msgstr "% Rust 言語チュートリアル"
+
+#. type: Plain text
+#: doc/tutorial.md:13
+msgid ""
+"Rust is a programming language with a focus on type safety, memory safety, "
+"concurrency and performance. It is intended for writing large-scale, high-"
+"performance software that is free from several classes of common errors. "
+"Rust has a sophisticated memory model that encourages efficient data "
+"structures and safe concurrency patterns, forbidding invalid memory accesses "
+"that would otherwise cause segmentation faults. It is statically typed and "
+"compiled ahead of time."
+msgstr ""
+"Rust は、型安全性、メモリ安全性、並列性、パフォーマンスを重視したプログラミン"
+"グ言語です。大規模でハイパフォーマンスなソフトウェア作成向きの、C++ 等の言語"
+"でよくある誤りを犯しにくい言語仕様になっています。Rust の洗練されたメモリモデ"
+"ルでは、効率的なデータ構造や安全な並行計算を実現することが可能であり、セグメ"
+"ンテーション違反を引き起こす不正なメモリアクセスは起こりえません。Rust は、静"
+"的型付けされた、コンパイル型の言語です。"
+
+#. type: Plain text
+#: doc/tutorial.md:17
+msgid ""
+"As a multi-paradigm language, Rust supports writing code in procedural, "
+"functional and object-oriented styles. Some of its pleasant high-level "
+"features include:"
+msgstr ""
+"Rust はマルチパラダイム言語であり、手続き型、関数型、オブジェクト指向型のプロ"
+"グラミングをサポートします。Rust には、次のような素敵で高レベルな特徴がありま"
+"す。"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:30
+msgid ""
+"**Type inference.** Type annotations on local variable declarations are "
+"optional."
+msgstr ""
+"**型推論:** ローカル変数の宣言では型注釈 (type annotation) を省略できます。"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:30
+msgid ""
+"**Safe task-based concurrency.** Rust's lightweight tasks do not share "
+"memory, instead communicating through messages."
+msgstr ""
+"**タスクベースの安全な並行計算:** Rust の軽量タスクはタスク間でメモリを共有す"
+"るのではなく、メッセージを介して通信します。"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:30
+msgid ""
+"**Higher-order functions.** Efficient and flexible closures provide "
+"iteration and other control structures"
+msgstr ""
+"**高階関数:** 効率的で柔軟なクロージャにより、イテレーションやその他の制御構"
+"造を実現できます。"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:30
+msgid ""
+"**Pattern matching and algebraic data types.** Pattern matching on Rust's "
+"enumeration types (a more powerful version of C's enums, similar to "
+"algebraic data types in functional languages) is a compact and expressive "
+"way to encode program logic."
+msgstr ""
+"**パターンマッチと代数的データ型:** Rust の列挙型 (C の列挙型の強化バージョ"
+"ン。関数型言語における代数的データ型のようなもの) のパターンマッチにより、プ"
+"ログラムの論理を、コンパクトで表現力豊かに記述することができます。"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:30
+msgid ""
+"**Polymorphism.** Rust has type-parametric functions and types, type classes "
+"and OO-style interfaces."
+msgstr ""
+"**ポリモーフィズム:** Rust には、型パラメータをもつ関数や型、型クラスとオブ"
+"ジェクト指向風のインターフェースがあります。"
+
+#. type: Plain text
+#: doc/tutorial.md:32
+msgid "## Scope"
+msgstr "## 本文書の位置づけ"
+
+#. type: Plain text
+#: doc/tutorial.md:38
+msgid ""
+"This is an introductory tutorial for the Rust programming language. It "
+"covers the fundamentals of the language, including the syntax, the type "
+"system and memory model, generics, and modules. [Additional tutorials](#what-"
+"next) cover specific language features in greater depth."
+msgstr ""
+"この文章は、Rust プログラミング言語のチュートリアルです。構文、型システムとメ"
+"モリモデル、ジェネリクス、モジュールなどの言語の基礎となる部分をカバーしてい"
+"ます。 いくつかの言語機能の詳細については、 [その他のチュートリアル](#次のス"
+"テップは) を参照してください。"
+
+#. type: Plain text
+#: doc/tutorial.md:42
+msgid ""
+"This tutorial assumes that the reader is already familiar with one or more "
+"languages in the C family. Understanding of pointers and general memory "
+"management techniques will help."
+msgstr ""
+"本チュートリアルは、読者がすでに 1 つ以上の C 系統言語 に精通していることを前"
+"提としています。本書を理解する上で、ポインタやメモリ管理のテクニックに関する"
+"知識が役に立つでしょう。"
+
+#. type: Plain text
+#: doc/tutorial.md:44
+msgid "## Conventions"
+msgstr "## 本書の表記について"
+
+#. type: Plain text
+#: doc/tutorial.md:47
+msgid ""
+"Throughout the tutorial, language keywords and identifiers defined in "
+"example code are displayed in `code font`."
+msgstr ""
+"本チュートリアルでは、言語のキーワードや、サンプルコード中で定義される識別子"
+"を `code font` のように示します。"
+
+#. type: Plain text
+#: doc/tutorial.md:53
+msgid ""
+"Code snippets are indented, and also shown in a monospaced font. Not all "
+"snippets constitute whole programs. For brevity, we'll often show fragments "
+"of programs that don't compile on their own. To try them out, you might have "
+"to wrap them in `fn main() { ... }`, and make sure they don't contain "
+"references to names that aren't actually defined."
+msgstr ""
+"コードスニペットは、インデントされ、固定幅フォントで表示されます。いくつかの"
+"コードスニペットは、プログラムの一部を抜き出したものになっています。説明を簡"
+"潔にするため、それだけではコンパイル不可能なプログラムの断片を掲載することが"
+"あります。プログラムの動作を試す際には、全体を `fn main() { ... }` で囲んでく"
+"ださい。また、プログラム中で未定義の名前を参照している箇所がないか確認してく"
+"ださい。"
+
+#. type: Plain text
+#: doc/tutorial.md:57
+msgid ""
+"> ***Warning:*** Rust is a language under ongoing development. Notes > about "
+"potential changes to the language, implementation > deficiencies, and other "
+"caveats appear offset in blockquotes."
+msgstr ""
+"> ***警告:*** Rust は開発途上の言語です。将来予定されている言語への変更や、実"
+"装上の不備、その他の注意事項など、 blockquote の段落 (この段落もそうです) に"
+"注意してください。"
+
+#. type: Plain text
+#: doc/tutorial.md:59
+msgid "# Getting started"
+msgstr "# はじめに"
+
+#. type: Plain text
+#: doc/tutorial.md:63
+msgid ""
+"The Rust compiler currently must be built from a [tarball], unless you are "
+"on Windows, in which case using the [installer][win-exe] is recommended."
+msgstr ""
+"Windows 以外の環境では、今のところ、Rust のコンパイラは [ソースコード]"
+"[tarball] からビルドする必要があります。Windows をお使いの場合は、 [インス"
+"トーラー][win-exe] の使用をおすすめします。"
+
+#. type: Plain text
+#: doc/tutorial.md:69
+msgid ""
+"Since the Rust compiler is written in Rust, it must be built by a "
+"precompiled \"snapshot\" version of itself (made in an earlier state of "
+"development). As such, source builds require a connection to the Internet, "
+"to fetch snapshots, and an OS that can execute the available snapshot "
+"binaries."
+msgstr ""
+"Rust のコンパイラは Rust で書かれているため、最新版の少し前のソースからコンパ"
+"イルされた「スナップショット」版コンパイラでビルドする必要があります。スナッ"
+"プショットを利用してビルドするためには、スナップショットをダウンロードするた"
+"めのインターネット接続と、スナップショットバイナリを実行できる OS が必要で"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:71
+msgid "Snapshot binaries are currently built and tested on several platforms:"
+msgstr ""
+"スナップショットバイナリは、現時点では以下のプラットフォーム向けのものがあり"
+"ます。"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:75
+msgid "Windows (7, Server 2008 R2), x86 only"
+msgstr "Windows (7, Server 2008 R2), x86 のみ"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:75
+msgid "Linux (various distributions), x86 and x86-64"
+msgstr "Linux (各種ディストリビューション), x86 または x86-64"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:75
+msgid "OSX 10.6 (\"Snow Leopard\") or greater, x86 and x86-64"
+msgstr "OSX 10.6 (\"Snow Leopard\") 以降, x86 または x86-64"
+
+#. type: Plain text
+#: doc/tutorial.md:78
+msgid ""
+"You may find that other platforms work, but these are our \"tier 1\" "
+"supported build environments that are most likely to work."
+msgstr ""
+"スナップショットは他のプラットフォームでも動作するかもしれませんが、\"tier "
+"1\" プラットフォームとしてサポートされているのは上記のみです。"
+
+#. type: Plain text
+#: doc/tutorial.md:85
+msgid ""
+"> ***Note:*** Windows users should read the detailed > \"[getting started]"
+"[wiki-start]\" notes on the wiki. Even when using > the binary installer, "
+"the Windows build requires a MinGW installation, > the precise details of "
+"which are not discussed here. Finally, `rustc` may > need to be [referred to "
+"as `rustc.exe`][bug-3319]. It's a bummer, we > know."
+msgstr ""
+"> ***注意:*** Windows ユーザーは wiki の [getting started][wiki-start] の記事"
+"を読んでください。 本書では詳細を説明しませんが、インストーラを利用する場合で"
+"も、MinGW のインストールなど、追加の手順が必要です。また、コンパイラは "
+"`rustc` ではなく、 [`rustc.exe` として呼び出す必要がある][bug-3319] かもしれ"
+"ません。このような制限があることはは、本当に残念です。"
+
+#. type: Plain text
+#: doc/tutorial.md:88
+msgid ""
+"[bug-3319]: https://github.com/mozilla/rust/issues/3319 [wiki-start]: "
+"https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust"
+msgstr ""
+"[bug-3319]: https://github.com/mozilla/rust/issues/3319\n"
+"[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-"
+"developing-Rust"
+
+#. type: Plain text
+#: doc/tutorial.md:91
+msgid ""
+"To build from source you will also need the following prerequisite packages:"
+msgstr "ソースからビルドするためには、以下のパッケージが必要です。"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:97
+msgid "g++ 4.4 or clang++ 3.x"
+msgstr "g++ 4.4 または clang++ 3.x"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:97
+msgid "python 2.6 or later (but not 3.x)"
+msgstr "python 2.6 以降 (ただし、 3.x は除く)"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:97
+msgid "perl 5.0 or later"
+msgstr "perl 5.0 以降"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:97
+msgid "gnu make 3.81 or later"
+msgstr "gnu make 3.81 以降"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:97
+msgid "curl"
+msgstr "curl"
+
+#. type: Plain text
+#: doc/tutorial.md:100
+msgid ""
+"If you've fulfilled those prerequisites, something along these lines should "
+"work."
+msgstr "上記条件を満たしていれば、以下のような手順でビルド可能なはずです。"
+
+#. type: Plain text
+#: doc/tutorial.md:108
+msgid ""
+"~~~~ {.notrust} $ 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 "
+"~~~~"
+msgstr ""
+"~~~~ {.notrust}\n"
+"$ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz\n"
+"$ tar -xzf rust-0.7.tar.gz $ cd rust-0.7 $ ./configure\n"
+"$ make && make install\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:114
+msgid ""
+"You may need to use `sudo make install` if you do not normally have "
+"permission to modify the destination directory. The install locations can be "
+"adjusted by passing a `--prefix` argument to `configure`. Various other "
+"options are also supported: pass `--help` for more information on them."
+msgstr ""
+"インストール先のディレクトリを変更する権限がない場合、 `sudo make install` を"
+"実行する必要があるかもしれません。インストール先は `configure` に `--prefix` "
+"引数を渡すことで変更できます。`configure` はその他いろいろなオプションをサ"
+"ポートしています。詳細については、 `--help` 引数を指定して実行してください。"
+
+#. type: Plain text
+#: doc/tutorial.md:120
+msgid ""
+"When complete, `make install` will place several programs into `/usr/local/"
+"bin`: `rustc`, the Rust compiler; `rustdoc`, the API-documentation tool; "
+"`rustpkg`, the Rust package manager; `rusti`, the Rust REPL; and `rust`, a "
+"tool which acts both as a unified interface for them, and for a few common "
+"command line scenarios."
+msgstr ""
+"ビルド完了後、`make install` を実行すると、以下のプログラムが `/usr/local/"
+"bin` にインストールされます。\n"
+"\n"
+"* `rustc`: Rust のコンパイラ\n"
+"* `rustdoc`: API ドキュメント作成ツール\n"
+"* `rustpkg`: Rust のパッケージマネージャ\n"
+"* `rust`: Rust の REPL\n"
+"* `rust`: Rust のツール群への共通のインターフェースと、いくつかのコマンドライ"
+"ンシナリオを提供するツール"
+
+#. type: Plain text
+#: doc/tutorial.md:123
+msgid ""
+"[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"
+msgstr ""
+"[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz\n"
+"[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe"
+
+#. type: Plain text
+#: doc/tutorial.md:125
+msgid "## Compiling your first program"
+msgstr "## 最初のプログラム"
+
+#. type: Plain text
+#: doc/tutorial.md:128
+msgid ""
+"Rust program files are, by convention, given the extension `.rs`. Say we "
+"have a file `hello.rs` containing this program:"
+msgstr ""
+"Rust プログラムのファイルの拡張子は、慣例的に `.rs` とされています。以下の内"
+"容を持つファイル、`hello.rs` が存在するとします。"
+
+#. type: Plain text
+#: doc/tutorial.md:134
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn main() {\n"
+" println(\"hello?\");\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:138
+msgid ""
+"If the Rust compiler was installed successfully, running `rustc hello.rs` "
+"will produce an executable called `hello` (or `hello.exe` on Windows) which, "
+"upon running, will likely do exactly what you expect."
+msgstr ""
+"Rust のコンパイラが正しくインストールされている場合、 `rustc hello.rs` を実行"
+"することで、実行ファイル `hello` (Windows の場合 `hello.exe`) を生成すること"
+"が可能です。このファイルを実行すれば、予想通りの出力が得られるでしょう。"
+
+#. type: Plain text
+#: doc/tutorial.md:143
+msgid ""
+"The Rust compiler tries to provide useful information when it encounters an "
+"error. If you introduce an error into the program (for example, by changing "
+"`println` to some nonexistent function), and then compile it, you'll see an "
+"error message like this:"
+msgstr ""
+"コンパイルエラーが発生した場合、Rust コンパイラはエラー解決のための情報を出力"
+"します。プログラム中にエラーが含まれる場合 (上記プログラムの `println` を存在"
+"しない別の名前に変更した場合など)、コンパイル時に以下のようなエラーメッセージ"
+"が出力されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:149
+#, no-wrap
+msgid ""
+"~~~~ {.notrust}\n"
+"hello.rs:2:4: 2:16 error: unresolved name: print_with_unicorns\n"
+"hello.rs:2 print_with_unicorns(\"hello?\");\n"
+" ^~~~~~~~~~~~~~~~~~~~~~~\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:156
+msgid ""
+"In its simplest form, a Rust program is a `.rs` file with some types and "
+"functions defined in it. If it has a `main` function, it can be compiled to "
+"an executable. Rust does not allow code that's not a declaration to appear "
+"at the top level of the file: all statements must live inside a function. "
+"Rust programs can also be compiled as libraries, and included in other "
+"programs."
+msgstr ""
+"最も単純な Rust プログラムは、いくつかの型や関数が定義された `.rs` ファイルの"
+"みからなります。`.rs` ファイルをコンパイルして実行可能ファイルを作成する場"
+"合、ファイル中に `main` 関数が含まれている必要があります。Rust プログラムで"
+"ファイルのトップレベルに記述可能なのは宣言 (declaration) のみです。ステートメ"
+"ント (statement) は、すべて関数内部に記述されます。Rust のプログラムは、他の"
+"プログラムから利用するライブラリとしてコンパイルすることも可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:158
+msgid "## Using the rust tool"
+msgstr "## `rust` コマンドを利用する"
+
+#. type: Plain text
+#: doc/tutorial.md:163
+msgid ""
+"While using `rustc` directly to generate your executables, and then running "
+"them manually is a perfectly valid way to test your code, for smaller "
+"projects, prototypes, or if you're a beginner, it might be more convenient "
+"to use the `rust` tool."
+msgstr ""
+"作成したプログラムのテストを行うには、`rustc` でコンパイル後、生成されたファ"
+"イルを手動で実行する方法だけではなく、 `rust` ツールを利用する方法もありま"
+"す。小さなプロジェクトやプロトタイプを作成する場合、もしくはあなたが初心者の"
+"場合は、 `rust` ツールによりコンパイルから実行までの一連の流れを簡単に行うこ"
+"とができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:169
+msgid ""
+"The `rust` tool provides central access to the other rust tools, as well as "
+"handy shortcuts for directly running source files. For example, if you have "
+"a file `foo.rs` in your current directory, `rust run foo.rs` would attempt "
+"to compile it and, if successful, directly run the resulting binary."
+msgstr ""
+"`rust` ツールには、rust ツール群を統一的なインターフェースで呼び出す機能だけ"
+"でなく、ソースファイルを直接実行する便利なショートカット機能もあります。例え"
+"ば、カレントディレクトリにある `foo.rs` を実行しようとする場合、 `rust run "
+"foo.rs` を実行することで、コンパイルから、コンパイル成功後に生成されるバイナ"
+"リの実行までを自動的に行なってくれます。"
+
+#. type: Plain text
+#: doc/tutorial.md:172
+msgid ""
+"To get a list of all available commands, simply call `rust` without any "
+"argument."
+msgstr ""
+"実行可能なコマンドを調べるためには、引数を与えず `rust` コマンドを実行してく"
+"ださい。"
+
+#. type: Plain text
+#: doc/tutorial.md:174
+msgid "## Editing Rust code"
+msgstr "## Rust のコードを編集する"
+
+#. type: Plain text
+#: doc/tutorial.md:184
+msgid ""
+"There are vim highlighting and indentation scripts in the Rust source "
+"distribution under `src/etc/vim/`. There is an emacs mode under `src/etc/"
+"emacs/` called `rust-mode`, but do read the instructions included in that "
+"directory. In particular, if you are running emacs 24, then using emacs's "
+"internal package manager to install `rust-mode` is the easiest way to keep "
+"it up to date. There is also a package for Sublime Text 2, available both "
+"[standalone][sublime] and through [Sublime Package Control][sublime-pkg], "
+"and support for Kate under `src/etc/kate`."
+msgstr ""
+"vim のハイライトとインデント用スクリプトは、Rust のソースツリーの `src/etc/"
+"vim` 以下にあります。emacs の Rust 編集用モードの `rust-mode` は、 `src/etc/"
+"emacs/` 以下にありますが、当該ディレクトリに配置されているインストール手順に"
+"従って操作する必要があります。 emacs 24 以降をご利用の場合、 emacs 組み込みの"
+"パッケージマネージャで `rust-mode` をインストールするのが最もお手軽です。"
+"Sublime Text 2 用のパッケージは、[スタンドアロン版][sublime] と、[Sublime "
+"Package Control][sublime-pkg] 版の2つがあります。Kate 向けパッケージは `src/"
+"etc/kate` 以下です。"
+
+#. type: Plain text
+#: doc/tutorial.md:188
+msgid ""
+"There is ctags support via `src/etc/ctags.rust`, but many other tools and "
+"editors are not yet supported. If you end up writing a Rust mode for your "
+"favorite editor, let us know so that we can link to it."
+msgstr ""
+"ctags は `src/etc/ctags.rust` を利用することで rust をサポートします。多くの"
+"ツールやエディタは rust をサポートしていません。もしあなたがお気に入りのエ"
+"ディタ向けのRust モードを作成した場合、リンクを貼りたいのでお知らせください。"
+
+#. type: Plain text
+#: doc/tutorial.md:191
+msgid ""
+"[sublime]: http://github.com/dbp/sublime-rust [sublime-pkg]: http://wbond."
+"net/sublime_packages/package_control"
+msgstr ""
+"[sublime]: http://github.com/dbp/sublime-rust\n"
+"[sublime-pkg]: http://wbond.net/sublime_packages/package_control"
+
+#. type: Plain text
+#: doc/tutorial.md:193
+msgid "# Syntax basics"
+msgstr "# 基本的な構文"
+
+#. type: Plain text
+#: doc/tutorial.md:201
+msgid ""
+"Assuming you've programmed in any C-family language (C++, Java, JavaScript, "
+"C#, or PHP), Rust will feel familiar. Code is arranged in blocks delineated "
+"by curly braces; there are control structures for branching and looping, "
+"like the familiar `if` and `while`; function calls are written `myfunc(arg1, "
+"arg2)`; operators are written the same and mostly have the same precedence "
+"as in C; comments are again like C; module names are separated with double-"
+"colon (`::`) as with C++."
+msgstr ""
+"あなたが C 系統の言語 (C++, Java, JavaScript, C# または PHP) でプログラミング"
+"したことがあれば、Rust の構文には馴染みがあるでしょう。コードは波括弧で区切ら"
+"れたブロックの中に配置され、分岐やループのための制御構文はお馴染みの `if` と "
+"`while` で、関数呼び出しは `myfunc(arg1, arg2)` と書け、演算子は C のものと同"
+"じで、優先順位もほとんど同じで、コメントもまた C と同じで、モジュール名のセパ"
+"レータは C++ と同様 2つのコロン (`::`) です。"
+
+#. type: Plain text
+#: doc/tutorial.md:206
+msgid ""
+"The main surface difference to be aware of is that the condition at the head "
+"of control structures like `if` and `while` does not require parentheses, "
+"while their bodies *must* be wrapped in braces. Single-statement, unbraced "
+"bodies are not allowed."
+msgstr ""
+"表記上の違いで注目すべき点は、`if` や `while` などの制御構造の先頭にある条件"
+"句を丸括弧で囲う必要がない点と、ボディ部をで波括弧で **囲わなければならない"
+"** という点です。ボディ部が単一のステートメントであっても、波括弧を省略するこ"
+"とはできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:219
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# mod universe { pub fn recalibrate() -> bool { true } }\n"
+"fn main() {\n"
+" /* A simple loop */\n"
+" loop {\n"
+" // A tricky calculation\n"
+" if universe::recalibrate() {\n"
+" return;\n"
+" }\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+"~~~~\n"
+"# mod universe { pub fn recalibrate() -> bool { true } }\n"
+"fn main() {\n"
+" /* シンプルなループ */\n"
+" loop {\n"
+" // 複雑な計算\n"
+" if universe::recalibrate() {\n"
+" return;\n"
+" }\n"
+" }\n"
+"}\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:223
+msgid ""
+"The `let` keyword introduces a local variable. Variables are immutable by "
+"default. To introduce a local variable that you can re-assign later, use "
+"`let mut` instead."
+msgstr ""
+"`let` キーワードにより、ローカル変数を定義します。変数はデフォルトでは "
+"immutable (変更不可) です。再代入可能なローカル変数を定義するためには、`let "
+"mut` を用います。"
+
+#. type: Plain text
+#: doc/tutorial.md:227
+msgid "~~~~ let hi = \"hi\"; let mut count = 0;"
+msgstr ""
+"~~~~\n"
+" let hi = \"hi\";\n"
+" let mut count = 0;"
+
+#. type: Plain text
+#: doc/tutorial.md:233
+#, no-wrap
+msgid ""
+"while count < 10 {\n"
+" println(fmt!(\"count: %?\", count));\n"
+" count += 1;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:237
+msgid ""
+"Although Rust can almost always infer the types of local variables, you can "
+"specify a variable's type by following it with a colon, then the type name. "
+"Static items, on the other hand, always require a type annotation."
+msgstr ""
+"Rust は、ほぼすべてのローカル変数の型を推論してくれますが、コロンの後に続けて"
+"型名を書くことで、明示的に変数の型を指定することもできます。一方、静的な項目 "
+"(static item) には、常に型注釈を指定しなければなりません。"
+
+#. type: Plain text
+#: doc/tutorial.md:243
+msgid ""
+"~~~~ static MONSTER_FACTOR: float = 57.8; let monster_size = MONSTER_FACTOR "
+"* 10.0; let monster_size: int = 50; ~~~~"
+msgstr ""
+"~~~~\n"
+"static MONSTER_FACTOR: float = 57.8;\n"
+"let monster_size = MONSTER_FACTOR * 10.0;\n"
+"let monster_size: int = 50;\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:252
+msgid ""
+"Local variables may shadow earlier declarations, as in the previous example: "
+"`monster_size` was first declared as a `float`, and then a second "
+"`monster_size` was declared as an `int`. If you were to actually compile "
+"this example, though, the compiler would determine that the first "
+"`monster_size` is unused and issue a warning (because this situation is "
+"likely to indicate a programmer error). For occasions where unused variables "
+"are intentional, their names may be prefixed with an underscore to silence "
+"the warning, like `let _monster_size = 50;`."
+msgstr ""
+"ローカル変数は、先行する宣言を隠すことがあります。先の例では、1つ目の "
+"`monster_size` は `float` として宣言され、2つ目の `monster_size` は `int` と"
+"して宣言されています。このプログラムをコンパイルした場合、「1つ目の "
+"`monster_size` は未使用である」という警告メッセージが出力されます (プログラマ"
+"が何らかの誤りを犯している可能性があるため)。未使用変数の存在が意図的なもので"
+"あった場合、未使用変数名の先頭にアンダースコアをつけることで、警告を抑制でき"
+"ます (`let _monster_size = 50;`)。"
+
+#. type: Plain text
+#: doc/tutorial.md:258
+msgid ""
+"Rust identifiers start with an alphabetic character or an underscore, and "
+"after that may contain any sequence of alphabetic characters, numbers, or "
+"underscores. The preferred style is to write function, variable, and module "
+"names with lowercase letters, using underscores where they help readability, "
+"while writing types in camel case."
+msgstr ""
+"Rust の識別子 (identifier) は、アルファベット、数字、またはアンダースコア "
+"(`_`) から構成されますが、先頭の文字は数字以外でなければなりません。関数名、"
+"変数名、モジュール名はスネークケース (アルファベットは小文字にし、単語間をア"
+"ンダースコアで区切る) にし、型の名前はアッパーキャメルケースにすることが推奨"
+"されています。"
+
+#. type: Plain text
+#: doc/tutorial.md:263
+#, no-wrap
+msgid ""
+"~~~\n"
+"let my_variable = 100;\n"
+"type MyType = int; // primitive types are _not_ camel case\n"
+"~~~\n"
+msgstr ""
+"~~~\n"
+"let my_variable = 100;\n"
+"type MyType = int; // プリミティブ型はキャメルケース __ではない__\n"
+"~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:265
+msgid "## Expressions and semicolons"
+msgstr "## 式とセミコロン"
+
+#. type: Plain text
+#: doc/tutorial.md:271
+msgid ""
+"Though it isn't apparent in all code, there is a fundamental difference "
+"between Rust's syntax and predecessors like C. Many constructs that are "
+"statements in C are expressions in Rust, allowing code to be more concise. "
+"For example, you might write a piece of code like this:"
+msgstr ""
+"コードの見た目から明らかではないのですが、Rust の構文と、C 等の先行言語の構文"
+"との間の根本的な違いがとして、C ではステートメントとして扱われる多くの構文要"
+"素が、Rust では式として扱われるという点があります。Rust のこの特徴により、"
+"コードをより簡潔に書くことができるようになります。例えば、C 系言語では以下の"
+"ようにコードを書きますが、"
+
+#. type: Plain text
+#: doc/tutorial.md:283
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# let item = \"salad\";\n"
+"let price;\n"
+"if item == \"salad\" {\n"
+" price = 3.50;\n"
+"} else if item == \"muffin\" {\n"
+" price = 2.25;\n"
+"} else {\n"
+" price = 2.00;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:285
+msgid "But, in Rust, you don't have to repeat the name `price`:"
+msgstr "Rust では、変数名 `price` を繰り返し書く必要はありません。"
+
+#. type: Plain text
+#: doc/tutorial.md:297
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# let item = \"salad\";\n"
+"let price =\n"
+" if item == \"salad\" {\n"
+" 3.50\n"
+" } else if item == \"muffin\" {\n"
+" 2.25\n"
+" } else {\n"
+" 2.00\n"
+" };\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:303
+msgid ""
+"Both pieces of code are exactly equivalent: they assign a value to `price` "
+"depending on the condition that holds. Note that there are no semicolons in "
+"the blocks of the second snippet. This is important: the lack of a semicolon "
+"after the last statement in a braced block gives the whole block the value "
+"of that last expression."
+msgstr ""
+"どちらのコードも、全く等価です。`price` には、条件 (この場合は `item` の値) "
+"に対応した値が代入されます。2つ目のコード例では、ブロックの中にセミコロンが書"
+"かれていないことに注意してください。ブロック内の最後のステートメントの後にセ"
+"ミコロンがない場合、**ブロック全体の値 (ブロックを式として評価した際の値) は"
+"最後の式の値になります**。"
+
+#. type: Plain text
+#: doc/tutorial.md:309
+msgid ""
+"Put another way, the semicolon in Rust *ignores the value of an "
+"expression*. Thus, if the branches of the `if` had looked like `{ 4; }`, "
+"the above example would simply assign `()` (nil or void) to `price`. But "
+"without the semicolon, each branch has a different value, and `price` gets "
+"the value of the branch that was taken."
+msgstr ""
+"言い換えると、Rust では、セミコロンにより **式の値が無視されます。** したがっ"
+"て、上記の例で `if` のすべての節 (branch) が `{ 4; }` のように書かれていたと"
+"したら、`price` には単に `()` (nil または void の意) が代入されます。しかし、"
+"式にセミコロンが付けられていない場合、各節はそれぞれ異なる値を持ち、 `price` "
+"には節のうち実行されたものの値が代入されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:314
+msgid ""
+"In short, everything that's not a declaration (declarations are `let` for "
+"variables; `fn` for functions; and any top-level named items such as [traits]"
+"(#traits), [enum types](#enums), and static items) is an expression, "
+"including function bodies."
+msgstr ""
+"まとめると、宣言 (変数の `let`, 関数の `fn`, [トレイト](#トレイト) や [列挙"
+"型](#列挙型)、静的な項目などの、トップレベルで名前を持つ項目) でないものは、"
+"すべてが式となります。関数のボディ部も式です。"
+
+#. type: Plain text
+#: doc/tutorial.md:322
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn is_four(x: int) -> bool {\n"
+" // No need for a return statement. The result of the expression\n"
+" // is used as the return value.\n"
+" x == 4\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+"~~~~\n"
+"fn is_four(x: int) -> bool {\n"
+" // return ステートメントは省略可能。最後の式の値が戻り値となる。\n"
+" x == 4\n"
+"}\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:324
+msgid "## Primitive types and literals"
+msgstr "## プリミティブ型とリテラル"
+
+#. type: Plain text
+#: doc/tutorial.md:331
+msgid ""
+"There are general signed and unsigned integer types, `int` and `uint`, as "
+"well as 8-, 16-, 32-, and 64-bit variants, `i8`, `u16`, etc. Integers can "
+"be written in decimal (`144`), hexadecimal (`0x90`), or binary "
+"(`0b10010000`) base. Each integral type has a corresponding literal suffix "
+"that can be used to indicate the type of a literal: `i` for `int`, `u` for "
+"`uint`, `i8` for the `i8` type."
+msgstr ""
+"Rust には、他の言語と同様、符号付き整数の `int` と、符号なし整数の `uint` が"
+"あります。同様に、8 または 16, 32, 64 ビット幅の `i8`, `u16` などもあります。"
+"整数リテラルは、10進数 (`144`)、16進数 (`0x90`)、または2進数 (`0b10010000`) "
+"の表記が可能です。整数リテラルの型を表すための、各整数型に対応したサフィック"
+"スがあります。例えば、`i` は `int` 型、`u` は `uint` 型、`i8` は `i8` 型に対"
+"応します。"
+
+#. type: Plain text
+#: doc/tutorial.md:337
+msgid ""
+"In the absence of an integer literal suffix, Rust will infer the integer "
+"type based on type annotations and function signatures in the surrounding "
+"program. In the absence of any type information at all, Rust will assume "
+"that an unsuffixed integer literal has type `int`."
+msgstr ""
+"サフィックスが省略されている整数リテラルの型は、周囲にある型アノテーションや"
+"関数のシグネチャから推論されます。型について一切情報が得られない場合、サ"
+"フィックスなしの整数リテラルは `int` 型だとみなされます。"
+
+#. type: Plain text
+#: doc/tutorial.md:344
+#, no-wrap
+msgid ""
+"~~~~\n"
+"let a = 1; // a is an int\n"
+"let b = 10i; // b is an int, due to the 'i' suffix\n"
+"let c = 100u; // c is a uint\n"
+"let d = 1000i32; // d is an i32\n"
+"~~~~\n"
+msgstr ""
+"~~~~\n"
+"let a = 1; // a は int\n"
+"let b = 10i; // b は int (サフィックス 'i' がある)\n"
+"let c = 100u; // c は uint\n"
+"let d = 1000i32; // d は i32\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:349
+msgid ""
+"There are three floating-point types: `float`, `f32`, and `f64`. Floating-"
+"point numbers are written `0.0`, `1e6`, or `2.1e-4`. Like integers, "
+"floating-point literals are inferred to the correct type. Suffixes `f`, "
+"`f32`, and `f64` can be used to create literals of a specific type."
+msgstr ""
+"浮動小数型は、 `float`, `f32`, `f64` の3種類があります。浮動小数リテラルは "
+"`0.0` や、 `1e6`、 `2.1e-4` といった表記が可能です。整数と同じく、サフィック"
+"スが省略された浮動小数リテラルは型推論されます。浮動小数のサフィックスは "
+"`f`、`f32`、`f64` の3種類で、リテラルの末尾につけることで、対応する型の値を作"
+"り出すことができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:351
+msgid "The keywords `true` and `false` produce literals of type `bool`."
+msgstr "`true` キーワードと `false` キーワードは、`bool` 型のリテラルです。"
+
+#. type: Plain text
+#: doc/tutorial.md:358
+msgid ""
+"Characters, the `char` type, are four-byte Unicode codepoints, whose "
+"literals are written between single quotes, as in `'x'`. Just like C, Rust "
+"understands a number of character escapes, using the backslash character, "
+"such as `\\n`, `\\r`, and `\\t`. String literals, written between double "
+"quotes, allow the same escape sequences. More on strings [later](#vectors-"
+"and-strings)."
+msgstr ""
+"文字は `char` 型で表され、4バイトの Unicode コードポイントに対応しています。"
+"`'x'` のように、文字をシングルクオートで囲んだものが文字リテラルです。C と同"
+"様、 Rust もバックスラッシュを使ったエスケープシーケンス (`\\n`, `\\r`, `"
+"\\t`) に対応しています。文字列リテラル (複数の文字をダブルクオートで囲ったも"
+"の) も同じエスケープシーケンスに対応しています。詳細は [ベクタと文字列](#ベク"
+"タと文字列) の章で述べます。"
+
+#. type: Plain text
+#: doc/tutorial.md:360
+msgid "The nil type, written `()`, has a single value, also written `()`."
+msgstr ""
+"nil 型は `()` と表記されます。 nil 型の唯一の値も `()` と表記されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:362
+msgid "## Operators"
+msgstr "## 演算子"
+
+#. type: Plain text
+#: doc/tutorial.md:367
+msgid ""
+"Rust's set of operators contains very few surprises. Arithmetic is done with "
+"`*`, `/`, `%`, `+`, and `-` (multiply, quotient, remainder, add, and "
+"subtract). `-` is also a unary prefix operator that negates numbers. As in "
+"C, the bitwise operators `>>`, `<<`, `&`, `|`, and `^` are also supported."
+msgstr ""
+"Rust の演算子には、あまり変わったものはありません。算術演算子は `*` (乗算)、 "
+"`/` (除算), `%` (剰余), `+` (加算), `-` (減算) です。`-` は数の符号を反転する"
+"単行演算子でもあります。C と同様、ビット演算子 `>>`, `<<`, `&`, `|`, `^` もサ"
+"ポートされています。"
+
+#. type: Plain text
+#: doc/tutorial.md:370
+msgid ""
+"Note that, if applied to an integer value, `!` flips all the bits (like `~` "
+"in C)."
+msgstr ""
+"整数型に対して `!` 演算子を適用すると、ビット単位での反転操作 (C の `~` と同"
+"じ動作) が行われることに注意してください。"
+
+#. type: Plain text
+#: doc/tutorial.md:374
+msgid ""
+"The comparison operators are the traditional `==`, `!=`, `<`, `>`, `<=`, and "
+"`>=`. Short-circuiting (lazy) boolean operators are written `&&` (and) and "
+"`||` (or)."
+msgstr ""
+"比較演算子は、従来の言語と同じく、`==`, `!=`, `<`, `>`, `<=`, `>=` です。短絡"
+"評価 (遅延評価) されるブール演算子は、 `&&` (and 演算) と `||` (or 演算) があ"
+"ります。"
+
+#. type: Plain text
+#: doc/tutorial.md:379
+msgid ""
+"For type casting, Rust uses the binary `as` operator. It takes an "
+"expression on the left side and a type on the right side and will, if a "
+"meaningful conversion exists, convert the result of the expression to the "
+"given type."
+msgstr ""
+"Rust では、型のキャストには二項演算子 `as` を使います。`as` 演算子は、左辺に"
+"式、右辺に型を取り、意味のある変換が可能な場合に限り、式の評価結果を指定され"
+"た型に変換します。"
+
+#. type: Plain text
+#: doc/tutorial.md:385
+msgid ""
+"~~~~ let x: float = 4.0; let y: uint = x as uint; assert!(y == 4u); ~~~~"
+msgstr ""
+"~~~~\n"
+"let x: float = 4.0;\n"
+"let y: uint = x as uint;\n"
+"assert!(y == 4u);\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:387
+msgid "## Syntax extensions"
+msgstr "## 構文拡張"
+
+#. type: Plain text
+#: doc/tutorial.md:394
+#, no-wrap
+msgid ""
+"*Syntax extensions* are special forms that are not built into the language,\n"
+"but are instead provided by the libraries. To make it clear to the reader when\n"
+"a name refers to a syntax extension, the names of all syntax extensions end\n"
+"with `!`. The standard library defines a few syntax extensions, the most\n"
+"useful of which is `fmt!`, a `sprintf`-style text formatter that you will\n"
+"often see in examples.\n"
+msgstr "**構文拡張** *(Syntax extensions)* は言語組み込みではなく、ライブラリにより提供される特殊形式 (スペシャルフォーム) です。プログラム中に構文拡張が登場したことを外見上明確にするため、構文拡張の名前には末尾に `!` をつけますなければなりません。標準ライブラリではいくつかの構文拡張が定義されていますが、その中でも最も有用なのは `fmt!` です。`fmt!` は `sprintf`スタイルの書式整形を行うもので、後のコード例の中でも何度か見かけることになるでしょう。\n"
+
+#. type: Plain text
+#: doc/tutorial.md:398
+msgid ""
+"`fmt!` supports most of the directives that [printf][pf] supports, but "
+"unlike printf, will give you a compile-time error when the types of the "
+"directives don't match the types of the arguments."
+msgstr ""
+"`fmt!` は、[`printf`][pf] がサポートするほとんどのディレクティブ (フォーマッ"
+"ト指定子) をサポートしますが、`printf` とは異なり、ディレクティブと引数の型が"
+"一致しない場合はコンパイルエラーとなります。"
+
+#. type: Plain text
+#: doc/tutorial.md:401
+msgid "~~~~ # let mystery_object = ();"
+msgstr ""
+"~~~~\n"
+"# let mystery_object = ();"
+
+#. type: Plain text
+#: doc/tutorial.md:403
+msgid "println(fmt!(\"%s is %d\", \"the answer\", 43));"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:407
+msgid ""
+"// %? will conveniently print any type println(fmt!(\"what is this thing: %?"
+"\", mystery_object)); ~~~~"
+msgstr ""
+"// %? は任意の型を表示できる便利なディレクティブです\n"
+"println(fmt!(\"what is this thing: %?\", mystery_object));\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:409
+msgid "[pf]: http://en.cppreference.com/w/cpp/io/c/fprintf"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:411
+msgid ""
+"You can define your own syntax extensions with the macro system. For "
+"details, see the [macro tutorial][macros]."
+msgstr ""
+"マクロシステムを利用すれば、独自に構文拡張を定義することも可能です。詳細は "
+"[マクロチュートリアル][macros] を参照してください。"
+
+#. type: Plain text
+#: doc/tutorial.md:413
+msgid "# Control structures"
+msgstr "# 制御構造"
+
+#. type: Plain text
+#: doc/tutorial.md:415
+msgid "## Conditionals"
+msgstr "## 条件式"
+
+#. type: Plain text
+#: doc/tutorial.md:419
+msgid ""
+"We've seen `if` expressions a few times already. To recap, braces are "
+"compulsory, an `if` can have an optional `else` clause, and multiple `if`/"
+"`else` constructs can be chained together:"
+msgstr ""
+"`if` 式は既に何度か登場しています。これまでの説明の要点をまとめると、波括弧は"
+"省略不可であり、`if` 式には省略可能な `else` 句があり、複数個の `if`/`else` "
+"構文は互いに連鎖できる、ということでした。"
+
+#. type: Plain text
+#: doc/tutorial.md:429
+#, no-wrap
+msgid ""
+"~~~~\n"
+"if false {\n"
+" println(\"that's odd\");\n"
+"} else if true {\n"
+" println(\"right\");\n"
+"} else {\n"
+" println(\"neither true nor false\");\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:434
+msgid ""
+"The condition given to an `if` construct *must* be of type `bool` (no "
+"implicit conversion happens). If the arms are blocks that have a value, this "
+"value must be of the same type for every arm in which control reaches the "
+"end of the block:"
+msgstr ""
+"`if` 構文の条件式は `bool` 型ででなければなりません (暗黙的な型変換は行われま"
+"せん)。同一の `if` 構文に属する arm のうち、制御がブロックの末尾まで到達し得"
+"るものは、すべて同じ型の値でなければなりません。"
+
+#. type: Plain text
+#: doc/tutorial.md:442
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn signum(x: int) -> int {\n"
+" if x < 0 { -1 }\n"
+" else if x > 0 { 1 }\n"
+" else { return 0 }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:444
+msgid "## Pattern matching"
+msgstr "## パターンマッチ"
+
+#. type: Plain text
+#: doc/tutorial.md:450
+msgid ""
+"Rust's `match` construct is a generalized, cleaned-up version of C's "
+"`switch` construct. You provide it with a value and a number of *arms*, each "
+"labelled with a pattern, and the code compares the value against each "
+"pattern in order until one matches. The matching pattern executes its "
+"corresponding arm."
+msgstr ""
+"Rust の `match` 構文は、C の `switch` 構文を整理・一般化したものです。"
+"`match` 構文は、パターンマッチの対象となる値と、いくつかの、 **arm** (**訳"
+"注:** 分岐条件と、条件を満たした場合に実行される式の組のこと。`match` の場合"
+"はパターンと式の組) から構成されます。`match` 構文では、指定された値とパター"
+"ンの比較をコード内で記述された順番通りに行います。比較の結果、値とパターンが"
+"マッチした場合、対応する式が実行されます。マッチしたパターンの後に現れるパ"
+"ターンとの比較は行われません。"
+
+#. type: Plain text
+#: doc/tutorial.md:460
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# let my_number = 1;\n"
+"match my_number {\n"
+" 0 => println(\"zero\"),\n"
+" 1 | 2 => println(\"one or two\"),\n"
+" 3..10 => println(\"three to ten\"),\n"
+" _ => println(\"something else\")\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:464
+msgid ""
+"Unlike in C, there is no \"falling through\" between arms: only one arm "
+"executes, and it doesn't have to explicitly `break` out of the construct "
+"when it is finished."
+msgstr ""
+"C とは異なり、Rust では arm 間での「フォールスルー」はないため、1つの arm の"
+"みが実行されます。 そのため、 `match` 構文から抜ける箇所を `break` により明示"
+"する必要はありません。"
+
+#. type: Plain text
+#: doc/tutorial.md:474
+msgid ""
+"A `match` arm consists of a *pattern*, then an arrow `=>`, followed by an "
+"*action* (expression). Literals are valid patterns and match only their own "
+"value. A single arm may match multiple different patterns by combining them "
+"with the pipe operator (`|`), so long as every pattern binds the same set of "
+"variables. Ranges of numeric literal patterns can be expressed with two "
+"dots, as in `M..N`. The underscore (`_`) is a wildcard pattern that matches "
+"any single value. The asterisk (`*`) is a different wildcard that can match "
+"one or more fields in an `enum` variant."
+msgstr ""
+"`match` の arm は、 **パターン** および矢印 `=>` と、それらに続く **アクショ"
+"ン** (式) から構成されます。リテラルはパターンとして利用可能で、リテラル自身"
+"の値のみとマッチするパターンを意味します。複数のパターンをパイプ演算子 (`|`) "
+"で結合させることで、複数の異なるパターンにマッチする単一の arm を作ることがで"
+"きます。ただし、変数の束縛を行うパターンをパイプ演算子で結合する場合は、すべ"
+"てのパータンで束縛する変数の名前・数が一致している必要があります (**訳注:** "
+"変数の束縛については、本節の後半で説明します)。指定した範囲に含まれる任意の数"
+"値にマッチするパターンは、2つのドットで `M..N` のように表記します。アンダース"
+"コア (`_`) は任意の値1つにマッチするワイルドカードパターンです。アスタリスク "
+"(`*`) は任意の値をもつ、`enum` バリアントの複数のフィールドにマッチする、ワイ"
+"ルドカードです (**訳注** `enum` については、[列挙型](#列挙型) の節で説明しま"
+"す)。"
+
+#. type: Plain text
+#: doc/tutorial.md:479
+msgid ""
+"The patterns in a match arm are followed by a fat arrow, `=>`, then an "
+"expression to evaluate. Each case is separated by commas. It's often "
+"convenient to use a block expression for each case, in which case the commas "
+"are optional."
+msgstr ""
+"`match` の各 arm はカンマ (`,`) は区切ります。 arm のアクションとしてブロック"
+"を記述することも可能で、その場合は arm 末尾のカンマを省略することが可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:487
+#, no-wrap
+msgid ""
+"~~~\n"
+"# let my_number = 1;\n"
+"match my_number {\n"
+" 0 => { println(\"zero\") }\n"
+" _ => { println(\"something else\") }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:492
+msgid ""
+"`match` constructs must be *exhaustive*: they must have an arm covering "
+"every possible case. For example, the typechecker would reject the previous "
+"example if the arm with the wildcard pattern was omitted."
+msgstr ""
+"`match` 構文は **網羅的** でなければなりません。すなわち、`match` 対象の値と"
+"同じ型を持つ任意の値に対し、少なくとも 1 つ以上のパターンがマッチするだけの "
+"arm を含んでいなければなりません。例えば、上記コード例のワイルドカードパター"
+"ンの arm を削除した場合、型検査によりコンパイルエラーとされます。"
+
+#. type: Plain text
+#: doc/tutorial.md:496
+msgid ""
+"A powerful application of pattern matching is *destructuring*: matching in "
+"order to bind names to the contents of data types."
+msgstr ""
+"パターンマッチの応用として、 **destructuring** という強力な機能があります。構"
+"造化代入とは、データ型内部の値を名前に束縛 (bind) することです。"
+
+#. type: Plain text
+#: doc/tutorial.md:500
+msgid ""
+"> ***Note:*** The following code makes use of tuples (`(float, float)`) "
+"which > are explained in section 5.3. For now you can think of tuples as a "
+"list of > items."
+msgstr ""
+"> ***注意:*** 以下のコード例では5.3 節で説明されるタプル (`(float, float)`) "
+"を使っています。現時点では、タプルは項目のリストのようなものだとみなしてくだ"
+"さい。"
+
+#. type: Plain text
+#: doc/tutorial.md:513
+#, no-wrap
+msgid ""
+"~~~~\n"
+"use std::float;\n"
+"use std::num::atan;\n"
+"fn angle(vector: (float, float)) -> float {\n"
+" let pi = float::consts::pi;\n"
+" match vector {\n"
+" (0f, y) if y < 0f => 1.5 * pi,\n"
+" (0f, y) => 0.5 * pi,\n"
+" (x, y) => atan(y / x)\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:519
+msgid ""
+"A variable name in a pattern matches any value, *and* binds that name to the "
+"value of the matched value inside of the arm's action. Thus, `(0f, y)` "
+"matches any tuple whose first element is zero, and binds `y` to the second "
+"element. `(x, y)` matches any two-element tuple, and binds both elements to "
+"variables."
+msgstr ""
+"パターン内に登場する変数は、任意の値にマッチ **するだけでなく**、arm のアク"
+"ション内ではマッチした値が変数の名前に束縛されます。従って、 `(0f, y)` は1つ"
+"目の要素が 0 である任意のタプルにマッチし、 `y` には2つ目の要素の値が束縛され"
+"ます。`(x, y)` は任意の2要素のタプルにマッチし、タプルの各要素がそれぞれの変"
+"数に束縛されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:526
+msgid ""
+"Any `match` arm can have a guard clause (written `if EXPR`), called a "
+"*pattern guard*, which is an expression of type `bool` that determines, "
+"after the pattern is found to match, whether the arm is taken or not. The "
+"variables bound by the pattern are in scope in this guard expression. The "
+"first arm in the `angle` example shows an example of a pattern guard."
+msgstr ""
+"`match` の任意の arm は **パターンガード** と呼ばれる、ガード節 (`if EXPR` と"
+"書かれる) を持つことができます。パターンガードは、 `bool` 型の値をもつ式で、"
+"値にマッチするパターンが見つかった後に評価され、arm が実行されるかどうかを決"
+"定します。パターンにより束縛される変数は、ガード式からも参照可能 (ガード式の"
+"スコープに含まれる) です。`angle` 関数の例の最初の arm に、パターンガードの使"
+"用例が示されています。"
+
+#. type: Plain text
+#: doc/tutorial.md:531
+msgid ""
+"You've already seen simple `let` bindings, but `let` is a little fancier "
+"than you've been led to believe. It, too, supports destructuring patterns. "
+"For example, you can write this to extract the fields from a tuple, "
+"introducing two variables at once: `a` and `b`."
+msgstr ""
+"`let` は単純な変数束縛だけではなく、パターンによる destructuring をサポートし"
+"ています。例えば、タプルからフィールドを抽出し、1度に2つの変数 `a` と `b` を"
+"定義することが可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:536
+msgid ""
+"~~~~ # fn get_tuple_of_two_ints() -> (int, int) { (1, 1) } let (a, b) = "
+"get_tuple_of_two_ints(); ~~~~"
+msgstr ""
+"~~~~\n"
+"# fn get_tuple_of_two_ints() -> (int, int) { (1, 1) }\n"
+"let (a, b) = get_tuple_of_two_ints();\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:540
+msgid ""
+"Let bindings only work with _irrefutable_ patterns: that is, patterns that "
+"can never fail to match. This excludes `let` from matching literals and most "
+"`enum` variants."
+msgstr ""
+"let による変数定義が可能なのは、パターンが __不可反駁__ (iefutable; 必ず値に"
+"マッチする) な場合のみです。この制限により、`let` を用いた destructuring で、"
+"リテラルやほとんどの `enum` バリアントをパターンとして用いることはできませ"
+"ん。"
+
+#. type: Plain text
+#: doc/tutorial.md:542
+msgid "## Loops"
+msgstr "## ループ"
+
+#. type: Plain text
+#: doc/tutorial.md:547
+msgid ""
+"`while` denotes a loop that iterates as long as its given condition (which "
+"must have type `bool`) evaluates to `true`. Inside a loop, the keyword "
+"`break` aborts the loop, and `loop` aborts the current iteration and "
+"continues with the next."
+msgstr ""
+"`while` は、与えられた条件 (`bool` 型の値でなければならない) が `true` と評価"
+"されている間、繰り返し実行されるループを表します。`break` キーワードは、ルー"
+"プの実行を中断させます。`loop` キーワードは、現在実行中の繰り返し (イテレー"
+"ション) を中断し、次の繰り返しを実行します。"
+
+#. type: Plain text
+#: doc/tutorial.md:554
+#, no-wrap
+msgid ""
+"~~~~\n"
+"let mut cake_amount = 8;\n"
+"while cake_amount > 0 {\n"
+" cake_amount -= 1;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:556
+msgid ""
+"`loop` denotes an infinite loop, and is the preferred way of writing `while "
+"true`:"
+msgstr ""
+"`loop` は無限ループを表します。 `while true` と書く代わりに `loop` と書くこと"
+"が推奨されています。"
+
+#. type: Plain text
+#: doc/tutorial.md:566
+#, no-wrap
+msgid ""
+"~~~~\n"
+"use std::int;\n"
+"let mut x = 5;\n"
+"loop {\n"
+" x += x - 3;\n"
+" if x % 5 == 0 { break; }\n"
+" println(int::to_str(x));\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:569
+msgid ""
+"This code prints out a weird sequence of numbers and stops as soon as it "
+"finds one that can be divided by five."
+msgstr "このコードは 5 で割り切れる数値が現れるまで、数値を出力し続けます。"
+
+#. type: Plain text
+#: doc/tutorial.md:571
+msgid "# Data structures"
+msgstr "# データ構造"
+
+#. type: Plain text
+#: doc/tutorial.md:573
+msgid "## Structs"
+msgstr "## 構造体"
+
+#. type: Plain text
+#: doc/tutorial.md:578
+msgid ""
+"Rust struct types must be declared before they are used using the `struct` "
+"syntax: `struct Name { field1: T1, field2: T2 [, ...] }`, where `T1`, "
+"`T2`, ... denote types. To construct a struct, use the same syntax, but "
+"leave off the `struct`: for example: `Point { x: 1.0, y: 2.0 }`."
+msgstr ""
+"Rust の構造体 (struct) 型を利用するためには、`struct Name { field1: T1, "
+"field2: T2 [, ...] }` (`T1`, `T2`, .. は型を意味する) のように、 `struct` 構"
+"文を使った型の宣言が必要です。構造体型の値は、`Point { x: 1.0, y: 2.0 }` のよ"
+"うに、構造体宣言から `struct` を取り除いたものと同じ構文で作成します。"
+
+#. type: Plain text
+#: doc/tutorial.md:582
+msgid ""
+"Structs are quite similar to C structs and are even laid out the same way in "
+"memory (so you can read from a Rust struct in C, and vice-versa). Use the "
+"dot operator to access struct fields, as in `mypoint.x`."
+msgstr ""
+"Rust の構造体は C の構造体とよく似ており、メモリ上のレイアウトも C と同じで"
+"す (そのため、Rust と C で相互に構造体を読み込むことが可能です)。構造体の"
+"フィールドにアクセスするには、 `mypoint.x` のように、ドット演算子を用います。"
+
+#. type: Plain text
+#: doc/tutorial.md:589
+#, no-wrap
+msgid ""
+"~~~~\n"
+"struct Point {\n"
+" x: float,\n"
+" y: float\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:593
+msgid ""
+"Inherited mutability means that any field of a struct may be mutable, if the "
+"struct is in a mutable slot (or a field of a struct in a mutable slot, and "
+"so forth)."
+msgstr ""
+"継承ミュータビリティ (inherited mutability) とは、構造体自体がミュータブルな"
+"スロットに配置されている場合、構造体のすべてのフィールドもミュータブルになる"
+"という性質を意味する言葉です (ミュータブルなスロットに配置された構造体の"
+"フィールドに配置された構造体のフィールドもまた、ミュータブルになります) 。"
+
+#. type: Plain text
+#: doc/tutorial.md:597
+msgid ""
+"With a value (say, `mypoint`) of such a type in a mutable location, you can "
+"do `mypoint.y += 1.0`. But in an immutable location, such an assignment to a "
+"struct without inherited mutability would result in a type error."
+msgstr ""
+"ある構造体の値 (仮に `mypoint` とします) がミュータブルな場所に配置された場"
+"合、 `mypoint.y += 1.0` というような操作を行うことができます。しかし、構造体"
+"がイミュータブルな場所に配置された場合、ミュータビリティは継承されないため、"
+"このような代入操作は型エラーとなります。"
+
+#. type: Plain text
+#: doc/tutorial.md:602
+msgid ""
+"~~~~ {.xfail-test} # struct Point { x: float, y: float } let mut mypoint = "
+"Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+msgstr ""
+"~~~~ {.xfail-test}\n"
+"# struct Point { x: float, y: float }\n"
+"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
+"let origin = Point { x: 0.0, y: 0.0 };"
+
+#. type: Plain text
+#: doc/tutorial.md:606
+msgid ""
+"mypoint.y += 1.0; // mypoint is mutable, and its fields as well origin.y += "
+"1.0; // ERROR: assigning to immutable field ~~~~"
+msgstr ""
+"mypoint.y += 1.0;\n"
+"// mypoint はミュータブル\n"
+"origin.y += 1.0; // ERROR: assigning to immutable field\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:609
+msgid ""
+"`match` patterns destructure structs. The basic syntax is `Name { fieldname: "
+"pattern, ... }`:"
+msgstr ""
+"`match` のパターンで構造体の destructuring を行うことも可能です。パターン"
+"は、 `Name { fieldname: pattern, ... }` という構文を持ちます。"
+
+#. type: Plain text
+#: doc/tutorial.md:618
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# struct Point { x: float, y: float }\n"
+"# let mypoint = Point { x: 0.0, y: 0.0 };\n"
+"match mypoint {\n"
+" Point { x: 0.0, y: yy } => { println(yy.to_str()); }\n"
+" Point { x: xx, y: yy } => { println(xx.to_str() + \" \" + yy.to_str()); }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:625
+msgid ""
+"In general, the field names of a struct do not have to appear in the same "
+"order they appear in the type. When you are not interested in all the fields "
+"of a struct, a struct pattern may end with `, _` (as in `Name { field1, _ }"
+"`) to indicate that you're ignoring all other fields. Additionally, struct "
+"fields have a shorthand matching form that simply reuses the field name as "
+"the binding name."
+msgstr ""
+"構造体のフィールド名の並び順は、型定義での並び順と同じにする必要はありませ"
+"ん。構造体のパターンマッチで、すべてのフィールドについて考える必要がない場合"
+"は、`Name { field1, _ }` のように、末尾に `, _` をつけることで、他のすべての"
+"フィールドを無視することができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:633
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point { x: float, y: float }\n"
+"# let mypoint = Point { x: 0.0, y: 0.0 };\n"
+"match mypoint {\n"
+" Point { x, _ } => { println(x.to_str()) }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:635
+msgid "## Enums"
+msgstr "## 列挙型"
+
+#. type: Plain text
+#: doc/tutorial.md:638
+msgid ""
+"Enums are datatypes that have several alternate representations. For "
+"example, consider the type shown earlier:"
+msgstr ""
+"列挙型 (enum) は、いくつかの代替表現を持つデータ型です。例えば、以下の型につ"
+"いて考えます。"
+
+#. type: Plain text
+#: doc/tutorial.md:646
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# struct Point { x: float, y: float }\n"
+"enum Shape {\n"
+" Circle(Point, float),\n"
+" Rectangle(Point, Point)\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:652
+msgid ""
+"A value of this type is either a `Circle`, in which case it contains a "
+"`Point` struct and a float, or a `Rectangle`, in which case it contains two "
+"`Point` structs. The run-time representation of such a value includes an "
+"identifier of the actual form that it holds, much like the \"tagged union\" "
+"pattern in C, but with better static guarantees."
+msgstr ""
+"この型の値は、`Point` 構造体と `float` を含む `Circle` か、2つの `Point` 構造"
+"体を含む `Rectangle` のどちらかになります。列挙型の値の実行時表現には、値がど"
+"の形式をとっているのか示す識別子が含まれます。この表現方法は C の \"タグ付き"
+"共用体\" と非常によく似ていますが、Rust の列挙型はコンパイラにより値の正当性"
+"が静的に保証されるという点でより良いものとなっています。"
+
+#. type: Plain text
+#: doc/tutorial.md:658
+msgid ""
+"The above declaration will define a type `Shape` that can refer to such "
+"shapes, and two functions, `Circle` and `Rectangle`, which can be used to "
+"construct values of the type (taking arguments of the specified types). So "
+"`Circle(Point { x: 0f, y: 0f }, 10f)` is the way to create a new circle."
+msgstr ""
+"上記の宣言は `Shape` 型と `Circle` と `Rectangle` という2つの関数も同時に定義"
+"します。これらの関数により、関数名に対応した `Shape` 型の値を構築することがで"
+"きます (引数の型も列挙型宣言時に指定されたものをとります)。例えば、"
+"`Circle(Point { x: 0f, y: 0f }, 10f)` という記述により、新しい circle を作る"
+"ことができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:661
+msgid ""
+"Enum variants need not have parameters. This `enum` declaration, for "
+"example, is equivalent to a C enum:"
+msgstr ""
+"列挙型のバリアントはパラメータを省略することもできます。以下の例の `enum` 宣"
+"言は C の列挙型と等価です。"
+
+#. type: Plain text
+#: doc/tutorial.md:670
+#, no-wrap
+msgid ""
+"~~~~\n"
+"enum Direction {\n"
+" North,\n"
+" East,\n"
+" South,\n"
+" West\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:673
+msgid ""
+"This declaration defines `North`, `East`, `South`, and `West` as constants, "
+"all of which have type `Direction`."
+msgstr ""
+"この宣言は `Direction` 型の定数 `North`, `East`, `South`, `West` を定義しま"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:677
+msgid ""
+"When an enum is C-like (that is, when none of the variants have parameters), "
+"it is possible to explicitly set the discriminator values to a constant "
+"value:"
+msgstr ""
+"列挙型が Cライクな (すべてのバリアントがパラメータを持たない) 場合、各定数の"
+"識別値 (discriminator value) を明示的に指定することも可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:685
+#, no-wrap
+msgid ""
+"~~~~\n"
+"enum Color {\n"
+" Red = 0xff0000,\n"
+" Green = 0x00ff00,\n"
+" Blue = 0x0000ff\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:690
+msgid ""
+"If an explicit discriminator is not specified for a variant, the value "
+"defaults to the value of the previous variant plus one. If the first variant "
+"does not have a discriminator, it defaults to 0. For example, the value of "
+"`North` is 0, `East` is 1, `South` is 2, and `West` is 3."
+msgstr ""
+"バリアントの識別値が明に指定されていない場合、1つ前のバリアントの値に1を足し"
+"たものが設定されます。また、最初のバリアントの場合は0が設定されます。上記の例"
+"で言うと、 `North` は 0、 `East` は 1、 `South` は 2、`West` は3となります。"
+
+#. type: Plain text
+#: doc/tutorial.md:693
+msgid ""
+"When an enum is C-like, you can apply the `as` cast operator to convert it "
+"to its discriminator value as an `int`."
+msgstr ""
+"C ライクな列挙型の値は、キャスト演算子 `as` を適用することで、`int` 型の識別"
+"値へ変換することができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:697
+msgid ""
+"For enum types with multiple variants, destructuring is the only way to get "
+"at their contents. All variant constructors can be used as patterns, as in "
+"this definition of `area`:"
+msgstr ""
+"複数のバリアントを持つ列挙型で、列挙型値の内部のデータを取得するには、 "
+"destructuring を使う必要があります。以下の `area` 関数の例のように、バリアン"
+"トのコンストラクタは、パターンとして用いることもできます。"
+
+#. type: Plain text
+#: doc/tutorial.md:709
+#, no-wrap
+msgid ""
+"~~~~\n"
+"use std::float;\n"
+"# struct Point {x: float, y: float}\n"
+"# enum Shape { Circle(Point, float), Rectangle(Point, Point) }\n"
+"fn area(sh: Shape) -> float {\n"
+" match sh {\n"
+" Circle(_, size) => float::consts::pi * size * size,\n"
+" Rectangle(Point { x, y }, Point { x: x2, y: y2 }) => (x2 - x) * (y2 - y)\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:714
+msgid ""
+"You can write a lone `_` to ignore an individual field, and can ignore all "
+"fields of a variant like: `Circle(*)`. As in their introduction form, "
+"nullary enum patterns are written without parentheses."
+msgstr ""
+"パターンマッチの際に、特定のフィールドに対するマッチングが不要な場合、無視し"
+"たいフィールドの場所に `_` を書くことで、個々のフィールドを無視することができ"
+"ます。また、 `Circle(*)` のように書くことで、すべてのフィールドを無視すること"
+"も可能です。引数をとらない列挙型のパターンは、定義時の形式と同様、丸括弧の無"
+"い形式で記述します。"
+
+#. type: Plain text
+#: doc/tutorial.md:727
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# struct Point { x: float, y: float }\n"
+"# enum Direction { North, East, South, West }\n"
+"fn point_from_direction(dir: Direction) -> Point {\n"
+" match dir {\n"
+" North => Point { x: 0f, y: 1f },\n"
+" East => Point { x: 1f, y: 0f },\n"
+" South => Point { x: 0f, y: -1f },\n"
+" West => Point { x: -1f, y: 0f }\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:729
+msgid "Enum variants may also be structs. For example:"
+msgstr "以下の例のように、列挙型バリアントを構造体にすることも可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:747
+#, no-wrap
+msgid ""
+"~~~~\n"
+"use std::float;\n"
+"# struct Point { x: float, y: float }\n"
+"# fn square(x: float) -> float { x * x }\n"
+"enum Shape {\n"
+" Circle { center: Point, radius: float },\n"
+" Rectangle { top_left: Point, bottom_right: Point }\n"
+"}\n"
+"fn area(sh: Shape) -> float {\n"
+" match sh {\n"
+" Circle { radius: radius, _ } => float::consts::pi * square(radius),\n"
+" Rectangle { top_left: top_left, bottom_right: bottom_right } => {\n"
+" (bottom_right.x - top_left.x) * (bottom_right.y - top_left.y)\n"
+" }\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:749
+msgid "## Tuples"
+msgstr "## タプル"
+
+#. type: Plain text
+#: doc/tutorial.md:754
+msgid ""
+"Tuples in Rust behave exactly like structs, except that their fields do not "
+"have names. Thus, you cannot access their fields with dot notation. Tuples "
+"can have any arity except for 0 (though you may consider unit, `()`, as the "
+"empty tuple if you like)."
+msgstr ""
+"Rust のタプルは、フィールドが名前を持たないという点以外は、構造体と同じように"
+"振る舞います。フィールド名が存在しないため、ドット記法を使ってタプルのフィー"
+"ルドにアクセスすることはできません。タプルは 1 個以上の要素を持つことができま"
+"す (必要ならば、ユニット型 `()` を 0 要素のタプルと見なすことはできます。)"
+
+#. type: Plain text
+#: doc/tutorial.md:761
+#, no-wrap
+msgid ""
+"~~~~\n"
+"let mytup: (int, int, float) = (10, 20, 30.0);\n"
+"match mytup {\n"
+" (a, b, c) => info!(a + b + (c as int))\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:763
+msgid "## Tuple structs"
+msgstr "## タプル構造体"
+
+#. type: Plain text
+#: doc/tutorial.md:768
+msgid ""
+"Rust also has _tuple structs_, which behave like both structs and tuples, "
+"except that, unlike tuples, tuple structs have names (so `Foo(1, 2)` has a "
+"different type from `Bar(1, 2)`), and tuple structs' _fields_ do not have "
+"names."
+msgstr ""
+"Rust には __タプル構造体__ と呼ばれる、構造体とタプルの両者の特徴を併せ持つも"
+"のが存在します。タプルと異なり、タプル構造体自体は名前を持ちます (従って、"
+"`Foo(1, 2)` と `Bar(1, 2)` は異なる型になります。) しかし、タプル構造体の __"
+"フィールド__ は名前を持ちません。"
+
+#. type: Plain text
+#: doc/tutorial.md:777
+#, no-wrap
+msgid ""
+"For example:\n"
+"~~~~\n"
+"struct MyTup(int, int, float);\n"
+"let mytup: MyTup = MyTup(10, 20, 30.0);\n"
+"match mytup {\n"
+" MyTup(a, b, c) => info!(a + b + (c as int))\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+"~~~~\n"
+"struct MyTup(int, int, float);\n"
+"let mytup: MyTup = MyTup(10, 20, 30.0);\n"
+"match mytup {\n"
+" MyTup(a, b, c) => info!(a + b + (c as int))\n"
+"}\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:779
+msgid "<a name=\"newtype\"></a>"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:784
+msgid ""
+"There is a special case for tuple structs with a single field, which are "
+"sometimes called \"newtypes\" (after Haskell's \"newtype\" feature). These "
+"are used to define new types in such a way that the new name is not just a "
+"synonym for an existing type but is rather its own distinct type."
+msgstr ""
+"タプル構造体がフィールドを 1 つしか持たない場合、 \"newtype\" と呼ばれること"
+"があります (Haskell の \"newtype\" 機能に由来しています)。 このようなタプル構"
+"造体を使うことで、既存の型の別名 (シノニム) となる新しい型を定義することがで"
+"きます。この新しい型は、元にした型とは異なった型として扱われます。"
+
+#. type: Plain text
+#: doc/tutorial.md:788
+msgid "~~~~ struct GizmoId(int); ~~~~"
+msgstr ""
+"~~~~\n"
+"struct GizmoId(int);\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:791
+msgid ""
+"For convenience, you can extract the contents of such a struct with the "
+"dereference (`*`) unary operator:"
+msgstr ""
+"便宜上、デリファレンス単項演算子 (`*`) により、タプル構造体の内容を展開するこ"
+"とが可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:797
+msgid ""
+"~~~~ # struct GizmoId(int); let my_gizmo_id: GizmoId = GizmoId(10); let "
+"id_int: int = *my_gizmo_id; ~~~~"
+msgstr ""
+"~~~~\n"
+"# struct GizmoId(int);\n"
+"let my_gizmo_id: GizmoId = GizmoId(10);\n"
+"let id_int: int = *my_gizmo_id;\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:800
+msgid ""
+"Types like this can be useful to differentiate between data that have the "
+"same type but must be used in different ways."
+msgstr ""
+"このような型は、型は同一でも、それぞれ全く異なる扱い方をしなければならない"
+"データを扱う場合に用いると便利です。"
+
+#. type: Plain text
+#: doc/tutorial.md:805
+msgid "~~~~ struct Inches(int); struct Centimeters(int); ~~~~"
+msgstr ""
+"~~~~\n"
+"struct Inches(int);\n"
+"struct Centimeters(int);\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:808
+msgid ""
+"The above definitions allow for a simple way for programs to avoid confusing "
+"numbers that correspond to different units."
+msgstr ""
+"上記のような単純な定義により、異なる単位を持つ数値を混同することなく扱うこと"
+"が可能になります。"
+
+#. type: Plain text
+#: doc/tutorial.md:810
+msgid "# Functions"
+msgstr "# 関数"
+
+#. type: Plain text
+#: doc/tutorial.md:818
+msgid ""
+"We've already seen several function definitions. Like all other static "
+"declarations, such as `type`, functions can be declared both at the top "
+"level and inside other functions (or in modules, which we'll come back to "
+"[later](#modules-and-crates)). The `fn` keyword introduces a function. A "
+"function has an argument list, which is a parenthesized list of `expr: type` "
+"pairs separated by commas. An arrow `->` separates the argument list and the "
+"function's return type."
+msgstr ""
+"関数定義はこれまでに何度か登場しています。他の静的な宣言 (`type` など)と同様"
+"に、関数はトップレベルまたは、他の関数の内部、モジュールの内部で定義すること"
+"ができます (モジュールについては、[後述](#モジュールとクレート)します) 。"
+
+#. type: Plain text
+#: doc/tutorial.md:824
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn line(a: int, b: int, x: int) -> int {\n"
+" return a * x + b;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:829
+msgid ""
+"The `return` keyword immediately returns from the body of a function. It is "
+"optionally followed by an expression to return. A function can also return a "
+"value by having its top-level block produce an expression."
+msgstr ""
+"`return` キーワードにより、呼び出し中の関数を即座に復帰させることができます。"
+"`return` の後に式を書くことで、呼び出し元へ戻り値として返すことも可能です。ま"
+"た、関数トップレベルのブロックを式と解釈した場合の値 (ブロック内最後の式の"
+"値) も関数の戻り値になります。"
+
+#. type: Plain text
+#: doc/tutorial.md:835
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn line(a: int, b: int, x: int) -> int {\n"
+" a * x + b\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:842
+msgid ""
+"It's better Rust style to write a return value this way instead of writing "
+"an explicit `return`. The utility of `return` comes in when returning early "
+"from a function. Functions that do not return a value are said to return "
+"nil, `()`, and both the return type and the return value may be omitted from "
+"the definition. The following two functions are equivalent."
+msgstr ""
+"Rust では、明示的に `return` を書くのではなく、上記のような方法で戻り値を返す"
+"スタイルが推奨されています。 `return` は、関数を途中で復帰させたい場合に使い"
+"ます。値を返さない関数は、 nil `()` を返す関数として取り扱われ、関数の戻り値"
+"の型や、戻り値を返す処理を省略することが可能です。以下の2つの関数は等価です。"
+
+#. type: Plain text
+#: doc/tutorial.md:845
+msgid "~~~~ fn do_nothing_the_hard_way() -> () { return (); }"
+msgstr ""
+"~~~~\n"
+"fn do_nothing_the_hard_way() -> () { return (); }"
+
+#. type: Plain text
+#: doc/tutorial.md:848
+msgid "fn do_nothing_the_easy_way() { } ~~~~"
+msgstr ""
+"fn do_nothing_the_easy_way() { }\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:850
+msgid ""
+"Ending the function with a semicolon like so is equivalent to returning `()`."
+msgstr "以下のように、セミコロンで終わる関数は `()` を返す関数と等価です。"
+
+#. type: Plain text
+#: doc/tutorial.md:854
+msgid ""
+"~~~~ fn line(a: int, b: int, x: int) -> int { a * x + b } fn oops(a: int, b: "
+"int, x: int) -> () { a * x + b; }"
+msgstr ""
+"~~~~\n"
+"fn line(a: int, b: int, x: int) -> int { a * x + b }\n"
+"fn oops(a: int, b: int, x: int) -> () { a * x + b; }"
+
+#. type: Plain text
+#: doc/tutorial.md:858
+msgid "assert!(8 == line(5, 3, 1)); assert!(() == oops(5, 3, 1)); ~~~~"
+msgstr ""
+"assert!(8 == line(5, 3, 1));\n"
+"assert!(() == oops(5, 3, 1));\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:862
+msgid ""
+"As with `match` expressions and `let` bindings, function arguments support "
+"pattern destructuring. Like `let`, argument patterns must be irrefutable, as "
+"in this example that unpacks the first value from a tuple and returns it."
+msgstr ""
+"`match` 式や `let` による変数定義のように、関数の引数もパターンによる "
+"destructuring をサポートしています。`let` と同様、引数のパターンは 不可反駁 "
+"(irrefutable) でなければなりません。以下の例では、タプルの最初の要素を取得"
+"し、呼び出し元へ返します。"
+
+#. type: Plain text
+#: doc/tutorial.md:866
+msgid "~~~ fn first((value, _): (int, float)) -> int { value } ~~~"
+msgstr ""
+"~~~\n"
+"fn first((value, _): (int, float)) -> int { value }\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:868 doc/tutorial-ffi.md:143
+msgid "# Destructors"
+msgstr "# デストラクタ"
+
+#. type: Plain text
+#: doc/tutorial.md:872
+msgid ""
+"A *destructor* is a function responsible for cleaning up the resources used "
+"by an object when it is no longer accessible. Destructors can be defined to "
+"handle the release of resources like files, sockets and heap memory."
+msgstr ""
+"**デストラクタ** はアクセスできなくなったオブジェクトから利用されていたリソー"
+"スを解放する役割を持つ関数です。デストラクタはファイルやソケット、ヒープメモ"
+"リのようなリソースの解放を処理するために定義することができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:876
+msgid ""
+"Objects are never accessible after their destructor has been called, so "
+"there are no dynamic failures from accessing freed resources. When a task "
+"fails, the destructors of all objects in the task are called."
+msgstr ""
+"オブジェクトは、デストラクタが呼び出された後にアクセス不能になります。そのた"
+"め、解放済みリソースへアクセスしたことによる動的なエラーは発生しません。タス"
+"クの実行に失敗した場合、タスクに属するすべてのオブジェクトのデストラクタが呼"
+"び出されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:878
+msgid ""
+"The `~` sigil represents a unique handle for a memory allocation on the heap:"
+msgstr ""
+"シジル `~` はヒープに獲得されたメモリへのユニークな (唯一の) ハンドルを表しま"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:886
+#, no-wrap
+msgid ""
+"~~~~\n"
+"{\n"
+" // an integer allocated on the heap\n"
+" let y = ~10;\n"
+"}\n"
+"// the destructor frees the heap memory as soon as `y` goes out of scope\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:890
+msgid ""
+"Rust includes syntax for heap memory allocation in the language since it's "
+"commonly used, but the same semantics can be implemented by a type with a "
+"custom destructor."
+msgstr ""
+"Rust はヒープメモリ獲得のための構文を持っています。これは、ヒープメモリ獲得が"
+"よく利用されるというのが理由ですが、同じ動作は独自のデストラクタを持つ型によ"
+"り実装することが可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:892
+msgid "# Ownership"
+msgstr "# 所有権"
+
+#. type: Plain text
+#: doc/tutorial.md:897
+msgid ""
+"Rust formalizes the concept of object ownership to delegate management of an "
+"object's lifetime to either a variable or a task-local garbage collector. An "
+"object's owner is responsible for managing the lifetime of the object by "
+"calling the destructor, and the owner determines whether the object is "
+"mutable."
+msgstr ""
+"Rust は、オブジェクトの寿命の管理を変数またはタスクローカルのガベージコレクタ"
+"に委譲するために、オブジェクトの所有権という考え方を取り入れています。オブ"
+"ジェクトの所有者はデストラクタを呼び出すことにより、オブジェクトの寿命を管理"
+"する責任を負っています。また、所有者はオブジェクトがミュータブルかどうかも判"
+"断します。"
+
+#. type: Plain text
+#: doc/tutorial.md:903
+msgid ""
+"Ownership is recursive, so mutability is inherited recursively and a "
+"destructor destroys the contained tree of owned objects. Variables are top-"
+"level owners and destroy the contained object when they go out of scope. A "
+"box managed by the garbage collector starts a new ownership tree, and the "
+"destructor is called when it is collected."
+msgstr ""
+"所有権は再帰的であるため、ミュータビリティは再帰的に継承され、デストラクタは"
+"所有しているオブジェクトの含まれているツリーを破壊します。変数はトップレベル"
+"の所有者です。変数の存在しているスコープを抜けるタイミングで、変数は所有して"
+"いるオブジェクトを破棄します。ガベージコレクタによって管理されるボックスは、"
+"新しい所有権ツリーを生成し、ガベージコレクタによりオブジェクトが回収されると"
+"きにデストラクタが呼び出されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:907
+msgid ""
+"~~~~ // the struct owns the objects contained in the `x` and `y` fields "
+"struct Foo { x: int, y: ~int }"
+msgstr ""
+"~~~~\n"
+"// この構造体はフィールド `x` と `y` に含まれるオブジェクトを所有している\n"
+"struct Foo { x: int, y: ~int }"
+
+#. type: Plain text
+#: doc/tutorial.md:914
+#, no-wrap
+msgid ""
+"{\n"
+" // `a` is the owner of the struct, and thus the owner of the struct's fields\n"
+" let a = Foo { x: 5, y: ~10 };\n"
+"}\n"
+"// when `a` goes out of scope, the destructor for the `~int` in the struct's\n"
+"// field is called\n"
+msgstr ""
+"{\n"
+" // `a` は構造体の所有者であり、構造体のフィールドの所有者でもある\n"
+" let a = Foo { x: 5, y: ~10 };\n"
+"}\n"
+"// `a` の含まれているスコープから抜けるとき、 構造体のフィールドの `~int` のデストラクタが呼ばれる\n"
+
+#. type: Plain text
+#: doc/tutorial.md:919
+msgid ""
+"// `b` is mutable, and the mutability is inherited by the objects it owns "
+"let mut b = Foo { x: 5, y: ~10 }; b.x = 10; ~~~~"
+msgstr ""
+"// `b` はミュータブルなので、所有しているオブジェクトにもミュターブル性が継承"
+"される\n"
+"let mut b = Foo { x: 5, y: ~10 };\n"
+"b.x = 10;\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:925
+msgid ""
+"If an object doesn't contain garbage-collected boxes, it consists of a "
+"single ownership tree and is given the `Owned` trait which allows it to be "
+"sent between tasks. Custom destructors can only be implemented directly on "
+"types that are `Owned`, but garbage-collected boxes can still *contain* "
+"types with custom destructors."
+msgstr ""
+"オブジェクトにガベージコレクトされるボックスが含まれていない場合、オブジェク"
+"トは単一の継承ツリーからの構成され、`Owned` トレイトが付与されます。`Owned` "
+"トレイトが付与されたデータは、タスク間を跨いで受け渡すことが可能です。独自の"
+"デストラクタは、`Owned` トレイトを満たす型に対して直接実装されなければなりま"
+"せんが、ガベージコレクトされるボックスが独自のデストラクタをもつ型を **含む"
+"** ことは依然可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:927
+msgid "# Boxes"
+msgstr "# ボックス"
+
+#. type: Plain text
+#: doc/tutorial.md:934
+msgid ""
+"Many modern languages represent values as pointers to heap memory by "
+"default. In contrast, Rust, like C and C++, represents such types directly. "
+"Another way to say this is that aggregate data in Rust are *unboxed*. This "
+"means that if you `let x = Point { x: 1f, y: 1f };`, you are creating a "
+"struct on the stack. If you then copy it into a data structure, you copy the "
+"entire struct, not just a pointer."
+msgstr ""
+"多くのモダンな言語では、デフォルトで、値はヒープメモリへのポインタとして表さ"
+"れます。一方、Rust は C や C++ のように、これらの型を直接取り扱うことができま"
+"す。言い換えると、集積データは **ボックス化されていない** ということです。つ"
+"まり、`let x = Point { x: 1f, y: 1f };` というコードは、スタック上に構造体を"
+"作成することを意味します。この構造体を別のデータ構造の中へコピーする場合、ポ"
+"インタのコピーではなく構造体全体をコピーすることになります。"
+
+#. type: Plain text
+#: doc/tutorial.md:939
+msgid ""
+"For small structs like `Point`, this is usually more efficient than "
+"allocating memory and indirecting through a pointer. But for big structs, or "
+"mutable state, it can be useful to have a single copy on the stack or on the "
+"heap, and refer to that through a pointer."
+msgstr ""
+"`Point` のような小さな構造体の場合、このような動作は、メモリを獲得しポインタ"
+"経由でアクセスするよりも一般的には効率的です。しかし、大きな構造体の場合や"
+"ミュータブルな状態を持つようなものの場合、スタックまたはヒープ上に単一ののコ"
+"ピーをもち、ポインタ経由で参照する方が便利な場合もあります。"
+
+#. type: Plain text
+#: doc/tutorial.md:941
+msgid "## Owned boxes"
+msgstr "## 所有ボックス"
+
+#. type: Plain text
+#: doc/tutorial.md:944
+msgid ""
+"An owned box (`~`) is a uniquely owned allocation on the heap. It inherits "
+"the mutability and lifetime of the owner as it would if there was no box:"
+msgstr ""
+"所有ボックス (Owned box, `~`) は、単一の所有者のみを持つ、ヒープ上に獲得され"
+"た領域です。所有ボックスは、ボックスが存在しない場合と同じように、所有者の"
+"ミュータビリティと寿命を継承します。"
+
+#. type: Plain text
+#: doc/tutorial.md:949
+msgid "~~~~ let x = 5; // immutable let mut y = 5; // mutable y += 2;"
+msgstr ""
+"~~~~\n"
+"let x = 5; // イミュータブル\n"
+"let mut y = 5; // ミュータブル\n"
+"y += 2;"
+
+#. type: Plain text
+#: doc/tutorial.md:954
+msgid ""
+"let x = ~5; // immutable let mut y = ~5; // mutable *y += 2; // the * "
+"operator is needed to access the contained value ~~~~"
+msgstr ""
+"let x = ~5; // イミュータブル\n"
+"let mut y = ~5; // ミュータブル\n"
+"*y += 2; // ボックスの中身にアクセスするには、 * 演算子が必要\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:959
+msgid ""
+"The purpose of an owned box is to add a layer of indirection in order to "
+"create recursive data structures or cheaply pass around an object larger "
+"than a pointer. Since an owned box has a unique owner, it can only be used "
+"to represent a tree data structure."
+msgstr ""
+"所有ボックスの目的は、再帰的なデータ型の作成や、ポインターのサイズより大きい"
+"オブジェクトを安価な方法で渡したりするための、関節参照のレイヤを追加すること"
+"です。所有ボックスは複数の所有者を持てないため、ツリー構造を持ったデータのみ"
+"を表すことが可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:962
+msgid ""
+"The following struct won't compile, because the lack of indirection would "
+"mean it has an infinite size:"
+msgstr ""
+"以下の構造体はコンパイルできません。構造体が自身を関節参照でない方法で参照し"
+"た場合、無限に大きなサイズを持つことになってしまうからです。"
+
+#. type: Plain text
+#: doc/tutorial.md:968
+#, no-wrap
+msgid ""
+"~~~~ {.xfail-test}\n"
+"struct Foo {\n"
+" child: Option<Foo>\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:972
+msgid ""
+"> ***Note:*** The `Option` type is an enum that represents an *optional* "
+"value. > It's comparable to a nullable pointer in many other languages, but "
+"stores the > contained value unboxed."
+msgstr ""
+"> ***注意*** `Option` 型は **オプショナルな** (値の有無を選択可能な) 値を表す"
+"列挙型です。`Option` 型は他の言語の null 値をとりうるポインタ型に相当します"
+"が、格納される値はボックス化されていません。"
+
+#. type: Plain text
+#: doc/tutorial.md:976
+msgid ""
+"Adding indirection with an owned pointer allocates the child outside of the "
+"struct on the heap, which makes it a finite size and won't result in a "
+"compile-time error:"
+msgstr ""
+"所有ポインタによる関節参照を導入することで、`child` を構造体の外のヒープ上に"
+"獲得することができ、構造体のデータサイズは有限となるため、コンパイルエラーと"
+"はなりません。"
+
+#. type: Plain text
+#: doc/tutorial.md:982
+#, no-wrap
+msgid ""
+"~~~~\n"
+"struct Foo {\n"
+" child: Option<~Foo>\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:984
+msgid "## Managed boxes"
+msgstr "## マネージドボックス"
+
+#. type: Plain text
+#: doc/tutorial.md:992
+msgid ""
+"A managed box (`@`) is a heap allocation with the lifetime managed by a task-"
+"local garbage collector. It will be destroyed at some point after there are "
+"no references left to the box, no later than the end of the task. Managed "
+"boxes lack an owner, so they start a new ownership tree and don't inherit "
+"mutability. They do own the contained object, and mutability is defined by "
+"the type of the managed box (`@` or `@mut`). An object containing a managed "
+"box is not `Owned`, and can't be sent between tasks."
+msgstr ""
+"マネージドボックス (`@`) は、タスクローカルなガベージコレクタにより寿命管理さ"
+"れる、ヒープ上に獲得された領域です。マネージドボックスは、ボックスへの参照が"
+"無くなった後、いずれかの時点で破棄されます。破棄のタイミングがタスク終了後に"
+"なることはありません。マネージドボックスは所有者を持たないので、新たな所有権"
+"ツリーを開始し、ミュータビリティを継承しません。マネージドボックスは、ボック"
+"スに含まれているオブジェクトを所有し、ミュータビリティはマネージドボックスの"
+"種別 (`@` または `@mut`) によって決定されます。マネージドボックスに含まれるオ"
+"ブジェクトは `Owned` を付与されず、タスク間で受け渡すことはできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:995
+msgid "~~~~ let a = @5; // immutable"
+msgstr ""
+"~~~~\n"
+"let a = @5; // イミュータブル"
+
+#. type: Plain text
+#: doc/tutorial.md:998
+msgid "let mut b = @5; // mutable variable, immutable box b = @10;"
+msgstr ""
+"let mut b = @5; // ミュータブルな変数、イミュータブルなボックス\n"
+"b = @10;"
+
+#. type: Plain text
+#: doc/tutorial.md:1001
+msgid "let c = @mut 5; // immutable variable, mutable box *c = 10;"
+msgstr ""
+"let c = @mut 5; // イミュータブルな変数、ミュータブルなボックス\n"
+"*c = 10;"
+
+#. type: Plain text
+#: doc/tutorial.md:1006
+msgid ""
+"let mut d = @mut 5; // mutable variable, mutable box *d += 5; d = @mut 15; "
+"~~~~"
+msgstr ""
+"let mut d = @mut 5; // ミュータブルな変数、ミュータブルなボックス\n"
+"*d += 5;\n"
+"d = @mut 15;\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1011
+msgid ""
+"A mutable variable and an immutable variable can refer to the same box, "
+"given that their types are compatible. Mutability of a box is a property of "
+"its type, however, so for example a mutable handle to an immutable box "
+"cannot be assigned a reference to a mutable box."
+msgstr ""
+"ミュータブルな変数とイミュータブルな変数は、それぞれの変数の型が同じであれ"
+"ば、同じボックスを参照することが可能です。ただし、ボックスのミュータビリティ"
+"は、型自体が持つ属性なので、ミュータブルなボックスの参照を、イミュータブルな"
+"ボックスを参照するミュータブルな変数 (handle) へ代入することはできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:1015
+#, no-wrap
+msgid ""
+"~~~~\n"
+"let a = @1; // immutable box\n"
+"let b = @mut 2; // mutable box\n"
+msgstr ""
+"~~~~\n"
+"let a = @1; // イミュータブルなボックス\n"
+"let b = @mut 2; // ミュータブルなボックス\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1018
+#, no-wrap
+msgid ""
+"let mut c : @int; // declare a variable with type managed immutable int\n"
+"let mut d : @mut int; // and one of type managed mutable int\n"
+msgstr ""
+"let mut c : @int; // イミュータブルなマネージド int 型の変数と、\n"
+"let mut d : @mut int; // ミュータブルなマネージド int 型の変数の宣言\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1022
+#, no-wrap
+msgid ""
+"c = a; // box type is the same, okay\n"
+"d = b; // box type is the same, okay\n"
+"~~~~\n"
+msgstr ""
+"c = a; // ボックスの型は変数の型と同じなので、OK\n"
+"d = b; // ボックスの型は変数の型と同じなので、OK\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1027
+#, no-wrap
+msgid ""
+"~~~~ {.xfail-test}\n"
+"// but b cannot be assigned to c, or a to d\n"
+"c = b; // error\n"
+"~~~~\n"
+msgstr ""
+"~~~~ {.xfail-test}\n"
+"// しかし、 b は c に代入できないし、a は d に代入できない\n"
+"c = b; // エラー\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1029
+msgid "# Move semantics"
+msgstr "# ムーブセマンティクス"
+
+#. type: Plain text
+#: doc/tutorial.md:1035
+msgid ""
+"Rust uses a shallow copy for parameter passing, assignment and returning "
+"values from functions. A shallow copy is considered a move of ownership if "
+"the ownership tree of the copied value includes an owned box or a type with "
+"a custom destructor. After a value has been moved, it can no longer be used "
+"from the source location and will not be destroyed there."
+msgstr ""
+"Rust は関数パラメータの受け渡しや、変数への代入、関数からの戻り値を設定する際"
+"に、シャローコピーを使用しています。コピーされる値の所有権ツリーが所有ボック"
+"スや独自のデストラクタを持つ型を含んでいる場合、シャローコピーは所有権の移動"
+"とみなされます。値の移動が行われた後、元々その値を参照していた箇所からは値を"
+"利用することはできなくなり、もとの所有者から値が破壊されることもありません。"
+
+#. type: Plain text
+#: doc/tutorial.md:1041
+msgid ""
+"~~~~ let x = ~5; let y = x.clone(); // y is a newly allocated box let z = "
+"x; // no new memory allocated, x can no longer be used ~~~~"
+msgstr ""
+"~~~~\n"
+"let x = ~5;\n"
+"let y = x.clone();\n"
+"// y は新しく獲得されるボックス\n"
+"let z = x; // 新たなメモリの獲得は行われない。x を使うことはできなくなる\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1044
+msgid ""
+"Since in owned boxes mutability is a property of the owner, not the box, "
+"mutable boxes may become immutable when they are moved, and vice-versa."
+msgstr ""
+"所有ボックスのミュータビリティは、ボックスではなく所有者のミュータビリティを"
+"引き継ぐため、同一のボックスが移動によりミュータブルになったりイミュータブル"
+"になったりすることがありえます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1051
+msgid ""
+"~~~~ let r = ~13; let mut s = r; // box becomes mutable *s += 1; let t = "
+"s; // box becomes immutable ~~~~"
+msgstr ""
+"~~~~\n"
+"let r = ~13;\n"
+"let mut s = r; // ボックスはミュータブルになる\n"
+"*s += 1;\n"
+"let t = s; // ボックスはイミュータブルになる\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1053
+msgid "# Borrowed pointers"
+msgstr "# 借用ポインタ"
+
+#. type: Plain text
+#: doc/tutorial.md:1059
+msgid ""
+"Rust's borrowed pointers are a general purpose reference type. In contrast "
+"with owned boxes, where the holder of an owned box is the owner of the "
+"pointed-to memory, borrowed pointers never imply ownership. A pointer can be "
+"borrowed to any object, and the compiler verifies that it cannot outlive the "
+"lifetime of the object."
+msgstr ""
+"Rust の借用ポインタ (borrowed pointer) は汎用的な参照型です。所有ボックスの場"
+"合、ボックスの所有者が参照されているメモリの所有者となるのに対して、借用ポイ"
+"ンタを所有することがメモリを所有を意味することはありません。ポインタは任意の"
+"オブジェクトから借用することが可能で、参照先のオブジェクトよりもポインタが長"
+"生きしないことがコンパイラにより保証されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1061
+msgid "As an example, consider a simple struct type, `Point`:"
+msgstr "例として、シンプルな構造体型の `Point` について考えます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1068
+#, no-wrap
+msgid ""
+"~~~\n"
+"struct Point {\n"
+" x: float,\n"
+" y: float\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1072
+msgid ""
+"We can use this simple definition to allocate points in many different ways. "
+"For example, in this code, each of these three local variables contains a "
+"point, but allocated in a different location:"
+msgstr ""
+"シンプルな定義ですが、この定義を使って `Point` 型のオブジェクトを様々な方法で"
+"割り当てることができます。例えば、このコードの3つのローカル変数は、それぞれ異"
+"なった場所に `Point` 型のオブジェクトを割り当てています。"
+
+#. type: Plain text
+#: doc/tutorial.md:1079
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point { x: float, y: float }\n"
+"let on_the_stack : Point = Point { x: 3.0, y: 4.0 };\n"
+"let managed_box : @Point = @Point { x: 5.0, y: 1.0 };\n"
+"let owned_box : ~Point = ~Point { x: 7.0, y: 9.0 };\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1089
+msgid ""
+"Suppose we want to write a procedure that computes the distance between any "
+"two points, no matter where they are stored. For example, we might like to "
+"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 this "
+"will cause the points to be copied when we call the function. For points, "
+"this is probably not so bad, but often copies are expensive. So we’d like to "
+"define a function that takes the points by pointer. We can use borrowed "
+"pointers to do this:"
+msgstr ""
+"`Point` 型のオブジェクトの割り当て先がどこであったとしても利用可能な、任意の "
+"2 点間の距離を計算する処理を書きたいとします。例えば、 `on_the_stack`, "
+"`managed_box` 間や `managed_box`, `owned_box` 間の距離を計算する処理です。 1"
+"つ目の実装方法として、2つの `Point` 型オブジェクトを引数にとる関数を定義する"
+"方法、すなわち、オブジェクトを値で受け渡す方法があります。しかし、この方法で"
+"は関数呼び出し時に `Point` オブジェクトのコピーが行われます。`Point` オブジェ"
+"クトの場合、このような実装はそれほど悪いものではないでしょうが、コピー処理の"
+"コストは高い場合もあります。したがって、`Point` オブジェクトをポインタ渡しす"
+"る関数を定義する必要があります。そのために、借用ポインタを利用することが可能"
+"です。"
+
+#. type: Plain text
+#: doc/tutorial.md:1099
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point { x: float, y: float }\n"
+"# fn sqrt(f: float) -> float { 0f }\n"
+"fn compute_distance(p1: &Point, p2: &Point) -> float {\n"
+" let x_d = p1.x - p2.x;\n"
+" let y_d = p1.y - p2.y;\n"
+" sqrt(x_d * x_d + y_d * y_d)\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1101 doc/tutorial-borrowed-ptr.md:72
+msgid "Now we can call `compute_distance()` in various ways:"
+msgstr ""
+"上記の `compute_distance()` 関数は、様々な方法で呼び出すことができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1111
+#, no-wrap
+msgid ""
+"~~~\n"
+"# struct Point{ x: float, y: float };\n"
+"# let on_the_stack : Point = Point { x: 3.0, y: 4.0 };\n"
+"# let managed_box : @Point = @Point { x: 5.0, y: 1.0 };\n"
+"# let owned_box : ~Point = ~Point { x: 7.0, y: 9.0 };\n"
+"# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }\n"
+"compute_distance(&on_the_stack, managed_box);\n"
+"compute_distance(managed_box, owned_box);\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1118
+msgid ""
+"Here the `&` operator is used to take the address of the variable "
+"`on_the_stack`; this is because `on_the_stack` has the type `Point` (that "
+"is, a struct value) and we have to take its address to get a value. We also "
+"call this _borrowing_ the local variable `on_the_stack`, because we are "
+"creating an alias: that is, another route to the same data."
+msgstr ""
+"ここで `&` 演算子は `on_the_stack` 変数のアドレスを取得するために使われていま"
+"す。これは、 `on_the_stack` の型は `Point` (つまり、構造体の値) であり、呼び"
+"出した関数から値を取得させるため、構造体のアドレスを渡す必要があるからです。"
+"値の別名 (エイリアス)、すなわち、同じデータへアクセスするための別の方法を提供"
+"するので、このような操作のことをローカル変数 `on_the_stack` の __借用__ "
+"(_borrowing_) と呼びます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1124
+msgid ""
+"In the case of the boxes `managed_box` and `owned_box`, however, no explicit "
+"action is necessary. The compiler will automatically convert a box like "
+"`@point` or `~point` to a borrowed pointer like `&point`. This is another "
+"form of borrowing; in this case, the contents of the managed/owned box are "
+"being lent out."
+msgstr ""
+"ボックスである `managed_box` と `owned_box` の場合は、特に明示的な操作を行う"
+"必要はありません。コンパイラは `@point` や `~point` のようなボックスを自動的"
+"に `&point` のような借用ポインタへと変換します。これは、別の形態の借用 "
+"(borrowing) です。この場合、マネージド/所有ボックスの内容が貸し出されていま"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:1133
+msgid ""
+"Whenever a value is borrowed, there are some limitations on what you can do "
+"with the original. For example, if the contents of a variable have been lent "
+"out, you cannot send that variable to another task, nor will you be "
+"permitted to take actions that might cause the borrowed value to be freed or "
+"to change its type. This rule should make intuitive sense: you must wait for "
+"a borrowed value to be returned (that is, for the borrowed pointer to go out "
+"of scope) before you can make full use of it again."
+msgstr ""
+"値が借用されている間、借用元の値に対して行える操作がいくらか制限されます。例"
+"えば、変数の内容が貸し出された場合、その変数を他のタスクに送信することはでき"
+"ませんし、借用された値を解放したり、型が変化させるような操作も行うことができ"
+"ません。このルールは理にかなったものでしょう。貸し出した値を最大限に活用する "
+"(make full use of it) ためには、貸し出した値の返却 (借用ポインタが存在するス"
+"コープを抜ける) を待たなければなりません。"
+
+#. type: Plain text
+#: doc/tutorial.md:1136
+msgid ""
+"For a more in-depth explanation of borrowed pointers, read the [borrowed "
+"pointer tutorial][borrowtut]."
+msgstr ""
+"借用ポインタの詳細については、[借用ポインタのチュートリアル][borrowtut]を参照"
+"してください。"
+
+#. type: Plain text
+#: doc/tutorial.md:1138
+msgid "[borrowtut]: tutorial-borrowed-ptr.html"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1140
+msgid "## Freezing"
+msgstr "## 凍結"
+
+#. type: Plain text
+#: doc/tutorial.md:1143
+msgid ""
+"Borrowing an immutable pointer to an object freezes it and prevents "
+"mutation. `Owned` objects have freezing enforced statically at compile-time."
+msgstr ""
+"オブジェクトへのイミュータブルな (借用) ポインタを借用した場合、借用されたオ"
+"ブジェクトは凍結 (freezing) され、変更することができなくなります。`Owned` ト"
+"レイトが付与されたオブジェクトは、コンパイル時の静的解析により、強制的に凍結"
+"されます (凍結された値を変更しようとすると、コンパイルエラーとなります)。"
+
+#. type: Plain text
+#: doc/tutorial.md:1152
+#, no-wrap
+msgid ""
+"~~~~\n"
+"let mut x = 5;\n"
+"{\n"
+" let y = &x; // x is now frozen, it cannot be modified\n"
+"}\n"
+"// x is now unfrozen again\n"
+"# x = 3;\n"
+"~~~~\n"
+msgstr ""
+"~~~~\n"
+"let mut x = 5;\n"
+"{\n"
+" let y = &x; // x は凍結されたので、変更することができない\n"
+"}\n"
+"// x の凍結状態は解除される\n"
+"# x = 3;\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1156
+msgid ""
+"Mutable managed boxes handle freezing dynamically when any of their contents "
+"are borrowed, and the task will fail if an attempt to modify them is made "
+"while they are frozen:"
+msgstr ""
+"ミュータブルなマネージドボックスは、その内容のいずれかが借用される際に動的に"
+"凍結され、凍結状態の間に内容を変更しようとすると、タスクが失敗します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1166
+#, no-wrap
+msgid ""
+"~~~~\n"
+"let x = @mut 5;\n"
+"let y = x;\n"
+"{\n"
+" let z = &*y; // the managed box is now frozen\n"
+" // modifying it through x or y will cause a task failure\n"
+"}\n"
+"// the box is now unfrozen again\n"
+"~~~~\n"
+msgstr ""
+"~~~~\n"
+"let x = @mut 5;\n"
+"let y = x;\n"
+"{\n"
+" let z = &*y; // マネージドボックスが凍結される\n"
+" // x か y を経由して内容を変更すると、タスクが異常終了する\n"
+"}\n"
+"// ボックスの凍結状態は解除される\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1168
+msgid "# Dereferencing pointers"
+msgstr "# ポインタのデリファレンス"
+
+#. type: Plain text
+#: doc/tutorial.md:1171
+msgid ""
+"Rust uses the unary star operator (`*`) to access the contents of a box or "
+"pointer, similarly to C."
+msgstr ""
+"Rust では、C と同様、ボックスの内容やポインタの参照先にアクセスするためには単"
+"項スター演算子 (`*`) を使います。"
+
+#. type: Plain text
+#: doc/tutorial.md:1176
+msgid "~~~ let managed = @10; let owned = ~20; let borrowed = &30;"
+msgstr ""
+"~~~\n"
+"let managed = @10;\n"
+"let owned = ~20;\n"
+"let borrowed = &30;"
+
+#. type: Plain text
+#: doc/tutorial.md:1179
+msgid "let sum = *managed + *owned + *borrowed; ~~~"
+msgstr ""
+"let sum = *managed + *owned + *borrowed;\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1183
+msgid ""
+"Dereferenced mutable pointers may appear on the left hand side of "
+"assignments. Such an assignment modifies the value that the pointer points "
+"to."
+msgstr ""
+"ミュータブルなポインタをデリファレンスしたものは、代入文の左辺に置くことがで"
+"きます。このような代入文は、ポインタが指す値を変更します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1187
+msgid "~~~ let managed = @mut 10; let mut owned = ~20;"
+msgstr ""
+"~~~\n"
+"let managed = @mut 10;\n"
+"let mut owned = ~20;"
+
+#. type: Plain text
+#: doc/tutorial.md:1190
+msgid "let mut value = 30; let borrowed = &mut value;"
+msgstr ""
+"let mut value = 30;\n"
+"let borrowed = &mut value;"
+
+#. type: Plain text
+#: doc/tutorial.md:1195
+#, no-wrap
+msgid ""
+"*managed = *owned + 10;\n"
+"*owned = *borrowed + 100;\n"
+"*borrowed = *managed + 1000;\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1199
+msgid ""
+"Pointers have high operator precedence, but lower precedence than the dot "
+"operator used for field and method access. This precedence order can "
+"sometimes make code awkward and parenthesis-filled."
+msgstr ""
+"ポインタ演算子の優先順位は高いですが、フィールドやメソッドのアクセスに用いる"
+"ドット演算子よりは優先順位は低いです。この優先順位により、コードが不格好で括"
+"弧だらけなものになることがあります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1209
+msgid ""
+"~~~ # struct Point { x: float, y: float } # enum Shape { Rectangle(Point, "
+"Point) } # impl Shape { fn area(&self) -> int { 0 } } let start = @Point "
+"{ x: 10f, y: 20f }; let end = ~Point { x: (*start).x + 100f, y: (*start).y + "
+"100f }; let rect = &Rectangle(*start, *end); let area = (*rect).area(); ~~~"
+msgstr ""
+"~~~\n"
+"# struct Point { x: float, y: float }\n"
+"# enum Shape { Rectangle(Point, Point) }\n"
+"# impl Shape { fn area(&self) -> int { 0 } }\n"
+"let start = @Point { x: 10f, y: 20f };\n"
+"let end = ~Point { x: (*start).x + 100f, y: (*start).y + 100f };\n"
+"let rect = &Rectangle(*start, *end);\n"
+"let area = (*rect).area();\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1213
+msgid ""
+"To combat this ugliness the dot operator applies _automatic pointer "
+"dereferencing_ to the receiver (the value on the left-hand side of the dot), "
+"so in most cases, explicitly dereferencing the receiver is not necessary."
+msgstr ""
+"コードが醜くなるのを防ぐため、ドット演算子はレシーバ (ドットの左にある値) の "
+"__ポインタを自動的にデリファレンス__ します。これにより、ほとんどのケースでは"
+"レシーバを明示的にデリファレンスする必要がなくなります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1223
+msgid ""
+"~~~ # struct Point { x: float, y: float } # enum Shape { Rectangle(Point, "
+"Point) } # impl Shape { fn area(&self) -> int { 0 } } let start = @Point "
+"{ x: 10f, y: 20f }; let end = ~Point { x: start.x + 100f, y: start.y + "
+"100f }; let rect = &Rectangle(*start, *end); let area = rect.area(); ~~~"
+msgstr ""
+"~~~\n"
+"# struct Point { x: float, y: float }\n"
+"# enum Shape { Rectangle(Point, Point) }\n"
+"# impl Shape { fn area(&self) -> int { 0 } }\n"
+"let start = @Point { x: 10f, y: 20f };\n"
+"let end = ~Point { x: start.x + 100f, y: start.y + 100f };\n"
+"let rect = &Rectangle(*start, *end);\n"
+"let area = rect.area();\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1227
+msgid ""
+"You can write an expression that dereferences any number of pointers "
+"automatically. For example, if you feel inclined, you could write something "
+"silly like"
+msgstr ""
+"1つのドット演算子で何度も自動デリファレンスが行うことができます。例えば、やろ"
+"うと思えば以下のような馬鹿げたものを書くこともできます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1233
+msgid ""
+"~~~ # struct Point { x: float, y: float } let point = &@~Point { x: 10f, y: "
+"20f }; println(fmt!(\"%f\", point.x)); ~~~"
+msgstr ""
+"~~~\n"
+"# struct Point { x: float, y: float }\n"
+"let point = &@~Point { x: 10f, y: 20f };\n"
+"println(fmt!(\"%f\", point.x));\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1235
+msgid "The indexing operator (`[]`) also auto-dereferences."
+msgstr "添字演算子 (`[]`) も自動でリファレンスを行います。"
+
+#. type: Plain text
+#: doc/tutorial.md:1237
+msgid "# Vectors and strings"
+msgstr "# ベクタと文字列"
+
+#. type: Plain text
+#: doc/tutorial.md:1242
+msgid ""
+"A vector is a contiguous section of memory containing zero or more values of "
+"the same type. Like other types in Rust, vectors can be stored on the stack, "
+"the local heap, or the exchange heap. Borrowed pointers to vectors are also "
+"called 'slices'."
+msgstr ""
+"ベクタは同じ型の値が0個以上含まれる、メモリ上の連続した部分のことです。Rust "
+"の他の型と同様、ベクタもスタック、ローカルヒープ、交換ヒープ (exchange heap) "
+"上に格納することができます。ベクトルの借用ポインタは、「スライス」と呼ばれる"
+"場合もあります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1252
+#, no-wrap
+msgid ""
+"~~~\n"
+"# enum Crayon {\n"
+"# Almond, AntiqueBrass, Apricot,\n"
+"# Aquamarine, Asparagus, AtomicTangerine,\n"
+"# BananaMania, Beaver, Bittersweet,\n"
+"# Black, BlizzardBlue, Blue\n"
+"# }\n"
+"// A fixed-size stack vector\n"
+"let stack_crayons: [Crayon, ..3] = [Almond, AntiqueBrass, Apricot];\n"
+msgstr ""
+"~~~\n"
+"# enum Crayon {\n"
+"# Almond, AntiqueBrass, Apricot,\n"
+"# Aquamarine, Asparagus, AtomicTangerine,\n"
+"# BananaMania, Beaver, Bittersweet,\n"
+"# Black, BlizzardBlue, Blue\n"
+"# }\n"
+"// スタック上の固定長ベクタ\n"
+"let stack_crayons: [Crayon, ..3] = [Almond, AntiqueBrass, Apricot];\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1255
+msgid ""
+"// A borrowed pointer to stack-allocated vector let stack_crayons: &[Crayon] "
+"= &[Aquamarine, Asparagus, AtomicTangerine];"
+msgstr ""
+"// スタックに獲得されたベクタへの借用ポインタ\n"
+"let stack_crayons: &[Crayon] = &[Aquamarine, Asparagus, AtomicTangerine];"
+
+#. type: Plain text
+#: doc/tutorial.md:1258
+msgid ""
+"// A local heap (managed) vector of crayons let local_crayons: @[Crayon] = "
+"@[BananaMania, Beaver, Bittersweet];"
+msgstr ""
+"// ローカルヒープ上に獲得された、クレヨンの (マネージド) ベクタ\n"
+"let local_crayons: @[Crayon] = @[BananaMania, Beaver, Bittersweet];"
+
+#. type: Plain text
+#: doc/tutorial.md:1262
+msgid ""
+"// An exchange heap (owned) vector of crayons let exchange_crayons: "
+"~[Crayon] = ~[Black, BlizzardBlue, Blue]; ~~~"
+msgstr ""
+"// 交換ヒープに獲得された、クレヨンの (所有) ベクタ\n"
+"let exchange_crayons: ~[Crayon] = ~[Black, BlizzardBlue, Blue];\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1264
+msgid "The `+` operator means concatenation when applied to vector types."
+msgstr "`+` 演算子がベクタ型に適用された場合、ベクタの結合を意味します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1274
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# enum Crayon { Almond, AntiqueBrass, Apricot,\n"
+"# Aquamarine, Asparagus, AtomicTangerine,\n"
+"# BananaMania, Beaver, Bittersweet };\n"
+"# impl Clone for Crayon {\n"
+"# fn clone(&self) -> Crayon {\n"
+"# *self\n"
+"# }\n"
+"# }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1277
+msgid ""
+"let my_crayons = ~[Almond, AntiqueBrass, Apricot]; let your_crayons = "
+"~[BananaMania, Beaver, Bittersweet];"
+msgstr ""
+"let my_crayons = ~[Almond, AntiqueBrass, Apricot];\n"
+"let your_crayons = ~[BananaMania, Beaver, Bittersweet];"
+
+#. type: Plain text
+#: doc/tutorial.md:1280
+msgid ""
+"// Add two vectors to create a new one let our_crayons = my_crayons + "
+"your_crayons;"
+msgstr ""
+"// 2 つのベクタを結合して、新しいベクタを作る\n"
+"let our_crayons = my_crayons + your_crayons;"
+
+#. type: Plain text
+#: doc/tutorial.md:1285
+msgid ""
+"// .push_all() will append to a vector, provided it lives in a mutable slot "
+"let mut my_crayons = my_crayons; my_crayons.push_all(your_crayons); ~~~~"
+msgstr ""
+"// .push_all() はベクタに要素を追加します。ミュータブルなスロットのベクタに対"
+"してのみ有効です\n"
+"let mut my_crayons = my_crayons;\n"
+"my_crayons.push_all(your_crayons);\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1290
+msgid ""
+"> ***Note:*** The above examples of vector addition use owned > vectors. "
+"Some operations on slices and stack vectors are > not yet well-supported. "
+"Owned vectors are often the most > usable."
+msgstr ""
+"> ***注意:*** 上記のベクタに要素を追加する例では、所有ベクタを利用していま"
+"す。いくつかの操作はスライスやスタックベクタを十分にサポートしていません。所"
+"有ベクタが最も便利な場合がしばしばあります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1292
+msgid "Square brackets denote indexing into a vector:"
+msgstr "角括弧はベクタの添字を表します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1304
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# enum Crayon { Almond, AntiqueBrass, Apricot,\n"
+"# Aquamarine, Asparagus, AtomicTangerine,\n"
+"# BananaMania, Beaver, Bittersweet };\n"
+"# fn draw_scene(c: Crayon) { }\n"
+"let crayons: [Crayon, ..3] = [BananaMania, Beaver, Bittersweet];\n"
+"match crayons[0] {\n"
+" Bittersweet => draw_scene(crayons[0]),\n"
+" _ => ()\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1306
+msgid "A vector can be destructured using pattern matching:"
+msgstr "ベクタはパターンマッチにより destructuring することができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1316
+#, no-wrap
+msgid ""
+"~~~~\n"
+"let numbers: &[int] = &[1, 2, 3];\n"
+"let score = match numbers {\n"
+" [] => 0,\n"
+" [a] => a * 10,\n"
+" [a, b] => a * 6 + b * 4,\n"
+" [a, b, c, ..rest] => a * 5 + b * 3 + c * 2 + rest.len() as int\n"
+"};\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1320
+msgid ""
+"The elements of a vector _inherit the mutability of the vector_, and as "
+"such, individual elements may not be reassigned when the vector lives in an "
+"immutable slot."
+msgstr ""
+"ベクタの要素は、 __ベクタのミュータビリティを継承するので__、ベクタがイミュー"
+"タブルなスロットに格納されている場合は個々の要素を変更する (再代入する) こと"
+"はできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:1326
+#, no-wrap
+msgid ""
+"~~~ {.xfail-test}\n"
+"# enum Crayon { Almond, AntiqueBrass, Apricot,\n"
+"# Aquamarine, Asparagus, AtomicTangerine,\n"
+"# BananaMania, Beaver, Bittersweet };\n"
+"let crayons: ~[Crayon] = ~[BananaMania, Beaver, Bittersweet];\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1329
+msgid "crayons[0] = Apricot; // ERROR: Can't assign to immutable vector ~~~"
+msgstr ""
+"crayons[0] = Apricot; // ERROR: Can't assign to immutable vector\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1331
+msgid "Moving it into a mutable slot makes the elements assignable."
+msgstr ""
+"ベクタをミュータブルなスロットに移動することで、要素への代入が可能になりま"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:1337
+#, no-wrap
+msgid ""
+"~~~\n"
+"# enum Crayon { Almond, AntiqueBrass, Apricot,\n"
+"# Aquamarine, Asparagus, AtomicTangerine,\n"
+"# BananaMania, Beaver, Bittersweet };\n"
+"let crayons: ~[Crayon] = ~[BananaMania, Beaver, Bittersweet];\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1340
+msgid ""
+"// Put the vector into a mutable slot let mut mutable_crayons = crayons;"
+msgstr ""
+"// ベクタをミュータブルなスロットに配置する\n"
+"let mut mutable_crayons = crayons;"
+
+#. type: Plain text
+#: doc/tutorial.md:1344
+msgid "// Now it's mutable to the bone mutable_crayons[0] = Apricot; ~~~"
+msgstr ""
+"// 完全にミュータブルになった\n"
+"mutable_crayons[0] = Apricot;\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1347
+msgid ""
+"This is a simple example of Rust's _dual-mode data structures_, also "
+"referred to as _freezing and thawing_."
+msgstr ""
+"これは、__凍結および解凍__ (_freezing and thawing_) と呼ばれる、Rust の __"
+"デュアルモードのデータ構造__ についての簡単な例です。"
+
+#. type: Plain text
+#: doc/tutorial.md:1355
+msgid ""
+"Strings are implemented with vectors of `u8`, though they have a distinct "
+"type. They support most of the same allocation options as vectors, though "
+"the string literal without a storage sigil (for example, `\"foo\"`) is "
+"treated differently than a comparable vector (`[foo]`). Whereas plain "
+"vectors are stack-allocated fixed-length vectors, plain strings are borrowed "
+"pointers to read-only (static) memory. All strings are immutable."
+msgstr ""
+"文字列は `u8` 型のベクタとして実装されていますが、ベクタとは異なる独自の型を"
+"持ちます。文字列はベクタと同じくメモリを獲得先を選択できますが、ストレージを"
+"表すシジルが付与されていない文字列リテラル (`\"foo\"` など) は対応するベクタ "
+"(`[foo]`) と異なった扱いをされます。シジルなしのベクタはスタックに獲得される"
+"固定長のベクタですが、シジルなしの文字列は読み込み専用の (静的な) メモリ領域"
+"への借用ポインタとなります。すべての文字列はイミュータブルです。"
+
+#. type: Plain text
+#: doc/tutorial.md:1359
+msgid ""
+"~~~ // A plain string is a slice to read-only (static) memory let "
+"stack_crayons: &str = \"Almond, AntiqueBrass, Apricot\";"
+msgstr ""
+"~~~\n"
+"// シジルなしの文字列は、読み込み専用な (静的) メモリへのスライス\n"
+"let stack_crayons: &str = \"Almond, AntiqueBrass, Apricot\";"
+
+#. type: Plain text
+#: doc/tutorial.md:1362
+msgid ""
+"// The same thing, but with the `&` let stack_crayons: &str = &\"Aquamarine, "
+"Asparagus, AtomicTangerine\";"
+msgstr ""
+"// `&` を付与した場合も、シジルなしと同じ意味\n"
+"let stack_crayons: &str = &\"Aquamarine, Asparagus, AtomicTangerine\";"
+
+#. type: Plain text
+#: doc/tutorial.md:1365
+msgid ""
+"// A local heap (managed) string let local_crayons: @str = @\"BananaMania, "
+"Beaver, Bittersweet\";"
+msgstr ""
+"// ローカルヒープ上の (マネージドな) 文字列\n"
+"let local_crayons: @str = @\"BananaMania, Beaver, Bittersweet\";"
+
+#. type: Plain text
+#: doc/tutorial.md:1369
+msgid ""
+"// An exchange heap (owned) string let exchange_crayons: ~str = ~\"Black, "
+"BlizzardBlue, Blue\"; ~~~"
+msgstr ""
+"// 交換ヒープ上の (所有) 文字列\n"
+"let exchange_crayons: ~str = ~\"Black, BlizzardBlue, Blue\";\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1373
+msgid ""
+"Both vectors and strings support a number of useful [methods](#methods), "
+"defined in [`std::vec`] and [`std::str`]. Here are some examples."
+msgstr ""
+"ベクタと文字列は、[`std::vec`] と [`std::str`] で定義された、多くの有用な [メ"
+"ソッド](#methods) を持ちます。以下にいくつか例を挙げます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1376
+msgid "[`std::vec`]: std/vec.html [`std::str`]: std/str.html"
+msgstr ""
+"[`std::vec`]: std/vec.html\n"
+"[`std::str`]: std/str.html"
+
+#. type: Plain text
+#: doc/tutorial.md:1387
+#, no-wrap
+msgid ""
+"~~~\n"
+"# enum Crayon {\n"
+"# Almond, AntiqueBrass, Apricot,\n"
+"# Aquamarine, Asparagus, AtomicTangerine,\n"
+"# BananaMania, Beaver, Bittersweet\n"
+"# }\n"
+"# fn unwrap_crayon(c: Crayon) -> int { 0 }\n"
+"# fn eat_crayon_wax(i: int) { }\n"
+"# fn store_crayon_in_nasal_cavity(i: uint, c: Crayon) { }\n"
+"# fn crayon_to_str(c: Crayon) -> &str { \"\" }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1389
+msgid "let crayons = [Almond, AntiqueBrass, Apricot];"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1393
+msgid ""
+"// Check the length of the vector assert!(crayons.len() == 3); assert!(!"
+"crayons.is_empty());"
+msgstr ""
+"// ベクタの長さをチェックする\n"
+"assert!(crayons.len() == 3);\n"
+"assert!(!crayons.is_empty());"
+
+#. type: Plain text
+#: doc/tutorial.md:1400
+#, no-wrap
+msgid ""
+"// Iterate over a vector, obtaining a pointer to each element\n"
+"// (`for` is explained in the container/iterator tutorial)\n"
+"for crayon in crayons.iter() {\n"
+" let delicious_crayon_wax = unwrap_crayon(*crayon);\n"
+" eat_crayon_wax(delicious_crayon_wax);\n"
+"}\n"
+msgstr ""
+"// ベクタの要素をイテレートし、各要素へのポインタを取得する\n"
+"// (`for` については、は次の章で説明します)\n"
+"for crayon in crayons.iter() {\n"
+" let delicious_crayon_wax = unwrap_crayon(*crayon);\n"
+" eat_crayon_wax(delicious_crayon_wax);\n"
+"}\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1404
+msgid ""
+"// Map vector elements let crayon_names = crayons.map(|v| "
+"crayon_to_str(*v)); let favorite_crayon_name = crayon_names[0];"
+msgstr ""
+"// ベクタの要素をマッピング (変換) する\n"
+"let crayon_names = crayons.map(|v| crayon_to_str(*v));\n"
+"let favorite_crayon_name = crayon_names[0];"
+
+#. type: Plain text
+#: doc/tutorial.md:1407
+msgid ""
+"// Remove whitespace from before and after the string let "
+"new_favorite_crayon_name = favorite_crayon_name.trim();"
+msgstr ""
+"// 文字列の先頭と末尾の空白を除去する\n"
+"let new_favorite_crayon_name = favorite_crayon_name.trim();"
+
+#. type: Plain text
+#: doc/tutorial.md:1413
+#, no-wrap
+msgid ""
+"if favorite_crayon_name.len() > 5 {\n"
+" // Create a substring\n"
+" println(favorite_crayon_name.slice_chars(0, 5));\n"
+"}\n"
+"~~~\n"
+msgstr ""
+"if favorite_crayon_name.len() > 5 {\n"
+" // 部分文字列を作る\n"
+" println(favorite_crayon_name.slice_chars(0, 5));\n"
+"}\n"
+"~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1415
+msgid "# Closures"
+msgstr "# クロージャ"
+
+#. type: Plain text
+#: doc/tutorial.md:1420
+msgid ""
+"Named functions, like those we've seen so far, may not refer to local "
+"variables declared outside the function: they do not close over their "
+"environment (sometimes referred to as \"capturing\" variables in their "
+"environment). For example, you couldn't write the following:"
+msgstr ""
+"これまで登場したような名前のある関数は、関数の外で定義されるローカル変数を参"
+"照することはできません。ローカル変数は環境を閉じ込める (環境中の変数を「キャ"
+"プチャする」と呼ばれることもあります) ことはありません。例えば、以下のような"
+"コードを書くことはできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:1423
+msgid "~~~~ {.ignore} let foo = 10;"
+msgstr ""
+"~~~~ {.ignore}\n"
+"let foo = 10;"
+
+#. type: Plain text
+#: doc/tutorial.md:1428
+#, no-wrap
+msgid ""
+"fn bar() -> int {\n"
+" return foo; // `bar` cannot refer to `foo`\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+"fn bar() -> int {\n"
+" return foo; // `bar` ば `foo` を参照できない\n"
+"}\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1431
+msgid ""
+"Rust also supports _closures_, functions that can access variables in the "
+"enclosing scope."
+msgstr ""
+"Rust は __クロージャ__ という、周囲のスコープの変数にアクセスできる関数をサ"
+"ポートしています。"
+
+#. type: Plain text
+#: doc/tutorial.md:1434
+msgid "~~~~ fn call_closure_with_ten(b: &fn(int)) { b(10); }"
+msgstr ""
+"~~~~\n"
+"fn call_closure_with_ten(b: &fn(int)) { b(10); }"
+
+#. type: Plain text
+#: doc/tutorial.md:1437
+msgid ""
+"let captured_var = 20; let closure = |arg| println(fmt!(\"captured_var=%d, "
+"arg=%d\", captured_var, arg));"
+msgstr ""
+"let captured_var = 20;\n"
+"let closure = |arg| println(fmt!(\"captured_var=%d, arg=%d\", captured_var, "
+"arg));"
+
+#. type: Plain text
+#: doc/tutorial.md:1440
+msgid "call_closure_with_ten(closure); ~~~~"
+msgstr ""
+"call_closure_with_ten(closure);\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1446
+msgid ""
+"Closures begin with the argument list between vertical bars and are followed "
+"by a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, "
+"is considered a single expression: it evaluates to the result of the last "
+"expression it contains if that expression is not followed by a semicolon, "
+"otherwise the block evaluates to `()`."
+msgstr ""
+"クロージャはバーティカルバー (`|`) で囲まれた引数リストと、それに続く単一の式"
+"から構成されます。ブロック `{ <expr1>; <expr2>; ...}` は単一の式とみなされる"
+"ことを思い出してください。ブロックに含まれる最後の式に続けてセミコロンがない"
+"場合、ブロックの値は最後の式の値となり、そうでなければ `()` となります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1451
+msgid ""
+"The types of the arguments are generally omitted, as is the return type, "
+"because the compiler can almost always infer them. In the rare case where "
+"the compiler needs assistance, though, the arguments and return types may be "
+"annotated."
+msgstr ""
+"引数の型や戻り値の型は、ほとんどすべての場合においてコンパイラにより推論され"
+"るため、通常省略できます。発生するのはまれですが、コンパイラが推論に失敗する"
+"場合は、引数と戻り値の型注釈を付けることがあります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1455
+msgid "~~~~ let square = |x: int| -> uint { (x * x) as uint }; ~~~~"
+msgstr ""
+"~~~~\n"
+"let square = |x: int| -> uint { (x * x) as uint };\n"
+"~~~~~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1459
+msgid ""
+"There are several forms of closure, each with its own role. The most common, "
+"called a _stack closure_, has type `&fn` and can directly access local "
+"variables in the enclosing scope."
+msgstr ""
+"クロージャにはいくつかの形態があり、それぞれに独自の役割があります。最も一般"
+"的なのはスタッククロージャと呼ばれるもので、 `&fn` という型を持ち、外側のロー"
+"カル変数に直接アクセスすることができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1464
+msgid "~~~~ let mut max = 0; [1, 2, 3].map(|x| if *x > max { max = *x }); ~~~~"
+msgstr ""
+"~~~~\n"
+"let mut max = 0;\n"
+"[1, 2, 3].map(|x| if *x > max { max = *x });\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1473
+msgid ""
+"Stack closures are very efficient because their environment is allocated on "
+"the call stack and refers by pointer to captured locals. To ensure that "
+"stack closures never outlive the local variables to which they refer, stack "
+"closures are not first-class. That is, they can only be used in argument "
+"position; they cannot be stored in data structures or returned from "
+"functions. Despite these limitations, stack closures are used pervasively in "
+"Rust code."
+msgstr ""
+"スタッククロージャは、閉じ込める環境はコールスタック上に獲得され、ローカル変"
+"数をポインタで参照するため、非常に効率的です。スタッククロージャが参照してい"
+"るローカル変数よりも長生きしないことを保証するため、スタッククロージャは第一"
+"級の値ではありません。すなわち、スタッククロージャは引数としてしか使うことが"
+"できず、データ構造や関数の戻り値となることはありません。この制限にも関わら"
+"ず、スタッククロージャは Rust のコードのあちこちに登場します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1475
+msgid "## Managed closures"
+msgstr "## マネージドクロージャ"
+
+#. type: Plain text
+#: doc/tutorial.md:1481
+msgid ""
+"When you need to store a closure in a data structure, a stack closure will "
+"not do, since the compiler will refuse to let you store it. For this "
+"purpose, Rust provides a type of closure that has an arbitrary lifetime, "
+"written `@fn` (boxed closure, analogous to the `@` pointer type described "
+"earlier). This type of closure *is* first-class."
+msgstr ""
+"クロージャをデータ構造に格納する必要がある場合、スタッククロージャを利用する"
+"ことは言語仕様上、許可されていませんRust は、このような目的のために任意の寿命"
+"を持つクロージャ型、`@fn` (ボックスクロージャ、 前述の `@` ポインタ型と似たよ"
+"うなもの) を提供しています。この種のクロージャ **は** 第一級の値です。"
+
+#. type: Plain text
+#: doc/tutorial.md:1486
+msgid ""
+"A managed closure does not directly access its environment, but merely "
+"copies out the values that it closes over into a private data structure. "
+"This means that it can not assign to these variables, and cannot observe "
+"updates to them."
+msgstr ""
+"マネージドクロージャは環境に直接アクセスすることはできませんが、単に値をコ"
+"ピーしてプライベートなデータ構造に閉じ込めます。これは、クロージャは変数に値"
+"を代入することや、値の変更を監視することもできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:1489
+msgid ""
+"This code creates a closure that adds a given string to its argument, "
+"returns it from a function, and then calls it:"
+msgstr ""
+"このコードは、与えられた文字列を引数に追加するクロージャを返却する関数と、そ"
+"の呼び出しです。"
+
+#. type: Plain text
+#: doc/tutorial.md:1495
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn mk_appender(suffix: ~str) -> @fn(~str) -> ~str {\n"
+" // The compiler knows that we intend this closure to be of type @fn\n"
+" return |s| s + suffix;\n"
+"}\n"
+msgstr ""
+"~~~~\n"
+"fn mk_appender(suffix: ~str) -> @fn(~str) -> ~str {\n"
+" // コンパイラはこのクロージャが @fn 型であることを推論します\n"
+" return |s| s + suffix;\n"
+"}\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1501
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" let shout = mk_appender(~\"!\");\n"
+" println(shout(~\"hey ho, let's go\"));\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1503
+msgid "## Owned closures"
+msgstr "## 所有クロージャ"
+
+#. type: Plain text
+#: doc/tutorial.md:1510
+msgid ""
+"Owned closures, written `~fn` in analogy to the `~` pointer type, hold on to "
+"things that can safely be sent between processes. They copy the values they "
+"close over, much like managed closures, but they also own them: that is, no "
+"other code can access them. Owned closures are used in concurrent code, "
+"particularly for spawning [tasks][tasks]."
+msgstr ""
+"`~` ポインタ型と同様に `~fn` 型 で書き表される所有クロージャは安全にプロセス"
+"間で送信することができます。所有クローじゃはマネージドクロージャと全く同じよ"
+"うに閉じ込める値をコピーしますが、値を所有します。つまり、他のコードは閉じ込"
+"められた値にアクセスできなくなります。所有クロージャは並列プログラム、特に "
+"[タスク][tasks] 生成で利用されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1512
+msgid "## Closure compatibility"
+msgstr "## クロージャの互換性"
+
+#. type: Plain text
+#: doc/tutorial.md:1519
+msgid ""
+"Rust closures have a convenient subtyping property: you can pass any kind of "
+"closure (as long as the arguments and return types match) to functions that "
+"expect a `&fn()`. Thus, when writing a higher-order function that only calls "
+"its function argument, and does nothing else with it, you should almost "
+"always declare the type of that argument as `&fn()`. That way, callers may "
+"pass any kind of closure."
+msgstr ""
+"Rust のクロージャは型の派生 (subtyping) という便利な性質を持っています。この"
+"性質により、`&fn()` 型を期待する関数には (引数と戻り値の型が一致する限り) 任"
+"意の種類のクロージャを渡すことができます。したがって、引数で渡された関数につ"
+"いては呼び出すだけで他に何もしない高階関数を書くときには、ほぼすべてのケース"
+"で引数の型を `&fn` と宣言するべきです。そうすることで、呼び出し元は任意の種類"
+"のクロージャを渡すことができるよになります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1527
+msgid ""
+"~~~~ fn call_twice(f: &fn()) { f(); f(); } let closure = || { \"I'm a "
+"closure, and it doesn't matter what type I am\"; }; fn function() { \"I'm a "
+"normal function\"; } call_twice(closure); call_twice(function); ~~~~"
+msgstr ""
+"~~~~\n"
+"fn call_twice(f: &fn()) { f(); f(); }\n"
+"let closure = || { \"I'm a closure, and it doesn't matter what type I am"
+"\"; };\n"
+"fn function() { \"I'm a normal function\"; }\n"
+"call_twice(closure);\n"
+"call_twice(function);\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1531
+msgid ""
+"> ***Note:*** Both the syntax and the semantics will be changing > in small "
+"ways. At the moment they can be unsound in some > scenarios, particularly "
+"with non-copyable types."
+msgstr ""
+"> ***注意*** コードの文法と意味は将来的に変更されるかもしれません。現時点では"
+"いくつかの状況、特にコピーできない型が関連するケースにおいて望ましくない振る"
+"舞いが起こされる場合があります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1533
+msgid "## Do syntax"
+msgstr "## do 構文"
+
+#. type: Plain text
+#: doc/tutorial.md:1536
+msgid ""
+"The `do` expression provides a way to treat higher-order functions "
+"(functions that take closures as arguments) as control structures."
+msgstr ""
+"`do` 式は高階関数 (クロージャを引数にとる関数) を制御構造のように取り扱う方法"
+"を提供します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1539
+msgid ""
+"Consider this function that iterates over a vector of integers, passing in a "
+"pointer to each integer in the vector:"
+msgstr ""
+"要素が整数のベクトルをイテレートし、各整数へのポインタをクロージャへと渡す、"
+"以下の関数について考えます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1549
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn each(v: &[int], op: &fn(v: &int)) {\n"
+" let mut n = 0;\n"
+" while n < v.len() {\n"
+" op(&v[n]);\n"
+" n += 1;\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1553
+msgid ""
+"As a caller, if we use a closure to provide the final operator argument, we "
+"can write it in a way that has a pleasant, block-like structure."
+msgstr ""
+"最後の引数にクロージャをとる関数を呼び出す場合、ブロック構造を持つかのように"
+"コードを書くことが可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:1561
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# fn each(v: &[int], op: &fn(v: &int)) { }\n"
+"# fn do_some_work(i: &int) { }\n"
+"each([1, 2, 3], |n| {\n"
+" do_some_work(n);\n"
+"});\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1564
+msgid ""
+"This is such a useful pattern that Rust has a special form of function call "
+"that can be written more like a built-in control structure:"
+msgstr ""
+"このような便利なパターンに対応するため、Rust には、言語組み込みの制御構造のよ"
+"うな記述が可能な、特別な関数呼び出し形式があります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1572
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# fn each(v: &[int], op: &fn(v: &int)) { }\n"
+"# fn do_some_work(i: &int) { }\n"
+"do each([1, 2, 3]) |n| {\n"
+" do_some_work(n);\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1577
+msgid ""
+"The call is prefixed with the keyword `do` and, instead of writing the final "
+"closure inside the argument list, it appears outside of the parentheses, "
+"where it looks more like a typical block of code."
+msgstr ""
+"関数呼び出しの前には `do` キーワードをつけ、引数リストの中に最後のクロージャ"
+"引数を書くのではなく、普通のコードブロックのように、丸括弧の外に記述します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1582
+msgid ""
+"`do` is a convenient way to create tasks with the `task::spawn` function. "
+"`spawn` has the signature `spawn(fn: ~fn())`. In other words, it is a "
+"function that takes an owned closure that takes no arguments."
+msgstr ""
+"`task::spawn` 関数を用いてタスクを生成する場合、 `do` を用いると便利です。"
+"`spawn` は、 `spawn(fn: ~fn())` という方を持っています。言い換えると、"
+"`spawn` は「引数をとらない所有クロージャ」を引数としてとる関数ということで"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:1585 doc/tutorial.md:1597
+msgid "~~~~ use std::task::spawn;"
+msgstr ""
+"~~~~\n"
+"use std::task::spawn;"
+
+#. type: Plain text
+#: doc/tutorial.md:1590
+#, no-wrap
+msgid ""
+"do spawn() || {\n"
+" debug!(\"I'm a task, whatever\");\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1594
+msgid ""
+"Look at all those bars and parentheses -- that's two empty argument lists "
+"back to back. Since that is so unsightly, empty argument lists may be "
+"omitted from `do` expressions."
+msgstr ""
+"このコードの丸括弧と縦棒に注目してください。立て続けに2の空の引数リストが現れ"
+"ているます。これは非常に見苦しいので、`do` 式では空の引数リストを省略すること"
+"が可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:1602
+#, no-wrap
+msgid ""
+"do spawn {\n"
+" debug!(\"Kablam!\");\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1605
+msgid ""
+"If you want to see the output of `debug!` statements, you will need to turn "
+"on `debug!` logging. To enable `debug!` logging, set the RUST_LOG "
+"environment variable to the name of your crate, which, for a file named `foo."
+"rs`, will be `foo` (e.g., with bash, `export RUST_LOG=foo`)."
+msgstr ""
+"`debug!` ステートメントの出力を見たい場合、`debug!` によるロギングを有効にす"
+"る必要があるでしょう。`debug!` によるロギングを有効にするためには、 RUST_LOG "
+"環境変数をクレートの名前に設定する必要があります (例えば、bash の場合、 "
+"`export RUST_LOG=foo` を実行する)。 `foo.rs` というファイルの場合、クレート名"
+"は `foo` になります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1607
+msgid "# Methods"
+msgstr "# メソッド"
+
+#. type: Plain text
+#: doc/tutorial.md:1613
+msgid ""
+"Methods are like functions except that they always begin with a special "
+"argument, called `self`, which has the type of the method's receiver. The "
+"`self` argument is like `this` in C++ and many other languages. Methods are "
+"called with dot notation, as in `my_vec.len()`."
+msgstr ""
+"メソッドは、`self` という、メソッドのレシーバと同じ型の特別な引数を第一引数と"
+"してとる関数のようなものです。`self` は、 C++ や他の言語の `this` のようなも"
+"のです。メソッドはドット記法を浸かって `my_vec.len()` のように呼び出します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1617
+msgid ""
+"_Implementations_, written with the `impl` keyword, can define methods on "
+"most Rust types, including structs and enums. As an example, let's define a "
+"`draw` method on our `Shape` enum."
+msgstr ""
+"`impl` キーワードを使って記述される __実装__ (_implementation_) により、構造"
+"体や列挙型を含むほとんどの Rust の型に対してメソッドを定義することができま"
+"す。例のように、 `draw` メソッドを `Shape` 列挙型に定義してみましょう。"
+
+#. type: Plain text
+#: doc/tutorial.md:1625
+#, no-wrap
+msgid ""
+"~~~\n"
+"# fn draw_circle(p: Point, f: float) { }\n"
+"# fn draw_rectangle(p: Point, p: Point) { }\n"
+"struct Point {\n"
+" x: float,\n"
+" y: float\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1630
+#, no-wrap
+msgid ""
+"enum Shape {\n"
+" Circle(Point, float),\n"
+" Rectangle(Point, Point)\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1639
+#, no-wrap
+msgid ""
+"impl Shape {\n"
+" fn draw(&self) {\n"
+" match *self {\n"
+" Circle(p, f) => draw_circle(p, f),\n"
+" Rectangle(p1, p2) => draw_rectangle(p1, p2)\n"
+" }\n"
+" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1643
+msgid "let s = Circle(Point { x: 1f, y: 2f }, 3f); s.draw(); ~~~"
+msgstr ""
+"let s = Circle(Point { x: 1f, y: 2f }, 3f);\n"
+"s.draw();\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1647
+msgid ""
+"This defines an _implementation_ for `Shape` containing a single method, "
+"`draw`. In most respects the `draw` method is defined like any other "
+"function, except for the name `self`."
+msgstr ""
+"この例では、 `Shape` に1つのメソッド `draw` をもつ __実装__ を定義していま"
+"す。`draw` メソッドは、`self` という名前を除くほとんどの面で他の関数と同じよ"
+"うに定義されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1652
+msgid ""
+"The type of `self` is the type on which the method is implemented, or a "
+"pointer thereof. As an argument it is written either `self`, `&self`, "
+"`@self`, or `~self`. A caller must in turn have a compatible pointer type "
+"to call the method."
+msgstr ""
+"`self` の型は、メソッドが実装されている型か、それらのポインタである。引数とし"
+"ては、 `self`, `&self`, `@self` または `~self` と記述されます。呼び出し側も同"
+"様、メソッドを呼び出すための互換性のあるポインタ型をもつ必要があります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1667
+#, no-wrap
+msgid ""
+"~~~\n"
+"# fn draw_circle(p: Point, f: float) { }\n"
+"# fn draw_rectangle(p: Point, p: Point) { }\n"
+"# struct Point { x: float, y: float }\n"
+"# enum Shape {\n"
+"# Circle(Point, float),\n"
+"# Rectangle(Point, Point)\n"
+"# }\n"
+"impl Shape {\n"
+" fn draw_borrowed(&self) { ... }\n"
+" fn draw_managed(@self) { ... }\n"
+" fn draw_owned(~self) { ... }\n"
+" fn draw_value(self) { ... }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1669
+msgid "let s = Circle(Point { x: 1f, y: 2f }, 3f);"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1675
+msgid ""
+"(@s).draw_managed(); (~s).draw_owned(); (&s).draw_borrowed(); s."
+"draw_value(); ~~~"
+msgstr ""
+"(@s).draw_managed();\n"
+"(~s).draw_owned();\n"
+"(&s).draw_borrowed();\n"
+"s.draw_value();\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1679
+msgid ""
+"Methods typically take a borrowed pointer self type, so the compiler will go "
+"to great lengths to convert a callee to a borrowed pointer."
+msgstr ""
+"多くのメソッドは、借用ポインタの self 型を持つので、コンパイラは呼び出し先を"
+"借用ポインタに変換するためあらゆる手段を講じます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1697
+#, no-wrap
+msgid ""
+"~~~\n"
+"# fn draw_circle(p: Point, f: float) { }\n"
+"# fn draw_rectangle(p: Point, p: Point) { }\n"
+"# struct Point { x: float, y: float }\n"
+"# enum Shape {\n"
+"# Circle(Point, float),\n"
+"# Rectangle(Point, Point)\n"
+"# }\n"
+"# impl Shape {\n"
+"# fn draw_borrowed(&self) { ... }\n"
+"# fn draw_managed(@self) { ... }\n"
+"# fn draw_owned(~self) { ... }\n"
+"# fn draw_value(self) { ... }\n"
+"# }\n"
+"# let s = Circle(Point { x: 1f, y: 2f }, 3f);\n"
+"// As with typical function arguments, managed and owned pointers\n"
+"// are automatically converted to borrowed pointers\n"
+msgstr ""
+"~~~\n"
+"# fn draw_circle(p: Point, f: float) { }\n"
+"# fn draw_rectangle(p: Point, p: Point) { }\n"
+"# struct Point { x: float, y: float }\n"
+"# enum Shape {\n"
+"# Circle(Point, float),\n"
+"# Rectangle(Point, Point)\n"
+"# }\n"
+"# impl Shape {\n"
+"# fn draw_borrowed(&self) { ... }\n"
+"# fn draw_managed(@self) { ... }\n"
+"# fn draw_owned(~self) { ... }\n"
+"# fn draw_value(self) { ... }\n"
+"# }\n"
+"# let s = Circle(Point { x: 1f, y: 2f }, 3f);\n"
+"// 関数の引数と同様、マネージドポインタと所有ポインタは、\n"
+"// 自動的に借用ポインタに変換される\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1700
+msgid "(@s).draw_borrowed(); (~s).draw_borrowed();"
+msgstr ""
+"(@s).draw_borrowed();\n"
+"(~s).draw_borrowed();"
+
+#. type: Plain text
+#: doc/tutorial.md:1704
+msgid ""
+"// Unlike typical function arguments, the self value will // automatically "
+"be referenced ... s.draw_borrowed();"
+msgstr ""
+"// 関数の引数とは異なり、 self の値は自動的にリファレンスされたり、 ...\n"
+"s.draw_borrowed();"
+
+#. type: Plain text
+#: doc/tutorial.md:1707
+msgid "// ... and dereferenced (& &s).draw_borrowed();"
+msgstr ""
+"// ... デリファレンスされたり、\n"
+"(& &s).draw_borrowed();"
+
+#. type: Plain text
+#: doc/tutorial.md:1711
+msgid "// ... and dereferenced and borrowed (&@~s).draw_borrowed(); ~~~"
+msgstr ""
+"// ... デリファレンス後借用されたりします\n"
+"(&@~s).draw_borrowed();\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1715
+msgid ""
+"Implementations may also define standalone (sometimes called \"static\") "
+"methods. The absence of a `self` parameter distinguishes such methods. "
+"These methods are the preferred way to define constructor functions."
+msgstr ""
+"実装では、スタンドアロンなメソッド (「静的 (static)」メソッドと呼ばれる場合も"
+"あります)を定義することも可能です。引数に `self` をつけない場合、スタンドアロ"
+"ンなメソッドとなります。コンストラクタ関数は、スタンドアロンなメソッドとして"
+"定義することが推奨されています。"
+
+#. type: Plain text
+#: doc/tutorial.md:1722
+#, no-wrap
+msgid ""
+"~~~~ {.xfail-test}\n"
+"impl Circle {\n"
+" fn area(&self) -> float { ... }\n"
+" fn new(area: float) -> Circle { ... }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1724
+msgid ""
+"To call such a method, just prefix it with the type name and a double colon:"
+msgstr ""
+"メソッド名の前に型名と2つのコロンを付けることで、スタンドアロンメソッドは呼び"
+"出せます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1733
+#, no-wrap
+msgid ""
+"~~~~\n"
+"use std::float::consts::pi;\n"
+"struct Circle { radius: float }\n"
+"impl Circle {\n"
+" fn new(area: float) -> Circle { Circle { radius: (area / pi).sqrt() } }\n"
+"}\n"
+"let c = Circle::new(42.5);\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1735
+msgid "# Generics"
+msgstr "# ジェネリクス"
+
+#. type: Plain text
+#: doc/tutorial.md:1743
+msgid ""
+"Throughout this tutorial, we've been defining functions that act only on "
+"specific data types. With type parameters we can also define functions whose "
+"arguments have generic types, and which can be invoked with a variety of "
+"types. Consider a generic `map` function, which takes a function `function` "
+"and a vector `vector` and returns a new vector consisting of the result of "
+"applying `function` to each element of `vector`:"
+msgstr ""
+"このチュートリアルでは、特定のデータ型のみに対して動作する関数を定義してきま"
+"した。型パラメータを用いるとジェネリックな型を引数にとり、様々な型で呼び出す"
+"ことの可能な関数を定義できます。関数 `function` とベクタ `vector` を引数にと"
+"り、`function` を`vector` の各要素に適用した結果からなる新たなベクタを返す、"
+"`map` というジェネリック関数について考えます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1753
+#, no-wrap
+msgid ""
+"~~~~\n"
+"fn map<T, U>(vector: &[T], function: &fn(v: &T) -> U) -> ~[U] {\n"
+" let mut accumulator = ~[];\n"
+" for element in vector.iter() {\n"
+" accumulator.push(function(element));\n"
+" }\n"
+" return accumulator;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1758
+msgid ""
+"When defined with type parameters, as denoted by `<T, U>`, this function can "
+"be applied to any type of vector, as long as the type of `function`'s "
+"argument and the type of the vector's contents agree with each other."
+msgstr ""
+"上記例で `<T, U>` と示されているように、型パラメータとともに関数を定義するこ"
+"とで、`function` の引数の型と`vectror` の要素の型が一致する場合に限りますが、"
+"任意の型のベクタを引数として渡すことが可能になります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1768
+msgid ""
+"Inside a generic function, the names of the type parameters (capitalized by "
+"convention) stand for opaque types. All you can do with instances of these "
+"types is pass them around: you can't apply any operations to them or pattern-"
+"match on them. Note that instances of generic types are often passed by "
+"pointer. For example, the parameter `function()` is supplied with a pointer "
+"to a value of type `T` and not a value of type `T` itself. This ensures that "
+"the function works with the broadest set of types possible, since some types "
+"are expensive or illegal to copy and pass by value."
+msgstr ""
+"ジェネリック関数の内部では、型パラメータの名前 (慣例的に大文字で表されます) "
+"は不透明型 (opaque type) を意味します。これらの型のインスタンスに対しては、他"
+"の関数に渡すことだけが可能で、演算子を適用したり、パターンマッチすることはで"
+"きません。ジェネリック型のインスタンスは、ポインタにより渡されることもあるこ"
+"とに注意してください。例えば、 `function()` パラメータが `T` 型自身の値ではな"
+"く `T` 型の値へのポインタとして渡されるということです。いくつかの型は、値をコ"
+"ピーするコストが高かったり、コピーが禁じられていたりするので、ポインタ渡しに"
+"することで、関数の引数としてとることのできる型の範囲が広がります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1770
+msgid ""
+"Generic `type`, `struct`, and `enum` declarations follow the same pattern:"
+msgstr ""
+"ジェネリックな型、構造体、および列挙型の宣言は、同じパターンに従います。"
+
+#. type: Plain text
+#: doc/tutorial.md:1774
+msgid "~~~~ use std::hashmap::HashMap; type Set<T> = HashMap<T, ()>;"
+msgstr ""
+"~~~~\n"
+"use std::hashmap::HashMap;\n"
+"type Set<T> = HashMap<T, ()>;"
+
+#. type: Plain text
+#: doc/tutorial.md:1778
+#, no-wrap
+msgid ""
+"struct Stack<T> {\n"
+" elements: ~[T]\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1784
+#, no-wrap
+msgid ""
+"enum Option<T> {\n"
+" Some(T),\n"
+" None\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1787
+msgid ""
+"These declarations can be instantiated to valid types like `Set<int>`, "
+"`Stack<int>`, and `Option<int>`."
+msgstr ""
+"これらの宣言により、 `Set<int>` や `Stack<int>`、 `Option<int>` のような正当"
+"な型を生成することができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1793
+msgid ""
+"The last type in that example, `Option`, appears frequently in Rust code. "
+"Because Rust does not have null pointers (except in unsafe code), we need "
+"another way to write a function whose result isn't defined on every possible "
+"combination of arguments of the appropriate types. The usual way is to write "
+"a function that returns `Option<T>` instead of `T`."
+msgstr ""
+"最後の例の `Option` 型は、Rust のコード中に頻繁に現れます。Rust には null ポ"
+"インタが存在しない (unsafe なコードを除く) ため、引数の組み合わせがとりうるす"
+"べての値に対し結果が定義されないような関数を記述するための別の方法が必要で"
+"す。このような場合には、 `T` 型ではなく `Option<T>` 型を返すよう関数を定義す"
+"ることが一般的です。"
+
+#. type: Plain text
+#: doc/tutorial.md:1804
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# struct Point { x: float, y: float }\n"
+"# enum Shape { Circle(Point, float), Rectangle(Point, Point) }\n"
+"fn radius(shape: Shape) -> Option<float> {\n"
+" match shape {\n"
+" Circle(_, radius) => Some(radius),\n"
+" Rectangle(*) => None\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1812
+msgid ""
+"The Rust compiler compiles generic functions very efficiently by "
+"*monomorphizing* them. *Monomorphization* is a fancy name for a simple idea: "
+"generate a separate copy of each generic function at each call site, a copy "
+"that is specialized to the argument types and can thus be optimized "
+"specifically for them. In this respect, Rust's generics have similar "
+"performance characteristics to C++ templates."
+msgstr ""
+"Rust のコンパイラは、ジェネリック関数を *monomorphizing* することで効率的にコ"
+"ンパイルします。*monomorphization* という名前は大げさに聞こえますが、考え方は"
+"単純です。ジェネリック関数のコピーを関数の呼び出し箇所に別々に生成し、引数の"
+"型により特殊化された各コピーは、それぞれの特性に応じて最適化が施されます。こ"
+"の点において、Rust のジェネリクスは C++ のテンプレートと似たパフォーマンス上"
+"の特性を持ちます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1814
+msgid "## Traits"
+msgstr "## トレイト"
+
+#. type: Plain text
+#: doc/tutorial.md:1824
+msgid ""
+"Within a generic function the operations available on generic types are very "
+"limited. After all, since the function doesn't know what types it is "
+"operating on, it can't safely modify or query their values. This is where "
+"_traits_ come into play. Traits are Rust's most powerful tool for writing "
+"polymorphic code. Java developers will see them as similar to Java "
+"interfaces, and Haskellers will notice their similarities to type classes. "
+"Rust's traits are a form of *bounded polymorphism*: a trait is a way of "
+"limiting the set of possible types that a type parameter could refer to."
+msgstr ""
+"ジェネリック関数の内部では、ジェネリック型に対して非常に限られた操作しか行え"
+"ません。つまるところ、ジェネリック関数は操作の対象とする型が何なのか知らない"
+"ため、対象の値を安全に変更・参照することができません。__トレイト__ (_trait_) "
+"の出番です。トレイトは Rust でポリモーフィックなコードを書くための最も強力な"
+"ツールです。Java 開発者にとってトレイトは Java のインターフェースのように見え"
+"ますし、Haskeller は型クラスとの類似点に気づくでしょう。Rust のトレイトは **"
+"有界ポリモーフィズム** (*bounded polymorphism*) の形式をとります。トレイトに"
+"より、型パラメータが示す得る型の集合を限定することができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1832
+msgid ""
+"As motivation, let us consider copying in Rust. The `clone` method is not "
+"defined for all Rust types. One reason is user-defined destructors: copying "
+"a type that has a destructor could result in the destructor running multiple "
+"times. Therefore, types with destructors cannot be copied unless you "
+"explicitly implement `Clone` for them."
+msgstr ""
+"トレイト導入の動機となる例として、Rust でのコピーについて考えます。`clone` メ"
+"ソッドはすべての Rust の型に対して定義されていません。定義されていない理由の"
+"一つとして、ユーザ定義のデストラクタの存在が挙げられます。デストラクタを持つ"
+"型をコピーすることで、デストラクタが複数回実行されるという事態を招いてしまう"
+"かもしれません。そのため、明示的に `Clone` を実装していない型を除き、デストラ"
+"クタをもつ型をコピーすることはできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:1837
+msgid ""
+"This complicates handling of generic functions. If you have a type "
+"parameter `T`, can you copy values of that type? In Rust, you can't, and if "
+"you try to run the following code the compiler will complain."
+msgstr ""
+"このことはジェネリック関数の扱い方を複雑にします。型パラメータ `T` が存在した"
+"として、この型の値をコピーすることができるでしょうか?Rust では、コピーするこ"
+"とはできません。以下のコードを実行しようとしてもコンパイラが文句を言うでしょ"
+"う。"
+
+#. type: Plain text
+#: doc/tutorial.md:1844
+#, no-wrap
+msgid ""
+"~~~~ {.xfail-test}\n"
+"// This does not compile\n"
+"fn head_bad<T>(v: &[T]) -> T {\n"
+" v[0] // error: copying a non-copyable value\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+"~~~~ {.xfail-test}\n"
+"// このコードはコンパイルできない\n"
+"fn head_bad<T>(v: &[T]) -> T {\n"
+" v[0] // error: copying a non-copyable value\n"
+"}\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1851
+msgid ""
+"However, we can tell the compiler that the `head` function is only for "
+"copyable types: that is, those that implement the `Clone` trait. In that "
+"case, we can explicitly create a second copy of the value we are returning "
+"using the `clone` keyword:"
+msgstr ""
+"`head` 関数はコピー可能な型、つまり `Clone` トレイトを実装している型だけを対"
+"象にしていることをコンパイラに教えることはできます。この場合、`clone` メソッ"
+"ドを使うことで、値のコピーを明示的に作成し、戻り値として返すことができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1858
+#, no-wrap
+msgid ""
+"~~~~\n"
+"// This does\n"
+"fn head<T: Clone>(v: &[T]) -> T {\n"
+" v[0].clone()\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+"~~~~\n"
+"// このコードはコンパイルできる\n"
+"fn head<T: Clone>(v: &[T]) -> T {\n"
+" v[0].clone()\n"
+"}\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1866
+msgid ""
+"This says that we can call `head` on any type `T` as long as that type "
+"implements the `Clone` trait. When instantiating a generic function, you "
+"can only instantiate it with types that implement the correct trait, so you "
+"could not apply `head` to a type that does not implement `Clone`."
+msgstr ""
+"このことは、`Clone` トレイトを実装している任意の型 `T` について、 `head` 関数"
+"を呼び出すことができることを示しています。ジェネリック関数を実体化する場合、"
+"正しいトレイトを実装した型を用いた場合のみ実体化できます。つまり、`Clone` ト"
+"レイトを実装していない型に対して `head` を呼び出すことはできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:1871
+msgid ""
+"While most traits can be defined and implemented by user code, two traits "
+"are automatically derived and implemented for all applicable types by the "
+"compiler, and may not be overridden:"
+msgstr ""
+"ほとんどのトレイトはユーザコードにより定義・実装できますが、2つのトレイトはコ"
+"ンパイラにより自動的に導出され、適用可能なすべての型に対し自動的に実装され、"
+"上書きすることはできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:1875
+#, no-wrap
+msgid ""
+"* `Send` - Sendable types.\n"
+"Types are sendable\n"
+"unless they contain managed boxes, managed closures, or borrowed pointers.\n"
+msgstr ""
+"* `Send` - 送信可能な型。\n"
+"マネージドボックスやマネージドクロージャ、借用ポインタを含まない場合、型は送信可能である。"
+
+#. type: Plain text
+#: doc/tutorial.md:1880
+#, no-wrap
+msgid ""
+"* `Freeze` - Constant (immutable) types.\n"
+"These are types that do not contain anything intrinsically mutable.\n"
+"Intrinsically mutable values include `@mut`\n"
+"and `Cell` in the standard library.\n"
+msgstr ""
+"* `Freeze` - 定数 (イミュータブル) 型。\n"
+"本質的に変更可能な値を含まない型のことです。本質的に変更可能な値には、`@mut` や標準ライブラリで定義されている `Cell` が含まれます。\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1883
+msgid ""
+"> ***Note:*** These two traits were referred to as 'kinds' in earlier > "
+"iterations of the language, and often still are."
+msgstr ""
+"> ***注意*** これら2つのトレイトは、以前は 「種」 (kind) と呼ばれており、現在"
+"でもそう呼ばれる場合があります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1889
+msgid ""
+"Additionally, the `Drop` trait is used to define destructors. This trait "
+"defines one method called `drop`, which is automatically called when a value "
+"of the type that implements this trait is destroyed, either because the "
+"value went out of scope or because the garbage collector reclaimed it."
+msgstr ""
+"上記に加え、 `Drop` トレイトはデストラクタを定義するために使われます。このト"
+"レイトは `drop` というこのトレイトを実装した型が破壊されるタイミング(値がス"
+"コープの外に出たタイミングか、ガベージコレクタが回収するタイミング) で呼び出"
+"されるメソッドを1つ定義しています。"
+
+#. type: Plain text
+#: doc/tutorial.md:1894
+#, no-wrap
+msgid ""
+"~~~\n"
+"struct TimeBomb {\n"
+" explosivity: uint\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1903
+#, no-wrap
+msgid ""
+"impl Drop for TimeBomb {\n"
+" fn drop(&self) {\n"
+" for _ in range(0, self.explosivity) {\n"
+" println(\"blam!\");\n"
+" }\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1906
+msgid ""
+"It is illegal to call `drop` directly. Only code inserted by the compiler "
+"may call it."
+msgstr ""
+"`drop` を直接呼び出すことはできません。コンパイラにより挿入されたコードのみ"
+"が `drop` を呼び出すことができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1908
+msgid "## Declaring and implementing traits"
+msgstr "## トレイトの宣言と実装"
+
+#. type: Plain text
+#: doc/tutorial.md:1914
+msgid ""
+"A trait consists of a set of methods without bodies, or may be empty, as is "
+"the case with `Send` and `Freeze`. For example, we could declare the trait "
+"`Printable` for things that can be printed to the console, with a single "
+"method:"
+msgstr ""
+"トレイトはボディを持たないメソッドの集合から構成されるか、 `Send` や "
+"`Freeze` トレイトのように空の場合があります。例えば、コンソールに出力可能なも"
+"のを表しメソッドを1つもつ `Printable` トレイトは以下のように宣言できます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1920
+#, no-wrap
+msgid ""
+"~~~~\n"
+"trait Printable {\n"
+" fn print(&self);\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1925
+msgid ""
+"Traits may be implemented for specific types with [impls]. An impl that "
+"implements a trait includes the name of the trait at the start of the "
+"definition, as in the following impls of `Printable` for `int` and `~str`."
+msgstr ""
+"[impl][impls] により特定の型にトレイトを実装することができます。トレイトを実"
+"装する impl は、以下の `Printable` の `int` と `~str` に対する実装のように、"
+"定義の先頭にトレイトの名前を含みます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1927
+msgid "[impls]: #methods"
+msgstr "[impls]: #メソッド"
+
+#. type: Plain text
+#: doc/tutorial.md:1933
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# trait Printable { fn print(&self); }\n"
+"impl Printable for int {\n"
+" fn print(&self) { println(fmt!(\"%d\", *self)) }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1937
+#, no-wrap
+msgid ""
+"impl Printable for ~str {\n"
+" fn print(&self) { println(*self) }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1941
+msgid "# 1.print(); # (~\"foo\").print(); ~~~~"
+msgstr ""
+"# 1.print();\n"
+"# (~\"foo\").print();\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:1946
+msgid ""
+"Methods defined in an implementation of a trait may be called just like any "
+"other method, using dot notation, as in `1.print()`. Traits may themselves "
+"contain type parameters. A trait for generalized sequence types might look "
+"like the following:"
+msgstr ""
+"トレイトの実装により定義されたメソッドは他のメソッドと全く同じように、ドット"
+"記法を用いて `1.print()` のように呼び出せます。トレイト自体に型パラメータを持"
+"たせることもできます。一般化されたシーケンスを表すトレイトは以下のように定義"
+"されるでしょう。"
+
+#. type: Plain text
+#: doc/tutorial.md:1951
+#, no-wrap
+msgid ""
+"~~~~\n"
+"trait Seq<T> {\n"
+" fn length(&self) -> uint;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1956
+#, no-wrap
+msgid ""
+"impl<T> Seq<T> for ~[T] {\n"
+" fn length(&self) -> uint { self.len() }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:1963
+msgid ""
+"The implementation has to explicitly declare the type parameter that it "
+"binds, `T`, before using it to specify its trait type. Rust requires this "
+"declaration because the `impl` could also, for example, specify an "
+"implementation of `Seq<int>`. The trait type (appearing between `impl` and "
+"`for`) *refers* to a type, rather than defining one."
+msgstr ""
+"実装が束縛する型パラメータ `T` は、トレイトの型を指定する前に明示的に宣言しな"
+"ければなりません。Rust でこの宣言が必要なのは、 `impl` では例えば `Seq<int>` "
+"の実装を指定することも可能だからです。トレイトの型 (`impl` と `for` の間に現"
+"れるもの) は、型を定義するのではなく、型を **参照** します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1968
+msgid ""
+"The type parameters bound by a trait are in scope in each of the method "
+"declarations. So, re-declaring the type parameter `T` as an explicit type "
+"parameter for `len`, in either the trait or the impl, would be a compile-"
+"time error."
+msgstr ""
+"トレイトにより束縛される型パラメータは、各メソッドの宣言のスコープに属しま"
+"す。したがって、trait と impl のいずれかで、型パラメータ `T` を `len` で用い"
+"る明示的な型パラメータとして再宣言すると、コンパイル時エラーとなります。"
+
+#. type: Plain text
+#: doc/tutorial.md:1973
+msgid ""
+"Within a trait definition, `Self` is a special type that you can think of as "
+"a type parameter. An implementation of the trait for any given type `T` "
+"replaces the `Self` type parameter with `T`. The following trait describes "
+"types that support an equality operation:"
+msgstr ""
+"トレイトの定義内部では、`Self` は型パラメータとみなすことのできる特別な型とな"
+"ります。型 `T` に対するトレイトの実装では `Self` は型パラメータ `T` で置き換"
+"えられます。以下のトレイトは等価性演算をサポートする型を意味します。"
+
+#. type: Plain text
+#: doc/tutorial.md:1980
+#, no-wrap
+msgid ""
+"~~~~\n"
+"// In a trait, `self` refers to the self argument.\n"
+"// `Self` refers to the type implementing the trait.\n"
+"trait Eq {\n"
+" fn equals(&self, other: &Self) -> bool;\n"
+"}\n"
+msgstr ""
+"~~~~\n"
+"// trait の内側では, `self` は self 引数を指します。\n"
+"// `Self` はトレイトを実装する型を指します。\n"
+"trait Eq {\n"
+" fn equals(&self, other: &Self) -> bool;\n"
+"}\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1986
+#, no-wrap
+msgid ""
+"// In an impl, `self` refers just to the value of the receiver\n"
+"impl Eq for int {\n"
+" fn equals(&self, other: &int) -> bool { *other == *self }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+"// impl の内側では `self` はレシーバの値を指します\n"
+"impl Eq for int {\n"
+" fn equals(&self, other: &int) -> bool { *other == *self }\n"
+"}\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:1991
+msgid ""
+"Notice that in the trait definition, `equals` takes a second parameter of "
+"type `Self`. In contrast, in the `impl`, `equals` takes a second parameter "
+"of type `int`, only using `self` as the name of the receiver."
+msgstr ""
+"トレイトの定義では、`equals` の第二引数の型は `Self` であることに注意してくだ"
+"さい。対照的に `impl` では、 `equals` の第二引数の型は `int` で、 `self` はレ"
+"シーバの名前としてのみ使用されます。"
+
+#. type: Plain text
+#: doc/tutorial.md:1996
+msgid ""
+"Just as in type implementations, traits can define standalone (static) "
+"methods. These methods are called by prefixing the method name with the "
+"trait name and a double colon. The compiler uses type inference to decide "
+"which implementation to use."
+msgstr ""
+"型への実装の場合と同様、トレイトもスタンドアロン (静的) メソッドを定義するこ"
+"とができます。メソッド名の前にトレイト名とコロン2つをつけることで、これらのメ"
+"ソッドを呼び出すことができます。コンパイラはどの実装を利用するか決定するた"
+"め、型推論を行います。"
+
+#. type: Plain text
+#: doc/tutorial.md:2002
+msgid ""
+"~~~~ use std::float::consts::pi; trait Shape { fn new(area: float) -> "
+"Self; } struct Circle { radius: float } struct Square { length: float }"
+msgstr ""
+"~~~~\n"
+"use std::float::consts::pi;\n"
+"trait Shape { fn new(area: float) -> Self; }\n"
+"struct Circle { radius: float }\n"
+"struct Square { length: float }"
+
+#. type: Plain text
+#: doc/tutorial.md:2009
+#, no-wrap
+msgid ""
+"impl Shape for Circle {\n"
+" fn new(area: float) -> Circle { Circle { radius: (area / pi).sqrt() } }\n"
+"}\n"
+"impl Shape for Square {\n"
+" fn new(area: float) -> Square { Square { length: (area).sqrt() } }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2014
+msgid ""
+"let area = 42.5; let c: Circle = Shape::new(area); let s: Square = Shape::"
+"new(area); ~~~~"
+msgstr ""
+"let area = 42.5;\n"
+"let c: Circle = Shape::new(area);\n"
+"let s: Square = Shape::new(area);\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2016
+msgid "## Bounded type parameters and static method dispatch"
+msgstr "## 境界型パラメータと静的メソッドディスパッチ"
+
+#. type: Plain text
+#: doc/tutorial.md:2021
+msgid ""
+"Traits give us a language for defining predicates on types, or abstract "
+"properties that types can have. We can use this language to define _bounds_ "
+"on type parameters, so that we can then operate on generic types."
+msgstr ""
+"トレイトは型の述語 (predicate) や型がもつことのできる抽象的な属性を定義するた"
+"めの言語として利用することができます。この言語を使うこととで型パラメータの __"
+"境界__ (_bound_) を定義することができ、ジェネリックな型を操作することが可能に"
+"なります。"
+
+#. type: Plain text
+#: doc/tutorial.md:2030
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# trait Printable { fn print(&self); }\n"
+"fn print_all<T: Printable>(printable_things: ~[T]) {\n"
+" for thing in printable_things.iter() {\n"
+" thing.print();\n"
+" }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2036
+msgid ""
+"Declaring `T` as conforming to the `Printable` trait (as we earlier did with "
+"`Clone`) makes it possible to call methods from that trait on values of type "
+"`T` inside the function. It will also cause a compile-time error when anyone "
+"tries to call `print_all` on an array whose element type does not have a "
+"`Printable` implementation."
+msgstr ""
+"(先に登場した `Clone` の例のように) `T` が `Printable` トレイトに従うことを宣"
+"言することで、関数内部で `T` 型の値に対して `Printable` トレイトのメソッドを"
+"呼び出すことが可能になります。また、この宣言により、`Printable` を実装してい"
+"ない型を要素とする配列に対して `print_all` 関数を呼びだそうとすると、コンパイ"
+"ル時エラーとなります。"
+
+#. type: Plain text
+#: doc/tutorial.md:2039
+msgid ""
+"Type parameters can have multiple bounds by separating them with `+`, as in "
+"this version of `print_all` that copies elements."
+msgstr ""
+"型パラメータは `+` で区切ることで複数の境界を持つことができます。以下の "
+"`print_all` は、ベクタの要素をコピーするバージョンです。"
+
+#. type: Plain text
+#: doc/tutorial.md:2051
+#, no-wrap
+msgid ""
+"~~~\n"
+"# trait Printable { fn print(&self); }\n"
+"fn print_all<T: Printable + Clone>(printable_things: ~[T]) {\n"
+" let mut i = 0;\n"
+" while i < printable_things.len() {\n"
+" let copy_of_thing = printable_things[i].clone();\n"
+" copy_of_thing.print();\n"
+" i += 1;\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2055
+msgid ""
+"Method calls to bounded type parameters are _statically dispatched_, "
+"imposing no more overhead than normal function invocation, so are the "
+"preferred way to use traits polymorphically."
+msgstr ""
+"境界型パラメータに対するメソッドの呼び出しは __静的にディスパッチ__ "
+"(_statically dispatched_) されるため、通常の関数呼び出し以上のオーバーヘッド"
+"は発生しません。そのため、ポリモーフィックにトレイトを使う方法としては、境界"
+"型パラメータが推奨されます。 "
+
+#. type: Plain text
+#: doc/tutorial.md:2057
+msgid "This usage of traits is similar to Haskell type classes."
+msgstr "トレイトのこのような使い方は、Haskell の型クラスと似ています。"
+
+#. type: Plain text
+#: doc/tutorial.md:2059
+msgid "## Trait objects and dynamic method dispatch"
+msgstr "## トレイトオブジェクトと動的メソッドディスパッチ"
+
+#. type: Plain text
+#: doc/tutorial.md:2063
+msgid ""
+"The above allows us to define functions that polymorphically act on values "
+"of a single unknown type that conforms to a given trait. However, consider "
+"this function:"
+msgstr ""
+"上述の例では、指定されたトレイトに従う、単一の未知の型の値についてポリモー"
+"フィックにふるまう関数を定義しました。ここでは、以下の関数について考えます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2069
+msgid ""
+"~~~~ # type Circle = int; type Rectangle = int; # impl Drawable for int { fn "
+"draw(&self) {} } # fn new_circle() -> int { 1 } trait Drawable { fn "
+"draw(&self); }"
+msgstr ""
+"~~~~\n"
+"# type Circle = int; type Rectangle = int;\n"
+"# impl Drawable for int { fn draw(&self) {} }\n"
+"# fn new_circle() -> int { 1 }\n"
+"trait Drawable { fn draw(&self); }"
+
+#. type: Plain text
+#: doc/tutorial.md:2076
+#, no-wrap
+msgid ""
+"fn draw_all<T: Drawable>(shapes: ~[T]) {\n"
+" for shape in shapes.iter() { shape.draw(); }\n"
+"}\n"
+"# let c: Circle = new_circle();\n"
+"# draw_all(~[c]);\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2082
+msgid ""
+"You can call that on an array of circles, or an array of rectangles "
+"(assuming those have suitable `Drawable` traits defined), but not on an "
+"array containing both circles and rectangles. When such behavior is needed, "
+"a trait name can alternately be used as a type, called an _object_."
+msgstr ""
+"円の配列や長方形の配列に対してこの関数を呼び出すことは (円や長方形に対し適切"
+"に `Drawable` トレイトが定義されていると仮定すれば) 可能ですが、円や長方形を"
+"両方共含む配列に対しては呼び出すことができません。そのような動作が必要な場"
+"合、__オブジェクト__ 型として、トレイトの名前を代わりに利用することができま"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:2089
+#, no-wrap
+msgid ""
+"~~~~\n"
+"# trait Drawable { fn draw(&self); }\n"
+"fn draw_all(shapes: &[@Drawable]) {\n"
+" for shape in shapes.iter() { shape.draw(); }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2094
+msgid ""
+"In this example, there is no type parameter. Instead, the `@Drawable` type "
+"denotes any managed box value that implements the `Drawable` trait. To "
+"construct such a value, you use the `as` operator to cast a value to an "
+"object:"
+msgstr ""
+"この例中には、型パラメータはありません。代わりに、「`Drawable` トレイトを実装"
+"した、任意のマネージドボックス値」を表す型 `@Drawable` 型があります。このよ"
+"うな値を作成するには、 `as` 演算子を使って値をオブジェクトへキャストします。"
+
+#. type: Plain text
+#: doc/tutorial.md:2101
+msgid ""
+"~~~~ # type Circle = int; type Rectangle = bool; # trait Drawable { fn "
+"draw(&self); } # fn new_circle() -> Circle { 1 } # fn new_rectangle() -> "
+"Rectangle { true } # fn draw_all(shapes: &[@Drawable]) {}"
+msgstr ""
+"~~~~\n"
+"# type Circle = int; type Rectangle = bool;\n"
+"# trait Drawable { fn draw(&self); }\n"
+"# fn new_circle() -> Circle { 1 }\n"
+"# fn new_rectangle() -> Rectangle { true }\n"
+"# fn draw_all(shapes: &[@Drawable]) {}"
+
+#. type: Plain text
+#: doc/tutorial.md:2104
+msgid ""
+"impl Drawable for Circle { fn draw(&self) { ... } } impl Drawable for "
+"Rectangle { fn draw(&self) { ... } }"
+msgstr ""
+"impl Drawable for Circle { fn draw(&self) { ... } }\n"
+"impl Drawable for Rectangle { fn draw(&self) { ... } }"
+
+#. type: Plain text
+#: doc/tutorial.md:2109
+msgid ""
+"let c: @Circle = @new_circle(); let r: @Rectangle = @new_rectangle(); "
+"draw_all([c as @Drawable, r as @Drawable]); ~~~~"
+msgstr ""
+"let c: @Circle = @new_circle();\n"
+"let r: @Rectangle = @new_rectangle();\n"
+"draw_all([c as @Drawable, r as @Drawable]);\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2117
+msgid ""
+"We omit the code for `new_circle` and `new_rectangle`; imagine that these "
+"just return `Circle`s and `Rectangle`s with a default size. Note that, like "
+"strings and vectors, objects have dynamic size and may only be referred to "
+"via one of the pointer types. Other pointer types work as well. Casts to "
+"traits may only be done with compatible pointers so, for example, an "
+"`@Circle` may not be cast to an `~Drawable`."
+msgstr ""
+"`new_circle` と `new_rectangle` のコードは省略されていますが、デフォルトのサ"
+"イズをもつ `Circle` と `Rectangle` をただ返すものだと考えてください。文字列や"
+"ベクタのように、オブジェクトも動的なサイズを持ち、いずれかのポインタ型を経由"
+"してしか参照できないことに注意してください。他のポインタ型でもうまく動作しま"
+"す。トレイトへのキャストは互換性のあるポインタの場合しか行えません。例えば、"
+"`@Cicle` を `~Drawable` にキャストすることはできません。"
+
+#. type: Plain text
+#: doc/tutorial.md:2131
+msgid ""
+"~~~ # type Circle = int; type Rectangle = int; # trait Drawable { fn "
+"draw(&self); } # impl Drawable for int { fn draw(&self) {} } # fn "
+"new_circle() -> int { 1 } # fn new_rectangle() -> int { 2 } // A managed "
+"object let boxy: @Drawable = @new_circle() as @Drawable; // An owned object "
+"let owny: ~Drawable = ~new_circle() as ~Drawable; // A borrowed object let "
+"stacky: &Drawable = &new_circle() as &Drawable; ~~~"
+msgstr ""
+"~~~\n"
+"# type Circle = int; type Rectangle = int;\n"
+"# trait Drawable { fn draw(&self); }\n"
+"# impl Drawable for int { fn draw(&self) {} }\n"
+"# fn new_circle() -> int { 1 }\n"
+"# fn new_rectangle() -> int { 2 }\n"
+"// A managed object\n"
+"let boxy: @Drawable = @new_circle() as @Drawable;\n"
+"// An owned object\n"
+"let owny: ~Drawable = ~new_circle() as ~Drawable;\n"
+"// A borrowed object\n"
+"let stacky: &Drawable = &new_circle() as &Drawable;\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2136
+msgid ""
+"Method calls to trait types are _dynamically dispatched_. Since the compiler "
+"doesn't know specifically which functions to call at compile time, it uses a "
+"lookup table (also known as a vtable or dictionary) to select the method to "
+"call at runtime."
+msgstr ""
+"トレイト型のメソッド呼び出しは __動的にディスパッチ__ (_dynamically "
+"dispatched_) されます。どの関数を呼び出すべきかコンパイル時にはわからないた"
+"め、ルックアップテーブル (vtable や dictionary としても知られている) を用い"
+"て、呼び出すメソッドの選択を実行時に行います。"
+
+#. type: Plain text
+#: doc/tutorial.md:2138
+msgid "This usage of traits is similar to Java interfaces."
+msgstr "トレイトのこのような使い方は、Java のインターフェースと似ています。"
+
+#. type: Plain text
+#: doc/tutorial.md:2140
+msgid "## Trait inheritance"
+msgstr "## トレイトの継承"
+
+#. type: Plain text
+#: doc/tutorial.md:2145
+msgid ""
+"We can write a trait declaration that _inherits_ from other traits, called "
+"_supertraits_. Types that implement a trait must also implement its "
+"supertraits. For example, we can define a `Circle` trait that inherits from "
+"`Shape`."
+msgstr ""
+"__スーパートレイト__ と呼ばれる他のトレイトから __継承した__ トレイトを宣言す"
+"ることができます。継承されたトレイトを実装する型は、スーパートレイトも実装し"
+"なければなりません。例えば、 `Circle` トレイトを `Shape` トレイトを継承したも"
+"のとして定義できます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2150
+msgid ""
+"~~~~ trait Shape { fn area(&self) -> float; } trait Circle : Shape { fn "
+"radius(&self) -> float; } ~~~~"
+msgstr ""
+"~~~~\n"
+"trait Shape { fn area(&self) -> float; }\n"
+"trait Circle : Shape { fn radius(&self) -> float; }\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2152
+msgid ""
+"Now, we can implement `Circle` on a type only if we also implement `Shape`."
+msgstr "`Circle` トレイトの実装は、 `Shape` を実装した型についてのみ行えます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2167
+#, no-wrap
+msgid ""
+"~~~~\n"
+"use std::float::consts::pi;\n"
+"# trait Shape { fn area(&self) -> float; }\n"
+"# trait Circle : Shape { fn radius(&self) -> float; }\n"
+"# struct Point { x: float, y: float }\n"
+"# fn square(x: float) -> float { x * x }\n"
+"struct CircleStruct { center: Point, radius: float }\n"
+"impl Circle for CircleStruct {\n"
+" fn radius(&self) -> float { (self.area() / pi).sqrt() }\n"
+"}\n"
+"impl Shape for CircleStruct {\n"
+" fn area(&self) -> float { pi * square(self.radius) }\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2172
+msgid ""
+"Notice that methods of `Circle` can call methods on `Shape`, as our `radius` "
+"implementation calls the `area` method. This is a silly way to compute the "
+"radius of a circle (since we could just return the `radius` field), but you "
+"get the idea."
+msgstr ""
+"`radius` の実装から `area` メソッドを呼び出せるように、`Circle` のメソッドは "
+"`Shape` のメソッドを呼び出せることに注意してください。(単純に `radius` フィー"
+"ルドの値を返すことができるにも関わらず) 円の半径を面積から計算するのは馬鹿げ"
+"ていますが、メソッド呼び出しの考え方は分かったでしょう。"
+
+#. type: Plain text
+#: doc/tutorial.md:2196
+msgid ""
+"~~~ {.xfail-test} use std::float::consts::pi; # trait Shape { fn area(&self) "
+"-> float; } # trait Circle : Shape { fn radius(&self) -> float; } # struct "
+"Point { x: float, y: float } # struct CircleStruct { center: Point, radius: "
+"float } # impl Circle for CircleStruct { fn radius(&self) -> float { (self."
+"area() / pi).sqrt() } } # impl Shape for CircleStruct { fn area(&self) -> "
+"float { pi * square(self.radius) } }"
+msgstr ""
+"~~~ {.xfail-test}\n"
+"use std::float::consts::pi;\n"
+"# trait Shape { fn area(&self) -> float; }\n"
+"# trait Circle : Shape { fn radius(&self) -> float; }\n"
+"# struct Point { x: float, y: float }\n"
+"# struct CircleStruct { center: Point, radius: float }\n"
+"# impl Circle for CircleStruct { fn radius(&self) -> float { (self.area() / "
+"pi).sqrt() } }\n"
+"# impl Shape for CircleStruct { fn area(&self) -> float { pi * square(self."
+"radius) } }"
+
+#. type: Plain text
+#: doc/tutorial.md:2201
+msgid ""
+"let concrete = @CircleStruct{center:Point{x:3f,y:4f},radius:5f}; let "
+"mycircle: @Circle = concrete as @Circle; let nonsense = mycircle.radius() * "
+"mycircle.area(); ~~~"
+msgstr ""
+"let concrete = @CircleStruct{center:Point{x:3f,y:4f},radius:5f};\n"
+"let mycircle: @Circle = concrete as @Circle;\n"
+"let nonsense = mycircle.radius() * mycircle.area();\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2203
+msgid "> ***Note:*** Trait inheritance does not actually work with objects yet"
+msgstr ""
+"> ***注意*** トレイトの継承は、実際にはまだオブジェクトに対しては動作しませ"
+"ん。"
+
+#. type: Plain text
+#: doc/tutorial.md:2205
+msgid "## Deriving implementations for traits"
+msgstr "## トレイトの実装の導出"
+
+#. type: Plain text
+#: doc/tutorial.md:2212
+msgid ""
+"A small number of traits in `std` and `extra` can have implementations that "
+"can be automatically derived. These instances are specified by placing the "
+"`deriving` attribute on a data type declaration. For example, the following "
+"will mean that `Circle` has an implementation for `Eq` and can be used with "
+"the equality operators, and that a value of type `ABC` can be randomly "
+"generated and converted to a string:"
+msgstr ""
+"`std` と `extra` で定義されているいくつかのトレイトは、自動的に実装を導出可能"
+"です。データ型の宣言時に `deriving` 属性を書くことで、これらのトレイトを実装"
+"することを指定します。例えば、以下の例では `Circle` は `Eq` を実装し等価演算"
+"子で比較することが可能であり、`ABC` 型の値はランダムに生成することや、文字列"
+"に変換することが可能です。"
+
+#. type: Plain text
+#: doc/tutorial.md:2216
+msgid "~~~ #[deriving(Eq)] struct Circle { radius: float }"
+msgstr ""
+"~~~\n"
+"#[deriving(Eq)]\n"
+"struct Circle { radius: float }"
+
+#. type: Plain text
+#: doc/tutorial.md:2220
+msgid "#[deriving(Rand, ToStr)] enum ABC { A, B, C } ~~~"
+msgstr ""
+"#[deriving(Rand, ToStr)]\n"
+"enum ABC { A, B, C }\n"
+"~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2224
+msgid ""
+"The full list of derivable traits is `Eq`, `TotalEq`, `Ord`, `TotalOrd`, "
+"`Encodable` `Decodable`, `Clone`, `DeepClone`, `IterBytes`, `Rand`, `Zero`, "
+"and `ToStr`."
+msgstr ""
+"実装を自動的に導出可能なトレイトは、 `Eq`, `TotalEq`, `Ord`, `TotalOrd`, "
+"`Encodable` `Decodable`, `Clone`, `DeepClone`, `IterBytes`, `Rand`, `Zero`, "
+"および `ToStr` です。."
+
+#. type: Plain text
+#: doc/tutorial.md:2226
+msgid "# Modules and crates"
+msgstr "# モジュールとクレート"
+
+#. type: Plain text
+#: doc/tutorial.md:2230
+msgid ""
+"The Rust namespace is arranged in a hierarchy of modules. Each source (.rs) "
+"file represents a single module and may in turn contain additional modules."
+msgstr ""
+"Rust の名前空間はモジュールの階層に配置されている。それぞれのソース (.rs) "
+"ファイルは単一のモジュールを表し、追加のモジュールを含んでいる場合もある。"
+
+#. type: Plain text
+#: doc/tutorial.md:2236
+#, no-wrap
+msgid ""
+"~~~~\n"
+"mod farm {\n"
+" pub fn chicken() -> &str { \"cluck cluck\" }\n"
+" pub fn cow() -> &str { \"mooo\" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2241
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" println(farm::chicken());\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2246
+msgid ""
+"The contents of modules can be imported into the current scope with the "
+"`use` keyword, optionally giving it an alias. `use` may appear at the "
+"beginning of crates, `mod`s, `fn`s, and other blocks."
+msgstr ""
+"でモジュールの内容は`use` キーワードにより現在のスコープにインポートすること"
+"ができます。必要に応じて別名を付けることもできます。`use` はクレートの先頭や "
+"`mod`, `fn` などのブロックの先頭に記述することができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2252
+msgid ""
+"~~~ # mod farm { pub fn chicken() { } } # fn main() { // Bring `chicken` "
+"into scope use farm::chicken;"
+msgstr ""
+"~~~\n"
+"# mod farm { pub fn chicken() { } }\n"
+"# fn main() {\n"
+"// `chicken` を現在のスコープに持ち込む\n"
+"use farm::chicken;"
+
+#. type: Plain text
+#: doc/tutorial.md:2262
+#, no-wrap
+msgid ""
+"fn chicken_farmer() {\n"
+" // The same, but name it `my_chicken`\n"
+" use my_chicken = farm::chicken;\n"
+" ...\n"
+"# my_chicken();\n"
+"}\n"
+"# chicken();\n"
+"# }\n"
+"~~~\n"
+msgstr ""
+"fn chicken_farmer() {\n"
+" // 同じことをするが、名前を `my_chicken` とする\n"
+" use my_chicken = farm::chicken;\n"
+" ...\n"
+"# my_chicken();\n"
+"}\n"
+"# chicken();\n"
+"# }\n"
+"~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:2269
+msgid ""
+"These farm animal functions have a new keyword, `pub`, attached to them. The "
+"`pub` keyword modifies an item's visibility, making it visible outside its "
+"containing module. An expression with `::`, like `farm::chicken`, can name "
+"an item outside of its containing module. Items, such as those declared with "
+"`fn`, `struct`, `enum`, `type`, or `static`, are module-private by default."
+msgstr ""
+"farm モジュールの動物の関数定義には、 `pub` という新しいキーワードが付けられ"
+"ています。`pub` キーワードは項目の可視性を変更し、項目を含んでいるモジュール"
+"の外側から見えるようにします。`farm::chicken` のような、 `::` を含む式は、式"
+"を含むモジュールの外側の項目を指定することができます。`fn` や `struct`, "
+"`enum`, `type`, `static` により宣言される項目の可視性は、デフォルトではモ"
+"ジュールプライベート (同一モジュール内からのみ参照可能)です。"
+
+#. type: Plain text
+#: doc/tutorial.md:2276
+msgid ""
+"Visibility restrictions in Rust exist only at module boundaries. This is "
+"quite different from most object-oriented languages that also enforce "
+"restrictions on objects themselves. That's not to say that Rust doesn't "
+"support encapsulation: both struct fields and methods can be private. But "
+"this encapsulation is at the module level, not the struct level. Note that "
+"fields and methods are _public_ by default."
+msgstr ""
+"Rust での可視性の制約はモジュールの境界にのみ存在します。これは、オブジェクト"
+"自体にも可視性の制約を課すほとんどのオブジェクト指向言語とは全く異なっていま"
+"す。しかし、Rust がカプセル化をサポートしていないというわけではありません。構"
+"造体のフィールドとメソッドはプライベートにすることができます。しかし、このカ"
+"プセル化はモジュールレベルで働くもので、構造体のレベルで働くものではありませ"
+"ん。フィールドとメソッドでは、デフォルトでは __パブリック__ であることに注意"
+"してください。"
+
+#. type: Plain text
+#: doc/tutorial.md:2289
+#, no-wrap
+msgid ""
+"~~~\n"
+"pub mod farm {\n"
+"# pub type Chicken = int;\n"
+"# type Cow = int;\n"
+"# struct Human(int);\n"
+"# impl Human { fn rest(&self) { } }\n"
+"# pub fn make_me_a_farm() -> Farm { Farm { chickens: ~[], cows: ~[], farmer: Human(0) } }\n"
+" pub struct Farm {\n"
+" priv chickens: ~[Chicken],\n"
+" priv cows: ~[Cow],\n"
+" farmer: Human\n"
+" }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2295
+#, no-wrap
+msgid ""
+" impl Farm {\n"
+" fn feed_chickens(&self) { ... }\n"
+" fn feed_cows(&self) { ... }\n"
+" pub fn add_chicken(&self, c: Chicken) { ... }\n"
+" }\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2301
+#, no-wrap
+msgid ""
+" pub fn feed_animals(farm: &Farm) {\n"
+" farm.feed_chickens();\n"
+" farm.feed_cows();\n"
+" }\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2311
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" let f = make_me_a_farm();\n"
+" f.add_chicken(make_me_a_chicken());\n"
+" farm::feed_animals(&f);\n"
+" f.farmer.rest();\n"
+"}\n"
+"# fn make_me_a_farm() -> farm::Farm { farm::make_me_a_farm() }\n"
+"# fn make_me_a_chicken() -> farm::Chicken { 0 }\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2313
+msgid "## Crates"
+msgstr "## クレート"
+
+#. type: Plain text
+#: doc/tutorial.md:2317
+msgid ""
+"The unit of independent compilation in Rust is the crate: rustc compiles a "
+"single crate at a time, from which it produces either a library or an "
+"executable."
+msgstr ""
+"Rust の独立コンパイルの単位はクレートです。rustc は1度に1つのクレートをコンパ"
+"イルし、ライブラリか実行可能ファイルを生成します。"
+
+#. type: Plain text
+#: doc/tutorial.md:2322
+msgid ""
+"When compiling a single `.rs` source file, the file acts as the whole "
+"crate. You can compile it with the `--lib` compiler switch to create a "
+"shared library, or without, provided that your file contains a `fn main` "
+"somewhere, to create an executable."
+msgstr ""
+"単一の `.rs` ファイルをコンパイルする場合、1つのファイルがクレート全体として"
+"振る舞います。`--lib` コンパイラスイッチを与えてコンパイルすることで、共有ラ"
+"イブラリを生成することができます。コンパイラスイッチを与えず、 `fn main` が"
+"ファイルのどこかに含まれていれば、実行可能ファイルを生成することができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2327
+msgid ""
+"Larger crates typically span multiple files and are, by convention, compiled "
+"from a source file with the `.rc` extension, called a *crate file*. The "
+"crate file extension distinguishes source files that represent crates from "
+"those that do not, but otherwise source files and crate files are identical."
+msgstr ""
+"大きなクレートは普通複数のファイルから構成され、慣習的に、 `.rc` という拡張子"
+"をもつ、 **クレートファイル** と呼ばれるファイルからコンパイルされます。ク"
+"レートファイルの拡張子はクレートを表すソースファイルを他のものと区別するため"
+"だけのもので、それ以外の店でクレートファイルとソースファイルに違いはありませ"
+"ん。"
+
+#. type: Plain text
+#: doc/tutorial.md:2336
+msgid ""
+"A typical crate file declares attributes associated with the crate that may "
+"affect how the compiler processes the source. Crate attributes specify "
+"metadata used for locating and linking crates, the type of crate (library or "
+"executable), and control warning and error behavior, among other things. "
+"Crate files additionally declare the external crates they depend on as well "
+"as any modules loaded from other files."
+msgstr ""
+"典型的なクレートファイルでは、コンパイラのソースコード処理法に影響を与える、"
+"クレートに紐付けられた属性を宣言します。クレートの属性は、クレートの配置やリ"
+"ンクに使われたり、クレートの種類 (ライブラリか実行ファイルか) を指定したり、"
+"警告やエラーの挙動を制御したりするためのメタデータを指定します。クレートファ"
+"イルは、クレートが依存する外部のクレートや、他のファイルから読み込むモジュー"
+"ルについても宣言します。"
+
+#. type: Plain text
+#: doc/tutorial.md:2340
+msgid ""
+"~~~~ { .xfail-test } // Crate linkage metadata #[link(name = \"farm\", vers "
+"= \"2.5\", author = \"mjh\")];"
+msgstr ""
+"~~~~ { .xfail-test }\n"
+"// クレートのリンケージに関するメタデータ\n"
+"#[link(name = \"farm\", vers = \"2.5\", author = \"mjh\")];"
+
+#. type: Plain text
+#: doc/tutorial.md:2343
+msgid "// Make a library (\"bin\" is the default) #[crate_type = \"lib\"];"
+msgstr ""
+"// ライブラリを作成する (\"bin\" がデフォルト値)\n"
+"#[crate_type = \"lib\"];"
+
+#. type: Plain text
+#: doc/tutorial.md:2346
+msgid "// Turn on a warning #[warn(non_camel_case_types)]"
+msgstr ""
+"// 警告を有効にする\n"
+"#[warn(non_camel_case_types)]"
+
+#. type: Plain text
+#: doc/tutorial.md:2349
+msgid "// Link to the standard library extern mod std;"
+msgstr ""
+"// 標準ライブラリをリンクする\n"
+"extern mod std;"
+
+#. type: Plain text
+#: doc/tutorial.md:2354
+msgid "// Load some modules from other files mod cow; mod chicken; mod horse;"
+msgstr ""
+"// 他のファイルからいくつかのモジュールを読み込む\n"
+"mod cow;\n"
+"mod chicken;\n"
+"mod horse;"
+
+#. type: Plain text
+#: doc/tutorial.md:2359
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" ...\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2366
+msgid ""
+"Compiling this file will cause `rustc` to look for files named `cow.rs`, "
+"`chicken.rs`, and `horse.rs` in the same directory as the `.rc` file, "
+"compile them all together, and, based on the presence of the `crate_type = "
+"\"lib\"` attribute, output a shared library or an executable. (If the line "
+"`#[crate_type = \"lib\"];` was omitted, `rustc` would create an executable.)"
+msgstr ""
+"このファイルをコンパイルすると、 `rustc` は `.rc` ファイルと同じディレクトリ"
+"の `cow.rs` と `chicken.rs`、 `horse.rs` を探し、すべてのファイルを同時にコン"
+"パイルし、`craete_type = \"lib\"` という属性の有無に応じて、共有ライブラリか"
+"実行可能ファイルを出力します。(`#[crate_type = \"lib\"];` の行が取り除かれば"
+"場合、 `rustc` は実行可能ファイルを生成します。)"
+
+#. type: Plain text
+#: doc/tutorial.md:2370
+msgid ""
+"The `#[link(...)]` attribute provides meta information about the module, "
+"which other crates can use to load the right module. More about that later."
+msgstr ""
+"`#[link(...)]` 属性は、モジュールに関するメタ情報を提供し、この情報により他の"
+"クレートは正しいモジュールをロードすることができます。あとで詳しく述べます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2373
+msgid ""
+"To have a nested directory structure for your source files, you can nest "
+"mods:"
+msgstr ""
+"ソースファイルをネストしたディレクトリに配置する場合、`mod` をネストさせま"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:2380
+#, no-wrap
+msgid ""
+"~~~~ {.ignore}\n"
+"mod poultry {\n"
+" mod chicken;\n"
+" mod turkey;\n"
+"}\n"
+"~~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2385
+msgid ""
+"The compiler will now look for `poultry/chicken.rs` and `poultry/turkey.rs`, "
+"and export their content in `poultry::chicken` and `poultry::turkey`. You "
+"can also provide a `poultry.rs` to add content to the `poultry` module "
+"itself."
+msgstr ""
+"コンパイラは `poultry/chicken.rs` と `poultry/turkey.rs` を読み込み、ファイル"
+"の内容を `poultry::chicken` と `poultry::turkey` としてエクスポートします。"
+"`poultry.rs` を作成することで、`poultry` モジュールの内容を追加することも可能"
+"です。"
+
+#. type: Plain text
+#: doc/tutorial.md:2387
+msgid "## Using other crates"
+msgstr "## 他のクレートの利用"
+
+#. type: Plain text
+#: doc/tutorial.md:2395
+msgid ""
+"The `extern mod` directive lets you use a crate (once it's been compiled "
+"into a library) from inside another crate. `extern mod` can appear at the "
+"top of a crate file or at the top of modules. It will cause the compiler to "
+"look in the library search path (which you can extend with the `-L` switch) "
+"for a compiled Rust library with the right name, then add a module with that "
+"crate's name into the local scope."
+msgstr ""
+"`extern mod` ディレクティブを使うと、あるクレートの中から、(ライブラリにコン"
+"パイルされている) 別のクレートを使用することができます。`extern mod` はク"
+"レートファイルの先頭かモジュールの先頭に記述することができます。コンパイラ"
+"は、対応する名前の Rust ライブラリをライブラリの検索パス (`-L` スイッチにより"
+"追加可能) から検索し、クレートと同じ名前のモジュールをローカルスコープに追加"
+"します。"
+
+#. type: Plain text
+#: doc/tutorial.md:2397
+msgid "For example, `extern mod std` links the [standard library]."
+msgstr ""
+"例えば、 `extern mod std` は [標準ライブラリ][standard library] をリンクしま"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:2399
+msgid "[standard library]: std/index.html"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2406
+msgid ""
+"When a comma-separated list of name/value pairs appears after `extern mod`, "
+"the compiler front-end matches these pairs against the attributes provided "
+"in the `link` attribute of the crate file. The front-end will only select "
+"this crate for use if the actual pairs match the declared attributes. You "
+"can provide a `name` value to override the name used to search for the crate."
+msgstr ""
+"`extern mod` の後にカンマで区切られた名前と値のペアが記述された場合、コンパイ"
+"ラのフロントエンドはクレートファイルの `link` 属性によって指定された属性と比"
+"較します。フロントエンドは宣言された属性とペアが一致するクレートだけを選択"
+"し、利用します。`name` の値を設定することで、クレートの検索に使う名前を上書き"
+"することができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2408
+msgid "Our example crate declared this set of `link` attributes:"
+msgstr ""
+"先ほどのクレートの例では、 `link` 属性は以下のように宣言されていました。"
+
+#. type: Plain text
+#: doc/tutorial.md:2412
+msgid "~~~~ #[link(name = \"farm\", vers = \"2.5\", author = \"mjh\")]; ~~~~"
+msgstr ""
+"~~~~\n"
+"#[link(name = \"farm\", vers = \"2.5\", author = \"mjh\")];\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2414
+msgid "Which you can then link with any (or all) of the following:"
+msgstr ""
+"以下のいずれか (またはすべて) の方法でクレートをリンクすることができます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2420
+msgid ""
+"~~~~ {.xfail-test} extern mod farm; extern mod my_farm (name = \"farm\", "
+"vers = \"2.5\"); extern mod my_auxiliary_farm (name = \"farm\", author = "
+"\"mjh\"); ~~~~"
+msgstr ""
+"~~~~ {.xfail-test}\n"
+"extern mod farm;\n"
+"extern mod my_farm (name = \"farm\", vers = \"2.5\");\n"
+"extern mod my_auxiliary_farm (name = \"farm\", author = \"mjh\");\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2423
+msgid ""
+"If any of the requested metadata do not match, then the crate will not be "
+"compiled successfully."
+msgstr ""
+"指定されたメタデータに一致するものが存在しない場合、クレートのコンパイルは失"
+"敗します。"
+
+#. type: Plain text
+#: doc/tutorial.md:2425
+msgid "## A minimal example"
+msgstr "## 最小限の例"
+
+#. type: Plain text
+#: doc/tutorial.md:2428
+msgid ""
+"Now for something that you can actually compile yourself, we have these two "
+"files:"
+msgstr ""
+"あなた自身で実際にコンパイルが行える例として、以下の2つのファイルを例示しま"
+"す。"
+
+#. type: Plain text
+#: doc/tutorial.md:2434
+msgid ""
+"~~~~ // world.rs #[link(name = \"world\", vers = \"1.0\")]; pub fn explore() "
+"-> &str { \"world\" } ~~~~"
+msgstr ""
+"~~~~\n"
+"// world.rs\n"
+"#[link(name = \"world\", vers = \"1.0\")];\n"
+"pub fn explore() -> &str { \"world\" }\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2440
+msgid ""
+"~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello "
+"\" + world::explore()); } ~~~~"
+msgstr ""
+"~~~~ {.xfail-test}\n"
+"// main.rs\n"
+"extern mod world;\n"
+"fn main() { println(~\"hello \" + world::explore()); }\n"
+"~~~~"
+
+#. type: Plain text
+#: doc/tutorial.md:2442
+msgid "Now compile and run like this (adjust to your platform if necessary):"
+msgstr ""
+"以下のようにコンパイルし、実行します (必要であれば、お使いのプラットフォーム"
+"に合わせて修正してください。)"
+
+#. type: Plain text
+#: doc/tutorial.md:2449
+#, no-wrap
+msgid ""
+"~~~~ {.notrust}\n"
+"> rustc --lib world.rs # compiles libworld-94839cbfe144198-1.0.so\n"
+"> rustc main.rs -L . # compiles main\n"
+"> ./main\n"
+"\"hello world\"\n"
+"~~~~\n"
+msgstr ""
+"~~~~ {.notrust}\n"
+"> rustc --lib world.rs # libworld-94839cbfe144198-1.0.so が生成される\n"
+"> rustc main.rs -L . # main が生成される\n"
+"> ./main\n"
+"\"hello world\"\n"
+"~~~~\n"
+
+#. type: Plain text
+#: doc/tutorial.md:2454
+msgid ""
+"Notice that the library produced contains the version in the filename as "
+"well as an inscrutable string of alphanumerics. These are both part of "
+"Rust's library versioning scheme. The alphanumerics are a hash representing "
+"the crate metadata."
+msgstr ""
+"生成されたライブラリのファイル名には、バージョン番号だけでなく謎めいた英数字"
+"が含まれていることに注意してください。これらは両方共 Rust のバージョン管理ス"
+"キームの一員です。英数字は、クレートのメタデータを表すハッシュ値です。"
+
+#. type: Plain text
+#: doc/tutorial.md:2456
+msgid "## The standard library"
+msgstr "## 標準ライブラリ"
+
+#. type: Plain text
+#: doc/tutorial.md:2461
+msgid ""
+"The Rust standard 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."
+msgstr ""
+"Rust の標準ライブラリは、タスクスケジューラやメモリアロケータを含む、言語自体"
+"が必要とするランタイム機能を提供するだけでなく、Rust の組み込み型や、プラット"
+"フォームの抽象化、その他一般的によく利用される機能ををサポートするライブラリ"
+"を含んでいます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2472
+msgid ""
+"[`std`] includes modules corresponding to each of the integer types, each of "
+"the floating point types, the [`bool`] type, [tuples], [characters], "
+"[strings], [vectors], [managed boxes], [owned boxes], and unsafe and "
+"borrowed [pointers]. Additionally, `std` provides some pervasive types "
+"([`option`] and [`result`]), [task] creation and [communication] primitives, "
+"platform abstractions ([`os`] and [`path`]), basic I/O abstractions "
+"([`io`]), [containers] like [`hashmap`], common traits ([`kinds`], [`ops`], "
+"[`cmp`], [`num`], [`to_str`], [`clone`]), and complete bindings to the C "
+"standard library ([`libc`])."
+msgstr ""
+"[`std`] は整数型や浮動小数点型、[`bool`] 型、[タプル][tuples]、[文字]"
+"[characters]、[文字列][strings]、[ベクタ][vectors]、[マネージドボックス]"
+"[managed boxes]、[所有ボックス][owned boxes]、unsafe または借用 [ポインタ]"
+"[pointers] に対応するモジュールを含んでいます。さらに、 `std` は、いくつかの"
+"よく使われる型 ([`option`] と [`result`])や、 [タスク][task] 生成と[通信]"
+"[communication] のためのプリミティブ、プラットフォームの抽象化 ([`os`] と "
+"[`path`])、基本的な I/O の抽象化 ([`io`]), [`hashmap`] などの [コンテナ]"
+"[containers]、共通的に使われるトレイト ([`kinds`], [`ops`], [`cmp`], "
+"[`num`], [`to_str`], [`clone`])、C 標準ライブラリ ([`libc`]) への完全なバイン"
+"ディングを提供します。"
+
+#. type: Plain text
+#: doc/tutorial.md:2474
+msgid "### Standard Library injection and the Rust prelude"
+msgstr "### 標準ライブラリの注入と Rust の prelude"
+
+#. type: Plain text
+#: doc/tutorial.md:2477
+msgid ""
+"`std` is imported at the topmost level of every crate by default, as if the "
+"first line of each crate was"
+msgstr ""
+"`std` は、すべてのクレートの先頭以下の行か書かれているかのように、デフォルト"
+"でクレートの最上位のレベルにインポートされます。"
+
+#. type: Plain text
+#: doc/tutorial.md:2479
+#, no-wrap
+msgid " extern mod std;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2483
+msgid ""
+"This means that the contents of std can be accessed from from any context "
+"with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`, "
+"etc."
+msgstr ""
+"これは、 std の内容には `std::` というパスプレフィックスを付けることで、任意"
+"のコンテキストから `use std::vec`. `use std::task::spawn` のようにアクセスで"
+"きることを意味します。"
+
+#. type: Plain text
+#: doc/tutorial.md:2488
+msgid ""
+"Additionally, `std` contains a `prelude` module that reexports many of the "
+"most common standard 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:"
+msgstr ""
+"さらに、 `std` は `prelude` という、最も共通的なモジュールや型、トレイトを再"
+"エクスポートするモジュールを含んでいます。prelude の内容は、デフォルトですべ"
+"ての **モジュール** にインポートされます。すべてのモジュールは、以下の文言を"
+"モジュール先頭に暗黙的に含んでいるように動作します。"
+
+#. type: Plain text
+#: doc/tutorial.md:2490
+#, no-wrap
+msgid " use std::prelude::*;\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial.md:2516
+msgid ""
+"[`std`]: std/index.html [`bool`]: std/bool.html [tuples]: std/tuple.html "
+"[characters]: std/char.html [strings]: std/str.html [vectors]: std/vec.html "
+"[managed boxes]: std/managed.html [owned boxes]: std/owned.html [pointers]: "
+"std/ptr.html [`option`]: std/option.html [`result`]: std/result.html [task]: "
+"std/task.html [communication]: std/comm.html [`os`]: std/os.html [`path`]: "
+"std/path.html [`io`]: std/io.html [containers]: std/container.html "
+"[`hashmap`]: std/hashmap.html [`kinds`]: std/kinds.html [`ops`]: std/ops."
+"html [`cmp`]: std/cmp.html [`num`]: std/num.html [`to_str`]: std/to_str.html "
+"[`clone`]: std/clone.html [`libc`]: std/libc.html"
+msgstr ""
+"[`std`]: std/index.html\n"
+"[`bool`]: std/bool.html\n"
+"[tuples]: std/tuple.html\n"
+"[characters]: std/char.html\n"
+"[strings]: std/str.html\n"
+"[vectors]: std/vec.html\n"
+"[managed boxes]: std/managed.html\n"
+"[owned boxes]: std/owned.html\n"
+"[pointers]: std/ptr.html\n"
+"[`option`]: std/option.html\n"
+"[`result`]: std/result.html\n"
+"[task]: std/task.html\n"
+"[communication]: std/comm.html\n"
+"[`os`]: std/os.html\n"
+"[`path`]: std/path.html\n"
+"[`io`]: std/io.html\n"
+"[containers]: std/container.html\n"
+"[`hashmap`]: std/hashmap.html\n"
+"[`kinds`]: std/kinds.html\n"
+"[`ops`]: std/ops.html\n"
+"[`cmp`]: std/cmp.html\n"
+"[`num`]: std/num.html\n"
+"[`to_str`]: std/to_str.html\n"
+"[`clone`]: std/clone.html\n"
+"[`libc`]: std/libc.html"
+
+#. type: Plain text
+#: doc/tutorial.md:2518
+msgid "# What next?"
+msgstr "# 次のステップは?"
+
+#. type: Plain text
+#: doc/tutorial.md:2521
+msgid ""
+"Now that you know the essentials, check out any of the additional tutorials "
+"on individual topics."
+msgstr ""
+"Rust の本質的な部分に関する説明は以上です。個々のトピックにおける追加のチュー"
+"トリアルもチェックしてみてください。"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:2527
+msgid "[Borrowed pointers][borrow]"
+msgstr "[借用ポインタ][borrow]"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:2527
+msgid "[Tasks and communication][tasks]"
+msgstr "[タスクと通信][tasks]"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:2527
+msgid "[Macros][macros]"
+msgstr "[マクロ][macros]"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:2527
+msgid "[The foreign function interface][ffi]"
+msgstr "[他言語間インターフェース (foreign function inferface)][ffi]"
+
+#. type: Bullet: '* '
+#: doc/tutorial.md:2527
+msgid "[Containers and iterators](tutorial-container.html)"
+msgstr "[コンテナとイテレータ](tutorial-container.html)"
+
+#. type: Plain text
+#: doc/tutorial.md:2529
+msgid "There is further documentation on the [wiki]."
+msgstr "[wiki] にもドキュメントがあります。"
+
+#. type: Plain text
+#: doc/tutorial.md:2534
+msgid ""
+"[borrow]: tutorial-borrowed-ptr.html [tasks]: tutorial-tasks.html [macros]: "
+"tutorial-macros.html [ffi]: tutorial-ffi.html"
+msgstr ""
+"[borrow]: tutorial-borrowed-ptr.html\n"
+"[tasks]: tutorial-tasks.html\n"
+"[macros]: tutorial-macros.html\n"
+"[ffi]: tutorial-ffi.html"
+
+#. type: Plain text
+#: doc/tutorial.md:2536
+msgid "[wiki]: https://github.com/mozilla/rust/wiki/Docs"
+msgstr ""
msgid ""
msgstr ""
"Project-Id-Version: Rust 0.8-pre\n"
-"POT-Creation-Date: 2013-07-17 07:47+0900\n"
+"POT-Creation-Date: 2013-08-12 02:06+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#. type: Plain text
msgstr ""
#. type: Plain text
-#: doc/rust.md:74 doc/rust.md:417 doc/rust.md:487
+#: doc/rust.md:74 doc/rust.md:416 doc/rust.md:486
msgid "~~~~~~~~"
msgstr ""
msgstr ""
#. type: Plain text
-#: doc/rust.md:223
+#: doc/rust.md:222
msgid ""
-"~~~~~~~~ {.keyword} as break copy do else enum extern false fn for if impl "
-"let loop match mod mut priv pub ref return self static struct super true "
-"trait type unsafe use while ~~~~~~~~"
+"~~~~~~~~ {.keyword} as break do else enum extern false fn for if impl let "
+"loop match mod mut priv pub ref return self static struct super true trait "
+"type unsafe use while ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:226
+#: doc/rust.md:225
msgid ""
"Each of these keywords has special meaning in its grammar, and all of them "
"are excluded from the `ident` rule."
msgstr ""
#. type: Plain text
-#: doc/rust.md:228
+#: doc/rust.md:227
msgid "### Literals"
msgstr ""
#. type: Plain text
-#: doc/rust.md:234
+#: doc/rust.md:233
msgid ""
"A literal is an expression consisting of a single token, rather than a "
"sequence of tokens, that immediately and directly denotes the value it "
msgstr ""
#. type: Plain text
-#: doc/rust.md:238
+#: doc/rust.md:237
msgid ""
"~~~~~~~~ {.ebnf .gram} literal : string_lit | char_lit | num_lit ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:240
+#: doc/rust.md:239
msgid "#### Character and string literals"
msgstr ""
#. type: Plain text
-#: doc/rust.md:244
+#: doc/rust.md:243
msgid ""
"~~~~~~~~ {.ebnf .gram} char_lit : '\\x27' char_body '\\x27' ; string_lit : "
"'\"' string_body * '\"' ;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:247
+#: doc/rust.md:246
#, no-wrap
msgid ""
"char_body : non_single_quote\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:250
+#: doc/rust.md:249
#, no-wrap
msgid ""
"string_body : non_double_quote\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:256
+#: doc/rust.md:255
#, no-wrap
msgid ""
"common_escape : '\\x5c'\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:264
+#: doc/rust.md:263
#, no-wrap
msgid ""
"hex_digit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f'\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:268
+#: doc/rust.md:267
msgid ""
"A _character literal_ is a single Unicode character enclosed within two `U"
"+0027` (single-quote) characters, with the exception of `U+0027` itself, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:272
+#: doc/rust.md:271
msgid ""
"A _string literal_ is a sequence of any Unicode characters enclosed within "
"two `U+0022` (double-quote) characters, with the exception of `U+0022` "
msgstr ""
#. type: Plain text
-#: doc/rust.md:276
+#: doc/rust.md:275
msgid ""
"Some additional _escapes_ are available in either character or string "
"literals. An escape starts with a `U+005C` (`\\`) and continues with one of "
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:291
+#: doc/rust.md:290
msgid ""
"An _8-bit codepoint escape_ escape starts with `U+0078` (`x`) and is "
"followed by exactly two _hex digits_. It denotes the Unicode codepoint equal "
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:291
+#: doc/rust.md:290
msgid ""
"A _16-bit codepoint escape_ starts with `U+0075` (`u`) and is followed by "
"exactly four _hex digits_. It denotes the Unicode codepoint equal to the "
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:291
+#: doc/rust.md:290
msgid ""
"A _32-bit codepoint escape_ starts with `U+0055` (`U`) and is followed by "
"exactly eight _hex digits_. It denotes the Unicode codepoint equal to the "
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:291
+#: doc/rust.md:290
msgid ""
"A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072` "
"(`r`), or `U+0074` (`t`), denoting the unicode values `U+000A` (LF), `U"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:291
+#: doc/rust.md:290
msgid ""
"The _backslash escape_ is the character U+005C (`\\`) which must be escaped "
"in order to denote *itself*."
msgstr ""
#. type: Plain text
-#: doc/rust.md:293
+#: doc/rust.md:292
msgid "#### Number literals"
msgstr ""
#. type: Plain text
-#: doc/rust.md:295 doc/rust.md:407 doc/rust.md:474
+#: doc/rust.md:294 doc/rust.md:406 doc/rust.md:473
msgid "~~~~~~~~ {.ebnf .gram}"
msgstr ""
#. type: Plain text
-#: doc/rust.md:300
+#: doc/rust.md:299
#, no-wrap
msgid ""
"num_lit : nonzero_dec [ dec_digit | '_' ] * num_suffix ?\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:302
+#: doc/rust.md:301
msgid "num_suffix : int_suffix | float_suffix ;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:306
+#: doc/rust.md:305
#, no-wrap
msgid ""
"int_suffix : 'u' int_suffix_size ?\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:312
+#: doc/rust.md:311
msgid ""
"float_suffix : [ exponent | '.' dec_lit exponent ? ] ? float_suffix_ty ? ; "
"float_suffix_ty : 'f' [ '3' '2' | '6' '4' ] ; exponent : ['E' | 'e'] ['-' | "
msgstr ""
#. type: Plain text
-#: doc/rust.md:316
+#: doc/rust.md:315
msgid ""
"A _number literal_ is either an _integer literal_ or a _floating-point "
"literal_. The grammar for recognizing the two kinds of literals is mixed, as "
msgstr ""
#. type: Plain text
-#: doc/rust.md:318
+#: doc/rust.md:317
msgid "##### Integer literals"
msgstr ""
#. type: Plain text
-#: doc/rust.md:320
+#: doc/rust.md:319
msgid "An _integer literal_ has one of three forms:"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:327
+#: doc/rust.md:326
msgid ""
"A _decimal literal_ starts with a *decimal digit* and continues with any "
"mixture of *decimal digits* and _underscores_."
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:327
+#: doc/rust.md:326
msgid ""
"A _hex literal_ starts with the character sequence `U+0030` `U+0078` (`0x`) "
"and continues as any mixture hex digits and underscores."
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:327
+#: doc/rust.md:326
msgid ""
"A _binary literal_ starts with the character sequence `U+0030` `U+0062` "
"(`0b`) and continues as any mixture binary digits and underscores."
msgstr ""
#. type: Plain text
-#: doc/rust.md:331
+#: doc/rust.md:330
msgid ""
"An integer literal may be followed (immediately, without any spaces) by an "
"_integer suffix_, which changes the type of the literal. There are two kinds "
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:337
+#: doc/rust.md:336
msgid ""
"The `i` and `u` suffixes give the literal type `int` or `uint`, respectively."
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:337
+#: doc/rust.md:336
msgid ""
"Each of the signed and unsigned machine types `u8`, `i8`, `u16`, `i16`, "
"`u32`, `i32`, `u64` and `i64` give the literal the corresponding machine "
msgstr ""
#. type: Plain text
-#: doc/rust.md:344
+#: doc/rust.md:343
msgid ""
"The type of an _unsuffixed_ integer literal is determined by type "
"inference. If a integer type can be _uniquely_ determined from the "
msgstr ""
#. type: Plain text
-#: doc/rust.md:346
+#: doc/rust.md:345
msgid "Examples of integer literals of various forms:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:351
+#: doc/rust.md:350
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:357
+#: doc/rust.md:356
#, no-wrap
msgid ""
"123u; // type uint\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:359
+#: doc/rust.md:358
msgid "##### Floating-point literals"
msgstr ""
#. type: Plain text
-#: doc/rust.md:361
+#: doc/rust.md:360
msgid "A _floating-point literal_ has one of two forms:"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:366
+#: doc/rust.md:365
msgid ""
"Two _decimal literals_ separated by a period character `U+002E` (`.`), with "
"an optional _exponent_ trailing after the second decimal literal."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:366
+#: doc/rust.md:365
msgid "A single _decimal literal_ followed by an _exponent_."
msgstr ""
#. type: Plain text
-#: doc/rust.md:373
+#: doc/rust.md:372
msgid ""
"By default, a floating-point literal is of type `float`. A floating-point "
"literal may be followed (immediately, without any spaces) by a _floating-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:375
+#: doc/rust.md:374
msgid "Examples of floating-point literals of various forms:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:383
+#: doc/rust.md:382
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:385
+#: doc/rust.md:384
msgid "##### Unit and boolean literals"
msgstr ""
#. type: Plain text
-#: doc/rust.md:388
+#: doc/rust.md:387
msgid ""
"The _unit value_, the only value of the type that has the same name, is "
"written as `()`. The two values of the boolean type are written `true` and "
msgstr ""
#. type: Plain text
-#: doc/rust.md:390
+#: doc/rust.md:389
msgid "### Symbols"
msgstr ""
#. type: Plain text
-#: doc/rust.md:396
+#: doc/rust.md:395
#, no-wrap
msgid ""
"~~~~~~~~ {.ebnf .gram}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:402
+#: doc/rust.md:401
msgid ""
"Symbols are a general class of printable [token](#tokens) that play "
"structural roles in a variety of grammar productions. They are catalogued "
msgstr ""
#. type: Plain text
-#: doc/rust.md:405
+#: doc/rust.md:404
msgid "## Paths"
msgstr ""
#. type: Plain text
-#: doc/rust.md:411
+#: doc/rust.md:410
#, no-wrap
msgid ""
"expr_path : ident [ \"::\" expr_path_tail ] + ;\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:415
+#: doc/rust.md:414
#, no-wrap
msgid ""
"type_path : ident [ type_path_tail ] + ;\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:422
+#: doc/rust.md:421
msgid ""
"A _path_ is a sequence of one or more path components _logically_ separated "
"by a namespace qualifier (`::`). If a path consists of only one component, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:426
+#: doc/rust.md:425
msgid ""
"Every item has a _canonical path_ within its crate, but the path naming an "
"item is only meaningful within a given crate. There is no global namespace "
msgstr ""
#. type: Plain text
-#: doc/rust.md:428
+#: doc/rust.md:427
msgid "Two examples of simple paths consisting of only identifier components:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:433
+#: doc/rust.md:432
msgid "~~~~{.ignore} x; x::y::z; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:440
+#: doc/rust.md:439
msgid ""
"Path components are usually [identifiers](#identifiers), but the trailing "
"component of a path may be an angle-bracket-enclosed list of type arguments. "
msgstr ""
#. type: Plain text
-#: doc/rust.md:442
+#: doc/rust.md:441
msgid "Two examples of paths with type arguments:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:451
+#: doc/rust.md:450
#, no-wrap
msgid ""
"~~~~\n"
"# use std::hashmap::HashMap;\n"
"# fn f() {\n"
-"# fn id<T:Copy>(t: T) -> T { t }\n"
+"# fn id<T>(t: T) -> T { t }\n"
"type t = HashMap<int,~str>; // Type arguments used in a type expression\n"
"let x = id::<int>(10); // Type arguments used in a call expression\n"
"# }\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:453
+#: doc/rust.md:452
msgid "# Syntax extensions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:458
+#: doc/rust.md:457
msgid ""
"A number of minor features of Rust are not central enough to have their own "
"syntax, and yet are not implementable as functions. Instead, they are given "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:467
+#: doc/rust.md:466
msgid "`fmt!` : format data into a string"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:467
+#: doc/rust.md:466
msgid "`env!` : look up an environment variable's value at compile time"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:467
+#: doc/rust.md:466
msgid "`stringify!` : pretty-print the Rust expression given as an argument"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:467
+#: doc/rust.md:466
msgid "`proto!` : define a protocol for inter-task communication"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:467
+#: doc/rust.md:466
msgid "`include!` : include the Rust expression in the given file"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:467
+#: doc/rust.md:466
msgid "`include_str!` : include the contents of the given file as a string"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:467
+#: doc/rust.md:466
msgid ""
"`include_bin!` : include the contents of the given file as a binary blob"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:467
+#: doc/rust.md:466
msgid "`error!`, `warn!`, `info!`, `debug!` : provide diagnostic information."
msgstr ""
#. type: Plain text
-#: doc/rust.md:470
+#: doc/rust.md:469
msgid ""
"All of the above extensions, with the exception of `proto!`, are expressions "
"with values. `proto!` is an item, defining a new name."
msgstr ""
#. type: Plain text
-#: doc/rust.md:472
+#: doc/rust.md:471
msgid "## Macros"
msgstr ""
#. type: Plain text
-#: doc/rust.md:485
+#: doc/rust.md:484
#, no-wrap
msgid ""
"expr_macro_rules : \"macro_rules\" '!' ident '(' macro_rule * ')'\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:491
+#: doc/rust.md:490
msgid ""
"User-defined syntax extensions are called \"macros\", and the `macro_rules` "
"syntax extension defines them. Currently, user-defined macros can expand to "
msgstr ""
#. type: Plain text
-#: doc/rust.md:494
+#: doc/rust.md:493
msgid ""
"(A `sep_token` is any token other than `*` and `+`. A `non_special_token` "
"is any token other than a delimiter or `$`.)"
msgstr ""
#. type: Plain text
-#: doc/rust.md:500
+#: doc/rust.md:499
msgid ""
"The macro expander looks up macro invocations by name, and tries each macro "
"rule in turn. It transcribes the first successful match. Matching and "
msgstr ""
#. type: Plain text
-#: doc/rust.md:502
+#: doc/rust.md:501
msgid "### Macro By Example"
msgstr ""
#. type: Plain text
-#: doc/rust.md:505
+#: doc/rust.md:504
msgid ""
"The macro expander matches and transcribes every token that does not begin "
"with a `$` literally, including delimiters. For parsing reasons, delimiters "
msgstr ""
#. type: Plain text
-#: doc/rust.md:511
+#: doc/rust.md:510
msgid ""
"In the matcher, `$` _name_ `:` _designator_ matches the nonterminal in the "
"Rust syntax named by _designator_. Valid designators are `item`, `block`, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:520
+#: doc/rust.md:519
msgid ""
"In both the matcher and transcriber, the Kleene star-like operator indicates "
"repetition. The Kleene star operator consists of `$` and parens, optionally "
msgstr ""
#. type: Plain text
-#: doc/rust.md:526
+#: doc/rust.md:525
msgid ""
"The rules for transcription of these repetitions are called \"Macro By "
"Example\". Essentially, one \"layer\" of repetition is discharged at a "
msgstr ""
#. type: Plain text
-#: doc/rust.md:534
+#: doc/rust.md:533
msgid ""
"When Macro By Example encounters a repetition, it examines all of the `$` "
"_name_ s that occur in its body. At the \"current layer\", they all must "
msgstr ""
#. type: Plain text
-#: doc/rust.md:536
+#: doc/rust.md:535
msgid "Nested repetitions are allowed."
msgstr ""
#. type: Plain text
-#: doc/rust.md:538
+#: doc/rust.md:537
msgid "### Parsing limitations"
msgstr ""
#. type: Plain text
-#: doc/rust.md:541
+#: doc/rust.md:540
msgid ""
"The parser used by the macro system is reasonably powerful, but the parsing "
"of Rust syntax is restricted in two ways:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:547
+#: doc/rust.md:546
#, no-wrap
msgid ""
"1. The parser will always parse as much as possible. If it attempts to match\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:550
+#: doc/rust.md:549
msgid "## Syntax extensions useful for the macro author"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:555
+#: doc/rust.md:554
msgid "`log_syntax!` : print out the arguments at compile time"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:555
+#: doc/rust.md:554
msgid ""
"`trace_macros!` : supply `true` or `false` to enable or disable macro "
"expansion logging"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:555
+#: doc/rust.md:554
msgid "`stringify!` : turn the identifier argument into a string literal"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:555
+#: doc/rust.md:554
msgid ""
"`concat_idents!` : create a new identifier by concatenating the arguments"
msgstr ""
#. type: Plain text
-#: doc/rust.md:557
+#: doc/rust.md:556
msgid "# Crates and source files"
msgstr ""
#. type: Plain text
-#: doc/rust.md:564
+#: doc/rust.md:563
msgid ""
"Rust is a *compiled* language. Its semantics obey a *phase distinction* "
"between compile-time and run-time. Those semantic rules that have a *static "
msgstr ""
#. type: Plain text
-#: doc/rust.md:570
+#: doc/rust.md:569
msgid ""
"The compilation model centres on artifacts called _crates_. Each "
"compilation processes a single crate in source form, and if successful, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:574
+#: doc/rust.md:573
msgid ""
"A _crate_ is a unit of compilation and linking, as well as versioning, "
"distribution and runtime loading. A crate contains a _tree_ of nested "
msgstr ""
#. type: Plain text
-#: doc/rust.md:579
+#: doc/rust.md:577
msgid ""
"The Rust compiler is always invoked with a single source file as input, and "
"always produces a single output crate. The processing of that source file "
-"may result in other source files being loaded as modules. Source files "
-"typically have the extension `.rs` but, by convention, source files that "
-"represent crates have the extension `.rc`, called *crate files*."
+"may result in other source files being loaded as modules. Source files have "
+"the extension `.rs`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:584
+#: doc/rust.md:582
msgid ""
"A Rust source file describes a module, the name and location of which -- in "
"the module tree of the current crate -- are defined from outside the source "
msgstr ""
#. type: Plain text
-#: doc/rust.md:589
+#: doc/rust.md:587
msgid ""
"Each source file contains a sequence of zero or more `item` definitions, and "
"may optionally begin with any number of `attributes` that apply to the "
msgstr ""
#. type: Plain text
-#: doc/rust.md:595
+#: doc/rust.md:593
#, no-wrap
msgid ""
"~~~~~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:600
+#: doc/rust.md:598
msgid ""
"// Additional metadata attributes #[ desc = \"Project X\" ]; #[ license = "
"\"BSD\" ]; #[ author = \"Jane Doe\" ];"
msgstr ""
#. type: Plain text
-#: doc/rust.md:603
+#: doc/rust.md:601
msgid "// Specify the output type #[ crate_type = \"lib\" ];"
msgstr ""
#. type: Plain text
-#: doc/rust.md:607
+#: doc/rust.md:605
msgid "// Turn on a warning #[ warn(non_camel_case_types) ]; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:610
+#: doc/rust.md:608
msgid ""
"A crate that contains a `main` function can be compiled to an executable. "
"If a `main` function is present, its return type must be [`unit`](#primitive-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:613
+#: doc/rust.md:611
msgid "# Items and attributes"
msgstr ""
#. type: Plain text
-#: doc/rust.md:616
+#: doc/rust.md:614
msgid ""
"Crates contain [items](#items), each of which may have some number of "
"[attributes](#attributes) attached to it."
msgstr ""
#. type: Plain text
-#: doc/rust.md:618
+#: doc/rust.md:616
msgid "## Items"
msgstr ""
#. type: Plain text
-#: doc/rust.md:623
+#: doc/rust.md:621
#, no-wrap
msgid ""
"~~~~~~~~ {.ebnf .gram}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:629
+#: doc/rust.md:627
msgid ""
"An _item_ is a component of a crate; some module items can be defined in "
"crate files, but most are defined in source files. Items are organized "
msgstr ""
#. type: Plain text
-#: doc/rust.md:632
+#: doc/rust.md:630
msgid ""
"Items are entirely determined at compile-time, generally remain fixed during "
"execution, and may reside in read-only memory."
msgstr ""
#. type: Plain text
-#: doc/rust.md:634
+#: doc/rust.md:632
msgid "There are several kinds of item:"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:643
+#: doc/rust.md:641
msgid "[modules](#modules)"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:643
+#: doc/rust.md:641
msgid "[functions](#functions)"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:643
+#: doc/rust.md:641
msgid "[type definitions](#type-definitions)"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:643
+#: doc/rust.md:641
msgid "[structures](#structures)"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:643
+#: doc/rust.md:641
msgid "[enumerations](#enumerations)"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:643
+#: doc/rust.md:641
msgid "[static items](#static-items)"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:643
+#: doc/rust.md:641
msgid "[traits](#traits)"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:643
+#: doc/rust.md:641
msgid "[implementations](#implementations)"
msgstr ""
#. type: Plain text
-#: doc/rust.md:653
+#: doc/rust.md:651
msgid ""
"Some items form an implicit scope for the declaration of sub-items. In other "
"words, within a function or module, declarations of items can (in many "
msgstr ""
#. type: Plain text
-#: doc/rust.md:655
+#: doc/rust.md:653
msgid "### Type Parameters"
msgstr ""
#. type: Plain text
-#: doc/rust.md:664
+#: doc/rust.md:662
msgid ""
"All items except modules may be *parameterized* by type. Type parameters are "
"given as a comma-separated list of identifiers enclosed in angle brackets "
msgstr ""
#. type: Plain text
-#: doc/rust.md:666
+#: doc/rust.md:664
msgid "### Modules"
msgstr ""
#. type: Plain text
-#: doc/rust.md:671
+#: doc/rust.md:669
msgid ""
"~~~~~~~~ {.ebnf .gram} mod_item : \"mod\" ident ( ';' | '{' mod '}' ); mod : "
"[ view_item | item ] * ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:676
+#: doc/rust.md:674
msgid ""
"A module is a container for zero or more [view items](#view-items) and zero "
"or more [items](#items). The view items manage the visibility of the items "
msgstr ""
#. type: Plain text
-#: doc/rust.md:680
+#: doc/rust.md:678
msgid ""
"A _module item_ is a module, surrounded in braces, named, and prefixed with "
"the keyword `mod`. A module item introduces a new, named module into the "
msgstr ""
#. type: Plain text
-#: doc/rust.md:682
+#: doc/rust.md:680
msgid "An example of a module:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:700
+#: doc/rust.md:698
#, no-wrap
msgid ""
"~~~~~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:705
+#: doc/rust.md:703
msgid ""
"Modules and types share the same namespace. Declaring a named type that has "
"the same name as a module in scope is forbidden: that is, a type definition, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:710
+#: doc/rust.md:708
msgid ""
"A module without a body is loaded from an external file, by default with the "
"same name as the module, plus the `.rs` extension. When a nested submodule "
msgstr ""
#. type: Plain text
-#: doc/rust.md:714
+#: doc/rust.md:712
msgid "~~~ {.xfail-test} // Load the `vec` module from `vec.rs` mod vec;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:720
+#: doc/rust.md:718
#, no-wrap
msgid ""
"mod task {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:723
+#: doc/rust.md:721
msgid ""
"The directories and files used for loading external file modules can be "
"influenced with the `path` attribute."
msgstr ""
#. type: Plain text
-#: doc/rust.md:732
+#: doc/rust.md:730
#, no-wrap
msgid ""
"~~~ {.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:734
+#: doc/rust.md:732
msgid "#### View items"
msgstr ""
#. type: Plain text
-#: doc/rust.md:738
+#: doc/rust.md:736
msgid ""
"~~~~~~~~ {.ebnf .gram} view_item : extern_mod_decl | use_decl ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:742
+#: doc/rust.md:740
msgid ""
"A view item manages the namespace of a module. View items do not define new "
"items, but rather, simply change other items' visibility. There are several "
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:745
+#: doc/rust.md:743
msgid "[`extern mod` declarations](#extern-mod-declarations)"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:745
+#: doc/rust.md:743
msgid "[`use` declarations](#use-declarations)"
msgstr ""
#. type: Plain text
-#: doc/rust.md:747
+#: doc/rust.md:745
msgid "##### Extern mod declarations"
msgstr ""
#. type: Plain text
-#: doc/rust.md:753
+#: doc/rust.md:751
msgid ""
"~~~~~~~~ {.ebnf .gram} extern_mod_decl : \"extern\" \"mod\" ident [ '(' "
-"link_attrs ')' ] ? ; link_attrs : link_attr [ ',' link_attrs ] + ; "
-"link_attr : ident '=' literal ; ~~~~~~~~"
+"link_attrs ')' ] ? [ '=' string_lit ] ? ; link_attrs : link_attr [ ',' "
+"link_attrs ] + ; link_attr : ident '=' literal ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:757
+#: doc/rust.md:755
msgid ""
"An _`extern mod` declaration_ specifies a dependency on an external crate. "
"The external crate is then bound into the declaring scope as the `ident` "
msgid ""
"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 "
+"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 "
-"crate when it was compiled. If no `link_attrs` are provided, a default "
+"crate when it was compiled. If no `link_attrs` are provided, a default "
"`name` attribute is assumed, equal to the `ident` given in the `use_decl`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:767
-msgid "Three examples of `extern mod` declarations:"
+#: doc/rust.md:775
+msgid ""
+"Optionally, an identifier in an `extern mod` declaration may be followed by "
+"an equals sign, then a string literal denoting a relative path on the "
+"filesystem. This path should exist in one of the directories in the Rust "
+"path, which by default contains the `.rust` subdirectory of the current "
+"directory and each of its parents, as well as any directories in the colon-"
+"separated (or semicolon-separated on Windows) list of paths that is the "
+"`RUST_PATH` environment variable. The meaning of `extern mod a = \"b/c/d\";"
+"`, supposing that `/a` is in the RUST_PATH, is that the name `a` should be "
+"taken as a reference to the crate whose absolute location is `/a/b/c/d`."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:777
+msgid "Four examples of `extern mod` declarations:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:770
+#: doc/rust.md:780
msgid ""
"~~~~~~~~{.xfail-test} extern mod pcre (uuid = \"54aba0f8-"
"a7b1-4beb-92f1-4cf625264841\");"
msgstr ""
#. type: Plain text
-#: doc/rust.md:772
+#: doc/rust.md:782
msgid ""
"extern mod extra; // equivalent to: extern mod extra ( name = \"extra\" );"
msgstr ""
#. type: Plain text
-#: doc/rust.md:775
+#: doc/rust.md:784
msgid ""
"extern mod rustextra (name = \"extra\"); // linking to 'extra' under another "
-"name ~~~~~~~~"
+"name"
msgstr ""
#. type: Plain text
-#: doc/rust.md:777
+#: doc/rust.md:787
+msgid "extern mod complicated_mod = \"some-file/in/the-rust/path\"; ~~~~~~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:789
msgid "##### Use declarations"
msgstr ""
#. type: Plain text
-#: doc/rust.md:781
+#: doc/rust.md:793
#, no-wrap
msgid ""
"~~~~~~~~ {.ebnf .gram}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:786
+#: doc/rust.md:798
#, no-wrap
msgid ""
"path_glob : ident [ \"::\" path_glob ] ?\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:790
+#: doc/rust.md:802
msgid ""
"A _use declaration_ creates one or more local name bindings synonymous with "
"some other [path](#paths). Usually a `use` declaration is used to shorten "
msgstr ""
#. type: Plain text
-#: doc/rust.md:794
+#: doc/rust.md:806
#, no-wrap
msgid ""
"*Note*: Unlike in many languages,\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:796
+#: doc/rust.md:808
msgid "Use declarations support a number of convenient shortcuts:"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:801
+#: doc/rust.md:813
msgid ""
"Rebinding the target name as a new local name, using the syntax `use x = p::"
"q::r;`."
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:801
+#: doc/rust.md:813
msgid ""
"Simultaneously binding a list of paths differing only in their final "
"element, using the glob-like brace syntax `use a::b::{c,d,e,f};`"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:801
+#: doc/rust.md:813
msgid ""
"Binding all paths matching a given prefix, using the asterisk wildcard "
"syntax `use a::b::*;`"
msgstr ""
#. type: Plain text
-#: doc/rust.md:803
+#: doc/rust.md:815
msgid "An example of `use` declarations:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:807
+#: doc/rust.md:819
msgid "~~~~ use std::num::sin; use std::option::{Some, None};"
msgstr ""
#. type: Plain text
-#: doc/rust.md:811
+#: doc/rust.md:823
#, no-wrap
msgid ""
"fn main() {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:816
+#: doc/rust.md:828
#, no-wrap
msgid ""
" // Equivalent to 'info!(~[std::option::Some(1.0), std::option::None]);'\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:824
+#: doc/rust.md:836
msgid ""
"Like items, `use` declarations are private to the containing module, by "
"default. Also like items, a `use` declaration can be public, if qualified "
msgstr ""
#. type: Plain text
-#: doc/rust.md:830
+#: doc/rust.md:842
#, no-wrap
msgid ""
"An example of re-exporting:\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:837
+#: doc/rust.md:849
#, no-wrap
msgid ""
" pub mod foo {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:839
+#: doc/rust.md:851
msgid ""
"In this example, the module `quux` re-exports all of the public names "
"defined in `foo`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:842
+#: doc/rust.md:854
msgid ""
"Also note that the paths contained in `use` items are relative to the crate "
"root. So, in the previous example, the `use` refers to `quux::foo::*`, and "
msgstr ""
#. type: Plain text
-#: doc/rust.md:844
+#: doc/rust.md:856
msgid "### Functions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:848
+#: doc/rust.md:860
msgid ""
"A _function item_ defines a sequence of [statements](#statements) and an "
"optional final [expression](#expressions), along with a name and a set of "
msgstr ""
#. type: Plain text
-#: doc/rust.md:853
+#: doc/rust.md:865
msgid ""
"A function may also be copied into a first class *value*, in which case the "
"value has the corresponding [*function type*](#function-types), and can be "
msgstr ""
#. type: Plain text
-#: doc/rust.md:859
+#: doc/rust.md:871
msgid ""
"Every control path in a function logically ends with a `return` expression "
"or a diverging expression. If the outermost block of a function has a value-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:861
+#: doc/rust.md:873
msgid "An example of a function:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:867
+#: doc/rust.md:879
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:870
+#: doc/rust.md:882
msgid ""
"As with `let` bindings, function arguments are irrefutable patterns, so any "
"pattern that is valid in a let binding is also valid as an argument."
msgstr ""
#. type: Plain text
-#: doc/rust.md:874
+#: doc/rust.md:886
msgid "~~~ fn first((value, _): (int, int)) -> int { value } ~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:877
+#: doc/rust.md:889
msgid "#### Generic functions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:882
+#: doc/rust.md:894
msgid ""
"A _generic function_ allows one or more _parameterized types_ to appear in "
"its signature. Each type parameter must be explicitly declared, in an angle-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:893
+#: doc/rust.md:905
#, no-wrap
msgid ""
"~~~~ {.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:896
+#: doc/rust.md:908
msgid ""
"Inside the function signature and body, the name of the type parameter can "
"be used as a type name."
msgstr ""
#. type: Plain text
-#: doc/rust.md:902
+#: doc/rust.md:914
msgid ""
"When a generic function is referenced, its type is instantiated based on the "
"context of the reference. For example, calling the `iter` function defined "
msgstr ""
#. type: Plain text
-#: doc/rust.md:907
+#: doc/rust.md:919
msgid ""
"The type parameters can also be explicitly supplied in a trailing [path]"
"(#paths) component after the function name. This might be necessary if there "
msgstr ""
#. type: Plain text
-#: doc/rust.md:912
+#: doc/rust.md:923
msgid ""
"Since a parameter type is opaque to the generic function, the set of "
"operations that can be performed on it is limited. Values of parameter type "
-"can always be moved, but they can only be copied when the parameter is given "
-"a [`Copy` bound](#type-kinds)."
+"can only be moved, not copied."
msgstr ""
#. type: Plain text
-#: doc/rust.md:916
-msgid "~~~~ fn id<T: Copy>(x: T) -> T { x } ~~~~"
+#: doc/rust.md:927
+msgid "~~~~ fn id<T>(x: T) -> T { x } ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:920
+#: doc/rust.md:931
msgid ""
"Similarly, [trait](#traits) bounds can be specified for type parameters to "
"allow methods with that trait to be called on values of that type."
msgstr ""
#. type: Plain text
-#: doc/rust.md:923
+#: doc/rust.md:934
msgid "#### Unsafe functions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:926
+#: doc/rust.md:937
msgid ""
"Unsafe functions are those containing unsafe operations that are not "
"contained in an [`unsafe` block](#unsafe-blocks). Such a function must be "
msgstr ""
#. type: Plain text
-#: doc/rust.md:929
+#: doc/rust.md:940
msgid ""
"Unsafe operations are those that potentially violate the memory-safety "
"guarantees of Rust's static semantics. Specifically, the following "
msgstr ""
#. type: Bullet: ' - '
-#: doc/rust.md:933
+#: doc/rust.md:944
msgid "Dereferencing a [raw pointer](#pointer-types)."
msgstr ""
#. type: Bullet: ' - '
-#: doc/rust.md:933
+#: doc/rust.md:944
msgid "Casting a [raw pointer](#pointer-types) to a safe pointer type."
msgstr ""
#. type: Bullet: ' - '
-#: doc/rust.md:933
+#: doc/rust.md:944
msgid "Calling an unsafe function."
msgstr ""
#. type: Plain text
-#: doc/rust.md:935
+#: doc/rust.md:946
msgid "##### Unsafe blocks"
msgstr ""
#. type: Plain text
-#: doc/rust.md:939
+#: doc/rust.md:950
msgid ""
"A block of code can also be prefixed with the `unsafe` keyword, to permit a "
"sequence of unsafe operations in an otherwise-safe function. This facility "
msgstr ""
#. type: Plain text
-#: doc/rust.md:942
+#: doc/rust.md:953
msgid "#### Diverging functions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:945
+#: doc/rust.md:956
msgid ""
"A special kind of function can be declared with a `!` character where the "
"output slot type would normally be. For example:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:952
+#: doc/rust.md:963
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:959
+#: doc/rust.md:970
msgid ""
"We call such functions \"diverging\" because they never return a value to "
"the caller. Every control path in a diverging function must end with a `fail!"
msgstr ""
#. type: Plain text
-#: doc/rust.md:965
+#: doc/rust.md:976
msgid ""
"It might be necessary to declare a diverging function because as mentioned "
"previously, the typechecker checks that every control path in a function "
msgstr ""
#. type: Plain text
-#: doc/rust.md:968
+#: doc/rust.md:979
msgid "~~~~ # fn my_err(s: &str) -> ! { fail!() }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:978
+#: doc/rust.md:989
#, no-wrap
msgid ""
"fn f(i: int) -> int {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:986
+#: doc/rust.md:997
msgid ""
"This will not compile without the `!` annotation on `my_err`, since the "
"`else` branch of the conditional in `f` does not return an `int`, as "
msgstr ""
#. type: Plain text
-#: doc/rust.md:989
+#: doc/rust.md:1000
msgid "#### Extern functions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:996
+#: doc/rust.md:1007
msgid ""
"Extern functions are part of Rust's foreign function interface, providing "
"the opposite functionality to [external blocks](#external-blocks). Whereas "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1000
+#: doc/rust.md:1011
msgid "~~~ extern fn new_vec() -> ~[int] { ~[] } ~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1003
+#: doc/rust.md:1014
msgid ""
"Extern functions may not be called from Rust code, but Rust code may take "
"their value as a raw `u8` pointer."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1008
+#: doc/rust.md:1019
msgid ""
"~~~ # extern fn new_vec() -> ~[int] { ~[] } let fptr: *u8 = new_vec; ~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1012
+#: doc/rust.md:1023
msgid ""
"The primary motivation for extern functions is to create callbacks for "
"foreign functions that expect to receive function pointers."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1014
+#: doc/rust.md:1025
msgid "### Type definitions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1018
+#: doc/rust.md:1029
msgid ""
"A _type definition_ defines a new name for an existing [type](#types). Type "
"definitions are declared with the keyword `type`. Every value has a single, "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1024
+#: doc/rust.md:1035
msgid "Whether the value is composed of sub-values or is indivisible."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1024
+#: doc/rust.md:1035
msgid "Whether the value represents textual or numerical information."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1024
+#: doc/rust.md:1035
msgid "Whether the value represents integral or floating-point information."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1024
+#: doc/rust.md:1035
msgid "The sequence of memory operations required to access the value."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1024
+#: doc/rust.md:1035
msgid "The [kind](#type-kinds) of the type."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1027
+#: doc/rust.md:1038
msgid ""
"For example, the type `(u8, u8)` defines the set of immutable values that "
"are composite pairs, each containing two unsigned 8-bit integers accessed by "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1029
+#: doc/rust.md:1040
msgid "### Structures"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1031
+#: doc/rust.md:1042
msgid ""
"A _structure_ is a nominal [structure type](#structure-types) defined with "
"the keyword `struct`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1033
+#: doc/rust.md:1044
msgid "An example of a `struct` item and its use:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1039
+#: doc/rust.md:1050
msgid ""
"~~~~ struct Point {x: int, y: int} let p = Point {x: 10, y: 11}; let px: int "
"= p.x; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1042
+#: doc/rust.md:1053
msgid ""
"A _tuple structure_ is a nominal [tuple type](#tuple-types), also defined "
"with the keyword `struct`. For example:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1048
+#: doc/rust.md:1059
msgid ""
"~~~~ struct Point(int, int); let p = Point(10, 11); let px: int = match p "
"{ Point(x, _) => x }; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1052
+#: doc/rust.md:1063
msgid ""
"A _unit-like struct_ is a structure without any fields, defined by leaving "
"off the list of fields entirely. Such types will have a single value, just "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1057
+#: doc/rust.md:1068
msgid "~~~~ struct Cookie; let c = [Cookie, Cookie, Cookie, Cookie]; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1059
+#: doc/rust.md:1070
msgid "### Enumerations"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1062
+#: doc/rust.md:1073
msgid ""
"An _enumeration_ is a simultaneous definition of a nominal [enumerated type]"
"(#enumerated-types) as well as a set of *constructors*, that can be used to "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1064
+#: doc/rust.md:1075
msgid "Enumerations are declared with the keyword `enum`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1066
+#: doc/rust.md:1077
msgid "An example of an `enum` item and its use:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1072
+#: doc/rust.md:1083
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1076
+#: doc/rust.md:1087
msgid "let mut a: Animal = Dog; a = Cat; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1083
+#: doc/rust.md:1094
#, no-wrap
msgid ""
"Enumeration constructors can have either named or unnamed fields:\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1087
+#: doc/rust.md:1098
msgid ""
"let mut a: Animal = Dog(~\"Cocoa\", 37.2); a = Cat{ name: ~\"Spotty\", "
"weight: 2.7 }; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1090
+#: doc/rust.md:1101
msgid ""
"In this example, `Cat` is a _struct-like enum variant_, whereas `Dog` is "
"simply called an enum variant."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1092
+#: doc/rust.md:1103
msgid "### Static items"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1096
+#: doc/rust.md:1107
msgid ""
"~~~~~~~~ {.ebnf .gram} static_item : \"static\" ident ':' type '=' expr "
"';' ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1103
+#: doc/rust.md:1114
msgid ""
"A *static item* is a named _constant value_ stored in the global data "
"section of a crate. Immutable static items are stored in the read-only data "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1108
+#: doc/rust.md:1119
msgid ""
"Static items must be explicitly typed. The type may be ```bool```, "
"```char```, a number, or a type derived from those primitive types. The "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1112
+#: doc/rust.md:1123
msgid "~~~~ static BIT1: uint = 1 << 0; static BIT2: uint = 1 << 1;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1115
+#: doc/rust.md:1126
msgid ""
"static BITS: [uint, ..2] = [BIT1, BIT2]; static STRING: &'static str = "
"\"bitstring\";"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1120
+#: doc/rust.md:1131
#, no-wrap
msgid ""
"struct BitsNStrings<'self> {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1126
+#: doc/rust.md:1137
#, no-wrap
msgid ""
"static bits_n_strings: BitsNStrings<'static> = BitsNStrings {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1128
+#: doc/rust.md:1139
+msgid "#### Mutable statics"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1147
+msgid ""
+"If a static item is declared with the ```mut``` keyword, then it is allowed "
+"to be modified by the program. One of Rust's goals is to make concurrency "
+"bugs hard to run into, and this is obviously a very large source of race "
+"conditions or other bugs. For this reason, an ```unsafe``` block is required "
+"when either reading or writing a mutable static variable. Care should be "
+"taken to ensure that modifications to a mutable static are safe with respect "
+"to other tasks running in the same process."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1150
+msgid ""
+"Mutable statics are still very useful, however. They can be used with C "
+"libraries and can also be bound from C libraries (in an ```extern``` block)."
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1153
+msgid "~~~ # fn atomic_add(_: &mut uint, _: uint) -> uint { 2 }"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1155
+msgid "static mut LEVELS: uint = 0;"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1163
+#, no-wrap
+msgid ""
+"// This violates the idea of no shared state, and this doesn't internally\n"
+"// protect against races, so this function is `unsafe`\n"
+"unsafe fn bump_levels_unsafe1() -> uint {\n"
+" let ret = LEVELS;\n"
+" LEVELS += 1;\n"
+" return ret;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1170
+#, no-wrap
+msgid ""
+"// Assuming that we have an atomic_add function which returns the old value,\n"
+"// this function is \"safe\" but the meaning of the return value may not be what\n"
+"// callers expect, so it's still marked as `unsafe`\n"
+"unsafe fn bump_levels_unsafe2() -> uint {\n"
+" return atomic_add(&mut LEVELS, 1);\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1172
+msgid "~~~"
+msgstr ""
+
+#. type: Plain text
+#: doc/rust.md:1174
msgid "### Traits"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1130
+#: doc/rust.md:1176
msgid "A _trait_ describes a set of method types."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1135
+#: doc/rust.md:1181
msgid ""
"Traits can include default implementations of methods, written in terms of "
"some unknown [`self` type](#self-types); the `self` type may either be "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1137
+#: doc/rust.md:1183
msgid ""
"Traits are implemented for specific types through separate [implementations]"
"(#implementations)."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1141
+#: doc/rust.md:1187
msgid "~~~~ # type Surface = int; # type BoundingBox = int;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1147
+#: doc/rust.md:1193
#, no-wrap
msgid ""
"trait Shape {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1151
+#: doc/rust.md:1197
msgid ""
"This defines a trait with two methods. All values that have "
"[implementations](#implementations) of this trait in scope can have their "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1154
+#: doc/rust.md:1200
msgid ""
"Type parameters can be specified for a trait to make it generic. These "
"appear after the trait name, using the same syntax used in [generic "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1162
+#: doc/rust.md:1208
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1168
+#: doc/rust.md:1214
msgid ""
"Generic functions may use traits as _bounds_ on their type parameters. This "
"will have two effects: only types that have the trait may instantiate the "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1172
+#: doc/rust.md:1218
msgid "~~~~ # type Surface = int; # trait Shape { fn draw(&self, Surface); }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1178
+#: doc/rust.md:1224
#, no-wrap
msgid ""
"fn draw_twice<T: Shape>(surface: Surface, sh: T) {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1183
+#: doc/rust.md:1229
msgid ""
"Traits also define an [object type](#object-types) with the same name as the "
"trait. Values of this type are created by [casting](#type-cast-expressions) "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1188
+#: doc/rust.md:1234
msgid "~~~~ # trait Shape { } # impl Shape for int { } # let mycircle = 0;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1191
+#: doc/rust.md:1237
msgid "let myshape: @Shape = @mycircle as @Shape; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1197
+#: doc/rust.md:1243
msgid ""
"The resulting value is a managed box containing the value that was cast, "
"along with information that identifies the methods of the implementation "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1205
+#: doc/rust.md:1251
msgid ""
"Trait methods may be static, which means that they lack a `self` argument. "
"This means that they can only be called with function call syntax (`f(x)`) "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1215
+#: doc/rust.md:1261
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1217
+#: doc/rust.md:1263
msgid "Traits may inherit from other traits. For example, in"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1222
+#: doc/rust.md:1268
msgid ""
"~~~~ trait Shape { fn area() -> float; } trait Circle : Shape { fn radius() -"
"> float; } ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1227
+#: doc/rust.md:1273
msgid ""
"the syntax `Circle : Shape` means that types that implement `Circle` must "
"also have an implementation for `Shape`. Multiple supertraits are separated "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1231 doc/tutorial.md:2177
+#: doc/rust.md:1277 doc/tutorial.md:2176
msgid ""
"In type-parameterized functions, methods of the supertrait may be called on "
"values of subtrait-bound type parameters. Refering to the previous example "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1240 doc/tutorial.md:2186
+#: doc/rust.md:1286 doc/tutorial.md:2185
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1242 doc/tutorial.md:2188
+#: doc/rust.md:1288 doc/tutorial.md:2187
msgid "Likewise, supertrait methods may also be called on trait objects."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1249
+#: doc/rust.md:1295
msgid ""
"~~~ {.xfail-test} # trait Shape { fn area(&self) -> float; } # trait "
"Circle : Shape { fn radius(&self) -> float; } # impl Shape for int { fn "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1253
+#: doc/rust.md:1299
msgid ""
"let mycircle: Circle = @mycircle as @Circle; let nonsense = mycircle."
"radius() * mycircle.area(); ~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1255
+#: doc/rust.md:1301
msgid "### Implementations"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1257
+#: doc/rust.md:1303
msgid ""
"An _implementation_ is an item that implements a [trait](#traits) for a "
"specific type."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1259
+#: doc/rust.md:1305
msgid "Implementations are defined with the keyword `impl`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1266
+#: doc/rust.md:1312
msgid ""
"~~~~ # struct Point {x: float, y: float}; # type Surface = int; # struct "
"BoundingBox {x: float, y: float, width: float, height: float}; # trait Shape "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1271
+#: doc/rust.md:1317
#, no-wrap
msgid ""
"struct Circle {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1281
+#: doc/rust.md:1327
#, no-wrap
msgid ""
"impl Shape for Circle {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1288
+#: doc/rust.md:1334
msgid ""
"It is possible to define an implementation without referring to a trait. "
"The methods in such an implementation can only be used as direct calls on "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1292
+#: doc/rust.md:1338
msgid ""
"When a trait _is_ specified in an `impl`, all methods declared as part of "
"the trait must be implemented, with matching types and type parameter counts."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1296
+#: doc/rust.md:1342
msgid ""
"An implementation can take type parameters, which can be different from the "
"type parameters taken by the trait it implements. Implementation parameters "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1299
+#: doc/rust.md:1345
msgid "~~~~ # trait Seq<T> { }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1307
+#: doc/rust.md:1353
#, no-wrap
msgid ""
"impl<T> Seq<T> for ~[T] {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1309
+#: doc/rust.md:1355
msgid "### External blocks"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1314
+#: doc/rust.md:1360
msgid ""
"~~~ {.ebnf .gram} extern_block_item : \"extern\" '{' extern_block '} ; "
"extern_block : [ foreign_fn ] * ; ~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1318
+#: doc/rust.md:1364
msgid ""
"External blocks form the basis for Rust's foreign function interface. "
"Declarations in an external block describe symbols in external, non-Rust "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1323
+#: doc/rust.md:1369
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1327
+#: doc/rust.md:1373
msgid "~~~ # use std::libc::{c_char, FILE}; # #[nolink]"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1332
+#: doc/rust.md:1378
#, no-wrap
msgid ""
"extern {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1337
+#: doc/rust.md:1383
msgid ""
"Functions within external blocks may be called by Rust code, just like "
"functions defined in Rust. The Rust compiler automatically translates "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1340
+#: doc/rust.md:1386
msgid ""
"A number of [attributes](#attributes) control the behavior of external "
"blocks."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1344
+#: doc/rust.md:1390
msgid ""
"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` "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1350
+#: doc/rust.md:1396
msgid ""
"~~~{.xfail-test} // Interface to the Windows API #[abi = \"stdcall\"] extern "
"{ } ~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1352
+#: doc/rust.md:1398
msgid ""
"The `link_name` attribute allows the name of the library to be specified."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1357
+#: doc/rust.md:1403
msgid "~~~{.xfail-test} #[link_name = \"crypto\"] extern { } ~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1363
+#: doc/rust.md:1409
msgid ""
"The `nolink` attribute tells the Rust compiler not to do any linking for the "
"external block. This is particularly useful for creating external blocks "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1365
+#: doc/rust.md:1411
msgid "## Attributes"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1372
+#: doc/rust.md:1418
#, no-wrap
msgid ""
"~~~~~~~~{.ebnf .gram}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1378
+#: doc/rust.md:1424
msgid ""
"Static entities in Rust -- crates, modules and items -- may have "
"_attributes_ applied to them. ^[Attributes in Rust are modeled on Attributes "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1382
+#: doc/rust.md:1428
msgid "A single identifier, the attribute name"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1382
+#: doc/rust.md:1428
msgid ""
"An identifier followed by the equals sign '=' and a literal, providing a key/"
"value pair"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1382
+#: doc/rust.md:1428
msgid ""
"An identifier followed by a parenthesized list of sub-attribute arguments"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1385
+#: doc/rust.md:1431
msgid ""
"Attributes terminated by a semi-colon apply to the entity that the attribute "
"is declared within. Attributes that are not terminated by a semi-colon apply "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1387
+#: doc/rust.md:1433
msgid "An example of attributes:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1391
+#: doc/rust.md:1437
msgid ""
"~~~~~~~~{.xfail-test} // General metadata applied to the enclosing module or "
"crate. #[license = \"BSD\"];"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1397
+#: doc/rust.md:1443
#, no-wrap
msgid ""
"// A function marked as a unit test\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1403
+#: doc/rust.md:1449
#, no-wrap
msgid ""
"// A conditionally-compiled module\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1408
+#: doc/rust.md:1454
msgid ""
"// A lint attribute used to suppress a warning/error "
"#[allow(non_camel_case_types)] pub type int8_t = i8; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1411
+#: doc/rust.md:1457
msgid ""
"> **Note:** In future versions of Rust, user-provided extensions to the "
"compiler will be able to interpret attributes. > When this facility is "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1414
+#: doc/rust.md:1460
msgid ""
"At present, only the Rust compiler interprets attributes, so all attribute "
"names are effectively reserved. Some significant attributes include:"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1425
+#: doc/rust.md:1471
msgid "The `doc` attribute, for documenting code in-place."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1425
+#: doc/rust.md:1471
msgid ""
"The `cfg` attribute, for conditional-compilation by build-configuration."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1425
+#: doc/rust.md:1471
msgid ""
"The `lang` attribute, for custom definitions of traits and functions that "
"are known to the Rust compiler (see [Language items](#language-items))."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1425
+#: doc/rust.md:1471
msgid "The `link` attribute, for describing linkage metadata for a crate."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1425
+#: doc/rust.md:1471
msgid "The `test` attribute, for marking functions as unit tests."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1425
+#: doc/rust.md:1471
msgid ""
"The `allow`, `warn`, `forbid`, and `deny` attributes, for controlling lint "
"checks (see [Lint check attributes](#lint-check-attributes))."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1425
+#: doc/rust.md:1471
msgid ""
"The `deriving` attribute, for automatically generating implementations of "
"certain traits."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1425
+#: doc/rust.md:1471
msgid ""
"The `static_assert` attribute, for asserting that a static bool is true at "
"compiletime"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1427
+#: doc/rust.md:1473
msgid ""
"Other attributes may be added or removed during development of the language."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1429
+#: doc/rust.md:1475
msgid "### Lint check attributes"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1433
+#: doc/rust.md:1479
msgid ""
"A lint check names a potentially undesirable coding pattern, such as "
"unreachable code or omitted documentation, for the static entity to which "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1435
+#: doc/rust.md:1481
msgid "For any lint check `C`:"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:1442
+#: doc/rust.md:1488
msgid "`warn(C)` warns about violations of `C` but continues compilation,"
msgstr ""
#. type: Bullet: ' * '
-#: doc/rust.md:1442
+#: doc/rust.md:1488
msgid "`deny(C)` signals an error after encountering a violation of `C`,"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1442
+#: doc/rust.md:1488
#, no-wrap
msgid ""
" * `allow(C)` overrides the check for `C` so that violations will go\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1445
+#: doc/rust.md:1491
msgid ""
"The lint checks supported by the compiler can be found via `rustc -W help`, "
"along with their default settings."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1451
+#: doc/rust.md:1497
#, no-wrap
msgid ""
"~~~{.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1455
+#: doc/rust.md:1501
#, no-wrap
msgid ""
" // Missing documentation signals a warning here\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1461
+#: doc/rust.md:1507
#, no-wrap
msgid ""
" // Missing documentation signals an error here\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1464
+#: doc/rust.md:1510
msgid ""
"This example shows how one can use `allow` and `warn` to toggle a particular "
"check on and off."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1472
+#: doc/rust.md:1518
#, no-wrap
msgid ""
-"~~~\n"
+"~~~{.xfail-test}\n"
"#[warn(missing_doc)]\n"
"mod m2{\n"
" #[allow(missing_doc)]\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1478
+#: doc/rust.md:1524
#, no-wrap
msgid ""
" // Missing documentation signals a warning here,\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1483
+#: doc/rust.md:1529
#, no-wrap
msgid ""
" // Missing documentation signals a warning here\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1486
+#: doc/rust.md:1532
msgid ""
"This example shows how one can use `forbid` to disallow uses of `allow` for "
"that lint check."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1496
+#: doc/rust.md:1542
#, no-wrap
msgid ""
"~~~{.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1498
+#: doc/rust.md:1544
msgid "### Language items"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1504
+#: doc/rust.md:1550
msgid ""
"Some primitive Rust operations are defined in Rust code, rather than being "
"implemented directly in C or assembly language. The definitions of these "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1511
+#: doc/rust.md:1557
#, no-wrap
msgid ""
"~~~ {.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1515
+#: doc/rust.md:1561
msgid ""
"The name `str_eq` has a special meaning to the Rust compiler, and the "
"presence of this definition means that it will use this definition when "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1517
+#: doc/rust.md:1563
msgid "A complete list of the built-in language items follows:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1519
+#: doc/rust.md:1565
msgid "#### Traits"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1560
+#: doc/rust.md:1604
#, no-wrap
msgid ""
"`const`\n"
" : Cannot be mutated.\n"
-"`copy`\n"
-" : Can be implicitly copied.\n"
"`owned`\n"
" : Are uniquely owned.\n"
"`durable`\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1562
+#: doc/rust.md:1606
msgid "#### Operations"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1591
+#: doc/rust.md:1636
#, no-wrap
msgid ""
"`str_eq`\n"
"`check_not_borrowed`\n"
" : Fail if a value has existing borrowed pointers to it.\n"
"`strdup_uniq`\n"
-" : Return a new unique string containing a copy of the contents of a unique string.\n"
+" : Return a new unique string\n"
+" containing a copy of the contents of a unique string.\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1594
+#: doc/rust.md:1639
msgid ""
"> **Note:** This list is likely to become out of date. We should auto-"
"generate it > from `librustc/middle/lang_items.rs`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1596
+#: doc/rust.md:1641
msgid "### Deriving"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1602
+#: doc/rust.md:1647
msgid ""
"The `deriving` attribute allows certain traits to be automatically "
"implemented for data structures. For example, the following will create an "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1610
+#: doc/rust.md:1655
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1612
+#: doc/rust.md:1657
msgid "The generated `impl` for `Eq` is equivalent to"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1619
+#: doc/rust.md:1664
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1625
+#: doc/rust.md:1670
#, no-wrap
msgid ""
" fn ne(&self, other: &Foo<T>) -> bool {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1627
+#: doc/rust.md:1672
msgid "Supported traits for `deriving` are:"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1638
+#: doc/rust.md:1683
msgid "Comparison traits: `Eq`, `TotalEq`, `Ord`, `TotalOrd`."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1638
+#: doc/rust.md:1683
msgid "Serialization: `Encodable`, `Decodable`. These require `extra`."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1638
+#: doc/rust.md:1683
msgid "`Clone` and `DeepClone`, to perform (deep) copies."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1638
+#: doc/rust.md:1683
msgid "`IterBytes`, to iterate over the bytes in a data type."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1638
+#: doc/rust.md:1683
msgid "`Rand`, to create a random instance of a data type."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1638
+#: doc/rust.md:1683
msgid "`Zero`, to create an zero (or empty) instance of a data type."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:1638
+#: doc/rust.md:1683
msgid ""
"`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 "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1640
+#: doc/rust.md:1685
msgid "# Statements and expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1647
+#: doc/rust.md:1692
msgid ""
"Rust is _primarily_ an expression language. This means that most forms of "
"value-producing or effect-causing evaluation are directed by the uniform "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1650
+#: doc/rust.md:1695
msgid ""
"In contrast, statements in Rust serve _mostly_ to contain and explicitly "
"sequence expression evaluation."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1652
+#: doc/rust.md:1697
msgid "## Statements"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1655
+#: doc/rust.md:1700
msgid ""
"A _statement_ is a component of a block, which is in turn a component of an "
"outer [expression](#expressions) or [function](#functions)."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1659
+#: doc/rust.md:1704
msgid ""
"Rust has two kinds of statement: [declaration statements](#declaration-"
"statements) and [expression statements](#expression-statements)."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1661
+#: doc/rust.md:1706
msgid "### Declaration statements"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1664
+#: doc/rust.md:1709
msgid ""
"A _declaration statement_ is one that introduces one or more *names* into "
"the enclosing statement block. The declared names may denote new slots or "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1666
+#: doc/rust.md:1711
msgid "#### Item declarations"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1673
+#: doc/rust.md:1718
msgid ""
"An _item declaration statement_ has a syntactic form identical to an [item]"
"(#items) declaration within a module. Declaring an item -- a function, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1676
+#: doc/rust.md:1721
msgid ""
"Note: there is no implicit capture of the function's dynamic environment "
"when declaring a function-local item."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1679
+#: doc/rust.md:1724
msgid "#### Slot declarations"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1684
+#: doc/rust.md:1729
msgid ""
"~~~~~~~~{.ebnf .gram} let_decl : \"let\" pat [':' type ] ? [ init ] ? ';' ; "
"init : [ '=' ] expr ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1690
+#: doc/rust.md:1735
msgid ""
"A _slot declaration_ introduces a new set of slots, given by a pattern. The "
"pattern may be followed by a type annotation, and/or an initializer "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1692
+#: doc/rust.md:1737
msgid "### Expression statements"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1697
+#: doc/rust.md:1742
msgid ""
"An _expression statement_ is one that evaluates an [expression]"
"(#expressions) and ignores its result. The type of an expression statement "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1699
+#: doc/rust.md:1744
msgid "## Expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1708
+#: doc/rust.md:1753
#, no-wrap
msgid ""
"An expression may have two roles: it always produces a *value*, and it may have *effects*\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1713
+#: doc/rust.md:1758
msgid ""
"In this way, the structure of expressions dictates the structure of "
"execution. Blocks are just another kind of expression, so blocks, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1715
+#: doc/rust.md:1760
msgid "#### Lvalues, rvalues and temporaries"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1719
+#: doc/rust.md:1764
msgid ""
"Expressions are divided into two main categories: _lvalues_ and _rvalues_. "
"Likewise within each expression, sub-expressions may occur in _lvalue "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1722
+#: doc/rust.md:1767
msgid ""
"[Path](#path-expressions), [field](#field-expressions) and [index](#index-"
"expressions) expressions are lvalues. All other expressions are rvalues."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1730
+#: doc/rust.md:1775
msgid ""
"The left operand of an [assignment](#assignment-expressions), [binary move]"
"(#binary-move-expressions) or [compound-assignment](#compound-assignment-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1733
+#: doc/rust.md:1778
msgid ""
"When an lvalue is evaluated in an _lvalue context_, it denotes a memory "
"location; when evaluated in an _rvalue context_, it denotes the value held "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1736
+#: doc/rust.md:1781
msgid ""
"When an rvalue is used in lvalue context, a temporary un-named lvalue is "
"created and used instead. A temporary's lifetime equals the largest "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1738
+#: doc/rust.md:1783
msgid "#### Moved and copied types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1744
+#: doc/rust.md:1792
msgid ""
"When a [local variable](#memory-slots) is used as an [rvalue](#lvalues-"
"rvalues-and-temporaries) the variable will either be [moved](#move-"
-"expressions) or [copied](#copy-expressions), depending on its type. For "
-"types that contain mutable fields or [owning pointers](#owning-pointers), "
-"the variable is moved. All other types are copied."
+"expressions) or copied, depending on its type. For types that contain "
+"[owning pointers](#owning-pointers) or values that implement the special "
+"trait `Drop`, the variable is moved. All other types are copied."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1747
+#: doc/rust.md:1795
msgid "### Literal expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1751
+#: doc/rust.md:1799
msgid ""
"A _literal expression_ consists of one of the [literal](#literals) forms "
"described earlier. It directly describes a number, character, string, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1758
+#: doc/rust.md:1806
#, no-wrap
msgid ""
"~~~~~~~~ {.literals}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1760
+#: doc/rust.md:1808
msgid "### Path expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1763
+#: doc/rust.md:1811
msgid ""
"A [path](#paths) used as an expression context denotes either a local "
"variable or an item. Path expressions are [lvalues](#lvalues-rvalues-and-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1765
+#: doc/rust.md:1813
msgid "### Tuple expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1769
+#: doc/rust.md:1817
msgid ""
"Tuples are written by enclosing one or more comma-separated expressions in "
"parentheses. They are used to create [tuple-typed](#tuple-types) values."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1775
+#: doc/rust.md:1823
msgid "~~~~~~~~ {.tuple} (0,); (0f, 4.5f); (\"a\", 4u, true); ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1777
+#: doc/rust.md:1825
msgid "### Structure expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1786
+#: doc/rust.md:1834
#, no-wrap
msgid ""
"~~~~~~~~{.ebnf .gram}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1793
+#: doc/rust.md:1841
msgid ""
"There are several forms of structure expressions. A _structure expression_ "
"consists of the [path](#paths) of a [structure item](#structures), followed "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1798
+#: doc/rust.md:1846
msgid ""
"A _tuple structure expression_ consists of the [path](#paths) of a "
"[structure item](#structures), followed by a parenthesized list of one or "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1800
+#: doc/rust.md:1848
msgid ""
"A _unit-like structure expression_ consists only of the [path](#paths) of a "
"[structure item](#structures)."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1802
+#: doc/rust.md:1850
msgid "The following are examples of structure expressions:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1813
+#: doc/rust.md:1861
msgid ""
"~~~~ # struct Point { x: float, y: float } # struct TuplePoint(float, "
"float); # mod game { pub struct User<'self> { name: &'self str, age: uint, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1816
+#: doc/rust.md:1864
msgid ""
"A structure expression forms a new value of the named structure type. Note "
"that for a given *unit-like* structure type, this will always be the same "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1823
+#: doc/rust.md:1871
msgid ""
"A structure expression can terminate with the syntax `..` followed by an "
"expression to denote a functional update. The expression following `..` "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1829
+#: doc/rust.md:1877
msgid ""
"~~~~ # struct Point3d { x: int, y: int, z: int } let base = Point3d {x: 1, "
"y: 2, z: 3}; Point3d {y: 0, z: 10, .. base}; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1831
+#: doc/rust.md:1879
msgid "### Record expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1837
+#: doc/rust.md:1885
#, no-wrap
msgid ""
"~~~~~~~~{.ebnf .gram}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1839
+#: doc/rust.md:1887
msgid "### Method-call expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1843
+#: doc/rust.md:1891
msgid ""
"~~~~~~~~{.ebnf .gram} method_call_expr : expr '.' ident paren_expr_list ; "
"~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1848
+#: doc/rust.md:1896
msgid ""
"A _method call_ consists of an expression followed by a single dot, an "
"identifier, and a parenthesized expression-list. Method calls are resolved "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1851
+#: doc/rust.md:1899
msgid "### Field expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1855
+#: doc/rust.md:1903
msgid "~~~~~~~~{.ebnf .gram} field_expr : expr '.' ident ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1859
+#: doc/rust.md:1907
msgid ""
"A _field expression_ consists of an expression followed by a single dot and "
"an identifier, when not immediately followed by a parenthesized expression-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1864
+#: doc/rust.md:1912
msgid "~~~~~~~~ {.field} myrecord.myfield; {a: 10, b: 20}.a; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1867
+#: doc/rust.md:1915
msgid ""
"A field access on a record is an [lvalue](#lvalues-rvalues-and-temporaries) "
"referring to the value of that field. When the field is mutable, it can be "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1870
+#: doc/rust.md:1918
msgid ""
"When the type of the expression to the left of the dot is a pointer to a "
"record or structure, it is automatically derferenced to make the field "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1873
+#: doc/rust.md:1921
msgid "### Vector expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1876
+#: doc/rust.md:1924
msgid "~~~~~~~~{.ebnf .gram} vec_expr : '[' \"mut\"? vec_elems? ']'"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1879
+#: doc/rust.md:1927
msgid "vec_elems : [expr [',' expr]*] | [expr ',' \"..\" expr] ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1882
+#: doc/rust.md:1930
msgid ""
"A [_vector_](#vector-types) _expression_ is written by enclosing zero or "
"more comma-separated expressions of uniform type in square brackets."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1886
+#: doc/rust.md:1934
msgid ""
"In the `[expr ',' \"..\" expr]` form, the expression after the `\"..\"` must "
"be a constant expression that can be evaluated at compile time, such as a "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1893
+#: doc/rust.md:1941
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1895
+#: doc/rust.md:1943
msgid "### Index expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1899
+#: doc/rust.md:1947
msgid "~~~~~~~~{.ebnf .gram} idx_expr : expr '[' expr ']' ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1904
+#: doc/rust.md:1952
msgid ""
"[Vector](#vector-types)-typed expressions can be indexed by writing a square-"
"bracket-enclosed expression (the index) after them. When the vector is "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1908
+#: doc/rust.md:1956
msgid ""
"Indices are zero-based, and may be of any integral type. Vector access is "
"bounds-checked at run-time. When the check fails, it will put the task in a "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1912
+#: doc/rust.md:1960
msgid "~~~~ # use std::task; # do task::spawn_unlinked {"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1915
+#: doc/rust.md:1963
msgid "([1, 2, 3, 4])[0]; ([\"a\", \"b\"])[10]; // fails"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1918 doc/tutorial-tasks.md:649
+#: doc/rust.md:1966 doc/tutorial-tasks.md:648
msgid "# } ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1920
+#: doc/rust.md:1968
msgid "### Unary operator expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1924
+#: doc/rust.md:1972
msgid ""
-"Rust defines six symbolic unary operators, in addition to the unary [copy]"
-"(#unary-copy-expressions) and [move](#unary-move-expressions) operators. "
-"They are all written as prefix operators, before the expression they apply "
-"to."
+"Rust defines six symbolic unary operators. They are all written as prefix "
+"operators, before the expression they apply to."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1943
+#: doc/rust.md:1991
#, no-wrap
msgid ""
"`-`\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1945
+#: doc/rust.md:1993
msgid "### Binary operator expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1949
+#: doc/rust.md:1997
msgid "~~~~~~~~{.ebnf .gram} binop_expr : expr binop expr ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1952
+#: doc/rust.md:2000
msgid ""
"Binary operators expressions are given in terms of [operator precedence]"
"(#operator-precedence)."
msgstr ""
#. type: Plain text
-#: doc/rust.md:1954
+#: doc/rust.md:2002
msgid "#### Arithmetic operators"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1959
+#: doc/rust.md:2007
msgid ""
"Binary arithmetic expressions are syntactic sugar for calls to built-in "
"traits, defined in the `std::ops` module of the `std` library. This means "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1975
+#: doc/rust.md:2023
#, no-wrap
msgid ""
"`+`\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1977
+#: doc/rust.md:2025
msgid "#### Bitwise operators"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1982
+#: doc/rust.md:2030
msgid ""
"Like the [arithmetic operators](#arithmetic-operators), bitwise operators "
"are syntactic sugar for calls to methods of built-in traits. This means "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1998
+#: doc/rust.md:2046
#, no-wrap
msgid ""
"`&`\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2000
+#: doc/rust.md:2048
msgid "#### Lazy boolean operators"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2007
+#: doc/rust.md:2055
msgid ""
"The operators `||` and `&&` may be applied to operands of boolean type. The "
"`||` operator denotes logical 'or', and the `&&` operator denotes logical "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2009
+#: doc/rust.md:2057
msgid "#### Comparison operators"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2015
+#: doc/rust.md:2063
msgid ""
"Comparison operators are, like the [arithmetic operators](#arithmetic-"
"operators), and [bitwise operators](#bitwise-operators), syntactic sugar for "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2034
+#: doc/rust.md:2082
#, no-wrap
msgid ""
"`==`\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2037
+#: doc/rust.md:2085
msgid "#### Type cast expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2039
+#: doc/rust.md:2087
msgid "A type cast expression is denoted with the binary operator `as`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2042
+#: doc/rust.md:2090
msgid ""
"Executing an `as` expression casts the value on the left-hand side to the "
"type on the right-hand side."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2046
+#: doc/rust.md:2094
msgid ""
"A numeric value can be cast to any numeric type. A raw pointer value can be "
"cast to or from any integral type or raw pointer type. Any other cast is "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2048
+#: doc/rust.md:2096
msgid "An example of an `as` expression:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2052
+#: doc/rust.md:2100
msgid ""
"~~~~ # fn sum(v: &[float]) -> float { 0.0 } # fn len(v: &[float]) -> int "
"{ 0 }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2059
+#: doc/rust.md:2107
#, no-wrap
msgid ""
"fn avg(v: &[float]) -> float {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2061
+#: doc/rust.md:2109
msgid "#### Assignment expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2064
+#: doc/rust.md:2112
msgid ""
"An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-"
"temporaries) expression followed by an equals sign (`=`) and an [rvalue]"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2066
+#: doc/rust.md:2114
msgid ""
"Evaluating an assignment expression [either copies or moves](#moved-and-"
"copied-types) its right-hand operand to its left-hand operand."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2070
+#: doc/rust.md:2118
msgid "~~~~ # let mut x = 0; # let y = 0;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2073
+#: doc/rust.md:2121
msgid "x = y; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2075
+#: doc/rust.md:2123
msgid "#### Compound assignment expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2080
+#: doc/rust.md:2128
msgid ""
"The `+`, `-`, `*`, `/`, `%`, `&`, `|`, `^`, `<<`, and `>>` operators may be "
"composed with the `=` operator. The expression `lval OP= val` is equivalent "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2082
+#: doc/rust.md:2130
msgid "Any such expression always has the [`unit`](#primitive-types) type."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2084
+#: doc/rust.md:2132
msgid "#### Operator precedence"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2087
+#: doc/rust.md:2135
msgid ""
"The precedence of Rust binary operators is ordered as follows, going from "
"strong to weak:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2100
+#: doc/rust.md:2148
#, no-wrap
msgid ""
"~~~~ {.precedence}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2102 doc/rust.md:2243 doc/tutorial-macros.md:323
+#: doc/rust.md:2150 doc/rust.md:2237 doc/tutorial-macros.md:323
msgid "~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2105
+#: doc/rust.md:2153
msgid ""
"Operators at the same precedence level are evaluated left-to-right. [Unary "
"operators](#unary-operator-expressions) have the same precedence level and "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2107
+#: doc/rust.md:2155
msgid "### Grouped expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2111
+#: doc/rust.md:2159
msgid ""
"An expression enclosed in parentheses evaluates to the result of the "
"enclosed expression. Parentheses can be used to explicitly specify "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2115
+#: doc/rust.md:2163
msgid "~~~~~~~~{.ebnf .gram} paren_expr : '(' expr ')' ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2117
+#: doc/rust.md:2165
msgid "An example of a parenthesized expression:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2121
+#: doc/rust.md:2169
msgid "~~~~ let x = (2 + 3) * 4; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2123
-msgid "### Unary copy expressions"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2127
-msgid "~~~~~~~~{.ebnf .gram} copy_expr : \"copy\" expr ; ~~~~~~~~"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2130
-msgid ""
-"> **Note:** `copy` expressions are deprecated. It's preferable to use > the "
-"`Clone` trait and `clone()` method."
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2133
-msgid ""
-"A _unary copy expression_ consists of the unary `copy` operator applied to "
-"some argument expression."
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2137
-msgid ""
-"Evaluating a copy expression first evaluates the argument expression, then "
-"copies the resulting value, allocating any memory necessary to hold the new "
-"copy."
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2141
-msgid ""
-"[Managed boxes](#pointer-types) (type `@`) are, as usual, shallow-copied, as "
-"are raw and borrowed pointers. [Owned boxes](#pointer-types), [owned "
-"vectors](#vector-types) and similar owned types are deep-copied."
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2144
-msgid ""
-"Since the binary [assignment operator](#assignment-expressions) `=` performs "
-"a copy or move implicitly, the unary copy operator is typically only used to "
-"cause an argument to a function to be copied and passed by value."
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2146
-msgid "An example of a copy expression:"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2151
-#, no-wrap
-msgid ""
-"~~~~\n"
-"fn mutate(mut vec: ~[int]) {\n"
-" vec[0] = 10;\n"
-"}\n"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2153
-msgid "let v = ~[1,2,3];"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2155
-#, no-wrap
-msgid "mutate(copy v); // Pass a copy\n"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2158
-msgid "assert!(v[0] == 1); // Original was not modified ~~~~"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2160
-msgid "### Unary move expressions"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2164
-msgid "~~~~~~~~{.ebnf .gram} move_expr : \"move\" expr ; ~~~~~~~~"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2171
-msgid ""
-"A _unary move expression_ is similar to a [unary copy](#unary-copy-"
-"expressions) expression, except that it can only be applied to a [local "
-"variable](#memory-slots), and it performs a _move_ on its operand, rather "
-"than a copy. That is, the memory location denoted by its operand is de-"
-"initialized after evaluation, and the resulting value is a shallow copy of "
-"the operand, even if the operand is an [owning type](#type-kinds)."
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2175
-msgid ""
-"> **Note:** In future versions of Rust, `move` may be removed as a separate "
-"operator; > moves are now [automatically performed](#moved-and-copied-types) "
-"for most cases `move` would be appropriate."
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2178
+#: doc/rust.md:2172
msgid "### Call expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2184
+#: doc/rust.md:2178
msgid ""
"~~~~~~~~ {.abnf .gram} expr_list : [ expr [ ',' expr ]* ] ? ; "
"paren_expr_list : '(' expr_list ')' ; call_expr : expr paren_expr_list ; "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2189
+#: doc/rust.md:2183
msgid ""
"A _call expression_ invokes a function, providing zero or more input slots "
"and an optional reference slot to serve as the function's output, bound to "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2191
+#: doc/rust.md:2185
msgid "Some examples of call expressions:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2195
+#: doc/rust.md:2189
msgid ""
"~~~~ # use std::from_str::FromStr; # fn add(x: int, y: int) -> int { 0 }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2199
+#: doc/rust.md:2193
msgid ""
"let x: int = add(1, 2); let pi = FromStr::from_str::<f32>(\"3.14\"); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2201
+#: doc/rust.md:2195
msgid "### Lambda expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2206
+#: doc/rust.md:2200
msgid ""
"~~~~~~~~ {.abnf .gram} ident_list : [ ident [ ',' ident ]* ] ? ; "
"lambda_expr : '|' ident_list '|' expr ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2210
+#: doc/rust.md:2204
msgid ""
"A _lambda expression_ (sometimes called an \"anonymous function expression"
"\") defines a function and denotes it as a value, in a single expression. A "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2215
+#: doc/rust.md:2209
msgid ""
"A lambda expression denotes a function that maps a list of parameters "
"(`ident_list`) onto the expression that follows the `ident_list`. The "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2218
+#: doc/rust.md:2212
msgid ""
"Lambda expressions are most useful when passing functions as arguments to "
"other functions, as an abbreviation for defining and capturing a separate "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2227
+#: doc/rust.md:2221
msgid ""
"Significantly, lambda expressions _capture their environment_, which regular "
"[function definitions](#functions) do not. The exact type of capture "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2230
+#: doc/rust.md:2224
msgid ""
"In this example, we define a function `ten_times` that takes a higher-order "
"function argument, and call it with a lambda expression as an argument."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2239
+#: doc/rust.md:2233
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2241
+#: doc/rust.md:2235
msgid "ten_times(|j| println(fmt!(\"hello, %d\", j)));"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2245
+#: doc/rust.md:2239
msgid "### While loops"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2249
+#: doc/rust.md:2243
msgid ""
"~~~~~~~~{.ebnf .gram} while_expr : \"while\" expr '{' block '}' ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2254
+#: doc/rust.md:2248
msgid ""
"A `while` loop begins by evaluating the boolean loop conditional "
"expression. If the loop conditional expression evaluates to `true`, the "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2256
+#: doc/rust.md:2250
msgid "An example:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2259
+#: doc/rust.md:2253
msgid "~~~~ let mut i = 0;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2265
+#: doc/rust.md:2259
#, no-wrap
msgid ""
"while i < 10 {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2267
+#: doc/rust.md:2261
msgid "### Infinite loops"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2271
+#: doc/rust.md:2265
msgid ""
"The keyword `loop` in Rust appears both in _loop expressions_ and in "
"_continue expressions_. A loop expression denotes an infinite loop; see "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2275
+#: doc/rust.md:2269
msgid ""
"~~~~~~~~{.ebnf .gram} loop_expr : [ lifetime ':' ] \"loop\" '{' block '}'; "
"~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2280
+#: doc/rust.md:2274
msgid ""
"A `loop` expression may optionally have a _label_. If a label is present, "
"then labeled `break` and `loop` expressions nested within this loop may exit "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2282
+#: doc/rust.md:2276
msgid "### Break expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2286
+#: doc/rust.md:2280
msgid "~~~~~~~~{.ebnf .gram} break_expr : \"break\" [ lifetime ]; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2293
+#: doc/rust.md:2287
msgid ""
"A `break` expression has an optional `label`. If the label is absent, then "
"executing a `break` expression immediately terminates the innermost loop "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2295
+#: doc/rust.md:2289
msgid "### Continue expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2299
+#: doc/rust.md:2293
msgid "~~~~~~~~{.ebnf .gram} continue_expr : \"loop\" [ lifetime ]; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2310
+#: doc/rust.md:2304
msgid ""
"A continue expression, written `loop`, also has an optional `label`. If the "
"label is absent, then executing a `loop` expression immediately terminates "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2312
+#: doc/rust.md:2306
msgid "A `loop` expression is only permitted in the body of a loop."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2315
+#: doc/rust.md:2309
msgid "### Do expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2319
+#: doc/rust.md:2313
msgid ""
"~~~~~~~~{.ebnf .gram} do_expr : \"do\" expr [ '|' ident_list '|' ] ? '{' "
"block '}' ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2322
+#: doc/rust.md:2316
msgid ""
"A _do expression_ provides a more-familiar block-syntax for a [lambda "
"expression](#lambda-expressions), including a special translation of [return "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2330
+#: doc/rust.md:2324
msgid ""
"Any occurrence of a [return expression](#return-expressions) inside this "
"`block` expression is rewritten as a reference to an (anonymous) flag set in "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2333
+#: doc/rust.md:2327
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2339
+#: doc/rust.md:2333
msgid ""
"The lambda expression is then provided as a _trailing argument_ to the "
"outermost [call](#call-expressions) or [method call](#method-call-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2341
+#: doc/rust.md:2335
msgid "In this example, both calls to `f` are equivalent:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2345
+#: doc/rust.md:2339
msgid "~~~~ # fn f(f: &fn(int)) { } # fn g(i: int) { }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2347
+#: doc/rust.md:2341
msgid "f(|j| g(j));"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2352
+#: doc/rust.md:2346
#, no-wrap
msgid ""
"do f |j| {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2354
+#: doc/rust.md:2348
msgid ""
"In this example, both calls to the (binary) function `k` are equivalent:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2358
+#: doc/rust.md:2352
msgid "~~~~ # fn k(x:int, f: &fn(int)) { } # fn l(i: int) { }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2360
+#: doc/rust.md:2354
msgid "k(3, |j| l(j));"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2365
+#: doc/rust.md:2359
#, no-wrap
msgid ""
"do k(3) |j| {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2368
+#: doc/rust.md:2362
msgid "### For expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2372
+#: doc/rust.md:2366
msgid ""
"~~~~~~~~{.ebnf .gram} for_expr : \"for\" expr [ '|' ident_list '|' ] ? '{' "
"block '}' ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2376
+#: doc/rust.md:2370
msgid ""
"A _for expression_ is similar to a [`do` expression](#do-expressions), in "
"that it provides a special block-form of lambda expression, suited to "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2382
+#: doc/rust.md:2376
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2389
+#: doc/rust.md:2383
msgid ""
"In addition, [`break`](#break-expressions) and [`loop`](#loop-expressions) "
"expressions are rewritten inside `for` expressions in the same way that "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2391
+#: doc/rust.md:2385
msgid "An example of a for loop over the contents of a vector:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2398
+#: doc/rust.md:2392
msgid ""
"~~~~ # type foo = int; # fn bar(f: foo) { } # let a = 0; # let b = 0; # let "
"c = 0;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2400
+#: doc/rust.md:2394
msgid "let v: &[foo] = &[a, b, c];"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2405
+#: doc/rust.md:2399
#, no-wrap
msgid ""
"for e in v.iter() {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2407
+#: doc/rust.md:2401
msgid "An example of a for loop over a series of integers:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2415
+#: doc/rust.md:2408
#, no-wrap
msgid ""
"~~~~\n"
-"# use std::uint;\n"
"# fn bar(b:uint) { }\n"
-"for uint::range(0, 256) |i| {\n"
+"for i in range(0u, 256) {\n"
" bar(i);\n"
"}\n"
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2417
+#: doc/rust.md:2410
msgid "### If expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2421
+#: doc/rust.md:2414
#, no-wrap
msgid ""
"~~~~~~~~{.ebnf .gram}\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2425
+#: doc/rust.md:2418
#, no-wrap
msgid ""
"else_tail : \"else\" [ if_expr\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2436
+#: doc/rust.md:2429
msgid ""
"An `if` expression is a conditional branch in program control. The form of "
"an `if` expression is a condition expression, followed by a consequent "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2439
+#: doc/rust.md:2432
msgid "### Match expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2442
+#: doc/rust.md:2435
msgid ""
"~~~~~~~~{.ebnf .gram} match_expr : \"match\" expr '{' match_arm [ '|' "
"match_arm ] * '}' ;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2444
+#: doc/rust.md:2437
msgid "match_arm : match_pat '=>' [ expr \",\" | '{' block '}' ] ;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2447
+#: doc/rust.md:2440
msgid "match_pat : pat [ \"..\" pat ] ? [ \"if\" expr ] ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2455
+#: doc/rust.md:2448
msgid ""
"A `match` expression branches on a *pattern*. The exact form of matching "
"that occurs depends on the pattern. Patterns consist of some combination of "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2459
+#: doc/rust.md:2452
msgid ""
"In a pattern whose head expression has an `enum` type, a placeholder (`_`) "
"stands for a *single* data field, whereas a wildcard `*` stands for *all* "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2462
+#: doc/rust.md:2455
msgid "~~~~ enum List<X> { Nil, Cons(X, @List<X>) }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2464 doc/rust.md:2493
+#: doc/rust.md:2457 doc/rust.md:2486
msgid "let x: List<int> = Cons(10, @Cons(11, @Nil));"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2471
+#: doc/rust.md:2464
#, no-wrap
msgid ""
"match x {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2476
+#: doc/rust.md:2469
msgid ""
"The first pattern matches lists constructed by applying `Cons` to any head "
"value, and a tail value of `@Nil`. The second pattern matches _any_ list "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2482
+#: doc/rust.md:2475
msgid ""
"To execute an `match` expression, first the head expression is evaluated, "
"then its value is sequentially compared to the patterns in the arms until a "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2484
+#: doc/rust.md:2477
msgid "An example of an `match` expression:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2489
+#: doc/rust.md:2482
msgid "~~~~ # fn process_pair(a: int, b: int) { } # fn process_ten() { }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2491
+#: doc/rust.md:2484
msgid "enum List<X> { Nil, Cons(X, @List<X>) }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2509
+#: doc/rust.md:2502
#, no-wrap
msgid ""
"match x {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2515
+#: doc/rust.md:2509
msgid ""
"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```."
+"matched value (depending on the matched value's type). This can be changed "
+"to bind to a borrowed pointer by using the ```ref``` keyword, or to a "
+"mutable borrowed pointer using ```ref mut```."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2526
+#: doc/rust.md:2520
msgid ""
"A pattern that's just an identifier, like `Nil` in the previous answer, "
"could either refer to an enum variant that's in scope, or bind a new "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2530
+#: doc/rust.md:2524
msgid ""
"Multiple match patterns may be joined with the `|` operator. A range of "
"values may be specified with `..`. For example:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2533
+#: doc/rust.md:2527
msgid "~~~~ # let x = 2;"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2540
+#: doc/rust.md:2534
#, no-wrap
msgid ""
"let message = match x {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2544
+#: doc/rust.md:2538
msgid ""
"Range patterns only work on scalar types (like integers and characters; not "
"like vectors and structs, which have sub-components). A range pattern may "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2549
+#: doc/rust.md:2543
msgid ""
"Finally, match patterns can accept *pattern guards* to further refine the "
"criteria for matching a case. Pattern guards appear after the pattern and "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2554
+#: doc/rust.md:2548
msgid ""
"~~~~ # let maybe_digit = Some(0); # fn process_digit(i: int) { } # fn "
"process_other(i: int) { }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2561
+#: doc/rust.md:2555
#, no-wrap
msgid ""
"let message = match maybe_digit {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2563
+#: doc/rust.md:2557
msgid "### Return expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2567
+#: doc/rust.md:2561
msgid "~~~~~~~~{.ebnf .gram} return_expr : \"return\" expr ? ; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2572
+#: doc/rust.md:2566
msgid ""
"Return expressions are denoted with the keyword `return`. Evaluating a "
"`return` expression moves its argument into the output slot of the current "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2574
+#: doc/rust.md:2568
msgid "An example of a `return` expression:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2583
+#: doc/rust.md:2577
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2586
+#: doc/rust.md:2580
msgid "# Type system"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2588
+#: doc/rust.md:2582
msgid "## Types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2591
+#: doc/rust.md:2585
msgid ""
"Every slot, item and value in a Rust program has a type. The _type_ of a "
"*value* defines the interpretation of the memory holding it."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2595
+#: doc/rust.md:2589
msgid ""
"Built-in types and type-constructors are tightly integrated into the "
"language, in nontrivial ways that are not possible to emulate in user-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2597
+#: doc/rust.md:2591
msgid "### Primitive types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2599
+#: doc/rust.md:2593
msgid "The primitive types are the following:"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:2605
+#: doc/rust.md:2599
msgid ""
"The \"unit\" type `()`, having the single \"unit\" value `()` (occasionally "
"called \"nil\"). ^[The \"unit\" value `()` is *not* a sentinel \"null "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:2605
+#: doc/rust.md:2599
msgid "The boolean type `bool` with values `true` and `false`."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:2605
+#: doc/rust.md:2599
msgid "The machine types."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:2605
+#: doc/rust.md:2599
msgid "The machine-dependent integer and floating-point types."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2607
+#: doc/rust.md:2601
msgid "#### Machine types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2609
+#: doc/rust.md:2603
msgid "The machine types are the following:"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:2614
+#: doc/rust.md:2608
msgid ""
"The unsigned word types `u8`, `u16`, `u32` and `u64`, with values drawn from "
"the integer intervals $[0, 2^8 - 1]$, $[0, 2^{16} - 1]$, $[0, 2^{32} - 1]$ "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:2619
+#: doc/rust.md:2613
msgid ""
"The signed two's complement word types `i8`, `i16`, `i32` and `i64`, with "
"values drawn from the integer intervals $[-(2^7), 2^7 - 1]$, $[-(2^{15}), "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:2622
+#: doc/rust.md:2616
msgid ""
"The IEEE 754-2008 `binary32` and `binary64` floating-point types: `f32` and "
"`f64`, respectively."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2624
+#: doc/rust.md:2618
msgid "#### Machine-dependent integer types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2629
+#: doc/rust.md:2623
msgid ""
"The Rust type `uint`^[A Rust `uint` is analogous to a C99 `uintptr_t`.] is "
"an unsigned integer type with target-machine-dependent size. Its size, in "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2634
+#: doc/rust.md:2628
msgid ""
"The Rust type `int`^[A Rust `int` is analogous to a C99 `intptr_t`.] is a "
"two's complement signed integer type with target-machine-dependent size. Its "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2637
+#: doc/rust.md:2631
msgid "#### Machine-dependent floating point type"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2644
+#: doc/rust.md:2638
msgid ""
"The Rust type `float` is a machine-specific type equal to one of the "
"supported Rust floating-point machine types (`f32` or `f64`). It is the "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2647
+#: doc/rust.md:2641
msgid ""
"Note that due to the preference for hardware-supported floating-point, the "
"type `float` may not be equal to the largest *supported* floating-point type."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2650
+#: doc/rust.md:2644
msgid "### Textual types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2652
+#: doc/rust.md:2646
msgid "The types `char` and `str` hold textual data."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2655
+#: doc/rust.md:2649
msgid ""
"A value of type `char` is a Unicode character, represented as a 32-bit "
"unsigned word holding a UCS-4 codepoint."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2661
+#: doc/rust.md:2655
msgid ""
"A value of type `str` is a Unicode string, represented as a vector of 8-bit "
"unsigned bytes holding a sequence of UTF-8 codepoints. Since `str` is of "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2664
+#: doc/rust.md:2658
msgid "### Tuple types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2667
+#: doc/rust.md:2661
msgid ""
"The tuple type-constructor forms a new heterogeneous product of values "
"similar to the record type-constructor. The differences are as follows:"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:2670
+#: doc/rust.md:2664
msgid "tuple elements cannot be mutable, unlike record fields"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:2670
+#: doc/rust.md:2664
msgid ""
"tuple elements are not named and can be accessed only by pattern-matching"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2674
+#: doc/rust.md:2668
msgid ""
"Tuple types and values are denoted by listing the types or values of their "
"elements, respectively, in a parenthesized, comma-separated list."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2677
+#: doc/rust.md:2671
msgid ""
"The members of a tuple are laid out in memory contiguously, like a record, "
"in order specified by the tuple type."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2679
+#: doc/rust.md:2673
msgid "An example of a tuple type and its use:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2686
+#: doc/rust.md:2680
msgid ""
"~~~~ type Pair<'self> = (int,&'self str); let p: Pair<'static> = (10,\"hello"
"\"); let (a, b) = p; assert!(b != \"world\"); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2689
+#: doc/rust.md:2683
msgid "### Vector types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2702
+#: doc/rust.md:2696
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2706
+#: doc/rust.md:2700
msgid ""
"Expressions producing vectors of definite size cannot be evaluated in a "
"context expecting a vector of indefinite size; one must copy the definite-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2708
+#: doc/rust.md:2702
msgid "An example of a vector type and its use:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2714
+#: doc/rust.md:2708
msgid ""
"~~~~ let v: &[int] = &[7, 5, 3]; let i: int = v[2]; assert!(i == 3); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2717
+#: doc/rust.md:2711
msgid ""
"All in-bounds elements of a vector are always initialized, and access to a "
"vector is always bounds-checked."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2720
+#: doc/rust.md:2714
msgid "### Structure types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2725
+#: doc/rust.md:2719
msgid ""
"A `struct` *type* is a heterogeneous product of other types, called the "
"*fields* of the type. ^[`struct` types are analogous `struct` types in C, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2727
+#: doc/rust.md:2721
msgid ""
"New instances of a `struct` can be constructed with a [struct expression]"
"(#struct-expressions)."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2731
+#: doc/rust.md:2725
msgid ""
"The memory order of fields in a `struct` is given by the item defining it. "
"Fields may be given in any order in a corresponding struct *expression*; the "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2734
+#: doc/rust.md:2728
msgid ""
"The fields of a `struct` may be qualified by [visibility modifiers]"
"(#visibility-modifiers), to restrict access to implementation-private data "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2736
+#: doc/rust.md:2730
msgid ""
"A _tuple struct_ type is just like a structure type, except that the fields "
"are anonymous."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2739
+#: doc/rust.md:2733
msgid ""
"A _unit-like struct_ type is like a structure type, except that it has no "
"fields. The one value constructed by the associated [structure expression]"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2741
+#: doc/rust.md:2735
msgid "### Enumerated types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2746
+#: doc/rust.md:2740
msgid ""
"An *enumerated type* is a nominal, heterogeneous disjoint union type, "
"denoted by the name of an [`enum` item](#enumerations). ^[The `enum` type "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2749
+#: doc/rust.md:2743
msgid ""
"An [`enum` item](#enumerations) declares both the type and a number of "
"*variant constructors*, each of which is independently named and takes an "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2752
+#: doc/rust.md:2746
msgid ""
"New instances of an `enum` can be constructed by calling one of the variant "
"constructors, in a [call expression](#call-expressions)."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2754
+#: doc/rust.md:2748
msgid ""
"Any `enum` value consumes as much memory as the largest variant constructor "
"for its corresponding `enum` type."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2757
+#: doc/rust.md:2751
msgid ""
"Enum types cannot be denoted *structurally* as types, but must be denoted by "
"named reference to an [`enum` item](#enumerations)."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2760
+#: doc/rust.md:2754
msgid "### Recursive types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2764
+#: doc/rust.md:2758
msgid ""
"Nominal types -- [enumerations](#enumerated-types) and [structures]"
"(#structure-types) -- may be recursive. That is, each `enum` constructor or "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2774
+#: doc/rust.md:2768
#, no-wrap
msgid ""
"* Recursive types must include a nominal type in the recursion\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2776
+#: doc/rust.md:2770
msgid "An example of a *recursive* type and its use:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2782
+#: doc/rust.md:2776
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2785
+#: doc/rust.md:2779
msgid "let a: List<int> = Cons(7, @Cons(13, @Nil)); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2788
+#: doc/rust.md:2782
msgid "### Pointer types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2792
+#: doc/rust.md:2786
msgid ""
"All pointers in Rust are explicit first-class values. They can be copied, "
"stored into data structures, and returned from functions. There are four "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2802
+#: doc/rust.md:2796
#, no-wrap
msgid ""
"Managed pointers (`@`)\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2811
+#: doc/rust.md:2805
#, no-wrap
msgid ""
"Owning pointers (`~`)\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2824
+#: doc/rust.md:2818
#, no-wrap
msgid ""
"Borrowed pointers (`&`)\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2834
+#: doc/rust.md:2828
#, no-wrap
msgid ""
"Raw pointers (`*`)\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2837
+#: doc/rust.md:2831
msgid "### Function types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2841
+#: doc/rust.md:2835
msgid ""
"The function type constructor `fn` forms new function types. A function "
"type consists of a possibly-empty set of function-type modifiers (such as "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2843
+#: doc/rust.md:2837
msgid "An example of a `fn` type:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2848
+#: doc/rust.md:2842
#, no-wrap
msgid ""
"~~~~~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2850
+#: doc/rust.md:2844
msgid "let mut x = add(5,7);"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2855
+#: doc/rust.md:2849
msgid ""
"type Binop<'self> = &'self fn(int,int) -> int; let bo: Binop = add; x = "
"bo(5,7); ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2857
+#: doc/rust.md:2851
msgid "### Object types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2864
+#: doc/rust.md:2858
msgid ""
"Every trait item (see [traits](#traits)) defines a type with the same name "
"as the trait. This type is called the _object type_ of the trait. Object "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2869
+#: doc/rust.md:2863
msgid ""
"Given a pointer-typed expression `E` of type `&T`, `~T` or `@T`, where `T` "
"implements trait `R`, casting `E` to the corresponding pointer type `&R`, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:2871
+#: doc/rust.md:2865
msgid "An example of an object type:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2877
+#: doc/rust.md:2871
#, no-wrap
msgid ""
"~~~~~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2881
+#: doc/rust.md:2875
#, no-wrap
msgid ""
"impl Printable for int {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2885
+#: doc/rust.md:2879
#, no-wrap
msgid ""
"fn print(a: @Printable) {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2890
+#: doc/rust.md:2884
#, no-wrap
msgid ""
"fn main() {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2893
+#: doc/rust.md:2887
msgid ""
"In this example, the trait `Printable` occurs as an object type in both the "
"type signature of `print`, and the cast expression in `main`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2895
+#: doc/rust.md:2889
msgid "### Type parameters"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2897
+#: doc/rust.md:2891
msgid ""
"Within the body of an item that has type parameter declarations, the names "
"of its type parameters are types:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2906
+#: doc/rust.md:2902
#, no-wrap
msgid ""
"~~~~~~~\n"
-"fn map<A: Copy, B: Copy>(f: &fn(A) -> B, xs: &[A]) -> ~[B] {\n"
-" if xs.len() == 0 { return ~[]; }\n"
-" let first: B = f(copy xs[0]);\n"
-" let rest: ~[B] = map(f, xs.slice(1, xs.len()));\n"
-" return ~[first] + rest;\n"
+"fn map<A: Clone, B: Clone>(f: &fn(A) -> B, xs: &[A]) -> ~[B] {\n"
+" if xs.len() == 0 {\n"
+" return ~[];\n"
+" }\n"
+" let first: B = f(xs[0].clone());\n"
+" let rest: ~[B] = map(f, xs.slice(1, xs.len()));\n"
+" return ~[first] + rest;\n"
"}\n"
"~~~~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2909
+#: doc/rust.md:2905
msgid ""
"Here, `first` has type `B`, referring to `map`'s `B` type parameter; and "
"`rest` has type `~[B]`, a vector type with element type `B`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2911
+#: doc/rust.md:2907
msgid "### Self types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2915
+#: doc/rust.md:2911
msgid ""
"The special type `self` has a meaning within methods inside an impl item. It "
"refers to the type of the implicit `self` argument. For example, in:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2920
+#: doc/rust.md:2916
#, no-wrap
msgid ""
"~~~~~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2925
+#: doc/rust.md:2923
#, no-wrap
msgid ""
"impl Printable for ~str {\n"
-" fn make_string(&self) -> ~str { copy *self }\n"
+" fn make_string(&self) -> ~str {\n"
+" (*self).clone()\n"
+" }\n"
"}\n"
"~~~~~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2928
+#: doc/rust.md:2926
msgid ""
"`self` refers to the value of type `~str` that is the receiver for a call to "
"the method `make_string`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2930
+#: doc/rust.md:2928
msgid "## Type kinds"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2933
+#: doc/rust.md:2931
msgid ""
"Types in Rust are categorized into kinds, based on various properties of the "
"components of the type. The kinds are:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2953
+#: doc/rust.md:2957
#, no-wrap
msgid ""
"`Freeze`\n"
" : Types of this kind are deeply immutable;\n"
-" they contain no mutable memory locations directly or indirectly via pointers.\n"
+" they contain no mutable memory locations\n"
+" directly or indirectly via pointers.\n"
"`Send`\n"
" : Types of this kind can be safely sent between tasks.\n"
" This kind includes scalars, owning pointers, owned closures, and\n"
-" structural types containing only other owned types. All `Send` types are `Static`.\n"
-"`Copy`\n"
-" : This kind includes all types that can be copied. All types with\n"
-" sendable kind are copyable, as are managed boxes, managed closures,\n"
-" trait types, and structural types built out of these.\n"
-" Types with destructors (types that implement `Drop`) can not implement `Copy`.\n"
+" structural types containing only other owned types.\n"
+" All `Send` types are `'static`.\n"
+"`'static`\n"
+" : Types of this kind do not contain any borrowed pointers;\n"
+" this can be a useful guarantee for code\n"
+" that breaks borrowing assumptions\n"
+" using [`unsafe` operations](#unsafe-functions).\n"
"`Drop`\n"
-" : This is not strictly a kind, but its presence interacts with kinds: the `Drop`\n"
-" trait provides a single method `drop` that takes no parameters, and is run\n"
-" when values of the type are dropped. Such a method is called a \"destructor\",\n"
-" and are always executed in \"top-down\" order: a value is completely destroyed\n"
-" before any of the values it owns run their destructors. Only `Send` types\n"
-" that do not implement `Copy` can implement `Drop`.\n"
+" : This is not strictly a kind,\n"
+" but its presence interacts with kinds:\n"
+" the `Drop` trait provides a single method `drop`\n"
+" that takes no parameters,\n"
+" and is run when values of the type are dropped.\n"
+" Such a method is called a \"destructor\",\n"
+" and are always executed in \"top-down\" order:\n"
+" a value is completely destroyed\n"
+" before any of the values it owns run their destructors.\n"
+" Only `Send` types can implement `Drop`.\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2960
+#: doc/rust.md:2964
#, no-wrap
msgid ""
"_Default_\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2963
+#: doc/rust.md:2967
msgid ""
"Kinds can be supplied as _bounds_ on type parameters, like traits, in which "
"case the parameter is constrained to types satisfying that kind."
msgstr ""
-#. type: Plain text
-#: doc/rust.md:2965
-msgid ""
-"By default, type parameters do not carry any assumed kind-bounds at all."
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2969
-msgid ""
-"Any operation that causes a value to be copied requires the type of that "
-"value to be of copyable kind, so the `Copy` bound is frequently required on "
-"function type parameters. For example, this is not a valid program:"
-msgstr ""
-
#. type: Plain text
#: doc/rust.md:2973
-msgid "~~~~{.xfail-test} fn box<T>(x: T) -> @T { @x } ~~~~"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2976
msgid ""
-"Putting `x` into a managed box involves copying, and the `T` parameter has "
-"the default (non-copyable) kind. To change that, a bound is declared:"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2980
-msgid "~~~~ fn box<T: Copy>(x: T) -> @T { @x } ~~~~"
-msgstr ""
-
-#. type: Plain text
-#: doc/rust.md:2985
-msgid ""
-"Calling this second version of `box` on a noncopyable type is not allowed. "
+"By default, type parameters do not carry any assumed kind-bounds at all. "
"When instantiating a type parameter, the kind bounds on the parameter are "
"checked to be the same or narrower than the kind of the type that it is "
"instantiated with."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2989
+#: doc/rust.md:2978
msgid ""
"Sending operations are not part of the Rust language, but are implemented in "
-"the library. Generic functions that send values bound the kind of these "
+"the library. Generic functions that send values bound the kind of these "
"values to sendable."
msgstr ""
#. type: Plain text
-#: doc/rust.md:2991
+#: doc/rust.md:2980
msgid "# Memory and concurrency models"
msgstr ""
#. type: Plain text
-#: doc/rust.md:2996
+#: doc/rust.md:2985
msgid ""
"Rust has a memory model centered around concurrently-executing _tasks_. Thus "
"its memory model and its concurrency model are best discussed "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3001
+#: doc/rust.md:2990
msgid ""
"When reading about the memory model, keep in mind that it is partitioned in "
"order to support tasks; and when reading about tasks, keep in mind that "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3003
+#: doc/rust.md:2992
msgid "## Memory model"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3007
+#: doc/rust.md:2996
msgid ""
"A Rust program's memory consists of a static set of *items*, a set of [tasks]"
"(#tasks) each with its own *stack*, and a *heap*. Immutable portions of the "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3010
+#: doc/rust.md:2999
msgid ""
"Allocations in the stack consist of *slots*, and allocations in the heap "
"consist of *boxes*."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3013
+#: doc/rust.md:3002
msgid "### Memory allocation and lifetime"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3018
+#: doc/rust.md:3007
msgid ""
"The _items_ of a program are those functions, modules and types that have "
"their value calculated at compile-time and stored uniquely in the memory "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3022
+#: doc/rust.md:3011
msgid ""
"A task's _stack_ consists of activation frames automatically allocated on "
"entry to each function as the task executes. A stack allocation is reclaimed "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3029
+#: doc/rust.md:3018
msgid ""
"The _heap_ is a general term that describes two separate sets of boxes: "
"managed boxes -- which may be subject to garbage collection -- and owned "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3031
+#: doc/rust.md:3020
msgid "### Memory ownership"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3034
+#: doc/rust.md:3023
msgid ""
"A task owns all memory it can *safely* reach through local variables, as "
"well as managed, owning and borrowed pointers."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3041
+#: doc/rust.md:3030
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3044
+#: doc/rust.md:3033
msgid ""
"When a stack frame is exited, its local allocations are all released, and "
"its references to boxes (both managed and owned) are dropped."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3050
+#: doc/rust.md:3039
msgid ""
"A managed box may (in the case of a recursive, mutable managed type) be "
"cyclic; in this case the release of memory inside the managed structure may "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3053
+#: doc/rust.md:3042
msgid ""
"When a task finishes, its stack is necessarily empty and it therefore has no "
"references to any boxes; the remainder of its heap is immediately freed."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3056
+#: doc/rust.md:3045
msgid "### Memory slots"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3058
+#: doc/rust.md:3047
msgid "A task's stack contains slots."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3061
+#: doc/rust.md:3050
msgid ""
"A _slot_ is a component of a stack frame, either a function parameter, a "
"[temporary](#lvalues-rvalues-and-temporaries), or a local variable."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3064
+#: doc/rust.md:3053
msgid ""
"A _local variable_ (or *stack-local* allocation) holds a value directly, "
"allocated within the stack's memory. The value is a part of the stack frame."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3069
+#: doc/rust.md:3058
msgid ""
"Local variables are immutable unless declared with `let mut`. The `mut` "
"keyword applies to all local variables declared within that declaration (so "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3074
+#: doc/rust.md:3063
msgid ""
"Function parameters are immutable unless declared with `mut`. The `mut` "
"keyword applies only to the following parameter (so `|mut x, y|` and `fn "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3080
+#: doc/rust.md:3069
msgid ""
"Local variables are not initialized when allocated; the entire frame worth "
"of local variables are allocated at once, on frame-entry, in an "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3083
+#: doc/rust.md:3072
msgid "### Memory boxes"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3086
+#: doc/rust.md:3075
msgid ""
"A _box_ is a reference to a heap allocation holding another value. There are "
"two kinds of boxes: *managed boxes* and *owned boxes*."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3088
+#: doc/rust.md:3077
msgid ""
"A _managed box_ type or value is constructed by the prefix *at* sigil `@`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3090
+#: doc/rust.md:3079
msgid ""
"An _owned box_ type or value is constructed by the prefix *tilde* sigil `~`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3095
+#: doc/rust.md:3084
msgid ""
"Multiple managed box values can point to the same heap allocation; copying a "
"managed box value makes a shallow copy of the pointer (optionally "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3099
+#: doc/rust.md:3086
msgid ""
-"Owned box values exist in 1:1 correspondence with their heap allocation; "
-"copying an owned box value makes a deep copy of the heap allocation and "
-"produces a pointer to the new allocation."
+"Owned box values exist in 1:1 correspondence with their heap allocation."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3102
+#: doc/rust.md:3089
msgid ""
"An example of constructing one managed box type and value, and one owned box "
"type and value:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3107
+#: doc/rust.md:3094
msgid "~~~~~~~~ let x: @int = @10; let x: ~int = ~10; ~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3110
+#: doc/rust.md:3097
msgid ""
"Some operations (such as field selection) implicitly dereference boxes. An "
"example of an _implicit dereference_ operation performed on box values:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3116
+#: doc/rust.md:3103
msgid ""
"~~~~~~~~ struct Foo { y: int } let x = @Foo{y: 10}; assert!(x.y == 10); "
"~~~~~~~~"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3122
+#: doc/rust.md:3109
msgid ""
"Other operations act on box values as single-word-sized address values. For "
"these operations, to access the value held in the box requires an explicit "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3125
+#: doc/rust.md:3112
msgid "copying box values (`x = y`)"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3125
+#: doc/rust.md:3112
msgid "passing box values to functions (`f(x,y)`)"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3128
+#: doc/rust.md:3115
msgid ""
"An example of an explicit-dereference operation performed on box values:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3132
+#: doc/rust.md:3119
msgid "~~~~~~~~ fn takes_boxed(b: @int) { }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3135
+#: doc/rust.md:3122
msgid "fn takes_unboxed(b: int) { }"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3142
+#: doc/rust.md:3129
#, no-wrap
msgid ""
"fn main() {\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3144
+#: doc/rust.md:3131
msgid "## Tasks"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3152
+#: doc/rust.md:3139
msgid ""
"An executing Rust program consists of a tree of tasks. A Rust _task_ "
"consists of an entry function, a stack, a set of outgoing communication "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3167
+#: doc/rust.md:3154
msgid ""
"Multiple Rust tasks may coexist in a single operating-system process. The "
"runtime scheduler maps tasks to a certain number of operating-system "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3170
+#: doc/rust.md:3157
msgid "### Communication between tasks"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3175
+#: doc/rust.md:3162
msgid ""
"Rust tasks are isolated and generally unable to interfere with one another's "
"memory directly, except through [`unsafe` code](#unsafe-functions). All "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3178
+#: doc/rust.md:3165
msgid ""
"Inter-task communication and co-ordination facilities are provided in the "
"standard library. These include:"
msgstr ""
#. type: Bullet: ' - '
-#: doc/rust.md:3182
+#: doc/rust.md:3169
msgid ""
"synchronous and asynchronous communication channels with various "
"communication topologies"
msgstr ""
#. type: Bullet: ' - '
-#: doc/rust.md:3182
+#: doc/rust.md:3169
msgid ""
"read-only and read-write shared variables with various safe mutual exclusion "
"patterns"
msgstr ""
#. type: Bullet: ' - '
-#: doc/rust.md:3182
+#: doc/rust.md:3169
msgid "simple locks and semaphores"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3187
+#: doc/rust.md:3174
msgid ""
"When such facilities carry values, the values are restricted to the [`Send` "
"type-kind](#type-kinds). Restricting communication interfaces to this kind "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3190
+#: doc/rust.md:3177
msgid "### Task lifecycle"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3193
+#: doc/rust.md:3180
msgid ""
"The _lifecycle_ of a task consists of a finite set of states and events that "
"cause transitions between the states. The lifecycle states of a task are:"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3198
+#: doc/rust.md:3185
msgid "running"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3198
+#: doc/rust.md:3185
msgid "blocked"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3198
+#: doc/rust.md:3185
msgid "failing"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3198
+#: doc/rust.md:3185
msgid "dead"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3202
+#: doc/rust.md:3189
msgid ""
"A task begins its lifecycle -- once it has been spawned -- in the *running* "
"state. In this state it executes the statements of its entry function, and "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3208
+#: doc/rust.md:3195
msgid ""
"A task may transition from the *running* state to the *blocked* state any "
"time it makes a blocking communication call. When the call can be completed "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3227
+#: doc/rust.md:3214
msgid ""
"A task may transition to the *failing* state at any time, due being killed "
"by some external event or internally, from the evaluation of a `fail!()` "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3231
+#: doc/rust.md:3218
msgid ""
"A task in the *dead* state cannot transition to other states; it exists only "
"to have its termination status inspected by other tasks, and/or to await "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3234
+#: doc/rust.md:3221
msgid "### Task scheduling"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3238
+#: doc/rust.md:3225
msgid ""
"The currently scheduled task is given a finite *time slice* in which to "
"execute, after which it is *descheduled* at a loop-edge or similar "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3242
+#: doc/rust.md:3229
msgid ""
"An executing task can yield control at any time, by making a library call to "
"`std::task::yield`, which deschedules it immediately. Entering any other non-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3245
+#: doc/rust.md:3232
msgid "# Runtime services, linkage and debugging"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3252
+#: doc/rust.md:3239
msgid ""
"The Rust _runtime_ is a relatively compact collection of C++ and Rust code "
"that provides fundamental services and datatypes to all Rust tasks at run-"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3254
+#: doc/rust.md:3241
msgid ""
"> **Note:** The runtime library will merge with the `std` library in future "
"versions of Rust."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3256
+#: doc/rust.md:3243
msgid "### Memory allocation"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3262
+#: doc/rust.md:3249
msgid ""
"The runtime memory-management system is based on a _service-provider "
"interface_, through which the runtime requests blocks of memory from its "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3266
+#: doc/rust.md:3253
msgid ""
"The runtime memory-management system, in turn, supplies Rust tasks with "
"facilities for allocating, extending and releasing stacks, as well as "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3268
+#: doc/rust.md:3255
msgid "### Built in types"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3272
+#: doc/rust.md:3259
msgid ""
"The runtime provides C and Rust code to assist with various built-in types, "
"such as vectors, strings, and the low level communication system (ports, "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3275
+#: doc/rust.md:3262
msgid ""
"Support for other built-in types such as simple types, tuples, records, and "
"enums is open-coded by the Rust compiler."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3279
+#: doc/rust.md:3266
msgid "### Task scheduling and communication"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3285
+#: doc/rust.md:3272
msgid ""
"The runtime provides code to manage inter-task communication. This includes "
"the system of task-lifecycle state transitions depending on the contents of "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3288
+#: doc/rust.md:3275
msgid "### Logging system"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3292
+#: doc/rust.md:3279
msgid ""
"The runtime contains a system for directing [logging expressions](#log-"
"expressions) to a logging console and/or internal logging buffers. Logging "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3299
+#: doc/rust.md:3286
msgid ""
"Logging output is enabled by setting the `RUST_LOG` environment variable. "
"`RUST_LOG` accepts a logging specification made up of a comma-separated list "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3307
+#: doc/rust.md:3294
msgid ""
"The path to a module consists of the crate name, any parent modules, then "
"the module itself, all separated by double colons (`::`). The optional log "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3313
+#: doc/rust.md:3300
msgid ""
"As an example, to see all the logs generated by the compiler, you would set "
"`RUST_LOG` to `rustc`, which is the crate name (as specified in its `link` "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3318
+#: doc/rust.md:3305
msgid ""
-"Note that when compiling either `.rs` or `.rc` files that don't specify a "
-"crate name the crate is given a default name that matches the source file, "
-"with the extension removed. In that case, to turn on logging for a program "
-"compiled from, e.g. `helloworld.rs`, `RUST_LOG` should be set to "
-"`helloworld`."
+"Note that when compiling source files that don't specify a crate name the "
+"crate is given a default name that matches the source file, with the "
+"extension removed. In that case, to turn on logging for a program compiled "
+"from, e.g. `helloworld.rs`, `RUST_LOG` should be set to `helloworld`."
msgstr ""
#. type: Plain text
-#: doc/rust.md:3322
+#: doc/rust.md:3309
msgid ""
"As a convenience, the logging spec can also be set to a special pseudo-"
"crate, `::help`. In this case, when the application starts, the runtime will "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3327
+#: doc/rust.md:3314
msgid ""
"The Rust runtime itself generates logging information. The runtime's logs "
"are generated for a number of artificial modules in the `::rt` pseudo-crate, "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::mem` Memory management"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::comm` Messaging and task communication"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::task` Task management"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::dom` Task scheduling"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::trace` Unused"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::cache` Type descriptor cache"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::upcall` Compiler-generated runtime calls"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::timer` The scheduler timer"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::gc` Garbage collection"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::stdlib` Functions used directly by the standard library"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::kern` The runtime kernel"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::backtrace` Log a backtrace on task failure"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3341
+#: doc/rust.md:3328
msgid "`::rt::callback` Unused"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3343
+#: doc/rust.md:3330
msgid "#### Logging Expressions"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3346
+#: doc/rust.md:3333
msgid ""
"Rust provides several macros to log information. Here's a simple Rust "
"program that demonstrates all four of them:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3355
+#: doc/rust.md:3342
#, no-wrap
msgid ""
"```rust\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3357
+#: doc/rust.md:3344
msgid ""
"These four log levels correspond to levels 1-4, as controlled by `RUST_LOG`:"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3364
+#: doc/rust.md:3351
msgid ""
"```bash $ RUST_LOG=rust=3 ./rust rust: ~\"\\\"This is an error log\\\"\" "
"rust: ~\"\\\"This is a warn log\\\"\" rust: ~\"\\\"this is an info log\\\"\" "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3366
+#: doc/rust.md:3353
msgid "# Appendix: Rationales and design tradeoffs"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3368
+#: doc/rust.md:3355
#, no-wrap
msgid "*TODO*.\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3370
+#: doc/rust.md:3357
msgid "# Appendix: Influences and further references"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3372
+#: doc/rust.md:3359
msgid "## Influences"
msgstr ""
#. type: Plain text
-#: doc/rust.md:3381
+#: doc/rust.md:3368
msgid ""
"> The essential problem that must be solved in making a fault-tolerant > "
"software system is therefore that of fault-isolation. Different programmers "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3393
+#: doc/rust.md:3380
msgid ""
"> In our approach, all data is private to some process, and processes can > "
"only communicate through communications channels. *Security*, as used > in "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3401
+#: doc/rust.md:3388
msgid ""
"> Concurrent and applicative programming complement each other. The > "
"ability to send messages on channels provides I/O without side effects, > "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3408
+#: doc/rust.md:3395
msgid ""
"Rust is not a particularly original language. It may however appear unusual "
"by contemporary standards, as its design elements are drawn from a number of "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3412
+#: doc/rust.md:3399
msgid ""
"The NIL (1981) and Hermes (1990) family. These languages were developed by "
"Robert Strom, Shaula Yemini, David Bacon and others in their group at IBM "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3416
+#: doc/rust.md:3403
msgid ""
"The Erlang (1987) language, developed by Joe Armstrong, Robert Virding, "
"Claes Wikström, Mike Williams and others in their group at the Ericsson "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3421
+#: doc/rust.md:3408
msgid ""
"The Sather (1990) language, developed by Stephen Omohundro, Chu-Cheow Lim, "
"Heinz Schmidt and others in their group at The International Computer "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3426
+#: doc/rust.md:3413
msgid ""
"The Newsqueak (1988), Alef (1995), and Limbo (1996) family. These languages "
"were developed by Rob Pike, Phil Winterbottom, Sean Dorward and others in "
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3430
+#: doc/rust.md:3417
msgid ""
"The Napier (1985) and Napier88 (1988) family. These languages were developed "
"by Malcolm Atkinson, Ron Morrison and others in their group at the "
msgstr ""
#. type: Plain text
-#: doc/rust.md:3432
+#: doc/rust.md:3419
msgid ""
"Additional specific influences can be seen from the following languages:"
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3440
+#: doc/rust.md:3427
msgid "The stack-growth implementation of Go."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3440
+#: doc/rust.md:3427
msgid "The structural algebraic types and compilation manager of SML."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3440
+#: doc/rust.md:3427
msgid "The attribute and assembly systems of C#."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3440
+#: doc/rust.md:3427
msgid "The references and deterministic destructor system of C++."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3440
+#: doc/rust.md:3427
msgid "The memory region systems of the ML Kit and Cyclone."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3440
+#: doc/rust.md:3427
msgid "The typeclass system of Haskell."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3440
+#: doc/rust.md:3427
msgid "The lexical identifier rule of Python."
msgstr ""
#. type: Bullet: '* '
-#: doc/rust.md:3440
+#: doc/rust.md:3427
msgid "The block syntax of Ruby."
msgstr ""
msgid ""
msgstr ""
"Project-Id-Version: Rust 0.8-pre\n"
-"POT-Creation-Date: 2013-07-17 07:18+0900\n"
+"POT-Creation-Date: 2013-07-30 07:07+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#. type: Plain text
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:79
+#: doc/rustpkg.md:87
msgid ""
"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 "
"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."
+"error otherwise. A package ID can also specify a particular revision of a "
+"repository, like: `github.com/mozilla/rust#release-0.7`. When the refspec "
+"(portion of the package ID after the `#`) can't be parsed as a decimal "
+"number, rustpkg passes the refspec along to the version control system "
+"without interpreting it. rustpkg also interprets any dependencies on such a "
+"package ID literally (as opposed to versions, where a newer version "
+"satisfies a dependency on an older version). Thus, `github.com/mozilla/"
+"rust#5c4cd30f80` is also a valid package ID, since git can deduce that "
+"5c4cd30f80 refers to a revision of the desired repository."
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:81
+#: doc/rustpkg.md:89
msgid "## Source files"
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:83
+#: doc/rustpkg.md:91
msgid ""
"rustpkg searches for four different fixed filenames in order to determine "
"the crates to build:"
msgstr ""
#. type: Bullet: '* '
-#: doc/rustpkg.md:88
+#: doc/rustpkg.md:96
msgid "`main.rs`: Assumed to be a main entry point for building an executable."
msgstr ""
#. type: Bullet: '* '
-#: doc/rustpkg.md:88
+#: doc/rustpkg.md:96
msgid "`lib.rs`: Assumed to be a library crate."
msgstr ""
#. type: Bullet: '* '
-#: doc/rustpkg.md:88
+#: doc/rustpkg.md:96
msgid ""
"`test.rs`: Assumed to contain tests declared with the `#[test]` attribute."
msgstr ""
#. type: Bullet: '* '
-#: doc/rustpkg.md:88
+#: doc/rustpkg.md:96
msgid ""
"`bench.rs`: Assumed to contain benchmarks declared with the `#[bench]` "
"attribute."
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:90
+#: doc/rustpkg.md:98
msgid "## Versions"
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:97
+#: doc/rustpkg.md:105
msgid ""
"`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 "
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:99
+#: doc/rustpkg.md:107
msgid "# Dependencies"
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:103
+#: doc/rustpkg.md:111
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:105
+#: doc/rustpkg.md:113
msgid "# Custom build scripts"
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:109
+#: doc/rustpkg.md:117
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:113
+#: doc/rustpkg.md:121
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:115
+#: doc/rustpkg.md:123
msgid "# Command reference"
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:117
+#: doc/rustpkg.md:125
msgid "## build"
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:123
+#: doc/rustpkg.md:131
msgid ""
"`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 "
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:125
+#: doc/rustpkg.md:133
msgid "## clean"
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:127
+#: doc/rustpkg.md:135
msgid "`rustpkg clean foo` deletes the contents of `foo`'s `build` directory."
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:129
+#: doc/rustpkg.md:137
msgid "## install"
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:133
+#: doc/rustpkg.md:141
msgid ""
"`rustpkg install foo` builds the libraries and/or executables that are "
"targets for `foo`, and then installs them either into `foo`'s `lib` and "
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:135
+#: doc/rustpkg.md:143
msgid "## test"
msgstr ""
#. type: Plain text
-#: doc/rustpkg.md:137
+#: doc/rustpkg.md:145
msgid ""
"`rustpkg test foo` builds `foo`'s `test.rs` file if necessary, then runs the "
"resulting test executable."
msgid ""
msgstr ""
"Project-Id-Version: Rust 0.8-pre\n"
-"POT-Creation-Date: 2013-07-17 07:18+0900\n"
+"POT-Creation-Date: 2013-07-22 23:37+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#. type: Plain text
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1111 doc/tutorial-borrowed-ptr.md:72
+#: doc/tutorial.md:1108 doc/tutorial-borrowed-ptr.md:72
msgid "Now we can call `compute_distance()` in various ways:"
msgstr ""
msgid ""
"Although borrowed pointers have rather elaborate theoretical underpinnings "
"(region pointers), the core concepts will be familiar to anyone who has "
-"worked with C or C++. Therefore, the best way to explain how they are "
-"usedand their limitationsis probably just to work through several examples."
+"worked with C or C++. Therefore, the best way to explain how they are used—"
+"and their limitations—is probably just to work through several examples."
msgstr ""
#. type: Plain text
"any two points, no matter where they were stored. For example, we might like "
"to 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 "
+"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 "
"expensive. Worse, if the data type contains mutable fields, copying can "
#. type: Plain text
#: doc/tutorial-borrowed-ptr.md:186
msgid ""
-"Weve seen a few examples so far of borrowing heap boxes, both managed and "
-"owned. Up till this point, weve glossed over issues of safety. As stated in "
+"We’ve seen a few examples so far of borrowing heap boxes, both managed 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."
#. type: Plain text
#: doc/tutorial-borrowed-ptr.md:376
msgid ""
-"As an example, lets look at the following `shape` type that can represent "
+"As an example, let’s look at the following `shape` type that can represent "
"both rectangles and circles:"
msgstr ""
#: doc/tutorial-borrowed-ptr.md:483
msgid ""
"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 "
+"“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 as we'll see, doing so "
"requires some explicit annotation."
msgid ""
"Named lifetimes that appear in function signatures are conceptually the same "
"as the other lifetimes we have seen before, but they are a bit abstract: "
-"they dont refer to a specific expression within `get_x()`, but rather to "
+"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 by the caller to "
"`get_x()`, just as the value for the parameter `p` is defined by that caller."
#. type: Plain text
#: doc/tutorial-borrowed-ptr.md:526
msgid ""
-"To emphasize this point, lets look at a variation on the example, this time "
+"To emphasize this point, let’s look at a variation on the example, this time "
"one that does not compile:"
msgstr ""
msgid ""
msgstr ""
"Project-Id-Version: Rust 0.8-pre\n"
-"POT-Creation-Date: 2013-07-17 07:18+0900\n"
+"POT-Creation-Date: 2013-08-05 19:40+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#. type: Plain text
#: doc/tutorial-container.md:112
msgid ""
"Containers implement iteration over the contained elements by returning an "
-"iterator object. For example, vector slices have four iterators available:"
+"iterator object. For example, vector slices several iterators available:"
msgstr ""
#. type: Bullet: '* '
-#: doc/tutorial-container.md:117
-msgid "`vector.iter()`, for immutable references to the elements"
+#: doc/tutorial-container.md:116
+msgid "`iter()` and `rev_iter()`, for immutable references to the elements"
msgstr ""
#. type: Bullet: '* '
-#: doc/tutorial-container.md:117
-msgid "`vector.mut_iter()`, for mutable references to the elements"
+#: doc/tutorial-container.md:116
+msgid ""
+"`mut_iter()` and `mut_rev_iter()`, for mutable references to the elements"
msgstr ""
#. type: Bullet: '* '
-#: doc/tutorial-container.md:117
+#: doc/tutorial-container.md:116
msgid ""
-"`vector.rev_iter()`, for immutable references to the elements in reverse "
-"order"
+"`consume_iter()` and `consume_rev_iter`, to move the elements out by-value"
msgstr ""
-#. type: Bullet: '* '
-#: doc/tutorial-container.md:117
+#. type: Plain text
+#: doc/tutorial-container.md:119
msgid ""
-"`vector.mut_rev_iter()`, for mutable references to the elements in reverse "
-"order"
+"A typical mutable container will implement at least `iter()`, `mut_iter()` "
+"and `consume_iter()` along with the reverse variants if it maintains an "
+"order."
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:119
+#: doc/tutorial-container.md:121
msgid "### Freezing"
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:123
+#: doc/tutorial-container.md:125
msgid ""
"Unlike most other languages with external iterators, Rust has no *iterator "
"invalidation*. As long an iterator is still in scope, the compiler will "
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:128
+#: doc/tutorial-container.md:130
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:134
+#: doc/tutorial-container.md:136
#, no-wrap
msgid ""
" // the vector is frozen for this scope, the compiler will statically\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:137
+#: doc/tutorial-container.md:139
msgid ""
"These semantics are due to most container iterators being implemented with "
"`&` and `&mut`."
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:139
+#: doc/tutorial-container.md:141
msgid "## Iterator adaptors"
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:143
+#: doc/tutorial-container.md:145
msgid ""
"The `IteratorUtil` trait implements common algorithms as methods extending "
"every `Iterator` implementation. For example, the `fold` method will "
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:149
+#: doc/tutorial-container.md:151
msgid ""
"~~~ let xs = [1, 9, 2, 3, 14, 12]; let result = xs.iter().fold(0, |"
"accumulator, item| accumulator - *item); assert_eq!(result, -41); ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:151
+#: doc/tutorial-container.md:153
msgid ""
"Some adaptors return an adaptor object implementing the `Iterator` trait "
"itself:"
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:158
+#: doc/tutorial-container.md:160
msgid ""
"~~~ 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); ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:162
+#: doc/tutorial-container.md:164
msgid ""
"Note that some adaptors like the `chain_` method above use a trailing "
"underscore to work around an issue with method resolve. The underscores will "
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:164
+#: doc/tutorial-container.md:166
msgid "## For loops"
msgstr ""
#. type: Plain text
#: doc/tutorial-container.md:168
msgid ""
-"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."
+"The `for` keyword can be used as sugar for iterating through any iterator:"
msgstr ""
#. type: Plain text
msgid ""
"// print out the pairs of elements up to (&3, &\"baz\")\n"
"for (x, y) in it {\n"
-" println(fmt!(\"%d %s\", *x, *y));\n"
+" printfln!(\"%d %s\", *x, *y);\n"
msgstr ""
#. type: Plain text
#. type: Plain text
#: doc/tutorial-container.md:204
msgid ""
-"// yield and print the last pair from the iterator println(fmt!(\"last: %?"
-"\", it.next()));"
+"// yield and print the last pair from the iterator printfln!(\"last: %?\", "
+"it.next());"
msgstr ""
#. type: Plain text
#, no-wrap
msgid ""
"~~~\n"
-"impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {\n"
-" pub fn from_iterator(iterator: &mut T) -> ~[A] {\n"
+"impl<A> FromIterator<A> for ~[A] {\n"
+" pub fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {\n"
" let (lower, _) = iterator.size_hint();\n"
" let mut xs = with_capacity(lower);\n"
" for x in iterator {\n"
#. type: Plain text
#: doc/tutorial-container.md:300
msgid ""
-"~~~ let xs = [1, 2, 3, 4, 5, 6]; let mut it = xs.iter(); println(fmt!(\"%?"
-"\", it.next())); // prints `Some(&1)` println(fmt!(\"%?\", it.next())); // "
-"prints `Some(&2)` println(fmt!(\"%?\", it.next_back())); // prints `Some(&6)`"
+"~~~ let xs = [1, 2, 3, 4, 5, 6]; let mut it = xs.iter(); printfln!(\"%?\", "
+"it.next()); // prints `Some(&1)` printfln!(\"%?\", it.next()); // prints "
+"`Some(&2)` printfln!(\"%?\", it.next_back()); // prints `Some(&6)`"
msgstr ""
#. type: Plain text
msgid ""
"// prints `5`, `4` and `3`\n"
"for &x in it.invert() {\n"
-" println(fmt!(\"%?\", x))\n"
+" printfln!(\"%?\", x)\n"
"}\n"
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-container.md:308
+#: doc/tutorial-container.md:309
msgid ""
"The `rev_iter` and `mut_rev_iter` methods on vectors just return an inverted "
"version of the standard immutable and mutable vector iterators."
msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:312
+msgid ""
+"The `chain_`, `transform`, `filter`, `filter_map` and `peek` adaptors are "
+"`DoubleEndedIterator` implementations if the underlying iterators are."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:317
+msgid ""
+"~~~ let xs = [1, 2, 3, 4]; let ys = [5, 6, 7, 8]; let mut it = xs.iter()."
+"chain_(ys.iter()).transform(|&x| x * 2);"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:319
+msgid "printfln!(\"%?\", it.next()); // prints `Some(2)`"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:325
+#, no-wrap
+msgid ""
+"// prints `16`, `14`, `12`, `10`, `8`, `6`, `4`\n"
+"for x in it.invert() {\n"
+" printfln!(\"%?\", x);\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:327
+msgid "## Random-access iterators"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:331
+msgid ""
+"The `RandomAccessIterator` trait represents an iterator offering random "
+"access to the whole range. The `indexable` method retrieves the number of "
+"elements accessible with the `idx` method."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:334
+msgid ""
+"The `chain_` adaptor is an implementation of `RandomAccessIterator` if the "
+"underlying iterators are."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:343
+msgid ""
+"~~~ let xs = [1, 2, 3, 4, 5]; let ys = ~[7, 9, 11]; let mut it = xs.iter()."
+"chain_(ys.iter()); printfln!(\"%?\", it.idx(0)); // prints `Some(&1)` "
+"printfln!(\"%?\", it.idx(5)); // prints `Some(&7)` printfln!(\"%?\", it."
+"idx(7)); // prints `Some(&11)` printfln!(\"%?\", it.idx(8)); // prints `None`"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:348
+msgid ""
+"// yield two elements from the beginning, and one from the end it.next(); it."
+"next(); it.next_back();"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-container.md:352
+msgid ""
+"printfln!(\"%?\", it.idx(0)); // prints `Some(&3)` printfln!(\"%?\", it."
+"idx(4)); // prints `Some(&9)` printfln!(\"%?\", it.idx(6)); // prints `None` "
+"~~~"
+msgstr ""
msgid ""
msgstr ""
"Project-Id-Version: Rust 0.8-pre\n"
-"POT-Creation-Date: 2013-07-17 07:18+0900\n"
+"POT-Creation-Date: 2013-08-10 07:44+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#. type: Plain text
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:876 doc/tutorial-ffi.md:143
+#: doc/tutorial.md:868 doc/tutorial-ffi.md:143
msgid "# Destructors"
msgstr ""
#. type: Plain text
#: doc/tutorial-ffi.md:232
+msgid "# Accessing foreign globals"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:236
+msgid ""
+"Foreign APIs often export a global variable which could do something like "
+"track global state. In order to access these variables, you declare them in "
+"`extern` blocks with the `static` keyword:"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:239
+msgid "~~~{.xfail-test} use std::libc;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:244
+#, no-wrap
+msgid ""
+"#[link_args = \"-lreadline\"]\n"
+"extern {\n"
+" static rl_readline_version: libc::c_int;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:250
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" println(fmt!(\"You have readline version %d installed.\",\n"
+" rl_readline_version as int));\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:254
+msgid ""
+"Alternatively, you may need to alter global state provided by a foreign "
+"interface. To do this, statics can be declared with `mut` so rust can mutate "
+"them."
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:258
+msgid "~~~{.xfail-test} use std::libc; use std::ptr;"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:263
+#, no-wrap
+msgid ""
+"#[link_args = \"-lreadline\"]\n"
+"extern {\n"
+" static mut rl_prompt: *libc::c_char;\n"
+"}\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:272
+#, no-wrap
+msgid ""
+"fn main() {\n"
+" do \"[my-awesome-shell] $\".as_c_str |buf| {\n"
+" unsafe { rl_prompt = buf; }\n"
+" // get a line, process it\n"
+" unsafe { rl_prompt = ptr::null(); }\n"
+" }\n"
+"}\n"
+"~~~\n"
+msgstr ""
+
+#. type: Plain text
+#: doc/tutorial-ffi.md:274
msgid "# Foreign calling conventions"
msgstr ""
#. type: Plain text
-#: doc/tutorial-ffi.md:237
+#: doc/tutorial-ffi.md:279
msgid ""
"Most foreign code exposes a C ABI, and Rust uses the platform's C calling "
"convention by default when calling foreign functions. Some foreign "
msgstr ""
#. type: Plain text
-#: doc/tutorial-ffi.md:246
+#: doc/tutorial-ffi.md:288
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-ffi.md:250
+#: doc/tutorial-ffi.md:292
msgid ""
"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 `"
msgstr ""
#. type: Plain text
-#: doc/tutorial-ffi.md:252
+#: doc/tutorial-ffi.md:294
msgid "# Interoperability with foreign code"
msgstr ""
#. type: Plain text
-#: doc/tutorial-ffi.md:256
+#: doc/tutorial-ffi.md:298
msgid ""
"Rust guarantees that the layout of a `struct` is compatible with the "
"platform's representation in C. A `#[packed]` attribute is available, which "
msgstr ""
#. type: Plain text
-#: doc/tutorial-ffi.md:263
+#: doc/tutorial-ffi.md:305
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/tutorial-ffi.md:268
+#: doc/tutorial-ffi.md:310
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/tutorial-ffi.md:270
+#: doc/tutorial-ffi.md:312
msgid ""
"The standard library includes type aliases and function definitions for the "
"C standard library in the `libc` module, and Rust links against `libc` and "
msgid ""
msgstr ""
"Project-Id-Version: Rust 0.8-pre\n"
-"POT-Creation-Date: 2013-07-17 07:18+0900\n"
+"POT-Creation-Date: 2013-07-22 23:37+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#. type: Plain text
msgstr ""
#. type: Plain text
-#: doc/rust.md:2033 doc/rust.md:2174 doc/tutorial-macros.md:323
+#: doc/rust.md:2136 doc/rust.md:2223 doc/tutorial-macros.md:323
msgid "~~~~"
msgstr ""
msgid ""
msgstr ""
"Project-Id-Version: Rust 0.8-pre\n"
-"POT-Creation-Date: 2013-07-17 07:18+0900\n"
+"POT-Creation-Date: 2013-08-08 22:27+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#. type: Plain text
msgstr ""
#. type: Plain text
-#: doc/rust.md:1849 doc/tutorial-tasks.md:649
+#: doc/rust.md:1952 doc/tutorial-tasks.md:648
msgid "# } ~~~~"
msgstr ""
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:124
-msgid "~~~ # use std::io::print; # use std::task::spawn; # use std::int;"
+#: doc/tutorial-tasks.md:123
+msgid "~~~ # use std::io::print; # use std::task::spawn;"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:131
+#: doc/tutorial-tasks.md:130
#, no-wrap
msgid ""
-"for int::range(0, 20) |child_task_number| {\n"
+"for child_task_number in range(0, 20) {\n"
" do spawn {\n"
" print(fmt!(\"I am child number %d\\n\", child_task_number));\n"
" }\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:133
+#: doc/tutorial-tasks.md:132
msgid "## Communication"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:138
+#: doc/tutorial-tasks.md:137
msgid ""
"Now that we have spawned a new task, it would be nice if we could "
"communicate with it. Recall that Rust does not have shared mutable state, so "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:143
+#: doc/tutorial-tasks.md:142
msgid ""
"A pipe is simply a pair of endpoints: one for sending messages and another "
"for receiving messages. Pipes are low-level communication building-blocks "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:149
+#: doc/tutorial-tasks.md:148
msgid ""
"The simplest way to create a pipe is to use the `pipes::stream` function to "
"create a `(Port, Chan)` pair. In Rust parlance, a *channel* is a sending "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:153
+#: doc/tutorial-tasks.md:152
msgid "~~~~ # use std::task::spawn; # use std::comm::{stream, Port, Chan};"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:155
+#: doc/tutorial-tasks.md:154
msgid "let (port, chan): (Port<int>, Chan<int>) = stream();"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:160
+#: doc/tutorial-tasks.md:159
#, no-wrap
msgid ""
"do spawn || {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:166
+#: doc/tutorial-tasks.md:165
msgid ""
"some_other_expensive_computation(); let result = port.recv(); # fn "
"some_expensive_computation() -> int { 42 } # fn "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:171
+#: doc/tutorial-tasks.md:170
msgid ""
"Let's examine this example in detail. First, the `let` statement creates a "
"stream for sending and receiving integers (the left-hand side of the `let`, "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:176
+#: doc/tutorial-tasks.md:175
msgid ""
"~~~~ # use std::comm::{stream, Chan, Port}; let (port, chan): (Port<int>, "
"Chan<int>) = stream(); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:180
+#: doc/tutorial-tasks.md:179
msgid ""
"The child task will use the channel to send data to the parent task, which "
"will wait to receive the data on the port. The next statement spawns the "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:191
+#: doc/tutorial-tasks.md:190
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:197
+#: doc/tutorial-tasks.md:196
msgid ""
"Notice that the creation of the task closure transfers `chan` to the child "
"task implicitly: the closure captures `chan` in its environment. Both `Chan` "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:201
+#: doc/tutorial-tasks.md:200
msgid ""
"Finally, the parent continues with some other expensive computation, then "
"waits for the child's result to arrive on the port:"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:210
+#: doc/tutorial-tasks.md:209
msgid ""
"~~~~ # use std::comm::{stream}; # fn some_other_expensive_computation() {} # "
"let (port, chan) = stream::<int>(); # chan.send(0); "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:216
+#: doc/tutorial-tasks.md:215
msgid ""
"The `Port` and `Chan` pair created by `stream` enables efficient "
"communication between a single sender and a single receiver, but multiple "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:222
+#: doc/tutorial-tasks.md:221
msgid ""
"~~~ {.xfail-test} # use std::task::{spawn}; # use std::comm::{stream, Port, "
"Chan}; # fn some_expensive_computation() -> int { 42 } let (port, chan) = "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:226
+#: doc/tutorial-tasks.md:225
#, no-wrap
msgid ""
"do spawn {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:233
+#: doc/tutorial-tasks.md:232
#, no-wrap
msgid ""
"// ERROR! The previous spawn statement already owns the channel,\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:236
+#: doc/tutorial-tasks.md:235
msgid ""
"Instead we can use a `SharedChan`, a type that allows a single `Chan` to be "
"shared by multiple senders."
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:241
-msgid ""
-"~~~ # use std::task::spawn; # use std::comm::{stream, SharedChan}; # use "
-"std::uint;"
+#: doc/tutorial-tasks.md:239
+msgid "~~~ # use std::task::spawn; # use std::comm::{stream, SharedChan};"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:244
+#: doc/tutorial-tasks.md:242
msgid "let (port, chan) = stream(); let chan = SharedChan::new(chan);"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:252
+#: doc/tutorial-tasks.md:250
#, no-wrap
msgid ""
-"for uint::range(0, 3) |init_val| {\n"
+"for init_val in range(0u, 3) {\n"
" // Create a new channel handle to distribute to the child task\n"
" let child_chan = chan.clone();\n"
" do spawn {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:256
+#: doc/tutorial-tasks.md:254
msgid ""
"let result = port.recv() + port.recv() + port.recv(); # fn "
"some_expensive_computation(_i: uint) -> int { 42 } ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:265
+#: doc/tutorial-tasks.md:263
msgid ""
"Here we transfer ownership of the channel into a new `SharedChan` value. "
"Like `Chan`, `SharedChan` is a non-copyable, owned type (sometimes also "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:270
+#: doc/tutorial-tasks.md:268
msgid ""
"Note that the above `SharedChan` example is somewhat contrived since you "
"could also simply use three `stream` pairs, but it serves to illustrate the "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:275
+#: doc/tutorial-tasks.md:273
msgid "~~~ # use std::task::spawn; # use std::comm::stream; # use std::vec;"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:284
+#: doc/tutorial-tasks.md:282
#, no-wrap
msgid ""
"// Create a vector of ports, one for each child task\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:289
+#: doc/tutorial-tasks.md:287
msgid ""
"// Wait on each port, accumulating the results let result = ports.iter()."
"fold(0, |accum, port| accum + port.recv() ); # fn "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:293
+#: doc/tutorial-tasks.md:291
msgid ""
"## Backgrounding computations: Futures With `extra::future`, rust has a "
"mechanism for requesting a computation and getting the result later."
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:301
+#: doc/tutorial-tasks.md:299
#, no-wrap
msgid ""
"The basic example below illustrates this.\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:306
+#: doc/tutorial-tasks.md:304
msgid ""
"let mut delayed_fib = extra::future::spawn (|| fib(50) ); make_a_sandwich(); "
"println(fmt!(\"fib(50) = %?\", delayed_fib.get())) ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:312
+#: doc/tutorial-tasks.md:310
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:325
+#: doc/tutorial-tasks.md:322
#, no-wrap
msgid ""
"Here is another example showing how futures allow you to background computations. The workload will\n"
"be distributed on the available cores.\n"
"~~~\n"
"# use std::vec;\n"
-"# use std::uint;\n"
"fn partial_sum(start: uint) -> f64 {\n"
" let mut local_sum = 0f64;\n"
-" for uint::range(start*100000, (start+1)*100000) |num| {\n"
+" for num in range(start*100000, (start+1)*100000) {\n"
" local_sum += (num as f64 + 1.0).pow(&-2.0);\n"
" }\n"
" local_sum\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:328
+#: doc/tutorial-tasks.md:325
#, no-wrap
msgid ""
"fn main() {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:336
+#: doc/tutorial-tasks.md:333
#, no-wrap
msgid ""
" let mut final_res = 0f64;\n"
" for ft in futures.mut_iter() {\n"
" final_res += ft.get();\n"
" }\n"
-" println(fmt!(\"^2/6 is not far from : %?\", final_res));\n"
+" println(fmt!(\"π^2/6 is not far from : %?\", final_res));\n"
"}\n"
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:338
+#: doc/tutorial-tasks.md:335
msgid "## Sharing immutable data without copy: Arc"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:343
+#: doc/tutorial-tasks.md:340
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:347
+#: doc/tutorial-tasks.md:344
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:355
+#: doc/tutorial-tasks.md:351
msgid ""
"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;"
+"full vector to perform its duty. ~~~ # use std::vec; # use std::rand; use "
+"extra::arc::Arc;"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:359
+#: doc/tutorial-tasks.md:355
#, no-wrap
msgid ""
"fn pnorm(nums: &~[float], p: uint) -> float {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:363
+#: doc/tutorial-tasks.md:359
#, no-wrap
msgid ""
"fn main() {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:365
+#: doc/tutorial-tasks.md:361
#, no-wrap
msgid " let numbers_arc = Arc::new(numbers);\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:369
+#: doc/tutorial-tasks.md:365
#, no-wrap
msgid ""
-" for uint::range(1,10) |num| {\n"
+" for num in range(1u, 10) {\n"
" let (port, chan) = stream();\n"
" chan.send(numbers_arc.clone());\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:378
+#: doc/tutorial-tasks.md:374
#, no-wrap
msgid ""
" do spawn {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:400
+#: doc/tutorial-tasks.md:396
msgid ""
"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::new(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::new(numbers); # let (port, chan) = stream(); chan.send(numbers_arc."
+"vec::from_fn(1000000, |_| rand::random::<float>()); let numbers_arc=Arc::"
+"new(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::"
+"new(numbers); # let (port, chan) = stream(); chan.send(numbers_arc."
"clone()); ~~~ copying only the wrapper and not its contents."
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:414
+#: doc/tutorial-tasks.md:410
msgid ""
"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::new(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."
+"random::<float>()); # let numbers_arc=Arc::new(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."
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:416
+#: doc/tutorial-tasks.md:412
msgid ""
"The `arc` module also implements Arcs around mutable data that are not "
"covered here."
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:418
+#: doc/tutorial-tasks.md:414
msgid "# Handling task failure"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:427
+#: doc/tutorial-tasks.md:423
msgid ""
"Rust has a built-in mechanism for raising exceptions. The `fail!()` macro "
"(which can also be written with an error string as an argument: `fail!"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:430
+#: doc/tutorial-tasks.md:426
msgid ""
"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."
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:438
+#: doc/tutorial-tasks.md:434
msgid ""
-"~~~ # use std::task::spawn; # use std::task; # fn do_some_work() { loop "
-"{ task::yield() } } # do task::try { // Create a child task that fails do "
-"spawn { fail!() }"
+"~~~{.xfail-test .linked-failure} # use std::task::spawn; # use std::task; # "
+"fn do_some_work() { loop { task::yield() } } # do task::try { // Create a "
+"child task that fails do spawn { fail!() }"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:443
+#: doc/tutorial-tasks.md:439
msgid ""
"// This will also fail because the task we spawned failed do_some_work(); "
"# }; ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:453
+#: doc/tutorial-tasks.md:449
msgid ""
"While it isn't possible for a task to recover from failure, tasks may notify "
"each other of failure. The simplest way of handling task failure is with the "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:467
+#: doc/tutorial-tasks.md:463
#, no-wrap
msgid ""
-"~~~\n"
+"~~~{.xfail-test .linked-failure}\n"
"# use std::task;\n"
"# fn some_condition() -> bool { false }\n"
"# fn calculate_result() -> int { 0 }\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:473
+#: doc/tutorial-tasks.md:469
msgid ""
"Unlike `spawn`, the function spawned using `try` may return a value, which "
"`try` will dutifully propagate back to the caller in a [`Result`] enum. If "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:475
+#: doc/tutorial-tasks.md:471
msgid "[`Result`]: std/result.html"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:480
+#: doc/tutorial-tasks.md:476
msgid ""
"> ***Note:*** A failed task does not currently produce a useful error > "
"value (`try` always returns `Err(())`). In the > future, it may be possible "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:483
+#: doc/tutorial-tasks.md:479
msgid ""
"TODO: Need discussion of `future_result` in order to make failure modes "
"useful."
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:491
+#: doc/tutorial-tasks.md:487
msgid ""
"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 "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:493
+#: doc/tutorial-tasks.md:489
msgid "## Failure modes"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:496
+#: doc/tutorial-tasks.md:492
msgid ""
"By default, task failure is _bidirectionally linked_, which means that if "
"either task fails, it kills the other one."
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:510
+#: doc/tutorial-tasks.md:507
#, no-wrap
msgid ""
-"~~~\n"
+"~~~{.xfail-test .linked-failure}\n"
"# use std::task;\n"
-"# fn sleep_forever() { loop { task::yield() } }\n"
+"# use std::comm::oneshot;\n"
+"# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }\n"
"# do task::try {\n"
"do spawn {\n"
" do spawn {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:517
+#: doc/tutorial-tasks.md:514
msgid ""
"If you want parent tasks to be able to kill their children, but do not want "
"a parent to fail automatically if one of its child task fails, you can call "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:538
+#: doc/tutorial-tasks.md:536
#, no-wrap
msgid ""
-"~~~\n"
+"~~~{.xfail-test .linked-failure}\n"
"# use std::comm::{stream, Chan, Port};\n"
+"# use std::comm::oneshot;\n"
"# use std::task::{spawn, try};\n"
"# use std::task;\n"
-"# fn sleep_forever() { loop { task::yield() } }\n"
+"# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }\n"
"# do task::try {\n"
"let (receiver, sender): (Port<int>, Chan<int>) = stream();\n"
"do spawn { // Bidirectionally linked\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:544
+#: doc/tutorial-tasks.md:542
msgid ""
"Supervised failure is useful in any situation where one task manages "
"multiple fallible child tasks, and the parent task can recover if any child "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:547
+#: doc/tutorial-tasks.md:545
msgid ""
"Supervised task failure propagates across multiple generations even if an "
"intermediate generation has already exited:"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:563
+#: doc/tutorial-tasks.md:562
#, no-wrap
msgid ""
-"~~~\n"
+"~~~{.xfail-test .linked-failure}\n"
"# use std::task;\n"
-"# fn sleep_forever() { loop { task::yield() } }\n"
-"# fn wait_for_a_while() { for 1000.times { task::yield() } }\n"
+"# use std::comm::oneshot;\n"
+"# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }\n"
+"# fn wait_for_a_while() { for _ in range(0, 1000u) { task::yield() } }\n"
"# do task::try::<int> {\n"
"do task::spawn_supervised {\n"
" do task::spawn_supervised {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:566
+#: doc/tutorial-tasks.md:565
msgid ""
"Finally, tasks can be configured to not propagate failure to each other at "
"all, using `task::spawn_unlinked` for _isolated failure_."
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:582
+#: doc/tutorial-tasks.md:581
#, no-wrap
msgid ""
-"~~~\n"
+"~~~{.xfail-test .linked-failure}\n"
"# use std::task;\n"
"# fn random() -> uint { 100 }\n"
-"# fn sleep_for(i: uint) { for i.times { task::yield() } }\n"
+"# fn sleep_for(i: uint) { for _ in range(0, i) { task::yield() } }\n"
"# do task::try::<()> {\n"
"let (time1, time2) = (random(), random());\n"
"do task::spawn_unlinked {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:584
+#: doc/tutorial-tasks.md:583
msgid "## Creating a task with a bi-directional communication path"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:589
+#: doc/tutorial-tasks.md:588
msgid ""
"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 `extra::"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:594
+#: doc/tutorial-tasks.md:593
msgid ""
"To see how `DuplexStream()` works, we will create a child task that "
"repeatedly receives a `uint` message, converts it to a string, and sends the "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:607
+#: doc/tutorial-tasks.md:606
#, no-wrap
msgid ""
-"~~~~\n"
+"~~~{.xfail-test .linked-failure}\n"
"# use extra::comm::DuplexStream;\n"
"# use std::uint;\n"
"fn stringifier(channel: &DuplexStream<~str, uint>) {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:615
+#: doc/tutorial-tasks.md:614
msgid ""
"The implementation of `DuplexStream` supports both sending and receiving. "
"The `stringifier` function takes a `DuplexStream` that can send strings (the "
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:617
+#: doc/tutorial-tasks.md:616
msgid "Here is the code for the parent task:"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:631
+#: doc/tutorial-tasks.md:630
#, no-wrap
msgid ""
-"~~~~\n"
+"~~~{.xfail-test .linked-failure}\n"
"# use std::task::spawn;\n"
"# use std::uint;\n"
"# use extra::comm::DuplexStream;\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:633
+#: doc/tutorial-tasks.md:632
msgid "let (from_child, to_child) = DuplexStream();"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:637
+#: doc/tutorial-tasks.md:636
#, no-wrap
msgid ""
"do spawn {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:640
+#: doc/tutorial-tasks.md:639
msgid "from_child.send(22); assert!(from_child.recv() == ~\"22\");"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:643
+#: doc/tutorial-tasks.md:642
msgid "from_child.send(23); from_child.send(0);"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:646
+#: doc/tutorial-tasks.md:645
msgid ""
"assert!(from_child.recv() == ~\"23\"); assert!(from_child.recv() == ~\"0\");"
msgstr ""
#. type: Plain text
-#: doc/tutorial-tasks.md:653
+#: doc/tutorial-tasks.md:652
msgid ""
"The parent task first calls `DuplexStream` to create a pair of bidirectional "
"endpoints. It then uses `task::spawn` to create the child task, which "
msgid ""
msgstr ""
"Project-Id-Version: Rust 0.8-pre\n"
-"POT-Creation-Date: 2013-07-17 07:18+0900\n"
+"POT-Creation-Date: 2013-08-12 02:06+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#. type: Plain text
msgstr ""
#. type: Plain text
-#: doc/rust.md:1231 doc/tutorial.md:2177
+#: doc/rust.md:1277 doc/tutorial.md:2176
msgid ""
"In type-parameterized functions, methods of the supertrait may be called on "
"values of subtrait-bound type parameters. Refering to the previous example "
msgstr ""
#. type: Plain text
-#: doc/rust.md:1240 doc/tutorial.md:2186
+#: doc/rust.md:1286 doc/tutorial.md:2185
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/rust.md:1242 doc/tutorial.md:2188
+#: doc/rust.md:1288 doc/tutorial.md:2187
msgid "Likewise, supertrait methods may also be called on trait objects."
msgstr ""
#. type: Plain text
#: doc/tutorial.md:88
msgid ""
-"[bug-3319]: https://github.com/mozilla/rust/issues/3319 [wiki-start]:"
-"\thttps://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust"
+"[bug-3319]: https://github.com/mozilla/rust/issues/3319 [wiki-start]: "
+"https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust"
msgstr ""
#. type: Plain text
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:124
+#: doc/tutorial.md:123
msgid ""
-"[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-"
-"developing-Rust [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"
+"[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"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:126
+#: doc/tutorial.md:125
msgid "## Compiling your first program"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:129
+#: doc/tutorial.md:128
msgid ""
"Rust program files are, by convention, given the extension `.rs`. Say we "
"have a file `hello.rs` containing this program:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:135
+#: doc/tutorial.md:134
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:139
+#: doc/tutorial.md:138
msgid ""
"If the Rust compiler was installed successfully, running `rustc hello.rs` "
"will produce an executable called `hello` (or `hello.exe` on Windows) which, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:144
+#: doc/tutorial.md:143
msgid ""
"The Rust compiler tries to provide useful information when it encounters an "
"error. If you introduce an error into the program (for example, by changing "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:150
+#: doc/tutorial.md:149
#, no-wrap
msgid ""
"~~~~ {.notrust}\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:157
+#: doc/tutorial.md:156
msgid ""
"In its simplest form, a Rust program is a `.rs` file with some types and "
"functions defined in it. If it has a `main` function, it can be compiled to "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:159
+#: doc/tutorial.md:158
msgid "## Using the rust tool"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:164
+#: doc/tutorial.md:163
msgid ""
"While using `rustc` directly to generate your executables, and then running "
"them manually is a perfectly valid way to test your code, for smaller "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:170
+#: doc/tutorial.md:169
msgid ""
"The `rust` tool provides central access to the other rust tools, as well as "
"handy shortcuts for directly running source files. For example, if you have "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:173
+#: doc/tutorial.md:172
msgid ""
"To get a list of all available commands, simply call `rust` without any "
"argument."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:175
+#: doc/tutorial.md:174
msgid "## Editing Rust code"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:185
+#: doc/tutorial.md:184
msgid ""
"There are vim highlighting and indentation scripts in the Rust source "
"distribution under `src/etc/vim/`. There is an emacs mode under `src/etc/"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:189
+#: doc/tutorial.md:188
msgid ""
"There is ctags support via `src/etc/ctags.rust`, but many other tools and "
"editors are not yet supported. If you end up writing a Rust mode for your "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:192
+#: doc/tutorial.md:191
msgid ""
"[sublime]: http://github.com/dbp/sublime-rust [sublime-pkg]: http://wbond."
"net/sublime_packages/package_control"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:194
+#: doc/tutorial.md:193
msgid "# Syntax basics"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:202
+#: doc/tutorial.md:201
msgid ""
"Assuming you've programmed in any C-family language (C++, Java, JavaScript, "
"C#, or PHP), Rust will feel familiar. Code is arranged in blocks delineated "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:207
+#: doc/tutorial.md:206
msgid ""
"The main surface difference to be aware of is that the condition at the head "
"of control structures like `if` and `while` does not require parentheses, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:220
+#: doc/tutorial.md:219
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:224
+#: doc/tutorial.md:223
msgid ""
"The `let` keyword introduces a local variable. Variables are immutable by "
"default. To introduce a local variable that you can re-assign later, use "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:228
+#: doc/tutorial.md:227
msgid "~~~~ let hi = \"hi\"; let mut count = 0;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:234
+#: doc/tutorial.md:233
#, no-wrap
msgid ""
"while count < 10 {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:238
+#: doc/tutorial.md:237
msgid ""
"Although Rust can almost always infer the types of local variables, you can "
"specify a variable's type by following it with a colon, then the type name. "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:244
+#: doc/tutorial.md:243
msgid ""
"~~~~ static MONSTER_FACTOR: float = 57.8; let monster_size = MONSTER_FACTOR "
"* 10.0; let monster_size: int = 50; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:253
+#: doc/tutorial.md:252
msgid ""
"Local variables may shadow earlier declarations, as in the previous example: "
"`monster_size` was first declared as a `float`, and then a second "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:259
+#: doc/tutorial.md:258
msgid ""
"Rust identifiers start with an alphabetic character or an underscore, and "
"after that may contain any sequence of alphabetic characters, numbers, or "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:264
+#: doc/tutorial.md:263
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:266
+#: doc/tutorial.md:265
msgid "## Expressions and semicolons"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:272
+#: doc/tutorial.md:271
msgid ""
"Though it isn't apparent in all code, there is a fundamental difference "
"between Rust's syntax and predecessors like C. Many constructs that are "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:284
+#: doc/tutorial.md:283
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:286
+#: doc/tutorial.md:285
msgid "But, in Rust, you don't have to repeat the name `price`:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:298
+#: doc/tutorial.md:297
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:304
+#: doc/tutorial.md:303
msgid ""
"Both pieces of code are exactly equivalent: they assign a value to `price` "
"depending on the condition that holds. Note that there are no semicolons in "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:310
+#: doc/tutorial.md:309
msgid ""
"Put another way, the semicolon in Rust *ignores the value of an "
"expression*. Thus, if the branches of the `if` had looked like `{ 4; }`, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:315
+#: doc/tutorial.md:314
msgid ""
"In short, everything that's not a declaration (declarations are `let` for "
"variables; `fn` for functions; and any top-level named items such as [traits]"
-"(#traits), [enum types](#enums), and [constants](#constants)) is an "
-"expression, including function bodies."
+"(#traits), [enum types](#enums), and static items) is an expression, "
+"including function bodies."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:323
+#: doc/tutorial.md:322
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:325
+#: doc/tutorial.md:324
msgid "## Primitive types and literals"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:332
+#: doc/tutorial.md:331
msgid ""
"There are general signed and unsigned integer types, `int` and `uint`, as "
"well as 8-, 16-, 32-, and 64-bit variants, `i8`, `u16`, etc. Integers can "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:338
+#: doc/tutorial.md:337
msgid ""
"In the absence of an integer literal suffix, Rust will infer the integer "
"type based on type annotations and function signatures in the surrounding "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:345
+#: doc/tutorial.md:344
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:350
+#: doc/tutorial.md:349
msgid ""
"There are three floating-point types: `float`, `f32`, and `f64`. Floating-"
"point numbers are written `0.0`, `1e6`, or `2.1e-4`. Like integers, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:352
+#: doc/tutorial.md:351
msgid "The keywords `true` and `false` produce literals of type `bool`."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:359
+#: doc/tutorial.md:358
msgid ""
"Characters, the `char` type, are four-byte Unicode codepoints, whose "
"literals are written between single quotes, as in `'x'`. Just like C, Rust "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:361
+#: doc/tutorial.md:360
msgid "The nil type, written `()`, has a single value, also written `()`."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:363
+#: doc/tutorial.md:362
msgid "## Operators"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:368
+#: doc/tutorial.md:367
msgid ""
"Rust's set of operators contains very few surprises. Arithmetic is done with "
"`*`, `/`, `%`, `+`, and `-` (multiply, quotient, remainder, add, and "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:371
+#: doc/tutorial.md:370
msgid ""
"Note that, if applied to an integer value, `!` flips all the bits (like `~` "
"in C)."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:375
+#: doc/tutorial.md:374
msgid ""
"The comparison operators are the traditional `==`, `!=`, `<`, `>`, `<=`, and "
"`>=`. Short-circuiting (lazy) boolean operators are written `&&` (and) and "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:380
+#: doc/tutorial.md:379
msgid ""
"For type casting, Rust uses the binary `as` operator. It takes an "
"expression on the left side and a type on the right side and will, if a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:386
+#: doc/tutorial.md:385
msgid ""
"~~~~ let x: float = 4.0; let y: uint = x as uint; assert!(y == 4u); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:388
+#: doc/tutorial.md:387
msgid "## Syntax extensions"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:395
+#: doc/tutorial.md:394
#, no-wrap
msgid ""
"*Syntax extensions* are special forms that are not built into the language,\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:399
+#: doc/tutorial.md:398
msgid ""
"`fmt!` supports most of the directives that [printf][pf] supports, but "
"unlike printf, will give you a compile-time error when the types of the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:402
+#: doc/tutorial.md:401
msgid "~~~~ # let mystery_object = ();"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:404
+#: doc/tutorial.md:403
msgid "println(fmt!(\"%s is %d\", \"the answer\", 43));"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:408
+#: doc/tutorial.md:407
msgid ""
"// %? will conveniently print any type println(fmt!(\"what is this thing: %?"
"\", mystery_object)); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:410
+#: doc/tutorial.md:409
msgid "[pf]: http://en.cppreference.com/w/cpp/io/c/fprintf"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:412
+#: doc/tutorial.md:411
msgid ""
"You can define your own syntax extensions with the macro system. For "
"details, see the [macro tutorial][macros]."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:414
-msgid "[macros]: tutorial-macros.html"
-msgstr ""
-
-#. type: Plain text
-#: doc/tutorial.md:416
+#: doc/tutorial.md:413
msgid "# Control structures"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:418
+#: doc/tutorial.md:415
msgid "## Conditionals"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:422
+#: doc/tutorial.md:419
msgid ""
"We've seen `if` expressions a few times already. To recap, braces are "
"compulsory, an `if` can have an optional `else` clause, and multiple `if`/"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:432
+#: doc/tutorial.md:429
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:437
+#: doc/tutorial.md:434
msgid ""
"The condition given to an `if` construct *must* be of type `bool` (no "
"implicit conversion happens). If the arms are blocks that have a value, this "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:445
+#: doc/tutorial.md:442
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:447
+#: doc/tutorial.md:444
msgid "## Pattern matching"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:453
+#: doc/tutorial.md:450
msgid ""
"Rust's `match` construct is a generalized, cleaned-up version of C's "
"`switch` construct. You provide it with a value and a number of *arms*, each "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:463
+#: doc/tutorial.md:460
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:467
+#: doc/tutorial.md:464
msgid ""
"Unlike in C, there is no \"falling through\" between arms: only one arm "
"executes, and it doesn't have to explicitly `break` out of the construct "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:477
+#: doc/tutorial.md:474
msgid ""
"A `match` arm consists of a *pattern*, then an arrow `=>`, followed by an "
"*action* (expression). Literals are valid patterns and match only their own "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:482
+#: doc/tutorial.md:479
msgid ""
"The patterns in a match arm are followed by a fat arrow, `=>`, then an "
"expression to evaluate. Each case is separated by commas. It's often "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:490
+#: doc/tutorial.md:487
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:495
+#: doc/tutorial.md:492
msgid ""
"`match` constructs must be *exhaustive*: they must have an arm covering "
"every possible case. For example, the typechecker would reject the previous "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:499
+#: doc/tutorial.md:496
msgid ""
"A powerful application of pattern matching is *destructuring*: matching in "
"order to bind names to the contents of data types."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:503
+#: doc/tutorial.md:500
msgid ""
"> ***Note:*** The following code makes use of tuples (`(float, float)`) "
"which > are explained in section 5.3. For now you can think of tuples as a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:516
+#: doc/tutorial.md:513
#, no-wrap
msgid ""
"~~~~\n"
-"# use std::float;\n"
-"# use std::num::atan;\n"
+"use std::float;\n"
+"use std::num::atan;\n"
"fn angle(vector: (float, float)) -> float {\n"
" let pi = float::consts::pi;\n"
" match vector {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:522
+#: doc/tutorial.md:519
msgid ""
"A variable name in a pattern matches any value, *and* binds that name to the "
"value of the matched value inside of the arm's action. Thus, `(0f, y)` "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:529
+#: doc/tutorial.md:526
msgid ""
"Any `match` arm can have a guard clause (written `if EXPR`), called a "
"*pattern guard*, which is an expression of type `bool` that determines, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:534
+#: doc/tutorial.md:531
msgid ""
"You've already seen simple `let` bindings, but `let` is a little fancier "
"than you've been led to believe. It, too, supports destructuring patterns. "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:539
+#: doc/tutorial.md:536
msgid ""
"~~~~ # fn get_tuple_of_two_ints() -> (int, int) { (1, 1) } let (a, b) = "
"get_tuple_of_two_ints(); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:543
+#: doc/tutorial.md:540
msgid ""
"Let bindings only work with _irrefutable_ patterns: that is, patterns that "
"can never fail to match. This excludes `let` from matching literals and most "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:545
+#: doc/tutorial.md:542
msgid "## Loops"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:550
+#: doc/tutorial.md:547
msgid ""
"`while` denotes a loop that iterates as long as its given condition (which "
"must have type `bool`) evaluates to `true`. Inside a loop, the keyword "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:557
+#: doc/tutorial.md:554
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:559
+#: doc/tutorial.md:556
msgid ""
"`loop` denotes an infinite loop, and is the preferred way of writing `while "
"true`:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:569
+#: doc/tutorial.md:566
#, no-wrap
msgid ""
"~~~~\n"
-"# use std::int;\n"
+"use std::int;\n"
"let mut x = 5;\n"
"loop {\n"
" x += x - 3;\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:572
+#: doc/tutorial.md:569
msgid ""
"This code prints out a weird sequence of numbers and stops as soon as it "
"finds one that can be divided by five."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:577
-msgid ""
-"Rust also has a `for` construct. It's different from C's `for` and it works "
-"best when iterating over collections. See the section on [closures]"
-"(#closures) to find out how to use `for` and higher-order functions for "
-"enumerating elements of a collection."
-msgstr ""
-
-#. type: Plain text
-#: doc/tutorial.md:579
+#: doc/tutorial.md:571
msgid "# Data structures"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:581
+#: doc/tutorial.md:573
msgid "## Structs"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:586
+#: doc/tutorial.md:578
msgid ""
"Rust struct types must be declared before they are used using the `struct` "
"syntax: `struct Name { field1: T1, field2: T2 [, ...] }`, where `T1`, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:590
+#: doc/tutorial.md:582
msgid ""
"Structs are quite similar to C structs and are even laid out the same way in "
"memory (so you can read from a Rust struct in C, and vice-versa). Use the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:597
+#: doc/tutorial.md:589
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:601
+#: doc/tutorial.md:593
msgid ""
"Inherited mutability means that any field of a struct may be mutable, if the "
"struct is in a mutable slot (or a field of a struct in a mutable slot, and "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:605
+#: doc/tutorial.md:597
msgid ""
"With a value (say, `mypoint`) of such a type in a mutable location, you can "
"do `mypoint.y += 1.0`. But in an immutable location, such an assignment to a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:610
+#: doc/tutorial.md:602
msgid ""
"~~~~ {.xfail-test} # struct Point { x: float, y: float } let mut mypoint = "
"Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:614
+#: doc/tutorial.md:606
msgid ""
"mypoint.y += 1.0; // mypoint is mutable, and its fields as well origin.y += "
"1.0; // ERROR: assigning to immutable field ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:617
+#: doc/tutorial.md:609
msgid ""
"`match` patterns destructure structs. The basic syntax is `Name { fieldname: "
"pattern, ... }`:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:626
+#: doc/tutorial.md:618
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:633
+#: doc/tutorial.md:625
msgid ""
"In general, the field names of a struct do not have to appear in the same "
"order they appear in the type. When you are not interested in all the fields "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:641
+#: doc/tutorial.md:633
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:643
+#: doc/tutorial.md:635
msgid "## Enums"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:646
+#: doc/tutorial.md:638
msgid ""
"Enums are datatypes that have several alternate representations. For "
"example, consider the type shown earlier:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:654
+#: doc/tutorial.md:646
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:660
+#: doc/tutorial.md:652
msgid ""
"A value of this type is either a `Circle`, in which case it contains a "
"`Point` struct and a float, or a `Rectangle`, in which case it contains two "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:666
+#: doc/tutorial.md:658
msgid ""
"The above declaration will define a type `Shape` that can refer to such "
"shapes, and two functions, `Circle` and `Rectangle`, which can be used to "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:669
+#: doc/tutorial.md:661
msgid ""
"Enum variants need not have parameters. This `enum` declaration, for "
"example, is equivalent to a C enum:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:678
+#: doc/tutorial.md:670
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:681
+#: doc/tutorial.md:673
msgid ""
"This declaration defines `North`, `East`, `South`, and `West` as constants, "
"all of which have type `Direction`."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:685
+#: doc/tutorial.md:677
msgid ""
"When an enum is C-like (that is, when none of the variants have parameters), "
"it is possible to explicitly set the discriminator values to a constant "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:693
+#: doc/tutorial.md:685
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:698
+#: doc/tutorial.md:690
msgid ""
"If an explicit discriminator is not specified for a variant, the value "
"defaults to the value of the previous variant plus one. If the first variant "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:701
+#: doc/tutorial.md:693
msgid ""
"When an enum is C-like, you can apply the `as` cast operator to convert it "
"to its discriminator value as an `int`."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:705
+#: doc/tutorial.md:697
msgid ""
"For enum types with multiple variants, destructuring is the only way to get "
"at their contents. All variant constructors can be used as patterns, as in "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:717
+#: doc/tutorial.md:709
#, no-wrap
msgid ""
"~~~~\n"
-"# use std::float;\n"
+"use std::float;\n"
"# struct Point {x: float, y: float}\n"
"# enum Shape { Circle(Point, float), Rectangle(Point, Point) }\n"
"fn area(sh: Shape) -> float {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:722
+#: doc/tutorial.md:714
msgid ""
"You can write a lone `_` to ignore an individual field, and can ignore all "
"fields of a variant like: `Circle(*)`. As in their introduction form, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:735
+#: doc/tutorial.md:727
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:737
+#: doc/tutorial.md:729
msgid "Enum variants may also be structs. For example:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:755
+#: doc/tutorial.md:747
#, no-wrap
msgid ""
"~~~~\n"
-"# use std::float;\n"
+"use std::float;\n"
"# struct Point { x: float, y: float }\n"
"# fn square(x: float) -> float { x * x }\n"
"enum Shape {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:757
+#: doc/tutorial.md:749
msgid "## Tuples"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:762
+#: doc/tutorial.md:754
msgid ""
"Tuples in Rust behave exactly like structs, except that their fields do not "
"have names. Thus, you cannot access their fields with dot notation. Tuples "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:769
+#: doc/tutorial.md:761
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:771
+#: doc/tutorial.md:763
msgid "## Tuple structs"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:776
+#: doc/tutorial.md:768
msgid ""
"Rust also has _tuple structs_, which behave like both structs and tuples, "
"except that, unlike tuples, tuple structs have names (so `Foo(1, 2)` has a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:785
+#: doc/tutorial.md:777
#, no-wrap
msgid ""
"For example:\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:787
+#: doc/tutorial.md:779
msgid "<a name=\"newtype\"></a>"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:792
+#: doc/tutorial.md:784
msgid ""
"There is a special case for tuple structs with a single field, which are "
"sometimes called \"newtypes\" (after Haskell's \"newtype\" feature). These "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:796
+#: doc/tutorial.md:788
msgid "~~~~ struct GizmoId(int); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:799
+#: doc/tutorial.md:791
msgid ""
"For convenience, you can extract the contents of such a struct with the "
"dereference (`*`) unary operator:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:805
+#: doc/tutorial.md:797
msgid ""
"~~~~ # struct GizmoId(int); let my_gizmo_id: GizmoId = GizmoId(10); let "
"id_int: int = *my_gizmo_id; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:808
+#: doc/tutorial.md:800
msgid ""
"Types like this can be useful to differentiate between data that have the "
"same type but must be used in different ways."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:813
+#: doc/tutorial.md:805
msgid "~~~~ struct Inches(int); struct Centimeters(int); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:816
+#: doc/tutorial.md:808
msgid ""
"The above definitions allow for a simple way for programs to avoid confusing "
"numbers that correspond to different units."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:818
+#: doc/tutorial.md:810
msgid "# Functions"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:826
+#: doc/tutorial.md:818
msgid ""
"We've already seen several function definitions. Like all other static "
"declarations, such as `type`, functions can be declared both at the top "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:832
+#: doc/tutorial.md:824
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:837
+#: doc/tutorial.md:829
msgid ""
"The `return` keyword immediately returns from the body of a function. It is "
"optionally followed by an expression to return. A function can also return a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:843
+#: doc/tutorial.md:835
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:850
+#: doc/tutorial.md:842
msgid ""
"It's better Rust style to write a return value this way instead of writing "
"an explicit `return`. The utility of `return` comes in when returning early "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:853
+#: doc/tutorial.md:845
msgid "~~~~ fn do_nothing_the_hard_way() -> () { return (); }"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:856
+#: doc/tutorial.md:848
msgid "fn do_nothing_the_easy_way() { } ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:858
+#: doc/tutorial.md:850
msgid ""
"Ending the function with a semicolon like so is equivalent to returning `()`."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:862
+#: doc/tutorial.md:854
msgid ""
"~~~~ fn line(a: int, b: int, x: int) -> int { a * x + b } fn oops(a: int, b: "
"int, x: int) -> () { a * x + b; }"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:866
+#: doc/tutorial.md:858
msgid "assert!(8 == line(5, 3, 1)); assert!(() == oops(5, 3, 1)); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:870
+#: doc/tutorial.md:862
msgid ""
"As with `match` expressions and `let` bindings, function arguments support "
"pattern destructuring. Like `let`, argument patterns must be irrefutable, as "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:874
+#: doc/tutorial.md:866
msgid "~~~ fn first((value, _): (int, float)) -> int { value } ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:876 doc/tutorial-ffi.md:143
+#: doc/tutorial.md:868 doc/tutorial-ffi.md:143
msgid "# Destructors"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:880
+#: doc/tutorial.md:872
msgid ""
"A *destructor* is a function responsible for cleaning up the resources used "
"by an object when it is no longer accessible. Destructors can be defined to "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:884
+#: doc/tutorial.md:876
msgid ""
"Objects are never accessible after their destructor has been called, so "
"there are no dynamic failures from accessing freed resources. When a task "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:886
+#: doc/tutorial.md:878
msgid ""
"The `~` sigil represents a unique handle for a memory allocation on the heap:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:894
+#: doc/tutorial.md:886
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:898
+#: doc/tutorial.md:890
msgid ""
"Rust includes syntax for heap memory allocation in the language since it's "
"commonly used, but the same semantics can be implemented by a type with a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:900
+#: doc/tutorial.md:892
msgid "# Ownership"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:905
+#: doc/tutorial.md:897
msgid ""
"Rust formalizes the concept of object ownership to delegate management of an "
"object's lifetime to either a variable or a task-local garbage collector. An "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:911
+#: doc/tutorial.md:903
msgid ""
"Ownership is recursive, so mutability is inherited recursively and a "
"destructor destroys the contained tree of owned objects. Variables are top-"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:915
+#: doc/tutorial.md:907
msgid ""
"~~~~ // the struct owns the objects contained in the `x` and `y` fields "
"struct Foo { x: int, y: ~int }"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:922
+#: doc/tutorial.md:914
#, no-wrap
msgid ""
"{\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:927
+#: doc/tutorial.md:919
msgid ""
"// `b` is mutable, and the mutability is inherited by the objects it owns "
"let mut b = Foo { x: 5, y: ~10 }; b.x = 10; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:933
+#: doc/tutorial.md:925
msgid ""
"If an object doesn't contain garbage-collected boxes, it consists of a "
"single ownership tree and is given the `Owned` trait which allows it to be "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:935
+#: doc/tutorial.md:927
msgid "# Boxes"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:942
+#: doc/tutorial.md:934
msgid ""
"Many modern languages represent values as pointers to heap memory by "
"default. In contrast, Rust, like C and C++, represents such types directly. "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:947
+#: doc/tutorial.md:939
msgid ""
"For small structs like `Point`, this is usually more efficient than "
"allocating memory and indirecting through a pointer. But for big structs, or "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:949
+#: doc/tutorial.md:941
msgid "## Owned boxes"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:952
+#: doc/tutorial.md:944
msgid ""
"An owned box (`~`) is a uniquely owned allocation on the heap. It inherits "
"the mutability and lifetime of the owner as it would if there was no box:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:957
+#: doc/tutorial.md:949
msgid "~~~~ let x = 5; // immutable let mut y = 5; // mutable y += 2;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:962
+#: doc/tutorial.md:954
msgid ""
"let x = ~5; // immutable let mut y = ~5; // mutable *y += 2; // the * "
"operator is needed to access the contained value ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:967
+#: doc/tutorial.md:959
msgid ""
"The purpose of an owned box is to add a layer of indirection in order to "
"create recursive data structures or cheaply pass around an object larger "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:970
+#: doc/tutorial.md:962
msgid ""
"The following struct won't compile, because the lack of indirection would "
"mean it has an infinite size:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:976
+#: doc/tutorial.md:968
#, no-wrap
msgid ""
"~~~~ {.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:980
+#: doc/tutorial.md:972
msgid ""
"> ***Note:*** The `Option` type is an enum that represents an *optional* "
"value. > It's comparable to a nullable pointer in many other languages, but "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:984
+#: doc/tutorial.md:976
msgid ""
"Adding indirection with an owned pointer allocates the child outside of the "
"struct on the heap, which makes it a finite size and won't result in a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:990
+#: doc/tutorial.md:982
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:992
+#: doc/tutorial.md:984
msgid "## Managed boxes"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1000
+#: doc/tutorial.md:992
msgid ""
"A managed box (`@`) is a heap allocation with the lifetime managed by a task-"
"local garbage collector. It will be destroyed at some point after there are "
"no references left to the box, no later than the end of the task. Managed "
"boxes lack an owner, so they start a new ownership tree and don't inherit "
"mutability. They do own the contained object, and mutability is defined by "
-"the type of the shared box (`@` or `@mut`). An object containing a managed "
+"the type of the managed box (`@` or `@mut`). An object containing a managed "
"box is not `Owned`, and can't be sent between tasks."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1003
+#: doc/tutorial.md:995
msgid "~~~~ let a = @5; // immutable"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1006
+#: doc/tutorial.md:998
msgid "let mut b = @5; // mutable variable, immutable box b = @10;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1009
+#: doc/tutorial.md:1001
msgid "let c = @mut 5; // immutable variable, mutable box *c = 10;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1014
+#: doc/tutorial.md:1006
msgid ""
"let mut d = @mut 5; // mutable variable, mutable box *d += 5; d = @mut 15; "
"~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1019
+#: doc/tutorial.md:1011
msgid ""
"A mutable variable and an immutable variable can refer to the same box, "
"given that their types are compatible. Mutability of a box is a property of "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1023
+#: doc/tutorial.md:1015
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1026
+#: doc/tutorial.md:1018
#, no-wrap
msgid ""
"let mut c : @int; // declare a variable with type managed immutable int\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1030
+#: doc/tutorial.md:1022
#, no-wrap
msgid ""
"c = a; // box type is the same, okay\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1035
+#: doc/tutorial.md:1027
#, no-wrap
msgid ""
"~~~~ {.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1037
+#: doc/tutorial.md:1029
msgid "# Move semantics"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1043
+#: doc/tutorial.md:1035
msgid ""
"Rust uses a shallow copy for parameter passing, assignment and returning "
"values from functions. A shallow copy is considered a move of ownership if "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1049
+#: doc/tutorial.md:1041
msgid ""
"~~~~ let x = ~5; let y = x.clone(); // y is a newly allocated box let z = "
"x; // no new memory allocated, x can no longer be used ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1052
+#: doc/tutorial.md:1044
msgid ""
"Since in owned boxes mutability is a property of the owner, not the box, "
"mutable boxes may become immutable when they are moved, and vice-versa."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1059
+#: doc/tutorial.md:1051
msgid ""
"~~~~ let r = ~13; let mut s = r; // box becomes mutable *s += 1; let t = "
"s; // box becomes immutable ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1061
+#: doc/tutorial.md:1053
msgid "# Borrowed pointers"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1067
+#: doc/tutorial.md:1059
msgid ""
"Rust's borrowed pointers are a general purpose reference type. In contrast "
"with owned boxes, where the holder of an owned box is the owner of the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1069
+#: doc/tutorial.md:1061
msgid "As an example, consider a simple struct type, `Point`:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1076
+#: doc/tutorial.md:1068
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1080
+#: doc/tutorial.md:1072
msgid ""
"We can use this simple definition to allocate points in many different ways. "
"For example, in this code, each of these three local variables contains a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1087
+#: doc/tutorial.md:1079
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1099
+#: doc/tutorial.md:1089
msgid ""
"Suppose we want to write a procedure that computes the distance between any "
"two points, no matter where they are stored. For example, we might like to "
"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 pointthat is, it takes the points by value. But this "
+"two arguments of type point—that is, it takes the points by value. But this "
"will cause the points to be copied when we call the function. For points, "
-"this is probably not so bad, but often copies are expensive or, worse, if "
-"there are mutable fields, they can change the semantics of your program. So "
-"wed like to define a function that takes the points by pointer. We can use "
-"borrowed pointers to do this:"
+"this is probably not so bad, but often copies are expensive. So we’d like to "
+"define a function that takes the points by pointer. We can use borrowed "
+"pointers to do this:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1109
+#: doc/tutorial.md:1099
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1111 doc/tutorial-borrowed-ptr.md:72
+#: doc/tutorial.md:1101 doc/tutorial-borrowed-ptr.md:72
msgid "Now we can call `compute_distance()` in various ways:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1121
+#: doc/tutorial.md:1111
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1128
+#: doc/tutorial.md:1118
msgid ""
"Here the `&` operator is used to take the address of the variable "
"`on_the_stack`; this is because `on_the_stack` has the type `Point` (that "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1134
+#: doc/tutorial.md:1124
msgid ""
"In the case of the boxes `managed_box` and `owned_box`, however, no explicit "
"action is necessary. The compiler will automatically convert a box like "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1143
+#: doc/tutorial.md:1133
msgid ""
"Whenever a value is borrowed, there are some limitations on what you can do "
"with the original. For example, if the contents of a variable have been lent "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1146
+#: doc/tutorial.md:1136
msgid ""
"For a more in-depth explanation of borrowed pointers, read the [borrowed "
"pointer tutorial][borrowtut]."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1148
+#: doc/tutorial.md:1138
msgid "[borrowtut]: tutorial-borrowed-ptr.html"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1150
+#: doc/tutorial.md:1140
msgid "## Freezing"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1153
+#: doc/tutorial.md:1143
msgid ""
"Borrowing an immutable pointer to an object freezes it and prevents "
"mutation. `Owned` objects have freezing enforced statically at compile-time."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1161
+#: doc/tutorial.md:1152
#, no-wrap
msgid ""
"~~~~\n"
" let y = &x; // x is now frozen, it cannot be modified\n"
"}\n"
"// x is now unfrozen again\n"
+"# x = 3;\n"
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1165
+#: doc/tutorial.md:1156
msgid ""
"Mutable managed boxes handle freezing dynamically when any of their contents "
"are borrowed, and the task will fail if an attempt to modify them is made "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1175
+#: doc/tutorial.md:1166
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1177
+#: doc/tutorial.md:1168
msgid "# Dereferencing pointers"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1180
+#: doc/tutorial.md:1171
msgid ""
"Rust uses the unary star operator (`*`) to access the contents of a box or "
"pointer, similarly to C."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1185
+#: doc/tutorial.md:1176
msgid "~~~ let managed = @10; let owned = ~20; let borrowed = &30;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1188
+#: doc/tutorial.md:1179
msgid "let sum = *managed + *owned + *borrowed; ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1192
+#: doc/tutorial.md:1183
msgid ""
"Dereferenced mutable pointers may appear on the left hand side of "
"assignments. Such an assignment modifies the value that the pointer points "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1196
+#: doc/tutorial.md:1187
msgid "~~~ let managed = @mut 10; let mut owned = ~20;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1199
+#: doc/tutorial.md:1190
msgid "let mut value = 30; let borrowed = &mut value;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1204
+#: doc/tutorial.md:1195
#, no-wrap
msgid ""
"*managed = *owned + 10;\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1208
+#: doc/tutorial.md:1199
msgid ""
"Pointers have high operator precedence, but lower precedence than the dot "
"operator used for field and method access. This precedence order can "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1218
+#: doc/tutorial.md:1209
msgid ""
"~~~ # struct Point { x: float, y: float } # enum Shape { Rectangle(Point, "
"Point) } # impl Shape { fn area(&self) -> int { 0 } } let start = @Point "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1222
+#: doc/tutorial.md:1213
msgid ""
"To combat this ugliness the dot operator applies _automatic pointer "
"dereferencing_ to the receiver (the value on the left-hand side of the dot), "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1232
+#: doc/tutorial.md:1223
msgid ""
"~~~ # struct Point { x: float, y: float } # enum Shape { Rectangle(Point, "
"Point) } # impl Shape { fn area(&self) -> int { 0 } } let start = @Point "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1236
+#: doc/tutorial.md:1227
msgid ""
"You can write an expression that dereferences any number of pointers "
"automatically. For example, if you feel inclined, you could write something "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1242
+#: doc/tutorial.md:1233
msgid ""
"~~~ # struct Point { x: float, y: float } let point = &@~Point { x: 10f, y: "
"20f }; println(fmt!(\"%f\", point.x)); ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1244
+#: doc/tutorial.md:1235
msgid "The indexing operator (`[]`) also auto-dereferences."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1246
+#: doc/tutorial.md:1237
msgid "# Vectors and strings"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1251
+#: doc/tutorial.md:1242
msgid ""
"A vector is a contiguous section of memory containing zero or more values of "
"the same type. Like other types in Rust, vectors can be stored on the stack, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1261
+#: doc/tutorial.md:1252
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1264
+#: doc/tutorial.md:1255
msgid ""
"// A borrowed pointer to stack-allocated vector let stack_crayons: &[Crayon] "
"= &[Aquamarine, Asparagus, AtomicTangerine];"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1267
+#: doc/tutorial.md:1258
msgid ""
"// A local heap (managed) vector of crayons let local_crayons: @[Crayon] = "
"@[BananaMania, Beaver, Bittersweet];"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1271
+#: doc/tutorial.md:1262
msgid ""
"// An exchange heap (owned) vector of crayons let exchange_crayons: "
"~[Crayon] = ~[Black, BlizzardBlue, Blue]; ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1273
+#: doc/tutorial.md:1264
msgid "The `+` operator means concatenation when applied to vector types."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1278
+#: doc/tutorial.md:1274
#, no-wrap
msgid ""
"~~~~\n"
"# enum Crayon { Almond, AntiqueBrass, Apricot,\n"
"# Aquamarine, Asparagus, AtomicTangerine,\n"
"# BananaMania, Beaver, Bittersweet };\n"
+"# impl Clone for Crayon {\n"
+"# fn clone(&self) -> Crayon {\n"
+"# *self\n"
+"# }\n"
+"# }\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1281
+#: doc/tutorial.md:1277
msgid ""
"let my_crayons = ~[Almond, AntiqueBrass, Apricot]; let your_crayons = "
"~[BananaMania, Beaver, Bittersweet];"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1284
+#: doc/tutorial.md:1280
msgid ""
"// Add two vectors to create a new one let our_crayons = my_crayons + "
"your_crayons;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1289
+#: doc/tutorial.md:1285
msgid ""
"// .push_all() will append to a vector, provided it lives in a mutable slot "
"let mut my_crayons = my_crayons; my_crayons.push_all(your_crayons); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1294
+#: doc/tutorial.md:1290
msgid ""
"> ***Note:*** The above examples of vector addition use owned > vectors. "
"Some operations on slices and stack vectors are > not yet well-supported. "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1296
+#: doc/tutorial.md:1292
msgid "Square brackets denote indexing into a vector:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1308
+#: doc/tutorial.md:1304
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1310
+#: doc/tutorial.md:1306
msgid "A vector can be destructured using pattern matching:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1320
+#: doc/tutorial.md:1316
#, no-wrap
msgid ""
"~~~~\n"
-"let numbers: [int, ..3] = [1, 2, 3];\n"
+"let numbers: &[int] = &[1, 2, 3];\n"
"let score = match numbers {\n"
" [] => 0,\n"
" [a] => a * 10,\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1324
+#: doc/tutorial.md:1320
msgid ""
"The elements of a vector _inherit the mutability of the vector_, and as "
"such, individual elements may not be reassigned when the vector lives in an "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1330
+#: doc/tutorial.md:1326
#, no-wrap
msgid ""
"~~~ {.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1333
+#: doc/tutorial.md:1329
msgid "crayons[0] = Apricot; // ERROR: Can't assign to immutable vector ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1335
+#: doc/tutorial.md:1331
msgid "Moving it into a mutable slot makes the elements assignable."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1341
+#: doc/tutorial.md:1337
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1344
+#: doc/tutorial.md:1340
msgid ""
"// Put the vector into a mutable slot let mut mutable_crayons = crayons;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1348
+#: doc/tutorial.md:1344
msgid "// Now it's mutable to the bone mutable_crayons[0] = Apricot; ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1351
+#: doc/tutorial.md:1347
msgid ""
"This is a simple example of Rust's _dual-mode data structures_, also "
"referred to as _freezing and thawing_."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1359
+#: doc/tutorial.md:1355
msgid ""
"Strings are implemented with vectors of `u8`, though they have a distinct "
"type. They support most of the same allocation options as vectors, though "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1363
+#: doc/tutorial.md:1359
msgid ""
"~~~ // A plain string is a slice to read-only (static) memory let "
"stack_crayons: &str = \"Almond, AntiqueBrass, Apricot\";"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1366
+#: doc/tutorial.md:1362
msgid ""
"// The same thing, but with the `&` let stack_crayons: &str = &\"Aquamarine, "
"Asparagus, AtomicTangerine\";"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1369
+#: doc/tutorial.md:1365
msgid ""
"// A local heap (managed) string let local_crayons: @str = @\"BananaMania, "
"Beaver, Bittersweet\";"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1373
+#: doc/tutorial.md:1369
msgid ""
"// An exchange heap (owned) string let exchange_crayons: ~str = ~\"Black, "
"BlizzardBlue, Blue\"; ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1377
+#: doc/tutorial.md:1373
msgid ""
-"Both vectors and strings support a number of useful [methods](#functions-and-"
-"methods), defined in [`std::vec`] and [`std::str`]. Here are some examples."
+"Both vectors and strings support a number of useful [methods](#methods), "
+"defined in [`std::vec`] and [`std::str`]. Here are some examples."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1380
+#: doc/tutorial.md:1376
msgid "[`std::vec`]: std/vec.html [`std::str`]: std/str.html"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1391
+#: doc/tutorial.md:1387
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1393
+#: doc/tutorial.md:1389
msgid "let crayons = [Almond, AntiqueBrass, Apricot];"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1397
+#: doc/tutorial.md:1393
msgid ""
"// Check the length of the vector assert!(crayons.len() == 3); assert!(!"
"crayons.is_empty());"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1404
+#: doc/tutorial.md:1400
#, no-wrap
msgid ""
"// Iterate over a vector, obtaining a pointer to each element\n"
-"// (`for` is explained in the next section)\n"
+"// (`for` is explained in the container/iterator tutorial)\n"
"for crayon in crayons.iter() {\n"
" let delicious_crayon_wax = unwrap_crayon(*crayon);\n"
" eat_crayon_wax(delicious_crayon_wax);\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1408
+#: doc/tutorial.md:1404
msgid ""
"// Map vector elements let crayon_names = crayons.map(|v| "
"crayon_to_str(*v)); let favorite_crayon_name = crayon_names[0];"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1411
+#: doc/tutorial.md:1407
msgid ""
"// Remove whitespace from before and after the string let "
"new_favorite_crayon_name = favorite_crayon_name.trim();"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1417
+#: doc/tutorial.md:1413
#, no-wrap
msgid ""
"if favorite_crayon_name.len() > 5 {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1419
+#: doc/tutorial.md:1415
msgid "# Closures"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1424
+#: doc/tutorial.md:1420
msgid ""
"Named functions, like those we've seen so far, may not refer to local "
"variables declared outside the function: they do not close over their "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1427
+#: doc/tutorial.md:1423
msgid "~~~~ {.ignore} let foo = 10;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1432
+#: doc/tutorial.md:1428
#, no-wrap
msgid ""
"fn bar() -> int {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1435
+#: doc/tutorial.md:1431
msgid ""
"Rust also supports _closures_, functions that can access variables in the "
"enclosing scope."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1438
+#: doc/tutorial.md:1434
msgid "~~~~ fn call_closure_with_ten(b: &fn(int)) { b(10); }"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1441
+#: doc/tutorial.md:1437
msgid ""
"let captured_var = 20; let closure = |arg| println(fmt!(\"captured_var=%d, "
"arg=%d\", captured_var, arg));"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1444
+#: doc/tutorial.md:1440
msgid "call_closure_with_ten(closure); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1450
+#: doc/tutorial.md:1446
msgid ""
"Closures begin with the argument list between vertical bars and are followed "
"by a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1455
+#: doc/tutorial.md:1451
msgid ""
"The types of the arguments are generally omitted, as is the return type, "
"because the compiler can almost always infer them. In the rare case where "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1459
-msgid "~~~~ let square = |x: int| -> uint { x * x as uint }; ~~~~"
+#: doc/tutorial.md:1455
+msgid "~~~~ let square = |x: int| -> uint { (x * x) as uint }; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1463
+#: doc/tutorial.md:1459
msgid ""
"There are several forms of closure, each with its own role. The most common, "
"called a _stack closure_, has type `&fn` and can directly access local "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1468
+#: doc/tutorial.md:1464
msgid "~~~~ let mut max = 0; [1, 2, 3].map(|x| if *x > max { max = *x }); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1477
+#: doc/tutorial.md:1473
msgid ""
"Stack closures are very efficient because their environment is allocated on "
"the call stack and refers by pointer to captured locals. To ensure that "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1479
+#: doc/tutorial.md:1475
msgid "## Managed closures"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1485
+#: doc/tutorial.md:1481
msgid ""
"When you need to store a closure in a data structure, a stack closure will "
"not do, since the compiler will refuse to let you store it. For this "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1490
+#: doc/tutorial.md:1486
msgid ""
"A managed closure does not directly access its environment, but merely "
"copies out the values that it closes over into a private data structure. "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1493
+#: doc/tutorial.md:1489
msgid ""
"This code creates a closure that adds a given string to its argument, "
"returns it from a function, and then calls it:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1499
+#: doc/tutorial.md:1495
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1505
+#: doc/tutorial.md:1501
#, no-wrap
msgid ""
"fn main() {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1507
+#: doc/tutorial.md:1503
msgid "## Owned closures"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1514
+#: doc/tutorial.md:1510
msgid ""
"Owned closures, written `~fn` in analogy to the `~` pointer type, hold on to "
"things that can safely be sent between processes. They copy the values they "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1516
-msgid "[tasks]: tutorial-tasks.html"
-msgstr ""
-
-#. type: Plain text
-#: doc/tutorial.md:1518
+#: doc/tutorial.md:1512
msgid "## Closure compatibility"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1525
+#: doc/tutorial.md:1519
msgid ""
"Rust closures have a convenient subtyping property: you can pass any kind of "
"closure (as long as the arguments and return types match) to functions that "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1533
+#: doc/tutorial.md:1527
msgid ""
"~~~~ fn call_twice(f: &fn()) { f(); f(); } let closure = || { \"I'm a "
"closure, and it doesn't matter what type I am\"; }; fn function() { \"I'm a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1537
+#: doc/tutorial.md:1531
msgid ""
"> ***Note:*** Both the syntax and the semantics will be changing > in small "
"ways. At the moment they can be unsound in some > scenarios, particularly "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1539
+#: doc/tutorial.md:1533
msgid "## Do syntax"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1542
+#: doc/tutorial.md:1536
msgid ""
"The `do` expression provides a way to treat higher-order functions "
"(functions that take closures as arguments) as control structures."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1545
+#: doc/tutorial.md:1539
msgid ""
"Consider this function that iterates over a vector of integers, passing in a "
"pointer to each integer in the vector:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1555
+#: doc/tutorial.md:1549
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1559
+#: doc/tutorial.md:1553
msgid ""
"As a caller, if we use a closure to provide the final operator argument, we "
"can write it in a way that has a pleasant, block-like structure."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1567
+#: doc/tutorial.md:1561
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1570
+#: doc/tutorial.md:1564
msgid ""
"This is such a useful pattern that Rust has a special form of function call "
"that can be written more like a built-in control structure:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1578
+#: doc/tutorial.md:1572
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1583
+#: doc/tutorial.md:1577
msgid ""
"The call is prefixed with the keyword `do` and, instead of writing the final "
"closure inside the argument list, it appears outside of the parentheses, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1588
+#: doc/tutorial.md:1582
msgid ""
"`do` is a convenient way to create tasks with the `task::spawn` function. "
"`spawn` has the signature `spawn(fn: ~fn())`. In other words, it is a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1591
+#: doc/tutorial.md:1585 doc/tutorial.md:1597
msgid "~~~~ use std::task::spawn;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1596
+#: doc/tutorial.md:1590
#, no-wrap
msgid ""
"do spawn() || {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1600
+#: doc/tutorial.md:1594
msgid ""
"Look at all those bars and parentheses -- that's two empty argument lists "
"back to back. Since that is so unsightly, empty argument lists may be "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1607
+#: doc/tutorial.md:1602
#, no-wrap
msgid ""
-"~~~~\n"
-"# use std::task::spawn;\n"
"do spawn {\n"
" debug!(\"Kablam!\");\n"
"}\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1610
+#: doc/tutorial.md:1605
msgid ""
"If you want to see the output of `debug!` statements, you will need to turn "
"on `debug!` logging. To enable `debug!` logging, set the RUST_LOG "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1612
+#: doc/tutorial.md:1607
msgid "# Methods"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1618
+#: doc/tutorial.md:1613
msgid ""
"Methods are like functions except that they always begin with a special "
"argument, called `self`, which has the type of the method's receiver. The "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1622
+#: doc/tutorial.md:1617
msgid ""
"_Implementations_, written with the `impl` keyword, can define methods on "
"most Rust types, including structs and enums. As an example, let's define a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1630
+#: doc/tutorial.md:1625
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1635
+#: doc/tutorial.md:1630
#, no-wrap
msgid ""
"enum Shape {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1644
+#: doc/tutorial.md:1639
#, no-wrap
msgid ""
"impl Shape {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1648
+#: doc/tutorial.md:1643
msgid "let s = Circle(Point { x: 1f, y: 2f }, 3f); s.draw(); ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1652
+#: doc/tutorial.md:1647
msgid ""
"This defines an _implementation_ for `Shape` containing a single method, "
"`draw`. In most respects the `draw` method is defined like any other "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1657
+#: doc/tutorial.md:1652
msgid ""
"The type of `self` is the type on which the method is implemented, or a "
"pointer thereof. As an argument it is written either `self`, `&self`, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1672
+#: doc/tutorial.md:1667
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1674
+#: doc/tutorial.md:1669
msgid "let s = Circle(Point { x: 1f, y: 2f }, 3f);"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1680
+#: doc/tutorial.md:1675
msgid ""
"(@s).draw_managed(); (~s).draw_owned(); (&s).draw_borrowed(); s."
"draw_value(); ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1684
+#: doc/tutorial.md:1679
msgid ""
"Methods typically take a borrowed pointer self type, so the compiler will go "
"to great lengths to convert a callee to a borrowed pointer."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1702
+#: doc/tutorial.md:1697
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1705
+#: doc/tutorial.md:1700
msgid "(@s).draw_borrowed(); (~s).draw_borrowed();"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1709
+#: doc/tutorial.md:1704
msgid ""
"// Unlike typical function arguments, the self value will // automatically "
"be referenced ... s.draw_borrowed();"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1712
+#: doc/tutorial.md:1707
msgid "// ... and dereferenced (& &s).draw_borrowed();"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1716
+#: doc/tutorial.md:1711
msgid "// ... and dereferenced and borrowed (&@~s).draw_borrowed(); ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1720
+#: doc/tutorial.md:1715
msgid ""
"Implementations may also define standalone (sometimes called \"static\") "
"methods. The absence of a `self` parameter distinguishes such methods. "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1727
+#: doc/tutorial.md:1722
#, no-wrap
msgid ""
"~~~~ {.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1729
+#: doc/tutorial.md:1724
msgid ""
"To call such a method, just prefix it with the type name and a double colon:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1738
+#: doc/tutorial.md:1733
#, no-wrap
msgid ""
"~~~~\n"
-"# use std::float::consts::pi;\n"
+"use std::float::consts::pi;\n"
"struct Circle { radius: float }\n"
"impl Circle {\n"
" fn new(area: float) -> Circle { Circle { radius: (area / pi).sqrt() } }\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1740
+#: doc/tutorial.md:1735
msgid "# Generics"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1748
+#: doc/tutorial.md:1743
msgid ""
"Throughout this tutorial, we've been defining functions that act only on "
"specific data types. With type parameters we can also define functions whose "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1758
+#: doc/tutorial.md:1753
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1763
+#: doc/tutorial.md:1758
msgid ""
"When defined with type parameters, as denoted by `<T, U>`, this function can "
"be applied to any type of vector, as long as the type of `function`'s "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1773
+#: doc/tutorial.md:1768
msgid ""
"Inside a generic function, the names of the type parameters (capitalized by "
"convention) stand for opaque types. All you can do with instances of these "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1775
+#: doc/tutorial.md:1770
msgid ""
"Generic `type`, `struct`, and `enum` declarations follow the same pattern:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1779
-msgid "~~~~ # use std::hashmap::HashMap; type Set<T> = HashMap<T, ()>;"
+#: doc/tutorial.md:1774
+msgid "~~~~ use std::hashmap::HashMap; type Set<T> = HashMap<T, ()>;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1783
+#: doc/tutorial.md:1778
#, no-wrap
msgid ""
"struct Stack<T> {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1789
+#: doc/tutorial.md:1784
#, no-wrap
msgid ""
"enum Option<T> {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1792
+#: doc/tutorial.md:1787
msgid ""
"These declarations can be instantiated to valid types like `Set<int>`, "
"`Stack<int>`, and `Option<int>`."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1798
+#: doc/tutorial.md:1793
msgid ""
"The last type in that example, `Option`, appears frequently in Rust code. "
"Because Rust does not have null pointers (except in unsafe code), we need "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1809
+#: doc/tutorial.md:1804
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1817
+#: doc/tutorial.md:1812
msgid ""
"The Rust compiler compiles generic functions very efficiently by "
"*monomorphizing* them. *Monomorphization* is a fancy name for a simple idea: "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1819
+#: doc/tutorial.md:1814
msgid "## Traits"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1829
+#: doc/tutorial.md:1824
msgid ""
"Within a generic function the operations available on generic types are very "
"limited. After all, since the function doesn't know what types it is "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1836
+#: doc/tutorial.md:1832
msgid ""
-"As motivation, let us consider copying in Rust. The `copy` operation is not "
-"defined for all Rust types. One reason is user-defined destructors: copying "
+"As motivation, let us consider copying in Rust. The `clone` method is not "
+"defined for all Rust types. One reason is user-defined destructors: copying "
"a type that has a destructor could result in the destructor running multiple "
-"times. Therefore, types with user-defined destructors cannot be copied, "
-"either implicitly or explicitly, and neither can types that own other types "
-"containing destructors."
+"times. Therefore, types with destructors cannot be copied unless you "
+"explicitly implement `Clone` for them."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1840
+#: doc/tutorial.md:1837
msgid ""
-"This complicates handling of generic functions. If you have a type parameter "
-"`T`, can you copy values of that type? In Rust, you can't, and if you try to "
-"run the following code the compiler will complain."
+"This complicates handling of generic functions. If you have a type "
+"parameter `T`, can you copy values of that type? In Rust, you can't, and if "
+"you try to run the following code the compiler will complain."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1847
+#: doc/tutorial.md:1844
#, no-wrap
msgid ""
"~~~~ {.xfail-test}\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1852
+#: doc/tutorial.md:1851
msgid ""
"However, we can tell the compiler that the `head` function is only for "
-"copyable types: that is, those that have the `Copy` trait. In that case, we "
-"can explicitly create a second copy of the value we are returning using the "
-"`copy` keyword:"
+"copyable types: that is, those that implement the `Clone` trait. In that "
+"case, we can explicitly create a second copy of the value we are returning "
+"using the `clone` keyword:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1859
+#: doc/tutorial.md:1858
#, no-wrap
msgid ""
"~~~~\n"
"// This does\n"
-"fn head<T: Copy>(v: &[T]) -> T {\n"
-" copy v[0]\n"
+"fn head<T: Clone>(v: &[T]) -> T {\n"
+" v[0].clone()\n"
"}\n"
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1867
+#: doc/tutorial.md:1866
msgid ""
"This says that we can call `head` on any type `T` as long as that type "
-"implements the `Copy` trait. When instantiating a generic function, you can "
-"only instantiate it with types that implement the correct trait, so you "
-"could not apply `head` to a type with a destructor. (`Copy` is a special "
-"trait that is built in to the compiler, making it possible for the compiler "
-"to enforce this restriction.)"
+"implements the `Clone` trait. When instantiating a generic function, you "
+"can only instantiate it with types that implement the correct trait, so you "
+"could not apply `head` to a type that does not implement `Clone`."
msgstr ""
#. type: Plain text
#: doc/tutorial.md:1871
msgid ""
-"While most traits can be defined and implemented by user code, three traits "
+"While most traits can be defined and implemented by user code, two traits "
"are automatically derived and implemented for all applicable types by the "
"compiler, and may not be overridden:"
msgstr ""
-#. type: Bullet: '* '
+#. type: Plain text
#: doc/tutorial.md:1875
+#, no-wrap
msgid ""
-"`Copy` - Types that can be copied, either implicitly, or explicitly with the "
-"`copy` operator. All types are copyable unless they have destructors or "
-"contain types with destructors."
-msgstr ""
-
-#. type: Bullet: '* '
-#: doc/tutorial.md:1879
-msgid ""
-"`Owned` - Owned types. Types are owned unless they contain managed boxes, "
-"managed closures, or borrowed pointers. Owned types may or may not be "
-"copyable."
+"* `Send` - Sendable types.\n"
+"Types are sendable\n"
+"unless they contain managed boxes, managed closures, or borrowed pointers.\n"
msgstr ""
-#. type: Bullet: '* '
-#: doc/tutorial.md:1882
+#. type: Plain text
+#: doc/tutorial.md:1880
+#, no-wrap
msgid ""
-"`Const` - Constant (immutable) types. These are types that do not contain "
-"mutable fields."
+"* `Freeze` - Constant (immutable) types.\n"
+"These are types that do not contain anything intrinsically mutable.\n"
+"Intrinsically mutable values include `@mut`\n"
+"and `Cell` in the standard library.\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1885
+#: doc/tutorial.md:1883
msgid ""
-"> ***Note:*** These three traits were referred to as 'kinds' in earlier > "
+"> ***Note:*** These two traits were referred to as 'kinds' in earlier > "
"iterations of the language, and often still are."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1891
+#: doc/tutorial.md:1889
msgid ""
"Additionally, the `Drop` trait is used to define destructors. This trait "
"defines one method called `drop`, which is automatically called when a value "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1896
+#: doc/tutorial.md:1894
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1905
+#: doc/tutorial.md:1903
#, no-wrap
msgid ""
"impl Drop for TimeBomb {\n"
" fn drop(&self) {\n"
-" for self.explosivity.times {\n"
+" for _ in range(0, self.explosivity) {\n"
" println(\"blam!\");\n"
" }\n"
" }\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1908
+#: doc/tutorial.md:1906
msgid ""
"It is illegal to call `drop` directly. Only code inserted by the compiler "
"may call it."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1910
+#: doc/tutorial.md:1908
msgid "## Declaring and implementing traits"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1915
+#: doc/tutorial.md:1914
msgid ""
-"A trait consists of a set of methods, without bodies, or may be empty, as is "
-"the case with `Copy`, `Owned`, and `Const`. For example, we could declare "
-"the trait `Printable` for things that can be printed to the console, with a "
-"single method:"
+"A trait consists of a set of methods without bodies, or may be empty, as is "
+"the case with `Send` and `Freeze`. For example, we could declare the trait "
+"`Printable` for things that can be printed to the console, with a single "
+"method:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1921
+#: doc/tutorial.md:1920
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1926
+#: doc/tutorial.md:1925
msgid ""
"Traits may be implemented for specific types with [impls]. An impl that "
"implements a trait includes the name of the trait at the start of the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1928
-msgid "[impls]: #functions-and-methods"
+#: doc/tutorial.md:1927
+msgid "[impls]: #methods"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1934
+#: doc/tutorial.md:1933
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1938
+#: doc/tutorial.md:1937
#, no-wrap
msgid ""
"impl Printable for ~str {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1942
+#: doc/tutorial.md:1941
msgid "# 1.print(); # (~\"foo\").print(); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1947
+#: doc/tutorial.md:1946
msgid ""
"Methods defined in an implementation of a trait may be called just like any "
"other method, using dot notation, as in `1.print()`. Traits may themselves "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1952
+#: doc/tutorial.md:1951
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1957
+#: doc/tutorial.md:1956
#, no-wrap
msgid ""
"impl<T> Seq<T> for ~[T] {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1964
+#: doc/tutorial.md:1963
msgid ""
"The implementation has to explicitly declare the type parameter that it "
"binds, `T`, before using it to specify its trait type. Rust requires this "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1969
+#: doc/tutorial.md:1968
msgid ""
"The type parameters bound by a trait are in scope in each of the method "
"declarations. So, re-declaring the type parameter `T` as an explicit type "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1974
+#: doc/tutorial.md:1973
msgid ""
"Within a trait definition, `Self` is a special type that you can think of as "
"a type parameter. An implementation of the trait for any given type `T` "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1981
+#: doc/tutorial.md:1980
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1987
+#: doc/tutorial.md:1986
#, no-wrap
msgid ""
"// In an impl, `self` refers just to the value of the receiver\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1992
+#: doc/tutorial.md:1991
msgid ""
"Notice that in the trait definition, `equals` takes a second parameter of "
"type `Self`. In contrast, in the `impl`, `equals` takes a second parameter "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:1997
+#: doc/tutorial.md:1996
msgid ""
"Just as in type implementations, traits can define standalone (static) "
"methods. These methods are called by prefixing the method name with the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2003
+#: doc/tutorial.md:2002
msgid ""
-"~~~~ # use std::float::consts::pi; trait Shape { fn new(area: float) -> "
+"~~~~ use std::float::consts::pi; trait Shape { fn new(area: float) -> "
"Self; } struct Circle { radius: float } struct Square { length: float }"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2010
+#: doc/tutorial.md:2009
#, no-wrap
msgid ""
"impl Shape for Circle {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2015
+#: doc/tutorial.md:2014
msgid ""
"let area = 42.5; let c: Circle = Shape::new(area); let s: Square = Shape::"
"new(area); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2017
+#: doc/tutorial.md:2016
msgid "## Bounded type parameters and static method dispatch"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2022
+#: doc/tutorial.md:2021
msgid ""
"Traits give us a language for defining predicates on types, or abstract "
"properties that types can have. We can use this language to define _bounds_ "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2031
+#: doc/tutorial.md:2030
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2037
+#: doc/tutorial.md:2036
msgid ""
"Declaring `T` as conforming to the `Printable` trait (as we earlier did with "
-"`Copy`) makes it possible to call methods from that trait on values of type "
+"`Clone`) makes it possible to call methods from that trait on values of type "
"`T` inside the function. It will also cause a compile-time error when anyone "
"tries to call `print_all` on an array whose element type does not have a "
"`Printable` implementation."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2040
+#: doc/tutorial.md:2039
msgid ""
"Type parameters can have multiple bounds by separating them with `+`, as in "
"this version of `print_all` that copies elements."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2052
+#: doc/tutorial.md:2051
#, no-wrap
msgid ""
"~~~\n"
"# trait Printable { fn print(&self); }\n"
-"fn print_all<T: Printable + Copy>(printable_things: ~[T]) {\n"
+"fn print_all<T: Printable + Clone>(printable_things: ~[T]) {\n"
" let mut i = 0;\n"
" while i < printable_things.len() {\n"
-" let copy_of_thing = copy printable_things[i];\n"
+" let copy_of_thing = printable_things[i].clone();\n"
" copy_of_thing.print();\n"
" i += 1;\n"
" }\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2056
+#: doc/tutorial.md:2055
msgid ""
"Method calls to bounded type parameters are _statically dispatched_, "
"imposing no more overhead than normal function invocation, so are the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2058
+#: doc/tutorial.md:2057
msgid "This usage of traits is similar to Haskell type classes."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2060
+#: doc/tutorial.md:2059
msgid "## Trait objects and dynamic method dispatch"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2064
+#: doc/tutorial.md:2063
msgid ""
"The above allows us to define functions that polymorphically act on values "
"of a single unknown type that conforms to a given trait. However, consider "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2070
+#: doc/tutorial.md:2069
msgid ""
"~~~~ # type Circle = int; type Rectangle = int; # impl Drawable for int { fn "
"draw(&self) {} } # fn new_circle() -> int { 1 } trait Drawable { fn "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2077
+#: doc/tutorial.md:2076
#, no-wrap
msgid ""
"fn draw_all<T: Drawable>(shapes: ~[T]) {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2083
+#: doc/tutorial.md:2082
msgid ""
"You can call that on an array of circles, or an array of rectangles "
"(assuming those have suitable `Drawable` traits defined), but not on an "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2090
+#: doc/tutorial.md:2089
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2095
+#: doc/tutorial.md:2094
msgid ""
"In this example, there is no type parameter. Instead, the `@Drawable` type "
"denotes any managed box value that implements the `Drawable` trait. To "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2102
+#: doc/tutorial.md:2101
msgid ""
"~~~~ # type Circle = int; type Rectangle = bool; # trait Drawable { fn "
"draw(&self); } # fn new_circle() -> Circle { 1 } # fn new_rectangle() -> "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2105
+#: doc/tutorial.md:2104
msgid ""
"impl Drawable for Circle { fn draw(&self) { ... } } impl Drawable for "
"Rectangle { fn draw(&self) { ... } }"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2110
+#: doc/tutorial.md:2109
msgid ""
"let c: @Circle = @new_circle(); let r: @Rectangle = @new_rectangle(); "
"draw_all([c as @Drawable, r as @Drawable]); ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2118
+#: doc/tutorial.md:2117
msgid ""
"We omit the code for `new_circle` and `new_rectangle`; imagine that these "
"just return `Circle`s and `Rectangle`s with a default size. Note that, like "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2132
+#: doc/tutorial.md:2131
msgid ""
"~~~ # type Circle = int; type Rectangle = int; # trait Drawable { fn "
"draw(&self); } # impl Drawable for int { fn draw(&self) {} } # fn "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2137
+#: doc/tutorial.md:2136
msgid ""
"Method calls to trait types are _dynamically dispatched_. Since the compiler "
"doesn't know specifically which functions to call at compile time, it uses a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2139
+#: doc/tutorial.md:2138
msgid "This usage of traits is similar to Java interfaces."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2141
+#: doc/tutorial.md:2140
msgid "## Trait inheritance"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2146
+#: doc/tutorial.md:2145
msgid ""
"We can write a trait declaration that _inherits_ from other traits, called "
"_supertraits_. Types that implement a trait must also implement its "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2151
+#: doc/tutorial.md:2150
msgid ""
"~~~~ trait Shape { fn area(&self) -> float; } trait Circle : Shape { fn "
"radius(&self) -> float; } ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2153
+#: doc/tutorial.md:2152
msgid ""
"Now, we can implement `Circle` on a type only if we also implement `Shape`."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2168
+#: doc/tutorial.md:2167
#, no-wrap
msgid ""
"~~~~\n"
-"# use std::float::consts::pi;\n"
+"use std::float::consts::pi;\n"
"# trait Shape { fn area(&self) -> float; }\n"
"# trait Circle : Shape { fn radius(&self) -> float; }\n"
"# struct Point { x: float, y: float }\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2173
+#: doc/tutorial.md:2172
msgid ""
"Notice that methods of `Circle` can call methods on `Shape`, as our `radius` "
"implementation calls the `area` method. This is a silly way to compute the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2197
+#: doc/tutorial.md:2196
msgid ""
-"~~~ {.xfail-test} # use std::float::consts::pi; # trait Shape { fn "
-"area(&self) -> float; } # trait Circle : Shape { fn radius(&self) -> "
-"float; } # struct Point { x: float, y: float } # struct CircleStruct "
-"{ center: Point, radius: float } # impl Circle for CircleStruct { fn "
-"radius(&self) -> float { (self.area() / pi).sqrt() } } # impl Shape for "
-"CircleStruct { fn area(&self) -> float { pi * square(self.radius) } }"
+"~~~ {.xfail-test} use std::float::consts::pi; # trait Shape { fn area(&self) "
+"-> float; } # trait Circle : Shape { fn radius(&self) -> float; } # struct "
+"Point { x: float, y: float } # struct CircleStruct { center: Point, radius: "
+"float } # impl Circle for CircleStruct { fn radius(&self) -> float { (self."
+"area() / pi).sqrt() } } # impl Shape for CircleStruct { fn area(&self) -> "
+"float { pi * square(self.radius) } }"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2202
+#: doc/tutorial.md:2201
msgid ""
"let concrete = @CircleStruct{center:Point{x:3f,y:4f},radius:5f}; let "
-"mycircle: Circle = concrete as @Circle; let nonsense = mycircle.radius() * "
+"mycircle: @Circle = concrete as @Circle; let nonsense = mycircle.radius() * "
"mycircle.area(); ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2204
+#: doc/tutorial.md:2203
msgid "> ***Note:*** Trait inheritance does not actually work with objects yet"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2206
+#: doc/tutorial.md:2205
msgid "## Deriving implementations for traits"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2213
+#: doc/tutorial.md:2212
msgid ""
"A small number of traits in `std` and `extra` can have implementations that "
"can be automatically derived. These instances are specified by placing the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2217
+#: doc/tutorial.md:2216
msgid "~~~ #[deriving(Eq)] struct Circle { radius: float }"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2221
+#: doc/tutorial.md:2220
msgid "#[deriving(Rand, ToStr)] enum ABC { A, B, C } ~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2225
+#: doc/tutorial.md:2224
msgid ""
"The full list of derivable traits is `Eq`, `TotalEq`, `Ord`, `TotalOrd`, "
"`Encodable` `Decodable`, `Clone`, `DeepClone`, `IterBytes`, `Rand`, `Zero`, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2227
+#: doc/tutorial.md:2226
msgid "# Modules and crates"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2231
+#: doc/tutorial.md:2230
msgid ""
"The Rust namespace is arranged in a hierarchy of modules. Each source (.rs) "
"file represents a single module and may in turn contain additional modules."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2237
+#: doc/tutorial.md:2236
#, no-wrap
msgid ""
"~~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2242
+#: doc/tutorial.md:2241
#, no-wrap
msgid ""
"fn main() {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2247
+#: doc/tutorial.md:2246
msgid ""
"The contents of modules can be imported into the current scope with the "
"`use` keyword, optionally giving it an alias. `use` may appear at the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2253
+#: doc/tutorial.md:2252
msgid ""
"~~~ # mod farm { pub fn chicken() { } } # fn main() { // Bring `chicken` "
"into scope use farm::chicken;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2263
+#: doc/tutorial.md:2262
#, no-wrap
msgid ""
"fn chicken_farmer() {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2270
+#: doc/tutorial.md:2269
msgid ""
"These farm animal functions have a new keyword, `pub`, attached to them. The "
"`pub` keyword modifies an item's visibility, making it visible outside its "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2277
+#: doc/tutorial.md:2276
msgid ""
"Visibility restrictions in Rust exist only at module boundaries. This is "
"quite different from most object-oriented languages that also enforce "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2290
+#: doc/tutorial.md:2289
#, no-wrap
msgid ""
"~~~\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2296
+#: doc/tutorial.md:2295
#, no-wrap
msgid ""
" impl Farm {\n"
-" priv fn feed_chickens(&self) { ... }\n"
-" priv fn feed_cows(&self) { ... }\n"
+" fn feed_chickens(&self) { ... }\n"
+" fn feed_cows(&self) { ... }\n"
" pub fn add_chicken(&self, c: Chicken) { ... }\n"
" }\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2302
+#: doc/tutorial.md:2301
#, no-wrap
msgid ""
" pub fn feed_animals(farm: &Farm) {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2312
+#: doc/tutorial.md:2311
#, no-wrap
msgid ""
"fn main() {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2314
+#: doc/tutorial.md:2313
msgid "## Crates"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2318
+#: doc/tutorial.md:2317
msgid ""
"The unit of independent compilation in Rust is the crate: rustc compiles a "
"single crate at a time, from which it produces either a library or an "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2323
+#: doc/tutorial.md:2322
msgid ""
"When compiling a single `.rs` source file, the file acts as the whole "
"crate. You can compile it with the `--lib` compiler switch to create a "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2328
+#: doc/tutorial.md:2327
msgid ""
"Larger crates typically span multiple files and are, by convention, compiled "
"from a source file with the `.rc` extension, called a *crate file*. The "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2337
+#: doc/tutorial.md:2336
msgid ""
"A typical crate file declares attributes associated with the crate that may "
"affect how the compiler processes the source. Crate attributes specify "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2341
+#: doc/tutorial.md:2340
msgid ""
"~~~~ { .xfail-test } // Crate linkage metadata #[link(name = \"farm\", vers "
"= \"2.5\", author = \"mjh\")];"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2344
+#: doc/tutorial.md:2343
msgid "// Make a library (\"bin\" is the default) #[crate_type = \"lib\"];"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2347
+#: doc/tutorial.md:2346
msgid "// Turn on a warning #[warn(non_camel_case_types)]"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2350
+#: doc/tutorial.md:2349
msgid "// Link to the standard library extern mod std;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2355
+#: doc/tutorial.md:2354
msgid "// Load some modules from other files mod cow; mod chicken; mod horse;"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2360
+#: doc/tutorial.md:2359
#, no-wrap
msgid ""
"fn main() {\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2367
+#: doc/tutorial.md:2366
msgid ""
"Compiling this file will cause `rustc` to look for files named `cow.rs`, "
"`chicken.rs`, and `horse.rs` in the same directory as the `.rc` file, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2371
+#: doc/tutorial.md:2370
msgid ""
"The `#[link(...)]` attribute provides meta information about the module, "
"which other crates can use to load the right module. More about that later."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2374
+#: doc/tutorial.md:2373
msgid ""
"To have a nested directory structure for your source files, you can nest "
"mods:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2381
+#: doc/tutorial.md:2380
#, no-wrap
msgid ""
"~~~~ {.ignore}\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2386
+#: doc/tutorial.md:2385
msgid ""
"The compiler will now look for `poultry/chicken.rs` and `poultry/turkey.rs`, "
"and export their content in `poultry::chicken` and `poultry::turkey`. You "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2388
+#: doc/tutorial.md:2387
msgid "## Using other crates"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2396
+#: doc/tutorial.md:2395
msgid ""
"The `extern mod` directive lets you use a crate (once it's been compiled "
"into a library) from inside another crate. `extern mod` can appear at the "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2398
+#: doc/tutorial.md:2397
msgid "For example, `extern mod std` links the [standard library]."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2400
+#: doc/tutorial.md:2399
msgid "[standard library]: std/index.html"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2407
+#: doc/tutorial.md:2406
msgid ""
"When a comma-separated list of name/value pairs appears after `extern mod`, "
"the compiler front-end matches these pairs against the attributes provided "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2409
+#: doc/tutorial.md:2408
msgid "Our example crate declared this set of `link` attributes:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2413
+#: doc/tutorial.md:2412
msgid "~~~~ #[link(name = \"farm\", vers = \"2.5\", author = \"mjh\")]; ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2415
+#: doc/tutorial.md:2414
msgid "Which you can then link with any (or all) of the following:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2421
+#: doc/tutorial.md:2420
msgid ""
"~~~~ {.xfail-test} extern mod farm; extern mod my_farm (name = \"farm\", "
"vers = \"2.5\"); extern mod my_auxiliary_farm (name = \"farm\", author = "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2424
+#: doc/tutorial.md:2423
msgid ""
"If any of the requested metadata do not match, then the crate will not be "
"compiled successfully."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2426
+#: doc/tutorial.md:2425
msgid "## A minimal example"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2429
+#: doc/tutorial.md:2428
msgid ""
"Now for something that you can actually compile yourself, we have these two "
"files:"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2435
+#: doc/tutorial.md:2434
msgid ""
"~~~~ // world.rs #[link(name = \"world\", vers = \"1.0\")]; pub fn explore() "
"-> &str { \"world\" } ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2441
+#: doc/tutorial.md:2440
msgid ""
"~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello "
"\" + world::explore()); } ~~~~"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2443
+#: doc/tutorial.md:2442
msgid "Now compile and run like this (adjust to your platform if necessary):"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2450
+#: doc/tutorial.md:2449
#, no-wrap
msgid ""
"~~~~ {.notrust}\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2455
+#: doc/tutorial.md:2454
msgid ""
"Notice that the library produced contains the version in the filename as "
"well as an inscrutable string of alphanumerics. These are both part of "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2457
+#: doc/tutorial.md:2456
msgid "## The standard library"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2462
+#: doc/tutorial.md:2461
msgid ""
"The Rust standard library provides runtime features required by the "
"language, including the task scheduler and memory allocators, as well as "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2473
+#: doc/tutorial.md:2472
msgid ""
"[`std`] includes modules corresponding to each of the integer types, each of "
"the floating point types, the [`bool`] type, [tuples], [characters], "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2475
+#: doc/tutorial.md:2474
msgid "### Standard Library injection and the Rust prelude"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2478
+#: doc/tutorial.md:2477
msgid ""
"`std` is imported at the topmost level of every crate by default, as if the "
"first line of each crate was"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2480
+#: doc/tutorial.md:2479
#, no-wrap
msgid " extern mod std;\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2484
+#: doc/tutorial.md:2483
msgid ""
"This means that the contents of std can be accessed from from any context "
"with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`, "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2489
+#: doc/tutorial.md:2488
msgid ""
"Additionally, `std` contains a `prelude` module that reexports many of the "
"most common standard modules, types and traits. The contents of the prelude "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2491
+#: doc/tutorial.md:2490
#, no-wrap
msgid " use std::prelude::*;\n"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2517
+#: doc/tutorial.md:2516
msgid ""
"[`std`]: std/index.html [`bool`]: std/bool.html [tuples]: std/tuple.html "
"[characters]: std/char.html [strings]: std/str.html [vectors]: std/vec.html "
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2519
+#: doc/tutorial.md:2518
msgid "# What next?"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2522
+#: doc/tutorial.md:2521
msgid ""
"Now that you know the essentials, check out any of the additional tutorials "
"on individual topics."
msgstr ""
#. type: Bullet: '* '
-#: doc/tutorial.md:2528
+#: doc/tutorial.md:2527
msgid "[Borrowed pointers][borrow]"
msgstr ""
#. type: Bullet: '* '
-#: doc/tutorial.md:2528
+#: doc/tutorial.md:2527
msgid "[Tasks and communication][tasks]"
msgstr ""
#. type: Bullet: '* '
-#: doc/tutorial.md:2528
+#: doc/tutorial.md:2527
msgid "[Macros][macros]"
msgstr ""
#. type: Bullet: '* '
-#: doc/tutorial.md:2528
+#: doc/tutorial.md:2527
msgid "[The foreign function interface][ffi]"
msgstr ""
#. type: Bullet: '* '
-#: doc/tutorial.md:2528
+#: doc/tutorial.md:2527
msgid "[Containers and iterators](tutorial-container.html)"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2530
+#: doc/tutorial.md:2529
msgid "There is further documentation on the [wiki]."
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2535
+#: doc/tutorial.md:2534
msgid ""
"[borrow]: tutorial-borrowed-ptr.html [tasks]: tutorial-tasks.html [macros]: "
"tutorial-macros.html [ffi]: tutorial-ffi.html"
msgstr ""
#. type: Plain text
-#: doc/tutorial.md:2541
-msgid ""
-"[wiki]: https://github.com/mozilla/rust/wiki/Docs [unit testing]: https://"
-"github.com/mozilla/rust/wiki/Doc-unit-testing [rustdoc]: https://github.com/"
-"mozilla/rust/wiki/Doc-using-rustdoc [cargo]: https://github.com/mozilla/rust/"
-"wiki/Doc-using-cargo-to-manage-packages [attributes]: https://github.com/"
-"mozilla/rust/wiki/Doc-attributes"
-msgstr ""
-
-#. type: Plain text
-#: doc/tutorial.md:2542
-msgid ""
-"[pound-rust]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust"
+#: doc/tutorial.md:2536
+msgid "[wiki]: https://github.com/mozilla/rust/wiki/Docs"
msgstr ""
# Add here a list of target languages; po4a will automatically
# generates .po for them and build .md when translated, eg:
# [po4a_langs] es fr it pt_BR
-[po4a_langs]
+[po4a_langs] ja
[po4a_paths] doc/po/$master.pot $lang:doc/po/$lang/$master.po
# Add here below all source documents to be translated
Each source file contains a sequence of zero or more `item` definitions,
and may optionally begin with any number of `attributes` that apply to the containing module.
-Atributes on the anonymous crate module define important metadata that influences
+Attributes on the anonymous crate module define important metadata that influences
the behavior of the compiler.
~~~~~~~~
##### Use declarations
~~~~~~~~ {.ebnf .gram}
-use_decl : "pub"? "use" ident [ '=' path
+use_decl : "pub" ? "use" ident [ '=' path
| "::" path_glob ] ;
path_glob : ident [ "::" path_glob ] ?
In type-parameterized functions,
methods of the supertrait may be called on values of subtrait-bound type parameters.
-Refering to the previous example of `trait Circle : Shape`:
+Referring to the previous example of `trait Circle : Shape`:
~~~
# trait Shape { fn area(&self) -> float; }
When the field is mutable, it can be [assigned](#assignment-expressions) to.
When the type of the expression to the left of the dot is a pointer to a record or structure,
-it is automatically derferenced to make the field access possible.
+it is automatically dereferenced to make the field access possible.
### Vector expressions
~~~~~~~~{.ebnf .gram}
-vec_expr : '[' "mut"? vec_elems? ']'
+vec_expr : '[' "mut" ? vec_elems? ']'
vec_elems : [expr [',' expr]*] | [expr ',' ".." expr]
~~~~~~~~
An example of an object type:
~~~~~~~~
-# use std::int;
trait Printable {
- fn to_str(&self) -> ~str;
+ fn to_string(&self) -> ~str;
}
impl Printable for int {
- fn to_str(&self) -> ~str { int::to_str(*self) }
+ fn to_string(&self) -> ~str { self.to_str() }
}
fn print(a: @Printable) {
- println(a.to_str());
+ println(a.to_string());
}
fn main() {
--- /dev/null
+% Rust Condition and Error-handling Tutorial
+
+# Introduction
+
+Rust does not provide exception handling[^why-no-exceptions]
+in the form most commonly seen in other programming languages such as C++ or Java.
+Instead, it provides four mechanisms that work together to handle errors or other rare events.
+The four mechanisms are:
+
+ - Options
+ - Results
+ - Failure
+ - Conditions
+
+This tutorial will lead you through use of these mechanisms
+in order to understand the trade-offs of each and relationships between them.
+
+# Example program
+
+This tutorial will be based around an example program
+that attempts to read lines from a file
+consisting of pairs of numbers,
+and then print them back out with slightly different formatting.
+The input to the program might look like this:
+
+~~~~ {.notrust}
+$ cat numbers.txt
+1 2
+34 56
+789 123
+45 67
+~~~~
+
+For which the intended output looks like this:
+
+~~~~ {.notrust}
+$ ./example numbers.txt
+0001, 0002
+0034, 0056
+0789, 0123
+0045, 0067
+~~~~
+
+An example program that does this task reads like this:
+
+~~~~
+# #[allow(unused_imports)];
+extern mod extra;
+use extra::fileinput::FileInput;
+use std::int;
+# mod FileInput {
+# use std::io::{Reader, BytesReader};
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn from_args() -> @Reader{
+# @BytesReader {
+# bytes: s,
+# pos: @mut 0
+# } as @Reader
+# }
+# }
+
+fn main() {
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println(fmt!("%4.4d, %4.4d", a, b));
+ }
+}
+
+
+fn read_int_pairs() -> ~[(int,int)] {
+
+ let mut pairs = ~[];
+
+ let fi = FileInput::from_args();
+ while ! fi.eof() {
+
+ // 1. Read a line of input.
+ let line = fi.read_line();
+
+ // 2. Split the line into fields ("words").
+ let fields = line.word_iter().to_owned_vec();
+
+ // 3. Match the vector of fields against a vector pattern.
+ match fields {
+
+ // 4. When the line had two fields:
+ [a, b] => {
+
+ // 5. Try parsing both fields as ints.
+ match (int::from_str(a), int::from_str(b)) {
+
+ // 6. If parsing succeeded for both, push both.
+ (Some(a), Some(b)) => pairs.push((a,b)),
+
+ // 7. Ignore non-int fields.
+ _ => ()
+ }
+ }
+
+ // 8. Ignore lines that don't have 2 fields.
+ _ => ()
+ }
+ }
+
+ pairs
+}
+~~~~
+
+This example shows the use of `Option`,
+along with some other forms of error-handling (and non-handling).
+We will look at these mechanisms
+and then modify parts of the example to perform "better" error handling.
+
+
+# Options
+
+The simplest and most lightweight mechanism in Rust for indicating an error is the type `std::option::Option<T>`.
+This type is a general purpose `enum`
+for conveying a value of type `T`, represented as `Some(T)`
+_or_ the sentinel `None`, to indicate the absence of a `T` value.
+For simple APIs, it may be sufficient to encode errors as `Option<T>`,
+returning `Some(T)` on success and `None` on error.
+In the example program, the call to `int::from_str` returns `Option<int>`
+with the understanding that "all parse errors" result in `None`.
+The resulting `Option<int>` values are matched against the pattern `(Some(a), Some(b))`
+in steps 5 and 6 in the example program,
+to handle the case in which both fields were parsed successfully.
+
+Using `Option` as in this API has some advantages:
+
+ - Simple API, users can read it and guess how it works.
+ - Very efficient, only an extra `enum` tag on return values.
+ - Caller has flexibility in handling or propagating errors.
+ - Caller is forced to acknowledge existence of possible-error before using value.
+
+However, it has serious disadvantages too:
+
+ - Verbose, requires matching results or calling `Option::unwrap` everywhere.
+ - Infects caller: if caller doesn't know how to handle the error, must propagate (or force).
+ - Temptation to do just that: force the `Some(T)` case by blindly calling `unwrap`,
+ which hides the error from the API without providing any way to make the program robust against the error.
+ - Collapses all errors into one:
+ - Caller can't handle different errors differently.
+ - Caller can't even report a very precise error message
+
+Note that in order to keep the example code reasonably compact,
+several unwanted cases are silently ignored:
+lines that do not contain two fields, as well as fields that do not parse as ints.
+To propagate these cases to the caller using `Option` would require even more verbose code.
+
+
+# Results
+
+Before getting into _trapping_ the error,
+we will look at a slight refinement on the `Option` type above.
+This second mechanism for indicating an error is called a `Result`.
+The type `std::result::Result<T,E>` is another simple `enum` type with two forms, `Ok(T)` and `Err(E)`.
+The `Result` type is not substantially different from the `Option` type in terms of its ergonomics.
+Its main advantage is that the error constructor `Err(E)` can convey _more detail_ about the error.
+For example, the `int::from_str` API could be reformed
+to return a `Result` carrying an informative description of a parse error,
+like this:
+
+~~~~ {.ignore}
+enum IntParseErr {
+ EmptyInput,
+ Overflow,
+ BadChar(char)
+}
+
+fn int::from_str(&str) -> Result<int,IntParseErr> {
+ // ...
+}
+~~~~
+
+This would give the caller more information for both handling and reporting the error,
+but would otherwise retain the verbosity problems of using `Option`.
+In particular, it would still be necessary for the caller to return a further `Result` to _its_ caller if it did not want to handle the error.
+Manually propagating result values this way can be attractive in certain circumstances
+-- for example when processing must halt on the very first error, or backtrack --
+but as we will see later, many cases have simpler options available.
+
+# Failure
+
+The third and arguably easiest mechanism for handling errors is called "failure".
+In fact it was hinted at earlier by suggesting that one can choose to propagate `Option` or `Result` types _or "force" them_.
+"Forcing" them, in this case, means calling a method like `Option<T>::unwrap`,
+which contains the following code:
+
+~~~~ {.ignore}
+pub fn unwrap(self) -> T {
+ match self {
+ Some(x) => return x,
+ None => fail!("option::unwrap `None`")
+ }
+}
+~~~~
+
+That is, it returns `T` when `self` is `Some(T)`, and _fails_ when `self` is `None`.
+
+Every Rust task can _fail_, either indirectly due to a kill signal or other asynchronous event,
+or directly by failing an `assert!` or calling the `fail!` macro.
+Failure is an _unrecoverable event_ at the task level:
+it causes the task to halt normal execution and unwind its control stack,
+freeing all task-local resources (the local heap as well as any task-owned values from the global heap)
+and running destructors (the `drop` method of the `Drop` trait)
+as frames are unwound and heap values destroyed.
+A failing task is not permitted to "catch" the unwinding during failure and recover,
+it is only allowed to clean up and exit.
+
+Failure has advantages:
+
+ - Simple and non-verbose. Suitable for programs that can't reasonably continue past an error anyways.
+ - _All_ errors (except memory-safety errors) can be uniformly trapped in a supervisory task outside the failing task.
+ For a large program to be robust against a variety of errors,
+ often some form of task-level partitioning to contain pervasive errors (arithmetic overflow, division by zero,
+ logic bugs) is necessary anyways.
+
+As well as obvious disadvantages:
+
+ - A blunt instrument, terminates the containing task entirely.
+
+Recall that in the first two approaches to error handling,
+the example program was only handling success cases, and ignoring error cases.
+That is, if the input is changed to contain a malformed line:
+
+~~~~ {.notrust}
+$ cat bad.txt
+1 2
+34 56
+ostrich
+789 123
+45 67
+~~~~
+
+Then the program would give the same output as if there was no error:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+0789, 0123
+0045, 0067
+~~~~
+
+If the example is rewritten to use failure, these error cases can be trapped.
+In this rewriting, failures are trapped by placing the I/O logic in a sub-task,
+and trapping its exit status using `task::try`:
+
+~~~~ {.xfail-test}
+# #[allowed(unused_imports)];
+extern mod extra;
+use extra::fileinput::FileInput;
+use std::int;
+use std::task;
+# mod FileInput {
+# use std::io::{Reader, BytesReader};
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# ostrich\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn from_args() -> @Reader{
+# @BytesReader {
+# bytes: s,
+# pos: @mut 0
+# } as @Reader
+# }
+# }
+
+fn main() {
+
+ // Isolate failure within a subtask.
+ let result = do task::try {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println(fmt!("%4.4d, %4.4d", a, b));
+ }
+
+ };
+ if result.is_err() {
+ println("parsing failed");
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+ let fi = FileInput::from_args();
+ while ! fi.eof() {
+ let line = fi.read_line();
+ let fields = line.word_iter().to_owned_vec();
+ match fields {
+ [a, b] => pairs.push((int::from_str(a).unwrap(),
+ int::from_str(b).unwrap())),
+
+ // Explicitly fail on malformed lines.
+ _ => fail!()
+ }
+ }
+ pairs
+}
+~~~~
+
+With these changes in place, running the program on malformed input gives a different answer:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+rust: task failed at 'explicit failure', ./example.rs:44
+parsing failed
+~~~~
+
+Note that while failure unwinds the sub-task performing I/O in `read_int_pairs`,
+control returns to `main` and can easily continue uninterrupted.
+In this case, control simply prints out `parsing failed` and then exits `main` (successfully).
+Failure of a (sub-)task is analogous to calling `exit(1)` or `abort()` in a unix C program:
+all the state of a sub-task is cleanly discarded on exit,
+and a supervisor task can take appropriate action
+without worrying about its own state having been corrupted.
+
+
+# Conditions
+
+The final mechanism for handling errors is called a "condition".
+Conditions are less blunt than failure, and less cumbersome than the `Option` or `Result` types;
+indeed they are designed to strike just the right balance between the two.
+Conditions require some care to use effectively, but give maximum flexibility with minimum verbosity.
+While conditions use exception-like terminology ("trap", "raise") they are significantly different:
+
+ - Like exceptions and failure, conditions separate the site at which the error is raised from the site where it is trapped.
+ - Unlike exceptions and unlike failure, when a condition is raised and trapped, _no unwinding occurs_.
+ - A successfully trapped condition causes execution to continue _at the site of the error_, as though no error occurred.
+
+Conditions are declared with the `condition!` macro.
+Each condition has a name, an input type and an output type, much like a function.
+In fact, conditions are implemented as dynamically-scoped functions held in task local storage.
+
+The `condition!` macro declares a module with the name of the condition;
+the module contains a single static value called `cond`, of type `std::condition::Condition`.
+The `cond` value within the module is the rendezvous point
+between the site of error and the site that handles the error.
+It has two methods of interest: `raise` and `trap`.
+
+The `raise` method maps a value of the condition's input type to its output type.
+The input type should therefore convey all relevant information to the condition handler.
+The output type should convey all relevant information _for continuing execution at the site of error_.
+When the error site raises a condition handler,
+the `Condition::raise` method searches task-local storage (TLS) for the innermost installed _handler_,
+and if any such handler is found, calls it with the provided input value.
+If no handler is found, `Condition::raise` will fail the task with an appropriate error message.
+
+Rewriting the example to use a condition in place of ignoring malformed lines makes it slightly longer,
+but similarly clear as the version that used `fail!` in the logic where the error occurs:
+
+~~~~ {.xfail-test}
+# #[allow(unused_imports)];
+extern mod extra;
+use extra::fileinput::FileInput;
+use std::int;
+# mod FileInput {
+# use std::io::{Reader, BytesReader};
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# ostrich\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn from_args() -> @Reader{
+# @BytesReader {
+# bytes: s,
+# pos: @mut 0
+# } as @Reader
+# }
+# }
+
+// Introduce a new condition.
+condition! {
+ pub malformed_line : ~str -> (int,int);
+}
+
+fn main() {
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println(fmt!("%4.4d, %4.4d", a, b));
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+ let fi = FileInput::from_args();
+ while ! fi.eof() {
+ let line = fi.read_line();
+ let fields = line.word_iter().to_owned_vec();
+ match fields {
+ [a, b] => pairs.push((int::from_str(a).unwrap(),
+ int::from_str(b).unwrap())),
+
+ // On malformed lines, call the condition handler and
+ // push whatever the condition handler returns.
+ _ => pairs.push(malformed_line::cond.raise(line.clone()))
+ }
+ }
+ pairs
+}
+~~~~
+
+When this is run on malformed input, it still fails,
+but with a slightly different failure message than before:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+rust: task failed at 'Unhandled condition: malformed_line: ~"ostrich"', .../libstd/condition.rs:43
+~~~~
+
+While this superficially resembles the trapped `fail!` call before,
+it is only because the example did not install a handler for the condition.
+The different failure message is indicating, among other things,
+that the condition-handling system is being invoked and failing
+only due to the absence of a _handler_ that traps the condition.
+
+# Trapping a condition
+
+To trap a condition, use `Condition::trap` in some caller of the site that calls `Condition::raise`.
+For example, this version of the program traps the `malformed_line` condition
+and replaces bad input lines with the pair `(-1,-1)`:
+
+~~~~
+# #[allow(unused_imports)];
+extern mod extra;
+use extra::fileinput::FileInput;
+use std::int;
+# mod FileInput {
+# use std::io::{Reader, BytesReader};
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# ostrich\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn from_args() -> @Reader{
+# @BytesReader {
+# bytes: s,
+# pos: @mut 0
+# } as @Reader
+# }
+# }
+
+condition! {
+ pub malformed_line : ~str -> (int,int);
+}
+
+fn main() {
+ // Trap the condition:
+ do malformed_line::cond.trap(|_| (-1,-1)).inside {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println(fmt!("%4.4d, %4.4d", a, b));
+ }
+
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+ let fi = FileInput::from_args();
+ while ! fi.eof() {
+ let line = fi.read_line();
+ let fields = line.word_iter().to_owned_vec();
+ match fields {
+ [a, b] => pairs.push((int::from_str(a).unwrap(),
+ int::from_str(b).unwrap())),
+ _ => pairs.push(malformed_line::cond.raise(line.clone()))
+ }
+ }
+ pairs
+}
+~~~~
+
+Note that the remainder of the program is _unchanged_ with this trap in place;
+only the caller that installs the trap changed.
+Yet when the condition-trapping variant runs on the malformed input,
+it continues execution past the malformed line, substituting the handler's return value.
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+-0001, -0001
+0789, 0123
+0045, 0067
+~~~~
+
+# Refining a condition
+
+As you work with a condition, you may find that the original set of options you present for recovery is insufficient.
+This is no different than any other issue of API design:
+a condition handler is an API for recovering from the condition, and sometimes APIs need to be enriched.
+In the example program, the first form of the `malformed_line` API implicitly assumes that recovery involves a substitute value.
+This assumption may not be correct; some callers may wish to skip malformed lines, for example.
+Changing the condition's return type from `(int,int)` to `Option<(int,int)>` will suffice to support this type of recovery:
+
+~~~~
+# #[allow(unused_imports)];
+extern mod extra;
+use extra::fileinput::FileInput;
+use std::int;
+# mod FileInput {
+# use std::io::{Reader, BytesReader};
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# ostrich\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn from_args() -> @Reader{
+# @BytesReader {
+# bytes: s,
+# pos: @mut 0
+# } as @Reader
+# }
+# }
+
+// Modify the condition signature to return an Option.
+condition! {
+ pub malformed_line : ~str -> Option<(int,int)>;
+}
+
+fn main() {
+ // Trap the condition and return `None`
+ do malformed_line::cond.trap(|_| None).inside {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println(fmt!("%4.4d, %4.4d", a, b));
+ }
+
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+ let fi = FileInput::from_args();
+ while ! fi.eof() {
+ let line = fi.read_line();
+ let fields = line.word_iter().to_owned_vec();
+ match fields {
+ [a, b] => pairs.push((int::from_str(a).unwrap(),
+ int::from_str(b).unwrap())),
+
+ // On malformed lines, call the condition handler and
+ // either ignore the line (if the handler returns `None`)
+ // or push any `Some(pair)` value returned instead.
+ _ => {
+ match malformed_line::cond.raise(line.clone()) {
+ Some(pair) => pairs.push(pair),
+ None => ()
+ }
+ }
+ }
+ }
+ pairs
+}
+~~~~
+
+Again, note that the remainder of the program is _unchanged_,
+in particular the signature of `read_int_pairs` is unchanged,
+even though the innermost part of its reading-loop has a new way of handling a malformed line.
+When the example is run with the `None` trap in place,
+the line is ignored as it was in the first example,
+but the choice of whether to ignore or use a substitute value has been moved to some caller,
+possibly a distant caller.
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+0789, 0123
+0045, 0067
+~~~~
+
+# Further refining a condition
+
+Like with any API, the process of refining argument and return types of a condition will continue,
+until all relevant combinations encountered in practice are encoded.
+In the example, suppose a third possible recovery form arose: reusing the previous value read.
+This can be encoded in the handler API by introducing a helper type: `enum MalformedLineFix`.
+
+~~~~
+# #[allow(unused_imports)];
+extern mod extra;
+use extra::fileinput::FileInput;
+use std::int;
+# mod FileInput {
+# use std::io::{Reader, BytesReader};
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# ostrich\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn from_args() -> @Reader{
+# @BytesReader {
+# bytes: s,
+# pos: @mut 0
+# } as @Reader
+# }
+# }
+
+// Introduce a new enum to convey condition-handling strategy to error site.
+pub enum MalformedLineFix {
+ UsePair(int,int),
+ IgnoreLine,
+ UsePreviousLine
+}
+
+// Modify the condition signature to return the new enum.
+// Note: a condition introduces a new module, so the enum must be
+// named with the `super::` prefix to access it.
+condition! {
+ pub malformed_line : ~str -> super::MalformedLineFix;
+}
+
+fn main() {
+ // Trap the condition and return `UsePreviousLine`
+ do malformed_line::cond.trap(|_| UsePreviousLine).inside {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println(fmt!("%4.4d, %4.4d", a, b));
+ }
+
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+ let fi = FileInput::from_args();
+ while ! fi.eof() {
+ let line = fi.read_line();
+ let fields = line.word_iter().to_owned_vec();
+ match fields {
+ [a, b] => pairs.push((int::from_str(a).unwrap(),
+ int::from_str(b).unwrap())),
+
+ // On malformed lines, call the condition handler and
+ // take action appropriate to the enum value returned.
+ _ => {
+ match malformed_line::cond.raise(line.clone()) {
+ UsePair(a,b) => pairs.push((a,b)),
+ IgnoreLine => (),
+ UsePreviousLine => {
+ let prev = pairs[pairs.len() - 1];
+ pairs.push(prev)
+ }
+ }
+ }
+ }
+ }
+ pairs
+}
+~~~~
+
+Running the example with `UsePreviousLine` as the fix code returned from the handler
+gives the expected result:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+0034, 0056
+0789, 0123
+0045, 0067
+~~~~
+
+At this point the example has a rich variety of recovery options,
+none of which is visible to casual users of the `read_int_pairs` function.
+This is intentional: part of the purpose of using a condition
+is to free intermediate callers from the burden of having to write repetitive error-propagation logic,
+and/or having to change function call and return types as error-handling strategies are refined.
+
+# Multiple conditions, intermediate callers
+
+So far the function trapping the condition and the function raising it have been immediately adjacent in the call stack.
+That is, the caller traps and its immediate callee raises.
+In most programs, the function that traps may be separated by very many function calls from the function that raises.
+Again, this is part of the point of using conditions:
+to support that separation without having to thread multiple error values and recovery strategies all the way through the program's main logic.
+
+Careful readers will notice that there is a remaining failure mode in the example program: the call to `.unwrap()` when parsing each integer.
+For example, when presented with a file that has the correct number of fields on a line,
+but a non-numeric value in one of them, such as this:
+
+~~~~ {.notrust}
+$ cat bad.txt
+1 2
+34 56
+7 marmot
+789 123
+45 67
+~~~~
+
+
+Then the program fails once more:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+task <unnamed> failed at 'called `Option::unwrap()` on a `None` value', .../libstd/option.rs:314
+~~~~
+
+To make the program robust -- or at least flexible -- in the face of this potential failure,
+a second condition and a helper function will suffice:
+
+~~~~
+# #[allow(unused_imports)];
+extern mod extra;
+use extra::fileinput::FileInput;
+use std::int;
+# mod FileInput {
+# use std::io::{Reader, BytesReader};
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# 7 marmot\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn from_args() -> @Reader{
+# @BytesReader {
+# bytes: s,
+# pos: @mut 0
+# } as @Reader
+# }
+# }
+
+pub enum MalformedLineFix {
+ UsePair(int,int),
+ IgnoreLine,
+ UsePreviousLine
+}
+
+condition! {
+ pub malformed_line : ~str -> ::MalformedLineFix;
+}
+
+// Introduce a second condition.
+condition! {
+ pub malformed_int : ~str -> int;
+}
+
+fn main() {
+ // Trap the `malformed_int` condition and return -1
+ do malformed_int::cond.trap(|_| -1).inside {
+
+ // Trap the `malformed_line` condition and return `UsePreviousLine`
+ do malformed_line::cond.trap(|_| UsePreviousLine).inside {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println(fmt!("%4.4d, %4.4d", a, b));
+ }
+
+ }
+ }
+}
+
+// Parse an int; if parsing fails, call the condition handler and
+// return whatever it returns.
+fn parse_int(x: &str) -> int {
+ match int::from_str(x) {
+ Some(v) => v,
+ None => malformed_int::cond.raise(x.to_owned())
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+ let fi = FileInput::from_args();
+ while ! fi.eof() {
+ let line = fi.read_line();
+ let fields = line.word_iter().to_owned_vec();
+ match fields {
+
+ // Delegate parsing ints to helper function that will
+ // handle parse errors by calling `malformed_int`.
+ [a, b] => pairs.push((parse_int(a), parse_int(b))),
+
+ _ => {
+ match malformed_line::cond.raise(line.clone()) {
+ UsePair(a,b) => pairs.push((a,b)),
+ IgnoreLine => (),
+ UsePreviousLine => {
+ let prev = pairs[pairs.len() - 1];
+ pairs.push(prev)
+ }
+ }
+ }
+ }
+ }
+ pairs
+}
+~~~~
+
+Again, note that `read_int_pairs` has not changed signature,
+nor has any of the machinery for trapping or raising `malformed_line`,
+but now the program can handle the "right number of fields, non-integral field" form of bad input:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+0007, -0001
+0789, 0123
+0045, 0067
+~~~~
+
+There are three other things to note in this variant of the example program:
+
+ - It traps multiple conditions simultaneously,
+ nesting the protected logic of one `trap` call inside the other.
+
+ - There is a function in between the `trap` site and `raise` site for the `malformed_int` condition.
+ There could be any number of calls between them:
+ so long as the `raise` occurs within a callee (of any depth) of the logic protected by the `trap` call,
+ it will invoke the handler.
+
+ - This variant insulates callers from a design choice in the `int` library:
+ the `int::from_str` function was designed to return an `Option<int>`,
+ but this program insulates callers from that choice,
+ routing all `None` values that arise from parsing integers in this file into the condition.
+
+
+# When to use which technique
+
+This tutorial explored several techniques for handling errors.
+Each is appropriate to different circumstances:
+
+ - If an error may be extremely frequent, expected, and very likely dealt with by an immediate caller,
+ then returning an `Option` or `Result` type is best. These types force the caller to handle the error,
+ and incur the lowest speed overhead, usually only returning one extra word to tag the return value.
+ Between `Option` and `Result`: use an `Option` when there is only one kind of error,
+ otherwise make an `enum FooErr` to represent the possible error codes and use `Result<T,FooErr>`.
+
+ - If an error can reasonably be handled at the site it occurs by one of a few strategies -- possibly including failure --
+ and it is not clear which strategy a caller would want to use, a condition is best.
+ For many errors, the only reasonable "non-stop" recovery strategies are to retry some number of times,
+ create or substitute an empty or sentinel value, ignore the error, or fail.
+
+ - If an error cannot reasonably be handled at the site it occurs,
+ and the only reasonable response is to abandon a large set of operations in progress,
+ then directly failing is best.
+
+Note that an unhandled condition will cause failure (along with a more-informative-than-usual message),
+so if there is any possibility that a caller might wish to "ignore and keep going",
+it is usually harmless to use a condition in place of a direct call to `fail!()`.
+
+
+[^why-no-exceptions]: Exceptions in languages like C++ and Java permit unwinding, like Rust's failure system,
+but with the option to halt unwinding partway through the process and continue execution.
+This behavior unfortunately means that the _heap_ may be left in an inconsistent but accessible state,
+if an exception is thrown part way through the process of initializing or modifying memory.
+To compensate for this risk, correct C++ and Java code must program in an extremely elaborate and difficult "exception-safe" style
+-- effectively transactional style against heap structures --
+or else risk introducing silent and very difficult-to-debug errors due to control resuming in a corrupted heap after a caught exception.
+These errors are frequently memory-safety errors, which Rust strives to eliminate,
+and so Rust unwinding is unrecoverable within a single task:
+once unwinding starts, the entire local heap of a task is destroyed and the task is terminated.
\ No newline at end of file
* `iter()` and `rev_iter()`, for immutable references to the elements
* `mut_iter()` and `mut_rev_iter()`, for mutable references to the elements
-* `consume_iter()` and `consume_rev_iter`, to move the elements out by-value
+* `move_iter()` and `move_rev_iter`, to move the elements out by-value
A typical mutable container will implement at least `iter()`, `mut_iter()` and
-`consume_iter()` along with the reverse variants if it maintains an order.
+`move_iter()` along with the reverse variants if it maintains an order.
### Freezing
## 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:
+The `Iterator` trait provides many common algorithms as default methods. 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 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);
+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` keyword can be used as sugar for iterating through any iterator:
~~~
-let xs = [2, 3, 5, 7, 11, 13, 17];
+let xs = [2u, 3, 5, 7, 11, 13, 17];
// print out all the elements in the vector
for x in xs.iter() {
~~~
let xs = [0, 1, 1, 2, 3, 5, 8];
-let ys = xs.rev_iter().skip(1).transform(|&x| x * 2).collect::<~[int]>();
+let ys = xs.rev_iter().skip(1).map(|&x| x * 2).collect::<~[int]>();
assert_eq!(ys, ~[10, 6, 4, 2, 2, 0]);
~~~
implementing the `FromIterator` trait. For example, the implementation for
vectors is as follows:
-~~~
-impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
- pub fn from_iterator(iterator: &mut T) -> ~[A] {
+~~~ {.xfail-test}
+impl<A> FromIterator<A> for ~[A] {
+ pub fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
let (lower, _) = iterator.size_hint();
let mut xs = with_capacity(lower);
for x in iterator {
The `Iterator` trait provides a `size_hint` default method, returning a lower
bound and optionally on upper bound on the length of the iterator:
-~~~
+~~~ {.xfail-test}
fn size_hint(&self) -> (uint, Option<uint>) { (0, None) }
~~~
The `rev_iter` and `mut_rev_iter` methods on vectors just return an inverted
version of the standard immutable and mutable vector iterators.
-The `chain_`, `transform`, `filter`, `filter_map` and `peek` adaptors are
+The `chain`, `map`, `filter`, `filter_map` and `inspect` adaptors are
`DoubleEndedIterator` implementations if the underlying iterators are.
~~~
let xs = [1, 2, 3, 4];
let ys = [5, 6, 7, 8];
-let mut it = xs.iter().chain_(ys.iter()).transform(|&x| x * 2);
+let mut it = xs.iter().chain(ys.iter()).map(|&x| x * 2);
printfln!("%?", it.next()); // prints `Some(2)`
}
~~~
+The `reverse_` method is also available for any double-ended iterator yielding
+mutable references. It can be used to reverse a container in-place. Note that
+the trailing underscore is a workaround for issue #5898 and will be removed.
+
+~~~
+let mut ys = [1, 2, 3, 4, 5];
+ys.mut_iter().reverse_();
+assert_eq!(ys, [5, 4, 3, 2, 1]);
+~~~
+
## Random-access iterators
The `RandomAccessIterator` trait represents an iterator offering random access
to the whole range. The `indexable` method retrieves the number of elements
accessible with the `idx` method.
-The `chain_` adaptor is an implementation of `RandomAccessIterator` if the
+The `chain` adaptor is an implementation of `RandomAccessIterator` if the
underlying iterators are.
~~~
let xs = [1, 2, 3, 4, 5];
let ys = ~[7, 9, 11];
-let mut it = xs.iter().chain_(ys.iter());
+let mut it = xs.iter().chain(ys.iter());
printfln!("%?", it.idx(0)); // prints `Some(&1)`
printfln!("%?", it.idx(5)); // prints `Some(&7)`
printfln!("%?", it.idx(7)); // prints `Some(&11)`
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}
+#[fixed_stack_segment]
fn main() {
let x = unsafe { snappy_max_compressed_length(100) };
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
Rust's safe memory model.
+Finally, the `#[fixed_stack_segment]` annotation that appears on
+`main()` instructs the Rust compiler that when `main()` executes, it
+should request a "very large" stack segment. More details on
+stack management can be found in the following sections.
+
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 allocated memory. The length is less than or equal to the capacity.
~~~~ {.xfail-test}
+#[fixed_stack_segment]
+#[inline(never)]
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
unsafe {
snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
signature.
+The `validate_compressed_buffer` wrapper is also annotated with two
+attributes `#[fixed_stack_segment]` and `#[inline(never)]`. The
+purpose of these attributes is to guarantee that there will be
+sufficient stack for the C function to execute. This is necessary
+because Rust, unlike C, does not assume that the stack is allocated in
+one continuous chunk. Instead, we rely on a *segmented stack* scheme,
+in which the stack grows and shrinks as necessary. C code, however,
+expects one large stack, and so callers of C functions must request a
+large stack segment to ensure that the C routine will not run off the
+end of the stack.
+
+The compiler includes a lint mode that will report an error if you
+call a C function without a `#[fixed_stack_segment]` attribute. More
+details on the lint mode are given in a later section.
+
+You may be wondering why we include a `#[inline(never)]` directive.
+This directive informs the compiler never to inline this function.
+While not strictly necessary, it is usually a good idea to use an
+`#[inline(never)]` directive in concert with `#[fixed_stack_segment]`.
+The reason is that if a fn annotated with `fixed_stack_segment` is
+inlined, then its caller also inherits the `fixed_stack_segment`
+annotation. This means that rather than requesting a large stack
+segment only for the duration of the call into C, the large stack
+segment would be used for the entire duration of the caller. This is
+not necessarily *bad* -- it can for example be more efficient,
+particularly if `validate_compressed_buffer()` is called multiple
+times in a row -- but it does work against the purpose of the
+segmented stack scheme, which is to keep stacks small and thus
+conserve address space.
+
The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
allocated to hold the output too.
~~~~ {.xfail-test}
pub fn compress(src: &[u8]) -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let srclen = src.len() as size_t;
let psrc = vec::raw::to_ptr(src);
~~~~ {.xfail-test}
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let srclen = src.len() as size_t;
let psrc = vec::raw::to_ptr(src);
For reference, the examples used here are also available as an [library on
GitHub](https://github.com/thestinger/rust-snappy).
+# Automatic wrappers
+
+Sometimes writing Rust wrappers can be quite tedious. For example, if
+function does not take any pointer arguments, often there is no need
+for translating types. In such cases, it is usually still a good idea
+to have a Rust wrapper so as to manage the segmented stacks, but you
+can take advantage of the (standard) `externfn!` macro to remove some
+of the tedium.
+
+In the initial section, we showed an extern block that added a call
+to a specific snappy API:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+#[link_args = "-lsnappy"]
+extern {
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+}
+
+#[fixed_stack_segment]
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+To avoid the need to create a wrapper fn for `snappy_max_compressed_length()`,
+and also to avoid the need to think about `#[fixed_stack_segment]`, we
+could simply use the `externfn!` macro instead, as shown here:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+externfn!(#[link_args = "-lsnappy"]
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t)
+
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+As you can see from the example, `externfn!` replaces the extern block
+entirely. After macro expansion, it will create something like this:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+// Automatically generated by
+// externfn!(#[link_args = "-lsnappy"]
+// fn snappy_max_compressed_length(source_length: size_t) -> size_t)
+unsafe fn snappy_max_compressed_length(source_length: size_t) -> size_t {
+ #[fixed_stack_segment]; #[inline(never)];
+ return snappy_max_compressed_length(source_length);
+
+ #[link_args = "-lsnappy"]
+ extern {
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+ }
+}
+
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+# Segmented stacks and the linter
+
+By default, whenever you invoke a non-Rust fn, the `cstack` lint will
+check that one of the following conditions holds:
+
+1. The call occurs inside of a fn that has been annotated with
+ `#[fixed_stack_segment]`;
+2. The call occurs inside of an `extern fn`;
+3. The call occurs within a stack closure created by some other
+ safe fn.
+
+All of these conditions ensure that you are running on a large stack
+segmented. However, they are sometimes too strict. If your application
+will be making many calls into C, it is often beneficial to promote
+the `#[fixed_stack_segment]` attribute higher up the call chain. For
+example, the Rust compiler actually labels main itself as requiring a
+`#[fixed_stack_segment]`. In such cases, the linter is just an
+annoyance, because all C calls that occur from within the Rust
+compiler are made on a large stack. Another situation where this
+frequently occurs is on a 64-bit architecture, where large stacks are
+the default. In cases, you can disable the linter by including a
+`#[allow(cstack)]` directive somewhere, which permits violations of
+the "cstack" rules given above (you can also use `#[warn(cstack)]` to
+convert the errors into warnings, if you prefer).
+
# Destructors
Foreign libraries often hand off ownership of resources to the calling code,
impl<T: Send> Unique<T> {
pub fn new(value: T) -> Unique<T> {
+ #[fixed_stack_segment];
+ #[inline(never)];
+
unsafe {
let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T;
assert!(!ptr::is_null(ptr));
#[unsafe_destructor]
impl<T: Send> Drop for Unique<T> {
fn drop(&self) {
+ #[fixed_stack_segment];
+ #[inline(never)];
+
unsafe {
let x = intrinsics::init(); // dummy value to swap in
// moving the object out is needed to call the destructor
fn signum(x: int) -> int {
if x < 0 { -1 }
else if x > 0 { 1 }
- else { return 0 }
+ else { 0 }
}
~~~~
`loop` denotes an infinite loop, and is the preferred way of writing `while true`:
~~~~
-use std::int;
-let mut x = 5;
+let mut x = 5u;
loop {
x += x - 3;
if x % 5 == 0 { break; }
- println(int::to_str(x));
+ println(x.to_str());
}
~~~~
######################################################################
DOCS :=
+DOCS_L10N :=
######################################################################
--include-before-body=doc/version_info.html \
--output=$@
+DOCS_L10N += doc/l10n/ja/tutorial.html
+doc/l10n/ja/tutorial.html: doc/l10n/ja/tutorial.md doc/version_info.html doc/rust.css
+ @$(call E, pandoc: $@)
+ $(Q)$(CFG_NODE) $(S)doc/prep.js --highlight doc/l10n/ja/tutorial.md | \
+ $(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-macros.html
doc/tutorial-macros.html: tutorial-macros.md doc/version_info.html \
doc/rust.css
--include-before-body=doc/version_info.html \
--output=$@
+DOCS += doc/tutorial-conditions.html
+doc/tutorial-conditions.html: tutorial-conditions.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=$@
+
ifeq ($(CFG_PDFLATEX),)
$(info cfg: no pdflatex found, omitting doc/rust.pdf)
else
docs: $(DOCS)
-docs-l10n:
+docs-l10n: $(DOCS_L10N)
+
+doc/l10n/%.md: doc/po/%.md.po doc/po4a.conf
po4a --copyright-holder="The Rust Project Developers" \
--package-name="Rust" \
--package-version="$(CFG_RELEASE)" \
+ -M UTF-8 -L UTF-8 \
doc/po4a.conf
.PHONY: docs-l10n
rt/sync/rust_thread.cpp \
rt/rust_builtin.cpp \
rt/rust_run_program.cpp \
- rt/rust_env.cpp \
rt/rust_rng.cpp \
- rt/rust_stack.cpp \
rt/rust_upcall.cpp \
rt/rust_uv.cpp \
rt/rust_crate_map.cpp \
$$(Q)$(AR_$(1)) rcs $$@ $$<
rt/$(1)/stage$(2)/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)_$(2)) $$(MKFILE_DEPS) \
- $$(RUNTIME_DEF_$(1)_$(2)) $$(LIBUV_LIB_$(1)_$(2))
+ $$(RUNTIME_DEF_$(1)_$(2)) $$(LIBUV_LIB_$(1)_$(2)) $$(JEMALLOC_LIB_$(1)_$(2))
@$$(call E, link: $$@)
$$(Q)$$(call CFG_LINK_CXX_$(1),$$@, $$(RUNTIME_OBJS_$(1)_$(2)) \
- $$(CFG_GCCISH_POST_LIB_FLAGS_$(1)) $$(LIBUV_LIB_$(1)_$(2)) \
+ $$(JEMALLOC_LIB_$(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
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) $(BORROWCK) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
# Only build the compiler for host triples
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
# Markdown files under doc/ that should have their code extracted and run
-DOC_TEST_NAMES = tutorial tutorial-ffi tutorial-macros tutorial-borrowed-ptr tutorial-tasks rust
+DOC_TEST_NAMES = tutorial tutorial-ffi tutorial-macros tutorial-borrowed-ptr \
+ tutorial-tasks tutorial-conditions tutorial-container rust
######################################################################
# Environment configuration
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)): \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X_$(4)): \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUST_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUST_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rust$$(X_$(4)): \
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())),
+ env: Some(env),
dir: None,
in_fd: None,
out_fd: None,
use util;
use util::logv;
+use std::cell::Cell;
use std::io;
use std::os;
use std::str;
+use std::task::{spawn_sched, SingleThreaded};
use std::vec;
+use std::unstable::running_on_valgrind;
use extra::test::MetricMap;
pub fn run(config: config, testfile: ~str) {
- let mut _mm = MetricMap::new();
- run_metrics(config, testfile, &mut _mm);
+ let config = Cell::new(config);
+ let testfile = Cell::new(testfile);
+ // FIXME #6436: Creating another thread to run the test because this
+ // is going to call waitpid. The new scheduler has some strange
+ // interaction between the blocking tasks and 'friend' schedulers
+ // that destroys parallelism if we let normal schedulers block.
+ // It should be possible to remove this spawn once std::run is
+ // rewritten to be non-blocking.
+ //
+ // We do _not_ create another thread if we're running on V because
+ // it serializes all threads anyways.
+ if running_on_valgrind() {
+ let config = config.take();
+ let testfile = testfile.take();
+ let mut _mm = MetricMap::new();
+ run_metrics(config, testfile, &mut _mm);
+ } else {
+ do spawn_sched(SingleThreaded) {
+ let config = config.take();
+ let testfile = testfile.take();
+ let mut _mm = MetricMap::new();
+ run_metrics(config, testfile, &mut _mm);
+ }
+ }
}
pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
#include <math.h>
#include <stdio.h>
-// must match core::ctypes
+// must match std::ctypes
#define C_FLT(x) (float)x
#define C_DBL(x) (double)x
"//": "linecomment",
"/*": "openblockcomment",
-"*/": "closeblockcomment"
+"*/": "closeblockcomment",
+"macro_rules": "macro_rules",
+"=>" : "eg",
+".." : "dotdot",
+"," : "comma"
}
lines = []
# xfail-license
# This creates the tables used for distributions implemented using the
-# ziggurat algorithm in `core::rand::distributions;`. They are
+# ziggurat algorithm in `std::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.
'path-statement[path statements with no effect]'
'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]'
+ 'ctypes[proper use of std::libc types in foreign modules]'
"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]'
do 10.times {
let tmp = *num;
*num = -1;
- task::yield();
+ task::deschedule();
*num = tmp + 1;
}
c.send(());
do read_mode.read |state| {
// if writer mistakenly got in, make sure it mutates state
// before we assert on it
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
// make sure writer didn't get in.
assert!(*state);
}
}
#[test]
fn test_rw_write_cond_downgrade_read_race() {
- // Ideally the above test case would have yield statements in it that
+ // Ideally the above test case would have deschedule statements in it that
// helped to expose the race nearly 100% of the time... but adding
- // yields in the intuitively-right locations made it even less likely,
+ // deschedules in the intuitively-right locations made it even less likely,
// and I wasn't sure why :( . This is a mediocre "next best" option.
do 8.times { test_rw_write_cond_downgrade_read_race_helper() }
}
use std::libc;
fn malloc(n: size_t) -> CVec<u8> {
+ #[fixed_stack_segment];
+ #[inline(never)];
+
unsafe {
let mem = libc::malloc(n);
assert!(mem as int != 0);
- c_vec_with_dtor(mem as *mut u8, n as uint, || free(mem))
+ return c_vec_with_dtor(mem as *mut u8, n as uint, || f(mem));
+ }
+
+ fn f(mem: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::free(mem) }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::num::One;
+use std::num::{One, Zero, CheckedAdd};
use std::vec::bytes::{MutableByteVector, copy_memory};
}
}
+/// Write a u32 into a vector, which must be 4 bytes long. The value is written in little-endian
+/// format.
+pub fn write_u32_le(dst: &mut[u8], input: u32) {
+ use std::cast::transmute;
+ use std::unstable::intrinsics::to_le32;
+ assert!(dst.len() == 4);
+ unsafe {
+ let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
+ *x = to_le32(input as i32);
+ }
+}
+
/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format.
pub fn read_u64v_be(dst: &mut[u64], input: &[u8]) {
use std::cast::transmute;
}
}
+/// Read a vector of bytes into a vector of u32s. The values are read in little-endian format.
+pub fn read_u32v_le(dst: &mut[u32], input: &[u8]) {
+ use std::cast::transmute;
+ use std::unstable::intrinsics::to_le32;
+ assert!(dst.len() * 4 == input.len());
+ unsafe {
+ let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
+ let mut y: *i32 = transmute(input.unsafe_ref(0));
+ do dst.len().times() {
+ *x = to_le32(*y);
+ x = x.offset(1);
+ y = y.offset(1);
+ }
+ }
+}
+
-/// Returns true if adding the two parameters will result in integer overflow
-pub fn will_add_overflow<T: Int + Unsigned>(x: T, y: T) -> bool {
- // This doesn't handle negative values! Don't copy this code elsewhere without considering if
- // negative values are important to you!
- let max: T = Bounded::max_value();
- return x > max - y;
+trait ToBits {
+ /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
+ /// high-order value and the 2nd item is the low order value.
+ fn to_bits(self) -> (Self, Self);
}
-/// Shifts the second parameter and then adds it to the first. fails!() if there would be unsigned
-/// integer overflow.
-pub fn shift_add_check_overflow<T: Int + Unsigned + Clone>(x: T, mut y: T, shift: T) -> T {
- if y.leading_zeros() < shift {
- fail!("Could not add values - integer overflow.");
+impl ToBits for u64 {
+ fn to_bits(self) -> (u64, u64) {
+ return (self >> 61, self << 3);
}
- y = y << shift;
+}
- if will_add_overflow(x.clone(), y.clone()) {
- fail!("Could not add values - integer overflow.");
- }
+/// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric
+/// overflow.
+pub fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T {
+ let (new_high_bits, new_low_bits) = bytes.to_bits();
- return x + y;
-}
+ if new_high_bits > Zero::zero() {
+ fail!("Numeric overflow occured.")
+ }
-/// Shifts the second parameter and then adds it to the first, which is a tuple where the first
-/// element is the high order value. fails!() if there would be unsigned integer overflow.
-pub fn shift_add_check_overflow_tuple
- <T: Int + Unsigned + Clone>
- (x: (T, T), mut y: T, shift: T) -> (T, T) {
- if y.leading_zeros() < shift {
- fail!("Could not add values - integer overflow.");
+ match bits.checked_add(&new_low_bits) {
+ Some(x) => return x,
+ None => fail!("Numeric overflow occured.")
}
- y = y << shift;
+}
- match x {
- (hi, low) => {
- let one: T = One::one();
- if will_add_overflow(low.clone(), y.clone()) {
- if will_add_overflow(hi.clone(), one.clone()) {
- fail!("Could not add values - integer overflow.");
- } else {
- return (hi + one, low + y);
- }
+/// Adds the specified number of bytes to the bit count, which is a tuple where the first element is
+/// the high order value. fail!() if this would cause numeric overflow.
+pub fn add_bytes_to_bits_tuple
+ <T: Int + Unsigned + CheckedAdd + ToBits>
+ (bits: (T, T), bytes: T) -> (T, T) {
+ let (new_high_bits, new_low_bits) = bytes.to_bits();
+ let (hi, low) = bits;
+
+ // Add the low order value - if there is no overflow, then add the high order values
+ // If the addition of the low order values causes overflow, add one to the high order values
+ // before adding them.
+ match low.checked_add(&new_low_bits) {
+ Some(x) => {
+ if new_high_bits == Zero::zero() {
+ // This is the fast path - every other alternative will rarely occur in practice
+ // considering how large an input would need to be for those paths to be used.
+ return (hi, x);
} else {
- return (hi, low + y);
+ match hi.checked_add(&new_high_bits) {
+ Some(y) => return (y, x),
+ None => fail!("Numeric overflow occured.")
+ }
+ }
+ },
+ None => {
+ let one: T = One::one();
+ let z = match new_high_bits.checked_add(&one) {
+ Some(w) => w,
+ None => fail!("Numeric overflow occured.")
+ };
+ match hi.checked_add(&z) {
+ // This re-executes the addition that was already performed earlier when overflow
+ // occured, this time allowing the overflow to happen. Technically, this could be
+ // avoided by using the checked add intrinsic directly, but that involves using
+ // unsafe code and is not really worthwhile considering how infrequently code will
+ // run in practice. This is the reason that this function requires that the type T
+ // be Unsigned - overflow is not defined for Signed types. This function could be
+ // implemented for signed types as well if that were needed.
+ Some(y) => return (y, low + new_low_bits),
+ None => fail!("Numeric overflow occured.")
}
}
}
/// method that modifies the buffer directory or provides the caller with bytes that can be modifies
/// results in those bytes being marked as used by the buffer.
pub trait FixedBuffer {
- /// Input a vector of bytes. If the buffer becomes full, proccess it with the provided
+ /// Input a vector of bytes. If the buffer becomes full, process it with the provided
/// function and then clear the buffer.
fn input(&mut self, input: &[u8], func: &fn(&[u8]));
use std::rand::RngUtil;
use std::vec;
+ use cryptoutil::{add_bytes_to_bits, add_bytes_to_bits_tuple};
use digest::Digest;
/// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
assert!(expected == result_str);
}
+
+ // A normal addition - no overflow occurs
+ #[test]
+ fn test_add_bytes_to_bits_ok() {
+ assert!(add_bytes_to_bits::<u64>(100, 10) == 180);
+ }
+
+ // A simple failure case - adding 1 to the max value
+ #[test]
+ #[should_fail]
+ fn test_add_bytes_to_bits_overflow() {
+ add_bytes_to_bits::<u64>(Bounded::max_value(), 1);
+ }
+
+ // A normal addition - no overflow occurs (fast path)
+ #[test]
+ fn test_add_bytes_to_bits_tuple_ok() {
+ assert!(add_bytes_to_bits_tuple::<u64>((5, 100), 10) == (5, 180));
+ }
+
+ // The low order value overflows into the high order value
+ #[test]
+ fn test_add_bytes_to_bits_tuple_ok2() {
+ assert!(add_bytes_to_bits_tuple::<u64>((5, Bounded::max_value()), 1) == (6, 7));
+ }
+
+ // The value to add is too large to be converted into bits without overflowing its type
+ #[test]
+ fn test_add_bytes_to_bits_tuple_ok3() {
+ assert!(add_bytes_to_bits_tuple::<u64>((5, 0), 0x4000000000000001) == (7, 8));
+ }
+
+ // A simple failure case - adding 1 to the max value
+ #[test]
+ #[should_fail]
+ fn test_add_bytes_to_bits_tuple_overflow() {
+ add_bytes_to_bits_tuple::<u64>((Bounded::max_value(), Bounded::max_value()), 1);
+ }
+
+ // The value to add is too large to convert to bytes without overflowing its type, but the high
+ // order value from this conversion overflows when added to the existing high order value
+ #[test]
+ #[should_fail]
+ fn test_add_bytes_to_bits_tuple_overflow2() {
+ add_bytes_to_bits_tuple::<u64>((Bounded::max_value::<u64>() - 1, 0), 0x8000000000000000);
+ }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::uint;
use std::vec;
fn output_bits(&self) -> uint;
/**
- * Convenience functon that feeds a string into a digest
+ * Convenience function that feeds a string into a digest.
*
* # Arguments
*
- * * in The string to feed into the digest
+ * * `input` The string to feed into the digest
*/
fn input_str(&mut self, input: &str) {
self.input(input.as_bytes());
}
/**
- * Convenience functon that retrieves the result of a digest as a
+ * Convenience function that retrieves the result of a digest as a
* ~str in hexadecimal format.
*/
fn result_str(&mut self) -> ~str {
fn to_hex(rr: &[u8]) -> ~str {
let mut s = ~"";
for b in rr.iter() {
- let hex = uint::to_str_radix(*b as uint, 16u);
+ let hex = (*b as uint).to_str_radix(16u);
if hex.len() == 1 {
s.push_char('0');
}
--- /dev/null
+// 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.
+
+use std::uint;
+
+use cryptoutil::{write_u32_le, read_u32v_le, FixedBuffer, FixedBuffer64, StandardPadding};
+use digest::Digest;
+
+
+// A structure that represents that state of a digest computation for the MD5 digest function
+struct Md5State {
+ s0: u32,
+ s1: u32,
+ s2: u32,
+ s3: u32
+}
+
+impl Md5State {
+ fn new() -> Md5State {
+ return Md5State {
+ s0: 0x67452301,
+ s1: 0xefcdab89,
+ s2: 0x98badcfe,
+ s3: 0x10325476
+ };
+ }
+
+ fn reset(&mut self) {
+ self.s0 = 0x67452301;
+ self.s1 = 0xefcdab89;
+ self.s2 = 0x98badcfe;
+ self.s3 = 0x10325476;
+ }
+
+ fn process_block(&mut self, input: &[u8]) {
+ fn f(u: u32, v: u32, w: u32) -> u32 {
+ return (u & v) | (!u & w);
+ }
+
+ fn g(u: u32, v: u32, w: u32) -> u32 {
+ return (u & w) | (v & !w);
+ }
+
+ fn h(u: u32, v: u32, w: u32) -> u32 {
+ return u ^ v ^ w;
+ }
+
+ fn i(u: u32, v: u32, w: u32) -> u32 {
+ return v ^ (u | !w);
+ }
+
+ fn rotate_left(x: u32, n: u32) -> u32 {
+ return (x << n) | (x >> (32 - n));
+ }
+
+ fn op_f(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+ return rotate_left(w + f(x, y, z) + m, s) + x;
+ }
+
+ fn op_g(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+ return rotate_left(w + g(x, y, z) + m, s) + x;
+ }
+
+ fn op_h(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+ return rotate_left(w + h(x, y, z) + m, s) + x;
+ }
+
+ fn op_i(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
+ return rotate_left(w + i(x, y, z) + m, s) + x;
+ }
+
+ let mut a = self.s0;
+ let mut b = self.s1;
+ let mut c = self.s2;
+ let mut d = self.s3;
+
+ let mut data = [0u32, ..16];
+
+ read_u32v_le(data, input);
+
+ // round 1
+ do uint::range_step(0, 16, 4) |i| {
+ a = op_f(a, b, c, d, data[i] + C1[i], 7);
+ d = op_f(d, a, b, c, data[i + 1] + C1[i + 1], 12);
+ c = op_f(c, d, a, b, data[i + 2] + C1[i + 2], 17);
+ b = op_f(b, c, d, a, data[i + 3] + C1[i + 3], 22);
+ true
+ };
+
+ // round 2
+ let mut t = 1;
+ do uint::range_step(0, 16, 4) |i| {
+ a = op_g(a, b, c, d, data[t & 0x0f] + C2[i], 5);
+ d = op_g(d, a, b, c, data[(t + 5) & 0x0f] + C2[i + 1], 9);
+ c = op_g(c, d, a, b, data[(t + 10) & 0x0f] + C2[i + 2], 14);
+ b = op_g(b, c, d, a, data[(t + 15) & 0x0f] + C2[i + 3], 20);
+ t += 20;
+ true
+ };
+
+ // round 3
+ t = 5;
+ do uint::range_step(0, 16, 4) |i| {
+ a = op_h(a, b, c, d, data[t & 0x0f] + C3[i], 4);
+ d = op_h(d, a, b, c, data[(t + 3) & 0x0f] + C3[i + 1], 11);
+ c = op_h(c, d, a, b, data[(t + 6) & 0x0f] + C3[i + 2], 16);
+ b = op_h(b, c, d, a, data[(t + 9) & 0x0f] + C3[i + 3], 23);
+ t += 12;
+ true
+ };
+
+ // round 4
+ t = 0;
+ do uint::range_step(0, 16, 4) |i| {
+ a = op_i(a, b, c, d, data[t & 0x0f] + C4[i], 6);
+ d = op_i(d, a, b, c, data[(t + 7) & 0x0f] + C4[i + 1], 10);
+ c = op_i(c, d, a, b, data[(t + 14) & 0x0f] + C4[i + 2], 15);
+ b = op_i(b, c, d, a, data[(t + 21) & 0x0f] + C4[i + 3], 21);
+ t += 28;
+ true
+ };
+
+ self.s0 += a;
+ self.s1 += b;
+ self.s2 += c;
+ self.s3 += d;
+ }
+}
+
+// Round 1 constants
+static C1: [u32, ..16] = [
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821
+];
+
+// Round 2 constants
+static C2: [u32, ..16] = [
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a
+];
+
+// Round 3 constants
+static C3: [u32, ..16] = [
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665
+];
+
+// Round 4 constants
+static C4: [u32, ..16] = [
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+];
+
+
+/// The MD5 Digest algorithm
+struct Md5 {
+ priv length_bytes: u64,
+ priv buffer: FixedBuffer64,
+ priv state: Md5State,
+ priv finished: bool,
+}
+
+impl Md5 {
+ /// Construct a new instance of the MD5 Digest.
+ pub fn new() -> Md5 {
+ return Md5 {
+ length_bytes: 0,
+ buffer: FixedBuffer64::new(),
+ state: Md5State::new(),
+ finished: false
+ }
+ }
+}
+
+impl Digest for Md5 {
+ fn input(&mut self, input: &[u8]) {
+ assert!(!self.finished);
+ // Unlike Sha1 and Sha2, the length value in MD5 is defined as the length of the message mod
+ // 2^64 - ie: integer overflow is OK.
+ self.length_bytes += input.len() as u64;
+ self.buffer.input(input, |d: &[u8]| { self.state.process_block(d); });
+ }
+
+ fn reset(&mut self) {
+ self.length_bytes = 0;
+ self.buffer.reset();
+ self.state.reset();
+ self.finished = false;
+ }
+
+ fn result(&mut self, out: &mut [u8]) {
+ if !self.finished {
+ self.buffer.standard_padding(8, |d: &[u8]| { self.state.process_block(d); });
+ write_u32_le(self.buffer.next(4), (self.length_bytes << 3) as u32);
+ write_u32_le(self.buffer.next(4), (self.length_bytes >> 29) as u32);
+ self.state.process_block(self.buffer.full_buffer());
+ self.finished = true;
+ }
+
+ write_u32_le(out.mut_slice(0, 4), self.state.s0);
+ write_u32_le(out.mut_slice(4, 8), self.state.s1);
+ write_u32_le(out.mut_slice(8, 12), self.state.s2);
+ write_u32_le(out.mut_slice(12, 16), self.state.s3);
+ }
+
+ fn output_bits(&self) -> uint { 128 }
+}
+
+
+#[cfg(test)]
+mod tests {
+ use cryptoutil::test::test_digest_1million_random;
+ use digest::Digest;
+ use md5::Md5;
+
+
+ struct Test {
+ input: ~str,
+ output_str: ~str,
+ }
+
+ fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) {
+ // Test that it works when accepting the message all at once
+ for t in tests.iter() {
+ sh.input_str(t.input);
+
+ let out_str = sh.result_str();
+ assert!(out_str == t.output_str);
+
+ sh.reset();
+ }
+
+ // Test that it works when accepting the message in pieces
+ for t in tests.iter() {
+ let len = t.input.len();
+ let mut left = len;
+ while left > 0u {
+ let take = (left + 1u) / 2u;
+ sh.input_str(t.input.slice(len - left, take + len - left));
+ left = left - take;
+ }
+
+ let out_str = sh.result_str();
+ assert!(out_str == t.output_str);
+
+ sh.reset();
+ }
+ }
+
+ #[test]
+ fn test_md5() {
+ // Examples from wikipedia
+ let wikipedia_tests = ~[
+ Test {
+ input: ~"",
+ output_str: ~"d41d8cd98f00b204e9800998ecf8427e"
+ },
+ Test {
+ input: ~"The quick brown fox jumps over the lazy dog",
+ output_str: ~"9e107d9d372bb6826bd81d3542a419d6"
+ },
+ Test {
+ input: ~"The quick brown fox jumps over the lazy dog.",
+ output_str: ~"e4d909c290d0fb1ca068ffaddf22cbd0"
+ },
+ ];
+
+ let tests = wikipedia_tests;
+
+ let mut sh = Md5::new();
+
+ test_hash(&mut sh, tests);
+ }
+
+ #[test]
+ fn test_1million_random_md5() {
+ let mut sh = Md5::new();
+ test_digest_1million_random(
+ &mut sh,
+ 64,
+ "7707d6ae4e027c70eea2a935c2296f21");
+ }
+}
+
+
+#[cfg(test)]
+mod bench {
+ use extra::test::BenchHarness;
+
+ use md5::Md5;
+
+
+ #[bench]
+ pub fn md5_10(bh: & mut BenchHarness) {
+ let mut sh = Md5::new();
+ let bytes = [1u8, ..10];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn md5_1k(bh: & mut BenchHarness) {
+ let mut sh = Md5::new();
+ let bytes = [1u8, ..1024];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn md5_64k(bh: & mut BenchHarness) {
+ let mut sh = Md5::new();
+ let bytes = [1u8, ..65536];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+}
*/
-use cryptoutil::{write_u32_be, read_u32v_be, shift_add_check_overflow, FixedBuffer, FixedBuffer64,
+use cryptoutil::{write_u32_be, read_u32v_be, add_bytes_to_bits, FixedBuffer, FixedBuffer64,
StandardPadding};
use digest::Digest;
fn add_input(st: &mut Sha1, msg: &[u8]) {
assert!((!st.computed));
// Assumes that msg.len() can be converted to u64 without overflow
- st.length_bits = shift_add_check_overflow(st.length_bits, msg.len() as u64, 3);
+ st.length_bits = add_bytes_to_bits(st.length_bits, msg.len() as u64);
st.buffer.input(msg, |d: &[u8]| { process_msg_block(d, &mut st.h); });
}
use std::uint;
-use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, shift_add_check_overflow,
- shift_add_check_overflow_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
+use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, add_bytes_to_bits,
+ add_bytes_to_bits_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
use digest::Digest;
fn input(&mut self, input: &[u8]) {
assert!(!self.finished)
// Assumes that input.len() can be converted to u64 without overflow
- self.length_bits = shift_add_check_overflow_tuple(self.length_bits, input.len() as u64, 3);
+ self.length_bits = add_bytes_to_bits_tuple(self.length_bits, input.len() as u64);
self.buffer.input(input, |input: &[u8]| { self.state.process_block(input) });
}
fn input(&mut self, input: &[u8]) {
assert!(!self.finished)
// Assumes that input.len() can be converted to u64 without overflow
- self.length_bits = shift_add_check_overflow(self.length_bits, input.len() as u64, 3);
+ self.length_bits = add_bytes_to_bits(self.length_bits, input.len() as u64);
self.buffer.input(input, |input: &[u8]| { self.state.process_block(input) });
}
fn next_back(&mut self) -> Option<A> { self.list.pop_back() }
}
-impl<A, T: Iterator<A>> FromIterator<A, T> for DList<A> {
- fn from_iterator(iterator: &mut T) -> DList<A> {
+impl<A> FromIterator<A> for DList<A> {
+ fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> DList<A> {
let mut ret = DList::new();
ret.extend(iterator);
ret
}
}
-impl<A, T: Iterator<A>> Extendable<A, T> for DList<A> {
- fn extend(&mut self, iterator: &mut T) {
+impl<A> Extendable<A> for DList<A> {
+ fn extend<T: Iterator<A>>(&mut self, iterator: &mut T) {
for elt in *iterator { self.push_back(elt); }
}
}
}
}
}
-
priv bits: uint
}
-/// An iterface for casting C-like enum to uint and back.
+/// An interface for casting C-like enum to uint and back.
pub trait CLike {
/// Converts C-like enum to uint.
fn to_uint(&self) -> uint;
pub mod container;
pub mod bitv;
-pub mod fun_treemap;
pub mod list;
pub mod ringbuf;
pub mod priority_queue;
mod cryptoutil;
#[path="crypto/digest.rs"]
pub mod digest;
+#[path="crypto/md5.rs"]
+pub mod md5;
#[path="crypto/sha1.rs"]
pub mod sha1;
#[path="crypto/sha2.rs"]
pub mod fileinput;
pub mod flate;
pub mod hex;
+pub mod uuid;
+
#[cfg(unicode)]
mod unicode;
/**
Create a `FileInput` object from a vec of files. An empty
vec means lines are read from `stdin` (use `from_vec_raw` to stop
- this behaviour). Any occurence of `None` represents `stdin`.
+ this behaviour). Any occurrence of `None` represents `stdin`.
*/
pub fn from_vec(files: ~[Option<Path>]) -> FileInput {
FileInput::from_vec_raw(
static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;
}
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;
This module is currently unsafe because it uses `Clone + Send` as a type
parameter bounds meaning POD (plain old data), but `Clone + Send` and
-POD are not equivelant.
+POD are not equivalent.
*/
pub mod pod {
+++ /dev/null
-// 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 functional key,value store that works on anything.
- *
- * This works using a binary search tree. In the first version, it's a
- * very naive algorithm, but it will probably be updated to be a
- * red-black tree or something else.
- *
- * This is copied and modified from treemap right now. It's missing a lot
- * of features.
- */
-
-
-use std::cmp::{Eq, Ord};
-use std::option::{Some, None};
-
-pub type Treemap<K, V> = @TreeNode<K, V>;
-
-enum TreeNode<K, V> {
- Empty,
- Node(@K, @V, @TreeNode<K, V>, @TreeNode<K, V>)
-}
-
-/// Create a treemap
-pub fn init<K: 'static, V: 'static>() -> Treemap<K, V> {
- @Empty
-}
-
-/// Insert a value into the map
-pub fn insert<K:Eq + Ord + 'static,
- V:'static>(
- m: Treemap<K, V>,
- k: K,
- v: V)
- -> Treemap<K, V> {
- @match m {
- @Empty => Node(@k, @v, @Empty, @Empty),
- @Node(kk, vv, left, right) => cond!(
- (k < *kk) { Node(kk, vv, insert(left, k, v), right) }
- (k == *kk) { Node(kk, @v, left, right) }
- _ { Node(kk, vv, left, insert(right, k, v)) }
- )
- }
-}
-
-/// Find a value based on the key
-pub fn find<K:Eq + Ord + 'static,
- V:Clone + 'static>(
- m: Treemap<K, V>,
- k: K)
- -> Option<V> {
- match *m {
- Empty => None,
- Node(kk, v, left, right) => cond!(
- (k == *kk) { Some((*v).clone()) }
- (k < *kk) { find(left, k) }
- _ { find(right, k) }
- )
- }
-}
-
-/// Visit all pairs in the map in order.
-pub fn traverse<K, V>(m: Treemap<K, V>, f: &fn(&K, &V)) {
- match *m {
- Empty => (),
- // Previously, this had what looked like redundant
- // matches to me, so I changed it. but that may be a
- // de-optimization -- tjc
- Node(@ref k, @ref v, left, right) => {
- traverse(left, |k,v| f(k,v));
- f(k, v);
- traverse(right, |k,v| f(k,v));
- }
- }
-}
// except according to those terms.
-use std::uint;
use std::vec;
struct Quad {
if byte <= 16u8 {
result.push_char('0')
}
- result.push_str(uint::to_str_radix(byte as uint, 16u));
+ result.push_str((byte as uint).to_str_radix(16u));
i += 1u32;
}
}
if v.is_empty() { return ~"0" }
let mut s = str::with_capacity(v.len() * l);
for n in v.rev_iter() {
- let ss = uint::to_str_radix(*n as uint, radix);
+ let ss = (*n as uint).to_str_radix(radix);
s.push_str("0".repeat(l - ss.len()));
s.push_str(ss);
}
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
}
-impl<T: Ord, Iter: Iterator<T>> FromIterator<T, Iter> for PriorityQueue<T> {
- fn from_iterator(iter: &mut Iter) -> PriorityQueue<T> {
+impl<T: Ord> FromIterator<T> for PriorityQueue<T> {
+ fn from_iterator<Iter: Iterator<T>>(iter: &mut Iter) -> PriorityQueue<T> {
let mut q = PriorityQueue::new();
q.extend(iter);
}
}
-impl<T: Ord, Iter: Iterator<T>> Extendable<T, Iter> for PriorityQueue<T> {
- fn extend(&mut self, iter: &mut Iter) {
+impl<T: Ord> Extendable<T> for PriorityQueue<T> {
+ fn extend<Iter: Iterator<T>>(&mut self, iter: &mut Iter) {
let (lower, _) = iter.size_hint();
let len = self.capacity();
}
}
-impl<A, T: Iterator<A>> FromIterator<A, T> for RingBuf<A> {
- fn from_iterator(iterator: &mut T) -> RingBuf<A> {
+impl<A> FromIterator<A> for RingBuf<A> {
+ fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> RingBuf<A> {
let (lower, _) = iterator.size_hint();
let mut deq = RingBuf::with_capacity(lower);
deq.extend(iterator);
}
}
-impl<A, T: Iterator<A>> Extendable<A, T> for RingBuf<A> {
- fn extend(&mut self, iterator: &mut T) {
+impl<A> Extendable<A> for RingBuf<A> {
+ fn extend<T: Iterator<A>>(&mut self, iterator: &mut T) {
for elt in *iterator {
self.push_back(elt);
}
pub mod rustrt {
use std::libc::{c_char, c_int};
- extern {
- pub fn linenoise(prompt: *c_char) -> *c_char;
- pub fn linenoiseHistoryAdd(line: *c_char) -> c_int;
- pub fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
- pub fn linenoiseHistorySave(file: *c_char) -> c_int;
- pub fn linenoiseHistoryLoad(file: *c_char) -> c_int;
- pub fn linenoiseSetCompletionCallback(callback: *u8);
- pub fn linenoiseAddCompletion(completions: *(), line: *c_char);
+ #[cfg(stage0)]
+ mod macro_hack {
+ #[macro_escape];
+ macro_rules! externfn(
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ )
+ )
}
+
+ externfn!(fn linenoise(prompt: *c_char) -> *c_char)
+ externfn!(fn linenoiseHistoryAdd(line: *c_char) -> c_int)
+ externfn!(fn linenoiseHistorySetMaxLen(len: c_int) -> c_int)
+ externfn!(fn linenoiseHistorySave(file: *c_char) -> c_int)
+ externfn!(fn linenoiseHistoryLoad(file: *c_char) -> c_int)
+ externfn!(fn linenoiseSetCompletionCallback(callback: *u8))
+ externfn!(fn linenoiseAddCompletion(completions: *(), line: *c_char))
}
/// Add a line to history
pub unsafe fn add_history(line: &str) -> bool {
- do line.to_c_str().with_ref |buf| {
+ do line.with_c_str |buf| {
rustrt::linenoiseHistoryAdd(buf) == 1 as c_int
}
}
/// Save line history to a file
pub unsafe fn save_history(file: &str) -> bool {
- do file.to_c_str().with_ref |buf| {
+ do file.with_c_str |buf| {
rustrt::linenoiseHistorySave(buf) == 1 as c_int
}
}
/// Load line history from a file
pub unsafe fn load_history(file: &str) -> bool {
- do file.to_c_str().with_ref |buf| {
+ do file.with_c_str |buf| {
rustrt::linenoiseHistoryLoad(buf) == 1 as c_int
}
}
/// Print out a prompt and then wait for input and return it
pub unsafe fn read(prompt: &str) -> Option<~str> {
- do prompt.to_c_str().with_ref |buf| {
+ do prompt.with_c_str |buf| {
let line = rustrt::linenoise(buf);
if line.is_null() { None }
unsafe {
do cb(str::raw::from_c_str(line)) |suggestion| {
- do suggestion.to_c_str().with_ref |buf| {
+ do suggestion.with_c_str |buf| {
rustrt::linenoiseAddCompletion(completions, buf);
}
}
-}
+ }
}
}
#[cfg(test)]
mod test_qsort {
-
use sort::*;
- use std::vec;
-
fn check_sort(v1: &mut [int], v2: &mut [int]) {
let len = v1.len();
fn leual(a: &int, b: &int) -> bool { *a <= *b }
let immut_names = names;
- let pairs = vec::zip_slice(expected, immut_names);
- for p in pairs.iter() {
- let (a, b) = *p;
+ for (&a, &b) in expected.iter().zip(immut_names.iter()) {
debug!("%d %d", a, b);
assert_eq!(a, b);
}
let (q1,q2,q3) = s.quartiles;
- let lomag = (10.0_f64).pow(&s.min.log10().floor());
- let himag = (10.0_f64).pow(&(s.max.log10().floor()));
- let lo = (s.min / lomag).floor() * lomag;
- let hi = (s.max / himag).ceil() * himag;
+ // the .abs() handles the case where numbers are negative
+ let lomag = (10.0_f64).pow(&(s.min.abs().log10().floor()));
+ let himag = (10.0_f64).pow(&(s.max.abs().log10().floor()));
+
+ // need to consider when the limit is zero
+ let lo = if lomag == 0.0 {
+ 0.0
+ } else {
+ (s.min / lomag).floor() * lomag
+ };
+
+ let hi = if himag == 0.0 {
+ 0.0
+ } else {
+ (s.max / himag).ceil() * himag
+ };
let range = hi - lo;
w.write_str(histr);
}
-/// Returns a HashMap with the number of occurences of every element in the
+/// Returns a HashMap with the number of occurrences of every element in the
/// sequence that the iterator exposes.
pub fn freq_count<T: Iterator<U>, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap<U, uint> {
let mut map = hashmap::HashMap::new::<U, uint>();
};
check(val, summ);
}
+
+ #[test]
+ fn test_boxplot_nonpositive() {
+ fn t(s: &Summary, expected: ~str) {
+ let out = do io::with_str_writer |w| {
+ write_boxplot(w, s, 30)
+ };
+
+ assert_eq!(out, expected);
+ }
+
+ t(&Summary::new([-2.0, -1.0]), ~"-2 |[------******#*****---]| -1");
+ t(&Summary::new([0.0, 2.0]), ~"0 |[-------*****#*******---]| 2");
+ t(&Summary::new([-2.0, 0.0]), ~"-2 |[------******#******---]| 0");
+
+ }
+
}
}
}
// Uncomment if you wish to test for sem races. Not valgrind-friendly.
- /* do 1000.times { task::yield(); } */
+ /* do 1000.times { task::deschedule(); } */
// Need to wait outside the exclusive.
if waiter_nobe.is_some() {
let _ = waiter_nobe.unwrap().recv();
}
}
- // If yield checks start getting inserted anywhere, we can be
+ // If deschedule checks start getting inserted anywhere, we can be
// killed before or after enqueueing. Deciding whether to
// unkillably reacquire the lock needs to happen atomically
// wrt enqueuing.
let s2 = ~s.clone();
do task::spawn || {
do s2.access {
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
}
}
do s.access {
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
}
}
#[test]
s2.acquire();
c.send(());
}
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
s.release();
let _ = p.recv();
let s = ~Semaphore::new(0);
let s2 = ~s.clone();
do task::spawn || {
- do 5.times { task::yield(); }
+ do 5.times { task::deschedule(); }
s2.release();
let _ = p.recv();
}
c.send(());
}
let _ = p.recv(); // wait for child to come alive
- do 5.times { task::yield(); } // let the child contend
+ do 5.times { task::deschedule(); } // let the child contend
}
let _ = p.recv(); // wait for child to be done
}
do n.times {
do m.lock {
let oldval = *sharedstate;
- task::yield();
+ task::deschedule();
*sharedstate = oldval + 1;
}
}
let (p,c) = comm::stream();
do task::spawn || { // linked
let _ = p.recv(); // wait for sibling to get in the mutex
- task::yield();
+ task::deschedule();
fail!();
}
do m2.lock_cond |cond| {
do n.times {
do lock_rwlock_in_mode(x, mode) {
let oldval = *sharedstate;
- task::yield();
+ task::deschedule();
*sharedstate = oldval + 1;
}
}
/// If the color is a bright color, but the terminal only supports 8 colors,
/// the corresponding normal color will be used instead.
///
- /// Rturns true if the color was set, false otherwise.
+ /// Returns true if the color was set, false otherwise.
pub fn bg(&self, color: color::Color) -> bool {
let color = self.dim_if_necessary(color);
if self.num_colors > color {
}
fn usage(binary: &str, helpstr: &str) -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+
let message = fmt!("Usage: %s [OPTIONS] [FILTER]", binary);
println(groups::usage(message, optgroups()));
println("");
use std::either;
use std::comm::{stream, SharedChan};
- use std::vec;
use tempfile;
use std::os;
~"test::parse_ignored_flag",
~"test::sort_tests"];
- let pairs = vec::zip(expected, filtered);
-
- for p in pairs.iter() {
- match *p {
- (ref a, ref b) => {
- assert!(*a == b.desc.name.to_str());
- }
- }
+ for (a, b) in expected.iter().zip(filtered.iter()) {
+ assert!(*a == b.desc.name.to_str());
}
}
#[allow(missing_doc)];
-
-use std::int;
use std::io;
use std::num;
use std::str;
}
/// A record specifying a time value in seconds and nanoseconds.
-#[deriving(Eq, Encodable, Decodable)]
+#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
pub struct Timespec { sec: i64, nsec: i32 }
/*
* nanoseconds since 1970-01-01T00:00:00Z.
*/
pub fn get_time() -> Timespec {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut sec = 0i64;
let mut nsec = 0i32;
* in nanoseconds since an unspecified epoch.
*/
pub fn precise_time_ns() -> u64 {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut ns = 0u64;
rustrt::precise_time_ns(&mut ns);
}
pub fn tzset() {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
rustrt::rust_tzset();
}
}
-#[deriving(Eq, Encodable, Decodable)]
+#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
pub struct Tm {
tm_sec: i32, // seconds after the minute ~[0-60]
tm_min: i32, // minutes after the hour ~[0-59]
/// Returns the specified time in UTC
pub fn at_utc(clock: Timespec) -> Tm {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
/// Returns the specified time in the local timezone
pub fn at(clock: Timespec) -> Tm {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
impl Tm {
/// Convert time to the seconds from January 1, 1970
pub fn to_timespec(&self) -> Timespec {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let sec = match self.tm_gmtoff {
0_i32 => rustrt::rust_timegm(self),
//'U' {}
'u' => {
let i = tm.tm_wday as int;
- int::to_str(if i == 0 { 7 } else { i })
+ (if i == 0 { 7 } else { i }).to_str()
}
//'V' {}
'v' => {
parse_type('Y', tm))
}
//'W' {}
- 'w' => int::to_str(tm.tm_wday as int),
+ 'w' => (tm.tm_wday as int).to_str(),
//'X' {}
//'x' {}
- 'Y' => int::to_str(tm.tm_year as int + 1900),
+ 'Y' => (tm.tm_year as int + 1900).to_str(),
'y' => fmt!("%02d", (tm.tm_year as int + 1900) % 100),
'Z' => tm.tm_zone.clone(),
'z' => {
};
}
-impl<K: TotalOrd, V, T: Iterator<(K, V)>> FromIterator<(K, V), T> for TreeMap<K, V> {
- fn from_iterator(iter: &mut T) -> TreeMap<K, V> {
+impl<K: TotalOrd, V> FromIterator<(K, V)> for TreeMap<K, V> {
+ fn from_iterator<T: Iterator<(K, V)>>(iter: &mut T) -> TreeMap<K, V> {
let mut map = TreeMap::new();
map.extend(iter);
map
}
}
-impl<K: TotalOrd, V, T: Iterator<(K, V)>> Extendable<(K, V), T> for TreeMap<K, V> {
+impl<K: TotalOrd, V> Extendable<(K, V)> for TreeMap<K, V> {
#[inline]
- fn extend(&mut self, iter: &mut T) {
+ fn extend<T: Iterator<(K, V)>>(&mut self, iter: &mut T) {
for (k, v) in *iter {
self.insert(k, v);
}
}
}
-impl<T: TotalOrd, Iter: Iterator<T>> FromIterator<T, Iter> for TreeSet<T> {
- fn from_iterator(iter: &mut Iter) -> TreeSet<T> {
+impl<T: TotalOrd> FromIterator<T> for TreeSet<T> {
+ fn from_iterator<Iter: Iterator<T>>(iter: &mut Iter) -> TreeSet<T> {
let mut set = TreeSet::new();
set.extend(iter);
set
}
}
-impl<T: TotalOrd, Iter: Iterator<T>> Extendable<T, Iter> for TreeSet<T> {
+impl<T: TotalOrd> Extendable<T> for TreeSet<T> {
#[inline]
- fn extend(&mut self, iter: &mut Iter) {
+ fn extend<Iter: Iterator<T>>(&mut self, iter: &mut Iter) {
for elem in *iter {
self.insert(elem);
}
--- /dev/null
+// 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.
+
+/*!
+Generate and parse UUIDs
+
+Provides support for Universally Unique Identifiers (UUIDs). A UUID is a
+unique 128-bit number, stored as 16 octets. UUIDs are used to assign unique
+identifiers to entities without requiring a central allocating authority.
+
+They are particularly useful in distributed systems, though can be used in
+disparate areas, such as databases and network protocols. Typically a UUID is
+displayed in a readable string form as a sequence of hexadecimals digits,
+separated into groups by hyphens.
+
+The uniqueness property is not strictly guaranteed, however for all practical
+purposes, it can be assumed that an unintentional collision would be extremely
+unlikely.
+
+# Examples
+
+To create a new random (V4) UUID and print it out in hexadecimal form:
+
+~~~ {.rust}
+extern mod extra;
+use extra::uuid::Uuid;
+
+fn main() {
+ let uuid1 = Uuid::new_v4();
+ println(uuid1.to_str());
+}
+~~~
+
+# Strings
+
+Examples of string representations:
+
+* simple: `936DA01F9ABD4d9d80C702AF85C822A8`
+* hyphenated: `550e8400-e29b-41d4-a716-446655440000`
+* urn: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4`
+
+# References
+
+* [Wikipedia: Universally Unique Identifier](
+ http://en.wikipedia.org/wiki/Universally_unique_identifier)
+* [RFC4122: A Universally Unique IDentifier (UUID) URN Namespace](
+ http://tools.ietf.org/html/rfc4122)
+
+*/
+
+use std::str;
+use std::vec;
+use std::num::{FromStrRadix, Zero};
+use std::char::Char;
+use std::container::Container;
+use std::to_str::ToStr;
+use std::rand;
+use std::rand::RngUtil;
+use std::cmp::Eq;
+use std::cast::{transmute,transmute_copy};
+
+/// A 128-bit (16 byte) buffer containing the ID
+pub type UuidBytes = [u8, ..16];
+
+/// The version of the UUID, denoting the generating algorithm
+#[deriving(Eq)]
+pub enum UuidVersion {
+ /// Version 1: MAC address
+ Version1Mac = 1,
+ /// Version 2: DCE Security
+ Version2Dce = 2,
+ /// Version 3: MD5 hash
+ Version3Md5 = 3,
+ /// Version 4: Random
+ Version4Random = 4,
+ /// Version 5: SHA-1 hash
+ Version5Sha1 = 5,
+}
+
+/// The reserved variants of UUIDs
+#[deriving(Eq)]
+pub enum UuidVariant {
+ /// Reserved by the NCS for backward compatability
+ VariantNCS,
+ /// As described in the RFC4122 Specification (default)
+ VariantRFC4122,
+ /// Resreved by Microsoft for backward compatability
+ VariantMicrosoft,
+ /// Reserved for future expansion
+ VariantFuture,
+}
+
+/// A Universally Unique Identifier (UUID)
+pub struct Uuid {
+ /// The 128-bit number stored in 16 bytes
+ bytes: UuidBytes
+}
+
+/// A UUID stored as fields (identical to UUID, used only for conversions)
+struct UuidFields {
+ /// First field, 32-bit word
+ data1: u32,
+ /// Second field, 16-bit short
+ data2: u16,
+ /// Third field, 16-bit short
+ data3: u16,
+ /// Fourth field, 8 bytes
+ data4: [u8, ..8]
+}
+
+/// Error details for string parsing failures
+pub enum ParseError {
+ ErrorInvalidLength(uint),
+ ErrorInvalidCharacter(char, uint),
+ ErrorInvalidGroups(uint),
+ ErrorInvalidGroupLength(uint, uint, uint),
+}
+
+/// Converts a ParseError to a string
+impl ToStr for ParseError {
+ #[inline]
+ fn to_str(&self) -> ~str {
+ match *self {
+ ErrorInvalidLength(found) =>
+ fmt!("Invalid length; expecting 32, 36 or 45 chars, found %u",
+ found),
+ ErrorInvalidCharacter(found, pos) =>
+ fmt!("Invalid character; found `%c` (0x%02x) at offset %u",
+ found, found as uint, pos),
+ ErrorInvalidGroups(found) =>
+ fmt!("Malformed; wrong number of groups: expected 1 or 5, found %u",
+ found),
+ ErrorInvalidGroupLength(group, found, expecting) =>
+ fmt!("Malformed; length of group %u was %u, expecting %u",
+ group, found, expecting),
+ }
+ }
+}
+
+// Length of each hyphenated group in hex digits
+static UuidGroupLens: [uint, ..5] = [8u, 4u, 4u, 4u, 12u];
+
+/// UUID support
+impl Uuid {
+
+ /// Returns a nil or empty UUID (containing all zeroes)
+ pub fn new_nil() -> Uuid {
+ let uuid = Uuid{ bytes: [0, .. 16] };
+ uuid
+ }
+
+ /// Create a new UUID of the specified version
+ pub fn new(v: UuidVersion) -> Option<Uuid> {
+ match v {
+ Version4Random => Some(Uuid::new_v4()),
+ _ => None
+ }
+ }
+
+ /// Creates a new random UUID
+ ///
+ /// Uses the `rand` module's default RNG task as the source
+ /// of random numbers. Use the rand::Rand trait to supply
+ /// a custom generator if required.
+ pub fn new_v4() -> Uuid {
+ let ub = rand::task_rng().gen_bytes(16);
+ let mut uuid = Uuid{ bytes: [0, .. 16] };
+ vec::bytes::copy_memory(uuid.bytes, ub, 16);
+ uuid.set_variant(VariantRFC4122);
+ uuid.set_version(Version4Random);
+ uuid
+ }
+
+ /// Creates a UUID using the supplied field values
+ ///
+ /// # Arguments
+ /// * `d1` A 32-bit word
+ /// * `d2` A 16-bit word
+ /// * `d3` A 16-bit word
+ /// * `d4` Array of 8 octets
+ pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8]) -> Uuid {
+ use std::unstable::intrinsics::{to_be16, to_be32};
+
+ // First construct a temporary field-based struct
+ let mut fields = UuidFields {
+ data1: 0,
+ data2: 0,
+ data3: 0,
+ data4: [0, ..8]
+ };
+
+ fields.data1 = to_be32(d1 as i32) as u32;
+ fields.data2 = to_be16(d2 as i16) as u16;
+ fields.data3 = to_be16(d3 as i16) as u16;
+ vec::bytes::copy_memory(fields.data4, d4, 8);
+
+ unsafe {
+ transmute(fields)
+ }
+ }
+
+ /// Creates a UUID using the supplied bytes
+ ///
+ /// # Arguments
+ /// * `b` An array or slice of 16 bytes
+ pub fn from_bytes(b: &[u8]) -> Option<Uuid> {
+ if b.len() != 16 {
+ return None
+ }
+
+ let mut uuid = Uuid{ bytes: [0, .. 16] };
+ unsafe {
+ vec::raw::copy_memory(uuid.bytes, b, 16);
+ }
+ Some(uuid)
+ }
+
+ /// Specifies the variant of the UUID structure
+ fn set_variant(&mut self, v: UuidVariant) {
+ // Octet 8 contains the variant in the most significant 3 bits
+ match v {
+ VariantNCS => // b0xx...
+ self.bytes[8] = self.bytes[8] & 0x7f,
+ VariantRFC4122 => // b10x...
+ self.bytes[8] = (self.bytes[8] & 0x3f) | 0x80,
+ VariantMicrosoft => // b110...
+ self.bytes[8] = (self.bytes[8] & 0x1f) | 0xc0,
+ VariantFuture => // b111...
+ self.bytes[8] = (self.bytes[8] & 0x1f) | 0xe0,
+ }
+ }
+
+ /// Returns the variant of the UUID structure
+ ///
+ /// This determines the interpretation of the structure of the UUID.
+ /// Currently only the RFC4122 variant is generated by this module.
+ ///
+ /// * [Variant Reference](http://tools.ietf.org/html/rfc4122#section-4.1.1)
+ pub fn get_variant(&self) -> Option<UuidVariant> {
+ if self.bytes[8] & 0x80 == 0x00 {
+ Some(VariantNCS)
+ } else if self.bytes[8] & 0xc0 == 0x80 {
+ Some(VariantRFC4122)
+ } else if self.bytes[8] & 0xe0 == 0xc0 {
+ Some(VariantMicrosoft)
+ } else if self.bytes[8] & 0xe0 == 0xe0 {
+ Some(VariantFuture)
+ } else {
+ None
+ }
+ }
+
+ /// Specifies the version number of the UUID
+ fn set_version(&mut self, v: UuidVersion) {
+ self.bytes[6] = (self.bytes[6] & 0xF) | ((v as u8) << 4);
+ }
+
+ /// Returns the version number of the UUID
+ ///
+ /// This represents the algorithm used to generate the contents.
+ ///
+ /// Currently only the Random (V4) algorithm is supported by this
+ /// module. There are security and privacy implications for using
+ /// older versions - see [Wikipedia: Universally Unique Identifier](
+ /// http://en.wikipedia.org/wiki/Universally_unique_identifier) for
+ /// details.
+ ///
+ /// * [Version Reference](http://tools.ietf.org/html/rfc4122#section-4.1.3)
+ pub fn get_version_num(&self) -> uint {
+ (self.bytes[6] >> 4) as uint
+ }
+
+ /// Returns the version of the UUID
+ ///
+ /// This represents the algorithm used to generate the contents
+ pub fn get_version(&self) -> Option<UuidVersion> {
+ let v = (self.bytes[6] >> 4);
+ match v {
+ 1 => Some(Version1Mac),
+ 2 => Some(Version2Dce),
+ 3 => Some(Version3Md5),
+ 4 => Some(Version4Random),
+ 5 => Some(Version5Sha1),
+ _ => None
+ }
+ }
+
+ /// Return an array of 16 octets containing the UUID data
+ pub fn to_bytes<'a>(&'a self) -> &'a [u8] {
+ self.bytes.as_slice()
+ }
+
+ /// Returns the UUID as a string of 16 hexadecimal digits
+ ///
+ /// Example: `936DA01F9ABD4d9d80C702AF85C822A8`
+ pub fn to_simple_str(&self) -> ~str {
+ let mut s: ~[u8] = vec::from_elem(32, 0u8);
+ for i in range(0u, 16u) {
+ let digit = fmt!("%02x", self.bytes[i] as uint);
+ s[i*2+0] = digit[0];
+ s[i*2+1] = digit[1];
+ }
+ str::from_bytes(s)
+ }
+
+ /// Returns a string of hexadecimal digits, separated into groups with a hypen
+ ///
+ /// Example: `550e8400-e29b-41d4-a716-446655440000`
+ pub fn to_hyphenated_str(&self) -> ~str {
+ use std::unstable::intrinsics::{to_be16, to_be32};
+ // Convert to field-based struct as it matches groups in output.
+ // Ensure fields are in network byte order, as per RFC.
+ let mut uf: UuidFields;
+ unsafe {
+ uf = transmute_copy(&self.bytes);
+ }
+ uf.data1 = to_be32(uf.data1 as i32) as u32;
+ uf.data2 = to_be16(uf.data2 as i16) as u16;
+ uf.data3 = to_be16(uf.data3 as i16) as u16;
+ let s = fmt!("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ uf.data1 as uint,
+ uf.data2 as uint, uf.data3 as uint,
+ uf.data4[0] as uint, uf.data4[1] as uint,
+ uf.data4[2] as uint, uf.data4[3] as uint, uf.data4[4] as uint,
+ uf.data4[5] as uint, uf.data4[6] as uint, uf.data4[7] as uint);
+ s
+ }
+
+ /// Returns the UUID formatted as a full URN string
+ ///
+ /// This is the same as the hyphenated format, but with the "urn:uuid:" prefix.
+ ///
+ /// Example: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4`
+ pub fn to_urn_str(&self) -> ~str {
+ "urn:uuid:" + self.to_hyphenated_str()
+ }
+
+ /// Parses a UUID from a string of hexadecimal digits with optional hyphens
+ ///
+ /// Any of the formats generated by this module (simple, hyphenated, urn) are
+ /// supported by this parsing function.
+ pub fn parse_string(us: &str) -> Result<Uuid, ParseError> {
+
+ let mut us = us.clone();
+ let orig_len = us.len();
+
+ // Ensure length is valid for any of the supported formats
+ if orig_len != 32 && orig_len != 36 && orig_len != 45 {
+ return Err(ErrorInvalidLength(orig_len));
+ }
+
+ // Strip off URN prefix if present
+ if us.starts_with("urn:uuid:") {
+ us = us.slice(9, orig_len);
+ }
+
+ // Make sure all chars are either hex digits or hyphen
+ for (i, c) in us.iter().enumerate() {
+ match c {
+ '0'..'9' | 'A'..'F' | 'a'..'f' | '-' => {},
+ _ => return Err(ErrorInvalidCharacter(c, i)),
+ }
+ }
+
+ // Split string up by hyphens into groups
+ let hex_groups: ~[&str] = us.split_str_iter("-").collect();
+
+ // Get the length of each group
+ let group_lens: ~[uint] = hex_groups.iter().map(|&v| v.len()).collect();
+
+ // Ensure the group lengths are valid
+ match group_lens.len() {
+ // Single group, no hyphens
+ 1 => {
+ if group_lens[0] != 32 {
+ return Err(ErrorInvalidLength(group_lens[0]));
+ }
+ },
+ // Five groups, hyphens in between each
+ 5 => {
+ // Ensure each group length matches the expected
+ for (i, (&gl, &expected)) in
+ group_lens.iter().zip(UuidGroupLens.iter()).enumerate() {
+ if gl != expected {
+ return Err(ErrorInvalidGroupLength(i, gl, expected))
+ }
+ }
+ },
+ _ => {
+ return Err(ErrorInvalidGroups(group_lens.len()));
+ }
+ }
+
+ // Normalise into one long hex string
+ let vs = hex_groups.concat();
+
+ // At this point, we know we have a valid hex string, without hyphens
+ assert!(vs.len() == 32);
+ assert!(vs.iter().all(|c| c.is_digit_radix(16)));
+
+ // Allocate output UUID buffer
+ let mut ub = [0u8, ..16];
+
+ // Extract each hex digit from the string
+ for i in range(0u, 16u) {
+ ub[i] = FromStrRadix::from_str_radix(vs.slice(i*2, (i+1)*2), 16).unwrap();
+ }
+
+ Ok(Uuid::from_bytes(ub).unwrap())
+ }
+}
+
+impl Zero for Uuid {
+ /// Returns the nil UUID, which is all zeroes
+ fn zero() -> Uuid {
+ Uuid::new_nil()
+ }
+
+ /// Tests if the UUID is nil or all zeroes
+ fn is_zero(&self) -> bool {
+ return self.bytes.iter().all(|&b| b == 0);
+ }
+}
+
+impl Clone for Uuid {
+ /// Returns a copy of the UUID
+ fn clone(&self) -> Uuid {
+ let mut clone = Uuid{ bytes: [0, .. 16] };
+ vec::bytes::copy_memory(clone.bytes, self.bytes, 16);
+ clone
+ }
+}
+
+impl FromStr for Uuid {
+ /// Parse a hex string and interpret as a UUID
+ ///
+ /// Accepted formats are a sequence of 32 hexadecimal characters,
+ /// with or without hypens (grouped as 8, 4, 4, 4, 12).
+ fn from_str(us: &str) -> Option<Uuid> {
+ let result = Uuid::parse_string(us);
+ match result {
+ Ok(u) => Some(u),
+ Err(_) => None
+ }
+ }
+}
+
+/// Convert the UUID to a hexadecimal-based string representation
+impl ToStr for Uuid {
+ fn to_str(&self) -> ~str {
+ self.to_simple_str()
+ }
+}
+
+/// Test two UUIDs for equality
+///
+/// UUIDs are equal only when they are byte-for-byte identical
+impl Eq for Uuid {
+ fn eq(&self, other: &Uuid) -> bool {
+ self.bytes == other.bytes
+ }
+}
+
+/// Test two UUIDs for equality
+///
+/// UUIDs are equal only when they are byte-for-byte identical
+impl TotalEq for Uuid {
+ fn equals(&self, other: &Uuid) -> bool {
+ self.bytes == other.bytes
+ }
+}
+
+/// Generates a random instance of UUID (V4 conformant)
+impl rand::Rand for Uuid {
+ #[inline]
+ fn rand<R: rand::Rng>(rng: &mut R) -> Uuid {
+ let ub = rng.gen_bytes(16);
+ let mut uuid = Uuid{ bytes: [0, .. 16] };
+ vec::bytes::copy_memory(uuid.bytes, ub, 16);
+ uuid.set_variant(VariantRFC4122);
+ uuid.set_version(Version4Random);
+ uuid
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::str;
+ use std::rand;
+ use std::num::Zero;
+
+ #[test]
+ fn test_new_nil() {
+ let nil = Uuid::new_nil();
+ let nb = nil.to_bytes();
+
+ assert!(nb.iter().all(|&b| b == 0));
+ }
+
+ #[test]
+ fn test_zero() {
+ let uz: Uuid = Zero::zero();
+ let nz = Uuid::new_v4();
+
+ assert!(uz.is_zero());
+ assert!(! nz.is_zero());
+ }
+
+ #[test]
+ fn test_new() {
+ // Supported
+ let uuid1 = Uuid::new(Version4Random).unwrap();
+ let s = uuid1.to_simple_str();
+
+ assert!(s.len() == 32);
+ assert!(uuid1.get_version().unwrap() == Version4Random);
+
+ // Test unsupported versions
+ assert!(Uuid::new(Version1Mac) == None);
+ assert!(Uuid::new(Version2Dce) == None);
+ assert!(Uuid::new(Version3Md5) == None);
+ assert!(Uuid::new(Version5Sha1) == None);
+ }
+
+ #[test]
+ fn test_new_v4() {
+ let uuid1 = Uuid::new_v4();
+
+ assert!(uuid1.get_version().unwrap() == Version4Random);
+ assert!(uuid1.get_variant().unwrap() == VariantRFC4122);
+ }
+
+ #[test]
+ fn test_get_version() {
+ let uuid1 = Uuid::new_v4();
+
+ assert!(uuid1.get_version().unwrap() == Version4Random);
+ assert!(uuid1.get_version_num() == 4);
+ }
+
+ #[test]
+ fn test_get_variant() {
+ let uuid1 = Uuid::new_v4();
+ let uuid2 = Uuid::parse_string("550e8400-e29b-41d4-a716-446655440000").unwrap();
+ let uuid3 = Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
+ let uuid4 = Uuid::parse_string("936DA01F9ABD4d9dC0C702AF85C822A8").unwrap();
+ let uuid5 = Uuid::parse_string("F9168C5E-CEB2-4faa-D6BF-329BF39FA1E4").unwrap();
+ let uuid6 = Uuid::parse_string("f81d4fae-7dec-11d0-7765-00a0c91e6bf6").unwrap();
+
+ assert!(uuid1.get_variant().unwrap() == VariantRFC4122);
+ assert!(uuid2.get_variant().unwrap() == VariantRFC4122);
+ assert!(uuid3.get_variant().unwrap() == VariantRFC4122);
+ assert!(uuid4.get_variant().unwrap() == VariantMicrosoft);
+ assert!(uuid5.get_variant().unwrap() == VariantMicrosoft);
+ assert!(uuid6.get_variant().unwrap() == VariantNCS);
+ }
+
+ #[test]
+ fn test_parse_uuid_v4() {
+
+ // Invalid
+ assert!(Uuid::parse_string("").is_err());
+ assert!(Uuid::parse_string("!").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4").is_err());
+ assert!(Uuid::parse_string("01020304-1112-2122-3132-41424344").is_err());
+ assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c").is_err());
+ assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c88").is_err());
+ assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0cg8").is_err());
+ assert!(Uuid::parse_string("67e5504410b1426%9247bb680e5fe0c8").is_err());
+
+ // Valid
+ assert!(Uuid::parse_string("00000000000000000000000000000000").is_ok());
+ assert!(Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
+ assert!(Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
+ assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").is_ok());
+ assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c8").is_ok());
+ assert!(Uuid::parse_string("01020304-1112-2122-3132-414243444546").is_ok());
+ assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
+
+ // Nil
+ let nil = Uuid::new_nil();
+ assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap() == nil);
+ assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil);
+
+ // Round-trip
+ let uuid_orig = Uuid::new_v4();
+ let orig_str = uuid_orig.to_str();
+ let uuid_out = Uuid::parse_string(orig_str).unwrap();
+ assert!(uuid_orig == uuid_out);
+
+ // Test error reporting
+ let e = Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c").unwrap_err();
+ assert!(match(e){ ErrorInvalidLength(n) => n==31, _ => false });
+
+ let e = Uuid::parse_string("67e550X410b1426f9247bb680e5fe0cd").unwrap_err();
+ assert!(match(e){ ErrorInvalidCharacter(c, n) => c=='X' && n==6, _ => false });
+
+ let e = Uuid::parse_string("67e550-4105b1426f9247bb680e5fe0c").unwrap_err();
+ assert!(match(e){ ErrorInvalidGroups(n) => n==2, _ => false });
+
+ let e = Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4").unwrap_err();
+ assert!(match(e){ ErrorInvalidGroupLength(g, n, e) => g==3 && n==5 && e==4, _ => false });
+ }
+
+ #[test]
+ fn test_to_simple_str() {
+ let uuid1 = Uuid::new_v4();
+ let s = uuid1.to_simple_str();
+
+ assert!(s.len() == 32);
+ assert!(s.iter().all(|c| c.is_digit_radix(16)));
+ }
+
+ #[test]
+ fn test_to_str() {
+ let uuid1 = Uuid::new_v4();
+ let s = uuid1.to_str();
+
+ assert!(s.len() == 32);
+ assert!(s.iter().all(|c| c.is_digit_radix(16)));
+ }
+
+ #[test]
+ fn test_to_hyphenated_str() {
+ let uuid1 = Uuid::new_v4();
+ let s = uuid1.to_hyphenated_str();
+
+ assert!(s.len() == 36);
+ assert!(s.iter().all(|c| c.is_digit_radix(16) || c == '-'));
+ }
+
+ #[test]
+ fn test_to_urn_str() {
+ let uuid1 = Uuid::new_v4();
+ let ss = uuid1.to_urn_str();
+ let s = ss.slice(9, ss.len());
+
+ assert!(ss.starts_with("urn:uuid:"));
+ assert!(s.len() == 36);
+ assert!(s.iter().all(|c| c.is_digit_radix(16) || c == '-'));
+ }
+
+ #[test]
+ fn test_to_str_matching() {
+ let uuid1 = Uuid::new_v4();
+
+ let hs = uuid1.to_hyphenated_str();
+ let ss = uuid1.to_str();
+
+ let hsn = str::from_chars(hs.iter().filter(|&c| c != '-').collect::<~[char]>());
+
+ assert!(hsn == ss);
+ }
+
+ #[test]
+ fn test_string_roundtrip() {
+ let uuid = Uuid::new_v4();
+
+ let hs = uuid.to_hyphenated_str();
+ let uuid_hs = Uuid::parse_string(hs).unwrap();
+ assert!(uuid_hs == uuid);
+
+ let ss = uuid.to_str();
+ let uuid_ss = Uuid::parse_string(ss).unwrap();
+ assert!(uuid_ss == uuid);
+ }
+
+ #[test]
+ fn test_compare() {
+ let uuid1 = Uuid::new_v4();
+ let uuid2 = Uuid::new_v4();
+
+ assert!(uuid1 == uuid1);
+ assert!(uuid2 == uuid2);
+ assert!(uuid1 != uuid2);
+ assert!(uuid2 != uuid1);
+ }
+
+ #[test]
+ fn test_from_fields() {
+ let d1: u32 = 0xa1a2a3a4;
+ let d2: u16 = 0xb1b2;
+ let d3: u16 = 0xc1c2;
+ let d4: ~[u8] = ~[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8];
+
+ let u = Uuid::from_fields(d1, d2, d3, d4);
+
+ let expected = ~"a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
+ let result = u.to_simple_str();
+ assert!(result == expected);
+ }
+
+ #[test]
+ fn test_from_bytes() {
+ let b = ~[ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2,
+ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 ];
+
+ let u = Uuid::from_bytes(b).unwrap();
+ let expected = ~"a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
+
+ assert!(u.to_simple_str() == expected);
+ }
+
+ #[test]
+ fn test_to_bytes() {
+ let u = Uuid::new_v4();
+ let ub = u.to_bytes();
+
+ assert!(ub.len() == 16);
+ assert!(! ub.iter().all(|&b| b == 0));
+ }
+
+ #[test]
+ fn test_bytes_roundtrip() {
+ let b_in: [u8, ..16] = [ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2,
+ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 ];
+
+ let u = Uuid::from_bytes(b_in.clone()).unwrap();
+
+ let b_out = u.to_bytes();
+
+ assert!(b_in == b_out);
+ }
+
+ #[test]
+ fn test_operator_eq() {
+ let u1 = Uuid::new_v4();
+ let u2 = u1.clone();
+ let u3 = Uuid::new_v4();
+
+ assert!(u1 == u1);
+ assert!(u1 == u2);
+ assert!(u2 == u1);
+
+ assert!(u1 != u3);
+ assert!(u3 != u1);
+ assert!(u2 != u3);
+ assert!(u3 != u2);
+ }
+
+ #[test]
+ fn test_rand_rand() {
+ let mut rng = rand::rng();
+ let u: ~Uuid = rand::Rand::rand(&mut rng);
+ let ub = u.to_bytes();
+
+ assert!(ub.len() == 16);
+ assert!(! ub.iter().all(|&b| b == 0));
+ }
+}
+
+#[cfg(test)]
+mod bench {
+ use super::*;
+ use test::BenchHarness;
+
+ #[bench]
+ pub fn create_uuids(bh: &mut BenchHarness) {
+ do bh.iter {
+ Uuid::new_v4();
+ }
+ }
+
+ #[bench]
+ pub fn uuid_to_str(bh: &mut BenchHarness) {
+ let u = Uuid::new_v4();
+ do bh.iter {
+ u.to_str();
+ }
+ }
+
+ #[bench]
+ pub fn parse_str(bh: &mut BenchHarness) {
+ let s = "urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4";
+ do bh.iter {
+ let u = Uuid::parse_string(s);
+ }
+ }
+}
}
pub fn main() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let os_args = os::args();
if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) {
OptLevel: c_int,
EnableSegmentedStacks: bool) {
unsafe {
- do Triple.to_c_str().with_ref |Triple| {
- do Cpu.to_c_str().with_ref |Cpu| {
- do Feature.to_c_str().with_ref |Feature| {
- do Output.to_c_str().with_ref |Output| {
+ do Triple.with_c_str |Triple| {
+ do Cpu.with_c_str |Cpu| {
+ do Feature.with_c_str |Feature| {
+ do Output.with_c_str |Output| {
let result = llvm::LLVMRustWriteOutputFile(
PM,
M,
debug!("linking: %s", path);
- do path.to_c_str().with_ref |buf_t| {
+ do path.with_c_str |buf_t| {
if !llvm::LLVMRustLoadCrate(manager, buf_t) {
llvm_err(sess, ~"Could not link");
}
// Next, we need to get a handle on the _rust_main function by
// looking up it's corresponding ValueRef and then requesting that
// the execution engine compiles the function.
- let fun = do "_rust_main".to_c_str().with_ref |entry| {
+ let fun = do "_rust_main".with_c_str |entry| {
llvm::LLVMGetNamedFunction(m, entry)
};
if fun.is_null() {
output_type_bitcode => {
if opts.optimize != session::No {
let filename = output.with_filetype("no-opt.bc");
- do filename.to_c_str().with_ref |buf| {
+ do filename.with_c_str |buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf);
}
}
}
_ => {
let filename = output.with_filetype("bc");
- do filename.to_c_str().with_ref |buf| {
+ do filename.with_c_str |buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf);
}
}
// Always output the bitcode file with --save-temps
let filename = output.with_filetype("opt.bc");
- do filename.to_c_str().with_ref |buf| {
+ do filename.with_c_str |buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf)
};
// Save the assembly file if -S is used
if output_type == output_type_llvm_assembly {
// Given options "-S --emit-llvm": output LLVM assembly
- do output.to_c_str().with_ref |buf_o| {
+ do output.with_c_str |buf_o| {
llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o);
}
} else {
// If only a bitcode file is asked for by using the
// '--emit-llvm' flag, then output it here
- do output.to_c_str().with_ref |buf| {
+ do output.with_c_str |buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf);
}
}
}
pub fn create_pass(name:&str) -> Option<PassRef> {
- do name.to_c_str().with_ref |s| {
+ do name.with_c_str |s| {
unsafe {
let p = llvm::LLVMCreatePass(s);
if p.is_null() {
("scalarrepl", "Scalar Replacement of Aggregates (DT)"),
("scalarrepl-ssa", "Scalar Replacement of Aggregates (SSAUp)"),
("sccp", "Sparse Conditional Constant Propagation"),
- ("simplify-libcalls", "Simplify well-known library calls"),
("simplifycfg", "Simplify the CFG"),
("sink", "Code sinking"),
("strip", "Strip all symbols from a module"),
pub struct Upcalls {
trace: ValueRef,
- call_shim_on_c_stack: ValueRef,
- call_shim_on_rust_stack: ValueRef,
rust_personality: ValueRef,
reset_stack_limit: ValueRef
}
@Upcalls {
trace: upcall!(fn trace(opaque_ptr, opaque_ptr, int_ty) -> Type::void()),
- call_shim_on_c_stack: upcall!(fn call_shim_on_c_stack(opaque_ptr, opaque_ptr) -> int_ty),
- call_shim_on_rust_stack:
- upcall!(fn call_shim_on_rust_stack(opaque_ptr, opaque_ptr) -> int_ty),
rust_personality: upcall!(nothrow fn rust_personality -> Type::i32()),
reset_stack_limit: upcall!(nothrow fn reset_stack_limit -> Type::void())
}
use util::ppaux;
use std::hashmap::{HashMap,HashSet};
-use std::int;
use std::io;
use std::os;
use std::vec;
}
}
-pub fn default_configuration(sess: Session, argv0: @str, input: &input) ->
+pub fn default_configuration(sess: Session) ->
ast::CrateConfig {
- let (libc, tos) = match sess.targ_cfg.os {
- session::os_win32 => (@"msvcrt.dll", @"win32"),
- session::os_macos => (@"libc.dylib", @"macos"),
- session::os_linux => (@"libc.so.6", @"linux"),
- session::os_android => (@"libc.so", @"android"),
- session::os_freebsd => (@"libc.so.7", @"freebsd")
+ let tos = match sess.targ_cfg.os {
+ session::os_win32 => @"win32",
+ session::os_macos => @"macos",
+ session::os_linux => @"linux",
+ session::os_android => @"android",
+ session::os_freebsd => @"freebsd"
};
// ARM is bi-endian, however using NDK seems to default
mk(@"target_arch", arch),
mk(@"target_endian", end),
mk(@"target_word_size", wordsz),
- mk(@"target_libc", libc),
- // Build bindings.
- mk(@"build_compiler", argv0),
- mk(@"build_input", source_name(input))];
+ ];
}
pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) {
}
}
-pub fn build_configuration(sess: Session, argv0: @str, input: &input) ->
+pub fn build_configuration(sess: Session) ->
ast::CrateConfig {
// Combine the configuration requested by the session (command line) with
// some default and generated configuration items
- let default_cfg = default_configuration(sess, argv0, input);
+ let default_cfg = default_configuration(sess);
let mut user_cfg = sess.opts.cfg.clone();
// If the user wants a test runner, then add the test cfg
if sess.opts.test { append_configuration(&mut user_cfg, @"test") }
time(time_passes, ~"loop checking", ||
middle::check_loop::check_crate(ty_cx, crate));
+ time(time_passes, ~"stack checking", ||
+ middle::stack_check::stack_check_crate(ty_cx, crate));
+
let middle::moves::MoveMaps {moves_map, moved_variables_set,
capture_map} =
time(time_passes, ~"compute moves", ||
match node {
pprust::node_item(s, item) => {
pp::space(s.s);
- pprust::synth_comment(s, int::to_str(item.id));
+ pprust::synth_comment(s, item.id.to_str());
}
pprust::node_block(s, ref blk) => {
pp::space(s.s);
pprust::synth_comment(
- s, ~"block " + int::to_str(blk.id));
+ s, ~"block " + blk.id.to_str());
}
pprust::node_expr(s, expr) => {
pp::space(s.s);
- pprust::synth_comment(s, int::to_str(expr.id));
+ pprust::synth_comment(s, expr.id.to_str());
pprust::pclose(s);
}
pprust::node_pat(s, pat) => {
pp::space(s.s);
- pprust::synth_comment(s, ~"pat " + int::to_str(pat.id));
+ pprust::synth_comment(s, ~"pat " + pat.id.to_str());
}
}
}
}
debugging_opts |= this_bit;
}
+
if debugging_opts & session::debug_llvm != 0 {
- unsafe {
- llvm::LLVMSetDebug(1);
+ set_llvm_debug();
+
+ fn set_llvm_debug() {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { llvm::LLVMSetDebug(1); }
}
}
let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
let debuginfo = debugging_opts & session::debug_info != 0 ||
extra_debuginfo;
+
+ // If debugging info is generated, do not collapse monomorphized function instances.
+ // Functions with equivalent llvm code still need separate debugging descriptions because names
+ // might differ.
+ if debuginfo {
+ debugging_opts |= session::no_monomorphic_collapse;
+ }
+
let statik = debugging_opts & session::statik != 0;
let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
mod test {
use driver::driver::{build_configuration, build_session};
- use driver::driver::{build_session_options, optgroups, str_input};
+ use driver::driver::{build_session_options, optgroups};
use extra::getopts::groups::getopts;
use extra::getopts;
let sessopts = build_session_options(
@"rustc", matches, diagnostic::emit);
let sess = build_session(sessopts, diagnostic::emit);
- let cfg = build_configuration(sess, @"whatever", &str_input(@""));
+ let cfg = build_configuration(sess);
assert!((attr::contains_name(cfg, "test")));
}
let sessopts = build_session_options(
@"rustc", matches, diagnostic::emit);
let sess = build_session(sessopts, diagnostic::emit);
- let cfg = build_configuration(sess, @"whatever", &str_input(@""));
+ let cfg = build_configuration(sess);
let mut test_items = cfg.iter().filter(|m| "test" == m.name());
assert!(test_items.next().is_some());
assert!(test_items.next().is_none());
}
}
+#[cfg(stage0)]
fn mk_test_module(cx: &TestCtxt) -> @ast::item {
// Link to extra
return @item;
}
+#[cfg(not(stage0))]
+fn mk_test_module(cx: &TestCtxt) -> @ast::item {
+
+ // Link to extra
+ let view_items = ~[mk_std(cx)];
+
+ // A constant vector of test descriptors.
+ let tests = mk_tests(cx);
+
+ // The synthesized main function which will call the console test runner
+ // with our list of tests
+ let mainfn = (quote_item!(cx.ext_cx,
+ pub fn main() {
+ #[main];
+ extra::test::test_main_static(::std::os::args(), TESTS);
+ }
+ )).unwrap();
+
+ let testmod = ast::_mod {
+ view_items: view_items,
+ items: ~[mainfn, tests],
+ };
+ let item_ = ast::item_mod(testmod);
+
+ // This attribute tells resolve to let us call unexported functions
+ let resolve_unexported_attr =
+ attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));
+
+ let item = ast::item {
+ ident: cx.sess.ident_of("__test"),
+ attrs: ~[resolve_unexported_attr],
+ id: cx.sess.next_node_id(),
+ node: item_,
+ vis: ast::public,
+ span: dummy_sp(),
+ };
+
+ debug!("Synthetic test module:\n%s\n",
+ pprust::item_to_str(@item.clone(), cx.sess.intr()));
+
+ return @item;
+}
fn nospan<T>(t: T) -> codemap::spanned<T> {
codemap::spanned { node: t, span: dummy_sp() }
types: ~[] }
}
+#[cfg(stage0)]
fn mk_tests(cx: &TestCtxt) -> @ast::item {
let ext_cx = cx.ext_cx;
;
)).unwrap()
}
+#[cfg(not(stage0))]
+fn mk_tests(cx: &TestCtxt) -> @ast::item {
+ // The vector of test_descs for this crate
+ let test_descs = mk_test_descs(cx);
+
+ (quote_item!(cx.ext_cx,
+ pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
+ $test_descs
+ ;
+ )).unwrap()
+}
fn is_extra(cx: &TestCtxt) -> bool {
let items = attr::find_linkage_metas(cx.crate.attrs);
}
}
+#[cfg(stage0)]
fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::expr {
let span = test.span;
let path = test.path.clone();
);
e
}
+#[cfg(not(stage0))]
+fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::expr {
+ let span = test.span;
+ let path = test.path.clone();
+
+ debug!("encoding %s", ast_util::path_name_i(path));
+
+ let name_lit: ast::lit =
+ nospan(ast::lit_str(ast_util::path_name_i(path).to_managed()));
+
+ let name_expr = @ast::expr {
+ id: cx.sess.next_node_id(),
+ node: ast::expr_lit(@name_lit),
+ span: span
+ };
+
+ let fn_path = path_node_global(path);
+
+ let fn_expr = @ast::expr {
+ id: cx.sess.next_node_id(),
+ node: ast::expr_path(fn_path),
+ span: span,
+ };
+
+ let t_expr = if test.bench {
+ quote_expr!(cx.ext_cx, self::extra::test::StaticBenchFn($fn_expr) )
+ } else {
+ quote_expr!(cx.ext_cx, self::extra::test::StaticTestFn($fn_expr) )
+ };
+
+ let ignore_expr = if test.ignore {
+ quote_expr!(cx.ext_cx, true )
+ } else {
+ quote_expr!(cx.ext_cx, false )
+ };
+
+ let fail_expr = if test.should_fail {
+ quote_expr!(cx.ext_cx, true )
+ } else {
+ quote_expr!(cx.ext_cx, false )
+ };
+
+ let e = quote_expr!(cx.ext_cx,
+ self::extra::test::TestDescAndFn {
+ desc: self::extra::test::TestDesc {
+ name: self::extra::test::StaticTestName($name_expr),
+ ignore: $ignore_expr,
+ should_fail: $fail_expr
+ },
+ testfn: $t_expr,
+ }
+ );
+ e
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// LLVM wrappers are intended to be called from trans,
+// which already runs in a #[fixed_stack_segment]
+#[allow(cstack)];
+
use std::c_str::ToCStr;
use std::hashmap::HashMap;
use std::libc::{c_uint, c_ushort};
ReturnsTwiceAttribute = 1 << 29,
UWTableAttribute = 1 << 30,
NonLazyBindAttribute = 1 << 31,
-
- // Not added to LLVM yet, so may need to stay updated if LLVM changes.
- // FIXME(#8199): if this changes, be sure to change the relevant constant
- // down below
- // FixedStackSegment = 1 << 41,
}
// enum for the LLVM IntPredicate type
#[fast_ffi]
pub fn LLVMSetGC(Fn: ValueRef, Name: *c_char);
#[fast_ffi]
- pub fn LLVMAddFunctionAttr(Fn: ValueRef, PA: c_uint, HighPA: c_uint);
+ pub fn LLVMAddFunctionAttr(Fn: ValueRef, PA: c_uint);
+ #[fast_ffi]
+ pub fn LLVMAddFunctionAttrString(Fn: ValueRef, Name: *c_char);
#[fast_ffi]
pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong;
#[fast_ffi]
#[fast_ffi]
pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool);
+
+ #[fast_ffi]
+ pub fn LLVMDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef,
+ Scope: ValueRef,
+ Name: *c_char,
+ Ty: ValueRef,
+ File: ValueRef,
+ LineNo: c_uint,
+ ColumnNo: c_uint)
+ -> ValueRef;
}
}
pub fn SetFunctionAttribute(Fn: ValueRef, attr: Attribute) {
unsafe {
- let attr = attr as u64;
- let lower = attr & 0xffffffff;
- let upper = (attr >> 32) & 0xffffffff;
- llvm::LLVMAddFunctionAttr(Fn, lower as c_uint, upper as c_uint);
- }
-}
-
-// FIXME(#8199): this shouldn't require this hackery. On i686
-// (FixedStackSegment as u64) will return 0 instead of 1 << 41.
-// Furthermore, if we use a match of any sort then an LLVM
-// assertion is generated!
-pub fn SetFixedStackSegmentAttribute(Fn: ValueRef) {
- unsafe {
- let attr = 1u64 << 41;
- let lower = attr & 0xffffffff;
- let upper = (attr >> 32) & 0xffffffff;
- llvm::LLVMAddFunctionAttr(Fn, lower as c_uint, upper as c_uint);
+ llvm::LLVMAddFunctionAttr(Fn, attr as c_uint)
}
}
/* Memory-managed object interface to type handles. */
self.type_to_str_depth(ty, 30)
}
+ pub fn types_to_str(&self, tys: &[Type]) -> ~str {
+ let strs = tys.map(|t| self.type_to_str(*t));
+ fmt!("[%s]", strs.connect(","))
+ }
+
pub fn val_to_str(&self, val: ValueRef) -> ~str {
unsafe {
let ty = Type::from_ref(llvm::LLVMTypeOf(val));
}
pub fn mk_target_data(string_rep: &str) -> TargetData {
- let lltd = do string_rep.to_c_str().with_ref |buf| {
+ let lltd = do string_rep.with_c_str |buf| {
unsafe { llvm::LLVMCreateTargetData(buf) }
};
warn_if_multiple_versions(e, diag, *e.crate_cache);
}
+#[deriving(Clone)]
struct cache_entry {
cnum: int,
span: span,
fn warn_if_multiple_versions(e: @mut Env,
diag: @mut span_handler,
crate_cache: &[cache_entry]) {
- use std::either::*;
-
if crate_cache.len() != 0u {
let name = loader::crate_name_from_metas(
*crate_cache[crate_cache.len() - 1].metas
);
- let vec: ~[Either<cache_entry, cache_entry>] = crate_cache.iter().map(|&entry| {
- let othername = loader::crate_name_from_metas(*entry.metas);
- if name == othername {
- Left(entry)
- } else {
- Right(entry)
- }
- }).collect();
- let (matches, non_matches) = partition(vec);
+ let (matches, non_matches) = crate_cache.partitioned(|entry|
+ name == loader::crate_name_from_metas(*entry.metas));
assert!(!matches.is_empty());
use std::hashmap::{HashMap, HashSet};
use std::io;
use std::str;
-use std::uint;
use std::vec;
use extra::flate;
use extra::serialize::Encodable;
use syntax::attr::AttrMetaMethods;
use syntax::diagnostic::span_handler;
use syntax::parse::token::special_idents;
-use syntax::{ast_util, oldvisit};
+use syntax::ast_util;
+use syntax::visit;
use syntax::parse::token;
use syntax;
use writer = extra::ebml::writer;
ebml_w: &mut writer::Encoder,
disr_val: uint) {
ebml_w.start_tag(tag_disr_val);
- let s = uint::to_str(disr_val);
+ let s = disr_val.to_str();
ebml_w.writer.write(s.as_bytes());
ebml_w.end_tag();
}
ebml_w.end_tag();
}
+fn my_visit_expr(_e:@expr) { }
+
+fn my_visit_item(i:@item, items: ast_map::map, ebml_w:&writer::Encoder,
+ ecx_ptr:*int, index: @mut ~[entry<i64>]) {
+ match items.get_copy(&i.id) {
+ ast_map::node_item(_, pt) => {
+ let mut ebml_w = ebml_w.clone();
+ // See above
+ let ecx : &EncodeContext = unsafe { cast::transmute(ecx_ptr) };
+ encode_info_for_item(ecx, &mut ebml_w, i, index, *pt);
+ }
+ _ => fail!("bad item")
+ }
+}
+
+fn my_visit_foreign_item(ni:@foreign_item, items: ast_map::map, ebml_w:&writer::Encoder,
+ ecx_ptr:*int, index: @mut ~[entry<i64>]) {
+ match items.get_copy(&ni.id) {
+ ast_map::node_foreign_item(_, abi, _, pt) => {
+ debug!("writing foreign item %s::%s",
+ ast_map::path_to_str(
+ *pt,
+ token::get_ident_interner()),
+ token::ident_to_str(&ni.ident));
+
+ let mut ebml_w = ebml_w.clone();
+ // See above
+ let ecx : &EncodeContext = unsafe { cast::transmute(ecx_ptr) };
+ encode_info_for_foreign_item(ecx,
+ &mut ebml_w,
+ ni,
+ index,
+ pt,
+ abi);
+ }
+ // case for separate item and foreign-item tables
+ _ => fail!("bad foreign item")
+ }
+}
+
+struct EncodeVisitor {
+ ebml_w_for_visit_item: writer::Encoder,
+ ebml_w_for_visit_foreign_item: writer::Encoder,
+ ecx_ptr:*int,
+ items: ast_map::map,
+ index: @mut ~[entry<i64>],
+}
+
+impl visit::Visitor<()> for EncodeVisitor {
+ fn visit_expr(&mut self, ex:@expr, _:()) { my_visit_expr(ex); }
+ fn visit_item(&mut self, i:@item, _:()) {
+ visit::walk_item(self, i, ());
+ my_visit_item(i,
+ self.items,
+ &self.ebml_w_for_visit_item,
+ self.ecx_ptr,
+ self.index);
+ }
+ fn visit_foreign_item(&mut self, ni:@foreign_item, _:()) {
+ visit::walk_foreign_item(self, ni, ());
+ my_visit_foreign_item(ni,
+ self.items,
+ &self.ebml_w_for_visit_foreign_item,
+ self.ecx_ptr,
+ self.index);
+ }
+}
+
fn encode_info_for_items(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
crate: &Crate)
let items = ecx.tcx.items;
// See comment in `encode_side_tables_for_ii` in astencode
- let ecx_ptr : *() = unsafe { cast::transmute(ecx) };
-
- oldvisit::visit_crate(crate, ((), oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: |_e, (_cx, _v)| { },
- visit_item: {
- let ebml_w = (*ebml_w).clone();
- |i, (cx, v)| {
- oldvisit::visit_item(i, (cx, v));
- match items.get_copy(&i.id) {
- ast_map::node_item(_, pt) => {
- let mut ebml_w = ebml_w.clone();
- // See above
- let ecx : &EncodeContext = unsafe { cast::transmute(ecx_ptr) };
- encode_info_for_item(ecx, &mut ebml_w, i, index, *pt);
- }
- _ => fail!("bad item")
- }
- }
- },
- visit_foreign_item: {
- let ebml_w = (*ebml_w).clone();
- |ni, (cx, v)| {
- oldvisit::visit_foreign_item(ni, (cx, v));
- match items.get_copy(&ni.id) {
- ast_map::node_foreign_item(_, abi, _, pt) => {
- debug!("writing foreign item %s::%s",
- ast_map::path_to_str(
- *pt,
- token::get_ident_interner()),
- token::ident_to_str(&ni.ident));
-
- let mut ebml_w = ebml_w.clone();
- // See above
- let ecx : &EncodeContext = unsafe { cast::transmute(ecx_ptr) };
- encode_info_for_foreign_item(ecx,
- &mut ebml_w,
- ni,
- index,
- pt,
- abi);
- }
- // case for separate item and foreign-item tables
- _ => fail!("bad foreign item")
- }
- }
- },
- ..*oldvisit::default_visitor()
- })));
+ let ecx_ptr : *int = unsafe { cast::transmute(ecx) };
+ let mut visitor = EncodeVisitor {
+ index: index,
+ items: items,
+ ecx_ptr: ecx_ptr,
+ ebml_w_for_visit_item: (*ebml_w).clone(),
+ ebml_w_for_visit_foreign_item: (*ebml_w).clone(),
+ };
+
+ visit::walk_crate(&mut visitor, crate, ());
+
ebml_w.end_tag();
return /*bad*/(*index).clone();
}
fn get_metadata_section(os: os,
filename: &Path) -> Option<@~[u8]> {
unsafe {
- let mb = do filename.to_c_str().with_ref |buf| {
+ let mb = do filename.with_c_str |buf| {
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
};
if mb as int == 0 { return option::None::<@~[u8]>; }
use std::hashmap::HashMap;
use std::io::WriterUtil;
use std::io;
-use std::uint;
use syntax::abi::AbiSet;
use syntax::ast;
use syntax::ast::*;
w.write_char('p');
w.write_str((cx.ds)(did));
w.write_char('|');
- w.write_str(uint::to_str(id));
+ w.write_str(id.to_str());
}
ty::ty_self(did) => {
w.write_char('s');
}
)
}
- typeck::method_trait(did, m) => {
- typeck::method_trait(did.tr(xcx), m)
+ typeck::method_object(ref mo) => {
+ typeck::method_object(
+ typeck::method_object {
+ trait_id: mo.trait_id.tr(xcx),
+ .. *mo
+ }
+ )
}
}
}
#[test]
fn test_basic() {
- let ext_cx = mk_ctxt();
- roundtrip(quote_item!(
+ let cx = mk_ctxt();
+ roundtrip(quote_item!(cx,
fn foo() {}
));
}
#[test]
fn test_smalltalk() {
- let ext_cx = mk_ctxt();
- roundtrip(quote_item!(
+ let cx = mk_ctxt();
+ roundtrip(quote_item!(cx,
fn foo() -> int { 3 + 4 } // first smalltalk program ever executed.
));
}
#[test]
fn test_more() {
- let ext_cx = mk_ctxt();
- roundtrip(quote_item!(
+ let cx = mk_ctxt();
+ roundtrip(quote_item!(cx,
fn foo(x: uint, y: uint) -> uint {
let z = x + y;
return z;
#[test]
fn test_simplification() {
- let ext_cx = mk_ctxt();
- let item_in = ast::ii_item(quote_item!(
+ let cx = mk_ctxt();
+ let item_in = ast::ii_item(quote_item!(cx,
fn new_int_alist<B>() -> alist<int, B> {
fn eq_int(a: int, b: int) -> bool { a == b }
return alist {eq_fn: eq_int, data: ~[]};
}
).unwrap());
let item_out = simplify_ast(&item_in);
- let item_exp = ast::ii_item(quote_item!(
+ let item_exp = ast::ii_item(quote_item!(cx,
fn new_int_alist<B>() -> alist<int, B> {
return alist {eq_fn: eq_int, data: ~[]};
}
use syntax::ast;
use syntax::ast_util;
use syntax::codemap::span;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
use util::ppaux::Repr;
#[deriving(Clone)]
reported: @mut HashSet<ast::NodeId>,
}
+struct CheckLoanVisitor;
+
+impl<'self> Visitor<CheckLoanCtxt<'self>> for CheckLoanVisitor {
+ fn visit_expr<'a>(&mut self, ex:@ast::expr, e:CheckLoanCtxt<'a>) {
+ check_loans_in_expr(self, ex, e);
+ }
+ fn visit_local(&mut self, l:@ast::Local, e:CheckLoanCtxt) {
+ check_loans_in_local(self, l, e);
+ }
+ fn visit_block(&mut self, b:&ast::Block, e:CheckLoanCtxt) {
+ check_loans_in_block(self, b, e);
+ }
+ fn visit_pat(&mut self, p:@ast::pat, e:CheckLoanCtxt) {
+ check_loans_in_pat(self, p, e);
+ }
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:CheckLoanCtxt) {
+ check_loans_in_fn(self, fk, fd, b, s, n, e);
+ }
+}
+
pub fn check_loans(bccx: @BorrowckCtxt,
dfcx_loans: &LoanDataFlow,
move_data: move_data::FlowedMoveData,
reported: @mut HashSet::new(),
};
- let vt = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: check_loans_in_expr,
- visit_local: check_loans_in_local,
- visit_block: check_loans_in_block,
- visit_pat: check_loans_in_pat,
- visit_fn: check_loans_in_fn,
- .. *oldvisit::default_visitor()
- });
- (vt.visit_block)(body, (clcx, vt));
+ let mut vt = CheckLoanVisitor;
+ vt.visit_block(body, clcx);
}
enum MoveError {
}
}
-fn check_loans_in_fn<'a>(fk: &oldvisit::fn_kind,
+fn check_loans_in_fn<'a>(visitor: &mut CheckLoanVisitor,
+ fk: &visit::fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
sp: span,
id: ast::NodeId,
- (this, visitor): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>)) {
+ this: CheckLoanCtxt<'a>) {
match *fk {
- oldvisit::fk_item_fn(*) |
- oldvisit::fk_method(*) => {
+ visit::fk_item_fn(*) |
+ visit::fk_method(*) => {
// Don't process nested items.
return;
}
- oldvisit::fk_anon(*) |
- oldvisit::fk_fn_block(*) => {
+ visit::fk_anon(*) |
+ visit::fk_fn_block(*) => {
check_captured_variables(this, id, sp);
}
}
- oldvisit::visit_fn(fk, decl, body, sp, id, (this, visitor));
+ visit::walk_fn(visitor, fk, decl, body, sp, id, this);
fn check_captured_variables(this: CheckLoanCtxt,
closure_id: ast::NodeId,
}
}
-fn check_loans_in_local<'a>(local: @ast::Local,
- (this, vt): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>)) {
- oldvisit::visit_local(local, (this, vt));
+fn check_loans_in_local<'a>(vt: &mut CheckLoanVisitor,
+ local: @ast::Local,
+ this: CheckLoanCtxt<'a>) {
+ visit::walk_local(vt, local, this);
}
-fn check_loans_in_expr<'a>(expr: @ast::expr,
- (this, vt): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>)) {
- oldvisit::visit_expr(expr, (this, vt));
+fn check_loans_in_expr<'a>(vt: &mut CheckLoanVisitor,
+ expr: @ast::expr,
+ this: CheckLoanCtxt<'a>) {
+ visit::walk_expr(vt, expr, this);
debug!("check_loans_in_expr(expr=%s)",
expr.repr(this.tcx()));
}
}
-fn check_loans_in_pat<'a>(pat: @ast::pat,
- (this, vt): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>))
+fn check_loans_in_pat<'a>(vt: &mut CheckLoanVisitor,
+ pat: @ast::pat,
+ this: CheckLoanCtxt<'a>)
{
this.check_for_conflicting_loans(pat.id);
this.check_move_out_from_id(pat.id, pat.span);
- oldvisit::visit_pat(pat, (this, vt));
+ visit::walk_pat(vt, pat, this);
}
-fn check_loans_in_block<'a>(blk: &ast::Block,
- (this, vt): (CheckLoanCtxt<'a>,
- oldvisit::vt<CheckLoanCtxt<'a>>))
+fn check_loans_in_block<'a>(vt: &mut CheckLoanVisitor,
+ blk: &ast::Block,
+ this: CheckLoanCtxt<'a>)
{
- oldvisit::visit_block(blk, (this, vt));
+ visit::walk_block(vt, blk, this);
this.check_for_conflicting_loans(blk.id);
}
use syntax::ast_util::id_range;
use syntax::codemap::span;
use syntax::print::pprust;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
+use syntax::ast::{expr, fn_kind, fn_decl, Block, NodeId, stmt, pat, Local};
mod lifetime;
mod restrictions;
repeating_ids: ~[ast::NodeId]
}
+struct GatherLoanVisitor;
+
+impl visit::Visitor<@mut GatherLoanCtxt> for GatherLoanVisitor {
+ fn visit_expr(&mut self, ex:@expr, e:@mut GatherLoanCtxt) {
+ gather_loans_in_expr(self, ex, e);
+ }
+ fn visit_block(&mut self, b:&Block, e:@mut GatherLoanCtxt) {
+ gather_loans_in_block(self, b, e);
+ }
+ fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, b:&Block,
+ s:span, n:NodeId, e:@mut GatherLoanCtxt) {
+ gather_loans_in_fn(self, fk, fd, b, s, n, e);
+ }
+ fn visit_stmt(&mut self, s:@stmt, e:@mut GatherLoanCtxt) {
+ add_stmt_to_map(self, s, e);
+ }
+ fn visit_pat(&mut self, p:@pat, e:@mut GatherLoanCtxt) {
+ add_pat_to_id_range(self, p, e);
+ }
+ fn visit_local(&mut self, l:@Local, e:@mut GatherLoanCtxt) {
+ gather_loans_in_local(self, l, e);
+ }
+}
+
pub fn gather_loans(bccx: @BorrowckCtxt,
decl: &ast::fn_decl,
body: &ast::Block)
move_data: @mut MoveData::new()
};
glcx.gather_fn_arg_patterns(decl, body);
- let v = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: gather_loans_in_expr,
- visit_block: gather_loans_in_block,
- visit_fn: gather_loans_in_fn,
- visit_stmt: add_stmt_to_map,
- visit_pat: add_pat_to_id_range,
- visit_local: gather_loans_in_local,
- .. *oldvisit::default_visitor()
- });
- (v.visit_block)(body, (glcx, v));
+
+ let mut v = GatherLoanVisitor;
+ v.visit_block(body, glcx);
return (glcx.id_range, glcx.all_loans, glcx.move_data);
}
-fn add_pat_to_id_range(p: @ast::pat,
- (this, v): (@mut GatherLoanCtxt,
- oldvisit::vt<@mut GatherLoanCtxt>)) {
+fn add_pat_to_id_range(v: &mut GatherLoanVisitor,
+ p: @ast::pat,
+ this: @mut GatherLoanCtxt) {
// NB: This visitor function just adds the pat ids into the id
// range. We gather loans that occur in patterns using the
// `gather_pat()` method below. Eventually these two should be
// brought together.
this.id_range.add(p.id);
- oldvisit::visit_pat(p, (this, v));
+ visit::walk_pat(v, p, this);
}
-fn gather_loans_in_fn(fk: &oldvisit::fn_kind,
+fn gather_loans_in_fn(v: &mut GatherLoanVisitor,
+ fk: &fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
sp: span,
id: ast::NodeId,
- (this, v): (@mut GatherLoanCtxt,
- oldvisit::vt<@mut GatherLoanCtxt>)) {
+ this: @mut GatherLoanCtxt) {
match fk {
// Do not visit items here, the outer loop in borrowck/mod
// will visit them for us in turn.
- &oldvisit::fk_item_fn(*) | &oldvisit::fk_method(*) => {
+ &visit::fk_item_fn(*) | &visit::fk_method(*) => {
return;
}
// Visit closures as part of the containing item.
- &oldvisit::fk_anon(*) | &oldvisit::fk_fn_block(*) => {
+ &visit::fk_anon(*) | &visit::fk_fn_block(*) => {
this.push_repeating_id(body.id);
- oldvisit::visit_fn(fk, decl, body, sp, id, (this, v));
+ visit::walk_fn(v, fk, decl, body, sp, id, this);
this.pop_repeating_id(body.id);
this.gather_fn_arg_patterns(decl, body);
}
}
}
-fn gather_loans_in_block(blk: &ast::Block,
- (this, vt): (@mut GatherLoanCtxt,
- oldvisit::vt<@mut GatherLoanCtxt>)) {
+fn gather_loans_in_block(v: &mut GatherLoanVisitor,
+ blk: &ast::Block,
+ this: @mut GatherLoanCtxt) {
this.id_range.add(blk.id);
- oldvisit::visit_block(blk, (this, vt));
+ visit::walk_block(v, blk, this);
}
-fn gather_loans_in_local(local: @ast::Local,
- (this, vt): (@mut GatherLoanCtxt,
- oldvisit::vt<@mut GatherLoanCtxt>)) {
+fn gather_loans_in_local(v: &mut GatherLoanVisitor,
+ local: @ast::Local,
+ this: @mut GatherLoanCtxt) {
match local.init {
None => {
// Variable declarations without initializers are considered "moves":
}
}
- oldvisit::visit_local(local, (this, vt));
+ visit::walk_local(v, local, this);
}
-fn gather_loans_in_expr(ex: @ast::expr,
- (this, vt): (@mut GatherLoanCtxt,
- oldvisit::vt<@mut GatherLoanCtxt>)) {
+
+fn gather_loans_in_expr(v: &mut GatherLoanVisitor,
+ ex: @ast::expr,
+ this: @mut GatherLoanCtxt) {
let bccx = this.bccx;
let tcx = bccx.tcx;
// for the lifetime `scope_r` of the resulting ptr:
let scope_r = ty_region(tcx, ex.span, ty::expr_ty(tcx, ex));
this.guarantee_valid(ex.id, ex.span, base_cmt, mutbl, scope_r);
- oldvisit::visit_expr(ex, (this, vt));
+ visit::walk_expr(v, ex, this);
}
ast::expr_assign(l, _) | ast::expr_assign_op(_, _, l, _) => {
// with moves etc, just ignore.
}
}
- oldvisit::visit_expr(ex, (this, vt));
+ visit::walk_expr(v, ex, this);
}
ast::expr_match(ex_v, ref arms) => {
this.gather_pat(cmt, *pat, Some((arm.body.id, ex.id)));
}
}
- oldvisit::visit_expr(ex, (this, vt));
+ visit::walk_expr(v, ex, this);
}
ast::expr_index(_, _, arg) |
let scope_r = ty::re_scope(ex.id);
let arg_cmt = this.bccx.cat_expr(arg);
this.guarantee_valid(arg.id, arg.span, arg_cmt, m_imm, scope_r);
- oldvisit::visit_expr(ex, (this, vt));
+ visit::walk_expr(v, ex, this);
}
// see explanation attached to the `root_ub` field:
ast::expr_while(cond, ref body) => {
// during the condition, can only root for the condition
this.push_repeating_id(cond.id);
- (vt.visit_expr)(cond, (this, vt));
+ v.visit_expr(cond, this);
this.pop_repeating_id(cond.id);
// during body, can only root for the body
this.push_repeating_id(body.id);
- (vt.visit_block)(body, (this, vt));
+ v.visit_block(body, this);
this.pop_repeating_id(body.id);
}
// see explanation attached to the `root_ub` field:
ast::expr_loop(ref body, _) => {
this.push_repeating_id(body.id);
- oldvisit::visit_expr(ex, (this, vt));
+ visit::walk_expr(v, ex, this);
this.pop_repeating_id(body.id);
}
ast::expr_fn_block(*) => {
gather_moves::gather_captures(this.bccx, this.move_data, ex);
- oldvisit::visit_expr(ex, (this, vt));
+ visit::walk_expr(v, ex, this);
}
_ => {
- oldvisit::visit_expr(ex, (this, vt));
+ visit::walk_expr(v, ex, this);
}
}
}
// Setting up info that preserve needs.
// This is just the most convenient place to do it.
-fn add_stmt_to_map(stmt: @ast::stmt,
- (this, vt): (@mut GatherLoanCtxt,
- oldvisit::vt<@mut GatherLoanCtxt>)) {
+fn add_stmt_to_map(v: &mut GatherLoanVisitor,
+ stmt: @ast::stmt,
+ this: @mut GatherLoanCtxt) {
match stmt.node {
ast::stmt_expr(_, id) | ast::stmt_semi(_, id) => {
this.bccx.stmt_map.insert(id);
}
_ => ()
}
- oldvisit::visit_stmt(stmt, (this, vt));
+ visit::walk_stmt(v, stmt, this);
}
use std::result::{Result};
use syntax::ast;
use syntax::ast_map;
-use syntax::oldvisit;
use syntax::codemap::span;
use syntax::parse::token;
+use syntax::visit;
+use syntax::visit::{Visitor,fn_kind};
+use syntax::ast::{fn_decl,Block,NodeId};
macro_rules! if_ok(
($inp: expr) => (
pub type LoanDataFlow = DataFlowContext<LoanDataFlowOperator>;
+struct BorrowckVisitor;
+
+impl Visitor<@BorrowckCtxt> for BorrowckVisitor {
+ fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl,
+ b:&Block, s:span, n:NodeId, e:@BorrowckCtxt) {
+ borrowck_fn(self, fk, fd, b, s, n, e);
+ }
+}
+
pub fn check_crate(
tcx: ty::ctxt,
method_map: typeck::method_map,
}
};
- let v = oldvisit::mk_vt(@oldvisit::Visitor {visit_fn: borrowck_fn,
- ..*oldvisit::default_visitor()});
- oldvisit::visit_crate(crate, (bccx, v));
+ let mut v = BorrowckVisitor;
+ visit::walk_crate(&mut v, crate, bccx);
if tcx.sess.borrowck_stats() {
io::println("--- borrowck stats ---");
}
}
-fn borrowck_fn(fk: &oldvisit::fn_kind,
+fn borrowck_fn(v: &mut BorrowckVisitor,
+ fk: &visit::fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
sp: span,
id: ast::NodeId,
- (this, v): (@BorrowckCtxt,
- oldvisit::vt<@BorrowckCtxt>)) {
+ this: @BorrowckCtxt) {
match fk {
- &oldvisit::fk_anon(*) |
- &oldvisit::fk_fn_block(*) => {
+ &visit::fk_anon(*) |
+ &visit::fk_fn_block(*) => {
// Closures are checked as part of their containing fn item.
}
- &oldvisit::fk_item_fn(*) |
- &oldvisit::fk_method(*) => {
+ &visit::fk_item_fn(*) |
+ &visit::fk_method(*) => {
debug!("borrowck_fn(id=%?)", id);
// Check the body of fn items.
}
}
- oldvisit::visit_fn(fk, decl, body, sp, id, (this, v));
+ visit::walk_fn(v, fk, decl, body, sp, id, this);
}
// ----------------------------------------------------------------------
use syntax::ast::*;
use syntax::codemap;
-use syntax::{oldvisit, ast_util, ast_map};
+use syntax::{ast_util, ast_map};
+use syntax::visit::Visitor;
+use syntax::visit;
+
+struct CheckCrateVisitor {
+ sess: Session,
+ ast_map: ast_map::map,
+ def_map: resolve::DefMap,
+ method_map: typeck::method_map,
+ tcx: ty::ctxt,
+}
+
+impl Visitor<bool> for CheckCrateVisitor {
+ fn visit_item(&mut self, i:@item, env:bool) {
+ check_item(self, self.sess, self.ast_map, self.def_map, i, env);
+ }
+ fn visit_pat(&mut self, p:@pat, env:bool) {
+ check_pat(self, p, env);
+ }
+ fn visit_expr(&mut self, ex:@expr, env:bool) {
+ check_expr(self, self.sess, self.def_map, self.method_map,
+ self.tcx, ex, env);
+ }
+}
pub fn check_crate(sess: Session,
crate: &Crate,
def_map: resolve::DefMap,
method_map: typeck::method_map,
tcx: ty::ctxt) {
- oldvisit::visit_crate(crate, (false, oldvisit::mk_vt(@oldvisit::Visitor {
- visit_item: |a,b| check_item(sess, ast_map, def_map, a, b),
- visit_pat: check_pat,
- visit_expr: |a,b|
- check_expr(sess, def_map, method_map, tcx, a, b),
- .. *oldvisit::default_visitor()
- })));
+ let mut v = CheckCrateVisitor {
+ sess: sess,
+ ast_map: ast_map,
+ def_map: def_map,
+ method_map: method_map,
+ tcx: tcx,
+ };
+ visit::walk_crate(&mut v, crate, false);
sess.abort_if_errors();
}
-pub fn check_item(sess: Session,
+pub fn check_item(v: &mut CheckCrateVisitor,
+ sess: Session,
ast_map: ast_map::map,
def_map: resolve::DefMap,
it: @item,
- (_is_const, v): (bool,
- oldvisit::vt<bool>)) {
+ _is_const: bool) {
match it.node {
item_static(_, _, ex) => {
- (v.visit_expr)(ex, (true, v));
+ v.visit_expr(ex, true);
check_item_recursion(sess, ast_map, def_map, it);
}
item_enum(ref enum_definition, _) => {
for var in (*enum_definition).variants.iter() {
for ex in var.node.disr_expr.iter() {
- (v.visit_expr)(*ex, (true, v));
+ v.visit_expr(*ex, true);
}
}
}
- _ => oldvisit::visit_item(it, (false, v))
+ _ => visit::walk_item(v, it, false)
}
}
-pub fn check_pat(p: @pat, (_is_const, v): (bool, oldvisit::vt<bool>)) {
+pub fn check_pat(v: &mut CheckCrateVisitor, p: @pat, _is_const: bool) {
fn is_str(e: @expr) -> bool {
match e.node {
expr_vstore(
}
match p.node {
// Let through plain ~-string literals here
- pat_lit(a) => if !is_str(a) { (v.visit_expr)(a, (true, v)); },
+ pat_lit(a) => if !is_str(a) { v.visit_expr(a, true); },
pat_range(a, b) => {
- if !is_str(a) { (v.visit_expr)(a, (true, v)); }
- if !is_str(b) { (v.visit_expr)(b, (true, v)); }
+ if !is_str(a) { v.visit_expr(a, true); }
+ if !is_str(b) { v.visit_expr(b, true); }
}
- _ => oldvisit::visit_pat(p, (false, v))
+ _ => visit::walk_pat(v, p, false)
}
}
-pub fn check_expr(sess: Session,
+pub fn check_expr(v: &mut CheckCrateVisitor,
+ sess: Session,
def_map: resolve::DefMap,
method_map: typeck::method_map,
tcx: ty::ctxt,
e: @expr,
- (is_const, v): (bool,
- oldvisit::vt<bool>)) {
+ is_const: bool) {
if is_const {
match e.node {
expr_unary(_, deref, _) => { }
}
}
}
- expr_paren(e) => { check_expr(sess, def_map, method_map,
- tcx, e, (is_const, v)); }
+ expr_paren(e) => { check_expr(v, sess, def_map, method_map,
+ tcx, e, is_const); }
expr_vstore(_, expr_vstore_slice) |
expr_vec(_, m_imm) |
expr_addr_of(m_imm, _) |
expr_field(*) |
expr_index(*) |
expr_tup(*) |
+ expr_repeat(*) |
expr_struct(*) => { }
expr_addr_of(*) => {
sess.span_err(
}
_ => ()
}
- oldvisit::visit_expr(e, (is_const, v));
+ visit::walk_expr(v, e, is_const);
}
#[deriving(Clone)]
idstack: @mut ~[NodeId]
}
+struct CheckItemRecursionVisitor;
+
// Make sure a const item doesn't recursively refer to itself
// FIXME: Should use the dependency graph when it's available (#1356)
pub fn check_item_recursion(sess: Session,
idstack: @mut ~[]
};
- let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_item: visit_item,
- visit_expr: visit_expr,
- .. *oldvisit::default_visitor()
- });
- (visitor.visit_item)(it, (env, visitor));
+ let mut visitor = CheckItemRecursionVisitor;
+ visitor.visit_item(it, env);
+}
- fn visit_item(it: @item, (env, v): (env, oldvisit::vt<env>)) {
+impl Visitor<env> for CheckItemRecursionVisitor {
+ fn visit_item(&mut self, it: @item, env: env) {
if env.idstack.iter().any(|x| x == &(it.id)) {
env.sess.span_fatal(env.root_it.span, "recursive constant");
}
env.idstack.push(it.id);
- oldvisit::visit_item(it, (env, v));
+ visit::walk_item(self, it, env);
env.idstack.pop();
}
- fn visit_expr(e: @expr, (env, v): (env, oldvisit::vt<env>)) {
+ fn visit_expr(&mut self, e: @expr, env: env) {
match e.node {
expr_path(*) => match env.def_map.find(&e.id) {
Some(&def_static(def_id, _)) if ast_util::is_local(def_id) =>
match env.ast_map.get_copy(&def_id.node) {
ast_map::node_item(it, _) => {
- (v.visit_item)(it, (env, v));
+ self.visit_item(it, env);
}
_ => fail!("const not bound to an item")
},
},
_ => ()
}
- oldvisit::visit_expr(e, (env, v));
+ visit::walk_expr(self, e, env);
}
}
use middle::ty;
use syntax::ast::*;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
#[deriving(Clone)]
pub struct Context {
can_ret: bool
}
+struct CheckLoopVisitor {
+ tcx: ty::ctxt,
+}
+
pub fn check_crate(tcx: ty::ctxt, crate: &Crate) {
- oldvisit::visit_crate(crate,
- (Context { in_loop: false, can_ret: true },
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_item: |i, (_cx, v)| {
- oldvisit::visit_item(i, (Context {
+ visit::walk_crate(&mut CheckLoopVisitor { tcx: tcx },
+ crate,
+ Context { in_loop: false, can_ret: true });
+}
+
+impl Visitor<Context> for CheckLoopVisitor {
+ fn visit_item(&mut self, i:@item, _cx:Context) {
+ visit::walk_item(self, i, Context {
in_loop: false,
can_ret: true
- }, v));
- },
- visit_expr: |e: @expr, (cx, v): (Context, oldvisit::vt<Context>)| {
+ });
+ }
+
+ fn visit_expr(&mut self, e:@expr, cx:Context) {
+
match e.node {
expr_while(e, ref b) => {
- (v.visit_expr)(e, (cx, v));
- (v.visit_block)(b, (Context { in_loop: true,.. cx }, v));
+ self.visit_expr(e, cx);
+ self.visit_block(b, Context { in_loop: true,.. cx });
}
expr_loop(ref b, _) => {
- (v.visit_block)(b, (Context { in_loop: true,.. cx }, v));
+ self.visit_block(b, Context { in_loop: true,.. cx });
}
expr_fn_block(_, ref b) => {
- (v.visit_block)(b, (Context {
- in_loop: false,
- can_ret: false
- }, v));
+ self.visit_block(b, Context { in_loop: false, can_ret: false });
}
expr_break(_) => {
if !cx.in_loop {
- tcx.sess.span_err(e.span, "`break` outside of loop");
+ self.tcx.sess.span_err(e.span, "`break` outside of loop");
}
}
expr_again(_) => {
if !cx.in_loop {
- tcx.sess.span_err(e.span, "`loop` outside of loop");
+ self.tcx.sess.span_err(e.span, "`loop` outside of loop");
}
}
expr_ret(oe) => {
if !cx.can_ret {
- tcx.sess.span_err(e.span, "`return` in block function");
+ self.tcx.sess.span_err(e.span, "`return` in block function");
}
- oldvisit::visit_expr_opt(oe, (cx, v));
+ visit::walk_expr_opt(self, oe, cx);
}
- _ => oldvisit::visit_expr(e, (cx, v))
+ _ => visit::walk_expr(self, e, cx)
}
- },
- .. *oldvisit::default_visitor()
- })));
+
+ }
}
use syntax::ast::*;
use syntax::ast_util::{unguarded_pat, walk_pat};
use syntax::codemap::{span, dummy_sp, spanned};
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::{Visitor,fn_kind};
pub struct MatchCheckCtxt {
tcx: ty::ctxt,
moves_map: moves::MovesMap
}
+struct CheckMatchVisitor {
+ cx: @MatchCheckCtxt
+}
+
+impl Visitor<()> for CheckMatchVisitor {
+ fn visit_expr(&mut self, ex:@expr, e:()) {
+ check_expr(self, self.cx, ex, e);
+ }
+ fn visit_local(&mut self, l:@Local, e:()) {
+ check_local(self, self.cx, l, e);
+ }
+ fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, b:&Block, s:span, n:NodeId, e:()) {
+ check_fn(self, self.cx, fk, fd, b, s, n, e);
+ }
+}
+
pub fn check_crate(tcx: ty::ctxt,
method_map: method_map,
moves_map: moves::MovesMap,
let cx = @MatchCheckCtxt {tcx: tcx,
method_map: method_map,
moves_map: moves_map};
- oldvisit::visit_crate(crate, ((), oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: |a,b| check_expr(cx, a, b),
- visit_local: |a,b| check_local(cx, a, b),
- visit_fn: |kind, decl, body, sp, id, (e, v)|
- check_fn(cx, kind, decl, body, sp, id, (e, v)),
- .. *oldvisit::default_visitor::<()>()
- })));
+ let mut v = CheckMatchVisitor { cx: cx };
+
+ visit::walk_crate(&mut v, crate, ());
+
tcx.sess.abort_if_errors();
}
-pub fn check_expr(cx: @MatchCheckCtxt,
+pub fn check_expr(v: &mut CheckMatchVisitor,
+ cx: @MatchCheckCtxt,
ex: @expr,
- (s, v): ((), oldvisit::vt<()>)) {
- oldvisit::visit_expr(ex, (s, v));
+ s: ()) {
+ visit::walk_expr(v, ex, s);
match ex.node {
expr_match(scrut, ref arms) => {
// First, check legality of move bindings.
else { None }
}
-pub fn check_local(cx: &MatchCheckCtxt,
+pub fn check_local(v: &mut CheckMatchVisitor,
+ cx: &MatchCheckCtxt,
loc: @Local,
- (s, v): ((), oldvisit::vt<()>)) {
- oldvisit::visit_local(loc, (s, v));
+ s: ()) {
+ visit::walk_local(v, loc, s);
if is_refutable(cx, loc.pat) {
cx.tcx.sess.span_err(loc.pat.span,
"refutable pattern in local binding");
check_legality_of_move_bindings(cx, false, [ loc.pat ]);
}
-pub fn check_fn(cx: &MatchCheckCtxt,
- kind: &oldvisit::fn_kind,
+pub fn check_fn(v: &mut CheckMatchVisitor,
+ cx: &MatchCheckCtxt,
+ kind: &visit::fn_kind,
decl: &fn_decl,
body: &Block,
sp: span,
id: NodeId,
- (s, v): ((),
- oldvisit::vt<()>)) {
- oldvisit::visit_fn(kind, decl, body, sp, id, (s, v));
+ s: ()) {
+ visit::walk_fn(v, kind, decl, body, sp, id, s);
for input in decl.inputs.iter() {
if is_refutable(cx, input.pat) {
cx.tcx.sess.span_err(input.pat.span,
let check_move: &fn(@pat, Option<@pat>) = |p, sub| {
// check legality of moving out of the enum
- if sub.is_some() {
+
+ // x @ Foo(*) is legal, but x @ Foo(y) isn't.
+ if sub.map_move_default(false, |p| pat_contains_bindings(def_map, p)) {
tcx.sess.span_err(
p.span,
"cannot bind by-move with sub-bindings");
use middle::ty;
use middle;
-use syntax::{ast, ast_map, ast_util, oldvisit};
+use syntax::{ast, ast_map, ast_util};
+use syntax::visit;
+use syntax::visit::Visitor;
use syntax::ast::*;
use std::float;
lookup_constness(tcx, e)
}
+ ast::expr_repeat(*) => general_const,
+
_ => non_const
};
tcx.ccache.insert(did, cn);
}
}
+struct ConstEvalVisitor { tcx: ty::ctxt }
+
+impl Visitor<()> for ConstEvalVisitor {
+ fn visit_expr_post(&mut self, e:@expr, _:()) {
+ classify(e, self.tcx);
+ }
+}
+
pub fn process_crate(crate: &ast::Crate,
tcx: ty::ctxt) {
- let v = oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
- visit_expr_post: |e| { classify(e, tcx); },
- .. *oldvisit::default_simple_visitor()
- });
- oldvisit::visit_crate(crate, ((), v));
+ let mut v = ConstEvalVisitor { tcx: tcx };
+ visit::walk_crate(&mut v, crate, ());
tcx.sess.abort_if_errors();
}
use syntax::ast::{expr_unary, unsafe_fn, expr_path};
use syntax::ast;
use syntax::codemap::span;
-use syntax::oldvisit::{fk_item_fn, fk_method};
-use syntax::oldvisit;
+use syntax::visit::{fk_item_fn, fk_method};
+use syntax::visit;
+use syntax::visit::{Visitor,fn_kind};
+use syntax::ast::{fn_decl,Block,NodeId,expr};
#[deriving(Eq)]
enum UnsafeContext {
}
}
-pub fn check_crate(tcx: ty::ctxt,
- method_map: method_map,
- crate: &ast::Crate) {
- let context = @mut Context {
- method_map: method_map,
- unsafe_context: SafeContext,
- };
+struct EffectCheckVisitor {
+ tcx: ty::ctxt,
+ context: @mut Context,
+}
- let require_unsafe: @fn(span: span,
- description: &str) = |span, description| {
- match context.unsafe_context {
+impl EffectCheckVisitor {
+ fn require_unsafe(&mut self, span: span, description: &str) {
+ match self.context.unsafe_context {
SafeContext => {
// Report an error.
- tcx.sess.span_err(span,
+ self.tcx.sess.span_err(span,
fmt!("%s requires unsafe function or block",
description))
}
UnsafeBlock(block_id) => {
// OK, but record this.
debug!("effect: recording unsafe block as used: %?", block_id);
- let _ = tcx.used_unsafe.insert(block_id);
+ let _ = self.tcx.used_unsafe.insert(block_id);
}
UnsafeFn => {}
}
- };
+ }
+}
+
+impl Visitor<()> for EffectCheckVisitor {
+ fn visit_fn(&mut self, fn_kind:&fn_kind, fn_decl:&fn_decl,
+ block:&Block, span:span, node_id:NodeId, _:()) {
- let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_fn: |fn_kind, fn_decl, block, span, node_id, (_, visitor)| {
let (is_item_fn, is_unsafe_fn) = match *fn_kind {
fk_item_fn(_, _, purity, _) => (true, purity == unsafe_fn),
fk_method(_, _, method) => (true, method.purity == unsafe_fn),
_ => (false, false),
};
- let old_unsafe_context = context.unsafe_context;
+ let old_unsafe_context = self.context.unsafe_context;
if is_unsafe_fn {
- context.unsafe_context = UnsafeFn
+ self.context.unsafe_context = UnsafeFn
} else if is_item_fn {
- context.unsafe_context = SafeContext
+ self.context.unsafe_context = SafeContext
}
- oldvisit::visit_fn(fn_kind,
+ visit::walk_fn(self,
+ fn_kind,
fn_decl,
block,
span,
node_id,
- ((),
- visitor));
+ ());
+
+ self.context.unsafe_context = old_unsafe_context
+ }
- context.unsafe_context = old_unsafe_context
- },
+ fn visit_block(&mut self, block:&Block, _:()) {
- visit_block: |block, (_, visitor)| {
- let old_unsafe_context = context.unsafe_context;
+ let old_unsafe_context = self.context.unsafe_context;
if block.rules == ast::UnsafeBlock &&
- context.unsafe_context == SafeContext {
- context.unsafe_context = UnsafeBlock(block.id)
+ self.context.unsafe_context == SafeContext {
+ self.context.unsafe_context = UnsafeBlock(block.id)
}
- oldvisit::visit_block(block, ((), visitor));
+ visit::walk_block(self, block, ());
- context.unsafe_context = old_unsafe_context
- },
+ self.context.unsafe_context = old_unsafe_context
+ }
+
+ fn visit_expr(&mut self, expr:@expr, _:()) {
- visit_expr: |expr, (_, visitor)| {
match expr.node {
expr_method_call(callee_id, _, _, _, _, _) => {
- let base_type = ty::node_id_to_type(tcx, callee_id);
+ let base_type = ty::node_id_to_type(self.tcx, callee_id);
debug!("effect: method call case, base type is %s",
- ppaux::ty_to_str(tcx, base_type));
+ ppaux::ty_to_str(self.tcx, base_type));
if type_is_unsafe_function(base_type) {
- require_unsafe(expr.span,
+ self.require_unsafe(expr.span,
"invocation of unsafe method")
}
}
expr_call(base, _, _) => {
- let base_type = ty::node_id_to_type(tcx, base.id);
+ let base_type = ty::node_id_to_type(self.tcx, base.id);
debug!("effect: call case, base type is %s",
- ppaux::ty_to_str(tcx, base_type));
+ ppaux::ty_to_str(self.tcx, base_type));
if type_is_unsafe_function(base_type) {
- require_unsafe(expr.span, "call to unsafe function")
+ self.require_unsafe(expr.span, "call to unsafe function")
}
}
expr_unary(_, deref, base) => {
- let base_type = ty::node_id_to_type(tcx, base.id);
+ let base_type = ty::node_id_to_type(self.tcx, base.id);
debug!("effect: unary case, base type is %s",
- ppaux::ty_to_str(tcx, base_type));
+ ppaux::ty_to_str(self.tcx, base_type));
match ty::get(base_type).sty {
ty_ptr(_) => {
- require_unsafe(expr.span,
+ self.require_unsafe(expr.span,
"dereference of unsafe pointer")
}
_ => {}
}
}
expr_inline_asm(*) => {
- require_unsafe(expr.span, "use of inline assembly")
+ self.require_unsafe(expr.span, "use of inline assembly")
}
expr_path(*) => {
- match ty::resolve_expr(tcx, expr) {
+ match ty::resolve_expr(self.tcx, expr) {
ast::def_static(_, true) => {
- require_unsafe(expr.span, "use of mutable static")
+ self.require_unsafe(expr.span, "use of mutable static")
}
_ => {}
}
_ => {}
}
- oldvisit::visit_expr(expr, ((), visitor))
- },
+ visit::walk_expr(self, expr, ());
+ }
+}
- .. *oldvisit::default_visitor()
- });
+pub fn check_crate(tcx: ty::ctxt,
+ method_map: method_map,
+ crate: &ast::Crate) {
+ let context = @mut Context {
+ method_map: method_map,
+ unsafe_context: SafeContext,
+ };
+
+ let mut visitor = EffectCheckVisitor {
+ tcx: tcx,
+ context: context,
+ };
- oldvisit::visit_crate(crate, ((), visitor))
+ visit::walk_crate(&mut visitor, crate, ());
}
use syntax::ast_map;
use syntax::attr;
use syntax::codemap::span;
-use syntax::oldvisit::{default_visitor, mk_vt, vt, Visitor, visit_crate};
-use syntax::oldvisit::{visit_item};
use syntax::parse::token::special_idents;
+use syntax::visit;
+use syntax::visit::Visitor;
use std::util;
struct EntryContext {
non_main_fns: ~[(NodeId, span)],
}
-type EntryVisitor = vt<@mut EntryContext>;
+struct EntryVisitor;
+
+impl Visitor<@mut EntryContext> for EntryVisitor {
+ fn visit_item(&mut self, item:@item, ctxt:@mut EntryContext) {
+ find_item(item, ctxt, self);
+ }
+}
pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map) {
non_main_fns: ~[],
};
- visit_crate(crate, (ctxt, mk_vt(@Visitor {
- visit_item: |item, (ctxt, visitor)| find_item(item, ctxt, visitor),
- .. *default_visitor()
- })));
+ let mut v = EntryVisitor;
+
+ visit::walk_crate(&mut v, crate, ctxt);
configure_main(ctxt);
}
-fn find_item(item: @item, ctxt: @mut EntryContext, visitor: EntryVisitor) {
+fn find_item(item: @item, ctxt: @mut EntryContext, visitor: &mut EntryVisitor) {
match item.node {
item_fn(*) => {
if item.ident == special_idents::main {
_ => ()
}
- visit_item(item, (ctxt, visitor));
+ visit::walk_item(visitor, item, ctxt);
}
fn configure_main(ctxt: @mut EntryContext) {
use std::hashmap::HashMap;
use syntax::codemap::span;
-use syntax::{ast, ast_util, oldvisit};
+use syntax::{ast, ast_util};
+use syntax::visit;
+use syntax::visit::Visitor;
+use syntax::ast::{item};
// A vector of defs representing the free variables referred to in a function.
// (The def_upvar will already have been stripped).
pub type freevar_info = @~[@freevar_entry];
pub type freevar_map = @mut HashMap<ast::NodeId, freevar_info>;
-// Searches through part of the AST for all references to locals or
-// upvars in this frame and returns the list of definition IDs thus found.
-// Since we want to be able to collect upvars in some arbitrary piece
-// of the AST, we take a walker function that we invoke with a visitor
-// in order to start the search.
-fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
- -> freevar_info {
- let seen = @mut HashMap::new();
- let refs = @mut ~[];
+struct CollectFreevarsVisitor {
+ seen: @mut HashMap<ast::NodeId, ()>,
+ refs: @mut ~[@freevar_entry],
+ def_map: resolve::DefMap,
+}
+
+impl Visitor<int> for CollectFreevarsVisitor {
- fn ignore_item(_i: @ast::item, (_depth, _v): (int, oldvisit::vt<int>)) { }
+ fn visit_item(&mut self, _:@item, _:int) {
+ // ignore_item
+ }
+
+ fn visit_expr(&mut self, expr:@ast::expr, depth:int) {
- let walk_expr: @fn(expr: @ast::expr, (int, oldvisit::vt<int>)) =
- |expr, (depth, v)| {
match expr.node {
ast::expr_fn_block(*) => {
- oldvisit::visit_expr(expr, (depth + 1, v))
+ visit::walk_expr(self, expr, depth + 1)
}
ast::expr_path(*) | ast::expr_self => {
let mut i = 0;
- match def_map.find(&expr.id) {
+ match self.def_map.find(&expr.id) {
None => fail!("path not found"),
Some(&df) => {
let mut def = df;
}
if i == depth { // Made it to end of loop
let dnum = ast_util::def_id_of_def(def).node;
- if !seen.contains_key(&dnum) {
- refs.push(@freevar_entry {
+ if !self.seen.contains_key(&dnum) {
+ self.refs.push(@freevar_entry {
def: def,
span: expr.span,
});
- seen.insert(dnum, ());
+ self.seen.insert(dnum, ());
}
}
}
}
}
- _ => oldvisit::visit_expr(expr, (depth, v))
+ _ => visit::walk_expr(self, expr, depth)
}
- };
+ }
- let v = oldvisit::mk_vt(@oldvisit::Visitor {visit_item: ignore_item,
- visit_expr: walk_expr,
- .. *oldvisit::default_visitor()});
- (v.visit_block)(blk, (1, v));
+
+}
+
+// Searches through part of the AST for all references to locals or
+// upvars in this frame and returns the list of definition IDs thus found.
+// Since we want to be able to collect upvars in some arbitrary piece
+// of the AST, we take a walker function that we invoke with a visitor
+// in order to start the search.
+fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
+ -> freevar_info {
+ let seen = @mut HashMap::new();
+ let refs = @mut ~[];
+
+ let mut v = CollectFreevarsVisitor {
+ seen: seen,
+ refs: refs,
+ def_map: def_map,
+ };
+
+ v.visit_block(blk, 1);
return @(*refs).clone();
}
+struct AnnotateFreevarsVisitor {
+ def_map: resolve::DefMap,
+ freevars: freevar_map,
+}
+
+impl Visitor<()> for AnnotateFreevarsVisitor {
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ blk:&ast::Block, s:span, nid:ast::NodeId, _:()) {
+ let vars = collect_freevars(self.def_map, blk);
+ self.freevars.insert(nid, vars);
+ visit::walk_fn(self, fk, fd, blk, s, nid, ());
+ }
+}
+
// Build a map from every function and for-each body to a set of the
// freevars contained in it. The implementation is not particularly
// efficient as it fully recomputes the free variables at every
freevar_map {
let freevars = @mut HashMap::new();
- let walk_fn: @fn(&oldvisit::fn_kind,
- &ast::fn_decl,
- &ast::Block,
- span,
- ast::NodeId) = |_, _, blk, _, nid| {
- let vars = collect_freevars(def_map, blk);
- freevars.insert(nid, vars);
+ let mut visitor = AnnotateFreevarsVisitor {
+ def_map: def_map,
+ freevars: freevars,
};
-
- let visitor =
- oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
- visit_fn: walk_fn,
- .. *oldvisit::default_simple_visitor()});
- oldvisit::visit_crate(crate, ((), visitor));
+ visit::walk_crate(&mut visitor, crate, ());
return freevars;
}
use syntax::codemap::span;
use syntax::opt_vec;
use syntax::print::pprust::expr_to_str;
-use syntax::{oldvisit, ast_util};
+use syntax::{visit,ast_util};
+use syntax::visit::Visitor;
// Kind analysis pass.
//
current_item: NodeId
}
+struct KindAnalysisVisitor;
+
+impl Visitor<Context> for KindAnalysisVisitor {
+
+ fn visit_expr(&mut self, ex:@expr, e:Context) {
+ check_expr(self, ex, e);
+ }
+
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&fn_decl, b:&Block, s:span, n:NodeId, e:Context) {
+ check_fn(self, fk, fd, b, s, n, e);
+ }
+
+ fn visit_ty(&mut self, t:&Ty, e:Context) {
+ check_ty(self, t, e);
+ }
+ fn visit_item(&mut self, i:@item, e:Context) {
+ check_item(self, i, e);
+ }
+ fn visit_block(&mut self, b:&Block, e:Context) {
+ check_block(self, b, e);
+ }
+}
+
pub fn check_crate(tcx: ty::ctxt,
method_map: typeck::method_map,
crate: &Crate) {
method_map: method_map,
current_item: -1
};
- let visit = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: check_expr,
- visit_fn: check_fn,
- visit_ty: check_ty,
- visit_item: check_item,
- visit_block: check_block,
- .. *oldvisit::default_visitor()
- });
- oldvisit::visit_crate(crate, (ctx, visit));
+ let mut visit = KindAnalysisVisitor;
+ visit::walk_crate(&mut visit, crate, ctx);
tcx.sess.abort_if_errors();
}
}
}
-fn check_block(block: &Block,
- (cx, visitor): (Context, oldvisit::vt<Context>)) {
- oldvisit::visit_block(block, (cx, visitor));
+fn check_block(visitor: &mut KindAnalysisVisitor,
+ block: &Block,
+ cx: Context) {
+ visit::walk_block(visitor, block, cx);
}
-fn check_item(item: @item, (cx, visitor): (Context, oldvisit::vt<Context>)) {
+fn check_item(visitor: &mut KindAnalysisVisitor, item: @item, cx: Context) {
// If this is a destructor, check kinds.
if !attr::contains_name(item.attrs, "unsafe_destructor") {
match item.node {
}
let cx = Context { current_item: item.id, ..cx };
- oldvisit::visit_item(item, (cx, visitor));
+ visit::walk_item(visitor, item, cx);
}
// Yields the appropriate function to check the kind of closed over
// Check that the free variables used in a shared/sendable closure conform
// to the copy/move kind bounds. Then recursively check the function body.
fn check_fn(
- fk: &oldvisit::fn_kind,
+ v: &mut KindAnalysisVisitor,
+ fk: &visit::fn_kind,
decl: &fn_decl,
body: &Block,
sp: span,
fn_id: NodeId,
- (cx, v): (Context,
- oldvisit::vt<Context>)) {
+ cx: Context) {
// Check kinds on free variables:
do with_appropriate_checker(cx, fn_id) |chk| {
}
}
- oldvisit::visit_fn(fk, decl, body, sp, fn_id, (cx, v));
+ visit::walk_fn(v, fk, decl, body, sp, fn_id, cx);
}
-pub fn check_expr(e: @expr, (cx, v): (Context, oldvisit::vt<Context>)) {
+pub fn check_expr(v: &mut KindAnalysisVisitor, e: @expr, cx: Context) {
debug!("kind::check_expr(%s)", expr_to_str(e, cx.tcx.sess.intr()));
// Handle any kind bounds on type parameters
}
_ => {}
}
- oldvisit::visit_expr(e, (cx, v));
+ visit::walk_expr(v, e, cx);
}
-fn check_ty(aty: &Ty, (cx, v): (Context, oldvisit::vt<Context>)) {
+fn check_ty(v: &mut KindAnalysisVisitor, aty: &Ty, cx: Context) {
match aty.node {
ty_path(_, _, id) => {
let r = cx.tcx.node_type_substs.find(&id);
}
_ => {}
}
- oldvisit::visit_ty(aty, (cx, v));
+ visit::walk_ty(v, aty, cx);
}
// Calls "any_missing" if any bounds were missing.
use syntax::ast::{Crate, def_id, MetaItem};
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
-use syntax::oldvisit::{default_simple_visitor, mk_simple_visitor};
-use syntax::oldvisit::{SimpleVisitor, visit_crate};
+use syntax::ast::{item};
+use syntax::visit;
+use syntax::visit::Visitor;
use std::hashmap::HashMap;
StrEqFnLangItem, // 19
UniqStrEqFnLangItem, // 20
- AnnihilateFnLangItem, // 21
- LogTypeFnLangItem, // 22
- FailFnLangItem, // 23
- FailBoundsCheckFnLangItem, // 24
- ExchangeMallocFnLangItem, // 25
- ClosureExchangeMallocFnLangItem, // 26
- ExchangeFreeFnLangItem, // 27
- MallocFnLangItem, // 28
- FreeFnLangItem, // 29
- BorrowAsImmFnLangItem, // 30
- BorrowAsMutFnLangItem, // 31
- ReturnToMutFnLangItem, // 32
- CheckNotBorrowedFnLangItem, // 33
- StrDupUniqFnLangItem, // 34
- RecordBorrowFnLangItem, // 35
- UnrecordBorrowFnLangItem, // 36
-
- StartFnLangItem, // 37
-
- TyDescStructLangItem, // 38
- TyVisitorTraitLangItem, // 39
- OpaqueStructLangItem, // 40
+ LogTypeFnLangItem, // 21
+ FailFnLangItem, // 22
+ FailBoundsCheckFnLangItem, // 23
+ ExchangeMallocFnLangItem, // 24
+ ClosureExchangeMallocFnLangItem, // 25
+ ExchangeFreeFnLangItem, // 26
+ MallocFnLangItem, // 27
+ FreeFnLangItem, // 28
+ BorrowAsImmFnLangItem, // 29
+ BorrowAsMutFnLangItem, // 30
+ ReturnToMutFnLangItem, // 31
+ CheckNotBorrowedFnLangItem, // 32
+ StrDupUniqFnLangItem, // 33
+ RecordBorrowFnLangItem, // 34
+ UnrecordBorrowFnLangItem, // 35
+
+ StartFnLangItem, // 36
+
+ TyDescStructLangItem, // 37
+ TyVisitorTraitLangItem, // 38
+ OpaqueStructLangItem, // 39
}
pub struct LanguageItems {
19 => "str_eq",
20 => "uniq_str_eq",
- 21 => "annihilate",
- 22 => "log_type",
- 23 => "fail_",
- 24 => "fail_bounds_check",
- 25 => "exchange_malloc",
- 26 => "closure_exchange_malloc",
- 27 => "exchange_free",
- 28 => "malloc",
- 29 => "free",
- 30 => "borrow_as_imm",
- 31 => "borrow_as_mut",
- 32 => "return_to_mut",
- 33 => "check_not_borrowed",
- 34 => "strdup_uniq",
- 35 => "record_borrow",
- 36 => "unrecord_borrow",
-
- 37 => "start",
-
- 38 => "ty_desc",
- 39 => "ty_visitor",
- 40 => "opaque",
+ 21 => "log_type",
+ 22 => "fail_",
+ 23 => "fail_bounds_check",
+ 24 => "exchange_malloc",
+ 25 => "closure_exchange_malloc",
+ 26 => "exchange_free",
+ 27 => "malloc",
+ 28 => "free",
+ 29 => "borrow_as_imm",
+ 30 => "borrow_as_mut",
+ 31 => "return_to_mut",
+ 32 => "check_not_borrowed",
+ 33 => "strdup_uniq",
+ 34 => "record_borrow",
+ 35 => "unrecord_borrow",
+
+ 36 => "start",
+
+ 37 => "ty_desc",
+ 38 => "ty_visitor",
+ 39 => "opaque",
_ => "???"
}
pub fn uniq_str_eq_fn(&self) -> Option<def_id> {
self.items[UniqStrEqFnLangItem as uint]
}
- pub fn annihilate_fn(&self) -> Option<def_id> {
- self.items[AnnihilateFnLangItem as uint]
- }
pub fn log_type_fn(&self) -> Option<def_id> {
self.items[LogTypeFnLangItem as uint]
}
item_refs: HashMap<@str, uint>,
}
+struct LanguageItemVisitor<'self> {
+ this: *mut LanguageItemCollector<'self>,
+}
+
+impl<'self> Visitor<()> for LanguageItemVisitor<'self> {
+
+ fn visit_item(&mut self, item:@item, _:()) {
+
+ for attribute in item.attrs.iter() {
+ unsafe {
+ (*self.this).match_and_collect_meta_item(
+ local_def(item.id),
+ attribute.node.value
+ );
+ }
+ }
+
+ visit::walk_item(self, item, ());
+ }
+}
+
impl<'self> LanguageItemCollector<'self> {
pub fn new<'a>(crate: &'a Crate, session: Session)
-> LanguageItemCollector<'a> {
item_refs.insert(@"str_eq", StrEqFnLangItem as uint);
item_refs.insert(@"uniq_str_eq", UniqStrEqFnLangItem as uint);
- item_refs.insert(@"annihilate", AnnihilateFnLangItem as uint);
item_refs.insert(@"log_type", LogTypeFnLangItem as uint);
item_refs.insert(@"fail_", FailFnLangItem as uint);
item_refs.insert(@"fail_bounds_check",
pub fn collect_local_language_items(&mut self) {
let this: *mut LanguageItemCollector = &mut *self;
- visit_crate(self.crate, ((), mk_simple_visitor(@SimpleVisitor {
- visit_item: |item| {
- for attribute in item.attrs.iter() {
- unsafe {
- (*this).match_and_collect_meta_item(
- local_def(item.id),
- attribute.node.value
- );
- }
- }
- },
- .. *default_simple_visitor()
- })));
+ let mut v = LanguageItemVisitor { this: this };
+ visit::walk_crate(&mut v, self.crate, ());
}
pub fn collect_external_language_items(&mut self) {
use syntax::codemap::span;
use syntax::codemap;
use syntax::parse::token;
-use syntax::{ast, oldvisit, ast_util, visit};
+use syntax::{ast, ast_util, visit};
+use syntax::visit::Visitor;
/**
* A 'lint' check is a kind of miscellaneous constraint that a user _might_
#[deriving(Clone, Eq)]
pub enum lint {
ctypes,
+ cstack,
unused_imports,
unnecessary_qualification,
while_true,
default: warn
}),
+ ("cstack",
+ LintSpec {
+ lint: cstack,
+ desc: "only invoke foreign functions from fixedstacksegment fns",
+ default: deny
+ }),
+
("unused_imports",
LintSpec {
lint: unused_imports,
return map;
}
+trait OuterLint {
+ fn process_item(@mut self, i:@ast::item, e:@mut Context);
+ fn process_fn(@mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context);
+
+ // Returned inner variant will not proceed past subitems.
+ // Supports decomposition of simple lints into subitem-traversing
+ // outer lint visitor and subitem-stopping inner lint visitor.
+ fn inner_variant(@mut self) -> @mut InnerLint;
+}
+
+trait InnerLint {
+ fn descend_item(@mut self, i:&ast::item, e:@mut Context);
+ fn descend_crate(@mut self, crate: &ast::Crate, env: @mut Context);
+ fn descend_fn(@mut self,
+ function_kind: &visit::fn_kind,
+ function_declaration: &ast::fn_decl,
+ function_body: &ast::Block,
+ sp: span,
+ id: ast::NodeId,
+ env: @mut Context);
+}
+
+impl<V:Visitor<@mut Context>> InnerLint for V {
+ fn descend_item(@mut self, i:&ast::item, e:@mut Context) {
+ visit::walk_item(self, i, e);
+ }
+ fn descend_crate(@mut self, crate: &ast::Crate, env: @mut Context) {
+ visit::walk_crate(self, crate, env);
+ }
+ fn descend_fn(@mut self, fk: &visit::fn_kind, fd: &ast::fn_decl, fb: &ast::Block,
+ sp: span, id: ast::NodeId, env: @mut Context) {
+ visit::walk_fn(self, fk, fd, fb, sp, id, env);
+ }
+}
+
enum AnyVisitor {
// This is a pair so every visitor can visit every node. When a lint pass
// is registered, another visitor is created which stops at all items
// first element. This means that when visiting a node, the original
// recursive call can use the original visitor's method, although the
// recursing visitor supplied to the method is the item stopping visitor.
- OldVisitor(oldvisit::vt<@mut Context>, oldvisit::vt<@mut Context>),
+ OldVisitor(@mut OuterLint, @mut InnerLint),
NewVisitor(@mut visit::Visitor<()>),
}
+type VCObj = @mut Visitor<@mut Context>;
+
struct Context {
// All known lint modes (string versions)
dict: @LintDict,
}
}
- fn add_oldvisit_lint(&mut self, v: oldvisit::vt<@mut Context>) {
- self.visitors.push(OldVisitor(v, item_stopping_visitor(v)));
+ fn add_oldvisit_lint(&mut self, v: @mut OuterLint) {
+ self.visitors.push(OldVisitor(v, v.inner_variant()));
}
fn add_lint(&mut self, v: @mut visit::Visitor<()>) {
for visitor in self.visitors.iter() {
match *visitor {
OldVisitor(orig, stopping) => {
- (orig.visit_item)(it, (self, stopping));
+ orig.process_item(it, self);
+ stopping.descend_item(it, self);
}
NewVisitor(new_visitor) => {
+ let new_visitor = new_visitor;
new_visitor.visit_item(it, ());
}
}
for visitor in self.visitors.iter() {
match *visitor {
OldVisitor(_, stopping) => {
- oldvisit::visit_crate(c, (self, stopping))
+ stopping.descend_crate(c, self)
}
NewVisitor(new_visitor) => {
- visit::visit_crate(new_visitor, c, ())
+ let mut new_visitor = new_visitor;
+ visit::walk_crate(&mut new_visitor, c, ())
}
}
}
for visitor in self.visitors.iter() {
match *visitor {
OldVisitor(orig, stopping) => {
- let fk = oldvisit::fk_method(m.ident,
- &m.generics,
- m);
- (orig.visit_fn)(&fk,
- &m.decl,
- &m.body,
- m.span,
- m.id,
- (self, stopping));
+ let fk = visit::fk_method(m.ident, &m.generics, m);
+ orig.process_fn(&fk, &m.decl, &m.body, m.span, m.id, self);
+ stopping.descend_fn(&fk, &m.decl, &m.body, m.span, m.id, self);
}
NewVisitor(new_visitor) => {
let fk = visit::fk_method(m.ident,
&m.generics,
m);
+ let new_visitor = new_visitor;
new_visitor.visit_fn(&fk,
&m.decl,
&m.body,
true
}
-// Take a visitor, and modify it so that it will not proceed past subitems.
-// This is used to make the simple visitors used for the lint passes
-// not traverse into subitems, since that is handled by the outer
-// lint visitor.
-fn item_stopping_visitor<E>(outer: oldvisit::vt<E>) -> oldvisit::vt<E> {
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_item: |_i, (_e, _v)| { },
- visit_fn: |fk, fd, b, s, id, (e, v)| {
+trait SubitemStoppableVisitor : Visitor<@mut Context> {
+ fn is_running_on_items(&mut self) -> bool;
+
+ fn visit_item_action(&mut self, _i:@ast::item, _e:@mut Context) {
+ // fill in with particular action without recursion if desired
+ }
+
+ fn visit_fn_action(&mut self, _fk:&visit::fn_kind, _fd:&ast::fn_decl,
+ _b:&ast::Block, _s:span, _n:ast::NodeId, _e:@mut Context) {
+ // fill in with particular action without recursion if desired
+ }
+
+ // The two OVERRIDE methods:
+ //
+ // OVERRIDE_visit_item
+ // OVERRIDE_visit_fn
+ //
+ // *must* be included as initial reimplementations of the standard
+ // default behavior of visit_item and visit_fn for every impl of
+ // Visitor, in order to recreate the effect of having two variant
+ // Outer/Inner behaviors of lint visitors. (See earlier versions
+ // of this module to see what the original encoding was of this
+ // emulated behavior.)
+
+ fn OVERRIDE_visit_item(&mut self, i:@ast::item, e:@mut Context) {
+ if self.is_running_on_items() {
+ self.visit_item_action(i, e);
+ visit::walk_item(self, i, e);
+ }
+ }
+
+ fn OVERRIDE_visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ if self.is_running_on_items() {
+ self.visit_fn_action(fk, fd, b, s, n, e);
+ visit::walk_fn(self, fk, fd, b, s, n, e);
+ } else {
match *fk {
- oldvisit::fk_method(*) => {}
- _ => (outer.visit_fn)(fk, fd, b, s, id, (e, v))
+ visit::fk_method(*) => {}
+ _ => {
+ self.visit_fn_action(fk, fd, b, s, n, e);
+ visit::walk_fn(self, fk, fd, b, s, n, e);
+ }
}
- },
- .. **outer})
+ }
+ }
}
-fn lint_while_true() -> oldvisit::vt<@mut Context> {
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: |e,
- (cx, vt): (@mut Context, oldvisit::vt<@mut Context>)| {
+struct WhileTrueLintVisitor { stopping_on_items: bool }
+
+
+impl SubitemStoppableVisitor for WhileTrueLintVisitor {
+ fn is_running_on_items(&mut self) -> bool { !self.stopping_on_items }
+}
+
+impl Visitor<@mut Context> for WhileTrueLintVisitor {
+ fn visit_item(&mut self, i:@ast::item, e:@mut Context) {
+ self.OVERRIDE_visit_item(i, e);
+ }
+
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ self.OVERRIDE_visit_fn(fk, fd, b, s, n, e);
+ }
+
+ fn visit_expr(&mut self, e:@ast::expr, cx:@mut Context) {
+
match e.node {
ast::expr_while(cond, _) => {
match cond.node {
}
_ => ()
}
- oldvisit::visit_expr(e, (cx, vt));
- },
- .. *oldvisit::default_visitor()
- })
+ visit::walk_expr(self, e, cx);
+ }
+}
+
+macro_rules! outer_lint_boilerplate_impl(
+ ($Visitor:ident) =>
+ (
+ impl OuterLint for $Visitor {
+ fn process_item(@mut self, i:@ast::item, e:@mut Context) {
+ self.visit_item_action(i, e);
+ }
+ fn process_fn(@mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ self.visit_fn_action(fk, fd, b, s, n, e);
+ }
+ fn inner_variant(@mut self) -> @mut InnerLint {
+ @mut $Visitor { stopping_on_items: true } as @mut InnerLint
+ }
+ }
+ ))
+
+outer_lint_boilerplate_impl!(WhileTrueLintVisitor)
+
+fn lint_while_true() -> @mut OuterLint {
+ @mut WhileTrueLintVisitor{ stopping_on_items: false } as @mut OuterLint
}
-fn lint_type_limits() -> oldvisit::vt<@mut Context> {
- fn is_valid<T:cmp::Ord>(binop: ast::binop, v: T,
+struct TypeLimitsLintVisitor { stopping_on_items: bool }
+
+impl SubitemStoppableVisitor for TypeLimitsLintVisitor {
+ fn is_running_on_items(&mut self) -> bool { !self.stopping_on_items }
+}
+
+impl TypeLimitsLintVisitor {
+ fn is_valid<T:cmp::Ord>(&mut self, binop: ast::binop, v: T,
min: T, max: T) -> bool {
match binop {
ast::lt => v <= max,
}
}
- fn rev_binop(binop: ast::binop) -> ast::binop {
+ fn rev_binop(&mut self, binop: ast::binop) -> ast::binop {
match binop {
ast::lt => ast::gt,
ast::le => ast::ge,
// for int & uint, be conservative with the warnings, so that the
// warnings are consistent between 32- and 64-bit platforms
- fn int_ty_range(int_ty: ast::int_ty) -> (i64, i64) {
+ fn int_ty_range(&mut self, int_ty: ast::int_ty) -> (i64, i64) {
match int_ty {
ast::ty_i => (i64::min_value, i64::max_value),
ast::ty_char => (u32::min_value as i64, u32::max_value as i64),
}
}
- fn uint_ty_range(uint_ty: ast::uint_ty) -> (u64, u64) {
+ fn uint_ty_range(&mut self, uint_ty: ast::uint_ty) -> (u64, u64) {
match uint_ty {
ast::ty_u => (u64::min_value, u64::max_value),
ast::ty_u8 => (u8::min_value as u64, u8::max_value as u64),
}
}
- fn check_limits(cx: &Context,
+ fn check_limits(&mut self,
+ cx: &Context,
binop: ast::binop,
l: @ast::expr,
r: @ast::expr)
// Normalize the binop so that the literal is always on the RHS in
// the comparison
let norm_binop = if swap {
- rev_binop(binop)
+ self.rev_binop(binop)
} else {
binop
};
match ty::get(ty::expr_ty(cx.tcx, expr)).sty {
ty::ty_int(int_ty) => {
- let (min, max) = int_ty_range(int_ty);
+ let (min, max) = self.int_ty_range(int_ty);
let lit_val: i64 = match lit.node {
ast::expr_lit(@li) => match li.node {
ast::lit_int(v, _) => v,
},
_ => fail!()
};
- is_valid(norm_binop, lit_val, min, max)
+ self.is_valid(norm_binop, lit_val, min, max)
}
ty::ty_uint(uint_ty) => {
- let (min, max): (u64, u64) = uint_ty_range(uint_ty);
+ let (min, max): (u64, u64) = self.uint_ty_range(uint_ty);
let lit_val: u64 = match lit.node {
ast::expr_lit(@li) => match li.node {
ast::lit_int(v, _) => v as u64,
},
_ => fail!()
};
- is_valid(norm_binop, lit_val, min, max)
+ self.is_valid(norm_binop, lit_val, min, max)
}
_ => true
}
}
- fn is_comparison(binop: ast::binop) -> bool {
+ fn is_comparison(&mut self, binop: ast::binop) -> bool {
match binop {
ast::eq | ast::lt | ast::le |
ast::ne | ast::ge | ast::gt => true,
_ => false
}
}
+}
+
+impl Visitor<@mut Context> for TypeLimitsLintVisitor {
+ fn visit_item(&mut self, i:@ast::item, e:@mut Context) {
+ self.OVERRIDE_visit_item(i, e);
+ }
+
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ self.OVERRIDE_visit_fn(fk, fd, b, s, n, e);
+ }
+
+ fn visit_expr(&mut self, e:@ast::expr, cx:@mut Context) {
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: |e,
- (cx, vt): (@mut Context, oldvisit::vt<@mut Context>)| {
match e.node {
ast::expr_binary(_, ref binop, l, r) => {
- if is_comparison(*binop)
- && !check_limits(cx, *binop, l, r) {
+ if self.is_comparison(*binop)
+ && !self.check_limits(cx, *binop, l, r) {
cx.span_lint(type_limits, e.span,
"comparison is useless due to type limits");
}
}
_ => ()
}
- oldvisit::visit_expr(e, (cx, vt));
- },
+ visit::walk_expr(self, e, cx);
+ }
+}
+
+outer_lint_boilerplate_impl!(TypeLimitsLintVisitor)
- .. *oldvisit::default_visitor()
- })
+fn lint_type_limits() -> @mut OuterLint {
+ @mut TypeLimitsLintVisitor{ stopping_on_items: false } as @mut OuterLint
}
fn check_item_ctypes(cx: &Context, it: &ast::item) {
}
}
-fn lint_heap() -> oldvisit::vt<@mut Context> {
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: |e,
- (cx, vt): (@mut Context, oldvisit::vt<@mut Context>)| {
+struct HeapLintVisitor { stopping_on_items: bool }
+
+impl SubitemStoppableVisitor for HeapLintVisitor {
+ fn is_running_on_items(&mut self) -> bool { !self.stopping_on_items }
+}
+
+impl Visitor<@mut Context> for HeapLintVisitor {
+ fn visit_item(&mut self, i:@ast::item, e:@mut Context) {
+ self.OVERRIDE_visit_item(i, e);
+ }
+
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ self.OVERRIDE_visit_fn(fk, fd, b, s, n, e);
+ }
+
+ fn visit_expr(&mut self, e:@ast::expr, cx:@mut Context) {
let ty = ty::expr_ty(cx.tcx, e);
check_type(cx, e.span, ty);
- oldvisit::visit_expr(e, (cx, vt));
- },
- .. *oldvisit::default_visitor()
- })
+ visit::walk_expr(self, e, cx);
+ }
}
-fn lint_path_statement() -> oldvisit::vt<@mut Context> {
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_stmt: |s,
- (cx, vt): (@mut Context, oldvisit::vt<@mut Context>)| {
+outer_lint_boilerplate_impl!(HeapLintVisitor)
+
+fn lint_heap() -> @mut OuterLint {
+ @mut HeapLintVisitor { stopping_on_items: false } as @mut OuterLint
+}
+
+struct PathStatementLintVisitor {
+ stopping_on_items: bool
+}
+
+impl SubitemStoppableVisitor for PathStatementLintVisitor {
+ fn is_running_on_items(&mut self) -> bool { !self.stopping_on_items }
+}
+
+impl Visitor<@mut Context> for PathStatementLintVisitor {
+ fn visit_item(&mut self, i:@ast::item, e:@mut Context) {
+ self.OVERRIDE_visit_item(i, e);
+ }
+
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ self.OVERRIDE_visit_fn(fk, fd, b, s, n, e);
+ }
+
+ fn visit_stmt(&mut self, s:@ast::stmt, cx:@mut Context) {
match s.node {
ast::stmt_semi(
@ast::expr { node: ast::expr_path(_), _ },
}
_ => ()
}
- oldvisit::visit_stmt(s, (cx, vt));
- },
- .. *oldvisit::default_visitor()
- })
+ visit::walk_stmt(self, s, cx);
+
+ }
+}
+
+outer_lint_boilerplate_impl!(PathStatementLintVisitor)
+
+fn lint_path_statement() -> @mut OuterLint {
+ @mut PathStatementLintVisitor{ stopping_on_items: false } as @mut OuterLint
}
fn check_item_non_camel_case_types(cx: &Context, it: &ast::item) {
}
}
-fn lint_unused_unsafe() -> oldvisit::vt<@mut Context> {
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: |e,
- (cx, vt): (@mut Context, oldvisit::vt<@mut Context>)| {
+struct UnusedUnsafeLintVisitor { stopping_on_items: bool }
+
+impl SubitemStoppableVisitor for UnusedUnsafeLintVisitor {
+ fn is_running_on_items(&mut self) -> bool { !self.stopping_on_items }
+}
+
+impl Visitor<@mut Context> for UnusedUnsafeLintVisitor {
+ fn visit_item(&mut self, i:@ast::item, e:@mut Context) {
+ self.OVERRIDE_visit_item(i, e);
+ }
+
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ self.OVERRIDE_visit_fn(fk, fd, b, s, n, e);
+ }
+
+ fn visit_expr(&mut self, e:@ast::expr, cx:@mut Context) {
+
match e.node {
ast::expr_block(ref blk) if blk.rules == ast::UnsafeBlock => {
if !cx.tcx.used_unsafe.contains(&blk.id) {
}
_ => ()
}
- oldvisit::visit_expr(e, (cx, vt));
- },
- .. *oldvisit::default_visitor()
- })
+ visit::walk_expr(self, e, cx);
+ }
+}
+
+outer_lint_boilerplate_impl!(UnusedUnsafeLintVisitor)
+
+fn lint_unused_unsafe() -> @mut OuterLint {
+ @mut UnusedUnsafeLintVisitor{ stopping_on_items: false } as @mut OuterLint
}
-fn lint_unused_mut() -> oldvisit::vt<@mut Context> {
- fn check_pat(cx: &Context, p: @ast::pat) {
+struct UnusedMutLintVisitor { stopping_on_items: bool }
+
+impl UnusedMutLintVisitor {
+ fn check_pat(&mut self, cx: &Context, p: @ast::pat) {
let mut used = false;
let mut bindings = 0;
do pat_util::pat_bindings(cx.tcx.def_map, p) |_, id, _, _| {
}
}
- fn visit_fn_decl(cx: &Context, fd: &ast::fn_decl) {
+ fn visit_fn_decl(&mut self, cx: &Context, fd: &ast::fn_decl) {
for arg in fd.inputs.iter() {
if arg.is_mutbl {
- check_pat(cx, arg.pat);
+ self.check_pat(cx, arg.pat);
}
}
}
+}
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_local: |l,
- (cx, vt): (@mut Context, oldvisit::vt<@mut Context>)| {
+impl SubitemStoppableVisitor for UnusedMutLintVisitor {
+ fn is_running_on_items(&mut self) -> bool { !self.stopping_on_items }
+
+ fn visit_fn_action(&mut self, _a:&visit::fn_kind, fd:&ast::fn_decl,
+ _b:&ast::Block, _c:span, _d:ast::NodeId, cx:@mut Context) {
+ self.visit_fn_decl(cx, fd);
+ }
+}
+
+impl Visitor<@mut Context> for UnusedMutLintVisitor {
+ fn visit_item(&mut self, i:@ast::item, e:@mut Context) {
+ self.OVERRIDE_visit_item(i, e);
+ }
+
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ self.OVERRIDE_visit_fn(fk, fd, b, s, n, e);
+ }
+
+
+ fn visit_local(&mut self, l:@ast::Local, cx:@mut Context) {
if l.is_mutbl {
- check_pat(cx, l.pat);
+ self.check_pat(cx, l.pat);
}
- oldvisit::visit_local(l, (cx, vt));
- },
- visit_fn: |a, fd, b, c, d, (cx, vt)| {
- visit_fn_decl(cx, fd);
- oldvisit::visit_fn(a, fd, b, c, d, (cx, vt));
- },
- visit_ty_method: |tm, (cx, vt)| {
- visit_fn_decl(cx, &tm.decl);
- oldvisit::visit_ty_method(tm, (cx, vt));
- },
- visit_trait_method: |tm, (cx, vt)| {
+ visit::walk_local(self, l, cx);
+ }
+
+ fn visit_ty_method(&mut self, tm:&ast::TypeMethod, cx:@mut Context) {
+ self.visit_fn_decl(cx, &tm.decl);
+ visit::walk_ty_method(self, tm, cx);
+ }
+
+ fn visit_trait_method(&mut self, tm:&ast::trait_method, cx:@mut Context) {
match *tm {
- ast::required(ref tm) => visit_fn_decl(cx, &tm.decl),
- ast::provided(m) => visit_fn_decl(cx, &m.decl)
+ ast::required(ref tm) => self.visit_fn_decl(cx, &tm.decl),
+ ast::provided(m) => self.visit_fn_decl(cx, &m.decl)
}
- oldvisit::visit_trait_method(tm, (cx, vt));
- },
- .. *oldvisit::default_visitor()
- })
+ visit::walk_trait_method(self, tm, cx);
+ }
+}
+
+outer_lint_boilerplate_impl!(UnusedMutLintVisitor)
+
+fn lint_unused_mut() -> @mut OuterLint {
+ @mut UnusedMutLintVisitor{ stopping_on_items: false } as @mut OuterLint
}
fn lint_session(cx: @mut Context) -> @mut visit::Visitor<()> {
}, false)
}
-fn lint_unnecessary_allocations() -> oldvisit::vt<@mut Context> {
+struct UnnecessaryAllocationLintVisitor { stopping_on_items: bool }
+
+impl SubitemStoppableVisitor for UnnecessaryAllocationLintVisitor {
+ fn is_running_on_items(&mut self) -> bool { !self.stopping_on_items }
+}
+
+impl Visitor<@mut Context> for UnnecessaryAllocationLintVisitor {
+ fn visit_item(&mut self, i:@ast::item, e:@mut Context) {
+ self.OVERRIDE_visit_item(i, e);
+ }
+
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ self.OVERRIDE_visit_fn(fk, fd, b, s, n, e);
+ }
+
+ fn visit_expr(&mut self, e:@ast::expr, cx:@mut Context) {
+ self.check(cx, e);
+ visit::walk_expr(self, e, cx);
+ }
+}
+
+impl UnnecessaryAllocationLintVisitor {
// Warn if string and vector literals with sigils are immediately borrowed.
// Those can have the sigil removed.
- fn check(cx: &Context, e: &ast::expr) {
+ fn check(&mut self, cx: &Context, e: &ast::expr) {
match e.node {
ast::expr_vstore(e2, ast::expr_vstore_uniq) |
ast::expr_vstore(e2, ast::expr_vstore_box) => {
_ => ()
}
}
+}
+
+outer_lint_boilerplate_impl!(UnnecessaryAllocationLintVisitor)
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: |e,
- (cx, vt): (@mut Context, oldvisit::vt<@mut Context>)| {
- check(cx, e);
- oldvisit::visit_expr(e, (cx, vt));
- },
- .. *oldvisit::default_visitor()
- })
+fn lint_unnecessary_allocations() -> @mut OuterLint {
+ @mut UnnecessaryAllocationLintVisitor{ stopping_on_items: false } as @mut OuterLint
}
-fn lint_missing_doc() -> oldvisit::vt<@mut Context> {
- fn check_attrs(cx: @mut Context,
+struct MissingDocLintVisitor { stopping_on_items: bool }
+
+impl MissingDocLintVisitor {
+ fn check_attrs(&mut self,
+ cx: @mut Context,
attrs: &[ast::Attribute],
sp: span,
msg: &str) {
// otherwise, warn!
cx.span_lint(missing_doc, sp, msg);
}
+}
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_ty_method: |m, (cx, vt)| {
+impl Visitor<@mut Context> for MissingDocLintVisitor {
+ fn visit_item(&mut self, i:@ast::item, e:@mut Context) {
+ self.OVERRIDE_visit_item(i, e);
+ }
+
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:@mut Context) {
+ self.OVERRIDE_visit_fn(fk, fd, b, s, n, e);
+ }
+
+ fn visit_ty_method(&mut self, m:&ast::TypeMethod, cx:@mut Context) {
// All ty_method objects are linted about because they're part of a
// trait (no visibility)
- check_attrs(cx, m.attrs, m.span,
+ self.check_attrs(cx, m.attrs, m.span,
"missing documentation for a method");
- oldvisit::visit_ty_method(m, (cx, vt));
- },
+ visit::walk_ty_method(self, m, cx);
+ }
+}
+
+impl SubitemStoppableVisitor for MissingDocLintVisitor {
+ fn is_running_on_items(&mut self) -> bool { !self.stopping_on_items }
+
+ fn visit_fn_action(&mut self, fk:&visit::fn_kind, _d:&ast::fn_decl,
+ _b:&ast::Block, sp:span, _id:ast::NodeId, cx:@mut Context) {
- visit_fn: |fk, d, b, sp, id, (cx, vt)| {
// Only warn about explicitly public methods. Soon implicit
// public-ness will hopefully be going away.
match *fk {
- oldvisit::fk_method(_, _, m) if m.vis == ast::public => {
+ visit::fk_method(_, _, m) if m.vis == ast::public => {
// If we're in a trait implementation, no need to duplicate
// documentation
if !cx.in_trait_impl {
- check_attrs(cx, m.attrs, sp,
+ self.check_attrs(cx, m.attrs, sp,
"missing documentation for a method");
}
}
_ => {}
}
- oldvisit::visit_fn(fk, d, b, sp, id, (cx, vt));
- },
+ }
+
+ fn visit_item_action(&mut self, it:@ast::item, cx:@mut Context) {
- visit_item: |it, (cx, vt)| {
match it.node {
// Go ahead and match the fields here instead of using
// visit_struct_field while we have access to the enclosing
// struct's visibility
ast::item_struct(sdef, _) if it.vis == ast::public => {
- check_attrs(cx, it.attrs, it.span,
+ self.check_attrs(cx, it.attrs, it.span,
"missing documentation for a struct");
for field in sdef.fields.iter() {
match field.node.kind {
ast::named_field(_, vis) if vis != ast::private => {
- check_attrs(cx, field.node.attrs, field.span,
+ self.check_attrs(cx, field.node.attrs, field.span,
"missing documentation for a field");
}
ast::unnamed_field | ast::named_field(*) => {}
}
ast::item_trait(*) if it.vis == ast::public => {
- check_attrs(cx, it.attrs, it.span,
+ self.check_attrs(cx, it.attrs, it.span,
"missing documentation for a trait");
}
ast::item_fn(*) if it.vis == ast::public => {
- check_attrs(cx, it.attrs, it.span,
+ self.check_attrs(cx, it.attrs, it.span,
"missing documentation for a function");
}
_ => {}
- };
+ }
+ }
+}
+
+outer_lint_boilerplate_impl!(MissingDocLintVisitor)
+
+fn lint_missing_doc() -> @mut OuterLint {
+ @mut MissingDocLintVisitor { stopping_on_items: false } as @mut OuterLint
+}
+
+struct LintCheckVisitor;
+
+impl Visitor<@mut Context> for LintCheckVisitor {
+
+ fn visit_item(&mut self, it:@ast::item, cx: @mut Context) {
+
+ do cx.with_lint_attrs(it.attrs) {
+ match it.node {
+ ast::item_impl(_, Some(*), _, _) => {
+ cx.in_trait_impl = true;
+ }
+ _ => {}
+ }
+ check_item_ctypes(cx, it);
+ check_item_non_camel_case_types(cx, it);
+ check_item_non_uppercase_statics(cx, it);
+ check_item_heap(cx, it);
+
+ cx.process(Item(it));
+ visit::walk_item(self, it, cx);
+ cx.in_trait_impl = false;
+ }
+ }
- oldvisit::visit_item(it, (cx, vt));
- },
+ fn visit_fn(&mut self, fk:&visit::fn_kind, decl:&ast::fn_decl,
+ body:&ast::Block, span:span, id:ast::NodeId, cx:@mut Context) {
- .. *oldvisit::default_visitor()
- })
+ match *fk {
+ visit::fk_method(_, _, m) => {
+ do cx.with_lint_attrs(m.attrs) {
+ cx.process(Method(m));
+ visit::walk_fn(self,
+ fk,
+ decl,
+ body,
+ span,
+ id,
+ cx);
+ }
+ }
+ _ => {
+ visit::walk_fn(self,
+ fk,
+ decl,
+ body,
+ span,
+ id,
+ cx);
+ }
+ }
+ }
}
pub fn check_crate(tcx: ty::ctxt, crate: @ast::Crate) {
do cx.with_lint_attrs(crate.attrs) {
cx.process(Crate(crate));
- oldvisit::visit_crate(crate, (cx, oldvisit::mk_vt(@oldvisit::Visitor {
- visit_item: |it,
- (cx, vt):
- (@mut Context, oldvisit::vt<@mut Context>)| {
- do cx.with_lint_attrs(it.attrs) {
- match it.node {
- ast::item_impl(_, Some(*), _, _) => {
- cx.in_trait_impl = true;
- }
- _ => {}
- }
- check_item_ctypes(cx, it);
- check_item_non_camel_case_types(cx, it);
- check_item_non_uppercase_statics(cx, it);
- check_item_heap(cx, it);
+ let mut visitor = LintCheckVisitor;
- cx.process(Item(it));
- oldvisit::visit_item(it, (cx, vt));
- cx.in_trait_impl = false;
- }
- },
- visit_fn: |fk, decl, body, span, id, (cx, vt)| {
- match *fk {
- oldvisit::fk_method(_, _, m) => {
- do cx.with_lint_attrs(m.attrs) {
- cx.process(Method(m));
- oldvisit::visit_fn(fk,
- decl,
- body,
- span,
- id,
- (cx, vt));
- }
- }
- _ => {
- oldvisit::visit_fn(fk,
- decl,
- body,
- span,
- id,
- (cx, vt));
- }
- }
- },
- .. *oldvisit::default_visitor()
- })));
+ visit::walk_crate(&mut visitor, crate, cx);
}
// If we missed any lints added to the session, then there's a bug somewhere
use syntax::codemap::span;
use syntax::parse::token::special_idents;
use syntax::print::pprust::{expr_to_str, block_to_str};
-use syntax::oldvisit::{fk_anon, fk_fn_block, fk_item_fn, fk_method};
-use syntax::oldvisit::{vt};
-use syntax::{oldvisit, ast_util};
+use syntax::{visit, ast_util};
+use syntax::visit::{Visitor,fn_kind};
#[deriving(Eq)]
struct Variable(uint);
}
}
+struct LivenessVisitor;
+
+impl Visitor<@mut IrMaps> for LivenessVisitor {
+ fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, b:&Block, s:span, n:NodeId, e:@mut IrMaps) {
+ visit_fn(self, fk, fd, b, s, n, e);
+ }
+ fn visit_local(&mut self, l:@Local, e:@mut IrMaps) { visit_local(self, l, e); }
+ fn visit_expr(&mut self, ex:@expr, e:@mut IrMaps) { visit_expr(self, ex, e); }
+ fn visit_arm(&mut self, a:&arm, e:@mut IrMaps) { visit_arm(self, a, e); }
+}
+
pub fn check_crate(tcx: ty::ctxt,
method_map: typeck::method_map,
capture_map: moves::CaptureMap,
crate: &Crate) {
- let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_fn: visit_fn,
- visit_local: visit_local,
- visit_expr: visit_expr,
- visit_arm: visit_arm,
- .. *oldvisit::default_visitor()
- });
+ let mut visitor = LivenessVisitor;
let initial_maps = @mut IrMaps(tcx,
method_map,
capture_map);
- oldvisit::visit_crate(crate, (initial_maps, visitor));
+ visit::walk_crate(&mut visitor, crate, initial_maps);
tcx.sess.abort_if_errors();
}
}
}
-fn visit_fn(fk: &oldvisit::fn_kind,
+struct ErrorCheckVisitor;
+
+impl Visitor<@Liveness> for ErrorCheckVisitor {
+ fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, b:&Block, s:span, n:NodeId, e:@Liveness) {
+ check_fn(self, fk, fd, b, s, n, e);
+ }
+ fn visit_local(&mut self, l:@Local, e:@Liveness) {
+ check_local(self, l, e);
+ }
+ fn visit_expr(&mut self, ex:@expr, e:@Liveness) {
+ check_expr(self, ex, e);
+ }
+ fn visit_arm(&mut self, a:&arm, e:@Liveness) {
+ check_arm(self, a, e);
+ }
+}
+
+fn visit_fn(v: &mut LivenessVisitor,
+ fk: &visit::fn_kind,
decl: &fn_decl,
body: &Block,
sp: span,
id: NodeId,
- (this, v): (@mut IrMaps,
- vt<@mut IrMaps>)) {
+ this: @mut IrMaps) {
debug!("visit_fn: id=%d", id);
let _i = ::util::common::indenter();
// Add `this`, whether explicit or implicit.
match *fk {
- fk_method(_, _, method) => {
+ visit::fk_method(_, _, method) => {
match method.explicit_self.node {
sty_value | sty_region(*) | sty_box(_) | sty_uniq => {
fn_maps.add_variable(Arg(method.self_id,
sty_static => {}
}
}
- fk_item_fn(*) | fk_anon(*) | fk_fn_block(*) => {}
+ visit::fk_item_fn(*) | visit::fk_anon(*) | visit::fk_fn_block(*) => {}
}
// gather up the various local variables, significant expressions,
// and so forth:
- oldvisit::visit_fn(fk, decl, body, sp, id, (fn_maps, v));
+ visit::walk_fn(v, fk, decl, body, sp, id, fn_maps);
// Special nodes and variables:
// - exit_ln represents the end of the fn, either by return or fail
let entry_ln = (*lsets).compute(decl, body);
// check for various error conditions
- let check_vt = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_fn: check_fn,
- visit_local: check_local,
- visit_expr: check_expr,
- visit_arm: check_arm,
- .. *oldvisit::default_visitor()
- });
- (check_vt.visit_block)(body, (lsets, check_vt));
+ let mut check_vt = ErrorCheckVisitor;
+ check_vt.visit_block(body, lsets);
lsets.check_ret(id, sp, fk, entry_ln);
lsets.warn_about_unused_args(decl, entry_ln);
}
-fn visit_local(local: @Local, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) {
+fn visit_local(v: &mut LivenessVisitor, local: @Local, this: @mut IrMaps) {
let def_map = this.tcx.def_map;
do pat_util::pat_bindings(def_map, local.pat) |_bm, p_id, sp, path| {
debug!("adding local variable %d", p_id);
kind: kind
}));
}
- oldvisit::visit_local(local, (this, vt));
+ visit::walk_local(v, local, this);
}
-fn visit_arm(arm: &arm, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) {
+fn visit_arm(v: &mut LivenessVisitor, arm: &arm, this: @mut IrMaps) {
let def_map = this.tcx.def_map;
for pat in arm.pats.iter() {
do pat_util::pat_bindings(def_map, *pat) |bm, p_id, sp, path| {
}));
}
}
- oldvisit::visit_arm(arm, (this, vt));
+ visit::walk_arm(v, arm, this);
}
-fn visit_expr(expr: @expr, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) {
+fn visit_expr(v: &mut LivenessVisitor, expr: @expr, this: @mut IrMaps) {
match expr.node {
// live nodes required for uses or definitions of variables:
expr_path(_) | expr_self => {
if moves::moved_variable_node_id_from_def(def).is_some() {
this.add_live_node_for_node(expr.id, ExprNode(expr.span));
}
- oldvisit::visit_expr(expr, (this, vt));
+ visit::walk_expr(v, expr, this);
}
expr_fn_block(*) => {
// Interesting control flow (for loops can contain labeled
}
this.set_captures(expr.id, call_caps);
- oldvisit::visit_expr(expr, (this, vt));
+ visit::walk_expr(v, expr, this);
}
// live nodes required for interesting control flow:
expr_if(*) | expr_match(*) | expr_while(*) | expr_loop(*) => {
this.add_live_node_for_node(expr.id, ExprNode(expr.span));
- oldvisit::visit_expr(expr, (this, vt));
+ visit::walk_expr(v, expr, this);
}
expr_for_loop(*) => fail!("non-desugared expr_for_loop"),
expr_binary(_, op, _, _) if ast_util::lazy_binop(op) => {
this.add_live_node_for_node(expr.id, ExprNode(expr.span));
- oldvisit::visit_expr(expr, (this, vt));
+ visit::walk_expr(v, expr, this);
}
// otherwise, live nodes are not required:
expr_assign(*) | expr_assign_op(*) | expr_mac(*) |
expr_struct(*) | expr_repeat(*) | expr_paren(*) |
expr_inline_asm(*) => {
- oldvisit::visit_expr(expr, (this, vt));
+ visit::walk_expr(v, expr, this);
}
}
}
// _______________________________________________________________________
// Checking for error conditions
-fn check_local(local: @Local, (this, vt): (@Liveness, vt<@Liveness>)) {
+fn check_local(vt: &mut ErrorCheckVisitor, local: @Local, this: @Liveness) {
match local.init {
Some(_) => {
this.warn_about_unused_or_dead_vars_in_pat(local.pat);
}
}
- oldvisit::visit_local(local, (this, vt));
+ visit::walk_local(vt, local, this);
}
-fn check_arm(arm: &arm, (this, vt): (@Liveness, vt<@Liveness>)) {
+fn check_arm(vt: &mut ErrorCheckVisitor, arm: &arm, this: @Liveness) {
do this.arm_pats_bindings(arm.pats) |ln, var, sp, id| {
this.warn_about_unused(sp, id, ln, var);
}
- oldvisit::visit_arm(arm, (this, vt));
+ visit::walk_arm(vt, arm, this);
}
-fn check_expr(expr: @expr, (this, vt): (@Liveness, vt<@Liveness>)) {
+fn check_expr(vt: &mut ErrorCheckVisitor, expr: @expr, this: @Liveness) {
match expr.node {
expr_assign(l, r) => {
this.check_lvalue(l, vt);
- (vt.visit_expr)(r, (this, vt));
+ vt.visit_expr(r, this);
- oldvisit::visit_expr(expr, (this, vt));
+ visit::walk_expr(vt, expr, this);
}
expr_assign_op(_, _, l, _) => {
this.check_lvalue(l, vt);
- oldvisit::visit_expr(expr, (this, vt));
+ visit::walk_expr(vt, expr, this);
}
expr_inline_asm(ref ia) => {
for &(_, input) in ia.inputs.iter() {
- (vt.visit_expr)(input, (this, vt));
+ vt.visit_expr(input, this);
}
// Output operands must be lvalues
}
_ => {}
}
- (vt.visit_expr)(out, (this, vt));
+ vt.visit_expr(out, this);
}
- oldvisit::visit_expr(expr, (this, vt));
+ visit::walk_expr(vt, expr, this);
}
// no correctness conditions related to liveness
expr_again(*) | expr_lit(_) | expr_block(*) |
expr_mac(*) | expr_addr_of(*) | expr_struct(*) | expr_repeat(*) |
expr_paren(*) | expr_fn_block(*) | expr_path(*) | expr_self(*) => {
- oldvisit::visit_expr(expr, (this, vt));
+ visit::walk_expr(vt, expr, this);
}
expr_for_loop(*) => fail!("non-desugared expr_for_loop")
}
}
-fn check_fn(_fk: &oldvisit::fn_kind,
+fn check_fn(_v: &mut ErrorCheckVisitor,
+ _fk: &visit::fn_kind,
_decl: &fn_decl,
_body: &Block,
_sp: span,
_id: NodeId,
- (_self, _v): (@Liveness, vt<@Liveness>)) {
+ _self: @Liveness) {
// do not check contents of nested fns
}
pub fn check_ret(&self,
id: NodeId,
sp: span,
- _fk: &oldvisit::fn_kind,
+ _fk: &visit::fn_kind,
entry_ln: LiveNode) {
if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
// if no_ret_var is live, then we fall off the end of the
}
}
- pub fn check_lvalue(@self, expr: @expr, vt: vt<@Liveness>) {
+ pub fn check_lvalue(@self, expr: @expr, vt: &mut ErrorCheckVisitor) {
match expr.node {
expr_path(_) => {
match self.tcx.def_map.get_copy(&expr.id) {
_ => {
// For other kinds of lvalues, no checks are required,
// and any embedded expressions are actually rvalues
- oldvisit::visit_expr(expr, (self, vt));
+ visit::walk_expr(vt, expr, self);
}
}
}
pat_bindings(dm, pat, |_bm, b_id, _sp, _pt| found.push(b_id) );
return found;
}
+
+/// Checks if the pattern contains any patterns that bind something to
+/// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(*)`.
+pub fn pat_contains_bindings(dm: resolve::DefMap, pat: @pat) -> bool {
+ let mut contains_bindings = false;
+ do walk_pat(pat) |p| {
+ if pat_is_binding(dm, p) {
+ contains_bindings = true;
+ false // there's at least one binding, can short circuit now.
+ } else {
+ true
+ }
+ };
+ contains_bindings
+}
use middle::ty::{ty_struct, ty_enum};
use middle::ty;
use middle::typeck::{method_map, method_origin, method_param};
-use middle::typeck::{method_static, method_trait};
+use middle::typeck::{method_static, method_object};
use std::util::ignore;
use syntax::ast::{decl_item, def, def_fn, def_id, def_static_method};
use syntax::attr;
use syntax::codemap::span;
use syntax::parse::token;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
+use syntax::ast::{_mod,expr,item,Block,pat};
-pub fn check_crate<'mm>(tcx: ty::ctxt,
- method_map: &'mm method_map,
- crate: &ast::Crate) {
- let privileged_items = @mut ~[];
+struct PrivacyVisitor {
+ tcx: ty::ctxt,
+ privileged_items: @mut ~[NodeId],
+}
+impl PrivacyVisitor {
// Adds an item to its scope.
- let add_privileged_item: @fn(@ast::item, &mut uint) = |item, count| {
+ fn add_privileged_item(&mut self, item: @ast::item, count: &mut uint) {
match item.node {
item_struct(*) | item_trait(*) | item_enum(*) |
item_fn(*) => {
- privileged_items.push(item.id);
+ self.privileged_items.push(item.id);
*count += 1;
}
item_impl(_, _, _, ref methods) => {
for method in methods.iter() {
- privileged_items.push(method.id);
+ self.privileged_items.push(method.id);
*count += 1;
}
- privileged_items.push(item.id);
+ self.privileged_items.push(item.id);
*count += 1;
}
item_foreign_mod(ref foreign_mod) => {
for foreign_item in foreign_mod.items.iter() {
- privileged_items.push(foreign_item.id);
+ self.privileged_items.push(foreign_item.id);
*count += 1;
}
}
_ => {}
}
- };
+ }
// Adds items that are privileged to this scope.
- let add_privileged_items: @fn(&[@ast::item]) -> uint = |items| {
+ fn add_privileged_items(&mut self, items: &[@ast::item]) -> uint {
let mut count = 0;
for &item in items.iter() {
- add_privileged_item(item, &mut count);
+ self.add_privileged_item(item, &mut count);
}
count
- };
+ }
// Checks that an enum variant is in scope
- let check_variant: @fn(span: span, enum_id: ast::def_id) =
- |span, enum_id| {
- let variant_info = ty::enum_variants(tcx, enum_id)[0];
+ fn check_variant(&mut self, span: span, enum_id: ast::def_id) {
+ let variant_info = ty::enum_variants(self.tcx, enum_id)[0];
let parental_privacy = if is_local(enum_id) {
- let parent_vis = ast_map::node_item_query(tcx.items, enum_id.node,
+ let parent_vis = ast_map::node_item_query(self.tcx.items,
+ enum_id.node,
|it| { it.vis },
~"unbound enum parent when checking \
dereference of enum type");
if variant_visibility_to_privacy(variant_info.vis,
parental_privacy == Public)
== Private {
- tcx.sess.span_err(span,
+ self.tcx.sess.span_err(span,
"can only dereference enums \
with a single, public variant");
}
- };
+ }
// Returns true if a crate-local method is private and false otherwise.
- let method_is_private: @fn(span: span, method_id: NodeId) -> bool =
- |span, method_id| {
+ fn method_is_private(&mut self, span: span, method_id: NodeId) -> bool {
let check = |vis: visibility, container_id: def_id| {
let mut is_private = false;
if vis == private {
} else {
// Look up the enclosing impl.
if container_id.crate != LOCAL_CRATE {
- tcx.sess.span_bug(span,
+ self.tcx.sess.span_bug(span,
"local method isn't in local \
impl?!");
}
- match tcx.items.find(&container_id.node) {
+ match self.tcx.items.find(&container_id.node) {
Some(&node_item(item, _)) => {
match item.node {
item_impl(_, None, _, _)
}
}
Some(_) => {
- tcx.sess.span_bug(span, "impl wasn't an item?!");
+ self.tcx.sess.span_bug(span, "impl wasn't an item?!");
}
None => {
- tcx.sess.span_bug(span, "impl wasn't in AST map?!");
+ self.tcx.sess.span_bug(span, "impl wasn't in AST map?!");
}
}
}
is_private
};
- match tcx.items.find(&method_id) {
+ match self.tcx.items.find(&method_id) {
Some(&node_method(method, impl_id, _)) => {
check(method.vis, impl_id)
}
}
}
Some(_) => {
- tcx.sess.span_bug(span,
+ self.tcx.sess.span_bug(span,
fmt!("method_is_private: method was a %s?!",
ast_map::node_id_to_str(
- tcx.items,
+ self.tcx.items,
method_id,
token::get_ident_interner())));
}
None => {
- tcx.sess.span_bug(span, "method not found in \
+ self.tcx.sess.span_bug(span, "method not found in \
AST map?!");
}
}
- };
+ }
// Returns true if the given local item is private and false otherwise.
- let local_item_is_private: @fn(span: span, item_id: NodeId) -> bool =
- |span, item_id| {
+ fn local_item_is_private(&mut self, span: span, item_id: NodeId) -> bool {
let mut f: &fn(NodeId) -> bool = |_| false;
f = |item_id| {
- match tcx.items.find(&item_id) {
+ match self.tcx.items.find(&item_id) {
Some(&node_item(item, _)) => item.vis != public,
Some(&node_foreign_item(*)) => false,
Some(&node_method(method, impl_did, _)) => {
}
Some(&node_trait_method(_, trait_did, _)) => f(trait_did.node),
Some(_) => {
- tcx.sess.span_bug(span,
+ self.tcx.sess.span_bug(span,
fmt!("local_item_is_private: item was \
a %s?!",
ast_map::node_id_to_str(
- tcx.items,
+ self.tcx.items,
item_id,
token::get_ident_interner())));
}
None => {
- tcx.sess.span_bug(span, "item not found in AST map?!");
+ self.tcx.sess.span_bug(span, "item not found in AST map?!");
}
}
};
f(item_id)
- };
+ }
// Checks that a private field is in scope.
- let check_field: @fn(span: span, id: ast::def_id, ident: ast::ident) =
- |span, id, ident| {
- let fields = ty::lookup_struct_fields(tcx, id);
+ fn check_field(&mut self, span: span, id: ast::def_id, ident: ast::ident) {
+ let fields = ty::lookup_struct_fields(self.tcx, id);
for field in fields.iter() {
if field.ident != ident { loop; }
if field.vis == private {
- tcx.sess.span_err(span, fmt!("field `%s` is private",
+ self.tcx.sess.span_err(span, fmt!("field `%s` is private",
token::ident_to_str(&ident)));
}
break;
}
- };
+ }
// Given the ID of a method, checks to ensure it's in scope.
- let check_method_common: @fn(span: span,
- method_id: def_id,
- name: &ident) =
- |span, method_id, name| {
+ fn check_method_common(&mut self, span: span, method_id: def_id, name: &ident) {
// If the method is a default method, we need to use the def_id of
// the default implementation.
// Having to do this this is really unfortunate.
- let method_id = ty::method(tcx, method_id).provided_source
+ let method_id = ty::method(self.tcx, method_id).provided_source
.unwrap_or_default(method_id);
if method_id.crate == LOCAL_CRATE {
- let is_private = method_is_private(span, method_id.node);
- let container_id = ty::method(tcx, method_id).container_id;
+ let is_private = self.method_is_private(span, method_id.node);
+ let container_id = ty::method(self.tcx, method_id).container_id;
if is_private &&
(container_id.crate != LOCAL_CRATE ||
- !privileged_items.iter().any(|x| x == &(container_id.node))) {
- tcx.sess.span_err(span,
+ !self.privileged_items.iter().any(|x| x == &(container_id.node))) {
+ self.tcx.sess.span_err(span,
fmt!("method `%s` is private",
token::ident_to_str(name)));
}
} else {
let visibility =
- csearch::get_item_visibility(tcx.sess.cstore, method_id);
+ csearch::get_item_visibility(self.tcx.sess.cstore, method_id);
if visibility != public {
- tcx.sess.span_err(span,
+ self.tcx.sess.span_err(span,
fmt!("method `%s` is private",
token::ident_to_str(name)));
}
}
- };
+ }
// Checks that a private path is in scope.
- let check_path: @fn(span: span, def: def, path: &Path) =
- |span, def, path| {
+ fn check_path(&mut self, span: span, def: def, path: &Path) {
debug!("checking path");
match def {
def_static_method(method_id, _, _) => {
debug!("found static method def, checking it");
- check_method_common(span, method_id, path.idents.last())
+ self.check_method_common(span, method_id, path.idents.last())
}
def_fn(def_id, _) => {
if def_id.crate == LOCAL_CRATE {
- if local_item_is_private(span, def_id.node) &&
- !privileged_items.iter().any(|x| x == &def_id.node) {
- tcx.sess.span_err(span,
+ if self.local_item_is_private(span, def_id.node) &&
+ !self.privileged_items.iter().any(|x| x == &def_id.node) {
+ self.tcx.sess.span_err(span,
fmt!("function `%s` is private",
token::ident_to_str(path.idents.last())));
}
- } else if csearch::get_item_visibility(tcx.sess.cstore,
+ } else if csearch::get_item_visibility(self.tcx.sess.cstore,
def_id) != public {
- tcx.sess.span_err(span,
+ self.tcx.sess.span_err(span,
fmt!("function `%s` is private",
token::ident_to_str(path.idents.last())));
}
}
_ => {}
}
- };
+ }
// Checks that a private method is in scope.
- let check_method: @fn(span: span,
- origin: &method_origin,
- ident: ast::ident) =
- |span, origin, ident| {
+ fn check_method(&mut self, span: span, origin: &method_origin, ident: ast::ident) {
match *origin {
method_static(method_id) => {
- check_method_common(span, method_id, &ident)
+ self.check_method_common(span, method_id, &ident)
}
method_param(method_param {
trait_id: trait_id,
- method_num: method_num,
+ method_num: method_num,
_
}) |
- method_trait(trait_id, method_num) => {
+ method_object(method_object {
+ trait_id: trait_id,
+ method_num: method_num,
+ _
+ }) => {
if trait_id.crate == LOCAL_CRATE {
- match tcx.items.find(&trait_id.node) {
+ match self.tcx.items.find(&trait_id.node) {
Some(&node_item(item, _)) => {
match item.node {
item_trait(_, _, ref methods) => {
if method_num >= (*methods).len() {
- tcx.sess.span_bug(span, "method number out of range?!");
+ self.tcx.sess.span_bug(span,
+ "method number out of range?!");
}
match (*methods)[method_num] {
provided(method)
if method.vis == private &&
- !privileged_items.iter()
+ !self.privileged_items.iter()
.any(|x| x == &(trait_id.node)) => {
- tcx.sess.span_err(span,
+ self.tcx.sess.span_err(span,
fmt!("method `%s` is private",
token::ident_to_str(&method
.ident)));
}
}
_ => {
- tcx.sess.span_bug(span, "trait wasn't actually a trait?!");
+ self.tcx.sess.span_bug(span, "trait wasn't actually a trait?!");
}
}
}
Some(_) => {
- tcx.sess.span_bug(span, "trait wasn't an item?!");
+ self.tcx.sess.span_bug(span, "trait wasn't an item?!");
}
None => {
- tcx.sess.span_bug(span, "trait item wasn't found in the AST map?!");
+ self.tcx.sess.span_bug(span,
+ "trait item wasn't found in the AST map?!");
}
}
} else {
}
}
}
- };
+ }
+}
- let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_mod: |the_module, span, node_id, (method_map, visitor)| {
- let n_added = add_privileged_items(the_module.items);
+impl<'self> Visitor<&'self method_map> for PrivacyVisitor {
- oldvisit::visit_mod(the_module,
- span,
- node_id,
- (method_map, visitor));
+ fn visit_mod<'mm>(&mut self, the_module:&_mod, _:span, _:NodeId,
+ method_map:&'mm method_map) {
+
+ let n_added = self.add_privileged_items(the_module.items);
+
+ visit::walk_mod(self, the_module, method_map);
do n_added.times {
- ignore(privileged_items.pop());
+ ignore(self.privileged_items.pop());
}
- },
- visit_item: |item, (method_map, visitor)| {
+ }
+
+ fn visit_item<'mm>(&mut self, item:@item, method_map:&'mm method_map) {
+
// Do not check privacy inside items with the resolve_unexported
// attribute. This is used for the test runner.
if !attr::contains_name(item.attrs, "!resolve_unexported") {
- check_sane_privacy(tcx, item);
- oldvisit::visit_item(item, (method_map, visitor));
+ check_sane_privacy(self.tcx, item);
+ visit::walk_item(self, item, method_map);
}
- },
- visit_block: |block, (method_map, visitor)| {
+ }
+
+ fn visit_block<'mm>(&mut self, block:&Block, method_map:&'mm method_map) {
+
// Gather up all the privileged items.
let mut n_added = 0;
for stmt in block.stmts.iter() {
stmt_decl(decl, _) => {
match decl.node {
decl_item(item) => {
- add_privileged_item(item, &mut n_added);
+ self.add_privileged_item(item, &mut n_added);
}
_ => {}
}
}
}
- oldvisit::visit_block(block, (method_map, visitor));
+ visit::walk_block(self, block, method_map);
do n_added.times {
- ignore(privileged_items.pop());
+ ignore(self.privileged_items.pop());
}
- },
- visit_expr: |expr,
- (method_map, visitor):
- (&'mm method_map, oldvisit::vt<&'mm method_map>)| {
+
+ }
+
+ fn visit_expr<'mm>(&mut self, expr:@expr, method_map:&'mm method_map) {
+
match expr.node {
expr_field(base, ident, _) => {
// Method calls are now a special syntactic form,
// With type_autoderef, make sure we don't
// allow pointers to violate privacy
- match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx,
+ match ty::get(ty::type_autoderef(self.tcx, ty::expr_ty(self.tcx,
base))).sty {
ty_struct(id, _)
- if id.crate != LOCAL_CRATE || !privileged_items.iter()
+ if id.crate != LOCAL_CRATE || !self.privileged_items.iter()
.any(|x| x == &(id.node)) => {
debug!("(privacy checking) checking field access");
- check_field(expr.span, id, ident);
+ self.check_field(expr.span, id, ident);
}
_ => {}
}
}
expr_method_call(_, base, ident, _, _, _) => {
// Ditto
- match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx,
+ match ty::get(ty::type_autoderef(self.tcx, ty::expr_ty(self.tcx,
base))).sty {
ty_enum(id, _) |
ty_struct(id, _)
if id.crate != LOCAL_CRATE ||
- !privileged_items.iter().any(|x| x == &(id.node)) => {
+ !self.privileged_items.iter().any(|x| x == &(id.node)) => {
match method_map.find(&expr.id) {
None => {
- tcx.sess.span_bug(expr.span,
+ self.tcx.sess.span_bug(expr.span,
"method call not in \
method map");
}
Some(ref entry) => {
debug!("(privacy checking) checking \
impl method");
- check_method(expr.span, &entry.origin, ident);
+ self.check_method(expr.span, &entry.origin, ident);
}
}
}
}
}
expr_path(ref path) => {
- check_path(expr.span, tcx.def_map.get_copy(&expr.id), path);
+ self.check_path(expr.span, self.tcx.def_map.get_copy(&expr.id), path);
}
expr_struct(_, ref fields, _) => {
- match ty::get(ty::expr_ty(tcx, expr)).sty {
+ match ty::get(ty::expr_ty(self.tcx, expr)).sty {
ty_struct(id, _) => {
if id.crate != LOCAL_CRATE ||
- !privileged_items.iter().any(|x| x == &(id.node)) {
+ !self.privileged_items.iter().any(|x| x == &(id.node)) {
for field in (*fields).iter() {
debug!("(privacy checking) checking \
field in struct literal");
- check_field(expr.span, id, field.ident);
+ self.check_field(expr.span, id, field.ident);
}
}
}
ty_enum(id, _) => {
if id.crate != LOCAL_CRATE ||
- !privileged_items.iter().any(|x| x == &(id.node)) {
- match tcx.def_map.get_copy(&expr.id) {
+ !self.privileged_items.iter().any(|x| x == &(id.node)) {
+ match self.tcx.def_map.get_copy(&expr.id) {
def_variant(_, variant_id) => {
for field in (*fields).iter() {
debug!("(privacy checking) \
checking field in \
struct variant \
literal");
- check_field(expr.span, variant_id, field.ident);
+ self.check_field(expr.span, variant_id, field.ident);
}
}
_ => {
- tcx.sess.span_bug(expr.span,
+ self.tcx.sess.span_bug(expr.span,
"resolve didn't \
map enum struct \
constructor to a \
}
}
_ => {
- tcx.sess.span_bug(expr.span, "struct expr \
+ self.tcx.sess.span_bug(expr.span, "struct expr \
didn't have \
struct type?!");
}
// enum type t, then t's first variant is public or
// privileged. (We can assume it has only one variant
// since typeck already happened.)
- match ty::get(ty::expr_ty(tcx, operand)).sty {
+ match ty::get(ty::expr_ty(self.tcx, operand)).sty {
ty_enum(id, _) => {
if id.crate != LOCAL_CRATE ||
- !privileged_items.iter().any(|x| x == &(id.node)) {
- check_variant(expr.span, id);
+ !self.privileged_items.iter().any(|x| x == &(id.node)) {
+ self.check_variant(expr.span, id);
}
}
_ => { /* No check needed */ }
_ => {}
}
- oldvisit::visit_expr(expr, (method_map, visitor));
- },
- visit_pat: |pattern, (method_map, visitor)| {
+ visit::walk_expr(self, expr, method_map);
+
+ }
+
+ fn visit_pat<'mm>(&mut self, pattern:@pat, method_map:&'mm method_map) {
+
match pattern.node {
pat_struct(_, ref fields, _) => {
- match ty::get(ty::pat_ty(tcx, pattern)).sty {
+ match ty::get(ty::pat_ty(self.tcx, pattern)).sty {
ty_struct(id, _) => {
if id.crate != LOCAL_CRATE ||
- !privileged_items.iter().any(|x| x == &(id.node)) {
+ !self.privileged_items.iter().any(|x| x == &(id.node)) {
for field in fields.iter() {
debug!("(privacy checking) checking \
struct pattern");
- check_field(pattern.span, id, field.ident);
+ self.check_field(pattern.span, id, field.ident);
}
}
}
ty_enum(enum_id, _) => {
if enum_id.crate != LOCAL_CRATE ||
- !privileged_items.iter().any(|x| x == &enum_id.node) {
- match tcx.def_map.find(&pattern.id) {
+ !self.privileged_items.iter().any(|x| x == &enum_id.node) {
+ match self.tcx.def_map.find(&pattern.id) {
Some(&def_variant(_, variant_id)) => {
for field in fields.iter() {
debug!("(privacy checking) \
checking field in \
struct variant pattern");
- check_field(pattern.span, variant_id, field.ident);
+ self.check_field(pattern.span, variant_id, field.ident);
}
}
_ => {
- tcx.sess.span_bug(pattern.span,
+ self.tcx.sess.span_bug(pattern.span,
"resolve didn't \
map enum struct \
pattern to a \
}
}
_ => {
- tcx.sess.span_bug(pattern.span,
+ self.tcx.sess.span_bug(pattern.span,
"struct pattern didn't have \
struct type?!");
}
_ => {}
}
- oldvisit::visit_pat(pattern, (method_map, visitor));
- },
- .. *oldvisit::default_visitor()
- });
- oldvisit::visit_crate(crate, (method_map, visitor));
+ visit::walk_pat(self, pattern, method_map);
+ }
+}
+
+pub fn check_crate<'mm>(tcx: ty::ctxt,
+ method_map: &'mm method_map,
+ crate: &ast::Crate) {
+ let privileged_items = @mut ~[];
+
+ let mut visitor = PrivacyVisitor {
+ tcx: tcx,
+ privileged_items: privileged_items,
+ };
+ visit::walk_crate(&mut visitor, crate, method_map);
}
/// Validates all of the visibility qualifers placed on the item given. This
use syntax::ast_util::def_id_of_def;
use syntax::attr;
use syntax::parse::token;
-use syntax::oldvisit::Visitor;
-use syntax::oldvisit;
+use syntax::visit::Visitor;
+use syntax::visit;
// Returns true if the given set of attributes contains the `#[inline]`
// attribute.
worklist: @mut ~[NodeId],
}
-impl ReachableContext {
- // Creates a new reachability computation context.
- fn new(tcx: ty::ctxt, method_map: typeck::method_map)
- -> ReachableContext {
- ReachableContext {
- tcx: tcx,
- method_map: method_map,
- reachable_symbols: @mut HashSet::new(),
- worklist: @mut ~[],
- }
- }
+struct ReachableVisitor {
+ reachable_symbols: @mut HashSet<NodeId>,
+ worklist: @mut ~[NodeId],
+}
+
+impl Visitor<PrivacyContext> for ReachableVisitor {
+
+ fn visit_item(&mut self, item:@item, privacy_context:PrivacyContext) {
- // Step 1: Mark all public symbols, and add all public symbols that might
- // be inlined to a worklist.
- fn mark_public_symbols(&self, crate: @Crate) {
- let reachable_symbols = self.reachable_symbols;
- let worklist = self.worklist;
- let visitor = oldvisit::mk_vt(@Visitor {
- visit_item: |item, (privacy_context, visitor):
- (PrivacyContext, oldvisit::vt<PrivacyContext>)| {
match item.node {
item_fn(*) => {
if privacy_context == PublicContext {
- reachable_symbols.insert(item.id);
+ self.reachable_symbols.insert(item.id);
}
if item_might_be_inlined(item) {
- worklist.push(item.id)
+ self.worklist.push(item.id)
}
}
item_struct(ref struct_def, _) => {
match struct_def.ctor_id {
Some(ctor_id) if
privacy_context == PublicContext => {
- reachable_symbols.insert(ctor_id);
+ self.reachable_symbols.insert(ctor_id);
}
Some(_) | None => {}
}
item_enum(ref enum_def, _) => {
if privacy_context == PublicContext {
for variant in enum_def.variants.iter() {
- reachable_symbols.insert(variant.node.id);
+ self.reachable_symbols.insert(variant.node.id);
}
}
}
// Mark all public methods as reachable.
for &method in methods.iter() {
if should_be_considered_public(method) {
- reachable_symbols.insert(method.id);
+ self.reachable_symbols.insert(method.id);
}
}
// symbols to the worklist.
for &method in methods.iter() {
if should_be_considered_public(method) {
- worklist.push(method.id)
+ self.worklist.push(method.id)
}
}
} else {
if generics_require_inlining(generics) ||
attributes_specify_inlining(*attrs) ||
should_be_considered_public(*method) {
- worklist.push(method.id)
+ self.worklist.push(method.id)
}
}
}
for trait_method in trait_methods.iter() {
match *trait_method {
provided(method) => {
- reachable_symbols.insert(method.id);
- worklist.push(method.id)
+ self.reachable_symbols.insert(method.id);
+ self.worklist.push(method.id)
}
required(_) => {}
}
}
if item.vis == public && privacy_context == PublicContext {
- oldvisit::visit_item(item, (PublicContext, visitor))
+ visit::walk_item(self, item, PublicContext)
} else {
- oldvisit::visit_item(item, (PrivateContext, visitor))
+ visit::walk_item(self, item, PrivateContext)
}
- },
- .. *oldvisit::default_visitor()
- });
+ }
+
+}
+
+struct MarkSymbolVisitor {
+ worklist: @mut ~[NodeId],
+ method_map: typeck::method_map,
+ tcx: ty::ctxt,
+ reachable_symbols: @mut HashSet<NodeId>,
+}
+
+impl Visitor<()> for MarkSymbolVisitor {
- oldvisit::visit_crate(crate, (PublicContext, visitor))
+ fn visit_expr(&mut self, expr:@expr, _:()) {
+
+ match expr.node {
+ expr_path(_) => {
+ let def = match self.tcx.def_map.find(&expr.id) {
+ Some(&def) => def,
+ None => {
+ self.tcx.sess.span_bug(expr.span,
+ "def ID not in def map?!")
+ }
+ };
+
+ let def_id = def_id_of_def(def);
+ if ReachableContext::
+ def_id_represents_local_inlined_item(self.tcx,
+ def_id) {
+ self.worklist.push(def_id.node)
+ }
+ self.reachable_symbols.insert(def_id.node);
+ }
+ expr_method_call(*) => {
+ match self.method_map.find(&expr.id) {
+ Some(&typeck::method_map_entry {
+ origin: typeck::method_static(def_id),
+ _
+ }) => {
+ if ReachableContext::
+ def_id_represents_local_inlined_item(
+ self.tcx,
+ def_id) {
+ self.worklist.push(def_id.node)
+ }
+ self.reachable_symbols.insert(def_id.node);
+ }
+ Some(_) => {}
+ None => {
+ self.tcx.sess.span_bug(expr.span,
+ "method call expression \
+ not in method map?!")
+ }
+ }
+ }
+ _ => {}
+ }
+
+ visit::walk_expr(self, expr, ())
+ }
+}
+
+impl ReachableContext {
+ // Creates a new reachability computation context.
+ fn new(tcx: ty::ctxt, method_map: typeck::method_map)
+ -> ReachableContext {
+ ReachableContext {
+ tcx: tcx,
+ method_map: method_map,
+ reachable_symbols: @mut HashSet::new(),
+ worklist: @mut ~[],
+ }
+ }
+
+ // Step 1: Mark all public symbols, and add all public symbols that might
+ // be inlined to a worklist.
+ fn mark_public_symbols(&self, crate: @Crate) {
+ let reachable_symbols = self.reachable_symbols;
+ let worklist = self.worklist;
+
+ let mut visitor = ReachableVisitor {
+ reachable_symbols: reachable_symbols,
+ worklist: worklist,
+ };
+
+
+ visit::walk_crate(&mut visitor, crate, PublicContext);
}
// Returns true if the given def ID represents a local item that is
}
// Helper function to set up a visitor for `propagate()` below.
- fn init_visitor(&self) -> oldvisit::vt<()> {
+ fn init_visitor(&self) -> MarkSymbolVisitor {
let (worklist, method_map) = (self.worklist, self.method_map);
let (tcx, reachable_symbols) = (self.tcx, self.reachable_symbols);
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: |expr, (_, visitor)| {
- match expr.node {
- expr_path(_) => {
- let def = match tcx.def_map.find(&expr.id) {
- Some(&def) => def,
- None => {
- tcx.sess.span_bug(expr.span,
- "def ID not in def map?!")
- }
- };
-
- let def_id = def_id_of_def(def);
- if ReachableContext::
- def_id_represents_local_inlined_item(tcx,
- def_id) {
- worklist.push(def_id.node)
- }
- reachable_symbols.insert(def_id.node);
- }
- expr_method_call(*) => {
- match method_map.find(&expr.id) {
- Some(&typeck::method_map_entry {
- origin: typeck::method_static(def_id),
- _
- }) => {
- if ReachableContext::
- def_id_represents_local_inlined_item(
- tcx,
- def_id) {
- worklist.push(def_id.node)
- }
- reachable_symbols.insert(def_id.node);
- }
- Some(_) => {}
- None => {
- tcx.sess.span_bug(expr.span,
- "method call expression \
- not in method map?!")
- }
- }
- }
- _ => {}
- }
- oldvisit::visit_expr(expr, ((), visitor))
- },
- ..*oldvisit::default_visitor()
- })
+ MarkSymbolVisitor {
+ worklist: worklist,
+ method_map: method_map,
+ tcx: tcx,
+ reachable_symbols: reachable_symbols,
+ }
}
// Step 2: Mark all symbols that the symbols on the worklist touch.
fn propagate(&self) {
- let visitor = self.init_visitor();
+ let mut visitor = self.init_visitor();
let mut scanned = HashSet::new();
while self.worklist.len() > 0 {
let search_item = self.worklist.pop();
Some(&ast_map::node_item(item, _)) => {
match item.node {
item_fn(_, _, _, _, ref search_block) => {
- oldvisit::visit_block(search_block, ((), visitor))
+ visit::walk_block(&mut visitor, search_block, ())
}
_ => {
self.tcx.sess.span_bug(item.span,
worklist?!")
}
provided(ref method) => {
- oldvisit::visit_block(&method.body, ((), visitor))
+ visit::walk_block(&mut visitor, &method.body, ())
}
}
}
Some(&ast_map::node_method(ref method, _, _)) => {
- oldvisit::visit_block(&method.body, ((), visitor))
+ visit::walk_block(&mut visitor, &method.body, ())
}
Some(_) => {
let ident_interner = token::get_ident_interner();
use syntax::print::pprust;
use syntax::parse::token;
use syntax::parse::token::special_idents;
-use syntax::{ast, oldvisit};
+use syntax::{ast, visit};
+use syntax::visit::{Visitor,fn_kind};
+use syntax::ast::{Block,item,fn_decl,NodeId,arm,pat,stmt,expr,Local};
+use syntax::ast::{Ty,TypeMethod,struct_field};
/**
The region maps encode information about region relationships.
}
}
-fn resolve_block(blk: &ast::Block,
- (cx, visitor): (Context, oldvisit::vt<Context>)) {
+fn resolve_block(visitor: &mut RegionResolutionVisitor,
+ blk: &ast::Block,
+ cx: Context) {
// Record the parent of this block.
parent_to_expr(cx, blk.id, blk.span);
let new_cx = Context {var_parent: Some(blk.id),
parent: Some(blk.id),
..cx};
- oldvisit::visit_block(blk, (new_cx, visitor));
+ visit::walk_block(visitor, blk, new_cx);
}
-fn resolve_arm(arm: &ast::arm,
- (cx, visitor): (Context, oldvisit::vt<Context>)) {
- oldvisit::visit_arm(arm, (cx, visitor));
+fn resolve_arm(visitor: &mut RegionResolutionVisitor,
+ arm: &ast::arm,
+ cx: Context) {
+ visit::walk_arm(visitor, arm, cx);
}
-fn resolve_pat(pat: @ast::pat,
- (cx, visitor): (Context, oldvisit::vt<Context>)) {
+fn resolve_pat(visitor: &mut RegionResolutionVisitor,
+ pat: @ast::pat,
+ cx: Context) {
assert_eq!(cx.var_parent, cx.parent);
parent_to_expr(cx, pat.id, pat.span);
- oldvisit::visit_pat(pat, (cx, visitor));
+ visit::walk_pat(visitor, pat, cx);
}
-fn resolve_stmt(stmt: @ast::stmt,
- (cx, visitor): (Context, oldvisit::vt<Context>)) {
+fn resolve_stmt(visitor: &mut RegionResolutionVisitor,
+ stmt: @ast::stmt,
+ cx: Context) {
match stmt.node {
ast::stmt_decl(*) => {
- oldvisit::visit_stmt(stmt, (cx, visitor));
+ visit::walk_stmt(visitor, stmt, cx);
}
ast::stmt_expr(_, stmt_id) |
ast::stmt_semi(_, stmt_id) => {
parent_to_expr(cx, stmt_id, stmt.span);
let expr_cx = Context {parent: Some(stmt_id), ..cx};
- oldvisit::visit_stmt(stmt, (expr_cx, visitor));
+ visit::walk_stmt(visitor, stmt, expr_cx);
}
ast::stmt_mac(*) => cx.sess.bug("unexpanded macro")
}
}
-fn resolve_expr(expr: @ast::expr,
- (cx, visitor): (Context, oldvisit::vt<Context>)) {
+fn resolve_expr(visitor: &mut RegionResolutionVisitor,
+ expr: @ast::expr,
+ cx: Context) {
parent_to_expr(cx, expr.id, expr.span);
let mut new_cx = cx;
};
- oldvisit::visit_expr(expr, (new_cx, visitor));
+ visit::walk_expr(visitor, expr, new_cx);
}
-fn resolve_local(local: @ast::Local,
- (cx, visitor): (Context, oldvisit::vt<Context>)) {
+fn resolve_local(visitor: &mut RegionResolutionVisitor,
+ local: @ast::Local,
+ cx: Context) {
assert_eq!(cx.var_parent, cx.parent);
parent_to_expr(cx, local.id, local.span);
- oldvisit::visit_local(local, (cx, visitor));
+ visit::walk_local(visitor, local, cx);
}
-fn resolve_item(item: @ast::item,
- (cx, visitor): (Context, oldvisit::vt<Context>)) {
+fn resolve_item(visitor: &mut RegionResolutionVisitor,
+ item: @ast::item,
+ cx: Context) {
// Items create a new outer block scope as far as we're concerned.
let new_cx = Context {var_parent: None, parent: None, ..cx};
- oldvisit::visit_item(item, (new_cx, visitor));
+ visit::walk_item(visitor, item, new_cx);
}
-fn resolve_fn(fk: &oldvisit::fn_kind,
+fn resolve_fn(visitor: &mut RegionResolutionVisitor,
+ fk: &visit::fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
sp: span,
id: ast::NodeId,
- (cx, visitor): (Context,
- oldvisit::vt<Context>)) {
+ cx: Context) {
debug!("region::resolve_fn(id=%?, \
span=%?, \
body.id=%?, \
var_parent: Some(body.id),
..cx};
match *fk {
- oldvisit::fk_method(_, _, method) => {
+ visit::fk_method(_, _, method) => {
cx.region_maps.record_parent(method.self_id, body.id);
}
_ => {}
}
- oldvisit::visit_fn_decl(decl, (decl_cx, visitor));
+ visit::walk_fn_decl(visitor, decl, decl_cx);
// The body of the fn itself is either a root scope (top-level fn)
// or it continues with the inherited scope (closures).
let body_cx = match *fk {
- oldvisit::fk_item_fn(*) |
- oldvisit::fk_method(*) => {
+ visit::fk_item_fn(*) |
+ visit::fk_method(*) => {
Context {parent: None, var_parent: None, ..cx}
}
- oldvisit::fk_anon(*) |
- oldvisit::fk_fn_block(*) => {
+ visit::fk_anon(*) |
+ visit::fk_fn_block(*) => {
cx
}
};
- (visitor.visit_block)(body, (body_cx, visitor));
+ visitor.visit_block(body, body_cx);
+}
+
+struct RegionResolutionVisitor;
+
+impl Visitor<Context> for RegionResolutionVisitor {
+
+ fn visit_block(&mut self, b:&Block, cx:Context) {
+ resolve_block(self, b, cx);
+ }
+
+ fn visit_item(&mut self, i:@item, cx:Context) {
+ resolve_item(self, i, cx);
+ }
+
+ fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, b:&Block, s:span, n:NodeId, cx:Context) {
+ resolve_fn(self, fk, fd, b, s, n, cx);
+ }
+ fn visit_arm(&mut self, a:&arm, cx:Context) {
+ resolve_arm(self, a, cx);
+ }
+ fn visit_pat(&mut self, p:@pat, cx:Context) {
+ resolve_pat(self, p, cx);
+ }
+ fn visit_stmt(&mut self, s:@stmt, cx:Context) {
+ resolve_stmt(self, s, cx);
+ }
+ fn visit_expr(&mut self, ex:@expr, cx:Context) {
+ resolve_expr(self, ex, cx);
+ }
+ fn visit_local(&mut self, l:@Local, cx:Context) {
+ resolve_local(self, l, cx);
+ }
}
pub fn resolve_crate(sess: Session,
region_maps: region_maps,
parent: None,
var_parent: None};
- let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_block: resolve_block,
- visit_item: resolve_item,
- visit_fn: resolve_fn,
- visit_arm: resolve_arm,
- visit_pat: resolve_pat,
- visit_stmt: resolve_stmt,
- visit_expr: resolve_expr,
- visit_local: resolve_local,
- .. *oldvisit::default_visitor()
- });
- oldvisit::visit_crate(crate, (cx, visitor));
+ let mut visitor = RegionResolutionVisitor;
+ visit::walk_crate(&mut visitor, crate, cx);
return region_maps;
}
}
}
-fn determine_rp_in_item(item: @ast::item,
- (cx, visitor): (@mut DetermineRpCtxt,
- oldvisit::vt<@mut DetermineRpCtxt>)) {
+fn determine_rp_in_item(visitor: &mut DetermineRpVisitor,
+ item: @ast::item,
+ cx: @mut DetermineRpCtxt) {
do cx.with(item.id, true) {
- oldvisit::visit_item(item, (cx, visitor));
+ visit::walk_item(visitor, item, cx);
}
}
-fn determine_rp_in_fn(fk: &oldvisit::fn_kind,
+fn determine_rp_in_fn(visitor: &mut DetermineRpVisitor,
+ fk: &visit::fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
_: span,
_: ast::NodeId,
- (cx, visitor): (@mut DetermineRpCtxt,
- oldvisit::vt<@mut DetermineRpCtxt>)) {
+ cx: @mut DetermineRpCtxt) {
do cx.with(cx.item_id, false) {
do cx.with_ambient_variance(rv_contravariant) {
for a in decl.inputs.iter() {
- (visitor.visit_ty)(&a.ty, (cx, visitor));
+ visitor.visit_ty(&a.ty, cx);
}
}
- (visitor.visit_ty)(&decl.output, (cx, visitor));
- let generics = oldvisit::generics_of_fn(fk);
- (visitor.visit_generics)(&generics, (cx, visitor));
- (visitor.visit_block)(body, (cx, visitor));
+ visitor.visit_ty(&decl.output, cx);
+ let generics = visit::generics_of_fn(fk);
+ visitor.visit_generics(&generics, cx);
+ visitor.visit_block(body, cx);
}
}
-fn determine_rp_in_ty_method(ty_m: &ast::TypeMethod,
- (cx, visitor):
- (@mut DetermineRpCtxt,
- oldvisit::vt<@mut DetermineRpCtxt>)) {
+fn determine_rp_in_ty_method(visitor: &mut DetermineRpVisitor,
+ ty_m: &ast::TypeMethod,
+ cx: @mut DetermineRpCtxt) {
do cx.with(cx.item_id, false) {
- oldvisit::visit_ty_method(ty_m, (cx, visitor));
+ visit::walk_ty_method(visitor, ty_m, cx);
}
}
-fn determine_rp_in_ty(ty: &ast::Ty,
- (cx, visitor): (@mut DetermineRpCtxt,
- oldvisit::vt<@mut DetermineRpCtxt>)) {
+fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
+ ty: &ast::Ty,
+ cx: @mut DetermineRpCtxt) {
// we are only interested in types that will require an item to
// be region-parameterized. if cx.item_id is zero, then this type
// is not a member of a type defn nor is it a constitutent of an
match ty.node {
ast::ty_box(ref mt) | ast::ty_uniq(ref mt) | ast::ty_vec(ref mt) |
ast::ty_rptr(_, ref mt) | ast::ty_ptr(ref mt) => {
- visit_mt(mt, (cx, visitor));
+ visit_mt(visitor, mt, cx);
}
ast::ty_path(ref path, _, _) => {
// type parameters are---for now, anyway---always invariant
do cx.with_ambient_variance(rv_invariant) {
for tp in path.types.iter() {
- (visitor.visit_ty)(tp, (cx, visitor));
+ visitor.visit_ty(tp, cx);
}
}
}
// parameters are contravariant
do cx.with_ambient_variance(rv_contravariant) {
for a in decl.inputs.iter() {
- (visitor.visit_ty)(&a.ty, (cx, visitor));
+ visitor.visit_ty(&a.ty, cx);
}
}
- (visitor.visit_ty)(&decl.output, (cx, visitor));
+ visitor.visit_ty(&decl.output, cx);
}
}
_ => {
- oldvisit::visit_ty(ty, (cx, visitor));
+ visit::walk_ty(visitor, ty, cx);
}
}
- fn visit_mt(mt: &ast::mt,
- (cx, visitor): (@mut DetermineRpCtxt,
- oldvisit::vt<@mut DetermineRpCtxt>)) {
+ fn visit_mt(visitor: &mut DetermineRpVisitor,
+ mt: &ast::mt,
+ cx: @mut DetermineRpCtxt) {
// mutability is invariant
if mt.mutbl == ast::m_mutbl {
do cx.with_ambient_variance(rv_invariant) {
- (visitor.visit_ty)(mt.ty, (cx, visitor));
+ visitor.visit_ty(mt.ty, cx);
}
} else {
- (visitor.visit_ty)(mt.ty, (cx, visitor));
+ visitor.visit_ty(mt.ty, cx);
}
}
}
-fn determine_rp_in_struct_field(
- cm: @ast::struct_field,
- (cx, visitor): (@mut DetermineRpCtxt,
- oldvisit::vt<@mut DetermineRpCtxt>)) {
- oldvisit::visit_struct_field(cm, (cx, visitor));
+fn determine_rp_in_struct_field(visitor: &mut DetermineRpVisitor,
+ cm: @ast::struct_field,
+ cx: @mut DetermineRpCtxt) {
+ visit::walk_struct_field(visitor, cm, cx);
+}
+
+struct DetermineRpVisitor;
+
+impl Visitor<@mut DetermineRpCtxt> for DetermineRpVisitor {
+
+ fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl,
+ b:&Block, s:span, n:NodeId, e:@mut DetermineRpCtxt) {
+ determine_rp_in_fn(self, fk, fd, b, s, n, e);
+ }
+ fn visit_item(&mut self, i:@item, e:@mut DetermineRpCtxt) {
+ determine_rp_in_item(self, i, e);
+ }
+ fn visit_ty(&mut self, t:&Ty, e:@mut DetermineRpCtxt) {
+ determine_rp_in_ty(self, t, e);
+ }
+ fn visit_ty_method(&mut self, t:&TypeMethod, e:@mut DetermineRpCtxt) {
+ determine_rp_in_ty_method(self, t, e);
+ }
+ fn visit_struct_field(&mut self, s:@struct_field, e:@mut DetermineRpCtxt) {
+ determine_rp_in_struct_field(self, s, e);
+ }
+
}
pub fn determine_rp_in_crate(sess: Session,
};
// Gather up the base set, worklist and dep_map
- let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_fn: determine_rp_in_fn,
- visit_item: determine_rp_in_item,
- visit_ty: determine_rp_in_ty,
- visit_ty_method: determine_rp_in_ty_method,
- visit_struct_field: determine_rp_in_struct_field,
- .. *oldvisit::default_visitor()
- });
- oldvisit::visit_crate(crate, (cx, visitor));
+ let mut visitor = DetermineRpVisitor;
+ visit::walk_crate(&mut visitor, crate, cx);
// Propagate indirect dependencies
//
use syntax::ast_util::{Privacy, Public, Private};
use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy};
use syntax::attr;
-use syntax::oldvisit::{mk_simple_visitor, default_simple_visitor};
-use syntax::oldvisit::{default_visitor, mk_vt, Visitor, visit_block};
-use syntax::oldvisit::{visit_crate, visit_expr, visit_expr_opt};
-use syntax::oldvisit::{visit_foreign_item, visit_item};
-use syntax::oldvisit::{visit_mod, visit_ty, vt, SimpleVisitor};
use syntax::parse::token;
use syntax::parse::token::ident_interner;
use syntax::parse::token::special_idents;
use syntax::print::pprust::path_to_str;
use syntax::codemap::{span, dummy_sp, BytePos};
use syntax::opt_vec::OptVec;
+use syntax::visit;
+use syntax::visit::Visitor;
use std::str;
use std::uint;
HasSelfBinding(NodeId, bool /* is implicit */)
}
-pub type ResolveVisitor = vt<()>;
+struct ResolveVisitor {
+ resolver: @mut Resolver,
+}
+
+impl Visitor<()> for ResolveVisitor {
+ fn visit_item(&mut self, item:@item, _:()) {
+ self.resolver.resolve_item(item, self);
+ }
+ fn visit_arm(&mut self, arm:&arm, _:()) {
+ self.resolver.resolve_arm(arm, self);
+ }
+ fn visit_block(&mut self, block:&Block, _:()) {
+ self.resolver.resolve_block(block, self);
+ }
+ fn visit_expr(&mut self, expr:@expr, _:()) {
+ self.resolver.resolve_expr(expr, self);
+ }
+ fn visit_local(&mut self, local:@Local, _:()) {
+ self.resolver.resolve_local(local, self);
+ }
+ fn visit_ty(&mut self, ty:&Ty, _:()) {
+ self.resolver.resolve_type(ty, self);
+ }
+}
/// Contains data for specific types of import directives.
pub enum ImportDirectiveSubclass {
used_imports: HashSet<NodeId>,
}
+struct BuildReducedGraphVisitor {
+ resolver: @mut Resolver,
+}
+
+impl Visitor<ReducedGraphParent> for BuildReducedGraphVisitor {
+
+ fn visit_item(&mut self, item:@item, context:ReducedGraphParent) {
+ self.resolver.build_reduced_graph_for_item(item, (context, self));
+ }
+
+ fn visit_foreign_item(&mut self, foreign_item:@foreign_item, context:ReducedGraphParent) {
+ self.resolver.build_reduced_graph_for_foreign_item(foreign_item,
+ (context,
+ self));
+ }
+
+ fn visit_view_item(&mut self, view_item:&view_item, context:ReducedGraphParent) {
+ self.resolver.build_reduced_graph_for_view_item(view_item,
+ (context,
+ self));
+ }
+
+ fn visit_block(&mut self, block:&Block, context:ReducedGraphParent) {
+ self.resolver.build_reduced_graph_for_block(block,
+ (context,
+ self));
+ }
+
+}
+
+struct UnusedImportCheckVisitor { resolver: @mut Resolver }
+
+impl Visitor<()> for UnusedImportCheckVisitor {
+ fn visit_view_item(&mut self, vi:&view_item, _:()) {
+ self.resolver.check_for_item_unused_imports(vi);
+ visit::walk_view_item(self, vi, ());
+ }
+}
+
impl Resolver {
/// The main name resolution procedure.
pub fn resolve(@mut self) {
pub fn build_reduced_graph(@mut self) {
let initial_parent =
ModuleReducedGraphParent(self.graph_root.get_module());
- visit_crate(self.crate, (initial_parent, mk_vt(@Visitor {
- visit_item: |item, (context, visitor)|
- self.build_reduced_graph_for_item(item, (context, visitor)),
-
- visit_foreign_item: |foreign_item, (context, visitor)|
- self.build_reduced_graph_for_foreign_item(foreign_item,
- (context,
- visitor)),
-
- visit_view_item: |view_item, (context, visitor)|
- self.build_reduced_graph_for_view_item(view_item,
- (context,
- visitor)),
-
- visit_block: |block, (context, visitor)|
- self.build_reduced_graph_for_block(block,
- (context,
- visitor)),
- .. *default_visitor()
- })));
+ let mut visitor = BuildReducedGraphVisitor { resolver: self, };
+ visit::walk_crate(&mut visitor, self.crate, initial_parent);
}
/// Returns the current module tracked by the reduced graph parent.
pub fn build_reduced_graph_for_item(@mut self,
item: @item,
(parent, visitor): (ReducedGraphParent,
- vt<ReducedGraphParent>)) {
+ &mut BuildReducedGraphVisitor)) {
let ident = item.ident;
let sp = item.span;
let privacy = visibility_to_privacy(item.vis);
let new_parent =
ModuleReducedGraphParent(name_bindings.get_module());
- visit_mod(module_, sp, item.id, (new_parent, visitor));
+ visit::walk_mod(visitor, module_, new_parent);
}
item_foreign_mod(ref fm) => {
anonymous => parent
};
- visit_item(item, (new_parent, visitor));
+ visit::walk_item(visitor, item, new_parent);
}
// These items live in the value namespace.
let def = def_fn(local_def(item.id), purity);
name_bindings.define_value(privacy, def, sp);
- visit_item(item, (new_parent, visitor));
+ visit::walk_item(visitor, item, new_parent);
}
// These items live in the type namespace.
// inherited => privacy of the enum item
variant_visibility_to_privacy(variant.node.vis,
privacy == Public),
- (new_parent, visitor));
+ new_parent, visitor);
}
}
// Record the def ID of this struct.
self.structs.insert(local_def(item.id));
- visit_item(item, (new_parent, visitor));
+ visit::walk_item(visitor, item, new_parent);
}
item_impl(_, None, ref ty, ref methods) => {
_ => {}
}
- visit_item(item, (parent, visitor));
+ visit::walk_item(visitor, item, parent);
}
item_impl(_, Some(_), _, _) => {
- visit_item(item, (parent, visitor));
+ visit::walk_item(visitor, item, parent);
}
item_trait(_, _, ref methods) => {
}
name_bindings.define_type(privacy, def_trait(def_id), sp);
- visit_item(item, (new_parent, visitor));
+ visit::walk_item(visitor, item, new_parent);
}
item_mac(*) => {
variant: &variant,
item_id: def_id,
parent_privacy: Privacy,
- (parent, _visitor):
- (ReducedGraphParent,
- vt<ReducedGraphParent>)) {
+ parent: ReducedGraphParent,
+ _: &mut BuildReducedGraphVisitor) {
let ident = variant.node.name;
let privacy =
view_item: &view_item,
(parent, _):
(ReducedGraphParent,
- vt<ReducedGraphParent>)) {
+ &mut BuildReducedGraphVisitor)) {
let privacy = visibility_to_privacy(view_item.vis);
match view_item.node {
view_item_use(ref view_paths) => {
foreign_item: @foreign_item,
(parent, visitor):
(ReducedGraphParent,
- vt<ReducedGraphParent>)) {
+ &mut BuildReducedGraphVisitor)) {
let name = foreign_item.ident;
let (name_bindings, new_parent) =
self.add_child(name, parent, ForbidDuplicateValues,
HasTypeParameters(
generics, foreign_item.id, 0, NormalRibKind))
{
- visit_foreign_item(foreign_item, (new_parent, visitor));
+ visit::walk_foreign_item(visitor, foreign_item, new_parent);
}
}
foreign_item_static(_, m) => {
let def = def_static(local_def(foreign_item.id), m);
name_bindings.define_value(Public, def, foreign_item.span);
- visit_foreign_item(foreign_item, (new_parent, visitor));
+ visit::walk_foreign_item(visitor, foreign_item, new_parent);
}
}
}
block: &Block,
(parent, visitor):
(ReducedGraphParent,
- vt<ReducedGraphParent>)) {
+ &mut BuildReducedGraphVisitor)) {
let new_parent;
if self.block_needs_anonymous_module(block) {
let block_id = block.id;
new_parent = parent;
}
- visit_block(block, (new_parent, visitor));
+ visit::walk_block(visitor, block, new_parent);
}
pub fn handle_external_def(@mut self,
pub fn resolve_crate(@mut self) {
debug!("(resolving crate) starting");
- visit_crate(self.crate, ((), mk_vt(@Visitor {
- visit_item: |item, (_context, visitor)|
- self.resolve_item(item, visitor),
- visit_arm: |arm, (_context, visitor)|
- self.resolve_arm(arm, visitor),
- visit_block: |block, (_context, visitor)|
- self.resolve_block(block, visitor),
- visit_expr: |expr, (_context, visitor)|
- self.resolve_expr(expr, visitor),
- visit_local: |local, (_context, visitor)|
- self.resolve_local(local, visitor),
- visit_ty: |ty, (_context, visitor)|
- self.resolve_type(ty, visitor),
- .. *default_visitor()
- })));
+ let mut visitor = ResolveVisitor{ resolver: self };
+ visit::walk_crate(&mut visitor, self.crate, ());
}
- pub fn resolve_item(@mut self, item: @item, visitor: ResolveVisitor) {
+ pub fn resolve_item(@mut self, item: @item, visitor: &mut ResolveVisitor) {
debug!("(resolving item) resolving %s",
self.session.str_of(item.ident));
do self.with_type_parameter_rib(
HasTypeParameters(
generics, item.id, 0, NormalRibKind)) {
- visit_item(item, ((), visitor));
+ visit::walk_item(visitor, item, ());
}
}
NormalRibKind))
|| {
- visit_item(item, ((), visitor));
+ visit::walk_item(visitor, item, ());
}
}
HasTypeParameters(
generics, foreign_item.id, 0,
NormalRibKind),
- || visit_foreign_item(*foreign_item,
- ((), visitor)));
+ || visit::walk_foreign_item(visitor,
+ *foreign_item,
+ ()));
}
foreign_item_static(*) => {
- visit_foreign_item(*foreign_item,
- ((), visitor));
+ visit::walk_foreign_item(visitor,
+ *foreign_item,
+ ());
}
}
}
item_static(*) => {
self.with_constant_rib(|| {
- visit_item(item, ((), visitor));
+ visit::walk_item(visitor, item, ());
});
}
type_parameters: TypeParameters,
block: &Block,
self_binding: SelfBinding,
- visitor: ResolveVisitor) {
+ visitor: &mut ResolveVisitor) {
// Create a value rib for the function.
let function_value_rib = @Rib(rib_kind);
self.value_ribs.push(function_value_rib);
pub fn resolve_type_parameters(@mut self,
type_parameters: &OptVec<TyParam>,
- visitor: ResolveVisitor) {
+ visitor: &mut ResolveVisitor) {
for type_parameter in type_parameters.iter() {
for bound in type_parameter.bounds.iter() {
self.resolve_type_parameter_bound(type_parameter.id, bound, visitor);
pub fn resolve_type_parameter_bound(@mut self,
id: NodeId,
type_parameter_bound: &TyParamBound,
- visitor: ResolveVisitor) {
+ visitor: &mut ResolveVisitor) {
match *type_parameter_bound {
TraitTyParamBound(ref tref) => {
self.resolve_trait_reference(id, tref, visitor, TraitBoundingTypeParameter)
pub fn resolve_trait_reference(@mut self,
id: NodeId,
trait_reference: &trait_ref,
- visitor: ResolveVisitor,
+ visitor: &mut ResolveVisitor,
reference_type: TraitReferenceType) {
match self.resolve_path(id, &trait_reference.path, TypeNS, true, visitor) {
None => {
id: NodeId,
generics: &Generics,
fields: &[@struct_field],
- visitor: ResolveVisitor) {
+ visitor: &mut ResolveVisitor) {
let mut ident_map = HashMap::new::<ast::ident, @struct_field>();
for &field in fields.iter() {
match field.node.kind {
rib_kind: RibKind,
method: @method,
outer_type_parameter_count: uint,
- visitor: ResolveVisitor) {
+ visitor: &mut ResolveVisitor) {
let method_generics = &method.generics;
let type_parameters =
HasTypeParameters(method_generics,
opt_trait_reference: &Option<trait_ref>,
self_type: &Ty,
methods: &[@method],
- visitor: ResolveVisitor) {
+ visitor: &mut ResolveVisitor) {
// If applicable, create a rib for the type parameters.
let outer_type_parameter_count = generics.ty_params.len();
do self.with_type_parameter_rib(HasTypeParameters
pub fn resolve_module(@mut self,
module_: &_mod,
- span: span,
+ _span: span,
_name: ident,
id: NodeId,
- visitor: ResolveVisitor) {
+ visitor: &mut ResolveVisitor) {
// Write the implementations in scope into the module metadata.
debug!("(resolving module) resolving module ID %d", id);
- visit_mod(module_, span, id, ((), visitor));
+ visit::walk_mod(visitor, module_, ());
}
- pub fn resolve_local(@mut self, local: @Local, visitor: ResolveVisitor) {
+ pub fn resolve_local(@mut self, local: @Local, visitor: &mut ResolveVisitor) {
let mutability = if local.is_mutbl {Mutable} else {Immutable};
// Resolve the type.
}
}
- pub fn resolve_arm(@mut self, arm: &arm, visitor: ResolveVisitor) {
+ pub fn resolve_arm(@mut self, arm: &arm, visitor: &mut ResolveVisitor) {
self.value_ribs.push(@Rib(NormalRibKind));
let bindings_list = @mut HashMap::new();
// pat_idents are variants
self.check_consistent_bindings(arm);
- visit_expr_opt(arm.guard, ((), visitor));
+ visit::walk_expr_opt(visitor, arm.guard, ());
self.resolve_block(&arm.body, visitor);
self.value_ribs.pop();
}
- pub fn resolve_block(@mut self, block: &Block, visitor: ResolveVisitor) {
+ pub fn resolve_block(@mut self, block: &Block, visitor: &mut ResolveVisitor) {
debug!("(resolving block) entering block");
self.value_ribs.push(@Rib(NormalRibKind));
}
// Descend into the block.
- visit_block(block, ((), visitor));
+ visit::walk_block(visitor, block, ());
// Move back up.
self.current_module = orig_module;
debug!("(resolving block) leaving block");
}
- pub fn resolve_type(@mut self, ty: &Ty, visitor: ResolveVisitor) {
+ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
match ty.node {
// Like path expressions, the interpretation of path types depends
// on whether the path has multiple elements in it or not.
self.resolve_type_parameter_bound(ty.id, bound, visitor);
}
};
- visit_ty(ty, ((), visitor));
+ visit::walk_ty(visitor, ty, ());
}
_ => {
// Just resolve embedded types.
- visit_ty(ty, ((), visitor));
+ visit::walk_ty(visitor, ty, ());
}
}
}
// Maps idents to the node ID for the (outermost)
// pattern that binds them
bindings_list: Option<@mut HashMap<ident,NodeId>>,
- visitor: ResolveVisitor) {
+ visitor: &mut ResolveVisitor) {
let pat_id = pattern.id;
do walk_pat(pattern) |pattern| {
match pattern.node {
path: &Path,
namespace: Namespace,
check_ribs: bool,
- visitor: ResolveVisitor)
+ visitor: &mut ResolveVisitor)
-> Option<def> {
// First, resolve the types.
for ty in path.types.iter() {
return false;
}
- pub fn resolve_expr(@mut self, expr: @expr, visitor: ResolveVisitor) {
+ pub fn resolve_expr(@mut self, expr: @expr, visitor: &mut ResolveVisitor) {
// First, record candidate traits for this expression if it could
// result in the invocation of a method call.
}
}
- visit_expr(expr, ((), visitor));
+ visit::walk_expr(visitor, expr, ());
}
expr_fn_block(ref fn_decl, ref block) => {
}
}
- visit_expr(expr, ((), visitor));
+ visit::walk_expr(visitor, expr, ());
}
expr_loop(_, Some(label)) => {
rib.bindings.insert(label, def_like);
}
- visit_expr(expr, ((), visitor));
+ visit::walk_expr(visitor, expr, ());
}
}
}
_ => {
- visit_expr(expr, ((), visitor));
+ visit::walk_expr(visitor, expr, ());
}
}
}
//
pub fn check_for_unused_imports(@mut self) {
- let vt = mk_simple_visitor(@SimpleVisitor {
- visit_view_item: |vi| self.check_for_item_unused_imports(vi),
- .. *default_simple_visitor()
- });
- visit_crate(self.crate, ((), vt));
+ let mut visitor = UnusedImportCheckVisitor{ resolver: self };
+ visit::walk_crate(&mut visitor, self.crate, ());
}
pub fn check_for_item_unused_imports(&mut self, vi: &view_item) {
--- /dev/null
+// 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.
+
+/*!
+
+Lint mode to detect cases where we call non-Rust fns, which do not
+have a stack growth check, from locations not annotated to request
+large stacks.
+
+*/
+
+use middle::lint;
+use middle::ty;
+use syntax::ast;
+use syntax::ast_map;
+use syntax::attr;
+use syntax::codemap::span;
+use visit = syntax::oldvisit;
+use util::ppaux::Repr;
+
+#[deriving(Clone)]
+struct Context {
+ tcx: ty::ctxt,
+ safe_stack: bool
+}
+
+pub fn stack_check_crate(tcx: ty::ctxt,
+ crate: &ast::Crate) {
+ let new_cx = Context {
+ tcx: tcx,
+ safe_stack: false
+ };
+ let visitor = visit::mk_vt(@visit::Visitor {
+ visit_item: stack_check_item,
+ visit_fn: stack_check_fn,
+ visit_expr: stack_check_expr,
+ ..*visit::default_visitor()
+ });
+ visit::visit_crate(crate, (new_cx, visitor));
+}
+
+fn stack_check_item(item: @ast::item,
+ (in_cx, v): (Context, visit::vt<Context>)) {
+ match item.node {
+ ast::item_fn(_, ast::extern_fn, _, _, _) => {
+ // an extern fn is already being called from C code...
+ let new_cx = Context {safe_stack: true, ..in_cx};
+ visit::visit_item(item, (new_cx, v));
+ }
+ ast::item_fn(*) => {
+ let safe_stack = fixed_stack_segment(item.attrs);
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+ visit::visit_item(item, (new_cx, v));
+ }
+ ast::item_impl(_, _, _, ref methods) => {
+ // visit_method() would make this nicer
+ for &method in methods.iter() {
+ let safe_stack = fixed_stack_segment(method.attrs);
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+ visit::visit_method_helper(method, (new_cx, v));
+ }
+ }
+ _ => {
+ visit::visit_item(item, (in_cx, v));
+ }
+ }
+
+ fn fixed_stack_segment(attrs: &[ast::Attribute]) -> bool {
+ attr::contains_name(attrs, "fixed_stack_segment")
+ }
+}
+
+fn stack_check_fn<'a>(fk: &visit::fn_kind,
+ decl: &ast::fn_decl,
+ body: &ast::Block,
+ sp: span,
+ id: ast::NodeId,
+ (in_cx, v): (Context, visit::vt<Context>)) {
+ let safe_stack = match *fk {
+ visit::fk_method(*) | visit::fk_item_fn(*) => {
+ in_cx.safe_stack // see stack_check_item above
+ }
+ visit::fk_anon(*) | visit::fk_fn_block => {
+ match ty::get(ty::node_id_to_type(in_cx.tcx, id)).sty {
+ ty::ty_bare_fn(*) |
+ ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) |
+ ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
+ false
+ }
+ _ => {
+ in_cx.safe_stack
+ }
+ }
+ }
+ };
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+ debug!("stack_check_fn(safe_stack=%b, id=%?)", safe_stack, id);
+ visit::visit_fn(fk, decl, body, sp, id, (new_cx, v));
+}
+
+fn stack_check_expr<'a>(expr: @ast::expr,
+ (cx, v): (Context, visit::vt<Context>)) {
+ debug!("stack_check_expr(safe_stack=%b, expr=%s)",
+ cx.safe_stack, expr.repr(cx.tcx));
+ if !cx.safe_stack {
+ match expr.node {
+ ast::expr_call(callee, _, _) => {
+ let callee_ty = ty::expr_ty(cx.tcx, callee);
+ debug!("callee_ty=%s", callee_ty.repr(cx.tcx));
+ match ty::get(callee_ty).sty {
+ ty::ty_bare_fn(ref fty) => {
+ if !fty.abis.is_rust() && !fty.abis.is_intrinsic() {
+ call_to_extern_fn(cx, callee);
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+ visit::visit_expr(expr, (cx, v));
+}
+
+fn call_to_extern_fn(cx: Context, callee: @ast::expr) {
+ // Permit direct calls to extern fns that are annotated with
+ // #[rust_stack]. This is naturally a horrible pain to achieve.
+ match callee.node {
+ ast::expr_path(*) => {
+ match cx.tcx.def_map.find(&callee.id) {
+ Some(&ast::def_fn(id, _)) if id.crate == ast::LOCAL_CRATE => {
+ match cx.tcx.items.find(&id.node) {
+ Some(&ast_map::node_foreign_item(item, _, _, _)) => {
+ if attr::contains_name(item.attrs, "rust_stack") {
+ return;
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+
+ cx.tcx.sess.add_lint(lint::cstack,
+ callee.id,
+ callee.span,
+ fmt!("invoking non-Rust fn in fn without \
+ #[fixed_stack_segment]"));
+}
bindings_map: @BindingsMap
}
+/**
+ * Info about Match.
+ * If all `pats` are matched then arm `data` will be executed.
+ * As we proceed `bound_ptrs` are filled with pointers to values to be bound,
+ * these pointers are stored in llmatch variables just before executing `data` arm.
+ */
#[deriving(Clone)]
struct Match<'self> {
pats: ~[@ast::pat],
- data: ArmData<'self>
+ data: ArmData<'self>,
+ bound_ptrs: ~[(ident, ValueRef)]
}
impl<'self> Repr for Match<'self> {
br.pats.slice(col + 1u,
br.pats.len())));
- let binding_info =
- br.data.bindings_map.get(&path_to_ident(path));
-
- Store(bcx, val, binding_info.llmatch);
- Match {
+ let mut res = Match {
pats: pats,
- data: br.data.clone()
- }
+ data: br.data.clone(),
+ bound_ptrs: br.bound_ptrs.clone()
+ };
+ res.bound_ptrs.push((path_to_ident(path), val));
+ res
}
_ => (*br).clone(),
}
br.pats.slice(col + 1u, br.pats.len()));
let this = br.pats[col];
+ let mut bound_ptrs = br.bound_ptrs.clone();
match this.node {
ast::pat_ident(_, ref path, None) => {
if pat_is_binding(dm, this) {
- let binding_info =
- br.data.bindings_map.get(
- &path_to_ident(path));
- Store(bcx, val, binding_info.llmatch);
+ bound_ptrs.push((path_to_ident(path), val));
}
}
_ => {}
result.push(Match {
pats: pats,
- data: br.data.clone()
+ data: br.data.clone(),
+ bound_ptrs: bound_ptrs
});
}
None => ()
fn insert_lllocals(bcx: @mut Block,
bindings_map: &BindingsMap,
- binding_mode: IrrefutablePatternBindingMode,
add_cleans: bool) -> @mut Block {
/*!
* For each binding in `data.bindings_map`, adds an appropriate entry into
* the bindings.
*/
- let llmap = match binding_mode {
- BindLocal => bcx.fcx.lllocals,
- BindArgument => bcx.fcx.llargs
- };
+ let llmap = bcx.fcx.lllocals;
for (&ident, &binding_info) in bindings_map.iter() {
let llval = match binding_info.trmode {
bcx = store_non_ref_bindings(bcx,
data.bindings_map,
Some(&mut temp_cleanups));
- bcx = insert_lllocals(bcx, data.bindings_map, BindLocal, false);
+ bcx = insert_lllocals(bcx, data.bindings_map, false);
let val = unpack_result!(bcx, {
do with_scope_result(bcx, guard_expr.info(),
}
if m[0].pats.len() == 0u {
let data = &m[0].data;
+ for &(ref ident, ref value_ptr) in m[0].bound_ptrs.iter() {
+ let llmatch = data.bindings_map.get(ident).llmatch;
+ Store(bcx, *value_ptr, llmatch);
+ }
match data.arm.guard {
Some(guard_expr) => {
bcx = compile_guard(bcx,
matches.push(Match {
pats: ~[*p],
data: arm_data.clone(),
+ bound_ptrs: ~[],
});
}
}
}
// insert bindings into the lllocals map and add cleanups
- bcx = insert_lllocals(bcx, arm_data.bindings_map, BindLocal, true);
+ bcx = insert_lllocals(bcx, arm_data.bindings_map, true);
bcx = controlflow::trans_block(bcx, &arm_data.arm.body, dest);
bcx = trans_block_cleanups(bcx, block_cleanups(arm_data.bodycx));
ast::asm_intel => lib::llvm::AD_Intel
};
- let r = do ia.asm.to_c_str().with_ref |a| {
- do constraints.to_c_str().with_ref |c| {
+ let r = do ia.asm.with_c_str |a| {
+ do constraints.with_c_str |c| {
InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect)
}
};
use std::hashmap::HashMap;
use std::io;
use std::libc::c_uint;
-use std::uint;
use std::vec;
use std::local_data;
use extra::time;
use syntax::parse::token;
use syntax::parse::token::{special_idents};
use syntax::print::pprust::stmt_to_str;
-use syntax::oldvisit;
+use syntax::visit;
use syntax::{ast, ast_util, codemap, ast_map};
use syntax::abi::{X86, X86_64, Arm, Mips};
fn fcx_has_nonzero_span(fcx: &FunctionContext) -> bool {
match fcx.span {
- None => true,
+ None => false,
Some(span) => *span.lo != 0 || *span.hi != 0
}
}
}
pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
- let llfn: ValueRef = do name.to_c_str().with_ref |buf| {
+ let llfn: ValueRef = do name.with_c_str |buf| {
unsafe {
llvm::LLVMGetOrInsertFunction(llmod, buf, ty.to_ref())
}
return llfn;
}
-pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: @str,
+pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
- match externs.find_copy(&name) {
- Some(n) => return n,
+ match externs.find_equiv(&name) {
+ Some(n) => return *n,
None => ()
}
let f = decl_fn(llmod, name, cc, ty);
- externs.insert(name, f);
+ externs.insert(name.to_owned(), f);
return f;
}
pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
- name: @str, ty: Type) -> ValueRef {
- match externs.find_copy(&name) {
- Some(n) => return n,
+ name: &str, ty: Type) -> ValueRef {
+ match externs.find_equiv(&name) {
+ Some(n) => return *n,
None => ()
}
unsafe {
- let c = do name.to_c_str().with_ref |buf| {
+ let c = do name.with_c_str |buf| {
llvm::LLVMAddGlobal(llmod, ty.to_ref(), buf)
};
- externs.insert(name, c);
+ externs.insert(name.to_owned(), c);
return c;
}
}
lib::llvm::SetFunctionAttribute(f, lib::llvm::InlineHintAttribute)
}
-pub fn set_inline_hint_if_appr(attrs: &[ast::Attribute],
- llfn: ValueRef) {
+pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) {
use syntax::attr::*;
+ // Set the inline hint if there is one
match find_inline_attr(attrs) {
InlineHint => set_inline_hint(llfn),
InlineAlways => set_always_inline(llfn),
InlineNever => set_no_inline(llfn),
InlineNone => { /* fallthrough */ }
}
+
+ // Add the no-split-stack attribute if requested
+ if contains_name(attrs, "no_split_stack") {
+ set_no_split_stack(llfn);
+ }
}
pub fn set_always_inline(f: ValueRef) {
}
pub fn set_fixed_stack_segment(f: ValueRef) {
- lib::llvm::SetFixedStackSegmentAttribute(f);
+ do "fixed-stack-segment".to_c_str().with_ref |buf| {
+ unsafe { llvm::LLVMAddFunctionAttrString(f, buf); }
+ }
+}
+
+pub fn set_no_split_stack(f: ValueRef) {
+ do "no-split-stack".to_c_str().with_ref |buf| {
+ unsafe { llvm::LLVMAddFunctionAttrString(f, buf); }
+ }
}
pub fn set_glue_inlining(f: ValueRef, t: ty::t) {
None,
ty::lookup_item_type(tcx, parent_id).ty);
let llty = type_of_dtor(ccx, class_ty);
- let name = name.to_managed(); // :-(
get_extern_fn(&mut ccx.externs,
ccx.llmod,
name,
// Structural comparison: a rather involved form of glue.
pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
if cx.sess.opts.save_temps {
- do s.to_c_str().with_ref |buf| {
+ do s.with_c_str |buf| {
unsafe {
llvm::LLVMSetValueName(v, buf)
}
for variant in (*variants).iter() {
let variant_cx =
sub_block(cx, ~"enum-iter-variant-" +
- uint::to_str(variant.disr_val));
+ variant.disr_val.to_str());
let variant_cx =
iter_variant(variant_cx, repr, av, *variant,
substs.tps, |x,y,z| f(x,y,z));
}
}
-pub fn null_env_ptr(bcx: @mut Block) -> ValueRef {
- C_null(Type::opaque_box(bcx.ccx()).ptr_to())
+pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
+ C_null(Type::opaque_box(ccx).ptr_to())
}
pub fn trans_external_path(ccx: &mut CrateContext, did: ast::def_id, t: ty::t)
-> ValueRef {
- let name = csearch::get_symbol(ccx.sess.cstore, did).to_managed(); // Sad
+ let name = csearch::get_symbol(ccx.sess.cstore, did);
match ty::get(t).sty {
ty::ty_bare_fn(_) | ty::ty_closure(_) => {
let llty = type_of_fn_from_ty(ccx, t);
opt_node_info: Option<NodeInfo>)
-> @mut Block {
unsafe {
- let llbb = do name.to_c_str().with_ref |buf| {
+ let llbb = do name.with_c_str |buf| {
llvm::LLVMAppendBasicBlockInContext(cx.ccx.llcx, cx.llfn, buf)
};
let bcx = @mut Block::new(llbb,
pub fn mk_staticallocas_basic_block(llfn: ValueRef) -> BasicBlockRef {
unsafe {
let cx = task_llcx();
- do "static_allocas".to_c_str().with_ref | buf| {
+ do "static_allocas".with_c_str | buf| {
llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)
}
}
pub fn mk_return_basic_block(llfn: ValueRef) -> BasicBlockRef {
unsafe {
let cx = task_llcx();
- do "return".to_c_str().with_ref |buf| {
+ do "return".with_c_str |buf| {
llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)
}
}
// slot where the return value of the function must go.
pub fn make_return_pointer(fcx: @mut FunctionContext, output_type: ty::t) -> ValueRef {
unsafe {
- if !ty::type_is_immediate(fcx.ccx.tcx, output_type) {
+ if type_of::return_uses_outptr(fcx.ccx.tcx, output_type) {
llvm::LLVMGetParam(fcx.llfn, 0)
} else {
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
ty::subst_tps(ccx.tcx, substs.tys, substs.self_ty, output_type)
}
};
- let is_immediate = ty::type_is_immediate(ccx.tcx, substd_output_type);
+ let uses_outptr = type_of::return_uses_outptr(ccx.tcx, substd_output_type);
let fcx = @mut FunctionContext {
llfn: llfndecl,
llenv: unsafe {
llreturn: None,
llself: None,
personality: None,
- loop_ret: None,
- has_immediate_return_value: is_immediate,
+ caller_expects_out_pointer: uses_outptr,
llargs: @mut HashMap::new(),
lllocals: @mut HashMap::new(),
llupvars: @mut HashMap::new(),
fcx.alloca_insert_pt = Some(llvm::LLVMGetFirstInstruction(entry_bcx.llbb));
}
- if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) {
- fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
+ if !ty::type_is_voidish(substd_output_type) {
+ // If the function returns nil/bot, there is no real return
+ // value, so do not set `llretptr`.
+ if !skip_retptr || uses_outptr {
+ // Otherwise, we normally allocate the llretptr, unless we
+ // have been instructed to skip it for immediate return
+ // values.
+ fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
+ }
}
fcx
}
fcx.llself = Some(ValSelfData {v: self_val, ..slf});
add_clean(bcx, self_val, slf.t);
+
+ if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
+ debuginfo::create_self_argument_metadata(bcx, slf.t, self_val);
+ }
}
_ => {}
}
// Builds the return block for a function.
pub fn build_return_block(fcx: &FunctionContext, ret_cx: @mut Block) {
// Return the value if this function immediate; otherwise, return void.
- if fcx.llretptr.is_none() || !fcx.has_immediate_return_value {
+ if fcx.llretptr.is_none() || fcx.caller_expects_out_pointer {
return RetVoid(ret_cx);
}
id: ast::NodeId,
attributes: &[ast::Attribute],
output_type: ty::t,
- maybe_load_env: &fn(@mut FunctionContext),
- finish: &fn(@mut Block)) {
+ maybe_load_env: &fn(@mut FunctionContext)) {
ccx.stats.n_closures += 1;
let _icx = push_ctxt("trans_closure");
set_uwtable(llfndecl);
set_fixed_stack_segment(fcx.llfn);
}
+ if ccx.sess.opts.debuginfo && fcx_has_nonzero_span(fcx) {
+ debuginfo::create_function_metadata(fcx);
+ }
+
// Create the first basic block in the function and keep a handle on it to
// pass to finish_fn later.
let bcx_top = fcx.entry_bcx.unwrap();
// translation calls that don't have a return value (trans_crate,
// trans_mod, trans_item, et cetera) and those that do
// (trans_block, trans_expr, et cetera).
- if body.expr.is_none() || ty::type_is_bot(block_ty) ||
- ty::type_is_nil(block_ty)
- {
+ if body.expr.is_none() || ty::type_is_voidish(block_ty) {
bcx = controlflow::trans_block(bcx, body, expr::Ignore);
} else {
let dest = expr::SaveIn(fcx.llretptr.unwrap());
bcx = controlflow::trans_block(bcx, body, dest);
}
- finish(bcx);
match fcx.llreturn {
Some(llreturn) => cleanup_and_Br(bcx, bcx_top, llreturn),
None => bcx = cleanup_block(bcx, Some(bcx_top.llbb))
id,
attrs,
output_type,
- |fcx| {
- if ccx.sess.opts.debuginfo
- && fcx_has_nonzero_span(fcx) {
- debuginfo::create_function_metadata(fcx);
- }
- },
- |_bcx| { });
+ |_fcx| { });
}
fn insert_synthetic_type_entries(bcx: @mut Block,
ast::item_fn(ref decl, purity, _abis, ref generics, ref body) => {
if purity == ast::extern_fn {
let llfndecl = get_item_val(ccx, item.id);
- foreign::trans_foreign_fn(ccx,
- vec::append((*path).clone(),
- [path_name(item.ident)]),
- decl,
- body,
- llfndecl,
- item.id);
+ foreign::trans_rust_fn_with_foreign_abi(
+ ccx,
+ &vec::append((*path).clone(),
+ [path_name(item.ident)]),
+ decl,
+ body,
+ llfndecl,
+ item.id);
} else if !generics.is_type_parameterized() {
let llfndecl = get_item_val(ccx, item.id);
trans_fn(ccx,
}
},
ast::item_foreign_mod(ref foreign_mod) => {
- foreign::trans_foreign_mod(ccx, path, foreign_mod);
+ foreign::trans_foreign_mod(ccx, foreign_mod);
}
ast::item_struct(struct_def, ref generics) => {
if !generics.is_type_parameterized() {
fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
let nt = ty::mk_nil();
-
- let llfty = type_of_fn(ccx, [], nt);
+ let llfty = type_of_rust_fn(ccx, [], nt);
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
lib::llvm::CCallConv, llfty);
// the args vector built in create_entry_fn will need
// be updated if this assertion starts to fail.
- assert!(fcx.has_immediate_return_value);
+ assert!(!fcx.caller_expects_out_pointer);
let bcx = fcx.entry_bcx.unwrap();
// Call main.
};
decl_cdecl_fn(ccx.llmod, main_name, llfty)
};
- let llbb = do "top".to_c_str().with_ref |buf| {
+ let llbb = do "top".with_c_str |buf| {
unsafe {
llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
}
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
let crate_map = ccx.crate_map;
- let opaque_crate_map = do "crate_map".to_c_str().with_ref |buf| {
+ let opaque_crate_map = do "crate_map".with_c_str |buf| {
llvm::LLVMBuildPointerCast(bld, crate_map, Type::i8p().to_ref(), buf)
};
};
let args = {
- let opaque_rust_main = do "rust_main".to_c_str().with_ref |buf| {
+ let opaque_rust_main = do "rust_main".with_c_str |buf| {
llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p().to_ref(), buf)
};
unsafe {
let llty = llvm::LLVMTypeOf(v);
- let g = do sym.to_c_str().with_ref |buf| {
+ let g = do sym.with_c_str |buf| {
llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
};
let llfn = if purity != ast::extern_fn {
register_fn(ccx, i.span, sym, i.id, ty)
} else {
- foreign::register_foreign_fn(ccx, i.span, sym, i.id)
+ foreign::register_rust_fn_with_foreign_abi(ccx,
+ i.span,
+ sym,
+ i.id)
};
- set_inline_hint_if_appr(i.attrs, llfn);
+ set_llvm_fn_attrs(i.attrs, llfn);
llfn
}
match (attr::first_attr_value_str_by_name(i.attrs, "link_section")) {
Some(sect) => unsafe {
- do sect.to_c_str().with_ref |buf| {
+ do sect.with_c_str |buf| {
llvm::LLVMSetSection(v, buf);
}
},
register_method(ccx, id, pth, m)
}
- ast_map::node_foreign_item(ni, _, _, pth) => {
+ ast_map::node_foreign_item(ni, abis, _, pth) => {
let ty = ty::node_id_to_type(ccx.tcx, ni.id);
exprt = true;
match ni.node {
ast::foreign_item_fn(*) => {
let path = vec::append((*pth).clone(), [path_name(ni.ident)]);
- let sym = exported_name(ccx, path, ty, ni.attrs);
-
- register_fn(ccx, ni.span, sym, ni.id, ty)
+ foreign::register_foreign_item_fn(ccx, abis, &path, ni)
}
ast::foreign_item_static(*) => {
let ident = token::ident_to_str(&ni.ident);
- let g = do ident.to_c_str().with_ref |buf| {
+ let g = do ident.with_c_str |buf| {
unsafe {
let ty = type_of(ccx, ty);
llvm::LLVMAddGlobal(ccx.llmod, ty.to_ref(), buf)
let sym = exported_name(ccx, path, mty, m.attrs);
let llfn = register_fn(ccx, m.span, sym, id, mty);
- set_inline_hint_if_appr(m.attrs, llfn);
+ set_llvm_fn_attrs(m.attrs, llfn);
llfn
}
let s = mangle_exported_name(ccx, p, ty::mk_int()).to_managed();
let disr_val = vi[i].disr_val;
note_unique_llvm_symbol(ccx, s);
- let discrim_gvar = do s.to_c_str().with_ref |buf| {
+ let discrim_gvar = do s.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf)
}
}
}
+struct TransConstantsVisitor { ccx: @mut CrateContext }
+
+impl visit::Visitor<()> for TransConstantsVisitor {
+ fn visit_item(&mut self, i:@ast::item, _:()) {
+ trans_constant(self.ccx, i);
+ visit::walk_item(self, i, ());
+ }
+}
+
pub fn trans_constants(ccx: @mut CrateContext, crate: &ast::Crate) {
- oldvisit::visit_crate(
- crate, ((),
- oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
- visit_item: |a| trans_constant(ccx, a),
- ..*oldvisit::default_simple_visitor()
- })));
+ let mut v = TransConstantsVisitor { ccx: ccx };
+ visit::walk_crate(&mut v, crate, ());
}
pub fn vp2i(cx: @mut Block, v: ValueRef) -> ValueRef {
}
let gc_metadata_name = ~"_gc_module_metadata_" + llmod_id;
- let gc_metadata = do gc_metadata_name.to_c_str().with_ref |buf| {
+ let gc_metadata = do gc_metadata_name.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf)
}
pub fn create_module_map(ccx: &mut CrateContext) -> ValueRef {
let elttype = Type::struct_([ccx.int_type, ccx.int_type], false);
let maptype = Type::array(&elttype, (ccx.module_data.len() + 1) as u64);
- let map = do "_rust_mod_map".to_c_str().with_ref |buf| {
+ let map = do "_rust_mod_map".with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, maptype.to_ref(), buf)
}
let sym_name = ~"_rust_crate_map_" + mapname;
let arrtype = Type::array(&int_type, n_subcrates as u64);
let maptype = Type::struct_([Type::i32(), Type::i8p(), int_type, arrtype], false);
- let map = do sym_name.to_c_str().with_ref |buf| {
+ let map = do sym_name.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(llmod, maptype.to_ref(), buf)
}
cdata.name,
cstore::get_crate_vers(cstore, i),
cstore::get_crate_hash(cstore, i));
- let cr = do nm.to_c_str().with_ref |buf| {
+ let cr = do nm.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf)
}
}
subcrates.push(C_int(ccx, 0));
- let llannihilatefn = match ccx.tcx.lang_items.annihilate_fn() {
- Some(annihilate_def_id) => {
- if annihilate_def_id.crate == ast::LOCAL_CRATE {
- get_item_val(ccx, annihilate_def_id.node)
- } else {
- let annihilate_fn_type = csearch::get_type(ccx.tcx,
- annihilate_def_id).ty;
- trans_external_path(ccx, annihilate_def_id, annihilate_fn_type)
- }
- }
- None => { C_null(Type::i8p()) }
- };
-
unsafe {
let mod_map = create_module_map(ccx);
llvm::LLVMSetInitializer(map, C_struct(
[C_i32(1),
- lib::llvm::llvm::LLVMConstPointerCast(llannihilatefn, Type::i8p().to_ref()),
+ // FIXME #8431 This used to be the annihilate function, now it's nothing
+ C_null(Type::i8p()),
p2i(ccx, mod_map),
C_array(ccx.int_type, subcrates)]));
}
let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item);
let llmeta = C_bytes(encoder::encode_metadata(encode_parms, crate));
let llconst = C_struct([llmeta]);
- let mut llglobal = do "rust_metadata".to_c_str().with_ref |buf| {
+ let mut llglobal = do "rust_metadata".with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst).to_ref(), buf)
}
};
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
- do cx.sess.targ_cfg.target_strs.meta_sect_name.to_c_str().with_ref |buf| {
+ do cx.sess.targ_cfg.target_strs.meta_sect_name.with_c_str |buf| {
llvm::LLVMSetSection(llglobal, buf)
};
lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
let t_ptr_i8 = Type::i8p();
llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8.to_ref());
- let llvm_used = do "llvm.used".to_c_str().with_ref |buf| {
+ let llvm_used = do "llvm.used".with_c_str |buf| {
llvm::LLVMAddGlobal(cx.llmod, Type::array(&t_ptr_i8, 1).to_ref(), buf)
};
lib::llvm::SetLinkage(llvm_used, lib::llvm::AppendingLinkage);
internal: bool)
-> ValueRef {
unsafe {
- let llglobal = do name.to_c_str().with_ref |buf| {
+ let llglobal = do name.with_c_str |buf| {
llvm::LLVMAddGlobal(ccx.llmod, val_ty(llval).to_ref(), buf)
};
llvm::LLVMSetInitializer(llglobal, llval);
if name.is_empty() {
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
} else {
- do name.to_c_str().with_ref |c| {
+ do name.with_c_str |c| {
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c)
}
}
let sanitized = text.replace("$", "");
let comment_text = fmt!("# %s", sanitized.replace("\n", "\n\t# "));
self.count_insn("inlineasm");
- let asm = do comment_text.to_c_str().with_ref |c| {
+ let asm = do comment_text.with_c_str |c| {
unsafe {
llvm::LLVMConstInlineAsm(Type::func([], &Type::void()).to_ref(),
c, noname(), False, False)
let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder);
let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB);
let M: ModuleRef = llvm::LLVMGetGlobalParent(FN);
- let T: ValueRef = do "llvm.trap".to_c_str().with_ref |buf| {
+ let T: ValueRef = do "llvm.trap".with_c_str |buf| {
llvm::LLVMGetNamedFunction(M, buf)
};
assert!((T as int != 0));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use lib::llvm::{llvm, ValueRef, Attribute, Void};
-use middle::trans::base::*;
-use middle::trans::build::*;
-use middle::trans::common::*;
-
-use middle::trans::type_::Type;
-
-use std::libc::c_uint;
+use lib::llvm::Attribute;
use std::option;
-
-pub trait ABIInfo {
- fn compute_info(&self, atys: &[Type], rty: Type, ret_def: bool) -> FnType;
-}
+use middle::trans::context::CrateContext;
+use middle::trans::cabi_x86;
+use middle::trans::cabi_x86_64;
+use middle::trans::cabi_arm;
+use middle::trans::cabi_mips;
+use middle::trans::type_::Type;
+use syntax::abi::{X86, X86_64, Arm, Mips};
#[deriving(Clone)]
pub struct LLVMType {
ty: Type
}
+/// Metadata describing how the arguments to a native function
+/// should be passed in order to respect the native ABI.
+///
+/// I will do my best to describe this structure, but these
+/// comments are reverse-engineered and may be inaccurate. -NDM
pub struct FnType {
+ /// The LLVM types of each argument. If the cast flag is true,
+ /// then the argument should be cast, typically because the
+ /// official argument type will be an int and the rust type is i8
+ /// or something like that.
arg_tys: ~[LLVMType],
- ret_ty: LLVMType,
- attrs: ~[option::Option<Attribute>],
- sret: bool
-}
-
-impl FnType {
- pub fn decl_fn(&self, decl: &fn(fnty: Type) -> ValueRef) -> ValueRef {
- let atys = self.arg_tys.iter().map(|t| t.ty).collect::<~[Type]>();
- let rty = self.ret_ty.ty;
- let fnty = Type::func(atys, &rty);
- let llfn = decl(fnty);
-
- for (i, a) in self.attrs.iter().enumerate() {
- match *a {
- option::Some(attr) => {
- unsafe {
- let llarg = get_param(llfn, i);
- llvm::LLVMAddAttribute(llarg, attr as c_uint);
- }
- }
- _ => ()
- }
- }
- return llfn;
- }
- pub fn build_shim_args(&self, bcx: @mut Block, arg_tys: &[Type], llargbundle: ValueRef)
- -> ~[ValueRef] {
- let mut atys: &[LLVMType] = self.arg_tys;
- let mut attrs: &[option::Option<Attribute>] = self.attrs;
-
- let mut llargvals = ~[];
- let mut i = 0u;
- let n = arg_tys.len();
-
- if self.sret {
- let llretptr = GEPi(bcx, llargbundle, [0u, n]);
- let llretloc = Load(bcx, llretptr);
- llargvals = ~[llretloc];
- atys = atys.tail();
- attrs = attrs.tail();
- }
-
- while i < n {
- let llargval = if atys[i].cast {
- let arg_ptr = GEPi(bcx, llargbundle, [0u, i]);
- let arg_ptr = BitCast(bcx, arg_ptr, atys[i].ty.ptr_to());
- Load(bcx, arg_ptr)
- } else if attrs[i].is_some() {
- GEPi(bcx, llargbundle, [0u, i])
- } else {
- load_inbounds(bcx, llargbundle, [0u, i])
- };
- llargvals.push(llargval);
- i += 1u;
- }
-
- return llargvals;
- }
-
- pub fn build_shim_ret(&self, bcx: @mut Block, arg_tys: &[Type], ret_def: bool,
- llargbundle: ValueRef, llretval: ValueRef) {
- for (i, a) in self.attrs.iter().enumerate() {
- match *a {
- option::Some(attr) => {
- unsafe {
- llvm::LLVMAddInstrAttribute(llretval, (i + 1u) as c_uint, attr as c_uint);
- }
- }
- _ => ()
- }
- }
- if self.sret || !ret_def {
- return;
- }
- let n = arg_tys.len();
- // R** llretptr = &args->r;
- let llretptr = GEPi(bcx, llargbundle, [0u, n]);
- // R* llretloc = *llretptr; /* (args->r) */
- let llretloc = Load(bcx, llretptr);
- if self.ret_ty.cast {
- let tmp_ptr = BitCast(bcx, llretloc, self.ret_ty.ty.ptr_to());
- // *args->r = r;
- Store(bcx, llretval, tmp_ptr);
- } else {
- // *args->r = r;
- Store(bcx, llretval, llretloc);
- };
- }
-
- pub fn build_wrap_args(&self, bcx: @mut Block, ret_ty: Type,
- llwrapfn: ValueRef, llargbundle: ValueRef) {
- let mut atys: &[LLVMType] = self.arg_tys;
- let mut attrs: &[option::Option<Attribute>] = self.attrs;
- let mut j = 0u;
- let llretptr = if self.sret {
- atys = atys.tail();
- attrs = attrs.tail();
- j = 1u;
- get_param(llwrapfn, 0u)
- } else if self.ret_ty.cast {
- let retptr = alloca(bcx, self.ret_ty.ty, "");
- BitCast(bcx, retptr, ret_ty.ptr_to())
- } else {
- alloca(bcx, ret_ty, "")
- };
+ /// A list of attributes to be attached to each argument (parallel
+ /// the `arg_tys` array). If the attribute for a given is Some,
+ /// then the argument should be passed by reference.
+ attrs: ~[option::Option<Attribute>],
- let mut i = 0u;
- let n = atys.len();
- while i < n {
- let mut argval = get_param(llwrapfn, i + j);
- if attrs[i].is_some() {
- argval = Load(bcx, argval);
- store_inbounds(bcx, argval, llargbundle, [0u, i]);
- } else if atys[i].cast {
- let argptr = GEPi(bcx, llargbundle, [0u, i]);
- let argptr = BitCast(bcx, argptr, atys[i].ty.ptr_to());
- Store(bcx, argval, argptr);
- } else {
- store_inbounds(bcx, argval, llargbundle, [0u, i]);
- }
- i += 1u;
- }
- store_inbounds(bcx, llretptr, llargbundle, [0u, n]);
- }
+ /// LLVM return type.
+ ret_ty: LLVMType,
- pub fn build_wrap_ret(&self, bcx: @mut Block, arg_tys: &[Type], llargbundle: ValueRef) {
- if self.ret_ty.ty.kind() == Void {
- return;
- }
+ /// If true, then an implicit pointer should be added for the result.
+ sret: bool
+}
- if bcx.fcx.llretptr.is_some() {
- let llretval = load_inbounds(bcx, llargbundle, [ 0, arg_tys.len() ]);
- let llretval = if self.ret_ty.cast {
- let retptr = BitCast(bcx, llretval, self.ret_ty.ty.ptr_to());
- Load(bcx, retptr)
- } else {
- Load(bcx, llretval)
- };
- let llretptr = BitCast(bcx, bcx.fcx.llretptr.unwrap(), self.ret_ty.ty.ptr_to());
- Store(bcx, llretval, llretptr);
- }
+pub fn compute_abi_info(ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
+ match ccx.sess.targ_cfg.arch {
+ X86 => cabi_x86::compute_abi_info(ccx, atys, rty, ret_def),
+ X86_64 => cabi_x86_64::compute_abi_info(ccx, atys, rty, ret_def),
+ Arm => cabi_arm::compute_abi_info(ccx, atys, rty, ret_def),
+ Mips => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
}
}
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
use lib::llvm::{Attribute, StructRetAttribute};
-use middle::trans::cabi::{ABIInfo, FnType, LLVMType};
+use middle::trans::cabi::{FnType, LLVMType};
+use middle::trans::context::CrateContext;
use middle::trans::type_::Type;
}
}
-enum ARM_ABIInfo { ARM_ABIInfo }
-
-impl ABIInfo for ARM_ABIInfo {
- fn compute_info(&self,
- atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
- let mut arg_tys = ~[];
- let mut attrs = ~[];
- for &aty in atys.iter() {
- let (ty, attr) = classify_arg_ty(aty);
- arg_tys.push(ty);
- attrs.push(attr);
- }
-
- let (ret_ty, ret_attr) = if ret_def {
- classify_ret_ty(rty)
- } else {
- (LLVMType { cast: false, ty: Type::void() }, None)
- };
+pub fn compute_abi_info(_ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
+ let mut arg_tys = ~[];
+ let mut attrs = ~[];
+ for &aty in atys.iter() {
+ let (ty, attr) = classify_arg_ty(aty);
+ arg_tys.push(ty);
+ attrs.push(attr);
+ }
- let mut ret_ty = ret_ty;
+ let (ret_ty, ret_attr) = if ret_def {
+ classify_ret_ty(rty)
+ } else {
+ (LLVMType { cast: false, ty: Type::void() }, None)
+ };
- let sret = ret_attr.is_some();
- if sret {
- arg_tys.unshift(ret_ty);
- attrs.unshift(ret_attr);
- ret_ty = LLVMType { cast: false, ty: Type::void() };
- }
+ let mut ret_ty = ret_ty;
- return FnType {
- arg_tys: arg_tys,
- ret_ty: ret_ty,
- attrs: attrs,
- sret: sret
- };
+ let sret = ret_attr.is_some();
+ if sret {
+ arg_tys.unshift(ret_ty);
+ attrs.unshift(ret_attr);
+ ret_ty = LLVMType { cast: false, ty: Type::void() };
}
-}
-pub fn abi_info() -> @ABIInfo {
- return @ARM_ABIInfo as @ABIInfo;
+ return FnType {
+ arg_tys: arg_tys,
+ ret_ty: ret_ty,
+ attrs: attrs,
+ sret: sret
+ };
}
use std::vec;
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
use lib::llvm::{Attribute, StructRetAttribute};
+use middle::trans::context::CrateContext;
use middle::trans::context::task_llcx;
use middle::trans::cabi::*;
return Type::struct_(fields, false);
}
-enum MIPS_ABIInfo { MIPS_ABIInfo }
-
-impl ABIInfo for MIPS_ABIInfo {
- fn compute_info(&self,
- atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
- let (ret_ty, ret_attr) = if ret_def {
- classify_ret_ty(rty)
- } else {
- (LLVMType { cast: false, ty: Type::void() }, None)
- };
-
- let mut ret_ty = ret_ty;
-
- let sret = ret_attr.is_some();
- let mut arg_tys = ~[];
- let mut attrs = ~[];
- let mut offset = if sret { 4 } else { 0 };
-
- for aty in atys.iter() {
- let (ty, attr) = classify_arg_ty(*aty, &mut offset);
- arg_tys.push(ty);
- attrs.push(attr);
- };
-
- if sret {
- arg_tys = vec::append(~[ret_ty], arg_tys);
- attrs = vec::append(~[ret_attr], attrs);
- ret_ty = LLVMType { cast: false, ty: Type::void() };
- }
+pub fn compute_abi_info(_ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
+ let (ret_ty, ret_attr) = if ret_def {
+ classify_ret_ty(rty)
+ } else {
+ (LLVMType { cast: false, ty: Type::void() }, None)
+ };
+
+ let mut ret_ty = ret_ty;
+
+ let sret = ret_attr.is_some();
+ let mut arg_tys = ~[];
+ let mut attrs = ~[];
+ let mut offset = if sret { 4 } else { 0 };
- return FnType {
- arg_tys: arg_tys,
- ret_ty: ret_ty,
- attrs: attrs,
- sret: sret
- };
+ for aty in atys.iter() {
+ let (ty, attr) = classify_arg_ty(*aty, &mut offset);
+ arg_tys.push(ty);
+ attrs.push(attr);
+ };
+
+ if sret {
+ arg_tys = vec::append(~[ret_ty], arg_tys);
+ attrs = vec::append(~[ret_attr], attrs);
+ ret_ty = LLVMType { cast: false, ty: Type::void() };
}
-}
-pub fn abi_info() -> @ABIInfo {
- return @MIPS_ABIInfo as @ABIInfo;
+ return FnType {
+ arg_tys: arg_tys,
+ ret_ty: ret_ty,
+ attrs: attrs,
+ sret: sret
+ };
}
use super::cabi::*;
use super::common::*;
use super::machine::*;
-
use middle::trans::type_::Type;
-struct X86_ABIInfo {
- ccx: @mut CrateContext
-}
+pub fn compute_abi_info(ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
+ let mut arg_tys = ~[];
+ let mut attrs = ~[];
-impl ABIInfo for X86_ABIInfo {
- fn compute_info(&self,
- atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
- let mut arg_tys = do atys.map |a| {
- LLVMType { cast: false, ty: *a }
- };
- let mut ret_ty = LLVMType {
+ let ret_ty;
+ let sret;
+ if !ret_def {
+ ret_ty = LLVMType {
cast: false,
- ty: rty
+ ty: Type::void(),
};
- let mut attrs = do atys.map |_| {
- None
- };
-
- // Rules for returning structs taken from
+ sret = false;
+ } else if rty.kind() == Struct {
+ // Returning a structure. Most often, this will use
+ // a hidden first argument. On some platforms, though,
+ // small structs are returned as integers.
+ //
+ // Some links:
// http://www.angelcode.com/dev/callconv/callconv.html
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
- let sret = {
- let returning_a_struct = rty.kind() == Struct && ret_def;
- let big_struct = match self.ccx.sess.targ_cfg.os {
- os_win32 | os_macos => llsize_of_alloc(self.ccx, rty) > 8,
- _ => true
- };
- returning_a_struct && big_struct
+
+ enum Strategy { RetValue(Type), RetPointer }
+ let strategy = match ccx.sess.targ_cfg.os {
+ os_win32 | os_macos => {
+ match llsize_of_alloc(ccx, rty) {
+ 1 => RetValue(Type::i8()),
+ 2 => RetValue(Type::i16()),
+ 4 => RetValue(Type::i32()),
+ 8 => RetValue(Type::i64()),
+ _ => RetPointer
+ }
+ }
+ _ => {
+ RetPointer
+ }
};
- if sret {
- let ret_ptr_ty = LLVMType {
- cast: false,
- ty: ret_ty.ty.ptr_to()
- };
- arg_tys = ~[ret_ptr_ty] + arg_tys;
- attrs = ~[Some(StructRetAttribute)] + attrs;
- ret_ty = LLVMType {
- cast: false,
- ty: Type::void(),
- };
- } else if !ret_def {
- ret_ty = LLVMType {
- cast: false,
- ty: Type::void()
- };
- }
+ match strategy {
+ RetValue(t) => {
+ ret_ty = LLVMType {
+ cast: true,
+ ty: t
+ };
+ sret = false;
+ }
+ RetPointer => {
+ arg_tys.push(LLVMType {
+ cast: false,
+ ty: rty.ptr_to()
+ });
+ attrs.push(Some(StructRetAttribute));
- return FnType {
- arg_tys: arg_tys,
- ret_ty: ret_ty,
- attrs: attrs,
- sret: sret
+ ret_ty = LLVMType {
+ cast: false,
+ ty: Type::void(),
+ };
+ sret = true;
+ }
+ }
+ } else {
+ ret_ty = LLVMType {
+ cast: false,
+ ty: rty
};
+ sret = false;
+ }
+
+ for &a in atys.iter() {
+ arg_tys.push(LLVMType { cast: false, ty: a });
+ attrs.push(None);
}
-}
-pub fn abi_info(ccx: @mut CrateContext) -> @ABIInfo {
- return @X86_ABIInfo {
- ccx: ccx
- } as @ABIInfo;
+ return FnType {
+ arg_tys: arg_tys,
+ ret_ty: ret_ty,
+ attrs: attrs,
+ sret: sret
+ };
}
use lib::llvm::{Struct, Array, Attribute};
use lib::llvm::{StructRetAttribute, ByValAttribute};
use middle::trans::cabi::*;
+use middle::trans::context::CrateContext;
use middle::trans::type_::Type;
return Type::struct_(tys, false);
}
-fn x86_64_tys(atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
-
+pub fn compute_abi_info(_ccx: &mut CrateContext,
+ atys: &[Type],
+ rty: Type,
+ ret_def: bool) -> FnType {
fn x86_64_ty(ty: Type,
is_mem_cls: &fn(cls: &[RegClass]) -> bool,
attr: Attribute) -> (LLVMType, Option<Attribute>) {
sret: sret
};
}
-
-enum X86_64_ABIInfo { X86_64_ABIInfo }
-
-impl ABIInfo for X86_64_ABIInfo {
- fn compute_info(&self,
- atys: &[Type],
- rty: Type,
- ret_def: bool) -> FnType {
- return x86_64_tys(atys, rty, ret_def);
- }
-}
-
-pub fn abi_info() -> @ABIInfo {
- return @X86_64_ABIInfo as @ABIInfo;
-}
use middle::trans::meth;
use middle::trans::monomorphize;
use middle::trans::type_of;
+use middle::trans::foreign;
use middle::ty;
use middle::subst::Subst;
use middle::typeck;
use middle::trans::type_::Type;
use syntax::ast;
+use syntax::abi::AbiSet;
use syntax::ast_map;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
// Represents a (possibly monomorphized) top-level fn item or method
// item. Note that this is just the fn-ptr and is not a Rust closure
type_params: &[ty::t], // values for fn's ty params
vtables: Option<typeck::vtable_res>) // vtables for the call
-> FnData {
- //!
- //
- // Translates a reference to a fn/method item, monomorphizing and
- // inlining as it goes.
- //
- // # Parameters
- //
- // - `bcx`: the current block where the reference to the fn occurs
- // - `def_id`: def id of the fn or method item being referenced
- // - `ref_id`: node id of the reference to the fn/method, if applicable.
- // This parameter may be zero; but, if so, the resulting value may not
- // have the right type, so it must be cast before being used.
- // - `type_params`: values for each of the fn/method's type parameters
- // - `vtables`: values for each bound on each of the type parameters
+ /*!
+ * Translates a reference to a fn/method item, monomorphizing and
+ * inlining as it goes.
+ *
+ * # Parameters
+ *
+ * - `bcx`: the current block where the reference to the fn occurs
+ * - `def_id`: def id of the fn or method item being referenced
+ * - `ref_id`: node id of the reference to the fn/method, if applicable.
+ * This parameter may be zero; but, if so, the resulting value may not
+ * have the right type, so it must be cast before being used.
+ * - `type_params`: values for each of the fn/method's type parameters
+ * - `vtables`: values for each bound on each of the type parameters
+ */
let _icx = push_ctxt("trans_fn_ref_with_vtables");
let ccx = bcx.ccx();
}
// Find the actual function pointer.
- let val = {
+ let mut val = {
if def_id.crate == ast::LOCAL_CRATE {
// Internal reference.
get_item_val(ccx, def_id.node)
}
};
+ // This is subtle and surprising, but sometimes we have to bitcast
+ // the resulting fn pointer. The reason has to do with external
+ // functions. If you have two crates that both bind the same C
+ // library, they may not use precisely the same types: for
+ // example, they will probably each declare their own structs,
+ // which are distinct types from LLVM's point of view (nominal
+ // types).
+ //
+ // Now, if those two crates are linked into an application, and
+ // they contain inlined code, you can wind up with a situation
+ // where both of those functions wind up being loaded into this
+ // application simultaneously. In that case, the same function
+ // (from LLVM's point of view) requires two types. But of course
+ // LLVM won't allow one function to have two types.
+ //
+ // What we currently do, therefore, is declare the function with
+ // one of the two types (whichever happens to come first) and then
+ // bitcast as needed when the function is referenced to make sure
+ // it has the type we expect.
+ //
+ // This can occur on either a crate-local or crate-external
+ // reference. It also occurs when testing libcore and in some
+ // other weird situations. Annoying.
+ let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
+ let llptrty = llty.ptr_to();
+ if val_ty(val) != llptrty {
+ val = BitCast(bcx, val, llptrty);
+ }
+
return FnData {llfn: val};
}
ArgVals(args), Some(dest), DontAutorefArg).bcx;
}
-pub fn body_contains_ret(body: &ast::Block) -> bool {
- let cx = @mut false;
- oldvisit::visit_block(body, (cx, oldvisit::mk_vt(@oldvisit::Visitor {
- visit_item: |_i, (_cx, _v)| { },
- visit_expr: |e: @ast::expr,
- (cx, v): (@mut bool, oldvisit::vt<@mut bool>)| {
+
+struct CalleeTranslationVisitor;
+
+impl Visitor<@mut bool> for CalleeTranslationVisitor {
+
+ fn visit_item(&mut self, _:@ast::item, _:@mut bool) { }
+
+ fn visit_expr(&mut self, e:@ast::expr, cx:@mut bool) {
+
if !*cx {
match e.node {
ast::expr_ret(_) => *cx = true,
- _ => oldvisit::visit_expr(e, (cx, v)),
+ _ => visit::walk_expr(self, e, cx),
}
}
- },
- ..*oldvisit::default_visitor()
- })));
+ }
+
+}
+
+pub fn body_contains_ret(body: &ast::Block) -> bool {
+ let cx = @mut false;
+ let mut v = CalleeTranslationVisitor;
+ visit::walk_block(&mut v, body, cx);
*cx
}
-// See [Note-arg-mode]
pub fn trans_call_inner(in_cx: @mut Block,
call_info: Option<NodeInfo>,
- fn_expr_ty: ty::t,
+ callee_ty: ty::t,
ret_ty: ty::t,
get_callee: &fn(@mut Block) -> Callee,
args: CallArgs,
dest: Option<expr::Dest>,
autoref_arg: AutorefArg)
-> Result {
+ /*!
+ * This behemoth of a function translates function calls.
+ * Unfortunately, in order to generate more efficient LLVM
+ * output at -O0, it has quite a complex signature (refactoring
+ * this into two functions seems like a good idea).
+ *
+ * In particular, for lang items, it is invoked with a dest of
+ * None, and
+ */
+
+
do base::with_scope_result(in_cx, call_info, "call") |cx| {
let callee = get_callee(cx);
let mut bcx = callee.bcx;
}
};
- let llretslot = trans_ret_slot(bcx, fn_expr_ty, dest);
+ let abi = match ty::get(callee_ty).sty {
+ ty::ty_bare_fn(ref f) => f.abis,
+ _ => AbiSet::Rust()
+ };
+ let is_rust_fn =
+ abi.is_rust() ||
+ abi.is_intrinsic();
+
+ // Generate a location to store the result. If the user does
+ // not care about the result, just make a stack slot.
+ let opt_llretslot = match dest {
+ None => {
+ assert!(!type_of::return_uses_outptr(in_cx.tcx(), ret_ty));
+ None
+ }
+ Some(expr::SaveIn(dst)) => Some(dst),
+ Some(expr::Ignore) => {
+ if !ty::type_is_voidish(ret_ty) {
+ Some(alloc_ty(bcx, ret_ty, "__llret"))
+ } else {
+ unsafe {
+ Some(llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()))
+ }
+ }
+ }
+ };
+
+ let mut llresult = unsafe {
+ llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref())
+ };
- let mut llargs = ~[];
+ // The code below invokes the function, using either the Rust
+ // conventions (if it is a rust fn) or the native conventions
+ // (otherwise). The important part is that, when all is sad
+ // and done, either the return value of the function will have been
+ // written in opt_llretslot (if it is Some) or `llresult` will be
+ // set appropriately (otherwise).
+ if is_rust_fn {
+ let mut llargs = ~[];
+
+ // Push the out-pointer if we use an out-pointer for this
+ // return type, otherwise push "undef".
+ if type_of::return_uses_outptr(in_cx.tcx(), ret_ty) {
+ llargs.push(opt_llretslot.unwrap());
+ }
- if !ty::type_is_immediate(bcx.tcx(), ret_ty) {
- llargs.push(llretslot);
- }
+ // Push the environment.
+ llargs.push(llenv);
- llargs.push(llenv);
- bcx = trans_args(bcx, args, fn_expr_ty, autoref_arg, &mut llargs);
+ // Push the arguments.
+ bcx = trans_args(bcx, args, callee_ty,
+ autoref_arg, &mut llargs);
- // Now that the arguments have finished evaluating, we need to revoke
- // the cleanup for the self argument
- match callee.data {
- Method(d) => {
- for &v in d.temp_cleanup.iter() {
- revoke_clean(bcx, v);
+ // Now that the arguments have finished evaluating, we
+ // need to revoke the cleanup for the self argument
+ match callee.data {
+ Method(d) => {
+ for &v in d.temp_cleanup.iter() {
+ revoke_clean(bcx, v);
+ }
}
+ _ => {}
}
- _ => {}
- }
- // Uncomment this to debug calls.
- /*
- printfln!("calling: %s", bcx.val_to_str(llfn));
- for llarg in llargs.iter() {
- printfln!("arg: %s", bcx.val_to_str(*llarg));
+ // Invoke the actual rust fn and update bcx/llresult.
+ let (llret, b) = base::invoke(bcx, llfn, llargs);
+ bcx = b;
+ llresult = llret;
+
+ // If the Rust convention for this type is return via
+ // the return value, copy it into llretslot.
+ match opt_llretslot {
+ Some(llretslot) => {
+ if !type_of::return_uses_outptr(bcx.tcx(), ret_ty) &&
+ !ty::type_is_voidish(ret_ty)
+ {
+ Store(bcx, llret, llretslot);
+ }
+ }
+ None => {}
+ }
+ } else {
+ // Lang items are the only case where dest is None, and
+ // they are always Rust fns.
+ assert!(dest.is_some());
+
+ let mut llargs = ~[];
+ bcx = trans_args(bcx, args, callee_ty,
+ autoref_arg, &mut llargs);
+ bcx = foreign::trans_native_call(bcx, callee_ty,
+ llfn, opt_llretslot.unwrap(), llargs);
}
- io::println("---");
- */
-
- // If the block is terminated, then one or more of the args
- // has type _|_. Since that means it diverges, the code for
- // the call itself is unreachable.
- let (llresult, new_bcx) = base::invoke(bcx, llfn, llargs);
- bcx = new_bcx;
+ // If the caller doesn't care about the result of this fn call,
+ // drop the temporary slot we made.
match dest {
- None => { assert!(ty::type_is_immediate(bcx.tcx(), ret_ty)) }
+ None => {
+ assert!(!type_of::return_uses_outptr(bcx.tcx(), ret_ty));
+ }
Some(expr::Ignore) => {
// drop the value if it is not being saved.
- if ty::type_needs_drop(bcx.tcx(), ret_ty) {
- if ty::type_is_immediate(bcx.tcx(), ret_ty) {
- let llscratchptr = alloc_ty(bcx, ret_ty, "__ret");
- Store(bcx, llresult, llscratchptr);
- bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
- } else {
- bcx = glue::drop_ty(bcx, llretslot, ret_ty);
- }
- }
- }
- Some(expr::SaveIn(lldest)) => {
- // If this is an immediate, store into the result location.
- // (If this was not an immediate, the result will already be
- // directly written into the output slot.)
- if ty::type_is_immediate(bcx.tcx(), ret_ty) {
- Store(bcx, llresult, lldest);
- }
+ bcx = glue::drop_ty(bcx, opt_llretslot.unwrap(), ret_ty);
}
+ Some(expr::SaveIn(_)) => { }
}
if ty::type_is_bot(ret_ty) {
Unreachable(bcx);
}
+
rslt(bcx, llresult)
}
}
-
pub enum CallArgs<'self> {
ArgExprs(&'self [@ast::expr]),
ArgVals(&'self [ValueRef])
}
-pub fn trans_ret_slot(bcx: @mut Block, fn_ty: ty::t, dest: Option<expr::Dest>)
- -> ValueRef {
- let retty = ty::ty_fn_ret(fn_ty);
-
- match dest {
- Some(expr::SaveIn(dst)) => dst,
- _ => {
- if ty::type_is_immediate(bcx.tcx(), retty) {
- unsafe {
- llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref())
- }
- } else {
- alloc_ty(bcx, retty, "__trans_ret_slot")
- }
- }
- }
-}
-
pub fn trans_args(cx: @mut Block,
args: CallArgs,
fn_ty: ty::t,
if formal_arg_ty != arg_datum.ty {
// this could happen due to e.g. subtyping
- let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, &formal_arg_ty);
+ let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
debug!("casting actual type (%s) to match formal (%s)",
bcx.val_to_str(val), bcx.llty_str(llformal_arg_ty));
val = PointerCast(bcx, val, llformal_arg_ty);
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::common::*;
-use middle::trans::datum::{Datum, INIT, ByRef, ZeroMem};
+use middle::trans::datum::{Datum, INIT};
use middle::trans::expr;
use middle::trans::glue;
use middle::trans::type_of::*;
use middle::ty;
use util::ppaux::ty_to_str;
-use middle::trans::type_::Type;
-
use std::vec;
use syntax::ast;
use syntax::ast_map::path_name;
// collects the upvars and packages them up for store_environment.
pub fn build_closure(bcx0: @mut Block,
cap_vars: &[moves::CaptureVar],
- sigil: ast::Sigil,
- include_ret_handle: Option<ValueRef>) -> ClosureResult {
+ sigil: ast::Sigil) -> ClosureResult {
let _icx = push_ctxt("closure::build_closure");
// If we need to, package up the iterator body to call
}
}
- // If this is a `for` loop body, add two special environment
- // variables:
- for flagptr in include_ret_handle.iter() {
- // Flag indicating we have returned (a by-ref bool):
- let flag_datum = Datum {val: *flagptr, ty: ty::mk_bool(),
- mode: ByRef(ZeroMem)};
- env_vals.push(EnvValue {action: EnvRef,
- datum: flag_datum});
-
- // Return value (we just pass a by-ref () and cast it later to
- // the right thing):
- let ret_true = match bcx.fcx.loop_ret {
- Some((_, retptr)) => retptr,
- None => match bcx.fcx.llretptr {
- None => C_null(Type::nil().ptr_to()),
- Some(retptr) => PointerCast(bcx, retptr, Type::nil().ptr_to()),
- }
- };
- let ret_datum = Datum {val: ret_true, ty: ty::mk_nil(),
- mode: ByRef(ZeroMem)};
- env_vals.push(EnvValue {action: EnvRef,
- datum: ret_datum});
- }
-
return store_environment(bcx, env_vals, sigil);
}
pub fn load_environment(fcx: @mut FunctionContext,
cdata_ty: ty::t,
cap_vars: &[moves::CaptureVar],
- load_ret_handle: bool,
sigil: ast::Sigil) {
let _icx = push_ctxt("closure::load_environment");
// Don't bother to create the block if there's nothing to load
- if cap_vars.len() == 0 && !load_ret_handle {
+ if cap_vars.len() == 0 {
return;
}
fcx.llupvars.insert(def_id.node, upvarptr);
i += 1u;
}
- if load_ret_handle {
- let flagptr = Load(bcx, GEPi(bcx, llcdata, [0u, i]));
- let retptr = Load(bcx,
- GEPi(bcx, llcdata, [0u, i+1u]));
- fcx.loop_ret = Some((flagptr, retptr));
- }
}
pub fn trans_expr_fn(bcx: @mut Block,
body: &ast::Block,
outer_id: ast::NodeId,
user_id: ast::NodeId,
- is_loop_body: Option<Option<ValueRef>>,
dest: expr::Dest) -> @mut Block {
/*!
*
* - `user_id`: The id of the closure as the user expressed it.
Generally the same as `outer_id`
* - `cap_clause`: information about captured variables, if any.
- * - `is_loop_body`: `Some()` if this is part of a `for` loop.
* - `dest`: where to write the closure value, which must be a
(fn ptr, env) pair
*/
"expr_fn");
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
- // Always mark inline if this is a loop body. This is important for
- // performance on many programs with tight loops.
- if is_loop_body.is_some() {
- set_always_inline(llfn);
- } else {
- // Can't hurt.
- set_inline_hint(llfn);
- }
-
- let real_return_type = if is_loop_body.is_some() {
- ty::mk_bool()
- } else {
- ty::ty_fn_ret(fty)
- };
+ // set an inline hint for all closures
+ set_inline_hint(llfn);
let Result {bcx: bcx, val: closure} = match sigil {
ast::BorrowedSigil | ast::ManagedSigil | ast::OwnedSigil => {
let cap_vars = ccx.maps.capture_map.get_copy(&user_id);
- let ret_handle = match is_loop_body {Some(x) => x,
- None => None};
let ClosureResult {llbox, cdata_ty, bcx}
- = build_closure(bcx, cap_vars, sigil, ret_handle);
+ = build_closure(bcx, cap_vars, sigil);
trans_closure(ccx,
sub_path,
decl,
bcx.fcx.param_substs,
user_id,
[],
- real_return_type,
- |fcx| load_environment(fcx, cdata_ty, cap_vars,
- ret_handle.is_some(), sigil),
- |bcx| {
- if is_loop_body.is_some() {
- Store(bcx,
- C_bool(true),
- bcx.fcx.llretptr.unwrap());
- }
- });
+ ty::ty_fn_ret(fty),
+ |fcx| load_environment(fcx, cdata_ty, cap_vars, sigil));
rslt(bcx, llbox)
}
};
use std::cast::transmute;
use std::cast;
use std::hashmap::{HashMap};
-use std::libc::{c_uint, c_longlong, c_ulonglong};
+use std::libc::{c_uint, c_longlong, c_ulonglong, c_char};
use std::vec;
use syntax::ast::ident;
use syntax::ast_map::{path, path_elt};
}
}
-pub type ExternMap = HashMap<@str, ValueRef>;
+pub type ExternMap = HashMap<~str, ValueRef>;
// Types used for llself.
pub struct ValSelfData {
// The a value alloca'd for calls to upcalls.rust_personality. Used when
// outputting the resume instruction.
personality: Option<ValueRef>,
- // If this is a for-loop body that returns, this holds the pointers needed
- // for that (flagptr, retptr)
- loop_ret: Option<(ValueRef, ValueRef)>,
- // True if this function has an immediate return value, false otherwise.
- // If this is false, the llretptr will alias the first argument of the
- // function.
- has_immediate_return_value: bool,
+ // True if the caller expects this fn to use the out pointer to
+ // return. Either way, your code should write into llretptr, but if
+ // this value is false, llretptr will be a local alloca.
+ caller_expects_out_pointer: bool,
// Maps arguments to allocas created for them in llallocas.
llargs: @mut HashMap<ast::NodeId, ValueRef>,
impl FunctionContext {
pub fn arg_pos(&self, arg: uint) -> uint {
- if self.has_immediate_return_value {
- arg + 1u
- } else {
+ if self.caller_expects_out_pointer {
arg + 2u
+ } else {
+ arg + 1u
}
}
pub fn out_arg_pos(&self) -> uint {
- assert!(!self.has_immediate_return_value);
+ assert!(self.caller_expects_out_pointer);
0u
}
pub fn env_arg_pos(&self) -> uint {
- if !self.has_immediate_return_value {
+ if self.caller_expects_out_pointer {
1u
} else {
0u
pub fn C_floating(s: &str, t: Type) -> ValueRef {
unsafe {
- do s.to_c_str().with_ref |buf| {
+ do s.with_c_str |buf| {
llvm::LLVMConstRealOfString(t.to_ref(), buf)
}
}
None => ()
}
- let sc = do s.to_c_str().with_ref |buf| {
- llvm::LLVMConstStringInContext(cx.llcx, buf, s.len() as c_uint, False)
+ let sc = do s.as_imm_buf |buf, buflen| {
+ llvm::LLVMConstStringInContext(cx.llcx, buf as *c_char, buflen as c_uint, False)
};
let gsym = token::gensym("str");
- let g = do fmt!("str%u", gsym).to_c_str().with_ref |buf| {
+ let g = do fmt!("str%u", gsym).with_c_str |buf| {
llvm::LLVMAddGlobal(cx.llmod, val_ty(sc).to_ref(), buf)
};
llvm::LLVMSetInitializer(g, sc);
raw_vtables.map_move(|vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts))
}
+// Apply the typaram substitutions in the FunctionContext to some
+// vtables. This should eliminate any vtable_params.
pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, vts: typeck::vtable_res)
-> typeck::vtable_res {
resolve_vtables_under_param_substs(fcx.ccx.tcx,
-// Apply the typaram substitutions in the FunctionContext to a vtable. This should
-// eliminate any vtable_params.
-pub fn resolve_vtable_in_fn_ctxt(fcx: &FunctionContext, vt: &typeck::vtable_origin)
- -> typeck::vtable_origin {
- resolve_vtable_under_param_substs(fcx.ccx.tcx,
- fcx.param_substs,
- vt)
-}
-
pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
param_substs: Option<@param_substs>,
vt: &typeck::vtable_origin)
}
_ => {
tcx.sess.bug(fmt!(
- "resolve_vtable_in_fn_ctxt: asked to lookup but \
- no vtables in the fn_ctxt!"))
+ "resolve_vtable_under_param_substs: asked to lookup \
+ but no vtables in the fn_ctxt!"))
}
}
}
use std::c_str::ToCStr;
use std::libc::c_uint;
+use std::vec;
use syntax::{ast, ast_util, ast_map};
pub fn const_lit(cx: &mut CrateContext, e: &ast::expr, lit: ast::lit)
fn const_addr_of(cx: &mut CrateContext, cv: ValueRef) -> ValueRef {
unsafe {
- let gv = do "const".to_c_str().with_ref |name| {
+ let gv = do "const".with_c_str |name| {
llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name)
};
llvm::LLVMSetInitializer(gv, cv);
ast::expr_vec(ref es, ast::m_imm) => {
let (cv, sz, llunitty) = const_vec(cx, e, *es);
let llty = val_ty(cv);
- let gv = do "const".to_c_str().with_ref |name| {
+ let gv = do "const".with_c_str |name| {
llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
};
llvm::LLVMSetInitializer(gv, cv);
_ => cx.sess.span_bug(e.span, "bad const-slice expr")
}
}
+ ast::expr_repeat(elem, count, _) => {
+ let vec_ty = ty::expr_ty(cx.tcx, e);
+ let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
+ let llunitty = type_of::type_of(cx, unit_ty);
+ let n = match const_eval::eval_const_expr(cx.tcx, count) {
+ const_eval::const_int(i) => i as uint,
+ const_eval::const_uint(i) => i as uint,
+ _ => cx.sess.span_bug(count.span, "count must be integral const expression.")
+ };
+ let vs = vec::from_elem(n, const_expr(cx, elem));
+ let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
+ C_struct(vs)
+ } else {
+ C_array(llunitty, vs)
+ };
+ v
+ }
ast::expr_path(ref pth) => {
assert_eq!(pth.types.len(), 0);
let tcx = cx.tcx;
use driver::session;
use lib::llvm::{ContextRef, ModuleRef, ValueRef};
use lib::llvm::{llvm, TargetData, TypeNames};
-use lib::llvm::{mk_target_data, False};
+use lib::llvm::mk_target_data;
use metadata::common::LinkMeta;
use middle::astencode;
use middle::resolve;
// Cache computed type parameter uses (see type_use.rs)
type_use_cache: HashMap<ast::def_id, @~[type_use::type_uses]>,
// Cache generated vtables
- vtables: HashMap<mono_id, ValueRef>,
+ vtables: HashMap<(ty::t, mono_id), ValueRef>,
// Cache of constant strings,
const_cstr_cache: HashMap<@str, ValueRef>,
unsafe {
let llcx = llvm::LLVMContextCreate();
set_task_llcx(llcx);
- let llmod = do name.to_c_str().with_ref |buf| {
+ let llmod = do name.with_c_str |buf| {
llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
};
let data_layout: &str = sess.targ_cfg.target_strs.data_layout;
let targ_triple: &str = sess.targ_cfg.target_strs.target_triple;
- do data_layout.to_c_str().with_ref |buf| {
+ do data_layout.with_c_str |buf| {
llvm::LLVMSetDataLayout(llmod, buf)
};
- do targ_triple.to_c_str().with_ref |buf| {
+ do targ_triple.with_c_str |buf| {
llvm::LLVMSetTarget(llmod, buf)
};
let targ_cfg = sess.targ_cfg;
use middle::trans::callee;
use middle::trans::common::*;
use middle::trans::expr;
-use middle::trans::type_of::*;
use middle::ty;
use util::common::indenter;
use util::ppaux;
ccx, modpath, "loglevel");
let global;
unsafe {
- global = do s.to_c_str().with_ref |buf| {
+ global = do s.with_c_str |buf| {
llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf)
};
llvm::LLVMSetGlobalConstant(global, False);
pub fn trans_ret(bcx: @mut Block, e: Option<@ast::expr>) -> @mut Block {
let _icx = push_ctxt("trans_ret");
let mut bcx = bcx;
- let dest = match bcx.fcx.loop_ret {
- Some((flagptr, retptr)) => {
- // This is a loop body return. Must set continue flag (our retptr)
- // to false, return flag to true, and then store the value in the
- // parent's retptr.
- Store(bcx, C_bool(true), flagptr);
- Store(bcx, C_bool(false), bcx.fcx.llretptr.unwrap());
- expr::SaveIn(match e {
- Some(x) => PointerCast(bcx, retptr,
- type_of(bcx.ccx(), expr_ty(bcx, x)).ptr_to()),
- None => retptr
- })
- }
- None => match bcx.fcx.llretptr {
+ let dest = match bcx.fcx.llretptr {
None => expr::Ignore,
Some(retptr) => expr::SaveIn(retptr),
- }
};
match e {
- Some(x) => {
- bcx = expr::trans_into(bcx, x, dest);
- }
- _ => ()
+ Some(x) => {
+ bcx = expr::trans_into(bcx, x, dest);
+ }
+ _ => ()
}
cleanup_and_leave(bcx, None, Some(bcx.fcx.get_llreturn()));
Unreachable(bcx);
pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode {
/*!
- *
- * Indicates the "appropriate" mode for this value,
- * which is either by ref or by value, depending
- * on whether type is immediate or not. */
+ * Indicates the "appropriate" mode for this value,
+ * which is either by ref or by value, depending
+ * on whether type is immediate or not.
+ */
- if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
+ if ty::type_is_voidish(ty) {
ByValue
} else if ty::type_is_immediate(tcx, ty) {
ByValue
let _icx = push_ctxt("copy_to");
- if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
+ if ty::type_is_voidish(self.ty) {
return bcx;
}
debug!("move_to(self=%s, action=%?, dst=%s)",
self.to_str(bcx.ccx()), action, bcx.val_to_str(dst));
- if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
+ if ty::type_is_voidish(self.ty) {
return bcx;
}
*
* Yields the value itself. */
- if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
+ if ty::type_is_voidish(self.ty) {
C_nil()
} else {
match self.mode {
match self.mode {
ByRef(_) => self.val,
ByValue => {
- if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
+ if ty::type_is_voidish(self.ty) {
C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to())
} else {
let slot = alloc_ty(bcx, self.ty, "");
use driver::session;
use lib::llvm::llvm;
-use lib::llvm::{ModuleRef, ContextRef};
+use lib::llvm::{ModuleRef, ContextRef, ValueRef};
use lib::llvm::debuginfo::*;
use middle::trans::common::*;
use middle::trans::machine;
use std::ptr;
use std::vec;
use syntax::codemap::span;
-use syntax::{ast, codemap, ast_util, ast_map};
+use syntax::{ast, codemap, ast_util, ast_map, opt_vec};
+use syntax::parse::token::special_idents;
static DW_LANG_RUST: int = 0x9000;
priv builder: DIBuilderRef,
priv curr_loc: (uint, uint),
priv created_files: HashMap<~str, DIFile>,
- priv created_functions: HashMap<ast::NodeId, DISubprogram>,
+ priv created_functions: HashMap<FunctionCacheKey, DISubprogram>,
priv created_blocks: HashMap<ast::NodeId, DILexicalBlock>,
priv created_types: HashMap<uint, DIType>
}
}
}
+#[deriving(Eq,IterBytes)]
+struct FunctionCacheKey {
+ // Use the address of the llvm function (FunctionContext::llfn) as key for the cache. This
+ // nicely takes care of monomorphization, where two specializations will have the same
+ // ast::NodeId but different llvm functions (each needing its own debug description).
+ priv llfn: ValueRef
+}
+
+impl FunctionCacheKey {
+ fn for_function_context(fcx: &FunctionContext) -> FunctionCacheKey {
+ FunctionCacheKey { llfn: fcx.llfn }
+ }
+}
pub struct FunctionDebugContext {
priv scope_map: HashMap<ast::NodeId, DIScope>,
priv argument_counter: uint,
}
-impl FunctionDebugContext {
- fn new() -> FunctionDebugContext {
- return FunctionDebugContext {
- scope_map: HashMap::new(),
- argument_counter: 1,
- };
- }
-}
-
/// Create any deferred debug metadata nodes
pub fn finalize(cx: @mut CrateContext) {
debug!("finalize");
}
}
+/// Creates debug information for a local variable introduced in the head of a match-statement arm.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_match_binding_metadata(bcx: @mut Block,
variable_ident: ast::ident,
node_id: ast::NodeId,
declare_local(bcx, variable_ident, node_id, variable_type, span);
}
+/// Creates debug information for the self argument of a method.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+pub fn create_self_argument_metadata(bcx: @mut Block,
+ variable_type: ty::t,
+ llptr: ValueRef) {
+ assert_fcx_has_span(bcx.fcx);
+ let span = bcx.fcx.span.unwrap();
+
+ let cx = bcx.ccx();
+
+ let filename = span_start(cx, span).file.name;
+ let file_metadata = file_metadata(cx, filename);
+
+ let loc = span_start(cx, span);
+ let type_metadata = type_metadata(cx, variable_type, span);
+ let scope = create_function_metadata(bcx.fcx);
+
+ let var_metadata = do cx.sess.str_of(special_idents::self_).to_c_str().with_ref |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateLocalVariable(
+ DIB(cx),
+ DW_TAG_arg_variable,
+ scope,
+ name,
+ file_metadata,
+ loc.line as c_uint,
+ type_metadata,
+ false,
+ 0,
+ 1)
+ }
+ };
+
+ set_debug_location(cx, scope, loc.line, loc.col.to_uint());
+ unsafe {
+ let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
+ DIB(cx),
+ llptr,
+ var_metadata,
+ bcx.llbb);
+
+ llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
+ }
+}
+
/// Creates debug information for the given function argument.
///
/// Adds the created metadata nodes directly to the crate's IR.
argument_index as c_uint
};
- let arg_metadata = do name.to_c_str().with_ref |name| {
+ let arg_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
}
}
-/// Sets the current debug location at the beginning of the span
+/// Sets the current debug location at the beginning of the span.
///
-/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...)
+/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...). The node_id parameter is used to
+/// reliably find the correct visibility scope for the code position.
pub fn update_source_pos(fcx: &FunctionContext,
node_id: ast::NodeId,
span: span) {
/// The return value should be ignored if called from outside of the debuginfo module.
pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
let cx = fcx.ccx;
+ let cache_key = FunctionCacheKey::for_function_context(fcx);
+
+ match dbg_cx(cx).created_functions.find_copy(&cache_key) {
+ Some(fn_metadata) => {
+ assert!(fcx.debug_context.is_some());
+ return fn_metadata;
+ }
+ None => { /* fallthrough */}
+ }
+
+ let empty_generics = ast::Generics { lifetimes: opt_vec::Empty, ty_params: opt_vec::Empty };
let fnitem = cx.tcx.items.get_copy(&fcx.id);
- let (ident, fn_decl, id) = match fnitem {
+ let (ident, fn_decl, generics, span) = match fnitem {
ast_map::node_item(ref item, _) => {
match item.node {
- ast::item_fn(ref fn_decl, _, _, _, _) => {
- (item.ident, fn_decl, item.id)
+ ast::item_fn(ref fn_decl, _, _, ref generics, _) => {
+ (item.ident, fn_decl, generics, item.span)
}
_ => fcx.ccx.sess.span_bug(item.span,
"create_function_metadata: item bound to non-function")
ast_map::node_method(
@ast::method {
decl: ref fn_decl,
- id: id,
ident: ident,
+ generics: ref generics,
+ span: span,
_
},
_,
_) => {
- (ident, fn_decl, id)
+ (ident, fn_decl, generics, span)
}
ast_map::node_expr(ref expr) => {
match expr.node {
ast::expr_fn_block(ref fn_decl, _) => {
let name = gensym_name("fn");
- (name, fn_decl, expr.id)
+ (name, fn_decl,
+ // This is not quite right. It should actually inherit the generics of the
+ // enclosing function.
+ &empty_generics,
+ expr.span)
}
_ => fcx.ccx.sess.span_bug(expr.span,
"create_function_metadata: expected an expr_fn_block here")
@ast::provided(
@ast::method {
decl: ref fn_decl,
- id: id,
ident: ident,
+ generics: ref generics,
+ span: span,
_
}),
_,
_) => {
- (ident, fn_decl, id)
+ (ident, fn_decl, generics, span)
}
_ => fcx.ccx.sess.bug(fmt!("create_function_metadata: unexpected sort of node: %?", fnitem))
};
- match dbg_cx(cx).created_functions.find_copy(&id) {
- Some(fn_metadata) => return fn_metadata,
- None => ()
- }
-
- let span = match fcx.span {
- Some(value) => value,
- None => codemap::dummy_sp()
- };
-
debug!("create_function_metadata: %s, %s",
cx.sess.str_of(ident),
cx.sess.codemap.span_to_str(span));
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name);
- let return_type_metadata = if cx.sess.opts.extra_debuginfo {
- match fn_decl.output.node {
- ast::ty_nil => ptr::null(),
- _ => type_metadata(cx, ty::node_id_to_type(cx.tcx, id), fn_decl.output.span)
- }
- } else {
- ptr::null()
+ let function_type_metadata = unsafe {
+ let fn_signature = get_function_signature(fcx, fn_decl);
+ llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
};
- let fn_ty = unsafe {
- llvm::LLVMDIBuilderCreateSubroutineType(
- DIB(cx),
- file_metadata,
- create_DIArray(DIB(cx), [return_type_metadata]))
+ // get_template_parameters() will append a `<...>` clause to the function name if necessary.
+ let mut function_name = cx.sess.str_of(ident).to_owned();
+ let template_parameters = get_template_parameters(fcx,
+ generics,
+ file_metadata,
+ &mut function_name);
+
+ let fn_metadata = do function_name.to_c_str().with_ref |function_name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateFunction(
+ DIB(cx),
+ file_metadata,
+ function_name,
+ function_name,
+ file_metadata,
+ loc.line as c_uint,
+ function_type_metadata,
+ false,
+ true,
+ loc.line as c_uint,
+ FlagPrototyped as c_uint,
+ cx.sess.opts.optimize != session::No,
+ fcx.llfn,
+ template_parameters,
+ ptr::null())
+ }
};
- let fn_metadata =
- do cx.sess.str_of(ident).to_c_str().with_ref |name| {
- do cx.sess.str_of(ident).to_c_str().with_ref |linkage| {
- unsafe {
- llvm::LLVMDIBuilderCreateFunction(
- DIB(cx),
- file_metadata,
- name,
- linkage,
- file_metadata,
- loc.line as c_uint,
- fn_ty,
- false,
- true,
- loc.line as c_uint,
- FlagPrototyped as c_uint,
- cx.sess.opts.optimize != session::No,
- fcx.llfn,
- ptr::null(),
- ptr::null())
+ dbg_cx(cx).created_functions.insert(cache_key, fn_metadata);
+
+ // Initialize fn debug context (including scope map)
+ {
+ assert!(fcx.debug_context.is_none());
+
+ let mut fn_debug_context = ~FunctionDebugContext {
+ scope_map: HashMap::new(),
+ argument_counter: if fcx.llself.is_some() { 2 } else { 1 }
+ };
+
+ let entry_block_id = fcx.entry_bcx.get_ref().node_info.get_ref().id;
+ let entry_block = cx.tcx.items.get(&entry_block_id);
+
+ match *entry_block {
+ ast_map::node_block(ref block) => {
+ let scope_map = &mut fn_debug_context.scope_map;
+ let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
+
+ populate_scope_map(cx, arg_pats, block, fn_metadata, scope_map);
}
- }};
+ _ => cx.sess.span_bug(span,
+ fmt!("debuginfo::create_function_metadata() - \
+ FunctionContext::entry_bcx::node_info points to wrong type of ast_map \
+ entry. Expected: ast_map::node_block, actual: %?", *entry_block))
+ }
+
+ fcx.debug_context = Some(fn_debug_context);
+ }
+
+ return fn_metadata;
- assert!(fcx.debug_context.is_none());
+ fn get_function_signature(fcx: &FunctionContext, fn_decl: &ast::fn_decl) -> DIArray {
+ let cx = fcx.ccx;
- let mut fn_debug_context = ~FunctionDebugContext::new();
- let entry_block_id = fcx.entry_bcx.get_ref().node_info.get_ref().id;
- let entry_block = cx.tcx.items.get(&entry_block_id);
+ if !cx.sess.opts.extra_debuginfo {
+ return create_DIArray(DIB(cx), []);
+ }
+
+ let mut signature = vec::with_capacity(fn_decl.inputs.len() + 1);
- match *entry_block {
- ast_map::node_block(ref block) => {
- let scope_map = &mut fn_debug_context.scope_map;
- let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
+ // Return type -- llvm::DIBuilder wants this at index 0
+ match fn_decl.output.node {
+ ast::ty_nil => {
+ signature.push(ptr::null());
+ }
+ _ => {
+ let return_type = ty::node_id_to_type(cx.tcx, fcx.id);
+ let return_type = match fcx.param_substs {
+ None => return_type,
+ Some(substs) => {
+ ty::subst_tps(cx.tcx, substs.tys, substs.self_ty, return_type)
+ }
+ };
- populate_scope_map(cx, arg_pats, block, fn_metadata, scope_map);
+ signature.push(type_metadata(cx, return_type, codemap::dummy_sp()));
+ }
}
- _ => cx.sess.span_bug(span,
- fmt!("debuginfo::create_function_metadata() - \
- FunctionContext::entry_bcx::node_info points to wrong type of ast_map entry. \
- Expected: ast_map::node_block, actual: %?", *entry_block))
+
+ // arguments types
+ for arg in fn_decl.inputs.iter() {
+ let arg_type = ty::node_id_to_type(cx.tcx, arg.pat.id);
+ let arg_type = match fcx.param_substs {
+ None => arg_type,
+ Some(substs) => {
+ ty::subst_tps(cx.tcx, substs.tys, substs.self_ty, arg_type)
+ }
+ };
+
+ signature.push(type_metadata(cx, arg_type, codemap::dummy_sp()));
+ }
+
+ return create_DIArray(DIB(cx), signature);
}
- fcx.debug_context = Some(fn_debug_context);
+ fn get_template_parameters(fcx: &FunctionContext,
+ generics: &ast::Generics,
+ file_metadata: DIFile,
+ name_to_append_suffix_to: &mut ~str)
+ -> DIArray {
+ let cx = fcx.ccx;
- dbg_cx(cx).created_functions.insert(id, fn_metadata);
- return fn_metadata;
+ let self_type = match fcx.param_substs {
+ Some(@param_substs{ self_ty: self_type, _ }) => self_type,
+ _ => None
+ };
+
+ // Only true for static default methods:
+ let has_self_type = self_type.is_some();
+
+ if !generics.is_type_parameterized() && !has_self_type {
+ return ptr::null();
+ }
+
+ name_to_append_suffix_to.push_char('<');
+
+ // The list to be filled with template parameters:
+ let mut template_params: ~[DIDescriptor] = vec::with_capacity(generics.ty_params.len() + 1);
+
+ // Handle self type
+ if has_self_type {
+ let actual_self_type = self_type.unwrap();
+ let actual_self_type_metadata = type_metadata(cx,
+ actual_self_type,
+ codemap::dummy_sp());
+
+ // Add self type name to <...> clause of function name
+ let actual_self_type_name = ty_to_str(cx.tcx, actual_self_type);
+ name_to_append_suffix_to.push_str(actual_self_type_name);
+ if generics.is_type_parameterized() {
+ name_to_append_suffix_to.push_str(",");
+ }
+
+ let ident = special_idents::type_self;
+
+ let param_metadata = do cx.sess.str_of(ident).to_c_str().with_ref |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ file_metadata,
+ name,
+ actual_self_type_metadata,
+ ptr::null(),
+ 0,
+ 0)
+ }
+ };
+
+ template_params.push(param_metadata);
+ }
+
+ // Handle other generic parameters
+ let actual_types = match fcx.param_substs {
+ Some(@param_substs { tys: ref types, _ }) => types,
+ None => {
+ return create_DIArray(DIB(cx), template_params);
+ }
+ };
+
+ for (index, &ast::TyParam{ ident: ident, _ }) in generics.ty_params.iter().enumerate() {
+ let actual_type = actual_types[index];
+ let actual_type_metadata = type_metadata(cx, actual_type, codemap::dummy_sp());
+
+ // Add actual type name to <...> clause of function name
+ let actual_type_name = ty_to_str(cx.tcx, actual_type);
+ name_to_append_suffix_to.push_str(actual_type_name);
+
+ if index != generics.ty_params.len() - 1 {
+ name_to_append_suffix_to.push_str(",");
+ }
+
+ let param_metadata = do cx.sess.str_of(ident).to_c_str().with_ref |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ file_metadata,
+ name,
+ actual_type_metadata,
+ ptr::null(),
+ 0,
+ 0)
+ }
+ };
+
+ template_params.push(param_metadata);
+ }
+
+ name_to_append_suffix_to.push_char('>');
+
+ return create_DIArray(DIB(cx), template_params);
+ }
}
let work_dir = cx.sess.working_dir.to_str();
let producer = fmt!("rustc version %s", env!("CFG_VERSION"));
- do crate_name.to_c_str().with_ref |crate_name| {
- do work_dir.to_c_str().with_ref |work_dir| {
- do producer.to_c_str().with_ref |producer| {
- do "".to_c_str().with_ref |flags| {
- do "".to_c_str().with_ref |split_name| {
+ do crate_name.with_c_str |crate_name| {
+ do work_dir.with_c_str |work_dir| {
+ do producer.with_c_str |producer| {
+ do "".with_c_str |flags| {
+ do "".with_c_str |split_name| {
unsafe {
llvm::LLVMDIBuilderCreateCompileUnit(dcx.builder,
DW_LANG_RUST as c_uint, crate_name, work_dir, producer,
let type_metadata = type_metadata(cx, variable_type, span);
let scope = scope_metadata(bcx.fcx, node_id, span);
- let var_metadata = do name.to_c_str().with_ref |name| {
+ let var_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
};
let file_metadata =
- do file_name.to_c_str().with_ref |file_name| {
- do work_dir.to_c_str().with_ref |work_dir| {
+ do file_name.with_c_str |file_name| {
+ do work_dir.with_c_str |work_dir| {
unsafe {
llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir)
}
let llvm_type = type_of::type_of(cx, t);
let (size, align) = size_and_align_of(cx, llvm_type);
- let ty_metadata = do name.to_c_str().with_ref |name| {
+ let ty_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateBasicType(
DIB(cx),
let pointer_llvm_type = type_of::type_of(cx, pointer_type);
let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
let name = ty_to_str(cx.tcx, pointer_type);
- let ptr_metadata = do name.to_c_str().with_ref |name| {
+ let ptr_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreatePointerType(
DIB(cx),
let struct_llvm_type = type_of::type_of(cx, struct_type);
let field_llvm_types = do fields.map |field| { type_of::type_of(cx, field.mt.ty) };
- let field_names = do fields.map |field| { cx.sess.str_of(field.ident).to_owned() };
+ let field_names = do fields.map |field| {
+ if field.ident == special_idents::unnamed_field {
+ ~""
+ } else {
+ cx.sess.str_of(field.ident).to_owned()
+ }
+ };
let field_types_metadata = do fields.map |field| {
type_metadata(cx, field.mt.ty, span)
};
let name: &str = cx.sess.str_of(v.name);
let discriminant_value = v.disr_val as c_ulonglong;
- do name.to_c_str().with_ref |name| {
+ do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateEnumerator(
DIB(cx),
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name);
- let discriminant_type_metadata = do enum_name.to_c_str().with_ref |enum_name| {
+ let discriminant_type_metadata = do enum_name.with_c_str |enum_name| {
unsafe {
llvm::LLVMDIBuilderCreateEnumerationType(
DIB(cx),
Some(discriminant_type_metadata),
span);
- do "".to_c_str().with_ref |name| {
+ do "".with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateMemberType(
DIB(cx),
let enum_llvm_type = type_of::type_of(cx, enum_type);
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
- return do enum_name.to_c_str().with_ref |enum_name| {
+ return do enum_name.with_c_str |enum_name| {
unsafe {
llvm::LLVMDIBuilderCreateUnionType(
DIB(cx),
let member_offset = machine::llelement_offset(cx, composite_llvm_type, i);
let member_name: &str = member_names[i];
- do member_name.to_c_str().with_ref |member_name| {
+ do member_name.with_c_str |member_name| {
unsafe {
llvm::LLVMDIBuilderCreateMemberType(
DIB(cx),
})
.collect();
- return do composite_type_name.to_c_str().with_ref |name| {
+ return do composite_type_name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateStructType(
DIB(cx),
debug!("unimplemented_type_metadata: %?", ty::get(t));
let name = ty_to_str(cx.tcx, t);
- let metadata = do fmt!("NYI<%s>", name).to_c_str().with_ref |name| {
+ let metadata = do fmt!("NYI<%s>", name).with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateBasicType(
DIB(cx),
cx.dbg_cx.get_ref().builder
}
+fn assert_fcx_has_span(fcx: &FunctionContext) {
+ if fcx.span.is_none() {
+ fcx.ccx.sess.bug(fmt!("debuginfo: Encountered function %s with invalid source span. \
+ This function should have been ignored by debuginfo generation.",
+ ast_map::path_to_str(fcx.path, fcx.ccx.sess.intr())));
+ }
+}
// This procedure builds the *scope map* for a given function, which maps any given ast::NodeId in
// the function's AST to the correct DIScope metadata instance.
assert_eq!(datum.appropriate_mode(tcx), ByValue);
Store(bcx, datum.to_appropriate_llval(bcx), llfn);
let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
- Store(bcx, base::null_env_ptr(bcx), llenv);
+ Store(bcx, base::null_env_ptr(bcx.ccx()), llenv);
DatumBlock {bcx: bcx, datum: scratch}
}
debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
let dest = {
- if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
+ if ty::type_is_voidish(ty) {
Ignore
} else {
dest
ty::RvalueDpsExpr => {
let ty = expr_ty(bcx, expr);
- if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
+ if ty::type_is_voidish(ty) {
bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
return nil(bcx, ty);
} else {
expr_to_str(expr, tcx.sess.intr()),
expr_ty.repr(tcx));
return closure::trans_expr_fn(bcx, sigil, decl, body,
- expr.id, expr.id,
- None, dest);
+ expr.id, expr.id, dest);
}
ast::expr_do_body(blk) => {
return trans_into(bcx, blk, dest);
return bcx;
}
}
- ast::def_struct(*) => {
+ ast::def_struct(def_id) => {
let ty = expr_ty(bcx, ref_expr);
match ty::get(ty).sty {
ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
let repr = adt::represent_type(ccx, ty);
adt::trans_start_init(bcx, repr, lldest, 0);
}
- _ => {}
+ ty::ty_bare_fn(*) => {
+ let fn_data = callee::trans_fn_ref(bcx, def_id, ref_expr.id);
+ Store(bcx, fn_data.llfn, lldest);
+ }
+ _ => ()
}
return bcx;
}
let symbol = csearch::get_symbol(
bcx.ccx().sess.cstore,
did);
- let llval = do symbol.to_c_str().with_ref |buf| {
+ let llval = do symbol.with_c_str |buf| {
llvm::LLVMAddGlobal(bcx.ccx().llmod,
llty.to_ref(),
buf)
// except according to those terms.
-use back::{link, abi};
-use lib::llvm::{Pointer, ValueRef};
+use back::{link};
+use std::libc::c_uint;
+use lib::llvm::{ValueRef, Attribute, CallConv};
+use lib::llvm::llvm;
use lib;
-use middle::trans::base::*;
+use middle::trans::machine;
+use middle::trans::base;
+use middle::trans::base::push_ctxt;
use middle::trans::cabi;
-use middle::trans::cabi_x86;
-use middle::trans::cabi_x86_64;
-use middle::trans::cabi_arm;
-use middle::trans::cabi_mips;
use middle::trans::build::*;
-use middle::trans::callee::*;
+use middle::trans::builder::noname;
use middle::trans::common::*;
-use middle::trans::datum::*;
-use middle::trans::expr::Ignore;
-use middle::trans::machine::llsize_of;
-use middle::trans::glue;
-use middle::trans::machine;
use middle::trans::type_of::*;
use middle::trans::type_of;
use middle::ty;
use middle::ty::FnSig;
-use util::ppaux::ty_to_str;
-use std::cell::Cell;
+use std::uint;
use std::vec;
use syntax::codemap::span;
-use syntax::{ast, ast_util};
+use syntax::{ast};
use syntax::{attr, ast_map};
-use syntax::opt_vec;
use syntax::parse::token::special_idents;
-use syntax::parse::token;
-use syntax::abi::{X86, X86_64, Arm, Mips};
use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall,
- Cdecl, Aapcs, C};
+ Cdecl, Aapcs, C, AbiSet};
+use util::ppaux::{Repr, UserString};
use middle::trans::type_::Type;
-fn abi_info(ccx: @mut CrateContext) -> @cabi::ABIInfo {
- return match ccx.sess.targ_cfg.arch {
- X86 => cabi_x86::abi_info(ccx),
- X86_64 => cabi_x86_64::abi_info(),
- Arm => cabi_arm::abi_info(),
- Mips => cabi_mips::abi_info(),
- }
-}
-
-pub fn link_name(ccx: &CrateContext, i: &ast::foreign_item) -> @str {
- match attr::first_attr_value_str_by_name(i.attrs, "link_name") {
- None => ccx.sess.str_of(i.ident),
- Some(ln) => ln,
- }
-}
+///////////////////////////////////////////////////////////////////////////
+// Type definitions
-struct ShimTypes {
+struct ForeignTypes {
+ /// Rust signature of the function
fn_sig: ty::FnSig,
+ /// Adapter object for handling native ABI rules (trust me, you
+ /// don't want to know)
+ fn_ty: cabi::FnType,
+
/// LLVM types that will appear on the foreign function
llsig: LlvmSignature,
/// True if there is a return value (not bottom, not unit)
ret_def: bool,
-
- /// Type of the struct we will use to shuttle values back and forth.
- /// This is always derived from the llsig.
- bundle_ty: Type,
-
- /// Type of the shim function itself.
- shim_fn_ty: Type,
-
- /// Adapter object for handling native ABI rules (trust me, you
- /// don't want to know).
- fn_ty: cabi::FnType
}
struct LlvmSignature {
+ // LLVM versions of the types of this function's arguments.
llarg_tys: ~[Type],
- llret_ty: Type,
- sret: bool,
-}
-fn foreign_signature(ccx: &mut CrateContext, fn_sig: &ty::FnSig)
- -> LlvmSignature {
- /*!
- * The ForeignSignature is the LLVM types of the arguments/return type
- * of a function. Note that these LLVM types are not quite the same
- * as the LLVM types would be for a native Rust function because foreign
- * functions just plain ignore modes. They also don't pass aggregate
- * values by pointer like we do.
- */
+ // LLVM version of the type that this function returns. Note that
+ // this *may not be* the declared return type of the foreign
+ // function, because the foreign function may opt to return via an
+ // out pointer.
+ llret_ty: Type,
- let llarg_tys = fn_sig.inputs.map(|arg_ty| type_of(ccx, *arg_ty));
- let llret_ty = type_of::type_of(ccx, fn_sig.output);
- LlvmSignature {
- llarg_tys: llarg_tys,
- llret_ty: llret_ty,
- sret: !ty::type_is_immediate(ccx.tcx, fn_sig.output),
- }
+ // True if *Rust* would use an outpointer for this function.
+ sret: bool,
}
-fn shim_types(ccx: @mut CrateContext, id: ast::NodeId) -> ShimTypes {
- let fn_sig = match ty::get(ty::node_id_to_type(ccx.tcx, id)).sty {
- ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(),
- _ => ccx.sess.bug("c_arg_and_ret_lltys called on non-function type")
- };
- let llsig = foreign_signature(ccx, &fn_sig);
- let bundle_ty = Type::struct_(llsig.llarg_tys + &[llsig.llret_ty.ptr_to()], false);
- let ret_def = !ty::type_is_bot(fn_sig.output) &&
- !ty::type_is_nil(fn_sig.output);
- let fn_ty = abi_info(ccx).compute_info(llsig.llarg_tys, llsig.llret_ty, ret_def);
- ShimTypes {
- fn_sig: fn_sig,
- llsig: llsig,
- ret_def: ret_def,
- bundle_ty: bundle_ty,
- shim_fn_ty: Type::func([bundle_ty.ptr_to()], &Type::void()),
- fn_ty: fn_ty
- }
-}
-type shim_arg_builder<'self> =
- &'self fn(bcx: @mut Block, tys: &ShimTypes,
- llargbundle: ValueRef) -> ~[ValueRef];
-
-type shim_ret_builder<'self> =
- &'self fn(bcx: @mut Block, tys: &ShimTypes,
- llargbundle: ValueRef,
- llretval: ValueRef);
-
-fn build_shim_fn_(ccx: @mut CrateContext,
- shim_name: &str,
- llbasefn: ValueRef,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv,
- arg_builder: shim_arg_builder,
- ret_builder: shim_ret_builder)
- -> ValueRef {
- let llshimfn = decl_internal_cdecl_fn(
- ccx.llmod, shim_name, tys.shim_fn_ty);
-
- // Declare the body of the shim function:
- let fcx = new_fn_ctxt(ccx, ~[], llshimfn, tys.fn_sig.output, None);
- let bcx = fcx.entry_bcx.unwrap();
-
- let llargbundle = get_param(llshimfn, 0u);
- let llargvals = arg_builder(bcx, tys, llargbundle);
-
- // Create the call itself and store the return value:
- let llretval = CallWithConv(bcx, llbasefn, llargvals, cc);
-
- ret_builder(bcx, tys, llargbundle, llretval);
-
- // Don't finish up the function in the usual way, because this doesn't
- // follow the normal Rust calling conventions.
- let ret_cx = match fcx.llreturn {
- Some(llreturn) => raw_block(fcx, false, llreturn),
- None => bcx
- };
- RetVoid(ret_cx);
- fcx.cleanup();
+///////////////////////////////////////////////////////////////////////////
+// Calls to external functions
- return llshimfn;
-}
+fn llvm_calling_convention(ccx: @mut CrateContext,
+ abis: AbiSet)
+ -> Option<CallConv> {
+ let arch = ccx.sess.targ_cfg.arch;
+ abis.for_arch(arch).map(|abi| {
+ match *abi {
+ RustIntrinsic => {
+ // Intrinsics are emitted by monomorphic fn
+ ccx.sess.bug(fmt!("Asked to register intrinsic fn"));
+ }
-type wrap_arg_builder<'self> = &'self fn(bcx: @mut Block,
- tys: &ShimTypes,
- llwrapfn: ValueRef,
- llargbundle: ValueRef);
-
-type wrap_ret_builder<'self> = &'self fn(bcx: @mut Block,
- tys: &ShimTypes,
- llargbundle: ValueRef);
-
-fn build_wrap_fn_(ccx: @mut CrateContext,
- tys: &ShimTypes,
- llshimfn: ValueRef,
- llwrapfn: ValueRef,
- shim_upcall: ValueRef,
- needs_c_return: bool,
- arg_builder: wrap_arg_builder,
- ret_builder: wrap_ret_builder) {
- let _icx = push_ctxt("foreign::build_wrap_fn_");
- let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None);
- let bcx = fcx.entry_bcx.unwrap();
-
- // Patch up the return type if it's not immediate and we're returning via
- // the C ABI.
- if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) {
- let lloutputtype = type_of::type_of(fcx.ccx, tys.fn_sig.output);
- fcx.llretptr = Some(alloca(bcx, lloutputtype, ""));
- }
+ Rust => {
+ // FIXME(#3678) Implement linking to foreign fns with Rust ABI
+ ccx.sess.unimpl(
+ fmt!("Foreign functions with Rust ABI"));
+ }
- // Allocate the struct and write the arguments into it.
- let llargbundle = alloca(bcx, tys.bundle_ty, "__llargbundle");
- arg_builder(bcx, tys, llwrapfn, llargbundle);
+ Stdcall => lib::llvm::X86StdcallCallConv,
+ Fastcall => lib::llvm::X86FastcallCallConv,
+ C => lib::llvm::CCallConv,
- // Create call itself.
- let llshimfnptr = PointerCast(bcx, llshimfn, Type::i8p());
- let llrawargbundle = PointerCast(bcx, llargbundle, Type::i8p());
- Call(bcx, shim_upcall, [llrawargbundle, llshimfnptr]);
- ret_builder(bcx, tys, llargbundle);
+ // NOTE These API constants ought to be more specific
+ Cdecl => lib::llvm::CCallConv,
+ Aapcs => lib::llvm::CCallConv,
+ }
+ })
+}
- // Then return according to the C ABI.
- let return_context = match fcx.llreturn {
- Some(llreturn) => raw_block(fcx, false, llreturn),
- None => bcx
- };
- let llfunctiontype = val_ty(llwrapfn);
- let llfunctiontype = llfunctiontype.element_type();
- let return_type = llfunctiontype.return_type();
- if return_type.kind() == ::lib::llvm::Void {
- // XXX: This might be wrong if there are any functions for which
- // the C ABI specifies a void output pointer and the Rust ABI
- // does not.
- RetVoid(return_context);
- } else {
- // Cast if we have to...
- // XXX: This is ugly.
- let llretptr = BitCast(return_context, fcx.llretptr.unwrap(), return_type.ptr_to());
- Ret(return_context, Load(return_context, llretptr));
- }
- fcx.cleanup();
-}
+pub fn register_foreign_item_fn(ccx: @mut CrateContext,
+ abis: AbiSet,
+ path: &ast_map::path,
+ foreign_item: @ast::foreign_item) -> ValueRef {
+ /*!
+ * Registers a foreign function found in a library.
+ * Just adds a LLVM global.
+ */
-// For each foreign function F, we generate a wrapper function W and a shim
-// function S that all work together. The wrapper function W is the function
-// that other rust code actually invokes. Its job is to marshall the
-// arguments into a struct. It then uses a small bit of assembly to switch
-// over to the C stack and invoke the shim function. The shim function S then
-// unpacks the arguments from the struct and invokes the actual function F
-// according to its specified calling convention.
-//
-// Example: Given a foreign c-stack function F(x: X, y: Y) -> Z,
-// we generate a wrapper function W that looks like:
-//
-// void W(Z* dest, void *env, X x, Y y) {
-// struct { X x; Y y; Z *z; } args = { x, y, z };
-// call_on_c_stack_shim(S, &args);
-// }
-//
-// The shim function S then looks something like:
-//
-// void S(struct { X x; Y y; Z *z; } *args) {
-// *args->z = F(args->x, args->y);
-// }
-//
-// However, if the return type of F is dynamically sized or of aggregate type,
-// the shim function looks like:
-//
-// void S(struct { X x; Y y; Z *z; } *args) {
-// F(args->z, args->x, args->y);
-// }
-//
-// Note: on i386, the layout of the args struct is generally the same
-// as the desired layout of the arguments on the C stack. Therefore,
-// we could use upcall_alloc_c_stack() to allocate the `args`
-// structure and switch the stack pointer appropriately to avoid a
-// round of copies. (In fact, the shim function itself is
-// unnecessary). We used to do this, in fact, and will perhaps do so
-// in the future.
-pub fn trans_foreign_mod(ccx: @mut CrateContext,
- path: &ast_map::path,
- foreign_mod: &ast::foreign_mod) {
- let _icx = push_ctxt("foreign::trans_foreign_mod");
+ debug!("register_foreign_item_fn(abis=%s, \
+ path=%s, \
+ foreign_item.id=%?)",
+ abis.repr(ccx.tcx),
+ path.repr(ccx.tcx),
+ foreign_item.id);
- let arch = ccx.sess.targ_cfg.arch;
- let abi = match foreign_mod.abis.for_arch(arch) {
+ let cc = match llvm_calling_convention(ccx, abis) {
+ Some(cc) => cc,
None => {
+ // FIXME(#8357) We really ought to report a span here
ccx.sess.fatal(
- fmt!("No suitable ABI for target architecture \
+ fmt!("ABI `%s` has no suitable ABI \
+ for target architecture \
in module %s",
+ abis.user_string(ccx.tcx),
ast_map::path_to_str(*path,
ccx.sess.intr())));
}
-
- Some(abi) => abi,
};
- for &foreign_item in foreign_mod.items.iter() {
- match foreign_item.node {
- ast::foreign_item_fn(*) => {
- let id = foreign_item.id;
- match abi {
- RustIntrinsic => {
- // Intrinsics are emitted by monomorphic fn
- }
-
- Rust => {
- // FIXME(#3678) Implement linking to foreign fns with Rust ABI
- ccx.sess.unimpl(
- fmt!("Foreign functions with Rust ABI"));
- }
-
- Stdcall => {
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::X86StdcallCallConv);
- }
-
- Fastcall => {
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::X86FastcallCallConv);
- }
-
- Cdecl => {
- // FIXME(#3678) should really be more specific
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::CCallConv);
- }
-
- Aapcs => {
- // FIXME(#3678) should really be more specific
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::CCallConv);
- }
-
- C => {
- build_foreign_fn(ccx, id, foreign_item,
- lib::llvm::CCallConv);
- }
- }
- }
- ast::foreign_item_static(*) => {
- let ident = token::ident_to_str(&foreign_item.ident);
- ccx.item_symbols.insert(foreign_item.id, /* bad */ident.to_owned());
- }
- }
- }
+ // Register the function as a C extern fn
+ let lname = link_name(ccx, foreign_item);
+ let tys = foreign_types_for_id(ccx, foreign_item.id);
- fn build_foreign_fn(ccx: @mut CrateContext,
- id: ast::NodeId,
- foreign_item: @ast::foreign_item,
- cc: lib::llvm::CallConv) {
- let llwrapfn = get_item_val(ccx, id);
- let tys = shim_types(ccx, id);
- if attr::contains_name(foreign_item.attrs, "rust_stack") {
- build_direct_fn(ccx, llwrapfn, foreign_item,
- &tys, cc);
- } else if attr::contains_name(foreign_item.attrs, "fast_ffi") {
- build_fast_ffi_fn(ccx, llwrapfn, foreign_item, &tys, cc);
- } else {
- let llshimfn = build_shim_fn(ccx, foreign_item, &tys, cc);
- build_wrap_fn(ccx, &tys, llshimfn, llwrapfn);
- }
- }
+ // Create the LLVM value for the C extern fn
+ let llfn_ty = lltype_for_fn_from_foreign_types(&tys);
+ let llfn = base::get_extern_fn(&mut ccx.externs, ccx.llmod,
+ lname, cc, llfn_ty);
+ add_argument_attributes(&tys, llfn);
- fn build_shim_fn(ccx: @mut CrateContext,
- foreign_item: &ast::foreign_item,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv)
- -> ValueRef {
- /*!
- *
- * Build S, from comment above:
- *
- * void S(struct { X x; Y y; Z *z; } *args) {
- * F(args->z, args->x, args->y);
- * }
- */
-
- let _icx = push_ctxt("foreign::build_shim_fn");
-
- fn build_args(bcx: @mut Block, tys: &ShimTypes, llargbundle: ValueRef)
- -> ~[ValueRef] {
- let _icx = push_ctxt("foreign::shim::build_args");
- tys.fn_ty.build_shim_args(bcx, tys.llsig.llarg_tys, llargbundle)
- }
+ return llfn;
+}
- fn build_ret(bcx: @mut Block,
- tys: &ShimTypes,
- llargbundle: ValueRef,
- llretval: ValueRef) {
- let _icx = push_ctxt("foreign::shim::build_ret");
- tys.fn_ty.build_shim_ret(bcx,
- tys.llsig.llarg_tys,
- tys.ret_def,
- llargbundle,
- llretval);
- }
+pub fn trans_native_call(bcx: @mut Block,
+ callee_ty: ty::t,
+ llfn: ValueRef,
+ llretptr: ValueRef,
+ llargs_rust: &[ValueRef]) -> @mut Block {
+ /*!
+ * Prepares a call to a native function. This requires adapting
+ * from the Rust argument passing rules to the native rules.
+ *
+ * # Parameters
+ *
+ * - `callee_ty`: Rust type for the function we are calling
+ * - `llfn`: the function pointer we are calling
+ * - `llretptr`: where to store the return value of the function
+ * - `llargs_rust`: a list of the argument values, prepared
+ * as they would be if calling a Rust function
+ */
- let lname = link_name(ccx, foreign_item);
- let llbasefn = base_fn(ccx, lname, tys, cc);
- // Name the shim function
- let shim_name = fmt!("%s__c_stack_shim", lname);
- build_shim_fn_(ccx,
- shim_name,
- llbasefn,
- tys,
- cc,
- build_args,
- build_ret)
- }
+ let ccx = bcx.ccx();
+ let tcx = bcx.tcx();
- fn base_fn(ccx: &CrateContext,
- lname: &str,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv)
- -> ValueRef {
- // Declare the "prototype" for the base function F:
- do tys.fn_ty.decl_fn |fnty| {
- decl_fn(ccx.llmod, lname, cc, fnty)
- }
- }
+ debug!("trans_native_call(callee_ty=%s, \
+ llfn=%s, \
+ llretptr=%s)",
+ callee_ty.repr(tcx),
+ ccx.tn.val_to_str(llfn),
+ ccx.tn.val_to_str(llretptr));
- // FIXME (#2535): this is very shaky and probably gets ABIs wrong all
- // over the place
- fn build_direct_fn(ccx: @mut CrateContext,
- decl: ValueRef,
- item: &ast::foreign_item,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv) {
- debug!("build_direct_fn(%s)", link_name(ccx, item));
-
- let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
- let bcx = fcx.entry_bcx.unwrap();
- let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
- let ty = ty::lookup_item_type(ccx.tcx,
- ast_util::local_def(item.id)).ty;
- let ret_ty = ty::ty_fn_ret(ty);
- let args = vec::from_fn(ty::ty_fn_args(ty).len(), |i| {
- get_param(decl, fcx.arg_pos(i))
- });
- let retval = Call(bcx, llbasefn, args);
- if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
- Store(bcx, retval, fcx.llretptr.unwrap());
+ let (fn_abis, fn_sig) = match ty::get(callee_ty).sty {
+ ty::ty_bare_fn(ref fn_ty) => (fn_ty.abis, fn_ty.sig.clone()),
+ _ => ccx.sess.bug("trans_native_call called on non-function type")
+ };
+ let llsig = foreign_signature(ccx, &fn_sig);
+ let ret_def = !ty::type_is_voidish(fn_sig.output);
+ let fn_type = cabi::compute_abi_info(ccx,
+ llsig.llarg_tys,
+ llsig.llret_ty,
+ ret_def);
+
+ let all_arg_tys: &[cabi::LLVMType] = fn_type.arg_tys;
+ let all_attributes: &[Option<Attribute>] = fn_type.attrs;
+
+ let mut llargs_foreign = ~[];
+
+ // If the foreign ABI expects return value by pointer, supply the
+ // pointer that Rust gave us. Sometimes we have to bitcast
+ // because foreign fns return slightly different (but equivalent)
+ // views on the same type (e.g., i64 in place of {i32,i32}).
+ let (arg_tys, attributes) = {
+ if fn_type.sret {
+ if all_arg_tys[0].cast {
+ let llcastedretptr =
+ BitCast(bcx, llretptr, all_arg_tys[0].ty.ptr_to());
+ llargs_foreign.push(llcastedretptr);
+ } else {
+ llargs_foreign.push(llretptr);
+ }
+ (all_arg_tys.tail(), all_attributes.tail())
+ } else {
+ (all_arg_tys, all_attributes)
}
- finish_fn(fcx, bcx);
- }
+ };
- // FIXME (#2535): this is very shaky and probably gets ABIs wrong all
- // over the place
- fn build_fast_ffi_fn(ccx: @mut CrateContext,
- decl: ValueRef,
- item: &ast::foreign_item,
- tys: &ShimTypes,
- cc: lib::llvm::CallConv) {
- debug!("build_fast_ffi_fn(%s)", link_name(ccx, item));
-
- let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
- let bcx = fcx.entry_bcx.unwrap();
- let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
- set_no_inline(fcx.llfn);
- set_fixed_stack_segment(fcx.llfn);
- let ty = ty::lookup_item_type(ccx.tcx,
- ast_util::local_def(item.id)).ty;
- let ret_ty = ty::ty_fn_ret(ty);
- let args = vec::from_fn(ty::ty_fn_args(ty).len(), |i| {
- get_param(decl, fcx.arg_pos(i))
- });
- let retval = Call(bcx, llbasefn, args);
- if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
- Store(bcx, retval, fcx.llretptr.unwrap());
- }
- finish_fn(fcx, bcx);
- }
+ for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
+ let mut llarg_rust = llarg_rust;
- fn build_wrap_fn(ccx: @mut CrateContext,
- tys: &ShimTypes,
- llshimfn: ValueRef,
- llwrapfn: ValueRef) {
- /*!
- *
- * Build W, from comment above:
- *
- * void W(Z* dest, void *env, X x, Y y) {
- * struct { X x; Y y; Z *z; } args = { x, y, z };
- * call_on_c_stack_shim(S, &args);
- * }
- *
- * One thing we have to be very careful of is to
- * account for the Rust modes.
- */
-
- let _icx = push_ctxt("foreign::build_wrap_fn");
-
- build_wrap_fn_(ccx,
- tys,
- llshimfn,
- llwrapfn,
- ccx.upcalls.call_shim_on_c_stack,
- false,
- build_args,
- build_ret);
-
- fn build_args(bcx: @mut Block,
- tys: &ShimTypes,
- llwrapfn: ValueRef,
- llargbundle: ValueRef) {
- let _icx = push_ctxt("foreign::wrap::build_args");
- let ccx = bcx.ccx();
- let n = tys.llsig.llarg_tys.len();
- for i in range(0u, n) {
- let arg_i = bcx.fcx.arg_pos(i);
- let mut llargval = get_param(llwrapfn, arg_i);
-
- // In some cases, Rust will pass a pointer which the
- // native C type doesn't have. In that case, just
- // load the value from the pointer.
- if type_of::arg_is_indirect(ccx, &tys.fn_sig.inputs[i]) {
- llargval = Load(bcx, llargval);
- }
+ // Does Rust pass this argument by pointer?
+ let rust_indirect = type_of::arg_is_indirect(ccx, fn_sig.inputs[i]);
- store_inbounds(bcx, llargval, llargbundle, [0u, i]);
- }
+ debug!("argument %u, llarg_rust=%s, rust_indirect=%b, arg_ty=%s",
+ i,
+ ccx.tn.val_to_str(llarg_rust),
+ rust_indirect,
+ ccx.tn.type_to_str(arg_tys[i].ty));
- for &retptr in bcx.fcx.llretptr.iter() {
- store_inbounds(bcx, retptr, llargbundle, [0u, n]);
- }
+ // Ensure that we always have the Rust value indirectly,
+ // because it makes bitcasting easier.
+ if !rust_indirect {
+ let scratch = base::alloca(bcx, arg_tys[i].ty, "__arg");
+ Store(bcx, llarg_rust, scratch);
+ llarg_rust = scratch;
}
- fn build_ret(bcx: @mut Block,
- shim_types: &ShimTypes,
- llargbundle: ValueRef) {
- let _icx = push_ctxt("foreign::wrap::build_ret");
- let arg_count = shim_types.fn_sig.inputs.len();
- for &retptr in bcx.fcx.llretptr.iter() {
- let llretptr = load_inbounds(bcx, llargbundle, [0, arg_count]);
- Store(bcx, Load(bcx, llretptr), retptr);
- }
- }
- }
-}
+ debug!("llarg_rust=%s (after indirection)",
+ ccx.tn.val_to_str(llarg_rust));
-pub fn trans_intrinsic(ccx: @mut CrateContext,
- decl: ValueRef,
- item: &ast::foreign_item,
- path: ast_map::path,
- substs: @param_substs,
- attributes: &[ast::Attribute],
- ref_id: Option<ast::NodeId>) {
- debug!("trans_intrinsic(item.ident=%s)", ccx.sess.str_of(item.ident));
-
- fn simple_llvm_intrinsic(bcx: @mut Block, name: &'static str, num_args: uint) {
- assert!(num_args <= 4);
- let mut args = [0 as ValueRef, ..4];
- let first_real_arg = bcx.fcx.arg_pos(0u);
- for i in range(0u, num_args) {
- args[i] = get_param(bcx.fcx.llfn, first_real_arg + i);
+ // Check whether we need to do any casting
+ let foreignarg_ty = arg_tys[i].ty;
+ if arg_tys[i].cast {
+ llarg_rust = BitCast(bcx, llarg_rust, foreignarg_ty.ptr_to());
}
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
- }
-
- fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
- let first_real_arg = bcx.fcx.arg_pos(0u);
- let a = get_param(bcx.fcx.llfn, first_real_arg);
- let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
-
- // convert `i1` to a `bool`, and write to the out parameter
- let val = Call(bcx, llfn, [a, b]);
- let result = ExtractValue(bcx, val, 0);
- let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
- let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
- let ret = Load(bcx, retptr);
- let ret = InsertValue(bcx, ret, result, 0);
- let ret = InsertValue(bcx, ret, overflow, 1);
- Store(bcx, ret, retptr);
- RetVoid(bcx)
- }
- fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
- let ccx = bcx.ccx();
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
- let size = match sizebits {
- 32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
- 64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
- _ => ccx.sess.fatal("Invalid value for sizebits")
- };
+ debug!("llarg_rust=%s (after casting)",
+ ccx.tn.val_to_str(llarg_rust));
- let decl = bcx.fcx.llfn;
- let first_real_arg = bcx.fcx.arg_pos(0u);
- let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
- let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
- let count = get_param(decl, first_real_arg + 2);
- let volatile = C_i1(false);
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
- RetVoid(bcx);
- }
-
- fn memset_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
- let ccx = bcx.ccx();
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
- let size = match sizebits {
- 32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
- 64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
- _ => ccx.sess.fatal("Invalid value for sizebits")
+ // Finally, load the value if needed for the foreign ABI
+ let foreign_indirect = attributes[i].is_some();
+ let llarg_foreign = if foreign_indirect {
+ llarg_rust
+ } else {
+ Load(bcx, llarg_rust)
};
- let decl = bcx.fcx.llfn;
- let first_real_arg = bcx.fcx.arg_pos(0u);
- let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
- let val = get_param(decl, first_real_arg + 1);
- let count = get_param(decl, first_real_arg + 2);
- let volatile = C_i1(false);
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
- RetVoid(bcx);
- }
+ debug!("argument %u, llarg_foreign=%s",
+ i, ccx.tn.val_to_str(llarg_foreign));
- fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
- let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
- let y = C_i1(false);
- let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Ret(bcx, Call(bcx, llfn, [x, y]));
+ llargs_foreign.push(llarg_foreign);
}
- let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
-
- let fcx = new_fn_ctxt_w_id(ccx,
- path,
- decl,
- item.id,
- output_type,
- true,
- Some(substs),
- None,
- Some(item.span));
-
- set_always_inline(fcx.llfn);
+ let cc = match llvm_calling_convention(ccx, fn_abis) {
+ Some(cc) => cc,
+ None => {
+ // FIXME(#8357) We really ought to report a span here
+ ccx.sess.fatal(
+ fmt!("ABI string `%s` has no suitable ABI \
+ for target architecture",
+ fn_abis.user_string(ccx.tcx)));
+ }
+ };
- // Set the fixed stack segment flag if necessary.
- if attr::contains_name(attributes, "fixed_stack_segment") {
- set_fixed_stack_segment(fcx.llfn);
- }
+ let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign, cc);
- let mut bcx = fcx.entry_bcx.unwrap();
- let first_real_arg = fcx.arg_pos(0u);
+ // If the function we just called does not use an outpointer,
+ // store the result into the rust outpointer. Cast the outpointer
+ // type to match because some ABIs will use a different type than
+ // the Rust type. e.g., a {u32,u32} struct could be returned as
+ // u64.
+ if ret_def && !fn_type.sret {
+ let llrust_ret_ty = llsig.llret_ty;
+ let llforeign_ret_ty = fn_type.ret_ty.ty;
- let nm = ccx.sess.str_of(item.ident);
- let name = nm.as_slice();
+ debug!("llretptr=%s", ccx.tn.val_to_str(llretptr));
+ debug!("llforeign_retval=%s", ccx.tn.val_to_str(llforeign_retval));
+ debug!("llrust_ret_ty=%s", ccx.tn.type_to_str(llrust_ret_ty));
+ debug!("llforeign_ret_ty=%s", ccx.tn.type_to_str(llforeign_ret_ty));
- // This requires that atomic intrinsics follow a specific naming pattern:
- // "atomic_<operation>[_<ordering>], and no ordering means SeqCst
- if name.starts_with("atomic_") {
- let split : ~[&str] = name.split_iter('_').collect();
- assert!(split.len() >= 2, "Atomic intrinsic not correct format");
- let order = if split.len() == 2 {
- lib::llvm::SequentiallyConsistent
+ if llrust_ret_ty == llforeign_ret_ty {
+ Store(bcx, llforeign_retval, llretptr);
} else {
- match split[2] {
- "relaxed" => lib::llvm::Monotonic,
- "acq" => lib::llvm::Acquire,
- "rel" => lib::llvm::Release,
- "acqrel" => lib::llvm::AcquireRelease,
- _ => ccx.sess.fatal("Unknown ordering in atomic intrinsic")
- }
- };
-
- match split[1] {
- "cxchg" => {
- let old = AtomicCmpXchg(bcx, get_param(decl, first_real_arg),
- get_param(decl, first_real_arg + 1u),
- get_param(decl, first_real_arg + 2u),
- order);
- Ret(bcx, old);
- }
- "load" => {
- let old = AtomicLoad(bcx, get_param(decl, first_real_arg),
- order);
- Ret(bcx, old);
- }
- "store" => {
- AtomicStore(bcx, get_param(decl, first_real_arg + 1u),
- get_param(decl, first_real_arg),
- order);
- RetVoid(bcx);
- }
- "fence" => {
- AtomicFence(bcx, order);
- RetVoid(bcx);
- }
- op => {
- // These are all AtomicRMW ops
- let atom_op = match op {
- "xchg" => lib::llvm::Xchg,
- "xadd" => lib::llvm::Add,
- "xsub" => lib::llvm::Sub,
- "and" => lib::llvm::And,
- "nand" => lib::llvm::Nand,
- "or" => lib::llvm::Or,
- "xor" => lib::llvm::Xor,
- "max" => lib::llvm::Max,
- "min" => lib::llvm::Min,
- "umax" => lib::llvm::UMax,
- "umin" => lib::llvm::UMin,
- _ => ccx.sess.fatal("Unknown atomic operation")
- };
-
- let old = AtomicRMW(bcx, atom_op, get_param(decl, first_real_arg),
- get_param(decl, first_real_arg + 1u),
- order);
- Ret(bcx, old);
- }
+ // The actual return type is a struct, but the ABI
+ // adaptation code has cast it into some scalar type. The
+ // code that follows is the only reliable way I have
+ // found to do a transform like i64 -> {i32,i32}.
+ // Basically we dump the data onto the stack then memcpy it.
+ //
+ // Other approaches I tried:
+ // - Casting rust ret pointer to the foreign type and using Store
+ // is (a) unsafe if size of foreign type > size of rust type and
+ // (b) runs afoul of strict aliasing rules, yielding invalid
+ // assembly under -O (specifically, the store gets removed).
+ // - Truncating foreign type to correct integral type and then
+ // bitcasting to the struct type yields invalid cast errors.
+ let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
+ Store(bcx, llforeign_retval, llscratch);
+ let llscratch_i8 = BitCast(bcx, llscratch, Type::i8().ptr_to());
+ let llretptr_i8 = BitCast(bcx, llretptr, Type::i8().ptr_to());
+ let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
+ let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
+ let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
+ let llalign = uint::min(llforeign_align, llrust_align);
+ debug!("llrust_size=%?", llrust_size);
+ base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
+ C_uint(ccx, llrust_size), llalign as u32);
}
-
- fcx.cleanup();
- return;
}
- match name {
- "size_of" => {
- let tp_ty = substs.tys[0];
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)));
- }
- "move_val" => {
- // Create a datum reflecting the value being moved.
- // Use `appropriate_mode` so that the datum is by ref
- // if the value is non-immediate. Note that, with
- // intrinsics, there are no argument cleanups to
- // concern ourselves with.
- let tp_ty = substs.tys[0];
- let mode = appropriate_mode(ccx.tcx, tp_ty);
- let src = Datum {val: get_param(decl, first_real_arg + 1u),
- ty: tp_ty, mode: mode};
- bcx = src.move_to(bcx, DROP_EXISTING,
- get_param(decl, first_real_arg));
- RetVoid(bcx);
- }
- "move_val_init" => {
- // See comments for `"move_val"`.
- let tp_ty = substs.tys[0];
- let mode = appropriate_mode(ccx.tcx, tp_ty);
- let src = Datum {val: get_param(decl, first_real_arg + 1u),
- ty: tp_ty, mode: mode};
- bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg));
- RetVoid(bcx);
- }
- "min_align_of" => {
- let tp_ty = substs.tys[0];
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)));
- }
- "pref_align_of"=> {
- let tp_ty = substs.tys[0];
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)));
- }
- "get_tydesc" => {
- let tp_ty = substs.tys[0];
- let static_ti = get_tydesc(ccx, tp_ty);
- glue::lazily_emit_all_tydesc_glue(ccx, static_ti);
-
- // FIXME (#3730): ideally this shouldn't need a cast,
- // but there's a circularity between translating rust types to llvm
- // types and having a tydesc type available. So I can't directly access
- // the llvm type of intrinsic::TyDesc struct.
- let userland_tydesc_ty = type_of::type_of(ccx, output_type);
- let td = PointerCast(bcx, static_ti.tydesc, userland_tydesc_ty);
- Ret(bcx, td);
- }
- "init" => {
- let tp_ty = substs.tys[0];
- let lltp_ty = type_of::type_of(ccx, tp_ty);
- match bcx.fcx.llretptr {
- Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); }
- None if ty::type_is_nil(tp_ty) => RetVoid(bcx),
- None => Ret(bcx, C_null(lltp_ty)),
- }
- }
- "uninit" => {
- // Do nothing, this is effectively a no-op
- let retty = substs.tys[0];
- if ty::type_is_immediate(ccx.tcx, retty) && !ty::type_is_nil(retty) {
- unsafe {
- Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref()));
- }
- } else {
- RetVoid(bcx)
- }
- }
- "forget" => {
- RetVoid(bcx);
- }
- "transmute" => {
- let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
- let llintype = type_of::type_of(ccx, in_type);
- let llouttype = type_of::type_of(ccx, out_type);
-
- let in_type_size = machine::llbitsize_of_real(ccx, llintype);
- let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
- if in_type_size != out_type_size {
- let sp = match ccx.tcx.items.get_copy(&ref_id.unwrap()) {
- ast_map::node_expr(e) => e.span,
- _ => fail!("transmute has non-expr arg"),
- };
- let pluralize = |n| if 1u == n { "" } else { "s" };
- ccx.sess.span_fatal(sp,
- fmt!("transmute called on types with \
- different sizes: %s (%u bit%s) to \
- %s (%u bit%s)",
- ty_to_str(ccx.tcx, in_type),
- in_type_size,
- pluralize(in_type_size),
- ty_to_str(ccx.tcx, out_type),
- out_type_size,
- pluralize(out_type_size)));
- }
+ return bcx;
+}
- if !ty::type_is_nil(out_type) {
- let llsrcval = get_param(decl, first_real_arg);
- if ty::type_is_immediate(ccx.tcx, in_type) {
- match fcx.llretptr {
- Some(llretptr) => {
- Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
- RetVoid(bcx);
- }
- None => match (llintype.kind(), llouttype.kind()) {
- (Pointer, other) | (other, Pointer) if other != Pointer => {
- let tmp = Alloca(bcx, llouttype, "");
- Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
- Ret(bcx, Load(bcx, tmp));
- }
- _ => Ret(bcx, BitCast(bcx, llsrcval, llouttype))
- }
- }
- } else if ty::type_is_immediate(ccx.tcx, out_type) {
- let llsrcptr = PointerCast(bcx, llsrcval, llouttype.ptr_to());
- Ret(bcx, Load(bcx, llsrcptr));
- } else {
- // NB: Do not use a Load and Store here. This causes massive
- // code bloat when `transmute` is used on large structural
- // types.
- let lldestptr = fcx.llretptr.unwrap();
- let lldestptr = PointerCast(bcx, lldestptr, Type::i8p());
- let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p());
-
- let llsize = llsize_of(ccx, llintype);
- call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
- RetVoid(bcx);
- };
- } else {
- RetVoid(bcx);
- }
- }
- "needs_drop" => {
- let tp_ty = substs.tys[0];
- Ret(bcx, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)));
- }
- "contains_managed" => {
- let tp_ty = substs.tys[0];
- Ret(bcx, C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()));
- }
- "visit_tydesc" => {
- let td = get_param(decl, first_real_arg);
- let visitor = get_param(decl, first_real_arg + 1u);
- let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to());
- glue::call_tydesc_glue_full(bcx, visitor, td,
- abi::tydesc_field_visit_glue, None);
- RetVoid(bcx);
- }
- "frame_address" => {
- let frameaddress = ccx.intrinsics.get_copy(& &"llvm.frameaddress");
- let frameaddress_val = Call(bcx, frameaddress, [C_i32(0i32)]);
- let star_u8 = ty::mk_imm_ptr(
- bcx.tcx(),
- ty::mk_mach_uint(ast::ty_u8));
- let fty = ty::mk_closure(bcx.tcx(), ty::ClosureTy {
- purity: ast::impure_fn,
- sigil: ast::BorrowedSigil,
- onceness: ast::Many,
- region: ty::re_bound(ty::br_anon(0)),
- bounds: ty::EmptyBuiltinBounds(),
- sig: FnSig {
- bound_lifetime_names: opt_vec::Empty,
- inputs: ~[ star_u8 ],
- output: ty::mk_nil()
- }
- });
- let datum = Datum {val: get_param(decl, first_real_arg),
- mode: ByRef(ZeroMem), ty: fty};
- let arg_vals = ~[frameaddress_val];
- bcx = trans_call_inner(
- bcx, None, fty, ty::mk_nil(),
- |bcx| Callee {bcx: bcx, data: Closure(datum)},
- ArgVals(arg_vals), Some(Ignore), DontAutorefArg).bcx;
- RetVoid(bcx);
- }
- "morestack_addr" => {
- // XXX This is a hack to grab the address of this particular
- // native function. There should be a general in-language
- // way to do this
- let llfty = type_of_fn(bcx.ccx(), [], ty::mk_nil());
- let morestack_addr = decl_cdecl_fn(
- bcx.ccx().llmod, "__morestack", llfty);
- let morestack_addr = PointerCast(bcx, morestack_addr, Type::nil().ptr_to());
- Ret(bcx, morestack_addr);
- }
- "offset" => {
- let ptr = get_param(decl, first_real_arg);
- let offset = get_param(decl, first_real_arg + 1);
- Ret(bcx, GEP(bcx, ptr, [offset]));
- }
- "offset_inbounds" => {
- let ptr = get_param(decl, first_real_arg);
- let offset = get_param(decl, first_real_arg + 1);
- Ret(bcx, InBoundsGEP(bcx, ptr, [offset]));
- }
- "memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32),
- "memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64),
- "memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32),
- "memmove64" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i64", substs.tys[0], 64),
- "memset32" => memset_intrinsic(bcx, "llvm.memset.p0i8.i32", substs.tys[0], 32),
- "memset64" => memset_intrinsic(bcx, "llvm.memset.p0i8.i64", substs.tys[0], 64),
- "sqrtf32" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f32", 1),
- "sqrtf64" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f64", 1),
- "powif32" => simple_llvm_intrinsic(bcx, "llvm.powi.f32", 2),
- "powif64" => simple_llvm_intrinsic(bcx, "llvm.powi.f64", 2),
- "sinf32" => simple_llvm_intrinsic(bcx, "llvm.sin.f32", 1),
- "sinf64" => simple_llvm_intrinsic(bcx, "llvm.sin.f64", 1),
- "cosf32" => simple_llvm_intrinsic(bcx, "llvm.cos.f32", 1),
- "cosf64" => simple_llvm_intrinsic(bcx, "llvm.cos.f64", 1),
- "powf32" => simple_llvm_intrinsic(bcx, "llvm.pow.f32", 2),
- "powf64" => simple_llvm_intrinsic(bcx, "llvm.pow.f64", 2),
- "expf32" => simple_llvm_intrinsic(bcx, "llvm.exp.f32", 1),
- "expf64" => simple_llvm_intrinsic(bcx, "llvm.exp.f64", 1),
- "exp2f32" => simple_llvm_intrinsic(bcx, "llvm.exp2.f32", 1),
- "exp2f64" => simple_llvm_intrinsic(bcx, "llvm.exp2.f64", 1),
- "logf32" => simple_llvm_intrinsic(bcx, "llvm.log.f32", 1),
- "logf64" => simple_llvm_intrinsic(bcx, "llvm.log.f64", 1),
- "log10f32" => simple_llvm_intrinsic(bcx, "llvm.log10.f32", 1),
- "log10f64" => simple_llvm_intrinsic(bcx, "llvm.log10.f64", 1),
- "log2f32" => simple_llvm_intrinsic(bcx, "llvm.log2.f32", 1),
- "log2f64" => simple_llvm_intrinsic(bcx, "llvm.log2.f64", 1),
- "fmaf32" => simple_llvm_intrinsic(bcx, "llvm.fma.f32", 3),
- "fmaf64" => simple_llvm_intrinsic(bcx, "llvm.fma.f64", 3),
- "fabsf32" => simple_llvm_intrinsic(bcx, "llvm.fabs.f32", 1),
- "fabsf64" => simple_llvm_intrinsic(bcx, "llvm.fabs.f64", 1),
- "floorf32" => simple_llvm_intrinsic(bcx, "llvm.floor.f32", 1),
- "floorf64" => simple_llvm_intrinsic(bcx, "llvm.floor.f64", 1),
- "ceilf32" => simple_llvm_intrinsic(bcx, "llvm.ceil.f32", 1),
- "ceilf64" => simple_llvm_intrinsic(bcx, "llvm.ceil.f64", 1),
- "truncf32" => simple_llvm_intrinsic(bcx, "llvm.trunc.f32", 1),
- "truncf64" => simple_llvm_intrinsic(bcx, "llvm.trunc.f64", 1),
- "ctpop8" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i8", 1),
- "ctpop16" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i16", 1),
- "ctpop32" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i32", 1),
- "ctpop64" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i64", 1),
- "ctlz8" => count_zeros_intrinsic(bcx, "llvm.ctlz.i8"),
- "ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"),
- "ctlz32" => count_zeros_intrinsic(bcx, "llvm.ctlz.i32"),
- "ctlz64" => count_zeros_intrinsic(bcx, "llvm.ctlz.i64"),
- "cttz8" => count_zeros_intrinsic(bcx, "llvm.cttz.i8"),
- "cttz16" => count_zeros_intrinsic(bcx, "llvm.cttz.i16"),
- "cttz32" => count_zeros_intrinsic(bcx, "llvm.cttz.i32"),
- "cttz64" => count_zeros_intrinsic(bcx, "llvm.cttz.i64"),
- "bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1),
- "bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
- "bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
-
- "i8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i8"),
- "i16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i16"),
- "i32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i32"),
- "i64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i64"),
-
- "u8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i8"),
- "u16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i16"),
- "u32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i32"),
- "u64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i64"),
-
- "i8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i8"),
- "i16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i16"),
- "i32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i32"),
- "i64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i64"),
-
- "u8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i8"),
- "u16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i16"),
- "u32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i32"),
- "u64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i64"),
-
- "i8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i8"),
- "i16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i16"),
- "i32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i32"),
- "i64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i64"),
-
- "u8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i8"),
- "u16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i16"),
- "u32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i32"),
- "u64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i64"),
-
- _ => {
- // Could we make this an enum rather than a string? does it get
- // checked earlier?
- ccx.sess.span_bug(item.span, "unknown intrinsic");
- }
+pub fn trans_foreign_mod(ccx: @mut CrateContext,
+ foreign_mod: &ast::foreign_mod) {
+ let _icx = push_ctxt("foreign::trans_foreign_mod");
+ for &foreign_item in foreign_mod.items.iter() {
+ let lname = link_name(ccx, foreign_item);
+ ccx.item_symbols.insert(foreign_item.id, lname.to_owned());
}
- fcx.cleanup();
}
-/**
- * Translates a "crust" fn, meaning a Rust fn that can be called
- * from C code. In this case, we have to perform some adaptation
- * to (1) switch back to the Rust stack and (2) adapt the C calling
- * convention to our own.
- *
- * Example: Given a crust fn F(x: X, y: Y) -> Z, we generate a
- * Rust function R as normal:
- *
- * void R(Z* dest, void *env, X x, Y y) {...}
- *
- * and then we generate a wrapper function W that looks like:
- *
- * Z W(X x, Y y) {
- * struct { X x; Y y; Z *z; } args = { x, y, z };
- * call_on_c_stack_shim(S, &args);
- * }
- *
- * Note that the wrapper follows the foreign (typically "C") ABI.
- * The wrapper is the actual "value" of the foreign fn. Finally,
- * we generate a shim function S that looks like:
- *
- * void S(struct { X x; Y y; Z *z; } *args) {
- * R(args->z, NULL, args->x, args->y);
- * }
- */
-pub fn trans_foreign_fn(ccx: @mut CrateContext,
- path: ast_map::path,
- decl: &ast::fn_decl,
- body: &ast::Block,
- llwrapfn: ValueRef,
- id: ast::NodeId) {
+///////////////////////////////////////////////////////////////////////////
+// Rust functions with foreign ABIs
+//
+// These are normal Rust functions defined with foreign ABIs. For
+// now, and perhaps forever, we translate these using a "layer of
+// indirection". That is, given a Rust declaration like:
+//
+// extern "C" fn foo(i: u32) -> u32 { ... }
+//
+// we will generate a function like:
+//
+// S foo(T i) {
+// S r;
+// foo0(&r, NULL, i);
+// return r;
+// }
+//
+// #[inline_always]
+// void foo0(uint32_t *r, void *env, uint32_t i) { ... }
+//
+// Here the (internal) `foo0` function follows the Rust ABI as normal,
+// where the `foo` function follows the C ABI. We rely on LLVM to
+// inline the one into the other. Of course we could just generate the
+// correct code in the first place, but this is much simpler.
+
+pub fn register_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
+ sp: span,
+ sym: ~str,
+ node_id: ast::NodeId)
+ -> ValueRef {
+ let _icx = push_ctxt("foreign::register_foreign_fn");
+
+ let tys = foreign_types_for_id(ccx, node_id);
+ let llfn_ty = lltype_for_fn_from_foreign_types(&tys);
+ let llfn = base::register_fn_llvmty(ccx,
+ sp,
+ sym,
+ node_id,
+ lib::llvm::CCallConv,
+ llfn_ty);
+ add_argument_attributes(&tys, llfn);
+ debug!("register_rust_fn_with_foreign_abi(node_id=%?, llfn_ty=%s, llfn=%s)",
+ node_id, ccx.tn.type_to_str(llfn_ty), ccx.tn.val_to_str(llfn));
+ llfn
+}
+
+pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
+ path: &ast_map::path,
+ decl: &ast::fn_decl,
+ body: &ast::Block,
+ llwrapfn: ValueRef,
+ id: ast::NodeId) {
let _icx = push_ctxt("foreign::build_foreign_fn");
+ let tys = foreign_types_for_id(ccx, id);
+
+ unsafe { // unsafe because we call LLVM operations
+ // Build up the Rust function (`foo0` above).
+ let llrustfn = build_rust_fn(ccx, path, decl, body, id);
+
+ // Build up the foreign wrapper (`foo` above).
+ return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys);
+ }
fn build_rust_fn(ccx: @mut CrateContext,
path: &ast_map::path,
decl: &ast::fn_decl,
body: &ast::Block,
id: ast::NodeId)
- -> ValueRef {
+ -> ValueRef {
let _icx = push_ctxt("foreign::foreign::build_rust_fn");
- let t = ty::node_id_to_type(ccx.tcx, id);
- // XXX: Bad copy.
+ let tcx = ccx.tcx;
+ let t = ty::node_id_to_type(tcx, id);
let ps = link::mangle_internal_name_by_path(
- ccx,
- vec::append_one((*path).clone(),
- ast_map::path_name(
- special_idents::clownshoe_abi)));
+ ccx, vec::append_one((*path).clone(), ast_map::path_name(
+ special_idents::clownshoe_abi
+ )));
let llty = type_of_fn_from_ty(ccx, t);
- let llfndecl = decl_internal_cdecl_fn(ccx.llmod, ps, llty);
- trans_fn(ccx,
- (*path).clone(),
- decl,
- body,
- llfndecl,
- no_self,
- None,
- id,
- []);
+ let llfndecl = base::decl_internal_cdecl_fn(ccx.llmod, ps, llty);
+ base::trans_fn(ccx,
+ (*path).clone(),
+ decl,
+ body,
+ llfndecl,
+ base::no_self,
+ None,
+ id,
+ []);
return llfndecl;
}
- fn build_shim_fn(ccx: @mut CrateContext,
- path: ast_map::path,
- llrustfn: ValueRef,
- tys: &ShimTypes)
- -> ValueRef {
- /*!
- *
- * Generate the shim S:
- *
- * void S(struct { X x; Y y; Z *z; } *args) {
- * R(args->z, NULL, &args->x, args->y);
- * }
- *
- * One complication is that we must adapt to the Rust
- * calling convention, which introduces indirection
- * in some cases. To demonstrate this, I wrote one of the
- * entries above as `&args->x`, because presumably `X` is
- * one of those types that is passed by pointer in Rust.
- */
-
- let _icx = push_ctxt("foreign::foreign::build_shim_fn");
-
- fn build_args(bcx: @mut Block, tys: &ShimTypes, llargbundle: ValueRef)
- -> ~[ValueRef] {
- let _icx = push_ctxt("foreign::extern::shim::build_args");
- let ccx = bcx.ccx();
- let mut llargvals = ~[];
- let mut i = 0u;
- let n = tys.fn_sig.inputs.len();
-
- if !ty::type_is_immediate(bcx.tcx(), tys.fn_sig.output) {
- let llretptr = load_inbounds(bcx, llargbundle, [0u, n]);
- llargvals.push(llretptr);
+ unsafe fn build_wrap_fn(ccx: @mut CrateContext,
+ llrustfn: ValueRef,
+ llwrapfn: ValueRef,
+ tys: &ForeignTypes) {
+ let _icx = push_ctxt(
+ "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
+ let tcx = ccx.tcx;
+
+ debug!("build_wrap_fn(llrustfn=%s, llwrapfn=%s)",
+ ccx.tn.val_to_str(llrustfn),
+ ccx.tn.val_to_str(llwrapfn));
+
+ // Avoid all the Rust generation stuff and just generate raw
+ // LLVM here.
+ //
+ // We want to generate code like this:
+ //
+ // S foo(T i) {
+ // S r;
+ // foo0(&r, NULL, i);
+ // return r;
+ // }
+
+ let the_block =
+ "the block".to_c_str().with_ref(
+ |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llwrapfn, s));
+
+ let builder = ccx.builder.B;
+ llvm::LLVMPositionBuilderAtEnd(builder, the_block);
+
+ // Array for the arguments we will pass to the rust function.
+ let mut llrust_args = ~[];
+ let mut next_foreign_arg_counter: c_uint = 0;
+ let next_foreign_arg: &fn() -> c_uint = {
+ || {
+ next_foreign_arg_counter += 1;
+ next_foreign_arg_counter - 1
}
+ };
- let llenvptr = C_null(Type::opaque_box(bcx.ccx()).ptr_to());
- llargvals.push(llenvptr);
- while i < n {
- // Get a pointer to the argument:
- let mut llargval = GEPi(bcx, llargbundle, [0u, i]);
+ // If there is an out pointer on the foreign function
+ let foreign_outptr = {
+ if tys.fn_ty.sret {
+ Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg()))
+ } else {
+ None
+ }
+ };
- if !type_of::arg_is_indirect(ccx, &tys.fn_sig.inputs[i]) {
- // If Rust would pass this by value, load the value.
- llargval = Load(bcx, llargval);
+ // Push Rust return pointer, using null if it will be unused.
+ let rust_uses_outptr =
+ type_of::return_uses_outptr(tcx, tys.fn_sig.output);
+ let return_alloca: Option<ValueRef>;
+ let llrust_ret_ty = tys.llsig.llret_ty;
+ let llrust_retptr_ty = llrust_ret_ty.ptr_to();
+ if rust_uses_outptr {
+ // Rust expects to use an outpointer. If the foreign fn
+ // also uses an outpointer, we can reuse it, but the types
+ // may vary, so cast first to the Rust type. If the
+ // foriegn fn does NOT use an outpointer, we will have to
+ // alloca some scratch space on the stack.
+ match foreign_outptr {
+ Some(llforeign_outptr) => {
+ debug!("out pointer, foreign=%s",
+ ccx.tn.val_to_str(llforeign_outptr));
+ let llrust_retptr =
+ llvm::LLVMBuildBitCast(builder,
+ llforeign_outptr,
+ llrust_ret_ty.ptr_to().to_ref(),
+ noname());
+ debug!("out pointer, foreign=%s (casted)",
+ ccx.tn.val_to_str(llrust_retptr));
+ llrust_args.push(llrust_retptr);
+ return_alloca = None;
}
- llargvals.push(llargval);
- i += 1u;
+ None => {
+ let slot = {
+ "return_alloca".to_c_str().with_ref(
+ |s| llvm::LLVMBuildAlloca(builder,
+ llrust_ret_ty.to_ref(),
+ s))
+ };
+ debug!("out pointer, \
+ allocad=%s, \
+ llrust_ret_ty=%s, \
+ return_ty=%s",
+ ccx.tn.val_to_str(slot),
+ ccx.tn.type_to_str(llrust_ret_ty),
+ tys.fn_sig.output.repr(tcx));
+ llrust_args.push(slot);
+ return_alloca = Some(slot);
+ }
+ }
+ } else {
+ // Rust does not expect an outpointer. If the foreign fn
+ // does use an outpointer, then we will do a store of the
+ // value that the Rust fn returns.
+ return_alloca = None;
+ };
+
+ // Push an (null) env pointer
+ let env_pointer = base::null_env_ptr(ccx);
+ debug!("env pointer=%s", ccx.tn.val_to_str(env_pointer));
+ llrust_args.push(env_pointer);
+
+ // Build up the arguments to the call to the rust function.
+ // Careful to adapt for cases where the native convention uses
+ // a pointer and Rust does not or vice versa.
+ for i in range(0, tys.fn_sig.inputs.len()) {
+ let rust_ty = tys.fn_sig.inputs[i];
+ let llrust_ty = tys.llsig.llarg_tys[i];
+ let foreign_index = next_foreign_arg();
+ let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
+ let foreign_indirect = tys.fn_ty.attrs[foreign_index].is_some();
+ let mut llforeign_arg = llvm::LLVMGetParam(llwrapfn, foreign_index);
+
+ debug!("llforeign_arg #%u: %s",
+ i, ccx.tn.val_to_str(llforeign_arg));
+ debug!("rust_indirect = %b, foreign_indirect = %b",
+ rust_indirect, foreign_indirect);
+
+ // Ensure that the foreign argument is indirect (by
+ // pointer). It makes adapting types easier, since we can
+ // always just bitcast pointers.
+ if !foreign_indirect {
+ let lltemp =
+ llvm::LLVMBuildAlloca(
+ builder, val_ty(llforeign_arg).to_ref(), noname());
+ llvm::LLVMBuildStore(
+ builder, llforeign_arg, lltemp);
+ llforeign_arg = lltemp;
+ }
+
+ // If the types in the ABI and the Rust types don't match,
+ // bitcast the llforeign_arg pointer so it matches the types
+ // Rust expects.
+ if tys.fn_ty.arg_tys[foreign_index].cast {
+ assert!(!foreign_indirect);
+ llforeign_arg = llvm::LLVMBuildBitCast(
+ builder, llforeign_arg,
+ llrust_ty.ptr_to().to_ref(), noname());
}
- return llargvals;
- }
- fn build_ret(bcx: @mut Block,
- shim_types: &ShimTypes,
- llargbundle: ValueRef,
- llretval: ValueRef) {
- if bcx.fcx.llretptr.is_some() &&
- ty::type_is_immediate(bcx.tcx(), shim_types.fn_sig.output) {
- // Write the value into the argument bundle.
- let arg_count = shim_types.fn_sig.inputs.len();
- let llretptr = load_inbounds(bcx,
- llargbundle,
- [0, arg_count]);
- Store(bcx, llretval, llretptr);
+ let llrust_arg = if rust_indirect {
+ llforeign_arg
} else {
- // NB: The return pointer in the Rust ABI function is wired
- // directly into the return slot in the shim struct.
+ llvm::LLVMBuildLoad(builder, llforeign_arg, noname())
+ };
+
+ debug!("llrust_arg #%u: %s",
+ i, ccx.tn.val_to_str(llrust_arg));
+ llrust_args.push(llrust_arg);
+ }
+
+ // Perform the call itself
+ let llrust_ret_val = do llrust_args.as_imm_buf |ptr, len| {
+ debug!("calling llrustfn = %s", ccx.tn.val_to_str(llrustfn));
+ llvm::LLVMBuildCall(builder, llrustfn, ptr,
+ len as c_uint, noname())
+ };
+
+ // Get the return value where the foreign fn expects it.
+ let llforeign_ret_ty = tys.fn_ty.ret_ty.ty;
+ match foreign_outptr {
+ None if !tys.ret_def => {
+ // Function returns `()` or `bot`, which in Rust is the LLVM
+ // type "{}" but in foreign ABIs is "Void".
+ llvm::LLVMBuildRetVoid(builder);
+ }
+
+ None if rust_uses_outptr => {
+ // Rust uses an outpointer, but the foreign ABI does not. Load.
+ let llrust_outptr = return_alloca.unwrap();
+ let llforeign_outptr_casted =
+ llvm::LLVMBuildBitCast(builder,
+ llrust_outptr,
+ llforeign_ret_ty.ptr_to().to_ref(),
+ noname());
+ let llforeign_retval =
+ llvm::LLVMBuildLoad(builder, llforeign_outptr_casted, noname());
+ llvm::LLVMBuildRet(builder, llforeign_retval);
+ }
+
+ None if llforeign_ret_ty != llrust_ret_ty => {
+ // Neither ABI uses an outpointer, but the types don't
+ // quite match. Must cast. Probably we should try and
+ // examine the types and use a concrete llvm cast, but
+ // right now we just use a temp memory location and
+ // bitcast the pointer, which is the same thing the
+ // old wrappers used to do.
+ let lltemp =
+ llvm::LLVMBuildAlloca(
+ builder, llforeign_ret_ty.to_ref(), noname());
+ let lltemp_casted =
+ llvm::LLVMBuildBitCast(builder,
+ lltemp,
+ llrust_ret_ty.ptr_to().to_ref(),
+ noname());
+ llvm::LLVMBuildStore(
+ builder, llrust_ret_val, lltemp_casted);
+ let llforeign_retval =
+ llvm::LLVMBuildLoad(builder, lltemp, noname());
+ llvm::LLVMBuildRet(builder, llforeign_retval);
+ }
+
+ None => {
+ // Neither ABI uses an outpointer, and the types
+ // match. Easy peasy.
+ llvm::LLVMBuildRet(builder, llrust_ret_val);
+ }
+
+ Some(llforeign_outptr) if !rust_uses_outptr => {
+ // Foreign ABI requires an out pointer, but Rust doesn't.
+ // Store Rust return value.
+ let llforeign_outptr_casted =
+ llvm::LLVMBuildBitCast(builder,
+ llforeign_outptr,
+ llrust_retptr_ty.to_ref(),
+ noname());
+ llvm::LLVMBuildStore(
+ builder, llrust_ret_val, llforeign_outptr_casted);
+ llvm::LLVMBuildRetVoid(builder);
+ }
+
+ Some(_) => {
+ // Both ABIs use outpointers. Easy peasy.
+ llvm::LLVMBuildRetVoid(builder);
}
}
+ }
+}
- let shim_name = link::mangle_internal_name_by_path(
- ccx,
- vec::append_one(path, ast_map::path_name(
- special_idents::clownshoe_stack_shim
- )));
- build_shim_fn_(ccx,
- shim_name,
- llrustfn,
- tys,
- lib::llvm::CCallConv,
- build_args,
- build_ret)
+///////////////////////////////////////////////////////////////////////////
+// General ABI Support
+//
+// This code is kind of a confused mess and needs to be reworked given
+// the massive simplifications that have occurred.
+
+pub fn link_name(ccx: &CrateContext, i: @ast::foreign_item) -> @str {
+ match attr::first_attr_value_str_by_name(i.attrs, "link_name") {
+ None => ccx.sess.str_of(i.ident),
+ Some(ln) => ln,
}
+}
- fn build_wrap_fn(ccx: @mut CrateContext,
- llshimfn: ValueRef,
- llwrapfn: ValueRef,
- tys: &ShimTypes) {
- /*!
- *
- * Generate the wrapper W:
- *
- * Z W(X x, Y y) {
- * struct { X x; Y y; Z *z; } args = { x, y, z };
- * call_on_c_stack_shim(S, &args);
- * }
- */
-
- let _icx = push_ctxt("foreign::foreign::build_wrap_fn");
-
- build_wrap_fn_(ccx,
- tys,
- llshimfn,
- llwrapfn,
- ccx.upcalls.call_shim_on_rust_stack,
- true,
- build_args,
- build_ret);
-
- fn build_args(bcx: @mut Block,
- tys: &ShimTypes,
- llwrapfn: ValueRef,
- llargbundle: ValueRef) {
- let _icx = push_ctxt("foreign::foreign::wrap::build_args");
- tys.fn_ty.build_wrap_args(bcx,
- tys.llsig.llret_ty,
- llwrapfn,
- llargbundle);
- }
+fn foreign_signature(ccx: &mut CrateContext, fn_sig: &ty::FnSig)
+ -> LlvmSignature {
+ /*!
+ * The ForeignSignature is the LLVM types of the arguments/return type
+ * of a function. Note that these LLVM types are not quite the same
+ * as the LLVM types would be for a native Rust function because foreign
+ * functions just plain ignore modes. They also don't pass aggregate
+ * values by pointer like we do.
+ */
- fn build_ret(bcx: @mut Block, tys: &ShimTypes, llargbundle: ValueRef) {
- let _icx = push_ctxt("foreign::foreign::wrap::build_ret");
- tys.fn_ty.build_wrap_ret(bcx, tys.llsig.llarg_tys, llargbundle);
- }
+ let llarg_tys = fn_sig.inputs.map(|&arg| type_of(ccx, arg));
+ let llret_ty = type_of::type_of(ccx, fn_sig.output);
+ LlvmSignature {
+ llarg_tys: llarg_tys,
+ llret_ty: llret_ty,
+ sret: type_of::return_uses_outptr(ccx.tcx, fn_sig.output),
}
+}
- let tys = shim_types(ccx, id);
- // The internal Rust ABI function - runs on the Rust stack
- // XXX: Bad copy.
- let llrustfn = build_rust_fn(ccx, &path, decl, body, id);
- // The internal shim function - runs on the Rust stack
- let llshimfn = build_shim_fn(ccx, path, llrustfn, &tys);
- // The foreign C function - runs on the C stack
- build_wrap_fn(ccx, llshimfn, llwrapfn, &tys)
+fn foreign_types_for_id(ccx: &mut CrateContext,
+ id: ast::NodeId) -> ForeignTypes {
+ foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx, id))
}
-pub fn register_foreign_fn(ccx: @mut CrateContext,
- sp: span,
- sym: ~str,
- node_id: ast::NodeId)
- -> ValueRef {
- let _icx = push_ctxt("foreign::register_foreign_fn");
+fn foreign_types_for_fn_ty(ccx: &mut CrateContext,
+ ty: ty::t) -> ForeignTypes {
+ let fn_sig = match ty::get(ty).sty {
+ ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(),
+ _ => ccx.sess.bug("foreign_types_for_fn_ty called on non-function type")
+ };
+ let llsig = foreign_signature(ccx, &fn_sig);
+ let ret_def = !ty::type_is_voidish(fn_sig.output);
+ let fn_ty = cabi::compute_abi_info(ccx,
+ llsig.llarg_tys,
+ llsig.llret_ty,
+ ret_def);
+ debug!("foreign_types_for_fn_ty(\
+ ty=%s, \
+ llsig=%s -> %s, \
+ fn_ty=%s -> %s, \
+ ret_def=%b",
+ ty.repr(ccx.tcx),
+ ccx.tn.types_to_str(llsig.llarg_tys),
+ ccx.tn.type_to_str(llsig.llret_ty),
+ ccx.tn.types_to_str(fn_ty.arg_tys.map(|t| t.ty)),
+ ccx.tn.type_to_str(fn_ty.ret_ty.ty),
+ ret_def);
+
+ ForeignTypes {
+ fn_sig: fn_sig,
+ llsig: llsig,
+ ret_def: ret_def,
+ fn_ty: fn_ty
+ }
+}
- let sym = Cell::new(sym);
+fn lltype_for_fn_from_foreign_types(tys: &ForeignTypes) -> Type {
+ let llargument_tys: ~[Type] =
+ tys.fn_ty.arg_tys.iter().map(|t| t.ty).collect();
+ let llreturn_ty = tys.fn_ty.ret_ty.ty;
+ Type::func(llargument_tys, &llreturn_ty)
+}
+
+pub fn lltype_for_foreign_fn(ccx: &mut CrateContext, ty: ty::t) -> Type {
+ let fn_types = foreign_types_for_fn_ty(ccx, ty);
+ lltype_for_fn_from_foreign_types(&fn_types)
+}
- let tys = shim_types(ccx, node_id);
- do tys.fn_ty.decl_fn |fnty| {
- register_fn_llvmty(ccx, sp, sym.take(), node_id, lib::llvm::CCallConv, fnty)
+fn add_argument_attributes(tys: &ForeignTypes,
+ llfn: ValueRef) {
+ for (i, a) in tys.fn_ty.attrs.iter().enumerate() {
+ match *a {
+ Some(attr) => {
+ let llarg = get_param(llfn, i);
+ unsafe {
+ llvm::LLVMAddAttribute(llarg, attr as c_uint);
+ }
+ }
+ None => ()
+ }
}
}
let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc").to_managed();
note_unique_llvm_symbol(ccx, name);
debug!("+++ declare_tydesc %s %s", ppaux::ty_to_str(ccx.tcx, t), name);
- let gvar = do name.to_c_str().with_ref |buf| {
+ let gvar = do name.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type.to_ref(), buf)
}
--- /dev/null
+// 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.
+
+use back::{abi};
+use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg};
+use lib::llvm::{ValueRef, Pointer};
+use lib;
+use middle::trans::base::*;
+use middle::trans::build::*;
+use middle::trans::callee::*;
+use middle::trans::common::*;
+use middle::trans::datum::*;
+use middle::trans::type_of::*;
+use middle::trans::type_of;
+use middle::trans::expr::Ignore;
+use middle::trans::machine;
+use middle::trans::glue;
+use middle::ty::FnSig;
+use middle::ty;
+use syntax::ast;
+use syntax::ast_map;
+use syntax::attr;
+use syntax::opt_vec;
+use util::ppaux::{ty_to_str};
+use middle::trans::machine::llsize_of;
+use middle::trans::type_::Type;
+
+pub fn trans_intrinsic(ccx: @mut CrateContext,
+ decl: ValueRef,
+ item: &ast::foreign_item,
+ path: ast_map::path,
+ substs: @param_substs,
+ attributes: &[ast::Attribute],
+ ref_id: Option<ast::NodeId>) {
+ debug!("trans_intrinsic(item.ident=%s)", ccx.sess.str_of(item.ident));
+
+ fn simple_llvm_intrinsic(bcx: @mut Block, name: &'static str, num_args: uint) {
+ assert!(num_args <= 4);
+ let mut args = [0 as ValueRef, ..4];
+ let first_real_arg = bcx.fcx.arg_pos(0u);
+ for i in range(0u, num_args) {
+ args[i] = get_param(bcx.fcx.llfn, first_real_arg + i);
+ }
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+ Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
+ }
+
+ fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
+ let first_real_arg = bcx.fcx.arg_pos(0u);
+ let a = get_param(bcx.fcx.llfn, first_real_arg);
+ let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+
+ // convert `i1` to a `bool`, and write to the out parameter
+ let val = Call(bcx, llfn, [a, b]);
+ let result = ExtractValue(bcx, val, 0);
+ let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
+ let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
+ let ret = Load(bcx, retptr);
+ let ret = InsertValue(bcx, ret, result, 0);
+ let ret = InsertValue(bcx, ret, overflow, 1);
+ Store(bcx, ret, retptr);
+ RetVoid(bcx)
+ }
+
+ fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
+ let ccx = bcx.ccx();
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
+ let size = match sizebits {
+ 32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
+ 64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
+ _ => ccx.sess.fatal("Invalid value for sizebits")
+ };
+
+ let decl = bcx.fcx.llfn;
+ let first_real_arg = bcx.fcx.arg_pos(0u);
+ let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
+ let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
+ let count = get_param(decl, first_real_arg + 2);
+ let volatile = C_i1(false);
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+ Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
+ RetVoid(bcx);
+ }
+
+ fn memset_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
+ let ccx = bcx.ccx();
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
+ let size = match sizebits {
+ 32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
+ 64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
+ _ => ccx.sess.fatal("Invalid value for sizebits")
+ };
+
+ let decl = bcx.fcx.llfn;
+ let first_real_arg = bcx.fcx.arg_pos(0u);
+ let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
+ let val = get_param(decl, first_real_arg + 1);
+ let count = get_param(decl, first_real_arg + 2);
+ let volatile = C_i1(false);
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+ Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
+ RetVoid(bcx);
+ }
+
+ fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
+ let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
+ let y = C_i1(false);
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+ Ret(bcx, Call(bcx, llfn, [x, y]));
+ }
+
+ let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
+
+ let fcx = new_fn_ctxt_w_id(ccx,
+ path,
+ decl,
+ item.id,
+ output_type,
+ true,
+ Some(substs),
+ None,
+ Some(item.span));
+
+ set_always_inline(fcx.llfn);
+
+ // Set the fixed stack segment flag if necessary.
+ if attr::contains_name(attributes, "fixed_stack_segment") {
+ set_fixed_stack_segment(fcx.llfn);
+ }
+
+ let mut bcx = fcx.entry_bcx.unwrap();
+ let first_real_arg = fcx.arg_pos(0u);
+
+ let nm = ccx.sess.str_of(item.ident);
+ let name = nm.as_slice();
+
+ // This requires that atomic intrinsics follow a specific naming pattern:
+ // "atomic_<operation>[_<ordering>], and no ordering means SeqCst
+ if name.starts_with("atomic_") {
+ let split : ~[&str] = name.split_iter('_').collect();
+ assert!(split.len() >= 2, "Atomic intrinsic not correct format");
+ let order = if split.len() == 2 {
+ lib::llvm::SequentiallyConsistent
+ } else {
+ match split[2] {
+ "relaxed" => lib::llvm::Monotonic,
+ "acq" => lib::llvm::Acquire,
+ "rel" => lib::llvm::Release,
+ "acqrel" => lib::llvm::AcquireRelease,
+ _ => ccx.sess.fatal("Unknown ordering in atomic intrinsic")
+ }
+ };
+
+ match split[1] {
+ "cxchg" => {
+ let old = AtomicCmpXchg(bcx, get_param(decl, first_real_arg),
+ get_param(decl, first_real_arg + 1u),
+ get_param(decl, first_real_arg + 2u),
+ order);
+ Ret(bcx, old);
+ }
+ "load" => {
+ let old = AtomicLoad(bcx, get_param(decl, first_real_arg),
+ order);
+ Ret(bcx, old);
+ }
+ "store" => {
+ AtomicStore(bcx, get_param(decl, first_real_arg + 1u),
+ get_param(decl, first_real_arg),
+ order);
+ RetVoid(bcx);
+ }
+ "fence" => {
+ AtomicFence(bcx, order);
+ RetVoid(bcx);
+ }
+ op => {
+ // These are all AtomicRMW ops
+ let atom_op = match op {
+ "xchg" => lib::llvm::Xchg,
+ "xadd" => lib::llvm::Add,
+ "xsub" => lib::llvm::Sub,
+ "and" => lib::llvm::And,
+ "nand" => lib::llvm::Nand,
+ "or" => lib::llvm::Or,
+ "xor" => lib::llvm::Xor,
+ "max" => lib::llvm::Max,
+ "min" => lib::llvm::Min,
+ "umax" => lib::llvm::UMax,
+ "umin" => lib::llvm::UMin,
+ _ => ccx.sess.fatal("Unknown atomic operation")
+ };
+
+ let old = AtomicRMW(bcx, atom_op, get_param(decl, first_real_arg),
+ get_param(decl, first_real_arg + 1u),
+ order);
+ Ret(bcx, old);
+ }
+ }
+
+ fcx.cleanup();
+ return;
+ }
+
+ match name {
+ "size_of" => {
+ let tp_ty = substs.tys[0];
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)));
+ }
+ "move_val" => {
+ // Create a datum reflecting the value being moved.
+ // Use `appropriate_mode` so that the datum is by ref
+ // if the value is non-immediate. Note that, with
+ // intrinsics, there are no argument cleanups to
+ // concern ourselves with.
+ let tp_ty = substs.tys[0];
+ let mode = appropriate_mode(ccx.tcx, tp_ty);
+ let src = Datum {val: get_param(decl, first_real_arg + 1u),
+ ty: tp_ty, mode: mode};
+ bcx = src.move_to(bcx, DROP_EXISTING,
+ get_param(decl, first_real_arg));
+ RetVoid(bcx);
+ }
+ "move_val_init" => {
+ // See comments for `"move_val"`.
+ let tp_ty = substs.tys[0];
+ let mode = appropriate_mode(ccx.tcx, tp_ty);
+ let src = Datum {val: get_param(decl, first_real_arg + 1u),
+ ty: tp_ty, mode: mode};
+ bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg));
+ RetVoid(bcx);
+ }
+ "min_align_of" => {
+ let tp_ty = substs.tys[0];
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)));
+ }
+ "pref_align_of"=> {
+ let tp_ty = substs.tys[0];
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)));
+ }
+ "get_tydesc" => {
+ let tp_ty = substs.tys[0];
+ let static_ti = get_tydesc(ccx, tp_ty);
+ glue::lazily_emit_all_tydesc_glue(ccx, static_ti);
+
+ // FIXME (#3730): ideally this shouldn't need a cast,
+ // but there's a circularity between translating rust types to llvm
+ // types and having a tydesc type available. So I can't directly access
+ // the llvm type of intrinsic::TyDesc struct.
+ let userland_tydesc_ty = type_of::type_of(ccx, output_type);
+ let td = PointerCast(bcx, static_ti.tydesc, userland_tydesc_ty);
+ Ret(bcx, td);
+ }
+ "init" => {
+ let tp_ty = substs.tys[0];
+ let lltp_ty = type_of::type_of(ccx, tp_ty);
+ match bcx.fcx.llretptr {
+ Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); }
+ None if ty::type_is_nil(tp_ty) => RetVoid(bcx),
+ None => Ret(bcx, C_null(lltp_ty)),
+ }
+ }
+ "uninit" => {
+ // Do nothing, this is effectively a no-op
+ let retty = substs.tys[0];
+ if ty::type_is_immediate(ccx.tcx, retty) && !ty::type_is_nil(retty) {
+ unsafe {
+ Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref()));
+ }
+ } else {
+ RetVoid(bcx)
+ }
+ }
+ "forget" => {
+ RetVoid(bcx);
+ }
+ "transmute" => {
+ let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
+ let llintype = type_of::type_of(ccx, in_type);
+ let llouttype = type_of::type_of(ccx, out_type);
+
+ let in_type_size = machine::llbitsize_of_real(ccx, llintype);
+ let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
+ if in_type_size != out_type_size {
+ let sp = match ccx.tcx.items.get_copy(&ref_id.unwrap()) {
+ ast_map::node_expr(e) => e.span,
+ _ => fail!("transmute has non-expr arg"),
+ };
+ let pluralize = |n| if 1u == n { "" } else { "s" };
+ ccx.sess.span_fatal(sp,
+ fmt!("transmute called on types with \
+ different sizes: %s (%u bit%s) to \
+ %s (%u bit%s)",
+ ty_to_str(ccx.tcx, in_type),
+ in_type_size,
+ pluralize(in_type_size),
+ ty_to_str(ccx.tcx, out_type),
+ out_type_size,
+ pluralize(out_type_size)));
+ }
+
+ if !ty::type_is_voidish(out_type) {
+ let llsrcval = get_param(decl, first_real_arg);
+ if ty::type_is_immediate(ccx.tcx, in_type) {
+ match fcx.llretptr {
+ Some(llretptr) => {
+ Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
+ RetVoid(bcx);
+ }
+ None => match (llintype.kind(), llouttype.kind()) {
+ (Pointer, other) | (other, Pointer) if other != Pointer => {
+ let tmp = Alloca(bcx, llouttype, "");
+ Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
+ Ret(bcx, Load(bcx, tmp));
+ }
+ _ => Ret(bcx, BitCast(bcx, llsrcval, llouttype))
+ }
+ }
+ } else if ty::type_is_immediate(ccx.tcx, out_type) {
+ let llsrcptr = PointerCast(bcx, llsrcval, llouttype.ptr_to());
+ Ret(bcx, Load(bcx, llsrcptr));
+ } else {
+ // NB: Do not use a Load and Store here. This causes massive
+ // code bloat when `transmute` is used on large structural
+ // types.
+ let lldestptr = fcx.llretptr.unwrap();
+ let lldestptr = PointerCast(bcx, lldestptr, Type::i8p());
+ let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p());
+
+ let llsize = llsize_of(ccx, llintype);
+ call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
+ RetVoid(bcx);
+ };
+ } else {
+ RetVoid(bcx);
+ }
+ }
+ "needs_drop" => {
+ let tp_ty = substs.tys[0];
+ Ret(bcx, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)));
+ }
+ "contains_managed" => {
+ let tp_ty = substs.tys[0];
+ Ret(bcx, C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()));
+ }
+ "visit_tydesc" => {
+ let td = get_param(decl, first_real_arg);
+ let visitor = get_param(decl, first_real_arg + 1u);
+ let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to());
+ glue::call_tydesc_glue_full(bcx, visitor, td,
+ abi::tydesc_field_visit_glue, None);
+ RetVoid(bcx);
+ }
+ "frame_address" => {
+ let frameaddress = ccx.intrinsics.get_copy(& &"llvm.frameaddress");
+ let frameaddress_val = Call(bcx, frameaddress, [C_i32(0i32)]);
+ let star_u8 = ty::mk_imm_ptr(
+ bcx.tcx(),
+ ty::mk_mach_uint(ast::ty_u8));
+ let fty = ty::mk_closure(bcx.tcx(), ty::ClosureTy {
+ purity: ast::impure_fn,
+ sigil: ast::BorrowedSigil,
+ onceness: ast::Many,
+ region: ty::re_bound(ty::br_anon(0)),
+ bounds: ty::EmptyBuiltinBounds(),
+ sig: FnSig {
+ bound_lifetime_names: opt_vec::Empty,
+ inputs: ~[ star_u8 ],
+ output: ty::mk_nil()
+ }
+ });
+ let datum = Datum {val: get_param(decl, first_real_arg),
+ mode: ByRef(ZeroMem), ty: fty};
+ let arg_vals = ~[frameaddress_val];
+ bcx = trans_call_inner(
+ bcx, None, fty, ty::mk_nil(),
+ |bcx| Callee {bcx: bcx, data: Closure(datum)},
+ ArgVals(arg_vals), Some(Ignore), DontAutorefArg).bcx;
+ RetVoid(bcx);
+ }
+ "morestack_addr" => {
+ // XXX This is a hack to grab the address of this particular
+ // native function. There should be a general in-language
+ // way to do this
+ let llfty = type_of_rust_fn(bcx.ccx(), [], ty::mk_nil());
+ let morestack_addr = decl_cdecl_fn(
+ bcx.ccx().llmod, "__morestack", llfty);
+ let morestack_addr = PointerCast(bcx, morestack_addr, Type::nil().ptr_to());
+ Ret(bcx, morestack_addr);
+ }
+ "offset" => {
+ let ptr = get_param(decl, first_real_arg);
+ let offset = get_param(decl, first_real_arg + 1);
+ Ret(bcx, GEP(bcx, ptr, [offset]));
+ }
+ "offset_inbounds" => {
+ let ptr = get_param(decl, first_real_arg);
+ let offset = get_param(decl, first_real_arg + 1);
+ Ret(bcx, InBoundsGEP(bcx, ptr, [offset]));
+ }
+ "memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32),
+ "memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64),
+ "memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32),
+ "memmove64" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i64", substs.tys[0], 64),
+ "memset32" => memset_intrinsic(bcx, "llvm.memset.p0i8.i32", substs.tys[0], 32),
+ "memset64" => memset_intrinsic(bcx, "llvm.memset.p0i8.i64", substs.tys[0], 64),
+ "sqrtf32" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f32", 1),
+ "sqrtf64" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f64", 1),
+ "powif32" => simple_llvm_intrinsic(bcx, "llvm.powi.f32", 2),
+ "powif64" => simple_llvm_intrinsic(bcx, "llvm.powi.f64", 2),
+ "sinf32" => simple_llvm_intrinsic(bcx, "llvm.sin.f32", 1),
+ "sinf64" => simple_llvm_intrinsic(bcx, "llvm.sin.f64", 1),
+ "cosf32" => simple_llvm_intrinsic(bcx, "llvm.cos.f32", 1),
+ "cosf64" => simple_llvm_intrinsic(bcx, "llvm.cos.f64", 1),
+ "powf32" => simple_llvm_intrinsic(bcx, "llvm.pow.f32", 2),
+ "powf64" => simple_llvm_intrinsic(bcx, "llvm.pow.f64", 2),
+ "expf32" => simple_llvm_intrinsic(bcx, "llvm.exp.f32", 1),
+ "expf64" => simple_llvm_intrinsic(bcx, "llvm.exp.f64", 1),
+ "exp2f32" => simple_llvm_intrinsic(bcx, "llvm.exp2.f32", 1),
+ "exp2f64" => simple_llvm_intrinsic(bcx, "llvm.exp2.f64", 1),
+ "logf32" => simple_llvm_intrinsic(bcx, "llvm.log.f32", 1),
+ "logf64" => simple_llvm_intrinsic(bcx, "llvm.log.f64", 1),
+ "log10f32" => simple_llvm_intrinsic(bcx, "llvm.log10.f32", 1),
+ "log10f64" => simple_llvm_intrinsic(bcx, "llvm.log10.f64", 1),
+ "log2f32" => simple_llvm_intrinsic(bcx, "llvm.log2.f32", 1),
+ "log2f64" => simple_llvm_intrinsic(bcx, "llvm.log2.f64", 1),
+ "fmaf32" => simple_llvm_intrinsic(bcx, "llvm.fma.f32", 3),
+ "fmaf64" => simple_llvm_intrinsic(bcx, "llvm.fma.f64", 3),
+ "fabsf32" => simple_llvm_intrinsic(bcx, "llvm.fabs.f32", 1),
+ "fabsf64" => simple_llvm_intrinsic(bcx, "llvm.fabs.f64", 1),
+ "floorf32" => simple_llvm_intrinsic(bcx, "llvm.floor.f32", 1),
+ "floorf64" => simple_llvm_intrinsic(bcx, "llvm.floor.f64", 1),
+ "ceilf32" => simple_llvm_intrinsic(bcx, "llvm.ceil.f32", 1),
+ "ceilf64" => simple_llvm_intrinsic(bcx, "llvm.ceil.f64", 1),
+ "truncf32" => simple_llvm_intrinsic(bcx, "llvm.trunc.f32", 1),
+ "truncf64" => simple_llvm_intrinsic(bcx, "llvm.trunc.f64", 1),
+ "ctpop8" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i8", 1),
+ "ctpop16" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i16", 1),
+ "ctpop32" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i32", 1),
+ "ctpop64" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i64", 1),
+ "ctlz8" => count_zeros_intrinsic(bcx, "llvm.ctlz.i8"),
+ "ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"),
+ "ctlz32" => count_zeros_intrinsic(bcx, "llvm.ctlz.i32"),
+ "ctlz64" => count_zeros_intrinsic(bcx, "llvm.ctlz.i64"),
+ "cttz8" => count_zeros_intrinsic(bcx, "llvm.cttz.i8"),
+ "cttz16" => count_zeros_intrinsic(bcx, "llvm.cttz.i16"),
+ "cttz32" => count_zeros_intrinsic(bcx, "llvm.cttz.i32"),
+ "cttz64" => count_zeros_intrinsic(bcx, "llvm.cttz.i64"),
+ "bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1),
+ "bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
+ "bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
+
+ "i8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i8"),
+ "i16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i16"),
+ "i32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i32"),
+ "i64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i64"),
+
+ "u8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i8"),
+ "u16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i16"),
+ "u32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i32"),
+ "u64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i64"),
+
+ "i8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i8"),
+ "i16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i16"),
+ "i32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i32"),
+ "i64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i64"),
+
+ "u8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i8"),
+ "u16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i16"),
+ "u32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i32"),
+ "u64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i64"),
+
+ "i8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i8"),
+ "i16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i16"),
+ "i32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i32"),
+ "i64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i64"),
+
+ "u8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i8"),
+ "u16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i16"),
+ "u32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i32"),
+ "u64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i64"),
+
+ _ => {
+ // Could we make this an enum rather than a string? does it get
+ // checked earlier?
+ ccx.sess.span_bug(item.span, "unknown intrinsic");
+ }
+ }
+ fcx.cleanup();
+}
}
}
- typeck::method_trait(_, off) => {
+ typeck::method_object(ref mt) => {
trans_trait_callee(bcx,
callee_id,
- off,
+ mt.real_index,
this)
}
}
return (ty_substs, vtables);
}
-
pub fn trans_trait_callee(bcx: @mut Block,
callee_id: ast::NodeId,
n_method: uint,
/// This is used only for objects.
pub fn get_vtable(bcx: @mut Block,
self_ty: ty::t,
- origin: typeck::vtable_origin)
+ origins: typeck::vtable_param_res)
-> ValueRef {
- let hash_id = vtable_id(bcx.ccx(), &origin);
- match bcx.ccx().vtables.find(&hash_id) {
- Some(&val) => val,
- None => {
- match origin {
- typeck::vtable_static(id, substs, sub_vtables) => {
- make_impl_vtable(bcx, id, self_ty, substs, sub_vtables)
- }
- _ => fail!("get_vtable: expected a static origin"),
+ let ccx = bcx.ccx();
+ let _icx = push_ctxt("impl::get_vtable");
+
+ // Check the cache.
+ let hash_id = (self_ty, vtable_id(ccx, &origins[0]));
+ match ccx.vtables.find(&hash_id) {
+ Some(&val) => { return val }
+ None => { }
+ }
+
+ // Not in the cache. Actually build it.
+ let methods = do origins.flat_map |origin| {
+ match *origin {
+ typeck::vtable_static(id, ref substs, sub_vtables) => {
+ emit_vtable_methods(bcx, id, *substs, sub_vtables)
}
+ _ => ccx.sess.bug("get_vtable: expected a static origin"),
}
- }
+ };
+
+ // Generate a type descriptor for the vtable.
+ let tydesc = get_tydesc(ccx, self_ty);
+ glue::lazily_emit_all_tydesc_glue(ccx, tydesc);
+
+ let vtable = make_vtable(ccx, tydesc, methods);
+ ccx.vtables.insert(hash_id, vtable);
+ return vtable;
}
/// Helper function to declare and initialize the vtable.
let tbl = C_struct(components);
let vtable = ccx.sess.str_of(gensym_name("vtable"));
- let vt_gvar = do vtable.to_c_str().with_ref |buf| {
+ let vt_gvar = do vtable.with_c_str |buf| {
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl).to_ref(), buf)
};
llvm::LLVMSetInitializer(vt_gvar, tbl);
}
}
-/// Generates a dynamic vtable for objects.
-pub fn make_impl_vtable(bcx: @mut Block,
- impl_id: ast::def_id,
- self_ty: ty::t,
- substs: &[ty::t],
- vtables: typeck::vtable_res)
- -> ValueRef {
+fn emit_vtable_methods(bcx: @mut Block,
+ impl_id: ast::def_id,
+ substs: &[ty::t],
+ vtables: typeck::vtable_res)
+ -> ~[ValueRef] {
let ccx = bcx.ccx();
- let _icx = push_ctxt("impl::make_impl_vtable");
let tcx = ccx.tcx;
let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
};
let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
- let methods = do trait_method_def_ids.map |method_def_id| {
+ do trait_method_def_ids.map |method_def_id| {
let im = ty::method(tcx, *method_def_id);
let fty = ty::subst_tps(tcx,
substs,
trans_fn_ref_with_vtables(bcx, m_id, 0,
substs, Some(vtables)).llfn
}
- };
-
- // Generate a type descriptor for the vtable.
- let tydesc = get_tydesc(ccx, self_ty);
- glue::lazily_emit_all_tydesc_glue(ccx, tydesc);
-
- make_vtable(ccx, tydesc, methods)
+ }
}
pub fn trans_trait_cast(bcx: @mut Block,
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
// Store the vtable into the pair or triple.
- let orig = ccx.maps.vtable_map.get(&id)[0][0].clone();
- let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, &orig);
- let vtable = get_vtable(bcx, v_ty, orig);
+ // This is structured a bit funny because of dynamic borrow failures.
+ let origins = {
+ let res = ccx.maps.vtable_map.get(&id);
+ let res = resolve_vtables_in_fn_ctxt(bcx.fcx, *res);
+ res[0]
+ };
+ let vtable = get_vtable(bcx, v_ty, origins);
Store(bcx, vtable, PointerCast(bcx,
GEPi(bcx, lldest, [0u, abi::trt_field_vtable]),
val_ty(vtable).ptr_to()));
pub mod cabi_arm;
pub mod cabi_mips;
pub mod foreign;
+pub mod intrinsic;
pub mod reflect;
pub mod debuginfo;
pub mod type_use;
use back::link::mangle_exported_name;
use driver::session;
use lib::llvm::ValueRef;
-use middle::trans::base::{set_inline_hint_if_appr, set_inline_hint};
+use middle::trans::base::{set_llvm_fn_attrs, set_inline_hint};
use middle::trans::base::{trans_enum_variant,push_ctxt};
use middle::trans::base::{trans_fn, decl_internal_cdecl_fn};
use middle::trans::base::{get_item_val, no_self};
use middle::trans::base;
use middle::trans::common::*;
use middle::trans::datum;
-use middle::trans::foreign;
use middle::trans::machine;
use middle::trans::meth;
use middle::trans::type_of::type_of_fn_from_ty;
use middle::trans::type_of;
use middle::trans::type_use;
+use middle::trans::intrinsic;
use middle::ty;
use middle::ty::{FnSig};
use middle::typeck;
_
}, _) => {
let d = mk_lldecl();
- set_inline_hint_if_appr(i.attrs, d);
+ set_llvm_fn_attrs(i.attrs, d);
trans_fn(ccx,
pt,
decl,
}
ast_map::node_foreign_item(i, _, _, _) => {
let d = mk_lldecl();
- foreign::trans_intrinsic(ccx, d, i, pt, psubsts, i.attrs,
- ref_id);
+ intrinsic::trans_intrinsic(ccx, d, i, pt, psubsts, i.attrs,
+ ref_id);
d
}
ast_map::node_variant(ref v, enum_item, _) => {
ast_map::node_method(mth, _, _) => {
// XXX: What should the self type be here?
let d = mk_lldecl();
- set_inline_hint_if_appr(mth.attrs.clone(), d);
+ set_llvm_fn_attrs(mth.attrs, d);
meth::trans_method(ccx, pt, mth, Some(psubsts), d);
d
}
ast_map::node_trait_method(@ast::provided(mth), _, pt) => {
let d = mk_lldecl();
- set_inline_hint_if_appr(mth.attrs.clone(), d);
+ set_llvm_fn_attrs(mth.attrs, d);
meth::trans_method(ccx, (*pt).clone(), mth, Some(psubsts), d);
d
}
sub_path,
"get_disr");
- let llfty = type_of_fn(ccx, [opaqueptrty], ty::mk_int());
+ let llfty = type_of_rust_fn(ccx, [opaqueptrty], ty::mk_int());
let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
let fcx = new_fn_ctxt(ccx,
~[],
Ignore => bcx,
SaveIn(lldest) => {
unsafe {
- let bytes = str_lit.len(); // count null-terminator too
+ let bytes = str_lit.len();
let llbytes = C_uint(bcx.ccx(), bytes);
let llcstr = C_cstr(bcx.ccx(), str_lit);
let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p().to_ref());
pub fn named_struct(name: &str) -> Type {
let ctx = base::task_llcx();
- ty!(name.to_c_str().with_ref(|s| llvm::LLVMStructCreateNamed(ctx, s)))
+ ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ctx, s)))
}
pub fn empty_struct() -> Type {
use middle::trans::adt;
use middle::trans::common::*;
+use middle::trans::foreign;
use middle::ty;
use util::ppaux;
use syntax::ast;
use syntax::opt_vec;
-pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: &ty::t) -> bool {
- !ty::type_is_immediate(ccx.tcx, *arg_ty)
+pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: ty::t) -> bool {
+ !ty::type_is_immediate(ccx.tcx, arg_ty)
}
-pub fn type_of_explicit_arg(ccx: &mut CrateContext, arg_ty: &ty::t) -> Type {
- let llty = type_of(ccx, *arg_ty);
+pub fn return_uses_outptr(tcx: ty::ctxt, ty: ty::t) -> bool {
+ !ty::type_is_immediate(tcx, ty)
+}
+
+pub fn type_of_explicit_arg(ccx: &mut CrateContext, arg_ty: ty::t) -> Type {
+ let llty = type_of(ccx, arg_ty);
if arg_is_indirect(ccx, arg_ty) {
llty.ptr_to()
} else {
pub fn type_of_explicit_args(ccx: &mut CrateContext,
inputs: &[ty::t]) -> ~[Type] {
- inputs.map(|arg_ty| type_of_explicit_arg(ccx, arg_ty))
+ inputs.map(|&arg_ty| type_of_explicit_arg(ccx, arg_ty))
}
-pub fn type_of_fn(cx: &mut CrateContext, inputs: &[ty::t], output: ty::t) -> Type {
+pub fn type_of_rust_fn(cx: &mut CrateContext,
+ inputs: &[ty::t],
+ output: ty::t) -> Type {
let mut atys: ~[Type] = ~[];
// Arg 0: Output pointer.
// (if the output type is non-immediate)
- let output_is_immediate = ty::type_is_immediate(cx.tcx, output);
+ let use_out_pointer = return_uses_outptr(cx.tcx, output);
let lloutputtype = type_of(cx, output);
- if !output_is_immediate {
+ if use_out_pointer {
atys.push(lloutputtype.ptr_to());
}
atys.push_all(type_of_explicit_args(cx, inputs));
// Use the output as the actual return value if it's immediate.
- if output_is_immediate && !ty::type_is_nil(output) {
+ if !use_out_pointer && !ty::type_is_voidish(output) {
Type::func(atys, &lloutputtype)
} else {
Type::func(atys, &Type::void())
// Given a function type and a count of ty params, construct an llvm type
pub fn type_of_fn_from_ty(cx: &mut CrateContext, fty: ty::t) -> Type {
- match ty::get(fty).sty {
- ty::ty_closure(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output),
- ty::ty_bare_fn(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output),
+ return match ty::get(fty).sty {
+ ty::ty_closure(ref f) => {
+ type_of_rust_fn(cx, f.sig.inputs, f.sig.output)
+ }
+ ty::ty_bare_fn(ref f) => {
+ if f.abis.is_rust() || f.abis.is_intrinsic() {
+ type_of_rust_fn(cx, f.sig.inputs, f.sig.output)
+ } else {
+ foreign::lltype_for_foreign_fn(cx, fty)
+ }
+ }
_ => {
cx.sess.bug("type_of_fn_from_ty given non-closure, non-bare-fn")
}
- }
+ };
}
// A "sizing type" is an LLVM type, the size and alignment of which are
Type::array(&type_of(cx, mt.ty), n as u64)
}
- ty::ty_bare_fn(_) => type_of_fn_from_ty(cx, t).ptr_to(),
+ ty::ty_bare_fn(_) => {
+ type_of_fn_from_ty(cx, t).ptr_to()
+ }
ty::ty_closure(_) => {
let ty = type_of_fn_from_ty(cx, t);
Type::func_pair(cx, &ty)
use syntax::ast_map;
use syntax::ast_util;
use syntax::parse::token;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
pub type type_uses = uint; // Bitmask
pub static use_repr: uint = 1; /* Dependency on size/alignment/mode and
pub static use_tydesc: uint = 2; /* Takes the tydesc, or compares */
pub static use_all: uint = use_repr|use_tydesc;
-
+#[deriving(Clone)]
pub struct Context {
ccx: @mut CrateContext,
uses: @mut ~[type_uses]
}
}
-pub fn handle_body(cx: &Context, body: &Block) {
- let v = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: |e, (cx, v)| {
- oldvisit::visit_expr(e, (cx, v));
+struct TypeUseVisitor;
+
+impl<'self> Visitor<&'self Context> for TypeUseVisitor {
+
+ fn visit_expr<'a>(&mut self, e:@expr, cx: &'a Context) {
+ visit::walk_expr(self, e, cx);
mark_for_expr(cx, e);
- },
- visit_local: |l, (cx, v)| {
- oldvisit::visit_local(l, (cx, v));
+ }
+
+ fn visit_local<'a>(&mut self, l:@Local, cx: &'a Context) {
+ visit::walk_local(self, l, cx);
node_type_needs(cx, use_repr, l.id);
- },
- visit_pat: |p, (cx, v)| {
- oldvisit::visit_pat(p, (cx, v));
+ }
+
+ fn visit_pat<'a>(&mut self, p:@pat, cx: &'a Context) {
+ visit::walk_pat(self, p, cx);
node_type_needs(cx, use_repr, p.id);
- },
- visit_block: |b, (cx, v)| {
- oldvisit::visit_block(b, (cx, v));
+ }
+
+ fn visit_block<'a>(&mut self, b:&Block, cx: &'a Context) {
+ visit::walk_block(self, b, cx);
for e in b.expr.iter() {
node_type_needs(cx, use_repr, e.id);
}
- },
- visit_item: |_i, (_cx, _v)| { },
- ..*oldvisit::default_visitor()
- });
- (v.visit_block)(body, (cx, v));
+ }
+
+ fn visit_item<'a>(&mut self, _:@item, _: &'a Context) {
+ // do nothing
+ }
+
+}
+
+pub fn handle_body(cx: &Context, body: &Block) {
+ let mut v = TypeUseVisitor;
+ v.visit_block(body, cx);
}
use std::ptr::to_unsafe_ptr;
use std::to_bytes;
use std::to_str::ToStr;
-use std::u32;
use std::vec;
use syntax::ast::*;
use syntax::ast_util::is_local;
mt: mt
}
+#[deriving(Clone)]
pub struct Method {
ident: ast::ident,
generics: ty::Generics,
// Type utilities
+pub fn type_is_voidish(ty: t) -> bool {
+ //! "nil" and "bot" are void types in that they represent 0 bits of information
+ type_is_nil(ty) || type_is_bot(ty)
+}
+
pub fn type_is_nil(ty: t) -> bool { get(ty).sty == ty_nil }
pub fn type_is_bot(ty: t) -> bool {
impl ToStr for TypeContents {
fn to_str(&self) -> ~str {
- fmt!("TypeContents(%s)", u32::to_str_radix(self.bits, 2))
+ fmt!("TypeContents(%s)", self.bits.to_str_radix(2))
}
}
typeck::method_param(typeck::method_param {
trait_id: trt_id,
method_num: n_mth, _}) |
- typeck::method_trait(trt_id, n_mth) => {
+ typeck::method_object(typeck::method_object {
+ trait_id: trt_id,
+ method_num: n_mth, _}) => {
// ...trait methods bounds, in contrast, include only the
// method bounds, so we must preprend the tps from the
// trait itself. This ought to be harmonized.
let trait_type_param_defs =
- ty::lookup_trait_def(tcx, trt_id).generics.type_param_defs;
+ lookup_trait_def(tcx, trt_id).generics.type_param_defs;
@vec::append(
(*trait_type_param_defs).clone(),
*ty::trait_method(tcx,
kind_name = "variant";
}
None => {
+ // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
fcx.infcx().type_error_message_str_with_expected(pat.span,
|expected, actual| {
expected.map_move_default(~"", |e| {
kind_name = "structure";
}
_ => {
+ // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
fcx.infcx().type_error_message_str_with_expected(pat.span,
|expected, actual| {
expected.map_move_default(~"", |e| {
}
None => {
let name = pprust::path_to_str(path, tcx.sess.intr());
+ // Check the pattern anyway, so that attempts to look
+ // up its type won't fail
+ check_pat(pcx, field.pat, ty::mk_err());
tcx.sess.span_err(span,
- fmt!("struct `%s` does not have a field
- named `%s`", name,
- tcx.sess.str_of(field.ident)));
+ fmt!("struct `%s` does not have a field named `%s`",
+ name,
+ tcx.sess.str_of(field.ident)));
}
}
}
pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: span,
expected: ty::t, path: &ast::Path,
fields: &[ast::field_pat], etc: bool,
- class_id: ast::def_id, substitutions: &ty::substs) {
+ struct_id: ast::def_id,
+ substitutions: &ty::substs) {
let fcx = pcx.fcx;
let tcx = pcx.fcx.ccx.tcx;
- let class_fields = ty::lookup_struct_fields(tcx, class_id);
+ let class_fields = ty::lookup_struct_fields(tcx, struct_id);
// Check to ensure that the struct is the one specified.
match tcx.def_map.find(&pat_id) {
Some(&ast::def_struct(supplied_def_id))
- if supplied_def_id == class_id => {
+ if supplied_def_id == struct_id => {
// OK.
}
Some(&ast::def_struct(*)) | Some(&ast::def_variant(*)) => {
name));
}
_ => {
- tcx.sess.span_bug(span, "resolve didn't write in class");
+ tcx.sess.span_bug(span, "resolve didn't write in struct ID");
}
}
- check_struct_pat_fields(pcx, span, path, fields, class_fields, class_id,
+ check_struct_pat_fields(pcx, span, path, fields, class_fields, struct_id,
substitutions, etc);
}
substs);
}
_ => {
- tcx.sess.span_err(pat.span,
- fmt!("mismatched types: expected `%s` but found struct",
- fcx.infcx().ty_to_str(expected)));
+ // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
+ fcx.infcx().type_error_message_str_with_expected(pat.span,
+ |expected, actual| {
+ expected.map_move_default(~"", |e| {
+ fmt!("mismatched types: expected `%s` but found %s",
+ e, actual)})},
+ Some(expected), ~"a structure pattern",
+ None);
+ match tcx.def_map.find(&pat.id) {
+ Some(&ast::def_struct(supplied_def_id)) => {
+ check_struct_pat(pcx, pat.id, pat.span, ty::mk_err(), path, *fields, etc,
+ supplied_def_id,
+ &ty::substs { self_ty: None, tps: ~[], regions: ty::ErasedRegions} );
+ }
+ _ => () // Error, but we're already in an error case
+ }
error_happened = true;
}
}
found: e_count}),
_ => ty::terr_mismatch
};
+ // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| {
expected.map_move_default(~"", |e| {
fmt!("mismatched types: expected `%s` but found %s",
for &elt in after.iter() {
check_pat(pcx, elt, ty::mk_err());
}
+ // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
fcx.infcx().type_error_message_str_with_expected(
pat.span,
|expected, actual| {
}
_ => {
check_pat(pcx, inner, ty::mk_err());
+ // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
fcx.infcx().type_error_message_str_with_expected(
span,
|expected, actual| {
use middle::typeck::check;
use middle::typeck::infer;
use middle::typeck::{method_map_entry, method_origin, method_param};
-use middle::typeck::{method_static, method_trait};
+use middle::typeck::{method_static, method_object};
use middle::typeck::{param_numbered, param_self, param_index};
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
use util::common::indenter;
loop {
match get(self_ty).sty {
ty_trait(did, ref substs, _, _, _) => {
- self.push_inherent_candidates_from_trait(did, substs);
+ self.push_inherent_candidates_from_object(did, substs);
self.push_inherent_impl_candidates_for_type(did);
}
ty_enum(did, _) | ty_struct(did, _) => {
}
}
- fn push_inherent_candidates_from_trait(&self,
- did: def_id,
- substs: &ty::substs) {
- debug!("push_inherent_candidates_from_trait(did=%s, substs=%s)",
- self.did_to_str(did),
- substs_to_str(self.tcx(), substs));
- let _indenter = indenter();
-
+ // Determine the index of a method in the list of all methods belonging
+ // to a trait and its supertraits.
+ fn get_method_index(&self,
+ trait_ref: @TraitRef,
+ subtrait_id: ast::def_id,
+ n_method: uint) -> uint {
let tcx = self.tcx();
- let ms = ty::trait_methods(tcx, did);
- let index = match ms.iter().position(|m| m.ident == self.m_name) {
- Some(i) => i,
- None => { return; } // no method with the right name
- };
- let method = ms[index];
- match method.explicit_self {
- ast::sty_static => {
- return; // not a method we can call with dot notation
+ // We need to figure the "real index" of the method in a
+ // listing of all the methods of an object. We do this by
+ // iterating down the supertraits of the object's trait until
+ // we find the trait the method came from, counting up the
+ // methods from them.
+ let mut method_count = 0;
+ do ty::each_bound_trait_and_supertraits(tcx, &[trait_ref])
+ |bound_ref| {
+ if bound_ref.def_id == subtrait_id { false }
+ else {
+ method_count += ty::trait_methods(tcx, bound_ref.def_id).len();
+ true
}
- _ => {}
- }
+ };
+
+ return method_count + n_method;
+ }
+
+
+ fn push_inherent_candidates_from_object(&self,
+ did: def_id,
+ substs: &ty::substs) {
+ debug!("push_inherent_candidates_from_object(did=%s, substs=%s)",
+ self.did_to_str(did),
+ substs_to_str(self.tcx(), substs));
+ let _indenter = indenter();
// It is illegal to invoke a method on a trait instance that
// refers to the `self` type. An error will be reported by
// to the `Self` type. Substituting ty_err here allows
// compiler to soldier on.
//
- // NOTE: `confirm_candidate()` also relies upon this substitution
+ // `confirm_candidate()` also relies upon this substitution
// for Self. (fix)
let rcvr_substs = substs {
self_ty: Some(ty::mk_err()),
..(*substs).clone()
};
-
- self.inherent_candidates.push(Candidate {
- rcvr_match_condition: RcvrMatchesIfObject(did),
- rcvr_substs: rcvr_substs,
- method_ty: method,
- origin: method_trait(did, index)
- });
+ let trait_ref = @TraitRef { def_id: did, substs: rcvr_substs.clone() };
+
+ do self.push_inherent_candidates_from_bounds_inner(&[trait_ref])
+ |trait_ref, m, method_num, _bound_num| {
+ let vtable_index =
+ self.get_method_index(trait_ref, trait_ref.def_id, method_num);
+ // We need to fix up the transformed self type.
+ let transformed_self_ty =
+ self.construct_transformed_self_ty_for_object(
+ did, &rcvr_substs, m);
+ let m = @Method {
+ transformed_self_ty: Some(transformed_self_ty),
+ .. (*m).clone()
+ };
+
+ Candidate {
+ rcvr_match_condition: RcvrMatchesIfObject(did),
+ rcvr_substs: trait_ref.substs.clone(),
+ method_ty: m,
+ origin: method_object(method_object {
+ trait_id: trait_ref.def_id,
+ object_trait_id: did,
+ method_num: method_num,
+ real_index: vtable_index
+ })
+ }
+ };
}
fn push_inherent_candidates_from_param(&self,
- rcvr_ty: ty::t,
- param_ty: param_ty) {
+ rcvr_ty: ty::t,
+ param_ty: param_ty) {
debug!("push_inherent_candidates_from_param(param_ty=%?)",
param_ty);
let _indenter = indenter();
}
fn push_inherent_candidates_from_bounds(&self,
- self_ty: ty::t,
- bounds: &[@TraitRef],
- param: param_index) {
+ self_ty: ty::t,
+ bounds: &[@TraitRef],
+ param: param_index) {
+ do self.push_inherent_candidates_from_bounds_inner(bounds)
+ |trait_ref, m, method_num, bound_num| {
+ Candidate {
+ rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
+ rcvr_substs: trait_ref.substs.clone(),
+ method_ty: m,
+ origin: method_param(
+ method_param {
+ trait_id: trait_ref.def_id,
+ method_num: method_num,
+ param_num: param,
+ bound_num: bound_num,
+ })
+ }
+ }
+ }
+
+ // Do a search through a list of bounds, using a callback to actually
+ // create the candidates.
+ fn push_inherent_candidates_from_bounds_inner(
+ &self,
+ bounds: &[@TraitRef],
+ mk_cand: &fn(trait_ref: @TraitRef, m: @ty::Method, method_num: uint,
+ bound_num: uint) -> Candidate) {
+
let tcx = self.tcx();
let mut next_bound_idx = 0; // count only trait bounds
Some(pos) => {
let method = trait_methods[pos];
- let cand = Candidate {
- rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
- rcvr_substs: bound_trait_ref.substs.clone(),
- method_ty: method,
- origin: method_param(
- method_param {
- trait_id: bound_trait_ref.def_id,
- method_num: pos,
- param_num: param,
- bound_num: this_bound_idx,
- })
- };
+ let cand = mk_cand(bound_trait_ref, method,
+ pos, this_bound_idx);
debug!("pushing inherent candidate for param: %?", cand);
self.inherent_candidates.push(cand);
fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
-> method_map_entry {
let tcx = self.tcx();
- let fty = self.fn_ty_from_origin(&candidate.origin);
+ let fty = ty::mk_bare_fn(tcx, candidate.method_ty.fty.clone());
debug!("confirm_candidate(expr=%s, candidate=%s, fty=%s)",
self.expr.repr(tcx),
// static methods should never have gotten this far:
assert!(candidate.method_ty.explicit_self != sty_static);
-
- let transformed_self_ty = match candidate.origin {
- method_trait(trait_def_id, _) => {
- self.construct_transformed_self_ty_for_object(
- trait_def_id, candidate)
- }
- _ => {
- let t = candidate.method_ty.transformed_self_ty.unwrap();
- ty::subst(tcx, &candidate.rcvr_substs, t)
- }
- };
+ let transformed_self_ty =
+ ty::subst(tcx, &candidate.rcvr_substs,
+ candidate.method_ty.transformed_self_ty.unwrap());
// Determine the values for the type parameters of the method.
// If they were not explicitly supplied, just construct fresh
}
}
- fn construct_transformed_self_ty_for_object(&self,
- trait_def_id: ast::def_id,
- candidate: &Candidate) -> ty::t
+ fn construct_transformed_self_ty_for_object(
+ &self,
+ trait_def_id: ast::def_id,
+ rcvr_substs: &ty::substs,
+ method_ty: &ty::Method) -> ty::t
{
/*!
* This is a bit tricky. We have a match against a trait method
* result to be `&'a Foo`. Assuming that `m_method` is being
* called, we want the result to be `@mut Foo`. Of course,
* this transformation has already been done as part of
- * `candidate.method_ty.transformed_self_ty`, but there the
+ * `method_ty.transformed_self_ty`, but there the
* type is expressed in terms of `Self` (i.e., `&'a Self`, `@mut Self`).
* Because objects are not standalone types, we can't just substitute
* `s/Self/Foo/`, so we must instead perform this kind of hokey
* match below.
*/
- let substs = ty::substs {regions: candidate.rcvr_substs.regions.clone(),
+ let substs = ty::substs {regions: rcvr_substs.regions.clone(),
self_ty: None,
- tps: candidate.rcvr_substs.tps.clone()};
- match candidate.method_ty.explicit_self {
+ tps: rcvr_substs.tps.clone()};
+ match method_ty.explicit_self {
ast::sty_static => {
self.bug(~"static method for object type receiver");
}
}
ast::sty_region(*) | ast::sty_box(*) | ast::sty_uniq(*) => {
let transformed_self_ty =
- candidate.method_ty.transformed_self_ty.clone().unwrap();
+ method_ty.transformed_self_ty.clone().unwrap();
match ty::get(transformed_self_ty).sty {
ty::ty_rptr(r, mt) => { // must be sty_region
ty::mk_trait(self.tcx(), trait_def_id,
method_static(*) | method_param(*) => {
return; // not a call to a trait instance
}
- method_trait(*) => {}
+ method_object(*) => {}
}
match candidate.method_ty.explicit_self {
// XXX: does this properly enforce this on everything now
// that self has been merged in? -sully
method_param(method_param { trait_id: trait_id, _ }) |
- method_trait(trait_id, _) => {
+ method_object(method_object { trait_id: trait_id, _ }) => {
bad = self.tcx().destructor_for_type.contains_key(&trait_id);
}
}
}
}
- fn fn_ty_from_origin(&self, origin: &method_origin) -> ty::t {
- return match *origin {
- method_static(did) => {
- ty::lookup_item_type(self.tcx(), did).ty
- }
- method_param(ref mp) => {
- type_of_trait_method(self.tcx(), mp.trait_id, mp.method_num)
- }
- method_trait(did, idx) => {
- type_of_trait_method(self.tcx(), did, idx)
- }
- };
-
- fn type_of_trait_method(tcx: ty::ctxt,
- trait_did: def_id,
- method_num: uint) -> ty::t {
- let trait_methods = ty::trait_methods(tcx, trait_did);
- ty::mk_bare_fn(tcx, trait_methods[method_num].fty.clone())
- }
- }
-
fn report_candidate(&self, idx: uint, origin: &method_origin) {
match *origin {
method_static(impl_did) => {
method_param(ref mp) => {
self.report_param_candidate(idx, (*mp).trait_id)
}
- method_trait(trait_did, _) => {
- self.report_trait_candidate(idx, trait_did)
+ method_object(ref mo) => {
+ self.report_trait_candidate(idx, mo.trait_id)
}
}
}
use syntax::parse::token;
use syntax::parse::token::special_idents;
use syntax::print::pprust;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
use syntax;
pub mod _match;
}
}
+struct CheckItemTypesVisitor { ccx: @mut CrateCtxt }
+
+impl Visitor<()> for CheckItemTypesVisitor {
+ fn visit_item(&mut self, i:@ast::item, _:()) {
+ check_item(self.ccx, i);
+ visit::walk_item(self, i, ());
+ }
+}
+
pub fn check_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) {
- let visit = oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
- visit_item: |a| check_item(ccx, a),
- .. *oldvisit::default_simple_visitor()
- });
- oldvisit::visit_crate(crate, ((), visit));
+ let mut visit = CheckItemTypesVisitor { ccx: ccx };
+ visit::walk_crate(&mut visit, crate, ());
}
pub fn check_bare_fn(ccx: @mut CrateCtxt,
}
}
+struct GatherLocalsVisitor {
+ fcx: @mut FnCtxt,
+ tcx: ty::ctxt,
+}
+
+impl GatherLocalsVisitor {
+ fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
+ match ty_opt {
+ None => {
+ // infer the variable's type
+ let var_id = self.fcx.infcx().next_ty_var_id();
+ let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
+ self.fcx.inh.locals.insert(nid, var_ty);
+ }
+ Some(typ) => {
+ // take type that the user specified
+ self.fcx.inh.locals.insert(nid, typ);
+ }
+ }
+ }
+}
+
+impl Visitor<()> for GatherLocalsVisitor {
+ // Add explicitly-declared locals.
+ fn visit_local(&mut self, local:@ast::Local, _:()) {
+ let o_ty = match local.ty.node {
+ ast::ty_infer => None,
+ _ => Some(self.fcx.to_ty(&local.ty))
+ };
+ self.assign(local.id, o_ty);
+ debug!("Local variable %s is assigned type %s",
+ self.fcx.pat_to_str(local.pat),
+ self.fcx.infcx().ty_to_str(
+ self.fcx.inh.locals.get_copy(&local.id)));
+ visit::walk_local(self, local, ());
+
+ }
+ // Add pattern bindings.
+ fn visit_pat(&mut self, p:@ast::pat, _:()) {
+ match p.node {
+ ast::pat_ident(_, ref path, _)
+ if pat_util::pat_is_binding(self.fcx.ccx.tcx.def_map, p) => {
+ self.assign(p.id, None);
+ debug!("Pattern binding %s is assigned to %s",
+ self.tcx.sess.str_of(path.idents[0]),
+ self.fcx.infcx().ty_to_str(
+ self.fcx.inh.locals.get_copy(&p.id)));
+ }
+ _ => {}
+ }
+ visit::walk_pat(self, p, ());
+
+ }
+
+ fn visit_block(&mut self, b:&ast::Block, _:()) {
+ // non-obvious: the `blk` variable maps to region lb, so
+ // we have to keep this up-to-date. This
+ // is... unfortunate. It'd be nice to not need this.
+ do self.fcx.with_region_lb(b.id) {
+ visit::walk_block(self, b, ());
+ }
+ }
+
+ // Don't descend into fns and items
+ fn visit_fn(&mut self, _:&visit::fn_kind, _:&ast::fn_decl,
+ _:&ast::Block, _:span, _:ast::NodeId, _:()) { }
+ fn visit_item(&mut self, _:@ast::item, _:()) { }
+
+}
+
pub fn check_fn(ccx: @mut CrateCtxt,
opt_self_info: Option<SelfInfo>,
purity: ast::purity,
opt_self_info: Option<SelfInfo>) {
let tcx = fcx.ccx.tcx;
- let assign: @fn(ast::NodeId, Option<ty::t>) = |nid, ty_opt| {
- match ty_opt {
- None => {
- // infer the variable's type
- let var_id = fcx.infcx().next_ty_var_id();
- let var_ty = ty::mk_var(fcx.tcx(), var_id);
- fcx.inh.locals.insert(nid, var_ty);
- }
- Some(typ) => {
- // take type that the user specified
- fcx.inh.locals.insert(nid, typ);
- }
- }
- };
+ let mut visit = GatherLocalsVisitor { fcx: fcx, tcx: tcx, };
// Add the self parameter
for self_info in opt_self_info.iter() {
- assign(self_info.self_id, Some(self_info.self_ty));
+ visit.assign(self_info.self_id, Some(self_info.self_ty));
debug!("self is assigned to %s",
fcx.infcx().ty_to_str(
fcx.inh.locals.get_copy(&self_info.self_id)));
// Create type variables for each argument.
do pat_util::pat_bindings(tcx.def_map, input.pat)
|_bm, pat_id, _sp, _path| {
- assign(pat_id, None);
+ visit.assign(pat_id, None);
}
// Check the pattern.
_match::check_pat(&pcx, input.pat, *arg_ty);
}
- // Add explicitly-declared locals.
- let visit_local: @fn(@ast::Local, ((), oldvisit::vt<()>)) =
- |local, (e, v)| {
- let o_ty = match local.ty.node {
- ast::ty_infer => None,
- _ => Some(fcx.to_ty(&local.ty))
- };
- assign(local.id, o_ty);
- debug!("Local variable %s is assigned type %s",
- fcx.pat_to_str(local.pat),
- fcx.infcx().ty_to_str(
- fcx.inh.locals.get_copy(&local.id)));
- oldvisit::visit_local(local, (e, v));
- };
-
- // Add pattern bindings.
- let visit_pat: @fn(@ast::pat, ((), oldvisit::vt<()>)) = |p, (e, v)| {
- match p.node {
- ast::pat_ident(_, ref path, _)
- if pat_util::pat_is_binding(fcx.ccx.tcx.def_map, p) => {
- assign(p.id, None);
- debug!("Pattern binding %s is assigned to %s",
- tcx.sess.str_of(path.idents[0]),
- fcx.infcx().ty_to_str(
- fcx.inh.locals.get_copy(&p.id)));
- }
- _ => {}
- }
- oldvisit::visit_pat(p, (e, v));
- };
-
- let visit_block:
- @fn(&ast::Block, ((), oldvisit::vt<()>)) = |b, (e, v)| {
- // non-obvious: the `blk` variable maps to region lb, so
- // we have to keep this up-to-date. This
- // is... unfortunate. It'd be nice to not need this.
- do fcx.with_region_lb(b.id) {
- oldvisit::visit_block(b, (e, v));
- }
- };
-
- // Don't descend into fns and items
- fn visit_fn(_fk: &oldvisit::fn_kind,
- _decl: &ast::fn_decl,
- _body: &ast::Block,
- _sp: span,
- _id: ast::NodeId,
- (_t,_v): ((), oldvisit::vt<()>)) {
- }
- fn visit_item(_i: @ast::item, (_e,_v): ((), oldvisit::vt<()>)) { }
-
- let visit = oldvisit::mk_vt(
- @oldvisit::Visitor {visit_local: visit_local,
- visit_pat: visit_pat,
- visit_fn: visit_fn,
- visit_item: visit_item,
- visit_block: visit_block,
- ..*oldvisit::default_visitor()});
-
- (visit.visit_block)(body, ((), visit));
+ visit.visit_block(body, ());
}
}
if ty::type_is_error(e) || ty::type_is_error(a) {
return;
}
- match self.fn_kind {
- DoBlock if ty::type_is_bool(e) && ty::type_is_nil(a) =>
- // If we expected bool and got ()...
- self.tcx().sess.span_err(sp, fmt!("Do-block body must \
- return %s, but returns () here. Perhaps you meant \
- to write a `for`-loop?",
- ppaux::ty_to_str(self.tcx(), e))),
- _ => self.infcx().report_mismatched_types(sp, e, a, err)
- }
+ self.infcx().report_mismatched_types(sp, e, a, err)
}
pub fn report_mismatched_types(&self,
use syntax::ast::{def_arg, def_binding, def_local, def_self, def_upvar};
use syntax::ast;
use syntax::codemap::span;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
pub struct Rcx {
fcx: @mut FnCtxt,
repeating_scope: ast::NodeId,
}
-pub type rvt = oldvisit::vt<@mut Rcx>;
-
fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::def) -> ty::Region {
let tcx = fcx.tcx();
match def {
repeating_scope: e.id };
if fcx.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
- let v = regionck_visitor();
- (v.visit_expr)(e, (rcx, v));
+ let mut v = regionck_visitor();
+ v.visit_expr(e, rcx);
}
fcx.infcx().resolve_regions();
}
repeating_scope: blk.id };
if fcx.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
- let v = regionck_visitor();
- (v.visit_block)(blk, (rcx, v));
+ let mut v = regionck_visitor();
+ v.visit_block(blk, rcx);
}
fcx.infcx().resolve_regions();
}
-fn regionck_visitor() -> rvt {
+struct RegionckVisitor;
+
+impl Visitor<@mut Rcx> for RegionckVisitor {
// (*) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
// However, right now we run into an issue whereby some free
// regions are not properly related if they appear within the
// addressed by deferring the construction of the region
// hierarchy, and in particular the relationships between free
// regions, until regionck, as described in #3238.
- oldvisit::mk_vt(@oldvisit::Visitor {
- visit_item: visit_item,
- visit_expr: visit_expr,
+
+ fn visit_item(&mut self, i:@ast::item, e:@mut Rcx) { visit_item(self, i, e); }
+
+ fn visit_expr(&mut self, ex:@ast::expr, e:@mut Rcx) { visit_expr(self, ex, e); }
//visit_pat: visit_pat, // (*) see above
- visit_arm: visit_arm,
- visit_local: visit_local,
- visit_block: visit_block,
- .. *oldvisit::default_visitor()
- })
+ fn visit_arm(&mut self, a:&ast::arm, e:@mut Rcx) { visit_arm(self, a, e); }
+
+ fn visit_local(&mut self, l:@ast::Local, e:@mut Rcx) { visit_local(self, l, e); }
+
+ fn visit_block(&mut self, b:&ast::Block, e:@mut Rcx) { visit_block(self, b, e); }
+}
+
+fn regionck_visitor() -> RegionckVisitor {
+ RegionckVisitor
}
-fn visit_item(_item: @ast::item, (_rcx, _v): (@mut Rcx, rvt)) {
+fn visit_item(_v: &mut RegionckVisitor, _item: @ast::item, _rcx: @mut Rcx) {
// Ignore items
}
-fn visit_block(b: &ast::Block, (rcx, v): (@mut Rcx, rvt)) {
+fn visit_block(v: &mut RegionckVisitor, b: &ast::Block, rcx: @mut Rcx) {
rcx.fcx.tcx().region_maps.record_cleanup_scope(b.id);
- oldvisit::visit_block(b, (rcx, v));
+ visit::walk_block(v, b, rcx);
}
-fn visit_arm(arm: &ast::arm, (rcx, v): (@mut Rcx, rvt)) {
+fn visit_arm(v: &mut RegionckVisitor, arm: &ast::arm, rcx: @mut Rcx) {
// see above
for &p in arm.pats.iter() {
constrain_bindings_in_pat(p, rcx);
}
- oldvisit::visit_arm(arm, (rcx, v));
+ visit::walk_arm(v, arm, rcx);
}
-fn visit_local(l: @ast::Local, (rcx, v): (@mut Rcx, rvt)) {
+fn visit_local(v: &mut RegionckVisitor, l: @ast::Local, rcx: @mut Rcx) {
// see above
constrain_bindings_in_pat(l.pat, rcx);
- oldvisit::visit_local(l, (rcx, v));
+ visit::walk_local(v, l, rcx);
}
fn constrain_bindings_in_pat(pat: @ast::pat, rcx: @mut Rcx) {
}
}
-fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
+fn visit_expr(v: &mut RegionckVisitor, expr: @ast::expr, rcx: @mut Rcx) {
debug!("regionck::visit_expr(e=%s, repeating_scope=%?)",
expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
constrain_callee(rcx, callee.id, expr, callee);
constrain_call(rcx, callee.id, expr, None, *args, false);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
}
ast::expr_method_call(callee_id, arg0, _, _, ref args, _) => {
constrain_call(rcx, callee_id, expr, Some(arg0), *args, false);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v,expr, rcx);
}
ast::expr_index(callee_id, lhs, rhs) |
// should be converted to an adjustment!
constrain_call(rcx, callee_id, expr, Some(lhs), [rhs], true);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
}
ast::expr_unary(callee_id, _, lhs) if has_method_map => {
// As above.
constrain_call(rcx, callee_id, expr, Some(lhs), [], true);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
}
ast::expr_unary(_, ast::deref, base) => {
let base_ty = rcx.resolve_node_type(base.id);
constrain_derefs(rcx, expr, 1, base_ty);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
}
ast::expr_index(_, vec_expr, _) => {
let vec_type = rcx.resolve_expr_type_adjusted(vec_expr);
constrain_index(rcx, expr, vec_type);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
}
ast::expr_cast(source, _) => {
_ => ()
}
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
}
ast::expr_addr_of(_, base) => {
let ty0 = rcx.resolve_node_type(expr.id);
constrain_regions_in_type(rcx, ty::re_scope(expr.id),
infer::AddrOf(expr.span), ty0);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
}
ast::expr_match(discr, ref arms) => {
guarantor::for_match(rcx, discr, *arms);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
}
ast::expr_fn_block(*) => {
- check_expr_fn_block(rcx, expr, v, false);
+ check_expr_fn_block(rcx, expr, v);
}
ast::expr_loop(ref body, _) => {
let repeating_scope = rcx.set_repeating_scope(body.id);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
rcx.set_repeating_scope(repeating_scope);
}
ast::expr_while(cond, ref body) => {
let repeating_scope = rcx.set_repeating_scope(cond.id);
- (v.visit_expr)(cond, (rcx, v));
+ v.visit_expr(cond, rcx);
rcx.set_repeating_scope(body.id);
- (v.visit_block)(body, (rcx, v));
+ v.visit_block(body, rcx);
rcx.set_repeating_scope(repeating_scope);
}
_ => {
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
}
}
}
fn check_expr_fn_block(rcx: @mut Rcx,
expr: @ast::expr,
- v: rvt,
- is_loop_body: bool) {
+ v: &mut RegionckVisitor) {
let tcx = rcx.fcx.tcx();
match expr.node {
ast::expr_fn_block(_, ref body) => {
ty::ty_closure(
ty::ClosureTy {
sigil: ast::BorrowedSigil, region: region, _}) => {
- if get_freevars(tcx, expr.id).is_empty() && !is_loop_body {
+ if get_freevars(tcx, expr.id).is_empty() {
// No free variables means that the environment
// will be NULL at runtime and hence the closure
// has static lifetime.
}
let repeating_scope = rcx.set_repeating_scope(body.id);
- oldvisit::visit_expr(expr, (rcx, v));
+ visit::walk_expr(v, expr, rcx);
rcx.set_repeating_scope(repeating_scope);
}
self_ty: Some(mt.ty)
}
};
- let vtable_opt =
- lookup_vtable(&vcx,
- location_info,
- mt.ty,
- target_trait_ref,
- is_early);
- match vtable_opt {
- Some(vtable) => {
- // Map this expression to that
- // vtable (that is: "ex has vtable
- // <vtable>")
- if !is_early {
- insert_vtables(fcx, ex.id,
- @~[@~[vtable]]);
- }
- }
- None => {
- fcx.tcx().sess.span_err(
- ex.span,
- fmt!("failed to find an implementation \
- of trait %s for %s",
- fcx.infcx().ty_to_str(target_ty),
- fcx.infcx().ty_to_str(mt.ty)));
- }
+
+ let param_bounds = ty::ParamBounds {
+ builtin_bounds: ty::EmptyBuiltinBounds(),
+ trait_bounds: ~[target_trait_ref]
+ };
+ let vtables =
+ lookup_vtables_for_param(&vcx,
+ location_info,
+ None,
+ ¶m_bounds,
+ mt.ty,
+ is_early);
+
+ if !is_early {
+ insert_vtables(fcx, ex.id, @~[vtables]);
}
// Now, if this is &trait, we need to link the
use syntax::ast_util::{def_id_of_def, local_def};
use syntax::codemap::{span, dummy_sp};
use syntax::opt_vec;
-use syntax::oldvisit::{default_simple_visitor, default_visitor};
-use syntax::oldvisit::{mk_simple_visitor, mk_vt, visit_crate, visit_item};
-use syntax::oldvisit::{Visitor, SimpleVisitor};
-use syntax::oldvisit::{visit_mod};
+use syntax::visit;
use syntax::parse;
use util::ppaux::ty_to_str;
base_type_def_ids: @mut HashMap<def_id,def_id>,
}
-impl CoherenceChecker {
- pub fn check_coherence(self, crate: &Crate) {
- // Check implementations and traits. This populates the tables
- // containing the inherent methods and extension methods. It also
- // builds up the trait inheritance table.
- visit_crate(crate, ((), mk_simple_visitor(@SimpleVisitor {
- visit_item: |item| {
+struct CoherenceCheckVisitor { cc: CoherenceChecker }
+
+impl visit::Visitor<()> for CoherenceCheckVisitor {
+ fn visit_item(&mut self, item:@item, _:()) {
+
// debug!("(checking coherence) item '%s'",
-// self.crate_context.tcx.sess.str_of(item.ident));
+// self.cc.crate_context.tcx.sess.str_of(item.ident));
match item.node {
item_impl(_, ref opt_trait, _, _) => {
opt_trait.iter()
.map(|x| (*x).clone())
.collect();
- self.check_implementation(item, opt_trait);
+ self.cc.check_implementation(item, opt_trait);
}
_ => {
// Nothing to do.
}
};
- },
- .. *default_simple_visitor()
- })));
+
+ visit::walk_item(self, item, ());
+ }
+}
+
+struct PrivilegedScopeVisitor { cc: CoherenceChecker }
+
+impl visit::Visitor<()> for PrivilegedScopeVisitor {
+ fn visit_item(&mut self, item:@item, _:()) {
+
+ match item.node {
+ item_mod(ref module_) => {
+ // Then visit the module items.
+ visit::walk_mod(self, module_, ());
+ }
+ item_impl(_, None, ref ast_ty, _) => {
+ if !self.cc.ast_type_is_defined_in_local_crate(ast_ty) {
+ // This is an error.
+ let session = self.cc.crate_context.tcx.sess;
+ session.span_err(item.span,
+ "cannot associate methods with a type outside the \
+ crate the type is defined in; define and implement \
+ a trait or new type instead");
+ }
+ }
+ item_impl(_, Some(ref trait_ref), _, _) => {
+ // `for_ty` is `Type` in `impl Trait for Type`
+ let for_ty =
+ ty::node_id_to_type(self.cc.crate_context.tcx,
+ item.id);
+ if !type_is_defined_in_local_crate(for_ty) {
+ // This implementation is not in scope of its base
+ // type. This still might be OK if the trait is
+ // defined in the same crate.
+
+ let trait_def_id =
+ self.cc.trait_ref_to_trait_def_id(trait_ref);
+
+ if trait_def_id.crate != LOCAL_CRATE {
+ let session = self.cc.crate_context.tcx.sess;
+ session.span_err(item.span,
+ "cannot provide an extension implementation \
+ for a trait not defined in this crate");
+ }
+ }
+
+ visit::walk_item(self, item, ());
+ }
+ _ => {
+ visit::walk_item(self, item, ());
+ }
+ }
+ }
+}
+
+impl CoherenceChecker {
+ pub fn check_coherence(self, crate: &Crate) {
+ // Check implementations and traits. This populates the tables
+ // containing the inherent methods and extension methods. It also
+ // builds up the trait inheritance table.
+
+ let mut visitor = CoherenceCheckVisitor { cc: self };
+ visit::walk_crate(&mut visitor, crate, ());
// Check that there are no overlapping trait instances
self.check_implementation_coherence();
// Privileged scope checking
pub fn check_privileged_scopes(self, crate: &Crate) {
- visit_crate(crate, ((), mk_vt(@Visitor {
- visit_item: |item, (_context, visitor)| {
- match item.node {
- item_mod(ref module_) => {
- // Then visit the module items.
- visit_mod(module_, item.span, item.id, ((), visitor));
- }
- item_impl(_, None, ref ast_ty, _) => {
- if !self.ast_type_is_defined_in_local_crate(ast_ty) {
- // This is an error.
- let session = self.crate_context.tcx.sess;
- session.span_err(item.span,
- "cannot associate methods with a type outside the \
- crate the type is defined in; define and implement \
- a trait or new type instead");
- }
- }
- item_impl(_, Some(ref trait_ref), _, _) => {
- // `for_ty` is `Type` in `impl Trait for Type`
- let for_ty =
- ty::node_id_to_type(self.crate_context.tcx,
- item.id);
- if !type_is_defined_in_local_crate(for_ty) {
- // This implementation is not in scope of its base
- // type. This still might be OK if the trait is
- // defined in the same crate.
-
- let trait_def_id =
- self.trait_ref_to_trait_def_id(trait_ref);
-
- if trait_def_id.crate != LOCAL_CRATE {
- let session = self.crate_context.tcx.sess;
- session.span_err(item.span,
- "cannot provide an extension implementation \
- for a trait not defined in this crate");
- }
- }
-
- visit_item(item, ((), visitor));
- }
- _ => {
- visit_item(item, ((), visitor));
- }
- }
- },
- .. *default_visitor()
- })));
+ let mut visitor = PrivilegedScopeVisitor{ cc: self };
+ visit::walk_crate(&mut visitor, crate, ());
}
pub fn trait_ref_to_trait_def_id(&self, trait_ref: &trait_ref) -> def_id {
use syntax::codemap::span;
use syntax::codemap;
use syntax::print::pprust::{path_to_str, explicit_self_to_str};
-use syntax::oldvisit;
+use syntax::visit;
use syntax::opt_vec::OptVec;
use syntax::opt_vec;
use syntax::parse::token::special_idents;
+struct CollectItemTypesVisitor {
+ ccx: @mut CrateCtxt
+}
+
+impl visit::Visitor<()> for CollectItemTypesVisitor {
+ fn visit_item(&mut self, i:@ast::item, _:()) {
+ convert(self.ccx, i);
+ visit::walk_item(self, i, ());
+ }
+ fn visit_foreign_item(&mut self, i:@ast::foreign_item, _:()) {
+ convert_foreign(self.ccx, i);
+ visit::walk_foreign_item(self, i, ());
+ }
+}
+
pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) {
fn collect_intrinsic_type(ccx: &CrateCtxt,
lang_item: ast::def_id) {
Some(id) => { collect_intrinsic_type(ccx, id); } None => {}
}
- oldvisit::visit_crate(
- crate, ((),
- oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
- visit_item: |a| convert(ccx, a),
- visit_foreign_item: |a|convert_foreign(ccx, a),
- .. *oldvisit::default_simple_visitor()
- })));
+ let mut visitor = CollectItemTypesVisitor{ ccx: ccx };
+ visit::walk_crate(&mut visitor, crate, ());
}
pub trait ToTy {
use middle::typeck::infer::{TypeTrace};
use util::common::indent;
-use std::result::{iter_vec2, map_vec2};
+use std::result;
use std::vec;
use syntax::ast::{Onceness, purity};
use syntax::ast;
// variance.
if vec::same_length(as_, bs) {
- iter_vec2(as_, bs, |a, b| {
- eq_tys(this, *a, *b)
- }).then(|| Ok(as_.to_owned()) )
+ result::fold_(as_.iter().zip(bs.iter())
+ .map(|(a, b)| eq_tys(this, *a, *b)))
+ .then(|| Ok(as_.to_owned()))
} else {
Err(ty::terr_ty_param_size(
expected_found(this, as_.len(), bs.len())))
{
fn argvecs<C:Combine>(this: &C, a_args: &[ty::t], b_args: &[ty::t]) -> cres<~[ty::t]> {
if vec::same_length(a_args, b_args) {
- map_vec2(a_args, b_args, |a, b| this.args(*a, *b))
+ result::collect(a_args.iter().zip(b_args.iter())
+ .map(|(a, b)| this.args(*a, *b)))
} else {
Err(ty::terr_arg_count)
}
(&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => {
if as_.len() == bs.len() {
- map_vec2(*as_, *bs, |a, b| this.tys(*a, *b) )
- .chain(|ts| Ok(ty::mk_tup(tcx, ts)) )
+ result::collect(as_.iter().zip(bs.iter())
+ .map(|(a, b)| this.tys(*a, *b)))
+ .chain(|ts| Ok(ty::mk_tup(tcx, ts)) )
} else {
Err(ty::terr_tuple_size(
expected_found(this, as_.len(), bs.len())))
}
}
+ // [Note-Type-error-reporting]
+ // An invariant is that anytime the expected or actual type is ty_err (the special
+ // error type, meaning that an error occurred when typechecking this expression),
+ // this is a derived error. The error cascaded from another error (that was already
+ // reported), so it's not useful to display it to the user.
+ // The following four methods -- type_error_message_str, type_error_message_str_with_expected,
+ // type_error_message, and report_mismatched_types -- implement this logic.
+ // They check if either the actual or expected type is ty_err, and don't print the error
+ // in this case. The typechecker should only ever report type errors involving mismatched
+ // types using one of these four methods, and should not call span_err directly for such
+ // errors.
pub fn type_error_message_str(@mut self,
sp: span,
mk_msg: &fn(Option<~str>, ~str) -> ~str,
use middle::typeck::infer::unify::{Redirect, Root, VarValue};
use util::ppaux::{mt_to_str, ty_to_str, trait_ref_to_str};
-use std::uint;
use syntax::ast;
pub trait InferStr {
match *self {
Redirect(ref vid) => fmt!("Redirect(%s)", vid.to_str()),
Root(ref pt, rk) => fmt!("Root(%s, %s)", pt.inf_str(cx),
- uint::to_str_radix(rk, 10u))
+ rk.to_str_radix(10u))
}
}
}
method_param(method_param),
// method invoked on a trait instance
- method_trait(ast::def_id, uint),
+ method_object(method_object),
}
bound_num: uint,
}
+// details for a method invoked with a receiver whose type is an object
+#[deriving(Clone, Encodable, Decodable)]
+pub struct method_object {
+ // the (super)trait containing the method to be invoked
+ trait_id: ast::def_id,
+
+ // the actual base trait id of the object
+ object_trait_id: ast::def_id,
+
+ // index of the method to be invoked amongst the trait's methods
+ method_num: uint,
+
+ // index into the actual runtime vtable.
+ // the vtable is formed by concatenating together the method lists of
+ // the base object trait and all supertraits; this is the index into
+ // that vtable
+ real_index: uint,
+}
+
+
#[deriving(Clone)]
pub struct method_map_entry {
// the type of the self parameter, which is not reflected in the fn type
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
+// Rustc tasks always run on a fixed_stack_segment, so code in this
+// module can call C functions (in particular, LLVM functions) with
+// impunity.
+#[allow(cstack)];
+
extern mod extra;
extern mod syntax;
pub mod reachable;
pub mod graph;
pub mod cfg;
+ pub mod stack_check;
}
pub mod front {
let sess = build_session(sopts, demitter);
let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
- let cfg = build_configuration(sess, binary, &input);
+ let cfg = build_configuration(sess);
let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
parse_pretty(sess, a)
};
let xs = [
~"the compiler hit an unexpected failure path. \
this is a bug",
- ~"try running with RUST_LOG=rustc=1,::rt::backtrace \
+ ~"try running with RUST_LOG=rustc=1 \
to get further details and report the results \
to github.com/mozilla/rust/issues"
];
use syntax::ast;
use syntax::codemap::{span};
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
use std::hashmap::HashSet;
use extra;
fields.map(|f| f.expr)
}
-// Takes a predicate p, returns true iff p is true for any subexpressions
-// of b -- skipping any inner loops (loop, while, loop_body)
-pub fn loop_query(b: &ast::Block, p: @fn(&ast::expr_) -> bool) -> bool {
- let rs = @mut false;
- let visit_expr: @fn(@ast::expr,
- (@mut bool,
- oldvisit::vt<@mut bool>)) = |e, (flag, v)| {
- *flag |= p(&e.node);
+struct LoopQueryVisitor {
+ p: @fn(&ast::expr_) -> bool
+}
+
+impl Visitor<@mut bool> for LoopQueryVisitor {
+ fn visit_expr(&mut self, e:@ast::expr, flag:@mut bool) {
+ *flag |= (self.p)(&e.node);
match e.node {
// Skip inner loops, since a break in the inner loop isn't a
// break inside the outer loop
ast::expr_loop(*) | ast::expr_while(*) => {}
- _ => oldvisit::visit_expr(e, (flag, v))
+ _ => visit::walk_expr(self, e, flag)
}
- };
- let v = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: visit_expr,
- .. *oldvisit::default_visitor()});
- oldvisit::visit_block(b, (rs, v));
+ }
+}
+
+// Takes a predicate p, returns true iff p is true for any subexpressions
+// of b -- skipping any inner loops (loop, while, loop_body)
+pub fn loop_query(b: &ast::Block, p: @fn(&ast::expr_) -> bool) -> bool {
+ let rs = @mut false;
+ let mut v = LoopQueryVisitor { p: p };
+ visit::walk_block(&mut v, b, rs);
return *rs;
}
+struct BlockQueryVisitor {
+ p: @fn(@ast::expr) -> bool
+}
+
+impl Visitor<@mut bool> for BlockQueryVisitor {
+ fn visit_expr(&mut self, e:@ast::expr, flag:@mut bool) {
+ *flag |= (self.p)(e);
+ visit::walk_expr(self, e, flag)
+ }
+}
+
// Takes a predicate p, returns true iff p is true for any subexpressions
// of b -- skipping any inner loops (loop, while, loop_body)
pub fn block_query(b: &ast::Block, p: @fn(@ast::expr) -> bool) -> bool {
let rs = @mut false;
- let visit_expr: @fn(@ast::expr,
- (@mut bool,
- oldvisit::vt<@mut bool>)) = |e, (flag, v)| {
- *flag |= p(e);
- oldvisit::visit_expr(e, (flag, v))
- };
- let v = oldvisit::mk_vt(@oldvisit::Visitor{
- visit_expr: visit_expr,
- .. *oldvisit::default_visitor()});
- oldvisit::visit_block(b, (rs, v));
+ let mut v = BlockQueryVisitor { p: p };
+ visit::walk_block(&mut v, b, rs);
return *rs;
}
&typeck::method_param(ref p) => {
p.repr(tcx)
}
- &typeck::method_trait(def_id, n) => {
- fmt!("method_trait(%s, %?)", def_id.repr(tcx), n)
+ &typeck::method_object(ref p) => {
+ p.repr(tcx)
}
}
}
}
}
+impl Repr for typeck::method_object {
+ fn repr(&self, tcx: ctxt) -> ~str {
+ fmt!("method_object(%s,%?,%?)",
+ self.trait_id.repr(tcx),
+ self.method_num,
+ self.real_index)
+ }
+}
+
+
impl Repr for ty::RegionVid {
fn repr(&self, _tcx: ctxt) -> ~str {
fmt!("%?", *self)
ty_to_str(tcx, *self)
}
}
+
+impl Repr for AbiSet {
+ fn repr(&self, _tcx: ctxt) -> ~str {
+ self.to_str()
+ }
+}
+
+impl UserString for AbiSet {
+ fn user_string(&self, _tcx: ctxt) -> ~str {
+ self.to_str()
+ }
+}
//! AST-parsing helpers
-
-use rustc::driver::driver::{file_input, str_input};
use rustc::driver::driver;
use rustc::driver::session;
use syntax::ast;
pub fn from_file_sess(sess: session::Session, file: &Path) -> @ast::Crate {
parse::parse_crate_from_file(
- file, cfg(sess, file_input((*file).clone())), sess.parse_sess)
+ file, cfg(sess), sess.parse_sess)
}
pub fn from_str_sess(sess: session::Session, source: @str) -> @ast::Crate {
parse::parse_crate_from_source_str(
- @"-", source, cfg(sess, str_input(source)), sess.parse_sess)
+ @"-", source, cfg(sess), sess.parse_sess)
}
-fn cfg(sess: session::Session, input: driver::input) -> ast::CrateConfig {
- driver::build_configuration(sess, @"rustdoc", &input)
+fn cfg(sess: session::Session) -> ast::CrateConfig {
+ driver::build_configuration(sess)
}
+
// Stage 1: parse the input and filter it into the program (as necessary)
//
debug!("parsing: %s", input);
- let crate = parse_input(sess, binary, input);
+ let crate = parse_input(sess, binary);
let mut to_run = ~[]; // statements to run (emitted back into code)
let new_locals = @mut ~[]; // new locals being defined
let mut result = None; // resultant expression (to print via pp)
let test = program.test_code(input, &result, *new_locals);
debug!("testing with ^^^^^^ %?", (||{ println(test) })());
let dinput = driver::str_input(test.to_managed());
- let cfg = driver::build_configuration(sess, binary, &dinput);
+ let cfg = driver::build_configuration(sess);
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &dinput);
let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
let code = program.code(input, &result);
debug!("actually running ^^^^^^ %?", (||{ println(code) })());
let input = driver::str_input(code.to_managed());
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
let outputs = driver::build_output_filenames(&input, &None, &None, [], sess);
let sess = driver::build_session(options, diagnostic::emit);
//
return (program, jit::consume_engine());
- fn parse_input(sess: session::Session, binary: @str,
- input: &str) -> @ast::Crate {
+ fn parse_input(sess: session::Session, input: &str) -> @ast::Crate {
let code = fmt!("fn main() {\n %s \n}", input);
let input = driver::str_input(code.to_managed());
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
driver::phase_1_parse_input(sess, cfg.clone(), &input)
}
let input = driver::file_input(src_path.clone());
let sess = driver::build_session(options, diagnostic::emit);
*sess.building_library = true;
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
let outputs = driver::build_output_filenames(
&input, &None, &None, [], sess);
// If the library already exists and is newer than the source
}
pub fn main() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let args = os::args();
let input = io::stdin();
let out = io::stdout();
use syntax::print::pp;
use syntax::print::pprust;
use syntax::parse::token;
+use syntax::visit;
-pub fn each_binding(l: @ast::Local, f: @fn(&ast::Path, ast::NodeId)) {
- use syntax::oldvisit;
+struct EachBindingVisitor {
+ f: @fn(&ast::Path, ast::NodeId)
+}
- let vt = oldvisit::mk_simple_visitor(
- @oldvisit::SimpleVisitor {
- visit_pat: |pat| {
+impl visit::Visitor<()> for EachBindingVisitor {
+ fn visit_pat(&mut self, pat:@ast::pat, _:()) {
match pat.node {
ast::pat_ident(_, ref path, _) => {
- f(path, pat.id);
+ (self.f)(path, pat.id);
}
_ => {}
}
- },
- .. *oldvisit::default_simple_visitor()
- }
- );
- (vt.visit_pat)(l.pat, ((), vt));
+
+ visit::walk_pat(self, pat, ());
+ }
+}
+
+pub fn each_binding(l: @ast::Local, f: @fn(&ast::Path, ast::NodeId)) {
+ use syntax::visit::Visitor;
+
+ let mut vt = EachBindingVisitor{ f: f };
+
+ vt.visit_pat(l.pat, ());
}
/// A utility function that hands off a pretty printer to a callback.
Some(p) => p.to_str()
}
}
+
+ // Hack so that rustpkg can run either out of a rustc target dir,
+ // or the host dir
+ pub fn sysroot_to_use(&self) -> Option<@Path> {
+ if !in_target(self.sysroot_opt) {
+ self.sysroot_opt
+ }
+ else {
+ self.sysroot_opt.map(|p| { @p.pop().pop().pop() })
+ }
+ }
}
/// We assume that if ../../rustc exists, then we're running
debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str());
let dirs = pkgid_src_in_workspace(&self.id, &self.root);
- debug!("Checking dirs: %?", dirs);
+ debug!("Checking dirs: %?", dirs.map(|s| s.to_str()).connect(":"));
let path = dirs.iter().find(|&d| os::path_exists(d));
let dir = match path {
pub use package_id::PkgId;
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
-pub use version::{Version, NoVersion, split_version_general};
+pub use version::{Version, NoVersion, split_version_general, try_parsing_version};
pub use rustc::metadata::filesearch::rust_path;
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
/// Figure out what the library name for <pkgid> in <workspace>'s build
/// directory is, and if the file exists, return it.
pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
- library_in_workspace(&pkgid.path, pkgid.short_name, Build, workspace, "build")
+ library_in_workspace(&pkgid.path, pkgid.short_name, Build, workspace, "build", &pkgid.version)
}
/// Does the actual searching stuff
pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option<Path> {
- library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib")
+ // NOTE: this could break once we're handling multiple versions better... want a test for it
+ library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib", &NoVersion)
}
-
-/// This doesn't take a PkgId, so we can use it for `extern mod` inference, where we
-/// don't know the entire package ID.
/// `workspace` is used to figure out the directory to search.
/// `short_name` is taken as the link name of the library.
pub fn library_in_workspace(path: &Path, short_name: &str, where: Target,
- workspace: &Path, prefix: &str) -> Option<Path> {
+ workspace: &Path, prefix: &str, version: &Version) -> Option<Path> {
debug!("library_in_workspace: checking whether a library named %s exists",
short_name);
for p_path in libraries {
// Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix)
// and remember what the hash was
- let f_name = match p_path.filename() {
+ let mut f_name = match p_path.filestem() {
Some(s) => s, None => loop
};
-
- let mut hash = None;
- let mut which = 0;
- for piece in f_name.split_iter('-') {
- debug!("a piece = %s", piece);
- if which == 0 && piece != lib_prefix {
- break;
- }
- else if which == 0 {
- which += 1;
- }
- else if which == 1 {
- hash = Some(piece.to_owned());
- break;
- }
- else {
- // something went wrong
- hash = None;
- break;
- }
- }
-
- if hash.is_some() {
- result_filename = Some(p_path);
- break;
- }
- }
+ // Already checked the filetype above
+
+ // This is complicated because library names and versions can both contain dashes
+ loop {
+ if f_name.is_empty() { break; }
+ match f_name.rfind('-') {
+ Some(i) => {
+ debug!("Maybe %s is a version", f_name.slice(i + 1, f_name.len()));
+ match try_parsing_version(f_name.slice(i + 1, f_name.len())) {
+ Some(ref found_vers) if version == found_vers => {
+ match f_name.slice(0, i).rfind('-') {
+ Some(j) => {
+ debug!("Maybe %s equals %s", f_name.slice(0, j), lib_prefix);
+ if f_name.slice(0, j) == lib_prefix {
+ result_filename = Some(p_path);
+ }
+ break;
+ }
+ None => break
+ }
+ }
+ _ => { f_name = f_name.slice(0, i).to_owned(); }
+ }
+ }
+ None => break
+ } // match
+ } // loop
+ } // for
if result_filename.is_none() {
warn(fmt!("library_in_workspace didn't find a library in %s for %s",
/// Given the path name for a package script
/// and a package ID, parse the package script into
/// a PkgScript that we can then execute
- fn parse<'a>(script: Path, workspace: &Path, id: &'a PkgId) -> PkgScript<'a> {
+ fn parse<'a>(sysroot: @Path,
+ script: Path,
+ workspace: &Path,
+ id: &'a PkgId) -> PkgScript<'a> {
// Get the executable name that was invoked
let binary = os::args()[0].to_managed();
// Build the rustc session data structures to pass
// to the compiler
- debug!("pkgscript parse: %?", os::self_exe_path());
+ debug!("pkgscript parse: %s", sysroot.to_str());
let options = @session::options {
binary: binary,
- maybe_sysroot: Some(@os::self_exe_path().unwrap().pop()),
+ maybe_sysroot: Some(sysroot),
crate_type: session::bin_crate,
.. (*session::basic_options()).clone()
};
let input = driver::file_input(script);
let sess = driver::build_session(options, diagnostic::emit);
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
let crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
let work_dir = build_pkg_id_in_workspace(id, workspace);
- debug!("Returning package script with id %?", id);
+ debug!("Returning package script with id %s", id.to_str());
PkgScript {
id: id,
let crate = util::ready_crate(sess, self.crate);
debug!("Building output filenames with script name %s",
driver::source_name(&self.input));
- let root = filesearch::get_or_default_sysroot().pop().pop(); // :-\
- debug!("Root is %s, calling compile_rest", root.to_str());
let exe = self.build_dir.push(~"pkg" + util::exe_suffix());
util::compile_crate_from_input(&self.input,
&self.build_dir,
sess,
crate);
- debug!("Running program: %s %s %s %s", exe.to_str(),
- sysroot.to_str(), root.to_str(), "install");
+ debug!("Running program: %s %s %s", exe.to_str(),
+ sysroot.to_str(), "install");
// FIXME #7401 should support commands besides `install`
let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]);
if status != 0 {
}
else {
debug!("Running program (configs): %s %s %s",
- exe.to_str(), root.to_str(), "configs");
- let output = run::process_output(exe.to_str(), [root.to_str(), ~"configs"]);
+ exe.to_str(), sysroot.to_str(), "configs");
+ let output = run::process_output(exe.to_str(), [sysroot.to_str(), ~"configs"]);
// Run the configs() function to get the configs
let cfgs = str::from_bytes_slice(output.output).word_iter()
.map(|w| w.to_owned()).collect();
debug!("Package source directory = %?", pkg_src_dir);
let cfgs = match pkg_src_dir.chain_ref(|p| src.package_script_option(p)) {
Some(package_script_path) => {
- let pscript = PkgScript::parse(package_script_path,
+ let sysroot = self.sysroot_to_use().expect("custom build needs a sysroot");
+ let pscript = PkgScript::parse(sysroot,
+ package_script_path,
workspace,
pkgid);
- let sysroot = self.sysroot_opt.expect("custom build needs a sysroot");
let (cfgs, hook_result) = pscript.run_custom(sysroot);
debug!("Command return code = %?", hook_result);
if hook_result != 0 {
fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) {
let cwd = (*cwd).clone();
let mut prog = run::Process::new("git", args, run::ProcessOptions {
- env: env.map(|v| v.slice(0, v.len())),
+ env: env,
dir: Some(&cwd),
in_fd: None,
out_fd: None,
assert!(os::path_is_dir(&*cwd));
let cwd = (*cwd).clone();
let mut prog = run::Process::new(cmd, args, run::ProcessOptions {
- env: env.map(|v| v.slice(0, v.len())),
+ env: env.map(|e| e + os::env()),
dir: Some(&cwd),
in_fd: None,
out_fd: None,
short_name,
Build,
workspace,
- "build").expect("lib_output_file_name")
+ "build",
+ &NoVersion).expect("lib_output_file_name")
}
fn output_file_name(workspace: &Path, short_name: &str) -> Path {
}
}
-// FIXME(#7249): these tests fail on multi-platform builds, so for now they're
-// only run one x86
-
-#[test] #[ignore(cfg(target_arch = "x86"))]
+#[test]
fn test_make_dir_rwx() {
let temp = &os::tmpdir();
let dir = temp.push("quux");
assert!(os::remove_dir_recursive(&dir));
}
-#[test] #[ignore(cfg(target_arch = "x86"))]
+#[test]
fn test_install_valid() {
use path_util::installed_library_in_workspace;
assert!(!os::path_exists(&bench));
}
-#[test] #[ignore(cfg(target_arch = "x86"))]
+#[test]
fn test_install_invalid() {
use conditions::nonexistent_package::cond;
use cond1 = conditions::missing_pkg_files::cond;
// Tests above should (maybe) be converted to shell out to rustpkg, too
-// FIXME: #7956: temporarily disabled
-#[ignore(cfg(target_arch = "x86"))]
fn test_install_git() {
let sysroot = test_sysroot();
debug!("sysroot = %s", sysroot.to_str());
assert!(!os::path_exists(&bench));
}
-#[test] #[ignore(cfg(target_arch = "x86"))]
+#[test]
fn test_package_ids_must_be_relative_path_like() {
use conditions::bad_pkg_id::cond;
}
-// FIXME: #7956: temporarily disabled
-#[ignore(cfg(target_arch = "x86"))]
fn test_package_version() {
let local_path = "mockgithub.com/catamorphism/test_pkg_version";
let repo = init_git_repo(&Path(local_path));
&temp_dir);
}
-// FIXME: #7956: temporarily disabled
#[test]
fn rustpkg_library_target() {
let foo_repo = init_git_repo(&Path("foo"));
assert_executable_exists(&dir, "foo");
}
-// FIXME: #7956: temporarily disabled
-// Failing on dist-linux bot
#[test]
-#[ignore]
fn package_script_with_default_build() {
let dir = create_local_package(&PkgId::new("fancy-lib"));
debug!("dir = %s", dir.to_str());
push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs");
debug!("package_script_with_default_build: %s", source.to_str());
if !os::copy_file(&source,
- & dir.push("src").push("fancy_lib-0.1").push("pkg.rs")) {
+ & dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
fail!("Couldn't copy file");
}
command_line_test([~"install", ~"fancy-lib"], &dir);
assert_lib_exists(&dir, "fancy-lib", NoVersion);
- assert!(os::path_exists(&dir.push("build").push("fancy_lib").push("generated.rs")));
+ assert!(os::path_exists(&dir.push("build").push("fancy-lib").push("generated.rs")));
}
#[test]
#[test]
fn rustpkg_install_no_arg() {
let tmp = mkdtemp(&os::tmpdir(),
- "rustpkg_install_no_arg").expect("rustpkg_build_no_arg failed");
+ "rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed");
let package_dir = tmp.push("src").push("foo");
assert!(os::mkdir_recursive(&package_dir, U_RWX));
writeFile(&package_dir.push("lib.rs"),
}
#[test]
-#[ignore (reason = "Specifying env doesn't work -- see #8028")]
fn rust_path_test() {
let dir_for_path = mkdtemp(&os::tmpdir(), "more_rust").expect("rust_path_test failed");
let dir = mk_workspace(&dir_for_path, &Path("foo"), &NoVersion);
let cwd = os::getcwd();
debug!("cwd = %s", cwd.to_str());
// use command_line_test_with_env
- let mut prog = run::Process::new("rustpkg",
- [~"install", ~"foo"],
- run::ProcessOptions { env: Some(&[(~"RUST_LOG",
- ~"rustpkg"),
- (~"RUST_PATH",
- dir_for_path.to_str())]),
- dir: Some(&cwd),
- in_fd: None,
- out_fd: None,
- err_fd: None
- });
- prog.finish_with_output();
+ command_line_test_with_env([~"install", ~"foo"],
+ &cwd,
+ Some(~[(~"RUST_PATH", dir_for_path.to_str())]));
assert_executable_exists(&dir_for_path, "foo");
}
~"--sysroot", test_sysroot().to_str(),
~"-o", exec_file.to_str()],
run::ProcessOptions {
- env: env.map(|v| v.slice(0, v.len())),
+ env: env,
dir: Some(&dir),
in_fd: None,
out_fd: None,
return;
}
- let out_path = Path("build/fancy_lib");
+ let out_path = Path("build/fancy-lib");
if !os::path_exists(&out_path) {
assert!(os::make_dir(&out_path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
}
// Infer dependencies that rustpkg needs to build, by scanning for
// `extern mod` directives.
- let cfg = driver::build_configuration(sess, binary, &input);
+ let cfg = driver::build_configuration(sess);
let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
#[cfg(windows)]
pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
/* FIXME (#1768): Investigate how to do this on win32
Node wraps symlinks by having a .bat,
but that won't work with minGW. */
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
pub fn link_exe(src: &Path, dest: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
use std::c_str::ToCStr;
use std::libc;
unsafe {
- do src.to_c_str().with_ref |src_buf| {
- do dest.to_c_str().with_ref |dest_buf| {
+ do src.with_c_str |src_buf| {
+ do dest.with_c_str |dest_buf| {
libc::link(src_buf, dest_buf) == 0 as libc::c_int &&
libc::chmod(dest_buf, 755) == 0 as libc::c_int
}
NoVersion // user didn't specify a version -- prints as 0.1
}
+// Equality on versions is non-symmetric: if self is NoVersion, it's equal to
+// anything; but if self is a precise version, it's not equal to NoVersion.
+// We should probably make equality symmetric, and use less-than and greater-than
+// where we currently use eq
impl Eq for Version {
fn eq(&self, other: &Version) -> bool {
match (self, other) {
SawDot
}
-fn try_parsing_version(s: &str) -> Option<Version> {
+pub fn try_parsing_version(s: &str) -> Option<Version> {
let s = s.trim();
debug!("Attempting to parse: %s", s);
let mut parse_state = Start;
/// number, return the prefix before the # and the version.
/// Otherwise, return None.
pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
- split_version_general(s, '#')
+ // Check for extra '#' characters separately
+ if s.split_iter('#').len() > 2 {
+ None
+ }
+ else {
+ split_version_general(s, '#')
+ }
}
pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Version)> {
- // reject strings with multiple '#'s
- for st in s.split_iter(sep) {
- debug!("whole = %s part = %s", s, st);
- }
- if s.split_iter(sep).len() > 2 {
- return None;
- }
match s.rfind(sep) {
Some(i) => {
debug!("in %s, i = %?", s, i);
* 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
+ * modifying its buffers, so it is up to the caller to ensure that
* the vector is actually the specified size.
*/
#[inline]
mod test {
use super::*;
use prelude::*;
+ use bh = extra::test::BenchHarness;
#[test]
fn test() {
assert_eq!(to_managed([@"abc", @"123"]), @[@"abc", @"123"]);
assert_eq!(to_managed([@[42]]), @[@[42]]);
}
+
+ #[bench]
+ fn bench_capacity(b: &mut bh) {
+ let x = @[1, 2, 3];
+ do b.iter {
+ capacity(x);
+ }
+ }
+
+ #[bench]
+ fn bench_build_sized(b: &mut bh) {
+ let len = 64;
+ do b.iter {
+ build_sized(len, |push| for i in range(0, 1024) { push(i) });
+ }
+ }
+
+ #[bench]
+ fn bench_build(b: &mut bh) {
+ do b.iter {
+ for i in range(0, 95) {
+ build(|push| push(i));
+ }
+ }
+ }
+
+ #[bench]
+ fn bench_append(b: &mut bh) {
+ let lhs = @[7, ..128];
+ let rhs = range(0, 256).to_owned_vec();
+ do b.iter {
+ append(lhs, rhs);
+ }
+ }
+
+ #[bench]
+ fn bench_map(b: &mut bh) {
+ let elts = range(0, 256).to_owned_vec();
+ do b.iter {
+ map(elts, |x| x*2);
+ }
+ }
+
+ #[bench]
+ fn bench_from_fn(b: &mut bh) {
+ do b.iter {
+ from_fn(1024, |x| x);
+ }
+ }
+
+ #[bench]
+ fn bench_from_elem(b: &mut bh) {
+ do b.iter {
+ from_elem(1024, 0u64);
+ }
+ }
+
+ #[bench]
+ fn bench_to_managed_move(b: &mut bh) {
+ do b.iter {
+ let elts = range(0, 1024).to_owned_vec(); // yikes! can't move out of capture, though
+ to_managed_move(elts);
+ }
+ }
+
+ #[bench]
+ fn bench_to_managed(b: &mut bh) {
+ let elts = range(0, 1024).to_owned_vec();
+ do b.iter {
+ to_managed(elts);
+ }
+ }
+
+ #[bench]
+ fn bench_clone(b: &mut bh) {
+ let elts = to_managed(range(0, 1024).to_owned_vec());
+ do b.iter {
+ elts.clone();
+ }
+ }
}
Also, a few conversion functions: `to_bit` and `to_str`.
-Finally, some inquries into the nature of truth: `is_true` and `is_false`.
+Finally, some inquiries into the nature of truth: `is_true` and `is_false`.
*/
// except according to those terms.
use cast;
-use iterator::Iterator;
+use iterator::{Iterator,range};
use libc;
use ops::Drop;
use option::{Option, Some, None};
use ptr::RawPtr;
use ptr;
use str::StrSlice;
-use vec::ImmutableVector;
+use vec::{ImmutableVector,CopyableVector};
+use container::Container;
+
+/// Resolution options for the `null_byte` condition
+pub enum NullByteResolution {
+ /// Truncate at the null byte
+ Truncate,
+ /// Use a replacement byte
+ ReplaceWith(libc::c_char)
+}
+
+condition! {
+ // this should be &[u8] but there's a lifetime issue
+ null_byte: (~[u8]) -> super::NullByteResolution;
+}
/// The representation of a C String.
///
}
/// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
+ /// Any ownership of the buffer by the `CString` wrapper is forgotten.
pub unsafe fn unwrap(self) -> *libc::c_char {
let mut c_str = self;
c_str.owns_buffer_ = false;
///
/// Fails if the CString is null.
pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
+ #[fixed_stack_segment]; #[inline(never)];
if self.buf.is_null() { fail!("CString is null!"); }
unsafe {
let len = libc::strlen(self.buf) as uint;
}
/// Return a CString iterator.
- fn iter<'a>(&'a self) -> CStringIterator<'a> {
+ pub fn iter<'a>(&'a self) -> CStringIterator<'a> {
CStringIterator {
ptr: self.buf,
lifetime: unsafe { cast::transmute(self.buf) },
impl Drop for CString {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
if self.owns_buffer_ {
unsafe {
libc::free(self.buf as *libc::c_void)
/// A generic trait for converting a value to a CString.
pub trait ToCStr {
- /// Create a C String.
+ /// Copy the receiver into a CString.
+ ///
+ /// # Failure
+ ///
+ /// Raises the `null_byte` condition if the receiver has an interior null.
fn to_c_str(&self) -> CString;
+
+ /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
+ unsafe fn to_c_str_unchecked(&self) -> CString;
+
+ /// Work with a temporary CString constructed from the receiver.
+ /// The provided `*libc::c_char` will be freed immediately upon return.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// let s = "PATH".with_c_str(|path| libc::getenv(path))
+ /// ~~~
+ ///
+ /// # Failure
+ ///
+ /// Raises the `null_byte` condition if the receiver has an interior null.
+ #[inline]
+ fn with_c_str<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
+ self.to_c_str().with_ref(f)
+ }
+
+ /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
+ #[inline]
+ unsafe fn with_c_str_unchecked<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
+ self.to_c_str_unchecked().with_ref(f)
+ }
}
impl<'self> ToCStr for &'self str {
fn to_c_str(&self) -> CString {
self.as_bytes().to_c_str()
}
+
+ #[inline]
+ unsafe fn to_c_str_unchecked(&self) -> CString {
+ self.as_bytes().to_c_str_unchecked()
+ }
}
impl<'self> ToCStr for &'self [u8] {
fn to_c_str(&self) -> CString {
- do self.as_imm_buf |self_buf, self_len| {
- unsafe {
- let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
- if buf.is_null() {
- fail!("failed to allocate memory!");
+ #[fixed_stack_segment]; #[inline(never)];
+ let mut cs = unsafe { self.to_c_str_unchecked() };
+ do cs.with_mut_ref |buf| {
+ for i in range(0, self.len()) {
+ unsafe {
+ let p = buf.offset_inbounds(i as int);
+ if *p == 0 {
+ match null_byte::cond.raise(self.to_owned()) {
+ Truncate => break,
+ ReplaceWith(c) => *p = c
+ }
+ }
}
+ }
+ }
+ cs
+ }
- ptr::copy_memory(buf, self_buf, self_len);
- *ptr::mut_offset(buf, self_len as int) = 0;
-
- CString::new(buf as *libc::c_char, true)
+ unsafe fn to_c_str_unchecked(&self) -> CString {
+ #[fixed_stack_segment]; #[inline(never)];
+ do self.as_imm_buf |self_buf, self_len| {
+ let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
+ if buf.is_null() {
+ fail!("failed to allocate memory!");
}
+
+ ptr::copy_memory(buf, self_buf, self_len);
+ *ptr::mut_offset(buf, self_len as int) = 0;
+
+ CString::new(buf as *libc::c_char, true)
}
}
}
#[test]
fn test_unwrap() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let c_str = "hello".to_c_str();
unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
}
#[test]
fn test_with_ref() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let c_str = "hello".to_c_str();
let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
assert!(!c_str.is_null());
assert_eq!(iter.next(), Some('o' as libc::c_char));
assert_eq!(iter.next(), None);
}
+
+ #[test]
+ #[ignore(cfg(windows))]
+ fn test_to_c_str_fail() {
+ use c_str::null_byte::cond;
+
+ let mut error_happened = false;
+ do cond.trap(|err| {
+ assert_eq!(err, bytes!("he", 0, "llo").to_owned())
+ error_happened = true;
+ Truncate
+ }).inside {
+ "he\x00llo".to_c_str()
+ };
+ assert!(error_happened);
+
+ do cond.trap(|_| {
+ ReplaceWith('?' as libc::c_char)
+ }).inside(|| "he\x00llo".to_c_str()).with_ref |buf| {
+ unsafe {
+ assert_eq!(*buf.offset(0), 'h' as libc::c_char);
+ assert_eq!(*buf.offset(1), 'e' as libc::c_char);
+ assert_eq!(*buf.offset(2), '?' as libc::c_char);
+ assert_eq!(*buf.offset(3), 'l' as libc::c_char);
+ assert_eq!(*buf.offset(4), 'l' as libc::c_char);
+ assert_eq!(*buf.offset(5), 'o' as libc::c_char);
+ assert_eq!(*buf.offset(6), 0);
+ }
+ }
+ }
+
+ #[test]
+ fn test_to_c_str_unchecked() {
+ unsafe {
+ do "he\x00llo".to_c_str_unchecked().with_ref |buf| {
+ assert_eq!(*buf.offset(0), 'h' as libc::c_char);
+ assert_eq!(*buf.offset(1), 'e' as libc::c_char);
+ assert_eq!(*buf.offset(2), 0);
+ assert_eq!(*buf.offset(3), 'l' as libc::c_char);
+ assert_eq!(*buf.offset(4), 'l' as libc::c_char);
+ assert_eq!(*buf.offset(5), 'o' as libc::c_char);
+ assert_eq!(*buf.offset(6), 0);
+ }
+ }
+ }
}
use io::WriterUtil;
use io;
use libc;
- use rt::borrowck;
use sys;
use managed;
n_bytes_freed: 0
};
- // Quick hack: we need to free this list upon task exit, and this
- // is a convenient place to do it.
- borrowck::clear_task_borrow_list();
-
// Pass 1: Make all boxes immortal.
//
// In this pass, nothing gets freed, so it does not matter whether
fn find<'a>(&'a self, key: &K) -> Option<&'a V>;
/// Return true if the map contains a value for the specified key
+ #[inline]
fn contains_key(&self, key: &K) -> bool {
self.find(key).is_some()
}
use clone::Clone;
use container::Container;
use cmp::Eq;
-use iterator::Iterator;
+use iterator::{Iterator, FilterMap};
use result::Result;
use result;
use str::StrSlice;
}
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Extracts from a vector of either all the left values
-pub fn lefts<L: Clone, R>(eithers: &[Either<L, R>]) -> ~[L] {
- do vec::build_sized(eithers.len()) |push| {
- for elt in eithers.iter() {
- match *elt {
- Left(ref l) => { push((*l).clone()); }
- _ => { /* fallthrough */ }
- }
+/// An iterator yielding the `Left` values of its source
+pub type Lefts<L, R, Iter> = FilterMap<'static, Either<L, R>, L, Iter>;
+
+/// An iterator yielding the `Right` values of its source
+pub type Rights<L, R, Iter> = FilterMap<'static, Either<L, R>, R, Iter>;
+
+/// Extracts all the left values
+pub fn lefts<L, R, Iter: Iterator<Either<L, R>>>(eithers: Iter)
+ -> Lefts<L, R, Iter> {
+ do eithers.filter_map |elt| {
+ match elt {
+ Left(x) => Some(x),
+ _ => None,
}
}
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Extracts from a vector of either all the right values
-pub fn rights<L, R: Clone>(eithers: &[Either<L, R>]) -> ~[R] {
- do vec::build_sized(eithers.len()) |push| {
- for elt in eithers.iter() {
- match *elt {
- Right(ref r) => { push((*r).clone()); }
- _ => { /* fallthrough */ }
- }
+/// Extracts all the right values
+pub fn rights<L, R, Iter: Iterator<Either<L, R>>>(eithers: Iter)
+ -> Rights<L, R, Iter> {
+ do eithers.filter_map |elt| {
+ match elt {
+ Right(x) => Some(x),
+ _ => None,
}
}
}
+
// FIXME: #8228 Replaceable by an external iterator?
/// 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.
pub fn partition<L, R>(eithers: ~[Either<L, R>]) -> (~[L], ~[R]) {
- let mut lefts: ~[L] = ~[];
- let mut rights: ~[R] = ~[];
+ let n_lefts = eithers.iter().count(|elt| elt.is_left());
+ let mut lefts = vec::with_capacity(n_lefts);
+ let mut rights = vec::with_capacity(eithers.len() - n_lefts);
for elt in eithers.move_iter() {
match elt {
Left(l) => lefts.push(l),
#[test]
fn test_lefts() {
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
- let result = lefts(input);
+ let result = lefts(input.move_iter()).to_owned_vec();
assert_eq!(result, ~[10, 12, 14]);
}
#[test]
fn test_lefts_none() {
let input: ~[Either<int, int>] = ~[Right(10), Right(10)];
- let result = lefts(input);
+ let result = lefts(input.move_iter()).to_owned_vec();
assert_eq!(result.len(), 0u);
}
#[test]
fn test_lefts_empty() {
let input: ~[Either<int, int>] = ~[];
- let result = lefts(input);
+ let result = lefts(input.move_iter()).to_owned_vec();
assert_eq!(result.len(), 0u);
}
#[test]
fn test_rights() {
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
- let result = rights(input);
+ let result = rights(input.move_iter()).to_owned_vec();
assert_eq!(result, ~[11, 13]);
}
#[test]
fn test_rights_none() {
let input: ~[Either<int, int>] = ~[Left(10), Left(10)];
- let result = rights(input);
+ let result = rights(input.move_iter()).to_owned_vec();
assert_eq!(result.len(), 0u);
}
#[test]
fn test_rights_empty() {
let input: ~[Either<int, int>] = ~[];
- let result = rights(input);
+ let result = rights(input.move_iter()).to_owned_vec();
assert_eq!(result.len(), 0u);
}
Because formatting is done via traits, there is no requirement that the
`d` format actually takes an `int`, but rather it simply requires a type which
ascribes to the `Signed` formatting trait. There are various parameters which do
-require a particular type, however. Namely if the sytnax `{:.*s}` is used, then
+require a particular type, however. Namely if the syntax `{:.*s}` is used, then
the number of characters to print from the string precedes the actual string and
must have the type `uint`. Although a `uint` can be printed with `{:u}`, it is
illegal to reference an argument as such. For example, this is another invalid
## Internationalization
The formatting syntax supported by the `ifmt!` extension supports
-internationalization by providing "methods" which execute various differnet
+internationalization by providing "methods" which execute various different
outputs depending on the input. The syntax and methods provided are similar to
other internationalization systems, so again nothing should seem alien.
Currently two methods are supported by this extension: "select" and "plural".
priv value: &'self util::Void,
}
+/// When a format is not otherwise specified, types are formatted by ascribing
+/// to this trait. There is not an explicit way of selecting this trait to be
+/// used for formatting, it is only if no other format is specified.
+#[allow(missing_doc)]
+pub trait Default { fn fmt(&Self, &mut Formatter); }
+
+/// Format trait for the `b` character
#[allow(missing_doc)]
pub trait Bool { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `c` character
#[allow(missing_doc)]
pub trait Char { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `i` and `d` characters
#[allow(missing_doc)]
pub trait Signed { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `u` character
#[allow(missing_doc)]
pub trait Unsigned { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `o` character
#[allow(missing_doc)]
pub trait Octal { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `b` character
#[allow(missing_doc)]
pub trait Binary { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `x` character
#[allow(missing_doc)]
pub trait LowerHex { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `X` character
#[allow(missing_doc)]
pub trait UpperHex { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `s` character
#[allow(missing_doc)]
pub trait String { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `?` character
#[allow(missing_doc)]
pub trait Poly { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `p` character
#[allow(missing_doc)]
pub trait Pointer { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `f` character
#[allow(missing_doc)]
pub trait Float { fn fmt(&Self, &mut Formatter); }
}
}
-impl<'self> String for &'self str {
- fn fmt(s: & &'self str, f: &mut Formatter) {
- f.pad(*s);
+impl<'self, T: str::Str> String for T {
+ fn fmt(s: &T, f: &mut Formatter) {
+ f.pad(s.as_slice());
}
}
}
}
+// Implementation of Default for various core types
+
+macro_rules! delegate(($ty:ty to $other:ident) => {
+ impl<'self> Default for $ty {
+ fn fmt(me: &$ty, f: &mut Formatter) {
+ $other::fmt(me, f)
+ }
+ }
+})
+delegate!(int to Signed)
+delegate!( i8 to Signed)
+delegate!(i16 to Signed)
+delegate!(i32 to Signed)
+delegate!(i64 to Signed)
+delegate!(uint to Unsigned)
+delegate!( u8 to Unsigned)
+delegate!( u16 to Unsigned)
+delegate!( u32 to Unsigned)
+delegate!( u64 to Unsigned)
+delegate!(@str to String)
+delegate!(~str to String)
+delegate!(&'self str to String)
+delegate!(bool to Bool)
+delegate!(char to Char)
+delegate!(float to Float)
+delegate!(f32 to Float)
+delegate!(f64 to Float)
+
+impl<T> Default for *const T {
+ fn fmt(me: &*const T, f: &mut Formatter) { Pointer::fmt(me, f) }
+}
+
// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
// it's a lot easier than creating all of the rt::Piece structures here.
ArgumentNext, ArgumentIs(uint), ArgumentNamed(&'self str)
}
-/// Enum of alignments which are supoprted.
+/// Enum of alignments which are supported.
#[deriving(Eq)]
pub enum Alignment { AlignLeft, AlignRight, AlignUnknown }
}
}
// Finally the actual format specifier
- spec.ty = self.word();
+ if self.consume('?') {
+ spec.ty = "?";
+ } else {
+ spec.ty = self.word();
+ }
return spec;
}
use rt::io::Writer;
use str::OwnedStr;
use to_bytes::IterBytes;
-use uint;
use vec::ImmutableVector;
+use num::ToStrRadix;
// Alias `SipState` to `State`.
pub use State = hash::SipState;
let r = self.result_bytes();
let mut s = ~"";
for b in r.iter() {
- s.push_str(uint::to_str_radix(*b as uint, 16u));
+ s.push_str((*b as uint).to_str_radix(16u));
}
s
}
use super::*;
use prelude::*;
- use uint;
+ // Hash just the bytes of the slice, without length prefix
+ struct Bytes<'self>(&'self [u8]);
+ impl<'self> IterBytes for Bytes<'self> {
+ fn iter_bytes(&self, _lsb0: bool, f: &fn(&[u8]) -> bool) -> bool {
+ f(**self)
+ }
+ }
#[test]
fn test_siphash() {
fn to_hex_str(r: &[u8, ..8]) -> ~str {
let mut s = ~"";
for b in r.iter() {
- s.push_str(uint::to_str_radix(*b as uint, 16u));
+ s.push_str((*b as uint).to_str_radix(16u));
}
s
}
while t < 64 {
debug!("siphash test %?", t);
let vec = u8to64_le!(vecs[t], 0);
- let out = buf.hash_keyed(k0, k1);
+ let out = Bytes(buf.as_slice()).hash_keyed(k0, k1);
debug!("got %?, expected %?", out, vec);
assert_eq!(vec, out);
fn test_float_hashes_of_zero() {
assert_eq!(0.0.hash(), (-0.0).hash());
}
+
+ #[test]
+ fn test_hash_no_concat_alias() {
+ let s = ("aa", "bb");
+ let t = ("aabb", "");
+ let u = ("a", "abb");
+
+ let v = (&[1u8], &[0u8, 0], &[0u8]);
+ let w = (&[1u8, 0, 0, 0], &[], &[]);
+
+ assert!(v != w);
+ assert!(s.hash() != t.hash() && s.hash() != u.hash());
+ assert!(v.hash() != w.hash());
+ }
}
}
}
-impl<K: Eq + Hash, V, T: Iterator<(K, V)>> FromIterator<(K, V), T> for HashMap<K, V> {
- fn from_iterator(iter: &mut T) -> HashMap<K, V> {
+impl<K: Eq + Hash, V> FromIterator<(K, V)> for HashMap<K, V> {
+ fn from_iterator<T: Iterator<(K, V)>>(iter: &mut T) -> HashMap<K, V> {
let (lower, _) = iter.size_hint();
let mut map = HashMap::with_capacity(lower);
map.extend(iter);
}
}
-impl<K: Eq + Hash, V, T: Iterator<(K, V)>> Extendable<(K, V), T> for HashMap<K, V> {
- fn extend(&mut self, iter: &mut T) {
+impl<K: Eq + Hash, V> Extendable<(K, V)> for HashMap<K, V> {
+ fn extend<T: Iterator<(K, V)>>(&mut self, iter: &mut T) {
for (k, v) in *iter {
self.insert(k, v);
}
}
-impl<K: Eq + Hash, T: Iterator<K>> FromIterator<K, T> for HashSet<K> {
- fn from_iterator(iter: &mut T) -> HashSet<K> {
+impl<T:Hash + Eq + Clone> Clone for HashSet<T> {
+ fn clone(&self) -> HashSet<T> {
+ HashSet {
+ map: self.map.clone()
+ }
+ }
+}
+
+impl<K: Eq + Hash> FromIterator<K> for HashSet<K> {
+ fn from_iterator<T: Iterator<K>>(iter: &mut T) -> HashSet<K> {
let (lower, _) = iter.size_hint();
let mut set = HashSet::with_capacity(lower);
set.extend(iter);
}
}
-impl<K: Eq + Hash, T: Iterator<K>> Extendable<K, T> for HashSet<K> {
- fn extend(&mut self, iter: &mut T) {
+impl<K: Eq + Hash> Extendable<K> for HashSet<K> {
+ fn extend<T: Iterator<K>>(&mut self, iter: &mut T) {
for k in *iter {
self.insert(k);
}
let v = hs.move_iter().collect::<~[char]>();
assert!(['a', 'b'] == v || ['b', 'a'] == v);
}
+
+ #[test]
+ fn test_eq() {
+ let mut s1 = HashSet::new();
+ s1.insert(1);
+ s1.insert(2);
+ s1.insert(3);
+
+ let mut s2 = HashSet::new();
+ s2.insert(1);
+ s2.insert(2);
+
+ assert!(s1 != s2);
+
+ s2.insert(3);
+
+ assert_eq!(s1, s2);
+ }
}
impl Reader for *libc::FILE {
fn read(&self, bytes: &mut [u8], len: uint) -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do bytes.as_mut_buf |buf_p, buf_len| {
assert!(buf_len >= len);
}
}
fn read_byte(&self) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::fgetc(*self) as int
}
}
fn eof(&self) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
return libc::feof(*self) != 0 as c_int;
}
}
fn seek(&self, offset: int, whence: SeekStyle) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
assert!(libc::fseek(*self,
offset as c_long,
}
}
fn tell(&self) -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
return libc::ftell(*self) as uint;
}
impl Drop for FILERes {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::fclose(self.f);
}
* # Example
*
* ~~~ {.rust}
-* let stdin = core::io::stdin();
+* let stdin = std::io::stdin();
* let line = stdin.read_line();
-* core::io::print(line);
+* std::io::print(line);
* ~~~
*/
pub fn stdin() -> @Reader {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
@rustrt::rust_get_stdin() as @Reader
}
}
pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
- let f = do path.to_c_str().with_ref |pathbuf| {
- do "rb".to_c_str().with_ref |modebuf| {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ let f = do path.with_c_str |pathbuf| {
+ do "rb".with_c_str |modebuf| {
unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) }
}
};
impl Writer for *libc::FILE {
fn write(&self, v: &[u8]) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do v.as_imm_buf |vbuf, len| {
let nout = libc::fwrite(vbuf as *c_void,
}
}
fn seek(&self, offset: int, whence: SeekStyle) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
assert!(libc::fseek(*self,
offset as c_long,
}
}
fn tell(&self) -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::ftell(*self) as uint
}
}
fn flush(&self) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::fflush(*self) as int
}
}
fn get_type(&self) -> WriterType {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let fd = libc::fileno(*self);
if libc::isatty(fd) == 0 { File }
impl Writer for fd_t {
fn write(&self, v: &[u8]) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut count = 0u;
do v.as_imm_buf |vbuf, len| {
}
fn flush(&self) -> int { 0 }
fn get_type(&self) -> WriterType {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
if libc::isatty(*self) == 0 { File } else { Screen }
}
impl Drop for FdRes {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::close(self.fd);
}
pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
-> Result<@Writer, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
#[cfg(windows)]
fn wb() -> c_int {
(O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
}
}
let fd = unsafe {
- do path.to_c_str().with_ref |pathbuf| {
+ do path.with_c_str |pathbuf| {
libc::open(pathbuf, fflags, (S_IRUSR | S_IWUSR) as c_int)
}
};
/// (8 bytes).
fn write_le_f64(&self, f: f64);
- /// Write a litten-endian IEEE754 single-precision floating-point
+ /// Write a little-endian IEEE754 single-precision floating-point
/// (4 bytes).
fn write_le_f32(&self, f: f32);
// FIXME: fileflags // #2004
pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
- let f = do path.to_c_str().with_ref |pathbuf| {
- do "w".to_c_str().with_ref |modebuf| {
+ let f = do path.with_c_str |pathbuf| {
+ do "w".with_c_str |modebuf| {
libc::fopen(pathbuf, modebuf)
}
};
* # Example
*
* ~~~ {.rust}
-* let stdout = core::io::stdout();
+* let stdout = std::io::stdout();
* stdout.write_str("hello\n");
* ~~~
*/
* # Example
*
* ~~~ {.rust}
-* let stderr = core::io::stderr();
+* let stderr = std::io::stderr();
* stderr.write_str("hello\n");
* ~~~
*/
blk: &fn(v: Res<*libc::FILE>)) {
blk(Res::new(Arg {
val: file.f, opt_level: opt_level,
- fsync_fn: |file, l| {
- unsafe {
- os::fsync_fd(libc::fileno(*file), l) as int
- }
- }
+ fsync_fn: |file, l| fsync_fd(fileno(*file), l)
}));
+
+ fn fileno(stream: *libc::FILE) -> libc::c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::fileno(stream) }
+ }
}
// fsync fd after executing blk
blk: &fn(v: Res<fd_t>)) {
blk(Res::new(Arg {
val: fd.fd, opt_level: opt_level,
- fsync_fn: |fd, l| os::fsync_fd(*fd, l) as int
+ fsync_fn: |fd, l| fsync_fd(*fd, l)
}));
}
+ fn fsync_fd(fd: libc::c_int, level: Level) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ os::fsync_fd(fd, level) as int
+ }
+
// Type of objects that may want to fsync
pub trait FSyncable { fn fsync(&self, l: Level) -> int; }
use cmp::Ord;
use clone::Clone;
use uint;
+use util;
/// Conversion from an `Iterator`
-pub trait FromIterator<A, T: Iterator<A>> {
+pub trait FromIterator<A> {
/// Build a container with elements from an external iterator.
- fn from_iterator(iterator: &mut T) -> Self;
+ fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> Self;
}
/// A type growable from an `Iterator` implementation
-pub trait Extendable<A, T: Iterator<A>>: FromIterator<A, T> {
+pub trait Extendable<A>: FromIterator<A> {
/// Extend a container with the elements yielded by an iterator
- fn extend(&mut self, iterator: &mut T);
+ fn extend<T: Iterator<A>>(&mut self, iterator: &mut T);
}
/// An interface for dealing with "external iterators". These types of iterators
/// assert!(it.peek().is_none());
/// assert!(it.next().is_none());
/// ~~~
+ #[inline]
fn peekable(self) -> Peekable<A, Self> {
Peekable{iter: self, peeked: None}
}
/// assert!(a == b);
/// ~~~
#[inline]
- fn collect<B: FromIterator<A, Self>>(&mut self) -> B {
+ fn collect<B: FromIterator<A>>(&mut self) -> B {
FromIterator::from_iterator(self)
}
i
}
- /// Return the element that gives the maximum value from the specfied function
+ /// Return the element that gives the maximum value from the
+ /// specified function.
///
/// # Example
///
}).map_move(|(x, _)| x)
}
- /// Return the element that gives the minimum value from the specfied function
+ /// Return the element that gives the minimum value from the
+ /// specified function.
///
/// # Example
///
}
}
+/// A double-ended iterator yielding mutable references
+pub trait MutableDoubleEndedIterator {
+ // FIXME: #5898: should be called `reverse`
+ /// Use an iterator to reverse a container in-place
+ fn reverse_(&mut self);
+}
+
+impl<'self, A, T: DoubleEndedIterator<&'self mut A>> MutableDoubleEndedIterator for T {
+ // FIXME: #5898: should be called `reverse`
+ /// Use an iterator to reverse a container in-place
+ fn reverse_(&mut self) {
+ loop {
+ match (self.next(), self.next_back()) {
+ (Some(x), Some(y)) => util::swap(x, y),
+ _ => break
+ }
+ }
+ }
+}
+
/// An object implementing random access indexing by `uint`
///
/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`.
}
}
-impl<'self, A, B, T: DoubleEndedIterator<A>> DoubleEndedIterator<B>
-for Map<'self, A, B, T> {
+impl<'self, A, B, T: DoubleEndedIterator<A>> DoubleEndedIterator<B> for Map<'self, A, B, T> {
#[inline]
fn next_back(&mut self) -> Option<B> {
let next = self.iter.next_back();
}
}
-impl<'self, A, B, T: RandomAccessIterator<A>> RandomAccessIterator<B>
-for Map<'self, A, B, T> {
+impl<'self, A, B, T: RandomAccessIterator<A>> RandomAccessIterator<B> for Map<'self, A, B, T> {
#[inline]
fn indexable(&self) -> uint {
self.iter.indexable()
}
}
+/// A range of numbers from [0, N]
+#[deriving(Clone, DeepClone)]
+pub struct RangeInclusive<A> {
+ priv range: Range<A>,
+ priv done: bool
+}
+
+/// Return an iterator over the range [start, stop]
+#[inline]
+pub fn range_inclusive<A: Add<A, A> + Ord + Clone + One>(start: A, stop: A) -> RangeInclusive<A> {
+ RangeInclusive{range: range(start, stop), done: false}
+}
+
+impl<A: Add<A, A> + Ord + Clone> Iterator<A> for RangeInclusive<A> {
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ match self.range.next() {
+ Some(x) => Some(x),
+ None => {
+ if self.done {
+ None
+ } else {
+ self.done = true;
+ Some(self.range.stop.clone())
+ }
+ }
+ }
+ }
+}
+
+impl<A: Sub<A, A> + Integer + Ord + Clone> DoubleEndedIterator<A> for RangeInclusive<A> {
+ #[inline]
+ fn next_back(&mut self) -> Option<A> {
+ if self.range.stop > self.range.state {
+ let result = self.range.stop.clone();
+ self.range.stop = self.range.stop - self.range.one;
+ Some(result)
+ } else if self.done {
+ None
+ } else {
+ self.done = true;
+ Some(self.range.stop.clone())
+ }
+ }
+}
+
impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> {
#[inline]
fn next(&mut self) -> Option<A> {
}
impl<A: Clone> Repeat<A> {
- /// Create a new `Repeat` that enlessly repeats the element `elt`.
+ /// Create a new `Repeat` that endlessly repeats the element `elt`.
#[inline]
pub fn new(elt: A) -> Repeat<A> {
Repeat{element: elt}
fail!("unreachable");
}
}
+
+ #[test]
+ fn test_range_inclusive() {
+ assert_eq!(range_inclusive(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4, 5]);
+ assert_eq!(range_inclusive(0i, 5).invert().collect::<~[int]>(), ~[5i, 4, 3, 2, 1, 0]);
+ }
+
+ #[test]
+ fn test_reverse() {
+ let mut ys = [1, 2, 3, 4, 5];
+ ys.mut_iter().reverse_();
+ assert_eq!(ys, [5, 4, 3, 2, 1]);
+ }
}
They cannot be implemented by user code, but are instead implemented
by the compiler automatically for the types to which they apply.
-The 2 kinds are
-
-* Send - owned types and types containing owned types. These types
- may be transferred across task boundaries.
-
-* Freeze - types that are deeply immutable.
-
*/
-#[allow(missing_doc)];
-
+/// Types able to be transferred across task boundaries.
#[lang="send"]
pub trait Send {
// empty.
}
+/// Types that are either immutable or have inherited mutability.
#[lang="freeze"]
pub trait Freeze {
// empty.
}
+/// Types with a constant size known at compile-time.
#[lang="sized"]
pub trait Sized {
// Empty.
// doesn't link it correctly on i686, so we're going
// through a C function that mysteriously does work.
pub unsafe fn opendir(dirname: *c_char) -> *DIR {
+ #[fixed_stack_segment]; #[inline(never)];
rust_opendir(dirname)
}
pub unsafe fn readdir(dirp: *DIR) -> *dirent_t {
+ #[fixed_stack_segment]; #[inline(never)];
rust_readdir(dirp)
}
~~~{.rust}
use std::local_data;
-static key_int: local_data::Key<int> = &local_data::Key;
-static key_vector: local_data::Key<~[int]> = &local_data::Key;
+local_data_key!(key_int: int);
+local_data_key!(key_vector: ~[int]);
local_data::set(key_int, 3);
local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
+++ /dev/null
-// 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.
-
-/*!
-
-Functions for the unit type.
-
-*/
-
-#[cfg(not(test))]
-use prelude::*;
-#[cfg(not(test))]
-use num::Zero;
-
-
-
-#[cfg(not(test))]
-impl Eq for () {
- #[inline]
- fn eq(&self, _other: &()) -> bool { true }
- #[inline]
- fn ne(&self, _other: &()) -> bool { false }
-}
-
-#[cfg(not(test))]
-impl Ord for () {
- #[inline]
- fn lt(&self, _other: &()) -> bool { false }
-}
-
-#[cfg(not(test))]
-impl TotalOrd for () {
- #[inline]
- fn cmp(&self, _other: &()) -> Ordering { Equal }
-}
-
-#[cfg(not(test))]
-impl TotalEq for () {
- #[inline]
- fn equals(&self, _other: &()) -> bool { true }
-}
-
-#[cfg(not(test))]
-impl Zero for () {
- #[inline]
- fn zero() -> () { () }
- #[inline]
- fn is_zero(&self) -> bool { true }
-}
-
use unstable::intrinsics;
$(
- #[inline]
+ #[inline] #[fixed_stack_segment] #[inline(never)]
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
unsafe {
$bound_name($( $arg ),*)
pub mod consts {
// FIXME (requires Issue #1433 to fix): replace with mathematical
// staticants from cmath.
- /// Archimedes' staticant
+ /// Archimedes' constant
pub static pi: f32 = 3.14159265358979323846264338327950288_f32;
/// pi/2.0
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]
-pub fn to_str_radix(num: f32, rdx: uint) -> ~str {
- let (r, special) = strconv::float_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
}
impl num::ToStrRadix for f32 {
+ /// 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]
fn to_str_radix(&self, rdx: uint) -> ~str {
- to_str_radix(*self, rdx)
+ let (r, special) = strconv::float_to_str_common(
+ *self, rdx, true, strconv::SignNeg, strconv::DigAll);
+ if special { fail!("number has a special value, \
+ try to_str_radix_special() if those are expected") }
+ r
}
}
use unstable::intrinsics;
$(
- #[inline]
+ #[inline] #[fixed_stack_segment] #[inline(never)]
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
unsafe {
$bound_name($( $arg ),*)
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]
-pub fn to_str_radix(num: f64, rdx: uint) -> ~str {
- let (r, special) = strconv::float_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
}
impl num::ToStrRadix for f64 {
+ /// 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]
fn to_str_radix(&self, rdx: uint) -> ~str {
- to_str_radix(*self, rdx)
+ let (r, special) = strconv::float_to_str_common(
+ *self, rdx, true, strconv::SignNeg, strconv::DigAll);
+ if special { fail!("number has a special value, \
+ try to_str_radix_special() if those are expected") }
+ r
}
}
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]
-pub fn to_str_radix(num: float, radix: uint) -> ~str {
- let (r, special) = strconv::float_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
}
impl num::ToStrRadix for float {
+ /// 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]
fn to_str_radix(&self, radix: uint) -> ~str {
- to_str_radix(*self, radix)
+ let (r, special) = strconv::float_to_str_common(
+ *self, radix, true, strconv::SignNeg, strconv::DigAll);
+ if special { fail!("number has a special value, \
+ try to_str_radix_special() if those are expected") }
+ r
}
}
#[test]
pub fn test_to_str_radix() {
- assert_eq!(to_str_radix(36., 36u), ~"10");
- assert_eq!(to_str_radix(8.125, 2u), ~"1000.001");
+ assert_eq!(36.0f.to_str_radix(36u), ~"10");
+ assert_eq!(8.125f.to_str_radix(2u), ~"1000.001");
}
#[test]
#[allow(non_uppercase_statics)];
use num::{ToStrRadix, FromStrRadix};
-use num::{Zero, One, strconv};
+use num::{CheckedDiv, Zero, One, strconv};
use prelude::*;
use str;
pub static min_value: $T = (-1 as $T) << (bits - 1);
pub static max_value: $T = min_value - 1 as $T;
+impl CheckedDiv for $T {
+ #[inline]
+ fn checked_div(&self, v: &$T) -> Option<$T> {
+ if *v == 0 || (*self == min_value && *v == -1) {
+ None
+ } else {
+ Some(self / *v)
+ }
+ }
+}
+
enum Range { Closed, HalfOpen }
#[inline]
f(buf.slice(0, cur))
}
-/// Convert to a string in base 10.
-#[inline]
-pub fn to_str(num: $T) -> ~str {
- to_str_radix(num, 10u)
-}
-
-/// Convert to a string in a given base.
-#[inline]
-pub fn to_str_radix(num: $T, radix: uint) -> ~str {
- let mut buf: ~[u8] = ~[];
- do strconv::int_to_str_bytes_common(num, radix, strconv::SignNeg) |i| {
- buf.push(i);
- }
- // We know we generated valid utf-8, so we don't need to go through that
- // check.
- unsafe { str::raw::from_bytes_owned(buf) }
-}
-
impl ToStr for $T {
+ /// Convert to a string in base 10.
#[inline]
fn to_str(&self) -> ~str {
- to_str(*self)
+ self.to_str_radix(10)
}
}
impl ToStrRadix for $T {
+ /// Convert to a string in a given base.
#[inline]
fn to_str_radix(&self, radix: uint) -> ~str {
- to_str_radix(*self, radix)
+ let mut buf: ~[u8] = ~[];
+ do strconv::int_to_str_bytes_common(*self, radix, strconv::SignNeg) |i| {
+ buf.push(i);
+ }
+ // We know we generated valid utf-8, so we don't need to go through that
+ // check.
+ unsafe { str::raw::from_bytes_owned(buf) }
}
}
use super::*;
use prelude::*;
+ use int;
use i16;
use i32;
use i64;
#[test]
fn test_to_str() {
- assert_eq!(to_str_radix(0 as $T, 10u), ~"0");
- assert_eq!(to_str_radix(1 as $T, 10u), ~"1");
- assert_eq!(to_str_radix(-1 as $T, 10u), ~"-1");
- assert_eq!(to_str_radix(127 as $T, 16u), ~"7f");
- assert_eq!(to_str_radix(100 as $T, 10u), ~"100");
+ assert_eq!((0 as $T).to_str_radix(10u), ~"0");
+ assert_eq!((1 as $T).to_str_radix(10u), ~"1");
+ assert_eq!((-1 as $T).to_str_radix(10u), ~"-1");
+ assert_eq!((127 as $T).to_str_radix(16u), ~"7f");
+ assert_eq!((100 as $T).to_str_radix(10u), ~"100");
}
#[test]
fn test_int_to_str_overflow() {
let mut i8_val: i8 = 127_i8;
- assert_eq!(i8::to_str(i8_val), ~"127");
+ assert_eq!(i8_val.to_str(), ~"127");
i8_val += 1 as i8;
- assert_eq!(i8::to_str(i8_val), ~"-128");
+ assert_eq!(i8_val.to_str(), ~"-128");
let mut i16_val: i16 = 32_767_i16;
- assert_eq!(i16::to_str(i16_val), ~"32767");
+ assert_eq!(i16_val.to_str(), ~"32767");
i16_val += 1 as i16;
- assert_eq!(i16::to_str(i16_val), ~"-32768");
+ assert_eq!(i16_val.to_str(), ~"-32768");
let mut i32_val: i32 = 2_147_483_647_i32;
- assert_eq!(i32::to_str(i32_val), ~"2147483647");
+ assert_eq!(i32_val.to_str(), ~"2147483647");
i32_val += 1 as i32;
- assert_eq!(i32::to_str(i32_val), ~"-2147483648");
+ assert_eq!(i32_val.to_str(), ~"-2147483648");
let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
- assert_eq!(i64::to_str(i64_val), ~"9223372036854775807");
+ assert_eq!(i64_val.to_str(), ~"9223372036854775807");
i64_val += 1 as i64;
- assert_eq!(i64::to_str(i64_val), ~"-9223372036854775808");
+ assert_eq!(i64_val.to_str(), ~"-9223372036854775808");
}
#[test]
fn test_range_step_zero_step() {
do range_step(0,10,0) |_i| { true };
}
+
+ #[test]
+ fn test_signed_checked_div() {
+ assert_eq!(10i.checked_div(&2), Some(5));
+ assert_eq!(5i.checked_div(&0), None);
+ assert_eq!(int::min_value.checked_div(&-1), None);
+ }
}
}))
}
/// Saturating math operations
-pub trait Saturating: Int {
+pub trait Saturating {
/// Saturating addition operator.
/// Returns a+b, saturating at the numeric bounds instead of overflowing.
+ fn saturating_add(self, v: Self) -> Self;
+
+ /// Saturating subtraction operator.
+ /// Returns a-b, saturating at the numeric bounds instead of overflowing.
+ fn saturating_sub(self, v: Self) -> Self;
+}
+
+impl<T: CheckedAdd+CheckedSub+Zero+Ord+Bounded> Saturating for T {
#[inline]
- fn saturating_add(self, v: Self) -> Self {
- let x = self + v;
- if v >= Zero::zero() {
- if x < self {
- // overflow
- Bounded::max_value::<Self>()
- } else { x }
- } else {
- if x > self {
- // underflow
- Bounded::min_value::<Self>()
- } else { x }
+ fn saturating_add(self, v: T) -> T {
+ match self.checked_add(&v) {
+ Some(x) => x,
+ None => if v >= Zero::zero() {
+ Bounded::max_value::<T>()
+ } else {
+ Bounded::min_value::<T>()
+ }
}
}
- /// Saturating subtraction operator.
- /// Returns a-b, saturating at the numeric bounds instead of overflowing.
#[inline]
- fn saturating_sub(self, v: Self) -> Self {
- let x = self - v;
- if v >= Zero::zero() {
- if x > self {
- // underflow
- Bounded::min_value::<Self>()
- } else { x }
- } else {
- if x < self {
- // overflow
- Bounded::max_value::<Self>()
- } else { x }
+ fn saturating_sub(self, v: T) -> T {
+ match self.checked_sub(&v) {
+ Some(x) => x,
+ None => if v >= Zero::zero() {
+ Bounded::min_value::<T>()
+ } else {
+ Bounded::max_value::<T>()
+ }
}
}
}
-impl Saturating for int {}
-impl Saturating for i8 {}
-impl Saturating for i16 {}
-impl Saturating for i32 {}
-impl Saturating for i64 {}
-impl Saturating for uint {}
-impl Saturating for u8 {}
-impl Saturating for u16 {}
-impl Saturating for u32 {}
-impl Saturating for u64 {}
-
pub trait CheckedAdd: Add<Self, Self> {
fn checked_add(&self, v: &Self) -> Option<Self>;
}
}
}
+pub trait CheckedDiv: Div<Self, Self> {
+ fn checked_div(&self, v: &Self) -> Option<Self>;
+}
+
/// Helper function for testing numeric operations
#[cfg(test)]
pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
mod bench {
use extra::test::BenchHarness;
use rand::{XorShiftRng,RngUtil};
- use uint;
use float;
+ use to_str::ToStr;
#[bench]
fn uint_to_str_rand(bh: &mut BenchHarness) {
let mut rng = XorShiftRng::new();
do bh.iter {
- uint::to_str(rng.gen());
+ rng.gen::<uint>().to_str();
}
}
use num::BitCount;
use num::{ToStrRadix, FromStrRadix};
-use num::{Zero, One, strconv};
+use num::{CheckedDiv, Zero, One, strconv};
use prelude::*;
use str;
pub static min_value: $T = 0 as $T;
pub static max_value: $T = 0 as $T - 1 as $T;
+impl CheckedDiv for $T {
+ #[inline]
+ fn checked_div(&self, v: &$T) -> Option<$T> {
+ if *v == 0 {
+ None
+ } else {
+ Some(self / *v)
+ }
+ }
+}
+
enum Range { Closed, HalfOpen }
#[inline]
f(buf.slice(0, cur))
}
-/// Convert to a string in base 10.
-#[inline]
-pub fn to_str(num: $T) -> ~str {
- to_str_radix(num, 10u)
-}
-
-/// Convert to a string in a given base.
-#[inline]
-pub fn to_str_radix(num: $T, radix: uint) -> ~str {
- let mut buf = ~[];
- do strconv::int_to_str_bytes_common(num, radix, strconv::SignNone) |i| {
- buf.push(i);
- }
- // We know we generated valid utf-8, so we don't need to go through that
- // check.
- unsafe { str::raw::from_bytes_owned(buf) }
-}
-
impl ToStr for $T {
+ /// Convert to a string in base 10.
#[inline]
fn to_str(&self) -> ~str {
- to_str(*self)
+ self.to_str_radix(10u)
}
}
impl ToStrRadix for $T {
+ /// Convert to a string in a given base.
#[inline]
fn to_str_radix(&self, radix: uint) -> ~str {
- to_str_radix(*self, radix)
+ let mut buf = ~[];
+ do strconv::int_to_str_bytes_common(*self, radix, strconv::SignNone) |i| {
+ buf.push(i);
+ }
+ // We know we generated valid utf-8, so we don't need to go through that
+ // check.
+ unsafe { str::raw::from_bytes_owned(buf) }
}
}
use u32;
use u64;
use u8;
- use uint;
#[test]
fn test_num() {
#[test]
pub fn test_to_str() {
- assert_eq!(to_str_radix(0 as $T, 10u), ~"0");
- assert_eq!(to_str_radix(1 as $T, 10u), ~"1");
- assert_eq!(to_str_radix(2 as $T, 10u), ~"2");
- assert_eq!(to_str_radix(11 as $T, 10u), ~"11");
- assert_eq!(to_str_radix(11 as $T, 16u), ~"b");
- assert_eq!(to_str_radix(255 as $T, 16u), ~"ff");
- assert_eq!(to_str_radix(0xff as $T, 10u), ~"255");
+ assert_eq!((0 as $T).to_str_radix(10u), ~"0");
+ assert_eq!((1 as $T).to_str_radix(10u), ~"1");
+ assert_eq!((2 as $T).to_str_radix(10u), ~"2");
+ assert_eq!((11 as $T).to_str_radix(10u), ~"11");
+ assert_eq!((11 as $T).to_str_radix(16u), ~"b");
+ assert_eq!((255 as $T).to_str_radix(16u), ~"ff");
+ assert_eq!((0xff as $T).to_str_radix(10u), ~"255");
}
#[test]
#[test]
fn test_uint_to_str_overflow() {
let mut u8_val: u8 = 255_u8;
- assert_eq!(u8::to_str(u8_val), ~"255");
+ assert_eq!(u8_val.to_str(), ~"255");
u8_val += 1 as u8;
- assert_eq!(u8::to_str(u8_val), ~"0");
+ assert_eq!(u8_val.to_str(), ~"0");
let mut u16_val: u16 = 65_535_u16;
- assert_eq!(u16::to_str(u16_val), ~"65535");
+ assert_eq!(u16_val.to_str(), ~"65535");
u16_val += 1 as u16;
- assert_eq!(u16::to_str(u16_val), ~"0");
+ assert_eq!(u16_val.to_str(), ~"0");
let mut u32_val: u32 = 4_294_967_295_u32;
- assert_eq!(u32::to_str(u32_val), ~"4294967295");
+ assert_eq!(u32_val.to_str(), ~"4294967295");
u32_val += 1 as u32;
- assert_eq!(u32::to_str(u32_val), ~"0");
+ assert_eq!(u32_val.to_str(), ~"0");
let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
- assert_eq!(u64::to_str(u64_val), ~"18446744073709551615");
+ assert_eq!(u64_val.to_str(), ~"18446744073709551615");
u64_val += 1 as u64;
- assert_eq!(u64::to_str(u64_val), ~"0");
+ assert_eq!(u64_val.to_str(), ~"0");
}
#[test]
#[should_fail]
#[ignore(cfg(windows))]
pub fn to_str_radix1() {
- uint::to_str_radix(100u, 1u);
+ 100u.to_str_radix(1u);
}
#[test]
#[should_fail]
#[ignore(cfg(windows))]
pub fn to_str_radix37() {
- uint::to_str_radix(100u, 37u);
+ 100u.to_str_radix(37u);
}
#[test]
fn test_range_step_zero_step_down() {
do range_step(0,-10,0) |_i| { true };
}
+
+ #[test]
+ fn test_unsigned_checked_div() {
+ assert_eq!(10u.checked_div(&2), Some(5));
+ assert_eq!(5u.checked_div(&0), None);
+ }
}
}))
use ops::Add;
use util;
use num::Zero;
-use iterator::Iterator;
use iterator;
+use iterator::{Iterator, DoubleEndedIterator};
use str::{StrSlice, OwnedStr};
use to_str::ToStr;
use clone::DeepClone;
}
}
- /// Returns self or `Some(zero)` (for this type)
+ /// Returns self or `Some`-wrapped zero value
#[inline]
pub fn or_zero(self) -> Option<T> {
match self {
}
/// An iterator that yields either one or zero elements
+#[deriving(Clone, DeepClone)]
pub struct OptionIterator<A> {
priv opt: Option<A>
}
}
}
+impl<A> DoubleEndedIterator<A> for OptionIterator<A> {
+ #[inline]
+ fn next_back(&mut self) -> Option<A> {
+ self.opt.take()
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
/// Delegates to the libc close() function, returning the same return value.
pub fn close(fd: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::close(fd)
}
static BUF_BYTES : uint = 2048u;
pub fn getcwd() -> Path {
+ #[fixed_stack_segment]; #[inline(never)];
let mut buf = [0 as libc::c_char, ..BUF_BYTES];
do buf.as_mut_buf |buf, len| {
unsafe {
pub fn fill_utf16_buf_and_decode(f: &fn(*mut u16, DWORD) -> DWORD)
-> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut n = TMPBUF_SZ as DWORD;
let mut res = None;
}
}
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+ (fn $name:ident ()) => (
+ extern {
+ fn $name();
+ }
+ )
+)
+}
+
/*
Accessing environment variables is not generally threadsafe.
Serialize access through a global lock.
};
}
- extern {
- #[fast_ffi]
- fn rust_take_env_lock();
- #[fast_ffi]
- fn rust_drop_env_lock();
- }
+ externfn!(fn rust_take_env_lock());
+ externfn!(fn rust_drop_env_lock());
}
/// Returns a vector of (variable, value) pairs for all the environment
unsafe {
#[cfg(windows)]
unsafe fn get_env_pairs() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::funcs::extra::kernel32::{
GetEnvironmentStringsA,
FreeEnvironmentStringsA
}
#[cfg(unix)]
unsafe fn get_env_pairs() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
extern {
fn rust_env_pairs() -> **libc::c_char;
}
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
pub fn getenv(n: &str) -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
- let s = do n.to_c_str().with_ref |buf| {
+ let s = do n.with_c_str |buf| {
libc::getenv(buf)
};
if s.is_null() {
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
pub fn getenv(n: &str) -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do with_env_lock {
use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
pub fn setenv(n: &str, v: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
- do n.to_c_str().with_ref |nbuf| {
- do v.to_c_str().with_ref |vbuf| {
+ do n.with_c_str |nbuf| {
+ do v.with_c_str |vbuf| {
libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
}
}
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
pub fn setenv(n: &str, v: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do with_env_lock {
use os::win32::as_utf16_p;
pub fn unsetenv(n: &str) {
#[cfg(unix)]
fn _unsetenv(n: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
- do n.to_c_str().with_ref |nbuf| {
+ do n.with_c_str |nbuf| {
libc::funcs::posix01::unistd::unsetenv(nbuf);
}
}
}
#[cfg(windows)]
fn _unsetenv(n: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
use os::win32::as_utf16_p;
}
pub fn fdopen(fd: c_int) -> *FILE {
- do "r".to_c_str().with_ref |modebuf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do "r".with_c_str |modebuf| {
unsafe {
libc::fdopen(fd, modebuf)
}
#[cfg(windows)]
pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::extra::msvcrt::*;
return commit(fd);
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::posix01::unistd::*;
match level {
#[cfg(target_os = "macos")]
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
use libc::consts::os::extra::*;
use libc::funcs::posix88::fcntl::*;
#[cfg(target_os = "freebsd")]
pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
use libc::funcs::posix01::unistd::*;
return fsync(fd);
#[cfg(unix)]
pub fn pipe() -> Pipe {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
let mut fds = Pipe {input: 0 as c_int,
out: 0 as c_int };
#[cfg(windows)]
pub fn pipe() -> Pipe {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
// Windows pipes work subtly differently than unix pipes, and their
// inheritance has to be handled in a different way that I do not
// fully understand. Here we explicitly make the pipe non-inheritable,
// which means to pass it to a subprocess they need to be duplicated
- // first, as in core::run.
+ // first, as in std::run.
let mut fds = Pipe {input: 0 as c_int,
out: 0 as c_int };
let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
}
fn dup2(src: c_int, dst: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::dup2(src, dst)
}
#[cfg(target_os = "freebsd")]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::bsd44::*;
use libc::consts::os::extra::*;
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::posix01::unistd::readlink;
let mut path = [0 as c_char, .. TMPBUF_SZ];
do path.as_mut_buf |buf, len| {
- let len = do "/proc/self/exe".to_c_str().with_ref |proc_self_buf| {
+ let len = do "/proc/self/exe".with_c_str |proc_self_buf| {
readlink(proc_self_buf, buf, len as size_t) as uint
};
#[cfg(target_os = "macos")]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do fill_charp_buf() |buf, sz| {
let mut sz = sz as u32;
#[cfg(windows)]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::fill_utf16_buf_and_decode;
do fill_utf16_buf_and_decode() |buf, sz| {
/// Indicates whether a path represents a directory
pub fn path_is_dir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
- do p.to_c_str().with_ref |buf| {
+ do p.with_c_str |buf| {
rustrt::rust_path_is_dir(buf) != 0 as c_int
}
}
/// Indicates whether a path exists
pub fn path_exists(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
- do p.to_c_str().with_ref |buf| {
+ do p.with_c_str |buf| {
rustrt::rust_path_exists(buf) != 0 as c_int
}
}
#[cfg(windows)]
fn mkdir(p: &Path, _mode: c_int) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
// FIXME: turn mode into something useful? #2623
#[cfg(unix)]
fn mkdir(p: &Path, mode: c_int) -> bool {
- do p.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do p.with_c_str |buf| {
unsafe {
libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int)
}
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
unsafe fn get_list(p: &Path) -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::{dirent_t};
use libc::{opendir, readdir, closedir};
extern {
let mut strings = ~[];
debug!("os::list_dir -- BEFORE OPENDIR");
- let dir_ptr = do p.to_c_str().with_ref |buf| {
+ let dir_ptr = do p.with_c_str |buf| {
opendir(buf)
};
}
#[cfg(windows)]
unsafe fn get_list(p: &Path) -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::consts::os::extra::INVALID_HANDLE_VALUE;
use libc::{wcslen, free};
use libc::funcs::extra::kernel32::{
#[cfg(windows)]
fn rmdir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
#[cfg(unix)]
fn rmdir(p: &Path) -> bool {
- do p.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do p.with_c_str |buf| {
unsafe {
libc::rmdir(buf) == (0 as c_int)
}
#[cfg(windows)]
fn chdir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
#[cfg(unix)]
fn chdir(p: &Path) -> bool {
- do p.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do p.with_c_str |buf| {
unsafe {
libc::chdir(buf) == (0 as c_int)
}
#[cfg(windows)]
fn do_copy_file(from: &Path, to: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(from.to_str()) |fromp| {
#[cfg(unix)]
fn do_copy_file(from: &Path, to: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
- let istream = do from.to_c_str().with_ref |fromp| {
- do "rb".to_c_str().with_ref |modebuf| {
+ let istream = do from.with_c_str |fromp| {
+ do "rb".with_c_str |modebuf| {
libc::fopen(fromp, modebuf)
}
};
let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \
for source file");
- let ostream = do to.to_c_str().with_ref |top| {
- do "w+b".to_c_str().with_ref |modebuf| {
+ let ostream = do to.with_c_str |top| {
+ do "w+b".with_c_str |modebuf| {
libc::fopen(top, modebuf)
}
};
fclose(ostream);
// Give the new file the old file's permissions
- if do to.to_c_str().with_ref |to_buf| {
+ if do to.with_c_str |to_buf| {
libc::chmod(to_buf, from_mode as libc::mode_t)
} != 0 {
return false; // should be a condition...
#[cfg(windows)]
fn unlink(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
#[cfg(unix)]
fn unlink(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
- do p.to_c_str().with_ref |buf| {
+ do p.with_c_str |buf| {
libc::unlink(buf) == (0 as c_int)
}
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn errno_location() -> *c_int {
+ #[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __error() -> *c_int;
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn errno_location() -> *c_int {
+ #[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __errno_location() -> *c_int;
#[cfg(windows)]
/// Returns the platform-specific value of errno
pub fn errno() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
#[link_name = "kernel32"]
#[cfg(target_os = "freebsd")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
-> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
#[nolink]
extern {
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
// So we just use __xpg_strerror_r which is always POSIX compliant
#[cfg(target_os = "linux")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __xpg_strerror_r(errnum: c_int,
#[cfg(windows)]
fn strerror() -> ~str {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::types::os::arch::extra::DWORD;
use libc::types::os::arch::extra::LPSTR;
use libc::types::os::arch::extra::LPVOID;
*/
#[cfg(target_os = "macos")]
pub fn real_args() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let (argc, argv) = (*_NSGetArgc() as c_int,
*_NSGetArgv() as **c_char);
#[cfg(windows)]
pub fn real_args() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
let mut nArgs: c_int = 0;
let lpArgCount: *mut c_int = &mut nArgs;
let lpCmdLine = unsafe { GetCommandLineW() };
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
pub fn glob(pattern: &str) -> ~[Path] {
+ #[fixed_stack_segment]; #[inline(never)];
+
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn default_glob_t () -> libc::glob_t {
}
let mut g = default_glob_t();
- do pattern.to_c_str().with_ref |c_pattern| {
+ do pattern.with_c_str |c_pattern| {
unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) }
};
do(|| {
#[cfg(unix)]
pub fn page_size() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::sysconf(libc::_SC_PAGESIZE) as uint
}
#[cfg(windows)]
pub fn page_size() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut info = libc::SYSTEM_INFO::new();
libc::GetSystemInfo(&mut info);
#[cfg(unix)]
impl MemoryMap {
pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::off_t;
let mut addr: *c_void = ptr::null();
#[cfg(unix)]
impl Drop for MemoryMap {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
match libc::munmap(self.data as *c_void, self.len) {
0 => (),
#[cfg(windows)]
impl MemoryMap {
pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
let mut lpAddress: LPVOID = ptr::mut_null();
#[cfg(windows)]
impl Drop for MemoryMap {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::types::os::arch::extra::{LPCVOID, HANDLE};
unsafe {
#[test]
fn copy_file_ok() {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let tempdir = getcwd(); // would like to use $TMPDIR,
// doesn't seem to work on Linux
let out = tempdir.push("out.txt");
/* Write the temp input file */
- let ostream = do input.to_c_str().with_ref |fromp| {
- do "w+b".to_c_str().with_ref |modebuf| {
+ let ostream = do input.with_c_str |fromp| {
+ do "w+b".with_c_str |modebuf| {
libc::fopen(fromp, modebuf)
}
};
assert!((ostream as uint != 0u));
let s = ~"hello";
- do "hello".to_c_str().with_ref |buf| {
+ do "hello".with_c_str |buf| {
let write_len = libc::fwrite(buf as *c_void,
1u as size_t,
(s.len() + 1u) as size_t,
#[test]
fn memory_map_file() {
+ #[fixed_stack_segment]; #[inline(never)];
+
use result::{Ok, Err};
use os::*;
use libc::*;
#[cfg(unix)]
+ #[fixed_stack_segment]
+ #[inline(never)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
}
}
#[cfg(windows)]
+ #[fixed_stack_segment]
+ #[inline(never)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
remove_file(&path);
let fd = unsafe {
- let fd = do path.to_c_str().with_ref |path| {
+ let fd = do path.with_c_str |path| {
open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
};
lseek_(fd, size);
- do "x".to_c_str().with_ref |x| {
+ do "x".with_c_str |x| {
assert!(write(fd, x as *c_void, 1) == 1);
}
fd
#[cfg(target_os = "win32")]
impl WindowsPath {
pub fn stat(&self) -> Option<libc::stat> {
- do self.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::stat(buf, &mut st) } {
0 => Some(st),
#[cfg(not(target_os = "win32"))]
impl PosixPath {
pub fn stat(&self) -> Option<libc::stat> {
- do self.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::stat(buf as *libc::c_char, &mut st) } {
0 => Some(st),
#[cfg(unix)]
impl PosixPath {
pub fn lstat(&self) -> Option<libc::stat> {
- do self.to_c_str().with_ref |buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::lstat(buf, &mut st) } {
0 => Some(st),
fn to_c_str(&self) -> c_str::CString {
self.to_str().to_c_str()
}
+
+ unsafe fn to_c_str_unchecked(&self) -> c_str::CString {
+ self.to_str().to_c_str_unchecked()
+ }
}
// FIXME (#3227): when default methods in traits are working, de-duplicate
fn to_c_str(&self) -> c_str::CString {
self.to_str().to_c_str()
}
+
+ unsafe fn to_c_str_unchecked(&self) -> c_str::CString {
+ self.to_str().to_c_str_unchecked()
+ }
}
impl GenericPath for WindowsPath {
}
pub fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
if (s.len() > 1 &&
libc::isalpha(s[0] as libc::c_int) != 0 &&
pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
pub use hash::Hash;
pub use iter::Times;
-pub use iterator::Extendable;
-pub use iterator::{Iterator, DoubleEndedIterator};
-pub use iterator::{ClonableIterator, OrdIterator};
+pub use iterator::{FromIterator, Extendable};
+pub use iterator::{Iterator, DoubleEndedIterator, RandomAccessIterator, ClonableIterator};
+pub use iterator::{OrdIterator, MutableDoubleEndedIterator};
pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
pub use num::{Bitwise, BitCount, Bounded};
-pub use num::{Primitive, Int, Float};
+pub use num::{Primitive, Int, Float, ToStrRadix};
pub use path::GenericPath;
pub use path::Path;
pub use path::PosixPath;
pub use from_str::FromStr;
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
-pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
+pub use tuple::{CopyableTuple, ImmutableTuple};
pub use tuple::{CloneableTuple1, ImmutableTuple1};
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
}
impl<T> Clone for *T {
+ #[inline]
fn clone(&self) -> *T {
*self
}
passing to the provided callback function
SAFETY NOTE: This will only work with a null-terminated
- pointer array. Barely less-dodgey Pointer Arithmetic.
+ pointer array. Barely less-dodgy Pointer Arithmetic.
Dragons be here.
*/
pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) {
fn test_position() {
use libc::c_char;
- do "hello".to_c_str().with_ref |p| {
+ do "hello".with_c_str |p| {
unsafe {
assert!(2u == position(p, |c| *c == 'l' as c_char));
assert!(4u == position(p, |c| *c == 'o' as c_char));
#[test]
fn test_buf_len() {
- do "hello".to_c_str().with_ref |p0| {
- do "there".to_c_str().with_ref |p1| {
- do "thing".to_c_str().with_ref |p2| {
+ do "hello".with_c_str |p0| {
+ do "there".with_c_str |p1| {
+ do "thing".with_c_str |p2| {
let v = ~[p0, p1, p2, null()];
do v.as_imm_buf |vp, len| {
assert_eq!(unsafe { buf_len(vp) }, 3u);
one, two, three
];
- do arr.as_imm_buf |arr_ptr, arr_len| {
+ do arr.as_imm_buf |arr_ptr, _| {
let mut ctr = 0;
let mut iteration_count = 0;
do array_each(arr_ptr) |e| {
* ~~~
*/
fn shuffle_mut<T>(&mut self, values: &mut [T]);
+
+ /**
+ * Sample up to `n` values from an iterator.
+ *
+ * # Example
+ *
+ * ~~~ {.rust}
+ *
+ * use std::rand;
+ * use std::rand::RngUtil;
+ *
+ * fn main() {
+ * let mut rng = rand::rng();
+ * let vals = range(1, 100).to_owned_vec();
+ * let sample = rng.sample(vals.iter(), 5);
+ * printfln!(sample);
+ * }
+ * ~~~
+ */
+ fn sample<A, T: Iterator<A>>(&mut self, iter: T, n: uint) -> ~[A];
}
/// Extension methods for random number generators
values.swap(i, self.gen_uint_range(0u, i + 1u));
}
}
+
+ /// Randomly sample up to `n` elements from an iterator
+ fn sample<A, T: Iterator<A>>(&mut self, iter: T, n: uint) -> ~[A] {
+ let mut reservoir : ~[A] = vec::with_capacity(n);
+ for (i, elem) in iter.enumerate() {
+ if i < n {
+ reservoir.push(elem);
+ loop
+ }
+
+ let k = self.gen_uint_range(0, i + 1);
+ if k < reservoir.len() {
+ reservoir[k] = elem
+ }
+ }
+ reservoir
+ }
}
/// Create a random number generator with a default algorithm and seed.
/// Create a weak random number generator with a default algorithm and seed.
///
-/// It returns the fatest `Rng` algorithm currently available in Rust without
+/// It returns the fastest `Rng` algorithm currently available in Rust without
/// consideration for cryptography or security. If you require a specifically
/// seeded `Rng` for consistency over time you should pick one algorithm and
/// create the `Rng` yourself.
}
impl XorShiftRng {
- /// Create an xor shift random number generator with a default seed.
+ /// Create an xor shift random number generator with a random seed.
pub fn new() -> XorShiftRng {
- // constants taken from http://en.wikipedia.org/wiki/Xorshift
- XorShiftRng::new_seeded(123456789u32,
- 362436069u32,
- 521288629u32,
- 88675123u32)
+ #[fixed_stack_segment]; #[inline(never)];
+
+ // generate seeds the same way as seed(), except we have a spceific size
+ let mut s = [0u8, ..16];
+ loop {
+ do s.as_mut_buf |p, sz| {
+ unsafe {
+ rustrt::rand_gen_seed(p, sz as size_t);
+ }
+ }
+ if !s.iter().all(|x| *x == 0) {
+ break;
+ }
+ }
+ let s: &[u32, ..4] = unsafe { cast::transmute(&s) };
+ XorShiftRng::new_seeded(s[0], s[1], s[2], s[3])
}
/**
/// Create a new random seed.
pub fn seed() -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let n = rustrt::rand_seed_size() as uint;
let mut s = vec::from_elem(n, 0_u8);
#[cfg(test)]
mod test {
+ use iterator::{Iterator, range};
use option::{Option, Some};
use super::*;
#[test]
fn compare_isaac_implementation() {
+ #[fixed_stack_segment]; #[inline(never)];
+
// This is to verify that the implementation of the ISAAC rng is
// correct (i.e. matches the output of the upstream implementation,
// which is in the runtime)
}
}
}
+
+ #[test]
+ fn test_sample() {
+ let MIN_VAL = 1;
+ let MAX_VAL = 100;
+
+ let mut r = rng();
+ let vals = range(MIN_VAL, MAX_VAL).to_owned_vec();
+ let small_sample = r.sample(vals.iter(), 5);
+ let large_sample = r.sample(vals.iter(), vals.len() + 5);
+
+ assert_eq!(small_sample.len(), 5);
+ assert_eq!(large_sample.len(), vals.len());
+
+ assert!(small_sample.iter().all(|e| {
+ **e >= MIN_VAL && **e <= MAX_VAL
+ }));
+ }
}
#[cfg(test)]
/// # Example
///
/// ~~~
-/// use core::rand::distributions::StandardNormal;
+/// use std::rand::distributions::StandardNormal;
///
/// fn main() {
/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0;
/// # Example
///
/// ~~~
-/// use core::rand::distributions::Exp1;
+/// use std::rand::distributions::Exp1;
///
/// fn main() {
/// let exp2 = (*rand::random::<Exp1>()) * 0.5;
use iterator::Iterator;
use option::{None, Option, Some, OptionIterator};
use vec;
-use vec::{OwnedVector, ImmutableVector};
-use container::Container;
+use vec::OwnedVector;
use to_str::ToStr;
use str::StrSlice;
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
///
-/// In order to provide informative error messages, `E` is reqired to implement `ToStr`.
+/// In order to provide informative error messages, `E` is required to implement `ToStr`.
/// It is further recommended for `E` to be a descriptive error type, eg a `enum` for
/// all possible errors cases.
#[deriving(Clone, Eq)]
}
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Maps each element in the vector `ts` using the operation `op`. Should an
-/// error occur, no further mappings are performed and the error is returned.
-/// Should no error occur, a vector containing the result of each map is
-/// returned.
+/// Takes each element in the iterator: if it is an error, no further
+/// elements are taken, and the error is returned.
+/// Should no error occur, a vector containing the values of each Result
+/// is returned.
///
/// Here is an example which increments every integer in a vector,
/// checking for overflow:
///
-/// fn inc_conditionally(x: uint) -> result<uint,str> {
+/// fn inc_conditionally(x: uint) -> Result<uint, &'static str> {
/// if x == uint::max_value { return Err("overflow"); }
/// else { return Ok(x+1u); }
/// }
-/// map(~[1u, 2u, 3u], inc_conditionally).chain {|incd|
-/// assert!(incd == ~[2u, 3u, 4u]);
-/// }
+/// let v = [1u, 2, 3];
+/// let res = collect(v.iter().map(|&x| inc_conditionally(x)));
+/// assert!(res == Ok(~[2u, 3, 4]));
#[inline]
-pub fn map_vec<T,U,V>(ts: &[T], op: &fn(&T) -> Result<V,U>)
- -> Result<~[V],U> {
- let mut vs: ~[V] = vec::with_capacity(ts.len());
- for t in ts.iter() {
- match op(t) {
- Ok(v) => vs.push(v),
- Err(u) => return Err(u)
+pub fn collect<T, E, Iter: Iterator<Result<T, E>>>(mut iterator: Iter)
+ -> Result<~[T], E> {
+ let (lower, _) = iterator.size_hint();
+ let mut vs: ~[T] = vec::with_capacity(lower);
+ for t in iterator {
+ match t {
+ Ok(v) => vs.push(v),
+ Err(u) => return Err(u)
}
}
- return Ok(vs);
+ Ok(vs)
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Same as map, but it operates over two parallel vectors.
+/// Perform a fold operation over the result values from an iterator.
///
-/// A precondition is used here to ensure that the vectors are the same
-/// length. While we do not often use preconditions in the standard
-/// library, a precondition is used here because result::t is generally
-/// used in 'careful' code contexts where it is both appropriate and easy
-/// to accommodate an error like the vectors being of different lengths.
+/// If an `Err` is encountered, it is immediately returned.
+/// Otherwise, the folded value is returned.
#[inline]
-pub fn map_vec2<S, T, U: ToStr, V>(ss: &[S], ts: &[T],
- op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> {
- assert!(vec::same_length(ss, ts));
- let n = ts.len();
- let mut vs = vec::with_capacity(n);
- let mut i = 0u;
- while i < n {
- match op(&ss[i],&ts[i]) {
- Ok(v) => vs.push(v),
- Err(u) => return Err(u)
+pub fn fold<T, V, E,
+ Iter: Iterator<Result<T, E>>>(
+ mut iterator: Iter,
+ mut init: V,
+ f: &fn(V, T) -> V)
+ -> Result<V, E> {
+ for t in iterator {
+ match t {
+ Ok(v) => init = f(init, v),
+ Err(u) => return Err(u)
}
- i += 1u;
}
- return Ok(vs);
+ Ok(init)
}
-// FIXME: #8228 Replaceable by an external iterator?
-/// Applies op to the pairwise elements from `ss` and `ts`, aborting on
-/// error. This could be implemented using `map_zip()` but it is more efficient
-/// on its own as no result vector is built.
+/// Perform a trivial fold operation over the result values
+/// from an iterator.
+///
+/// If an `Err` is encountered, it is immediately returned.
+/// Otherwise, a simple `Ok(())` is returned.
#[inline]
-pub fn iter_vec2<S, T, U: ToStr>(ss: &[S], ts: &[T],
- op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> {
- assert!(vec::same_length(ss, ts));
- let n = ts.len();
- let mut i = 0u;
- while i < n {
- match op(&ss[i],&ts[i]) {
- Ok(()) => (),
- Err(u) => return Err(u)
- }
- i += 1u;
- }
- return Ok(());
+pub fn fold_<T, E, Iter: Iterator<Result<T, E>>>(
+ iterator: Iter)
+ -> Result<(), E> {
+ fold(iterator, (), |_, _| ())
}
+
#[cfg(test)]
mod tests {
use super::*;
use either;
+ use iterator::range;
use str::OwnedStr;
+ use vec::ImmutableVector;
pub fn op1() -> Result<int, ~str> { Ok(666) }
assert_eq!(r.to_either(), either::Right(100));
assert_eq!(err.to_either(), either::Left(404));
}
+
+ #[test]
+ fn test_collect() {
+ assert_eq!(collect(range(0, 0)
+ .map(|_| Ok::<int, ()>(0))),
+ Ok(~[]));
+ assert_eq!(collect(range(0, 3)
+ .map(|x| Ok::<int, ()>(x))),
+ Ok(~[0, 1, 2]));
+ assert_eq!(collect(range(0, 3)
+ .map(|x| if x > 1 { Err(x) } else { Ok(x) })),
+ Err(2));
+
+ // test that it does not take more elements than it needs
+ let functions = [|| Ok(()), || Err(1), || fail!()];
+
+ assert_eq!(collect(functions.iter().map(|f| (*f)())),
+ Err(1));
+ }
+
+ #[test]
+ fn test_fold() {
+ assert_eq!(fold_(range(0, 0)
+ .map(|_| Ok::<(), ()>(()))),
+ Ok(()));
+ assert_eq!(fold(range(0, 3)
+ .map(|x| Ok::<int, ()>(x)),
+ 0, |a, b| a + b),
+ Ok(3));
+ assert_eq!(fold_(range(0, 3)
+ .map(|x| if x > 1 { Err(x) } else { Ok(()) })),
+ Err(2));
+
+ // test that it does not take more elements than it needs
+ let functions = [|| Ok(()), || Err(1), || fail!()];
+
+ assert_eq!(fold_(functions.iter()
+ .map(|f| (*f)())),
+ Err(1));
+ }
}
args
}
- extern {
- fn rust_take_global_args_lock();
- fn rust_drop_global_args_lock();
- fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>;
+ #[cfg(stage0)]
+ mod macro_hack {
+ #[macro_escape];
+ macro_rules! externfn(
+ (fn $name:ident () $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ )
+ )
}
+ externfn!(fn rust_take_global_args_lock())
+ externfn!(fn rust_drop_global_args_lock())
+ externfn!(fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>)
+
#[cfg(test)]
mod tests {
use option::{Some, None};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use cell::Cell;
use c_str::ToCStr;
use cast::transmute;
use libc::{c_char, size_t, STDERR_FILENO};
use io::{Writer, WriterUtil};
use option::{Option, None, Some};
use uint;
+use rt::env;
+use rt::local::Local;
+use rt::task::Task;
use str;
use str::{OwnedStr, StrSlice};
use sys;
static ALL_BITS: uint = FROZEN_BIT | MUT_BIT;
#[deriving(Eq)]
-struct BorrowRecord {
+pub struct BorrowRecord {
box: *mut raw::Box<()>,
file: *c_char,
line: size_t
}
fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {
- // XXX
- None
+ do Local::borrow::<Task, Option<~[BorrowRecord]>> |task| {
+ task.borrow_list.take()
+ }
}
-fn swap_task_borrow_list(_f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) {
- // XXX
+fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) {
+ let borrows = match try_take_task_borrow_list() {
+ Some(l) => l,
+ None => ~[]
+ };
+ let borrows = f(borrows);
+ let borrows = Cell::new(borrows);
+ do Local::borrow::<Task, ()> |task| {
+ task.borrow_list = Some(borrows.take());
+ }
}
-pub unsafe fn clear_task_borrow_list() {
+pub fn clear_task_borrow_list() {
// pub because it is used by the box annihilator.
let _ = try_take_task_borrow_list();
}
match try_take_task_borrow_list() {
None => { // not recording borrows
let msg = "borrowed";
- do msg.to_c_str().with_ref |msg_p| {
+ do msg.with_c_str |msg_p| {
sys::begin_unwind_(msg_p, file, line);
}
}
sep = " and at ";
}
}
- do msg.to_c_str().with_ref |msg_p| {
+ do msg.with_c_str |msg_p| {
sys::begin_unwind_(msg_p, file, line)
}
}
//! A useful debugging function that prints a pointer + tag + newline
//! without allocating memory.
- // XXX
- if false {
+ if ENABLE_DEBUG && env::debug_borrow() {
debug_borrow_slow(tag, p, old_bits, new_bits, filename, line);
}
}
unsafe fn write_cstr(&self, p: *c_char) {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::strlen;
use vec;
let br = borrow_list.pop();
if br.box != a || br.file != file || br.line != line {
let err = fmt!("wrong borrow found, br=%?", br);
- do err.to_c_str().with_ref |msg_p| {
+ do err.with_c_str |msg_p| {
sys::begin_unwind_(msg_p, file, line)
}
}
use rt::test::*;
use cell::Cell;
use iter::Times;
+ use rt::util;
#[test]
fn oneshot_single_thread_close_port_first() {
#[test]
fn oneshot_multi_thread_close_stress() {
+ if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
do stress_factor().times {
do run_in_newsched_task {
let (port, chan) = oneshot::<int>();
#[test]
fn oneshot_multi_thread_send_close_stress() {
+ if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
do stress_factor().times {
do run_in_newsched_task {
let (port, chan) = oneshot::<int>();
#[test]
fn oneshot_multi_thread_recv_close_stress() {
+ if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
do stress_factor().times {
do run_in_newsched_task {
let (port, chan) = oneshot::<int>();
#[test]
fn oneshot_multi_thread_send_recv_stress() {
+ if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
do stress_factor().times {
do run_in_newsched_task {
let (port, chan) = oneshot::<~int>();
#[test]
fn stream_send_recv_stress() {
+ if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
do stress_factor().times {
do run_in_mt_newsched_task {
let (port, chan) = stream::<~int>();
#[test]
fn shared_chan_stress() {
+ if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
do run_in_mt_newsched_task {
let (port, chan) = stream();
let chan = SharedChan::new(chan);
#[test]
fn shared_port_stress() {
+ if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
do run_in_mt_newsched_task {
// XXX: Removing these type annotations causes an ICE
let (end_port, end_chan) = stream::<()>();
use rand;
use rand::RngUtil;
+ if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
+
do run_in_mt_newsched_task {
let (end_port, end_chan) = stream::<()>();
let end_chan = SharedChan::new(end_chan);
// They are expected to be initialized once then left alone.
static mut MIN_STACK: uint = 2000000;
+static mut DEBUG_BORROW: bool = false;
pub fn init() {
unsafe {
},
None => ()
}
+ match os::getenv("RUST_DEBUG_BORROW") {
+ Some(_) => DEBUG_BORROW = true,
+ None => ()
+ }
}
}
pub fn min_stack() -> uint {
unsafe { MIN_STACK }
}
+
+pub fn debug_borrow() -> bool {
+ unsafe { DEBUG_BORROW }
+}
}
/// A wrapper around libc::malloc, aborting on out-of-memory
-#[inline]
pub unsafe fn malloc_raw(size: uint) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
let p = malloc(size as size_t);
if p.is_null() {
// we need a non-allocating way to print an error here
}
/// A wrapper around libc::realloc, aborting on out-of-memory
-#[inline]
pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
let p = realloc(ptr, size as size_t);
if p.is_null() {
// we need a non-allocating way to print an error here
exchange_free(ptr)
}
-#[inline]
pub unsafe fn exchange_free(ptr: *c_char) {
+ #[fixed_stack_segment]; #[inline(never)];
+
free(ptr as *c_void);
}
/// (8 bytes).
fn write_le_f64(&mut self, f: f64);
- /// Write a litten-endian IEEE754 single-precision floating-point
+ /// Write a little-endian IEEE754 single-precision floating-point
/// (4 bytes).
fn write_le_f32(&mut self, f: f32);
Readers and Writers may be composed to add capabilities like string
parsing, encoding, and compression.
-This will likely live in core::io, not core::rt::io.
+This will likely live in std::io, not std::rt::io.
# Examples
(continuation-passing) style popularised by node.js. Such systems rely
on all computations being run inside an event loop which maintains a
list of all pending I/O events; when one completes the registered
-callback is run and the code that made the I/O request continiues.
+callback is run and the code that made the I/O request continues.
Such interfaces achieve non-blocking at the expense of being more
difficult to reason about.
while still providing feedback about errors. The basic strategy:
* Errors are fatal by default, resulting in task failure
-* Errors raise the `io_error` conditon which provides an opportunity to inspect
+* Errors raise the `io_error` condition which provides an opportunity to inspect
an IoError object containing details.
* Return values must have a sensible null or zero value which is returned
if a condition is handled successfully. This may be an `Option`, an empty
* XXX: How should we use condition handlers that return values?
* XXX: Should EOF raise default conditions when EOF is not an error?
-# Issues withi/o scheduler affinity, work stealing, task pinning
+# Issues with i/o scheduler affinity, work stealing, task pinning
# Resource management
pub mod ip;
#[cfg(unix)]
pub mod unix;
- pub mod http;
}
/// Readers and Writers for memory buffers and strings.
/// println(reader.read_line());
/// }
///
- /// # Failue
+ /// # Failure
///
/// Returns `true` on failure.
fn eof(&mut self) -> bool;
+++ /dev/null
-// 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.
-
-//! Simple HTTP client and server
-
-// XXX This should not be in core
-
-struct HttpServer;
-
-#[cfg(test)]
-mod test {
- use unstable::run_in_bare_thread;
-
- #[test] #[ignore]
- fn smoke_test() {
- do run_in_bare_thread {
- }
-
- do run_in_bare_thread {
- }
- }
-}
type Port = u16;
-#[deriving(Eq, TotalEq)]
+#[deriving(Eq, TotalEq, Clone)]
pub enum IpAddr {
Ipv4Addr(u8, u8, u8, u8),
Ipv6Addr(u16, u16, u16, u16, u16, u16, u16, u16)
}
}
-#[deriving(Eq, TotalEq)]
+#[deriving(Eq, TotalEq, Clone)]
pub struct SocketAddr {
ip: IpAddr,
port: Port,
fn write(&mut self, buf: &[u8]) {
match (**self).write(buf) {
Ok(_) => (),
- Err(ioerr) => {
- io_error::cond.raise(ioerr);
- }
+ Err(ioerr) => io_error::cond.raise(ioerr),
}
}
impl Listener<TcpStream> for TcpListener {
fn accept(&mut self) -> Option<TcpStream> {
match (**self).accept() {
- Ok(s) => {
- Some(TcpStream::new(s))
- }
+ Ok(s) => Some(TcpStream::new(s)),
Err(ioerr) => {
io_error::cond.raise(ioerr);
return None;
}
impl RtioTimer for Timer {
- fn sleep(&self, msecs: u64) {
+ fn sleep(&mut self, msecs: u64) {
(**self).sleep(msecs);
}
}
mod test {
use super::*;
use rt::test::*;
- use option::{Some, None};
#[test]
fn test_io_timer_sleep_simple() {
do run_in_newsched_task {
let timer = Timer::new();
- match timer {
- Some(t) => t.sleep(1),
- None => assert!(false)
- }
+ do timer.map_move |mut t| { t.sleep(1) };
}
}
-}
\ No newline at end of file
+}
on_exit: Option<~fn(bool)>,
// nesting level counter for task::unkillable calls (0 == killable).
unkillable: int,
- // nesting level counter for unstable::atomically calls (0 == can yield).
+ // nesting level counter for unstable::atomically calls (0 == can deschedule).
wont_sleep: int,
// A "spare" handle to the kill flag inside the kill handle. Used during
// blocking/waking as an optimization to avoid two xadds on the refcount.
}
/// Enter a possibly-nested "atomic" section of code. Just for assertions.
- /// All calls must be paired with a subsequent call to allow_yield.
+ /// All calls must be paired with a subsequent call to allow_deschedule.
#[inline]
- pub fn inhibit_yield(&mut self) {
+ pub fn inhibit_deschedule(&mut self) {
self.wont_sleep += 1;
}
/// Exit a possibly-nested "atomic" section of code. Just for assertions.
- /// All calls must be paired with a preceding call to inhibit_yield.
+ /// All calls must be paired with a preceding call to inhibit_deschedule.
#[inline]
- pub fn allow_yield(&mut self) {
+ pub fn allow_deschedule(&mut self) {
rtassert!(self.wont_sleep != 0);
self.wont_sleep -= 1;
}
}
impl LocalHeap {
+ #[fixed_stack_segment] #[inline(never)]
pub fn new() -> LocalHeap {
unsafe {
// Don't need synchronization for the single-threaded local heap
}
}
+ #[fixed_stack_segment] #[inline(never)]
pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox {
unsafe {
return rust_boxed_region_malloc(self.boxed_region, td, size as size_t);
}
}
+ #[fixed_stack_segment] #[inline(never)]
pub fn realloc(&mut self, ptr: *OpaqueBox, size: uint) -> *OpaqueBox {
unsafe {
return rust_boxed_region_realloc(self.boxed_region, ptr, size as size_t);
}
}
+ #[fixed_stack_segment] #[inline(never)]
pub fn free(&mut self, box: *OpaqueBox) {
unsafe {
return rust_boxed_region_free(self.boxed_region, box);
}
impl Drop for LocalHeap {
+ #[fixed_stack_segment] #[inline(never)]
fn drop(&self) {
unsafe {
rust_delete_boxed_region(self.boxed_region);
use tls = rt::thread_local_storage;
/// Initialize the TLS key. Other ops will fail if this isn't executed first.
+#[fixed_stack_segment]
+#[inline(never)]
pub fn init_tls_key() {
unsafe {
rust_initialize_rt_tls_key();
}
}
+#[fixed_stack_segment]
+#[inline(never)]
fn maybe_tls_key() -> Option<tls::Key> {
unsafe {
let key: *mut c_void = rust_get_rt_tls_key();
}
extern {
- #[fast_ffi]
fn rust_get_rt_tls_key() -> *mut c_void;
}
-
}
};
// Truncate the string
- let buf_bytes = 256;
+ let buf_bytes = 2048;
if s.len() > buf_bytes {
let s = s.slice(0, buf_bytes) + "[...]";
print(s);
/// Configure logging by traversing the crate map and setting the
/// per-module global logging flags based on the logging spec
+#[fixed_stack_segment] #[inline(never)]
pub fn init(crate_map: *u8) {
use c_str::ToCStr;
use os;
let log_spec = os::getenv("RUST_LOG");
match log_spec {
Some(spec) => {
- do spec.to_c_str().with_ref |buf| {
+ do spec.with_c_str |buf| {
unsafe { rust_update_log_settings(crate_map, buf) }
}
}
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn console_on() { unsafe { rust_log_console_on() } }
+
+#[fixed_stack_segment] #[inline(never)]
pub fn console_off() { unsafe { rust_log_console_off() } }
+
+#[fixed_stack_segment] #[inline(never)]
fn should_log_console() -> bool { unsafe { rust_should_log_console() != 0 } }
extern {
Several modules in `core` are clients of `rt`:
-* `core::task` - The user-facing interface to the Rust task model.
-* `core::task::local_data` - The interface to local data.
-* `core::gc` - The garbage collector.
-* `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`.
-* `core::condition` - Uses local data.
-* `core::cleanup` - Local heap destruction.
-* `core::io` - In the future `core::io` will use an `rt` implementation.
-* `core::logging`
-* `core::pipes`
-* `core::comm`
-* `core::stackwalk`
+* `std::task` - The user-facing interface to the Rust task model.
+* `std::task::local_data` - The interface to local data.
+* `std::gc` - The garbage collector.
+* `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`.
+* `std::condition` - Uses local data.
+* `std::cleanup` - Local heap destruction.
+* `std::io` - In the future `std::io` will use an `rt` implementation.
+* `std::logging`
+* `std::pipes`
+* `std::comm`
+* `std::stackwalk`
*/
/// scheduler and task context
pub mod tube;
-/// Simple reimplementation of core::comm
+/// Simple reimplementation of std::comm
pub mod comm;
mod select;
return exit_code;
}
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ )
+)
+}
+
/// One-time runtime initialization.
///
/// Initializes global state, including frobbing
rust_update_gc_metadata(crate_map);
}
- extern {
- fn rust_update_gc_metadata(crate_map: *u8);
- }
+ externfn!(fn rust_update_gc_metadata(crate_map: *u8));
}
/// One-time runtime cleanup.
pub type RtioTcpListenerObject = uvio::UvTcpListener;
pub type RtioUdpSocketObject = uvio::UvUdpSocket;
pub type RtioTimerObject = uvio::UvTimer;
+pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback;
pub trait EventLoop {
fn run(&mut self);
fn callback(&mut self, ~fn());
+ fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback;
fn callback_ms(&mut self, ms: u64, ~fn());
fn remote_callback(&mut self, ~fn()) -> ~RemoteCallbackObject;
/// The asynchronous I/O services. Not all event loops may provide one
}
pub trait RemoteCallback {
- /// Trigger the remote callback. Note that the number of times the callback
- /// is run is not guaranteed. All that is guaranteed is that, after calling 'fire',
- /// the callback will be called at least once, but multiple callbacks may be coalesced
- /// and callbacks may be called more often requested. Destruction also triggers the
- /// callback.
+ /// Trigger the remote callback. Note that the number of times the
+ /// callback is run is not guaranteed. All that is guaranteed is
+ /// that, after calling 'fire', the callback will be called at
+ /// least once, but multiple callbacks may be coalesced and
+ /// callbacks may be called more often requested. Destruction also
+ /// triggers the callback.
fn fire(&mut self);
}
}
pub trait RtioTimer {
- fn sleep(&self, msecs: u64);
+ fn sleep(&mut self, msecs: u64);
}
use rt::kill::BlockedTask;
use rt::local_ptr;
use rt::local::Local;
-use rt::rtio::RemoteCallback;
+use rt::rtio::{RemoteCallback, PausibleIdleCallback};
use rt::metrics::SchedMetrics;
use borrow::{to_uint};
use cell::Cell;
use iterator::{range};
use vec::{OwnedVector};
-/// The Scheduler is responsible for coordinating execution of Coroutines
-/// on a single thread. When the scheduler is running it is owned by
-/// thread local storage and the running task is owned by the
-/// scheduler.
+/// A scheduler is responsible for coordinating the execution of Tasks
+/// on a single thread. The scheduler runs inside a slightly modified
+/// Rust Task. When not running this task is stored in the scheduler
+/// struct. The scheduler struct acts like a baton, all scheduling
+/// actions are transfers of the baton.
///
/// XXX: This creates too many callbacks to run_sched_once, resulting
/// in too much allocation and too many events.
stack_pool: StackPool,
/// The event loop used to drive the scheduler and perform I/O
event_loop: ~EventLoopObject,
- /// The scheduler runs on a special task.
+ /// The scheduler runs on a special task. When it is not running
+ /// it is stored here instead of the work queue.
sched_task: Option<~Task>,
/// An action performed after a context switch on behalf of the
/// code running before the context switch
- priv cleanup_job: Option<CleanupJob>,
+ cleanup_job: Option<CleanupJob>,
metrics: SchedMetrics,
/// Should this scheduler run any task, or only pinned tasks?
run_anything: bool,
/// them to.
friend_handle: Option<SchedHandle>,
/// A fast XorShift rng for scheduler use
- rng: XorShiftRng
-
-}
-
-pub struct SchedHandle {
- priv remote: ~RemoteCallbackObject,
- priv queue: MessageQueue<SchedMessage>,
- sched_id: uint
-}
-
-pub enum SchedMessage {
- Wake,
- Shutdown,
- PinnedTask(~Task),
- TaskFromFriend(~Task)
-}
-
-enum CleanupJob {
- DoNothing,
- GiveTask(~Task, UnsafeTaskReceiver)
+ rng: XorShiftRng,
+ /// A toggleable idle callback
+ idle_callback: Option<~PausibleIdleCallback>
}
impl Scheduler {
- pub fn sched_id(&self) -> uint { to_uint(self) }
+ // * Initialization Functions
pub fn new(event_loop: ~EventLoopObject,
work_queue: WorkQueue<~Task>,
}
- // When you create a scheduler it isn't yet "in" a task, so the
- // task field is None.
pub fn new_special(event_loop: ~EventLoopObject,
work_queue: WorkQueue<~Task>,
work_queues: ~[WorkQueue<~Task>],
metrics: SchedMetrics::new(),
run_anything: run_anything,
friend_handle: friend,
- rng: XorShiftRng::new()
+ rng: XorShiftRng::new(),
+ idle_callback: None
}
}
// scheduler task and bootstrap into it.
pub fn bootstrap(~self, task: ~Task) {
+ let mut this = self;
+
+ // Build an Idle callback.
+ this.idle_callback = Some(this.event_loop.pausible_idle_callback());
+
// Initialize the TLS key.
local_ptr::init_tls_key();
// task, put it in TLS.
Local::put::(sched_task);
+ // Before starting our first task, make sure the idle callback
+ // is active. As we do not start in the sleep state this is
+ // important.
+ this.idle_callback.get_mut_ref().start(Scheduler::run_sched_once);
+
// Now, as far as all the scheduler state is concerned, we are
// inside the "scheduler" context. So we can act like the
// scheduler and resume the provided task.
- self.resume_task_immediately(task);
+ this.resume_task_immediately(task);
// Now we are back in the scheduler context, having
// successfully run the input task. Start by running the
let sched = Local::take::<Scheduler>();
rtdebug!("starting scheduler %u", sched.sched_id());
+ sched.run();
+ // Close the idle callback.
+ let mut sched = Local::take::<Scheduler>();
+ sched.idle_callback.get_mut_ref().close();
+ // Make one go through the loop to run the close callback.
sched.run();
// Now that we are done with the scheduler, clean up the
let mut self_sched = self;
- // Always run through the scheduler loop at least once so that
- // we enter the sleep state and can then be woken up by other
- // schedulers.
- self_sched.event_loop.callback(Scheduler::run_sched_once);
-
// This is unsafe because we need to place the scheduler, with
// the event_loop inside, inside our task. But we still need a
// mutable reference to the event_loop to give it the "run"
}
}
- // One iteration of the scheduler loop, always run at least once.
+ // * Execution Functions - Core Loop Logic
// The model for this function is that you continue through it
// until you either use the scheduler while performing a schedule
- // action, in which case you give it away and do not return, or
+ // action, in which case you give it away and return early, or
// you reach the end and sleep. In the case that a scheduler
// action is performed the loop is evented such that this function
// is called again.
// already have a scheduler stored in our local task, so we
// start off by taking it. This is the only path through the
// scheduler where we get the scheduler this way.
- let sched = Local::take::<Scheduler>();
+ let mut sched = Local::take::<Scheduler>();
- // Our first task is to read mail to see if we have important
- // messages.
-
- // 1) A wake message is easy, mutate sched struct and return
- // it.
- // 2) A shutdown is also easy, shutdown.
- // 3) A pinned task - we resume immediately and do not return
- // here.
- // 4) A message from another scheduler with a non-homed task
- // to run here.
-
- let result = sched.interpret_message_queue();
- let sched = match result {
- Some(sched) => {
- // We did not resume a task, so we returned.
- sched
- }
- None => {
- return;
- }
- };
+ // Assume that we need to continue idling unless we reach the
+ // end of this function without performing an action.
+ sched.idle_callback.get_mut_ref().resume();
- // Second activity is to try resuming a task from the queue.
+ // First we check for scheduler messages, these are higher
+ // priority than regular tasks.
+ let sched = match sched.interpret_message_queue() {
+ Some(sched) => sched,
+ None => return
+ };
- let result = sched.do_work();
- let mut sched = match result {
- Some(sched) => {
- // Failed to dequeue a task, so we return.
- sched
- }
- None => {
- return;
- }
+ // This helper will use a randomized work-stealing algorithm
+ // to find work.
+ let mut sched = match sched.do_work() {
+ Some(sched) => sched,
+ None => return
};
// If we got here then there was no work to do.
sched.sleepy = true;
let handle = sched.make_handle();
sched.sleeper_list.push(handle);
+ // Since we are sleeping, deactivate the idle callback.
+ sched.idle_callback.get_mut_ref().pause();
} else {
rtdebug!("not sleeping, already doing so or no_sleep set");
+ // We may not be sleeping, but we still need to deactivate
+ // the idle callback.
+ sched.idle_callback.get_mut_ref().pause();
}
// Finished a cycle without using the Scheduler. Place it back
Local::put(sched);
}
- pub fn make_handle(&mut self) -> SchedHandle {
- let remote = self.event_loop.remote_callback(Scheduler::run_sched_once);
-
- return SchedHandle {
- remote: remote,
- queue: self.message_queue.clone(),
- sched_id: self.sched_id()
- };
- }
-
- /// Schedule a task to be executed later.
- ///
- /// Pushes the task onto the work stealing queue and tells the
- /// event loop to run it later. Always use this instead of pushing
- /// to the work queue directly.
- pub fn enqueue_task(&mut self, task: ~Task) {
-
- let this = self;
-
- // We push the task onto our local queue clone.
- this.work_queue.push(task);
- this.event_loop.callback(Scheduler::run_sched_once);
-
- // We've made work available. Notify a
- // sleeping scheduler.
-
- // XXX: perf. Check for a sleeper without
- // synchronizing memory. It's not critical
- // that we always find it.
-
- // XXX: perf. If there's a sleeper then we
- // might as well just send it the task
- // directly instead of pushing it to the
- // queue. That is essentially the intent here
- // and it is less work.
- match this.sleeper_list.pop() {
- Some(handle) => {
- let mut handle = handle;
- handle.send(Wake)
- }
- None => { (/* pass */) }
- };
- }
-
- /// As enqueue_task, but with the possibility for the blocked task to
- /// already have been killed.
- pub fn enqueue_blocked_task(&mut self, blocked_task: BlockedTask) {
- do blocked_task.wake().map_move |task| {
- self.enqueue_task(task);
- };
- }
-
- // * Scheduler-context operations
-
// This function returns None if the scheduler is "used", or it
- // returns the still-available scheduler.
+ // returns the still-available scheduler. At this point all
+ // message-handling will count as a turn of work, and as a result
+ // return None.
fn interpret_message_queue(~self) -> Option<~Scheduler> {
let mut this = self;
match this.message_queue.pop() {
Some(PinnedTask(task)) => {
- this.event_loop.callback(Scheduler::run_sched_once);
let mut task = task;
task.give_home(Sched(this.make_handle()));
this.resume_task_immediately(task);
return None;
}
Some(TaskFromFriend(task)) => {
- this.event_loop.callback(Scheduler::run_sched_once);
rtdebug!("got a task from a friend. lovely!");
- return this.sched_schedule_task(task);
+ this.process_task(task,
+ Scheduler::resume_task_immediately_cl).map_move(Local::put);
+ return None;
}
Some(Wake) => {
- this.event_loop.callback(Scheduler::run_sched_once);
this.sleepy = false;
- return Some(this);
+ Local::put(this);
+ return None;
}
Some(Shutdown) => {
- this.event_loop.callback(Scheduler::run_sched_once);
+ rtdebug!("shutting down");
if this.sleepy {
// There may be an outstanding handle on the
// sleeper list. Pop them all to make sure that's
// event loop references we will shut down.
this.no_sleep = true;
this.sleepy = false;
- // YYY: Does a shutdown count as a "use" of the
- // scheduler? This seems to work - so I'm leaving it
- // this way despite not having a solid rational for
- // why I should return the scheduler here.
- return Some(this);
+ Local::put(this);
+ return None;
}
None => {
return Some(this);
}
}
- /// Given an input Coroutine sends it back to its home scheduler.
- fn send_task_home(task: ~Task) {
- let mut task = task;
- let mut home = task.take_unwrap_home();
- match home {
- Sched(ref mut home_handle) => {
- home_handle.send(PinnedTask(task));
- }
- AnySched => {
- rtabort!("error: cannot send anysched task home");
- }
- }
- }
+ fn do_work(~self) -> Option<~Scheduler> {
+ let mut this = self;
- /// Take a non-homed task we aren't allowed to run here and send
- /// it to the designated friend scheduler to execute.
- fn send_to_friend(&mut self, task: ~Task) {
- rtdebug!("sending a task to friend");
- match self.friend_handle {
- Some(ref mut handle) => {
- handle.send(TaskFromFriend(task));
+ rtdebug!("scheduler calling do work");
+ match this.find_work() {
+ Some(task) => {
+ rtdebug!("found some work! processing the task");
+ return this.process_task(task,
+ Scheduler::resume_task_immediately_cl);
}
None => {
- rtabort!("tried to send task to a friend but scheduler has no friends");
+ rtdebug!("no work was found, returning the scheduler struct");
+ return Some(this);
}
}
}
None => {
// Our naive stealing, try kinda hard.
rtdebug!("scheduler trying to steal");
- let _len = self.work_queues.len();
- return self.try_steals(2);
+ let len = self.work_queues.len();
+ return self.try_steals(len/2);
}
}
}
let work_queues = &mut self.work_queues;
match work_queues[index].steal() {
Some(task) => {
- rtdebug!("found task by stealing"); return Some(task)
+ rtdebug!("found task by stealing");
+ return Some(task)
}
None => ()
}
return None;
}
- // Given a task, execute it correctly.
- fn process_task(~self, task: ~Task) -> Option<~Scheduler> {
+ // * Task Routing Functions - Make sure tasks send up in the right
+ // place.
+
+ fn process_task(~self, task: ~Task,
+ schedule_fn: SchedulingFn) -> Option<~Scheduler> {
let mut this = self;
let mut task = task;
} else {
rtdebug!("running task here");
task.give_home(Sched(home_handle));
- this.resume_task_immediately(task);
- return None;
+ return schedule_fn(this, task);
}
}
AnySched if this.run_anything => {
rtdebug!("running anysched task here");
task.give_home(AnySched);
- this.resume_task_immediately(task);
- return None;
+ return schedule_fn(this, task);
}
AnySched => {
rtdebug!("sending task to friend");
}
}
- // Bundle the helpers together.
- fn do_work(~self) -> Option<~Scheduler> {
- let mut this = self;
-
- rtdebug!("scheduler calling do work");
- match this.find_work() {
- Some(task) => {
- rtdebug!("found some work! processing the task");
- return this.process_task(task);
+ fn send_task_home(task: ~Task) {
+ let mut task = task;
+ let mut home = task.take_unwrap_home();
+ match home {
+ Sched(ref mut home_handle) => {
+ home_handle.send(PinnedTask(task));
}
- None => {
- rtdebug!("no work was found, returning the scheduler struct");
- return Some(this);
+ AnySched => {
+ rtabort!("error: cannot send anysched task home");
}
}
}
- /// Called by a running task to end execution, after which it will
- /// be recycled by the scheduler for reuse in a new task.
- pub fn terminate_current_task(~self) {
- // Similar to deschedule running task and then, but cannot go through
- // the task-blocking path. The task is already dying.
- let mut this = self;
- let stask = this.sched_task.take_unwrap();
- do this.change_task_context(stask) |sched, mut dead_task| {
- let coroutine = dead_task.coroutine.take_unwrap();
- coroutine.recycle(&mut sched.stack_pool);
+ /// Take a non-homed task we aren't allowed to run here and send
+ /// it to the designated friend scheduler to execute.
+ fn send_to_friend(&mut self, task: ~Task) {
+ rtdebug!("sending a task to friend");
+ match self.friend_handle {
+ Some(ref mut handle) => {
+ handle.send(TaskFromFriend(task));
+ }
+ None => {
+ rtabort!("tried to send task to a friend but scheduler has no friends");
+ }
}
}
- // Scheduling a task requires a few checks to make sure the task
- // ends up in the appropriate location. The run_anything flag on
- // the scheduler and the home on the task need to be checked. This
- // helper performs that check. It takes a function that specifies
- // how to queue the the provided task if that is the correct
- // action. This is a "core" function that requires handling the
- // returned Option correctly.
-
- pub fn schedule_task(~self, task: ~Task,
- schedule_fn: ~fn(sched: ~Scheduler, task: ~Task))
- -> Option<~Scheduler> {
-
- // is the task home?
- let is_home = task.is_home_no_tls(&self);
+ /// Schedule a task to be executed later.
+ ///
+ /// Pushes the task onto the work stealing queue and tells the
+ /// event loop to run it later. Always use this instead of pushing
+ /// to the work queue directly.
+ pub fn enqueue_task(&mut self, task: ~Task) {
- // does the task have a home?
- let homed = task.homed();
+ let this = self;
- let mut this = self;
+ // We push the task onto our local queue clone.
+ this.work_queue.push(task);
+ this.idle_callback.get_mut_ref().resume();
- if is_home || (!homed && this.run_anything) {
- // here we know we are home, execute now OR we know we
- // aren't homed, and that this sched doesn't care
- rtdebug!("task: %u is on ok sched, executing", to_uint(task));
- schedule_fn(this, task);
- return None;
- } else if !homed && !this.run_anything {
- // the task isn't homed, but it can't be run here
- this.send_to_friend(task);
- return Some(this);
- } else {
- // task isn't home, so don't run it here, send it home
- Scheduler::send_task_home(task);
- return Some(this);
- }
- }
+ // We've made work available. Notify a
+ // sleeping scheduler.
- // There are two contexts in which schedule_task can be called:
- // inside the scheduler, and inside a task. These contexts handle
- // executing the task slightly differently. In the scheduler
- // context case we want to receive the scheduler as an input, and
- // manually deal with the option. In the task context case we want
- // to use TLS to find the scheduler, and deal with the option
- // inside the helper.
-
- pub fn sched_schedule_task(~self, task: ~Task) -> Option<~Scheduler> {
- do self.schedule_task(task) |sched, next_task| {
- sched.resume_task_immediately(next_task);
- }
+ // XXX: perf. Check for a sleeper without
+ // synchronizing memory. It's not critical
+ // that we always find it.
+ match this.sleeper_list.pop() {
+ Some(handle) => {
+ let mut handle = handle;
+ handle.send(Wake)
+ }
+ None => { (/* pass */) }
+ };
}
- // Task context case - use TLS.
- pub fn run_task(task: ~Task) {
- let sched = Local::take::<Scheduler>();
- let opt = do sched.schedule_task(task) |sched, next_task| {
- do sched.switch_running_tasks_and_then(next_task) |sched, last_task| {
- sched.enqueue_blocked_task(last_task);
- }
+ /// As enqueue_task, but with the possibility for the blocked task to
+ /// already have been killed.
+ pub fn enqueue_blocked_task(&mut self, blocked_task: BlockedTask) {
+ do blocked_task.wake().map_move |task| {
+ self.enqueue_task(task);
};
- opt.map_move(Local::put);
}
+ // * Core Context Switching Functions
+
// The primary function for changing contexts. In the current
// design the scheduler is just a slightly modified GreenTask, so
// all context swaps are from Task to Task. The only difference
// The current task is placed inside an enum with the cleanup
// function. This enum is then placed inside the scheduler.
- this.enqueue_cleanup_job(GiveTask(current_task, f_opaque));
+ this.cleanup_job = Some(CleanupJob::new(current_task, f_opaque));
// The scheduler is then placed inside the next task.
let mut next_task = next_task;
transmute_mut_region(*next_task.sched.get_mut_ref());
let current_task: &mut Task = match sched.cleanup_job {
- Some(GiveTask(ref task, _)) => {
+ Some(CleanupJob { task: ref task, _ }) => {
transmute_mut_region(*transmute_mut_unsafe(task))
}
- Some(DoNothing) => {
- rtabort!("no next task");
- }
None => {
rtabort!("no cleanup job");
}
}
}
- // Old API for task manipulation implemented over the new core
- // function.
+ // Returns a mutable reference to both contexts involved in this
+ // swap. This is unsafe - we are getting mutable internal
+ // references to keep even when we don't own the tasks. It looks
+ // kinda safe because we are doing transmutes before passing in
+ // the arguments.
+ pub fn get_contexts<'a>(current_task: &mut Task, next_task: &mut Task) ->
+ (&'a mut Context, &'a mut Context) {
+ let current_task_context =
+ &mut current_task.coroutine.get_mut_ref().saved_context;
+ let next_task_context =
+ &mut next_task.coroutine.get_mut_ref().saved_context;
+ unsafe {
+ (transmute_mut_region(current_task_context),
+ transmute_mut_region(next_task_context))
+ }
+ }
+
+ // * Context Swapping Helpers - Here be ugliness!
- pub fn resume_task_immediately(~self, task: ~Task) {
+ pub fn resume_task_immediately(~self, task: ~Task) -> Option<~Scheduler> {
do self.change_task_context(task) |sched, stask| {
sched.sched_task = Some(stask);
}
+ return None;
}
+ fn resume_task_immediately_cl(sched: ~Scheduler,
+ task: ~Task) -> Option<~Scheduler> {
+ sched.resume_task_immediately(task)
+ }
+
+
pub fn resume_blocked_task_immediately(~self, blocked_task: BlockedTask) {
match blocked_task.wake() {
- Some(task) => self.resume_task_immediately(task),
- None => Local::put(self),
+ Some(task) => { self.resume_task_immediately(task); }
+ None => Local::put(self)
};
}
}
}
- // A helper that looks up the scheduler and runs a task later by
- // enqueuing it.
+ fn switch_task(sched: ~Scheduler, task: ~Task) -> Option<~Scheduler> {
+ do sched.switch_running_tasks_and_then(task) |sched, last_task| {
+ sched.enqueue_blocked_task(last_task);
+ };
+ return None;
+ }
+
+ // * Task Context Helpers
+
+ /// Called by a running task to end execution, after which it will
+ /// be recycled by the scheduler for reuse in a new task.
+ pub fn terminate_current_task(~self) {
+ // Similar to deschedule running task and then, but cannot go through
+ // the task-blocking path. The task is already dying.
+ let mut this = self;
+ let stask = this.sched_task.take_unwrap();
+ do this.change_task_context(stask) |sched, mut dead_task| {
+ let coroutine = dead_task.coroutine.take_unwrap();
+ coroutine.recycle(&mut sched.stack_pool);
+ }
+ }
+
+ pub fn run_task(task: ~Task) {
+ let sched = Local::take::<Scheduler>();
+ sched.process_task(task, Scheduler::switch_task).map_move(Local::put);
+ }
+
pub fn run_task_later(next_task: ~Task) {
- // We aren't performing a scheduler operation, so we want to
- // put the Scheduler back when we finish.
let next_task = Cell::new(next_task);
do Local::borrow::<Scheduler,()> |sched| {
sched.enqueue_task(next_task.take());
};
}
- // Returns a mutable reference to both contexts involved in this
- // swap. This is unsafe - we are getting mutable internal
- // references to keep even when we don't own the tasks. It looks
- // kinda safe because we are doing transmutes before passing in
- // the arguments.
- pub fn get_contexts<'a>(current_task: &mut Task, next_task: &mut Task) ->
- (&'a mut Context, &'a mut Context) {
- let current_task_context =
- &mut current_task.coroutine.get_mut_ref().saved_context;
- let next_task_context =
- &mut next_task.coroutine.get_mut_ref().saved_context;
- unsafe {
- (transmute_mut_region(current_task_context),
- transmute_mut_region(next_task_context))
- }
- }
+ // * Utility Functions
- pub fn enqueue_cleanup_job(&mut self, job: CleanupJob) {
- self.cleanup_job = Some(job);
- }
+ pub fn sched_id(&self) -> uint { to_uint(self) }
pub fn run_cleanup_job(&mut self) {
- rtdebug!("running cleanup job");
let cleanup_job = self.cleanup_job.take_unwrap();
- match cleanup_job {
- DoNothing => { }
- GiveTask(task, f) => f.to_fn()(self, task)
- }
+ cleanup_job.run(self);
+ }
+
+ pub fn make_handle(&mut self) -> SchedHandle {
+ let remote = self.event_loop.remote_callback(Scheduler::run_sched_once);
+
+ return SchedHandle {
+ remote: remote,
+ queue: self.message_queue.clone(),
+ sched_id: self.sched_id()
+ };
}
}
-// The cases for the below function.
-enum ResumeAction {
- SendHome,
- Requeue,
- ResumeNow,
- Homeless
+// Supporting types
+
+type SchedulingFn = ~fn(~Scheduler, ~Task) -> Option<~Scheduler>;
+
+pub enum SchedMessage {
+ Wake,
+ Shutdown,
+ PinnedTask(~Task),
+ TaskFromFriend(~Task)
+}
+
+pub struct SchedHandle {
+ priv remote: ~RemoteCallbackObject,
+ priv queue: MessageQueue<SchedMessage>,
+ sched_id: uint
}
impl SchedHandle {
}
}
+struct CleanupJob {
+ task: ~Task,
+ f: UnsafeTaskReceiver
+}
+
+impl CleanupJob {
+ pub fn new(task: ~Task, f: UnsafeTaskReceiver) -> CleanupJob {
+ CleanupJob {
+ task: task,
+ f: f
+ }
+ }
+
+ pub fn run(self, sched: &mut Scheduler) {
+ let CleanupJob { task: task, f: f } = self;
+ f.to_fn()(sched, task)
+ }
+}
+
// XXX: Some hacks to put a &fn in Scheduler without borrowck
// complaining
type UnsafeTaskReceiver = raw::Closure;
use cell::Cell;
use rt::thread::Thread;
use rt::task::{Task, Sched};
+ use rt::util;
use option::{Some};
#[test]
#[test]
fn test_stress_schedule_task_states() {
+ if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
let n = stress_factor() * 120;
for _ in range(0, n as int) {
test_schedule_home_states();
}
}
+ // A regression test that the final message is always handled.
+ // Used to deadlock because Shutdown was never recvd.
+ #[test]
+ fn no_missed_messages() {
+ use rt::work_queue::WorkQueue;
+ use rt::sleeper_list::SleeperList;
+ use rt::stack::StackPool;
+ use rt::uv::uvio::UvEventLoop;
+ use rt::sched::{Shutdown, TaskFromFriend};
+ use util;
+
+ do run_in_bare_thread {
+ do stress_factor().times {
+ let sleepers = SleeperList::new();
+ let queue = WorkQueue::new();
+ let queues = ~[queue.clone()];
+
+ let mut sched = ~Scheduler::new(
+ ~UvEventLoop::new(),
+ queue,
+ queues.clone(),
+ sleepers.clone());
+
+ let mut handle = sched.make_handle();
+
+ let sched = Cell::new(sched);
+
+ let thread = do Thread::start {
+ let mut sched = sched.take();
+ let bootstrap_task = ~Task::new_root(&mut sched.stack_pool, None, ||());
+ sched.bootstrap(bootstrap_task);
+ };
+
+ let mut stack_pool = StackPool::new();
+ let task = ~Task::new_root(&mut stack_pool, None, ||());
+ handle.send(TaskFromFriend(task));
+
+ handle.send(Shutdown);
+ util::ignore(handle);
+
+ thread.join();
+ }
+ }
+ }
+
#[test]
fn multithreading() {
use rt::comm::*;
impl StackSegment {
pub fn new(size: uint) -> StackSegment {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
// Crate a block of uninitialized values
let mut stack = vec::with_capacity(size);
impl Drop for StackSegment {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
// XXX: Using the FFI to call a C macro. Slow
rust_valgrind_stack_deregister(self.valgrind_id);
use ptr;
use prelude::*;
use option::{Option, Some, None};
+use rt::borrowck;
+use rt::borrowck::BorrowRecord;
use rt::env;
use rt::kill::Death;
use rt::local::Local;
name: Option<~str>,
coroutine: Option<Coroutine>,
sched: Option<~Scheduler>,
- task_type: TaskType
+ task_type: TaskType,
+ // Dynamic borrowck debugging info
+ borrow_list: Option<~[BorrowRecord]>
}
pub enum TaskType {
saved_context: Context
}
-/// Some tasks have a deciated home scheduler that they must run on.
+/// Some tasks have a dedicated home scheduler that they must run on.
pub enum SchedHome {
AnySched,
Sched(SchedHandle)
coroutine: Some(Coroutine::empty()),
name: None,
sched: None,
- task_type: SchedTask
+ task_type: SchedTask,
+ borrow_list: None
}
}
name: None,
coroutine: Some(Coroutine::new(stack_pool, stack_size, start)),
sched: None,
- task_type: GreenTask(Some(~home))
+ task_type: GreenTask(Some(~home)),
+ borrow_list: None
}
}
name: None,
coroutine: Some(Coroutine::new(stack_pool, stack_size, start)),
sched: None,
- task_type: GreenTask(Some(~home))
+ task_type: GreenTask(Some(~home)),
+ borrow_list: None
}
}
}
}
+ // Cleanup the dynamic borrowck debugging info
+ borrowck::clear_task_borrow_list();
+
// NB. We pass the taskgroup into death so that it can be dropped while
// the unkillable counter is set. This is necessary for when the
// taskgroup destruction code drops references on KillHandles, which
// Again - might work while safe, or it might not.
do Local::borrow::<Scheduler,()> |sched| {
- (sched).run_cleanup_job();
+ sched.run_cleanup_job();
}
// To call the run method on a task we need a direct
}
pub fn begin_unwind(&mut self) -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+
self.unwinding = true;
unsafe {
rust_begin_unwind(UNWIND_TOKEN);
}
}
}
-
use super::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
use vec::{OwnedVector, MutableVector, ImmutableVector};
use rt::sched::Scheduler;
-use unstable::run_in_bare_thread;
+use unstable::{run_in_bare_thread};
use rt::thread::Thread;
use rt::task::Task;
use rt::uv::uvio::UvEventLoop;
static RLIMIT_NOFILE: libc::c_int = 8;
pub unsafe fn raise_fd_limit() {
+ #[fixed_stack_segment]; #[inline(never)];
+
// The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
// sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
use ptr::{to_unsafe_ptr, to_mut_unsafe_ptr, mut_null};
let nthreads = match os::getenv("RUST_RT_TEST_THREADS") {
Some(nstr) => FromStr::from_str(nstr).unwrap(),
None => {
- // Using more threads than cores in test code
- // to force the OS to preempt them frequently.
- // Assuming that this help stress test concurrent types.
- util::num_cpus() * 2
+ if util::limit_thread_creation_due_to_osx_and_valgrind() {
+ 1
+ } else {
+ // Using more threads than cores in test code
+ // to force the OS to preempt them frequently.
+ // Assuming that this help stress test concurrent types.
+ util::num_cpus() * 2
+ }
}
};
}
/// Get a port number, starting at 9600, for use in tests
+#[fixed_stack_segment] #[inline(never)]
pub fn next_test_port() -> u16 {
unsafe {
return rust_dbg_next_port(base_port() as libc::uintptr_t) as u16;
impl Thread {
pub fn start(main: ~fn()) -> Thread {
fn substart(main: &~fn()) -> *raw_thread {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe { rust_raw_thread_start(main) }
}
let raw = substart(&main);
}
pub fn join(self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(!self.joined);
let mut this = self;
unsafe { rust_raw_thread_join(this.raw_thread); }
impl Drop for Thread {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(self.joined);
unsafe { rust_raw_thread_delete(self.raw_thread) }
}
pub type Key = pthread_key_t;
#[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn create(key: &mut Key) {
assert_eq!(0, pthread_key_create(key, null()));
}
#[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn set(key: Key, value: *mut c_void) {
assert_eq!(0, pthread_setspecific(key, value));
}
#[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn get(key: Key) -> *mut c_void {
pthread_getspecific(key)
}
pub type Key = DWORD;
#[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn create(key: &mut Key) {
static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
*key = TlsAlloc();
}
#[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn set(key: Key, value: *mut c_void) {
assert!(0 != TlsSetValue(key, value))
}
#[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn get(key: Key) -> *mut c_void {
TlsGetValue(key)
}
use os;
use str::StrSlice;
+#[cfg(target_os="macos")]
+use unstable::running_on_valgrind;
+
/// Get the number of cores available
pub fn num_cpus() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
return rust_get_num_cpus();
}
}
}
+/// Valgrind has a fixed-sized array (size around 2000) of segment descriptors wired into it; this
+/// is a hard limit and requires rebuilding valgrind if you want to go beyond it. Normally this is
+/// not a problem, but in some tests, we produce a lot of threads casually. Making lots of threads
+/// alone might not be a problem _either_, except on OSX, the segments produced for new threads
+/// _take a while_ to get reclaimed by the OS. Combined with the fact that libuv schedulers fork off
+/// a separate thread for polling fsevents on OSX, we get a perfect storm of creating "too many
+/// mappings" for valgrind to handle when running certain stress tests in the runtime.
+#[cfg(target_os="macos")]
+pub fn limit_thread_creation_due_to_osx_and_valgrind() -> bool {
+ running_on_valgrind()
+}
+
+#[cfg(not(target_os="macos"))]
+pub fn limit_thread_creation_due_to_osx_and_valgrind() -> bool {
+ false
+}
+
/// Get's the number of scheduler threads requested by the environment
/// either `RUST_THREADS` or `num_cpus`.
pub fn default_sched_threads() -> uint {
match os::getenv("RUST_THREADS") {
Some(nstr) => FromStr::from_str(nstr).unwrap(),
- None => num_cpus()
+ None => {
+ if limit_thread_creation_due_to_osx_and_valgrind() {
+ 1
+ } else {
+ num_cpus()
+ }
+ }
}
}
pub fn dumb_println(s: &str) {
use io::WriterUtil;
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
- dbg.write_str(s);
- dbg.write_str("\n");
+ dbg.write_str(s + "\n");
}
pub fn abort(msg: &str) -> ! {
rterrln!("%s", "");
rterrln!("fatal runtime error: %s", msg);
- unsafe { libc::abort(); }
+ abort();
+
+ fn abort() -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::abort() }
+ }
}
pub fn set_exit_status(code: int) {
-
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
return rust_set_exit_status_newrt(code as libc::uintptr_t);
}
}
pub fn get_exit_status() -> int {
-
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
return rust_get_exit_status_newrt() as int;
}
}
}
+ pub fn restart(&mut self) {
+ unsafe {
+ assert!(0 == uvll::idle_start(self.native_handle(), idle_cb))
+ };
+
+ extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
+ let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
+ let data = idle_watcher.get_watcher_data();
+ let cb: &IdleCallback = data.idle_cb.get_ref();
+ let status = status_to_maybe_uv_error(idle_watcher, status);
+ (*cb)(idle_watcher, status);
+ }
+ }
+
pub fn stop(&mut self) {
// NB: Not resetting the Rust idle_cb to None here because `stop` is
// likely called from *within* the idle callback, causing a use after
/*!
-Bindings to libuv, along with the default implementation of `core::rt::rtio`.
+Bindings to libuv, along with the default implementation of `std::rt::rtio`.
UV types consist of the event loop (Loop), Watchers, Requests and
Callbacks.
/// Transmute an owned vector to a Buf
pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let data = malloc(v.len() as size_t) as *u8;
assert!(data.is_not_null());
/// Transmute a Buf that was once a ~[u8] back to ~[u8]
pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> {
+ #[fixed_stack_segment]; #[inline(never)];
+
if !(buf.len == 0 && buf.base.is_null()) {
let v = unsafe { vec::from_buf(buf.base, buf.len as uint) };
unsafe { free(buf.base as *c_void) };
extern fn close_cb(handle: *uvll::uv_stream_t) {
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle);
- stream_watcher.get_watcher_data().close_cb.take_unwrap()();
+ let cb = stream_watcher.get_watcher_data().close_cb.take_unwrap();
stream_watcher.drop_watcher_data();
unsafe { free_handle(handle as *c_void) }
+ cb();
}
}
}
extern fn close_cb(handle: *uvll::uv_udp_t) {
let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
- udp_watcher.get_watcher_data().close_cb.take_unwrap()();
+ let cb = udp_watcher.get_watcher_data().close_cb.take_unwrap();
udp_watcher.drop_watcher_data();
unsafe { free_handle(handle as *c_void) }
+ cb();
}
}
}
use rt::io::{standard_error, OtherIoError};
use rt::local::Local;
use rt::rtio::*;
-use rt::sched::Scheduler;
+use rt::sched::{Scheduler, SchedHandle};
use rt::tube::Tube;
use rt::uv::*;
use rt::uv::idle::IdleWatcher;
run_in_newsched_task};
#[cfg(test)] use iterator::{Iterator, range};
+// XXX we should not be calling uvll functions in here.
+
+trait HomingIO {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle;
+ /* XXX This will move pinned tasks to do IO on the proper scheduler
+ * and then move them back to their home.
+ */
+ fn home_for_io<A>(&mut self, io: &fn(&mut Self) -> A) -> A {
+ use rt::sched::{PinnedTask, TaskFromFriend};
+ // go home
+ let old_home = Cell::new_empty();
+ let old_home_ptr = &old_home;
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ // get the old home first
+ do task.wake().map_move |mut task| {
+ old_home_ptr.put_back(task.take_unwrap_home());
+ self.home().send(PinnedTask(task));
+ };
+ }
+
+ // do IO
+ let a = io(self);
+
+ // unhome home
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |scheduler, task| {
+ do task.wake().map_move |mut task| {
+ task.give_home(old_home.take());
+ scheduler.make_handle().send(TaskFromFriend(task));
+ };
+ }
+
+ // return the result of the IO
+ a
+ }
+}
+
+// get a handle for the current scheduler
+macro_rules! get_handle_to_current_scheduler(
+ () => (do Local::borrow::<Scheduler, SchedHandle> |sched| { sched.make_handle() })
+)
+
enum SocketNameKind {
TcpPeer,
Tcp,
fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
handle: U) -> Result<SocketAddr, IoError> {
-
let getsockname = match sk {
- TcpPeer => uvll::rust_uv_tcp_getpeername,
- Tcp => uvll::rust_uv_tcp_getsockname,
- Udp => uvll::rust_uv_udp_getsockname
+ TcpPeer => uvll::tcp_getpeername,
+ Tcp => uvll::tcp_getsockname,
+ Udp => uvll::udp_getsockname,
};
// Allocate a sockaddr_storage
}
+// Obviously an Event Loop is always home.
pub struct UvEventLoop {
uvio: UvIoFactory
}
}
}
+ fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback {
+ let idle_watcher = IdleWatcher::new(self.uvio.uv_loop());
+ return ~UvPausibleIdleCallback {
+ watcher: idle_watcher,
+ idle_flag: false,
+ closed: false
+ };
+ }
+
fn callback_ms(&mut self, ms: u64, f: ~fn()) {
let mut timer = TimerWatcher::new(self.uvio.uv_loop());
do timer.start(ms, 0) |timer, status| {
}
}
+pub struct UvPausibleIdleCallback {
+ watcher: IdleWatcher,
+ idle_flag: bool,
+ closed: bool
+}
+
+impl UvPausibleIdleCallback {
+ #[inline]
+ pub fn start(&mut self, f: ~fn()) {
+ do self.watcher.start |_idle_watcher, _status| {
+ f();
+ };
+ self.idle_flag = true;
+ }
+ #[inline]
+ pub fn pause(&mut self) {
+ if self.idle_flag == true {
+ self.watcher.stop();
+ self.idle_flag = false;
+ }
+ }
+ #[inline]
+ pub fn resume(&mut self) {
+ if self.idle_flag == false {
+ self.watcher.restart();
+ self.idle_flag = true;
+ }
+ }
+ #[inline]
+ pub fn close(&mut self) {
+ self.pause();
+ if !self.closed {
+ self.closed = true;
+ self.watcher.close(||{});
+ }
+ }
+}
+
#[test]
fn test_callback_run_once() {
do run_in_bare_thread {
}
}
+// The entire point of async is to call into a loop from other threads so it does not need to home.
pub struct UvRemoteCallback {
// The uv async handle for triggering the callback
async: AsyncWatcher,
let exit_flag_clone = exit_flag.clone();
let async = do AsyncWatcher::new(loop_) |watcher, status| {
assert!(status.is_none());
+
+ // The synchronization logic here is subtle. To review,
+ // the uv async handle type promises that, after it is
+ // triggered the remote callback is definitely called at
+ // least once. UvRemoteCallback needs to maintain those
+ // semantics while also shutting down cleanly from the
+ // dtor. In our case that means that, when the
+ // UvRemoteCallback dtor calls `async.send()`, here `f` is
+ // always called later.
+
+ // In the dtor both the exit flag is set and the async
+ // callback fired under a lock. Here, before calling `f`,
+ // we take the lock and check the flag. Because we are
+ // checking the flag before calling `f`, and the flag is
+ // set under the same lock as the send, then if the flag
+ // is set then we're guaranteed to call `f` after the
+ // final send.
+
+ // If the check was done after `f()` then there would be a
+ // period between that call and the check where the dtor
+ // could be called in the other thread, missing the final
+ // callback while still destroying the handle.
+
+ let should_exit = unsafe {
+ exit_flag_clone.with_imm(|&should_exit| should_exit)
+ };
+
f();
- unsafe {
- do exit_flag_clone.with_imm |&should_exit| {
- if should_exit {
- watcher.close(||());
- }
- }
+
+ if should_exit {
+ watcher.close(||());
}
+
};
UvRemoteCallback {
async: async,
let tube_clone = tube_clone.clone();
let tube_clone_cell = Cell::new(tube_clone);
let remote = do sched.event_loop.remote_callback {
- tube_clone_cell.take().send(1);
+ // This could be called multiple times
+ if !tube_clone_cell.is_empty() {
+ tube_clone_cell.take().send(1);
+ }
};
remote_cell.put_back(remote);
}
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<~RtioTcpStreamObject, IoError>> = &result_cell;
- let scheduler = Local::take::<Scheduler>();
-
// Block this task and take ownership, switch to scheduler context
+ let scheduler = Local::take::<Scheduler>();
do scheduler.deschedule_running_task_and_then |_, task| {
- rtdebug!("connect: entered scheduler context");
- let mut tcp_watcher = TcpWatcher::new(self.uv_loop());
+ let mut tcp = TcpWatcher::new(self.uv_loop());
let task_cell = Cell::new(task);
// Wait for a connection
- do tcp_watcher.connect(addr) |stream_watcher, status| {
- rtdebug!("connect: in connect callback");
- if status.is_none() {
- rtdebug!("status is none");
- let tcp_watcher =
- NativeHandle::from_native_handle(stream_watcher.native_handle());
- let res = Ok(~UvTcpStream(tcp_watcher));
-
- // Store the stream in the task's stack
- unsafe { (*result_cell_ptr).put_back(res); }
-
- // Context switch
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- } else {
- rtdebug!("status is some");
- let task_cell = Cell::new(task_cell.take());
- do stream_watcher.close {
- let res = Err(uv_error_to_io_error(status.unwrap()));
+ do tcp.connect(addr) |stream, status| {
+ match status {
+ None => {
+ let tcp = NativeHandle::from_native_handle(stream.native_handle());
+ let home = get_handle_to_current_scheduler!();
+ let res = Ok(~UvTcpStream { watcher: tcp, home: home });
+
+ // Store the stream in the task's stack
unsafe { (*result_cell_ptr).put_back(res); }
+
+ // Context switch
let scheduler = Local::take::<Scheduler>();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
- };
+ Some(_) => {
+ let task_cell = Cell::new(task_cell.take());
+ do stream.close {
+ let res = Err(uv_error_to_io_error(status.unwrap()));
+ unsafe { (*result_cell_ptr).put_back(res); }
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ }
}
}
fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError> {
let mut watcher = TcpWatcher::new(self.uv_loop());
match watcher.bind(addr) {
- Ok(_) => Ok(~UvTcpListener::new(watcher)),
+ Ok(_) => {
+ let home = get_handle_to_current_scheduler!();
+ Ok(~UvTcpListener::new(watcher, home))
+ }
Err(uverr) => {
let scheduler = Local::take::<Scheduler>();
do scheduler.deschedule_running_task_and_then |_, task| {
fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError> {
let mut watcher = UdpWatcher::new(self.uv_loop());
match watcher.bind(addr) {
- Ok(_) => Ok(~UvUdpSocket(watcher)),
+ Ok(_) => {
+ let home = get_handle_to_current_scheduler!();
+ Ok(~UvUdpSocket { watcher: watcher, home: home })
+ }
Err(uverr) => {
let scheduler = Local::take::<Scheduler>();
do scheduler.deschedule_running_task_and_then |_, task| {
}
fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError> {
- Ok(~UvTimer(TimerWatcher::new(self.uv_loop())))
+ let watcher = TimerWatcher::new(self.uv_loop());
+ let home = get_handle_to_current_scheduler!();
+ Ok(~UvTimer::new(watcher, home))
}
}
pub struct UvTcpListener {
watcher: TcpWatcher,
listening: bool,
- incoming_streams: Tube<Result<~RtioTcpStreamObject, IoError>>
+ incoming_streams: Tube<Result<~RtioTcpStreamObject, IoError>>,
+ home: SchedHandle,
+}
+
+impl HomingIO for UvTcpListener {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
}
impl UvTcpListener {
- fn new(watcher: TcpWatcher) -> UvTcpListener {
+ fn new(watcher: TcpWatcher, home: SchedHandle) -> UvTcpListener {
UvTcpListener {
watcher: watcher,
listening: false,
- incoming_streams: Tube::new()
+ incoming_streams: Tube::new(),
+ home: home,
}
}
impl Drop for UvTcpListener {
fn drop(&self) {
- let watcher = self.watcher();
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do watcher.as_stream().close {
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ // XXX need mutable finalizer
+ let self_ = unsafe { transmute::<&UvTcpListener, &mut UvTcpListener>(self) };
+ do self_.home_for_io |self_| {
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self_.watcher().as_stream().close {
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
}
}
impl RtioSocket for UvTcpListener {
fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
- socket_name(Tcp, self.watcher)
+ do self.home_for_io |self_| {
+ socket_name(Tcp, self_.watcher)
+ }
}
}
impl RtioTcpListener for UvTcpListener {
fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> {
- rtdebug!("entering listen");
-
- if self.listening {
- return self.incoming_streams.recv();
- }
-
- self.listening = true;
-
- let server_tcp_watcher = self.watcher();
- let incoming_streams_cell = Cell::new(self.incoming_streams.clone());
-
- let incoming_streams_cell = Cell::new(incoming_streams_cell.take());
- let mut server_tcp_watcher = server_tcp_watcher;
- do server_tcp_watcher.listen |mut server_stream_watcher, status| {
- let maybe_stream = if status.is_none() {
- let mut loop_ = server_stream_watcher.event_loop();
- let client_tcp_watcher = TcpWatcher::new(&mut loop_);
- // XXX: Need's to be surfaced in interface
- server_stream_watcher.accept(client_tcp_watcher.as_stream());
- Ok(~UvTcpStream(client_tcp_watcher))
- } else {
- Err(standard_error(OtherIoError))
- };
+ do self.home_for_io |self_| {
+
+ if !self_.listening {
+ self_.listening = true;
+
+ let incoming_streams_cell = Cell::new(self_.incoming_streams.clone());
+
+ do self_.watcher().listen |mut server, status| {
+ let stream = match status {
+ Some(_) => Err(standard_error(OtherIoError)),
+ None => {
+ let client = TcpWatcher::new(&server.event_loop());
+ // XXX: needs to be surfaced in interface
+ server.accept(client.as_stream());
+ let home = get_handle_to_current_scheduler!();
+ Ok(~UvTcpStream { watcher: client, home: home })
+ }
+ };
+
+ let mut incoming_streams = incoming_streams_cell.take();
+ incoming_streams.send(stream);
+ incoming_streams_cell.put_back(incoming_streams);
+ }
- let mut incoming_streams = incoming_streams_cell.take();
- incoming_streams.send(maybe_stream);
- incoming_streams_cell.put_back(incoming_streams);
+ }
+ self_.incoming_streams.recv()
}
-
- return self.incoming_streams.recv();
}
fn accept_simultaneously(&mut self) -> Result<(), IoError> {
- let r = unsafe {
- uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 1 as c_int)
- };
+ do self.home_for_io |self_| {
+ let r = unsafe {
+ uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 1 as c_int)
+ };
- match status_to_maybe_uv_error(self.watcher, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher(), r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
- let r = unsafe {
- uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 0 as c_int)
- };
+ do self.home_for_io |self_| {
+ let r = unsafe {
+ uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 0 as c_int)
+ };
- match status_to_maybe_uv_error(self.watcher, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher(), r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
}
-pub struct UvTcpStream(TcpWatcher);
+pub struct UvTcpStream {
+ watcher: TcpWatcher,
+ home: SchedHandle,
+}
+
+impl HomingIO for UvTcpStream {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
impl Drop for UvTcpStream {
fn drop(&self) {
- rtdebug!("closing tcp stream");
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do self.as_stream().close {
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ // XXX need mutable finalizer
+ let this = unsafe { transmute::<&UvTcpStream, &mut UvTcpStream>(self) };
+ do this.home_for_io |self_| {
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self_.watcher.as_stream().close {
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
}
}
impl RtioSocket for UvTcpStream {
fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
- socket_name(Tcp, **self)
+ do self.home_for_io |self_| {
+ socket_name(Tcp, self_.watcher)
+ }
}
}
impl RtioTcpStream for UvTcpStream {
fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
-
- let scheduler = Local::take::<Scheduler>();
- let buf_ptr: *&mut [u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_sched, task| {
- rtdebug!("read: entered scheduler context");
- let task_cell = Cell::new(task);
- // XXX: We shouldn't reallocate these callbacks every
- // call to read
- let alloc: AllocCallback = |_| unsafe {
- slice_to_uv_buf(*buf_ptr)
- };
- let mut watcher = self.as_stream();
- do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
-
- // Stop reading so that no read callbacks are
- // triggered before the user calls `read` again.
- // XXX: Is there a performance impact to calling
- // stop here?
- watcher.read_stop();
-
- let result = if status.is_none() {
- assert!(nread >= 0);
- Ok(nread as uint)
- } else {
- Err(uv_error_to_io_error(status.unwrap()))
+ do self.home_for_io |self_| {
+ let result_cell = Cell::new_empty();
+ let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
+
+ let scheduler = Local::take::<Scheduler>();
+ let buf_ptr: *&mut [u8] = &buf;
+ do scheduler.deschedule_running_task_and_then |_sched, task| {
+ let task_cell = Cell::new(task);
+ // XXX: We shouldn't reallocate these callbacks every
+ // call to read
+ let alloc: AllocCallback = |_| unsafe {
+ slice_to_uv_buf(*buf_ptr)
};
+ let mut watcher = self_.watcher.as_stream();
+ do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
- unsafe { (*result_cell_ptr).put_back(result); }
+ // Stop reading so that no read callbacks are
+ // triggered before the user calls `read` again.
+ // XXX: Is there a performance impact to calling
+ // stop here?
+ watcher.read_stop();
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ let result = if status.is_none() {
+ assert!(nread >= 0);
+ Ok(nread as uint)
+ } else {
+ Err(uv_error_to_io_error(status.unwrap()))
+ };
+
+ unsafe { (*result_cell_ptr).put_back(result); }
+
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
- }
- assert!(!result_cell.is_empty());
- return result_cell.take();
+ assert!(!result_cell.is_empty());
+ result_cell.take()
+ }
}
fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
- let scheduler = Local::take::<Scheduler>();
- let buf_ptr: *&[u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
- let mut watcher = self.as_stream();
- do watcher.write(buf) |_watcher, status| {
- let result = if status.is_none() {
- Ok(())
- } else {
- Err(uv_error_to_io_error(status.unwrap()))
- };
-
- unsafe { (*result_cell_ptr).put_back(result); }
+ do self.home_for_io |self_| {
+ let result_cell = Cell::new_empty();
+ let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+ let scheduler = Local::take::<Scheduler>();
+ let buf_ptr: *&[u8] = &buf;
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
+ let mut watcher = self_.watcher.as_stream();
+ do watcher.write(buf) |_watcher, status| {
+ let result = if status.is_none() {
+ Ok(())
+ } else {
+ Err(uv_error_to_io_error(status.unwrap()))
+ };
+
+ unsafe { (*result_cell_ptr).put_back(result); }
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
- }
- assert!(!result_cell.is_empty());
- return result_cell.take();
+ assert!(!result_cell.is_empty());
+ result_cell.take()
+ }
}
fn peer_name(&mut self) -> Result<SocketAddr, IoError> {
- socket_name(TcpPeer, **self)
+ do self.home_for_io |self_| {
+ socket_name(TcpPeer, self_.watcher)
+ }
}
fn control_congestion(&mut self) -> Result<(), IoError> {
- let r = unsafe {
- uvll::rust_uv_tcp_nodelay(self.native_handle(), 0 as c_int)
- };
+ do self.home_for_io |self_| {
+ let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 0 as c_int) };
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn nodelay(&mut self) -> Result<(), IoError> {
- let r = unsafe {
- uvll::rust_uv_tcp_nodelay(self.native_handle(), 1 as c_int)
- };
+ do self.home_for_io |self_| {
+ let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 1 as c_int) };
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> {
- let r = unsafe {
- uvll::rust_uv_tcp_keepalive(self.native_handle(), 1 as c_int,
- delay_in_seconds as c_uint)
- };
+ do self.home_for_io |self_| {
+ let r = unsafe {
+ uvll::tcp_keepalive(self_.watcher.native_handle(), 1 as c_int,
+ delay_in_seconds as c_uint)
+ };
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn letdie(&mut self) -> Result<(), IoError> {
- let r = unsafe {
- uvll::rust_uv_tcp_keepalive(self.native_handle(), 0 as c_int, 0 as c_uint)
- };
+ do self.home_for_io |self_| {
+ let r = unsafe {
+ uvll::tcp_keepalive(self_.watcher.native_handle(), 0 as c_int, 0 as c_uint)
+ };
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
}
-pub struct UvUdpSocket(UdpWatcher);
+pub struct UvUdpSocket {
+ watcher: UdpWatcher,
+ home: SchedHandle,
+}
+
+impl HomingIO for UvUdpSocket {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
impl Drop for UvUdpSocket {
fn drop(&self) {
- rtdebug!("closing udp socket");
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do self.close {
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ // XXX need mutable finalizer
+ let this = unsafe { transmute::<&UvUdpSocket, &mut UvUdpSocket>(self) };
+ do this.home_for_io |_| {
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do this.watcher.close {
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
}
}
impl RtioSocket for UvUdpSocket {
fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
- socket_name(Udp, **self)
+ do self.home_for_io |self_| {
+ socket_name(Udp, self_.watcher)
+ }
}
}
impl RtioUdpSocket for UvUdpSocket {
fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, SocketAddr), IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(uint, SocketAddr), IoError>> = &result_cell;
-
- let scheduler = Local::take::<Scheduler>();
- let buf_ptr: *&mut [u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_sched, task| {
- rtdebug!("recvfrom: entered scheduler context");
- let task_cell = Cell::new(task);
- let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) };
- do self.recv_start(alloc) |mut watcher, nread, _buf, addr, flags, status| {
- let _ = flags; // XXX add handling for partials?
-
- watcher.recv_stop();
+ do self.home_for_io |self_| {
+ let result_cell = Cell::new_empty();
+ let result_cell_ptr: *Cell<Result<(uint, SocketAddr), IoError>> = &result_cell;
+
+ let scheduler = Local::take::<Scheduler>();
+ let buf_ptr: *&mut [u8] = &buf;
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) };
+ do self_.watcher.recv_start(alloc) |mut watcher, nread, _buf, addr, flags, status| {
+ let _ = flags; // /XXX add handling for partials?
+
+ watcher.recv_stop();
+
+ let result = match status {
+ None => {
+ assert!(nread >= 0);
+ Ok((nread as uint, addr))
+ }
+ Some(err) => Err(uv_error_to_io_error(err)),
+ };
+
+ unsafe { (*result_cell_ptr).put_back(result); }
- let result = match status {
- None => {
- assert!(nread >= 0);
- Ok((nread as uint, addr))
- }
- Some(err) => Err(uv_error_to_io_error(err))
- };
-
- unsafe { (*result_cell_ptr).put_back(result); }
-
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
- }
- assert!(!result_cell.is_empty());
- return result_cell.take();
+ assert!(!result_cell.is_empty());
+ result_cell.take()
+ }
}
fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> Result<(), IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
- let scheduler = Local::take::<Scheduler>();
- let buf_ptr: *&[u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
- do self.send(buf, dst) |_watcher, status| {
-
- let result = match status {
- None => Ok(()),
- Some(err) => Err(uv_error_to_io_error(err)),
- };
-
- unsafe { (*result_cell_ptr).put_back(result); }
+ do self.home_for_io |self_| {
+ let result_cell = Cell::new_empty();
+ let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+ let scheduler = Local::take::<Scheduler>();
+ let buf_ptr: *&[u8] = &buf;
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
+ do self_.watcher.send(buf, dst) |_watcher, status| {
+
+ let result = match status {
+ None => Ok(()),
+ Some(err) => Err(uv_error_to_io_error(err)),
+ };
+
+ unsafe { (*result_cell_ptr).put_back(result); }
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
- }
- assert!(!result_cell.is_empty());
- return result_cell.take();
+ assert!(!result_cell.is_empty());
+ result_cell.take()
+ }
}
fn join_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
- let r = unsafe {
- do multi.to_str().to_c_str().with_ref |m_addr| {
- uvll::udp_set_membership(self.native_handle(), m_addr,
- ptr::null(), uvll::UV_JOIN_GROUP)
- }
- };
+ do self.home_for_io |self_| {
+ let r = unsafe {
+ do multi.to_str().with_c_str |m_addr| {
+ uvll::udp_set_membership(self_.watcher.native_handle(), m_addr,
+ ptr::null(), uvll::UV_JOIN_GROUP)
+ }
+ };
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn leave_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
- let r = unsafe {
- do multi.to_str().to_c_str().with_ref |m_addr| {
- uvll::udp_set_membership(self.native_handle(), m_addr,
- ptr::null(), uvll::UV_LEAVE_GROUP)
- }
- };
+ do self.home_for_io |self_| {
+ let r = unsafe {
+ do multi.to_str().with_c_str |m_addr| {
+ uvll::udp_set_membership(self_.watcher.native_handle(), m_addr,
+ ptr::null(), uvll::UV_LEAVE_GROUP)
+ }
+ };
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn loop_multicast_locally(&mut self) -> Result<(), IoError> {
- let r = unsafe {
- uvll::udp_set_multicast_loop(self.native_handle(), 1 as c_int)
- };
+ do self.home_for_io |self_| {
+
+ let r = unsafe {
+ uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 1 as c_int)
+ };
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn dont_loop_multicast_locally(&mut self) -> Result<(), IoError> {
- let r = unsafe {
- uvll::udp_set_multicast_loop(self.native_handle(), 0 as c_int)
- };
+ do self.home_for_io |self_| {
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ let r = unsafe {
+ uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 0 as c_int)
+ };
+
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn multicast_time_to_live(&mut self, ttl: int) -> Result<(), IoError> {
- let r = unsafe {
- uvll::udp_set_multicast_ttl(self.native_handle(), ttl as c_int)
- };
+ do self.home_for_io |self_| {
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ let r = unsafe {
+ uvll::udp_set_multicast_ttl(self_.watcher.native_handle(), ttl as c_int)
+ };
+
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn time_to_live(&mut self, ttl: int) -> Result<(), IoError> {
- let r = unsafe {
- uvll::udp_set_ttl(self.native_handle(), ttl as c_int)
- };
+ do self.home_for_io |self_| {
+
+ let r = unsafe {
+ uvll::udp_set_ttl(self_.watcher.native_handle(), ttl as c_int)
+ };
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn hear_broadcasts(&mut self) -> Result<(), IoError> {
- let r = unsafe {
- uvll::udp_set_broadcast(self.native_handle(), 1 as c_int)
- };
+ do self.home_for_io |self_| {
+
+ let r = unsafe {
+ uvll::udp_set_broadcast(self_.watcher.native_handle(), 1 as c_int)
+ };
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
fn ignore_broadcasts(&mut self) -> Result<(), IoError> {
- let r = unsafe {
- uvll::udp_set_broadcast(self.native_handle(), 0 as c_int)
- };
+ do self.home_for_io |self_| {
- match status_to_maybe_uv_error(**self, r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
+ let r = unsafe {
+ uvll::udp_set_broadcast(self_.watcher.native_handle(), 0 as c_int)
+ };
+
+ match status_to_maybe_uv_error(self_.watcher, r) {
+ Some(err) => Err(uv_error_to_io_error(err)),
+ None => Ok(())
+ }
}
}
}
-pub struct UvTimer(timer::TimerWatcher);
+pub struct UvTimer {
+ watcher: timer::TimerWatcher,
+ home: SchedHandle,
+}
+
+impl HomingIO for UvTimer {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
impl UvTimer {
- fn new(w: timer::TimerWatcher) -> UvTimer {
- UvTimer(w)
+ fn new(w: timer::TimerWatcher, home: SchedHandle) -> UvTimer {
+ UvTimer { watcher: w, home: home }
}
}
impl Drop for UvTimer {
fn drop(&self) {
- rtdebug!("closing UvTimer");
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do self.close {
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ let self_ = unsafe { transmute::<&UvTimer, &mut UvTimer>(self) };
+ do self_.home_for_io |self_| {
+ rtdebug!("closing UvTimer");
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self_.watcher.close {
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
}
}
}
impl RtioTimer for UvTimer {
- fn sleep(&self, msecs: u64) {
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_sched, task| {
- rtdebug!("sleep: entered scheduler context");
- let task_cell = Cell::new(task);
- let mut watcher = **self;
- do watcher.start(msecs, 0) |_, status| {
- assert!(status.is_none());
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ fn sleep(&mut self, msecs: u64) {
+ do self.home_for_io |self_| {
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |_sched, task| {
+ rtdebug!("sleep: entered scheduler context");
+ let task_cell = Cell::new(task);
+ do self_.watcher.start(msecs, 0) |_, status| {
+ assert!(status.is_none());
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
+ self_.watcher.stop();
}
- let mut w = **self;
- w.stop();
}
}
}
}
+#[test]
+fn test_simple_homed_udp_io_bind_then_move_task_then_home_and_close() {
+ use rt::sleeper_list::SleeperList;
+ use rt::work_queue::WorkQueue;
+ use rt::thread::Thread;
+ use rt::task::Task;
+ use rt::sched::{Shutdown, TaskFromFriend};
+ do run_in_bare_thread {
+ let sleepers = SleeperList::new();
+ let work_queue1 = WorkQueue::new();
+ let work_queue2 = WorkQueue::new();
+ let queues = ~[work_queue1.clone(), work_queue2.clone()];
+
+ let mut sched1 = ~Scheduler::new(~UvEventLoop::new(), work_queue1, queues.clone(),
+ sleepers.clone());
+ let mut sched2 = ~Scheduler::new(~UvEventLoop::new(), work_queue2, queues.clone(),
+ sleepers.clone());
+
+ let handle1 = Cell::new(sched1.make_handle());
+ let handle2 = Cell::new(sched2.make_handle());
+ let tasksFriendHandle = Cell::new(sched2.make_handle());
+
+ let on_exit: ~fn(bool) = |exit_status| {
+ handle1.take().send(Shutdown);
+ handle2.take().send(Shutdown);
+ rtassert!(exit_status);
+ };
+
+ let test_function: ~fn() = || {
+ let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+ let addr = next_test_ip4();
+ let maybe_socket = unsafe { (*io).udp_bind(addr) };
+ // this socket is bound to this event loop
+ assert!(maybe_socket.is_ok());
+
+ // block self on sched1
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ // unblock task
+ do task.wake().map_move |task| {
+ // send self to sched2
+ tasksFriendHandle.take().send(TaskFromFriend(task));
+ };
+ // sched1 should now sleep since it has nothing else to do
+ }
+ // sched2 will wake up and get the task
+ // as we do nothing else, the function ends and the socket goes out of scope
+ // sched2 will start to run the destructor
+ // the destructor will first block the task, set it's home as sched1, then enqueue it
+ // sched2 will dequeue the task, see that it has a home, and send it to sched1
+ // sched1 will wake up, exec the close function on the correct loop, and then we're done
+ };
+
+ let mut main_task = ~Task::new_root(&mut sched1.stack_pool, None, test_function);
+ main_task.death.on_exit = Some(on_exit);
+ let main_task = Cell::new(main_task);
+
+ let null_task = Cell::new(~do Task::new_root(&mut sched2.stack_pool, None) || {});
+
+ let sched1 = Cell::new(sched1);
+ let sched2 = Cell::new(sched2);
+
+ let thread1 = do Thread::start {
+ sched1.take().bootstrap(main_task.take());
+ };
+ let thread2 = do Thread::start {
+ sched2.take().bootstrap(null_task.take());
+ };
+
+ thread1.join();
+ thread2.join();
+ }
+}
+
+#[test]
+fn test_simple_homed_udp_io_bind_then_move_handle_then_home_and_close() {
+ use rt::sleeper_list::SleeperList;
+ use rt::work_queue::WorkQueue;
+ use rt::thread::Thread;
+ use rt::task::Task;
+ use rt::comm::oneshot;
+ use rt::sched::Shutdown;
+ do run_in_bare_thread {
+ let sleepers = SleeperList::new();
+ let work_queue1 = WorkQueue::new();
+ let work_queue2 = WorkQueue::new();
+ let queues = ~[work_queue1.clone(), work_queue2.clone()];
+
+ let mut sched1 = ~Scheduler::new(~UvEventLoop::new(), work_queue1, queues.clone(),
+ sleepers.clone());
+ let mut sched2 = ~Scheduler::new(~UvEventLoop::new(), work_queue2, queues.clone(),
+ sleepers.clone());
+
+ let handle1 = Cell::new(sched1.make_handle());
+ let handle2 = Cell::new(sched2.make_handle());
+
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
+
+ let body1: ~fn() = || {
+ let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+ let addr = next_test_ip4();
+ let socket = unsafe { (*io).udp_bind(addr) };
+ assert!(socket.is_ok());
+ chan.take().send(socket);
+ };
+
+ let body2: ~fn() = || {
+ let socket = port.take().recv();
+ assert!(socket.is_ok());
+ /* The socket goes out of scope and the destructor is called.
+ * The destructor:
+ * - sends itself back to sched1
+ * - frees the socket
+ * - resets the home of the task to whatever it was previously
+ */
+ };
+
+ let on_exit: ~fn(bool) = |exit| {
+ handle1.take().send(Shutdown);
+ handle2.take().send(Shutdown);
+ rtassert!(exit);
+ };
+
+ let task1 = Cell::new(~Task::new_root(&mut sched1.stack_pool, None, body1));
+
+ let mut task2 = ~Task::new_root(&mut sched2.stack_pool, None, body2);
+ task2.death.on_exit = Some(on_exit);
+ let task2 = Cell::new(task2);
+
+ let sched1 = Cell::new(sched1);
+ let sched2 = Cell::new(sched2);
+
+ let thread1 = do Thread::start {
+ sched1.take().bootstrap(task1.take());
+ };
+ let thread2 = do Thread::start {
+ sched2.take().bootstrap(task2.take());
+ };
+
+ thread1.join();
+ thread2.join();
+ }
+}
+
#[test]
fn test_simple_tcp_server_and_client() {
do run_in_newsched_task {
}
}
+#[test]
+fn test_simple_tcp_server_and_client_on_diff_threads() {
+ use rt::sleeper_list::SleeperList;
+ use rt::work_queue::WorkQueue;
+ use rt::thread::Thread;
+ use rt::task::Task;
+ use rt::sched::{Shutdown};
+ do run_in_bare_thread {
+ let sleepers = SleeperList::new();
+
+ let server_addr = next_test_ip4();
+ let client_addr = server_addr.clone();
+
+ let server_work_queue = WorkQueue::new();
+ let client_work_queue = WorkQueue::new();
+ let queues = ~[server_work_queue.clone(), client_work_queue.clone()];
+
+ let mut server_sched = ~Scheduler::new(~UvEventLoop::new(), server_work_queue,
+ queues.clone(), sleepers.clone());
+ let mut client_sched = ~Scheduler::new(~UvEventLoop::new(), client_work_queue,
+ queues.clone(), sleepers.clone());
+
+ let server_handle = Cell::new(server_sched.make_handle());
+ let client_handle = Cell::new(client_sched.make_handle());
+
+ let server_on_exit: ~fn(bool) = |exit_status| {
+ server_handle.take().send(Shutdown);
+ rtassert!(exit_status);
+ };
+
+ let client_on_exit: ~fn(bool) = |exit_status| {
+ client_handle.take().send(Shutdown);
+ rtassert!(exit_status);
+ };
+
+ let server_fn: ~fn() = || {
+ let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+ let mut listener = unsafe { (*io).tcp_bind(server_addr).unwrap() };
+ let mut stream = listener.accept().unwrap();
+ let mut buf = [0, .. 2048];
+ let nread = stream.read(buf).unwrap();
+ assert_eq!(nread, 8);
+ for i in range(0u, nread) {
+ assert_eq!(buf[i], i as u8);
+ }
+ };
+
+ let client_fn: ~fn() = || {
+ let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+ let mut stream = unsafe { (*io).tcp_connect(client_addr) };
+ while stream.is_err() {
+ stream = unsafe { (*io).tcp_connect(client_addr) };
+ }
+ stream.unwrap().write([0, 1, 2, 3, 4, 5, 6, 7]);
+ };
+
+ let mut server_task = ~Task::new_root(&mut server_sched.stack_pool, None, server_fn);
+ server_task.death.on_exit = Some(server_on_exit);
+ let server_task = Cell::new(server_task);
+
+ let mut client_task = ~Task::new_root(&mut client_sched.stack_pool, None, client_fn);
+ client_task.death.on_exit = Some(client_on_exit);
+ let client_task = Cell::new(client_task);
+
+ let server_sched = Cell::new(server_sched);
+ let client_sched = Cell::new(client_sched);
+
+ let server_thread = do Thread::start {
+ server_sched.take().bootstrap(server_task.take());
+ };
+ let client_thread = do Thread::start {
+ client_sched.take().bootstrap(client_task.take());
+ };
+
+ server_thread.join();
+ client_thread.join();
+ }
+}
+
#[test]
fn test_simple_udp_server_and_client() {
do run_in_newsched_task {
}
}
-fn test_timer_sleep_simple_impl() {
- unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
- let timer = (*io).timer_init();
- match timer {
- Ok(t) => t.sleep(1),
- Err(_) => assert!(false)
- }
- }
-}
#[test]
fn test_timer_sleep_simple() {
do run_in_newsched_task {
- test_timer_sleep_simple_impl();
+ unsafe {
+ let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let timer = (*io).timer_init();
+ do timer.map_move |mut t| { t.sleep(1) };
+ }
}
}
* There are also a collection of helper functions to ease interacting
* with the low-level API.
*
- * As new functionality, existant in uv.h, is added to the rust stdlib,
+ * As new functionality, existent in uv.h, is added to the rust stdlib,
* the mappings should be added in this module.
*/
}
pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX);
let size = rust_uv_handle_size(handle as uint);
let p = malloc(size);
}
pub unsafe fn free_handle(v: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
free(v)
}
pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX);
let size = rust_uv_req_size(req as uint);
let p = malloc(size);
}
pub unsafe fn free_req(v: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
free(v)
}
#[test]
fn handle_sanity_check() {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
assert_eq!(UV_HANDLE_TYPE_MAX as uint, rust_uv_handle_type_max());
}
}
#[test]
+#[fixed_stack_segment]
+#[inline(never)]
fn request_sanity_check() {
unsafe {
assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max());
}
}
+// XXX Event loops ignore SIGPIPE by default.
pub unsafe fn loop_new() -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_loop_new();
}
pub unsafe fn loop_delete(loop_handle: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_loop_delete(loop_handle);
}
pub unsafe fn run(loop_handle: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_run(loop_handle);
}
pub unsafe fn close<T>(handle: *T, cb: *u8) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_close(handle as *c_void, cb);
}
pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_walk(loop_handle, cb, arg);
}
pub unsafe fn idle_new() -> *uv_idle_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_new()
}
pub unsafe fn idle_delete(handle: *uv_idle_t) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_delete(handle)
}
pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_init(loop_handle, handle)
}
pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_start(handle, cb)
}
pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_stop(handle)
}
pub unsafe fn udp_init(loop_handle: *uv_loop_t, handle: *uv_udp_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_init(loop_handle, handle);
}
pub unsafe fn udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_bind(server, addr, flags);
}
pub unsafe fn udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_bind6(server, addr, flags);
}
pub unsafe fn udp_send<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
addr: *sockaddr_in, cb: uv_udp_send_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
pub unsafe fn udp_send6<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_udp_send6(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb,
on_recv: uv_udp_recv_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_recv_start(server, on_alloc, on_recv);
}
pub unsafe fn udp_recv_stop(server: *uv_udp_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_recv_stop(server);
}
pub unsafe fn get_udp_handle_from_send_req(send_req: *uv_udp_send_t) -> *uv_udp_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_udp_handle_from_send_req(send_req);
}
-pub unsafe fn udp_get_sockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int {
+pub unsafe fn udp_getsockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_getsockname(handle, name);
}
pub unsafe fn udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char,
interface_addr: *c_char, membership: uv_membership) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_membership(handle, multicast_addr, interface_addr, membership as c_int);
}
pub unsafe fn udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_multicast_loop(handle, on);
}
pub unsafe fn udp_set_multicast_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_multicast_ttl(handle, ttl);
}
pub unsafe fn udp_set_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_ttl(handle, ttl);
}
pub unsafe fn udp_set_broadcast(handle: *uv_udp_t, on: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_broadcast(handle, on);
}
pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_init(loop_handle, handle);
}
pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in, after_connect_cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
}
pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in6, after_connect_cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
}
pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr);
}
pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr);
}
pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_getpeername(tcp_handle_ptr, name);
}
pub unsafe fn tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_getsockname(handle, name);
}
pub unsafe fn tcp_nodelay(handle: *uv_tcp_t, enable: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_nodelay(handle, enable);
}
pub unsafe fn tcp_keepalive(handle: *uv_tcp_t, enable: c_int, delay: c_uint) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_keepalive(handle, enable, delay);
}
pub unsafe fn tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_simultaneous_accepts(handle, enable);
}
pub unsafe fn listen<T>(stream: *T, backlog: c_int, cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_listen(stream as *c_void, backlog, cb);
}
pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_accept(server as *c_void, client as *c_void);
}
pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
}
pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: uv_alloc_cb, on_read: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_read_start(stream as *c_void, on_alloc, on_read);
}
pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_read_stop(stream as *c_void);
}
pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_last_error(loop_handle);
}
pub unsafe fn strerror(err: *uv_err_t) -> *c_char {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_strerror(err);
}
pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_err_name(err);
}
pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_async_init(loop_handle, async_handle, cb);
}
pub unsafe fn async_send(async_handle: *uv_async_t) {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_async_send(async_handle);
}
pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
let out_buf = uv_buf_t { base: ptr::null(), len: 0 as size_t };
let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf);
rust_uv_buf_init(out_buf_ptr, input, len as size_t);
}
pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_timer_init(loop_ptr, timer_ptr);
}
pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64,
repeat: u64) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_timer_start(timer_ptr, cb, timeout, repeat);
}
pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_timer_stop(timer_ptr);
}
pub unsafe fn is_ip4_addr(addr: *sockaddr) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
match rust_uv_is_ipv4_sockaddr(addr) { 0 => false, _ => true }
}
pub unsafe fn is_ip6_addr(addr: *sockaddr) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
match rust_uv_is_ipv6_sockaddr(addr) { 0 => false, _ => true }
}
pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in {
- do ip.to_c_str().with_ref |ip_buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do ip.with_c_str |ip_buf| {
rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int)
}
}
pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 {
- do ip.to_c_str().with_ref |ip_buf| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do ip.with_c_str |ip_buf| {
rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int)
}
}
pub unsafe fn malloc_sockaddr_storage() -> *sockaddr_storage {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_malloc_sockaddr_storage()
}
pub unsafe fn free_sockaddr_storage(ss: *sockaddr_storage) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_free_sockaddr_storage(ss);
}
pub unsafe fn free_ip4_addr(addr: *sockaddr_in) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_free_ip4_addr(addr);
}
pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_free_ip6_addr(addr);
}
pub unsafe fn ip4_name(addr: *sockaddr_in, dst: *u8, size: size_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip4_name(addr, dst, size);
}
pub unsafe fn ip6_name(addr: *sockaddr_in6, dst: *u8, size: size_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip6_name(addr, dst, size);
}
pub unsafe fn ip4_port(addr: *sockaddr_in) -> c_uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip4_port(addr);
}
pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip6_port(addr);
}
// data access helpers
pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_loop_for_uv_handle(handle as *c_void);
}
pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_stream_handle_from_connect_req(connect);
}
pub unsafe fn get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_stream_handle_from_write_req(write_req);
}
pub unsafe fn get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_get_data_for_uv_loop(loop_ptr)
}
pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_set_data_for_uv_loop(loop_ptr, data);
}
pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_data_for_uv_handle(handle as *c_void);
}
pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void);
}
pub unsafe fn get_data_for_req<T>(req: *T) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_data_for_req(req as *c_void);
}
pub unsafe fn set_data_for_req<T, U>(req: *T, data: *U) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_set_data_for_req(req as *c_void, data as *c_void);
}
pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_base_from_buf(buf);
}
pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_len_from_buf(buf);
}
pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
* If this is Some(vec-of-names-and-values) then the new process will
* have an environment containing the given named values only.
*/
- env: Option<&'self [(~str, ~str)]>,
+ env: Option<~[(~str, ~str)]>,
/**
* If this is None then the new process will use the same initial working
in_fd: Option<c_int>,
/**
- * If this is None then a new pipe will be created for the new progam's
+ * If this is None then a new pipe will be created for the new program's
* output and Process.output() will provide a Reader to read from this pipe.
*
* If this is Some(file-descriptor) then the new process will write its output
out_fd: Option<c_int>,
/**
- * If this is None then a new pipe will be created for the new progam's
+ * If this is None then a new pipe will be created for the new program's
* error stream and Process.error() will provide a Reader to read from this pipe.
*
* If this is Some(file-descriptor) then the new process will write its error output
* * options - Options to configure the environment of the process,
* the working directory and the standard IO streams.
*/
- pub fn new(prog: &str, args: &[~str], options: ProcessOptions)
+ pub fn new(prog: &str, args: &[~str],
+ options: ProcessOptions)
-> Process {
+ #[fixed_stack_segment]; #[inline(never)];
+
let (in_pipe, in_fd) = match options.in_fd {
None => {
let pipe = os::pipe();
Some(fd) => (None, fd)
};
- let res = spawn_process_os(prog, args, options.env, options.dir,
+ let res = spawn_process_os(prog, args, options.env.clone(), options.dir,
in_fd, out_fd, err_fd);
unsafe {
* method does nothing.
*/
pub fn close_input(&mut self) {
+ #[fixed_stack_segment]; #[inline(never)];
match self.input {
Some(-1) | None => (),
Some(fd) => {
}
fn close_outputs(&mut self) {
+ #[fixed_stack_segment]; #[inline(never)];
fclose_and_null(&mut self.output);
fclose_and_null(&mut self.error);
fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
+ #[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
match *f_opt {
Some(f) if !f.is_null() => {
unsafe {
#[cfg(windows)]
fn killpid(pid: pid_t, _force: bool) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::funcs::extra::kernel32::TerminateProcess(
cast::transmute(pid), 1);
#[cfg(unix)]
fn killpid(pid: pid_t, force: bool) {
+ #[fixed_stack_segment]; #[inline(never)];
+
let signal = if force {
libc::consts::os::posix88::SIGKILL
} else {
#[cfg(windows)]
fn spawn_process_os(prog: &str, args: &[~str],
- env: Option<&[(~str, ~str)]>,
+ env: Option<~[(~str, ~str)]>,
dir: Option<&Path>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
use libc::consts::os::extra::{
do with_envp(env) |envp| {
do with_dirp(dir) |dirp| {
- do cmd.to_c_str().with_ref |cmdp| {
+ do cmd.with_c_str |cmdp| {
let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
ptr::mut_null(), ptr::mut_null(), TRUE,
0, envp, dirp, &mut si, &mut pi);
#[cfg(unix)]
fn spawn_process_os(prog: &str, args: &[~str],
- env: Option<&[(~str, ~str)]>,
+ env: Option<~[(~str, ~str)]>,
dir: Option<&Path>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
use libc::funcs::bsd44::getdtablesize;
}
#[cfg(unix)]
-fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
+fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
use vec;
// On posixy systems we can pass a char** for envp, which is a
}
#[cfg(windows)]
-fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
+fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
// On win32 we pass an "environment block" which is not a char**, but
// rather a concatenation of null-terminated k=v\0 sequences, with a final
// \0 to terminate.
fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
match d {
- Some(dir) => dir.to_c_str().with_ref(|buf| cb(buf)),
+ Some(dir) => dir.with_c_str(|buf| cb(buf)),
None => cb(ptr::null())
}
}
#[cfg(windows)]
fn free_handle(handle: *()) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
}
* Note that this is private to avoid race conditions on unix where if
* a user calls waitpid(some_process.get_id()) then some_process.finish()
* and some_process.destroy() and some_process.finalize() will then either
- * operate on a none-existant process or, even worse, on a newer process
+ * operate on a none-existent process or, even worse, on a newer process
* with the same id.
*/
fn waitpid(pid: pid_t) -> int {
#[cfg(windows)]
fn waitpid_os(pid: pid_t) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
use libc::consts::os::extra::{
#[cfg(unix)]
fn waitpid_os(pid: pid_t) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::funcs::posix01::wait::*;
use path::Path;
use run;
use str;
+ use unstable::running_on_valgrind;
#[test]
#[cfg(windows)]
}
fn readclose(fd: c_int) -> ~str {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let file = os::fdopen(fd);
let reader = io::FILE_reader(file, false);
}
#[cfg(unix,not(target_os="android"))]
- fn run_env(env: Option<&[(~str, ~str)]>) -> run::Process {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
run::Process::new("env", [], run::ProcessOptions {
env: env,
.. run::ProcessOptions::new()
})
}
#[cfg(unix,target_os="android")]
- fn run_env(env: Option<&[(~str, ~str)]>) -> run::Process {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions {
env: env,
.. run::ProcessOptions::new()
}
#[cfg(windows)]
- fn run_env(env: Option<&[(~str, ~str)]>) -> run::Process {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions {
env: env,
.. run::ProcessOptions::new()
let mut new_env = os::env();
new_env.push((~"RUN_TEST_NEW_ENV", ~"123"));
- let mut prog = run_env(Some(new_env.slice(0, new_env.len())));
+ let mut prog = run_env(Some(new_env));
let output = str::from_bytes(prog.finish_with_output().output);
assert!(output.contains("RUN_TEST_NEW_ENV=123"));
}
-
- fn running_on_valgrind() -> bool {
- unsafe { rust_running_on_valgrind() != 0 }
- }
-
- extern {
- fn rust_running_on_valgrind() -> uintptr_t;
- }
}
use rt::local::Local;
use rt::rtio::EventLoop;
use task;
+use unstable::finally::Finally;
use vec::{OwnedVector, MutableVector};
/// Trait for message-passing primitives that can be select()ed on.
let p = Cell::new(p);
let c = Cell::new(c);
- let sched = Local::take::<Scheduler>();
- do sched.deschedule_running_task_and_then |sched, task| {
- let task_handles = task.make_selectable(ports.len());
-
- for (index, (port, task_handle)) in
- ports.mut_iter().zip(task_handles.move_iter()).enumerate() {
- // If one of the ports has data by now, it will wake the handle.
- if port.block_on(sched, task_handle) {
- ready_index = index;
- break;
+ do (|| {
+ let c = Cell::new(c.take());
+ let sched = Local::take::<Scheduler>();
+ do sched.deschedule_running_task_and_then |sched, task| {
+ let task_handles = task.make_selectable(ports.len());
+
+ for (index, (port, task_handle)) in
+ ports.mut_iter().zip(task_handles.move_iter()).enumerate() {
+ // If one of the ports has data by now, it will wake the handle.
+ if port.block_on(sched, task_handle) {
+ ready_index = index;
+ break;
+ }
}
- }
- let c = Cell::new(c.take());
- do sched.event_loop.callback { c.take().send_deferred(()) }
+ let c = Cell::new(c.take());
+ do sched.event_loop.callback { c.take().send_deferred(()) }
+ }
+ }).finally {
+ let p = Cell::new(p.take());
+ // Unkillable is necessary not because getting killed is dangerous here,
+ // but to force the recv not to use the same kill-flag that we used for
+ // selecting. Otherwise a user-sender could spuriously wakeup us here.
+ do task::unkillable { p.take().recv(); }
}
- // Unkillable is necessary not because getting killed is dangerous here,
- // but to force the recv not to use the same kill-flag that we used for
- // selecting. Otherwise a user-sender could spuriously wakeup us here.
- do task::unkillable { p.take().recv(); }
-
// Task resumes. Now unblock ourselves from all the ports we blocked on.
// If the success index wasn't reset, 'take' will just take all of them.
// Iterate in reverse so the 'earliest' index that's ready gets returned.
let (c2, p3, c4) = x.take();
p3.recv(); // handshake parent
c4.send(()); // normal receive
- task::yield();
+ task::deschedule();
c2.send(()); // select receive
}
if send_on_chans.contains(&i) {
let c = Cell::new(c);
do spawntask_random {
- task::yield();
+ task::deschedule();
c.take().send(());
}
}
#[path = "num/f32.rs"] pub mod f32;
#[path = "num/f64.rs"] pub mod f64;
-pub mod nil;
+pub mod unit;
pub mod bool;
pub mod char;
pub mod tuple;
pub use fmt;
pub use to_bytes;
}
+
use cast;
use char;
use char::Char;
-use clone::Clone;
+use clone::{Clone, DeepClone};
use container::{Container, Mutable};
use iter::Times;
use iterator::{Iterator, FromIterator, Extendable};
}
}
-/// An iterator over the start and end indicies of the matches of a
+/// An iterator over the start and end indices of the matches of a
/// substring within a larger string
#[deriving(Clone)]
pub struct MatchesIndexIterator<'self> {
/// Sets the length of a string
///
/// This will explicitly set the size of the string, without actually
- /// modifing its buffers, so it is up to the caller to ensure that
+ /// modifying its buffers, so it is up to the caller to ensure that
/// the string is actually the specified size.
#[inline]
pub unsafe fn set_len(s: &mut ~str, new_len: uint) {
/// Work with `self` as a slice.
fn as_slice<'a>(&'a self) -> &'a str;
- /// Convert `self` into a ~str.
+ /// Convert `self` into a ~str, not making a copy if possible
fn into_owned(self) -> ~str;
}
}
}
+impl DeepClone for ~str {
+ #[inline]
+ fn deep_clone(&self) -> ~str {
+ self.to_owned()
+ }
+}
+
impl Clone for @str {
#[inline]
fn clone(&self) -> @str {
}
}
-impl<T: Iterator<char>> FromIterator<char, T> for ~str {
+impl DeepClone for @str {
+ #[inline]
+ fn deep_clone(&self) -> @str {
+ *self
+ }
+}
+
+impl FromIterator<char> for ~str {
#[inline]
- fn from_iterator(iterator: &mut T) -> ~str {
+ fn from_iterator<T: Iterator<char>>(iterator: &mut T) -> ~str {
let (lower, _) = iterator.size_hint();
let mut buf = with_capacity(lower);
buf.extend(iterator);
}
}
-impl<T: Iterator<char>> Extendable<char, T> for ~str {
+impl Extendable<char> for ~str {
#[inline]
- fn extend(&mut self, iterator: &mut T) {
+ fn extend<T: Iterator<char>>(&mut self, iterator: &mut T) {
let (lower, _) = iterator.size_hint();
let reserve = lower + self.len();
self.reserve_at_least(reserve);
#[test]
fn test_map() {
+ #[fixed_stack_segment]; #[inline(never)];
assert_eq!(~"", "".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
assert_eq!(~"YMCA", "ymca".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
}
use option::{Some, None};
/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
-#[deriving(Clone, Eq)]
+#[deriving(Clone, Eq, Ord, TotalOrd, TotalEq)]
pub struct Ascii { priv chr: u8 }
impl Ascii {
}
}
-
-/// Convert the string to ASCII upper case:
-/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
-/// but non-ASCII letters are unchanged.
-#[inline]
-pub fn to_ascii_upper(string: &str) -> ~str {
- map_bytes(string, ASCII_UPPER_MAP)
+/// Extension methods for ASCII-subset only operations on strings
+pub trait StrAsciiExt {
+ /// Convert the string to ASCII upper case:
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ fn to_ascii_upper(&self) -> ~str;
+
+ /// Convert the string to ASCII lower case:
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ fn to_ascii_lower(&self) -> ~str;
+
+ /// Check that two strings are an ASCII case-insensitive match.
+ /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
+ /// but without allocating and copying temporary strings.
+ fn eq_ignore_ascii_case(&self, other: &str) -> bool;
}
-/// Convert the string to ASCII lower case:
-/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
-/// but non-ASCII letters are unchanged.
-#[inline]
-pub fn to_ascii_lower(string: &str) -> ~str {
- map_bytes(string, ASCII_LOWER_MAP)
+impl<'self> StrAsciiExt for &'self str {
+ #[inline]
+ fn to_ascii_upper(&self) -> ~str {
+ map_bytes(*self, ASCII_UPPER_MAP)
+ }
+
+ #[inline]
+ fn to_ascii_lower(&self) -> ~str {
+ map_bytes(*self, ASCII_LOWER_MAP)
+ }
+
+ #[inline]
+ fn eq_ignore_ascii_case(&self, other: &str) -> bool {
+ self.len() == other.len() && self.as_bytes().iter().zip(other.as_bytes().iter()).all(
+ |(byte_self, byte_other)| ASCII_LOWER_MAP[*byte_self] == ASCII_LOWER_MAP[*byte_other])
+ }
}
#[inline]
result
}
-/// Check that two strings are an ASCII case-insensitive match.
-/// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
-/// but without allocating and copying temporary strings.
-#[inline]
-pub fn eq_ignore_ascii_case(a: &str, b: &str) -> bool {
- a.len() == b.len() && a.as_bytes().iter().zip(b.as_bytes().iter()).all(
- |(byte_a, byte_b)| ASCII_LOWER_MAP[*byte_a] == ASCII_LOWER_MAP[*byte_b])
-}
-
static ASCII_LOWER_MAP: &'static [u8] = &[
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
#[cfg(test)]
mod tests {
use super::*;
- use to_bytes::ToBytes;
use str::from_char;
macro_rules! v2ascii (
#[test]
fn test_ascii_to_bytes() {
- assert_eq!(v2ascii!(~[40, 32, 59]).to_bytes(false), ~[40u8, 32u8, 59u8]);
assert_eq!(v2ascii!(~[40, 32, 59]).into_bytes(), ~[40u8, 32u8, 59u8]);
}
#[test]
fn test_to_ascii_upper() {
- assert_eq!(to_ascii_upper("url()URL()uRl()ürl"), ~"URL()URL()URL()üRL");
- assert_eq!(to_ascii_upper("hıKß"), ~"HıKß");
+ assert_eq!("url()URL()uRl()ürl".to_ascii_upper(), ~"URL()URL()URL()üRL");
+ assert_eq!("hıKß".to_ascii_upper(), ~"HıKß");
let mut i = 0;
while i <= 500 {
let c = i as char;
let upper = if 'a' <= c && c <= 'z' { c + 'A' - 'a' } else { c };
- assert_eq!(to_ascii_upper(from_char(i as char)), from_char(upper))
+ assert_eq!(from_char(i as char).to_ascii_upper(), from_char(upper))
i += 1;
}
}
#[test]
fn test_to_ascii_lower() {
- assert_eq!(to_ascii_lower("url()URL()uRl()Ürl"), ~"url()url()url()Ürl");
+ assert_eq!("url()URL()uRl()Ürl".to_ascii_lower(), ~"url()url()url()Ürl");
// Dotted capital I, Kelvin sign, Sharp S.
- assert_eq!(to_ascii_lower("HİKß"), ~"hİKß");
+ assert_eq!("HİKß".to_ascii_lower(), ~"hİKß");
let mut i = 0;
while i <= 500 {
let c = i as char;
let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c };
- assert_eq!(to_ascii_lower(from_char(i as char)), from_char(lower))
+ assert_eq!(from_char(i as char).to_ascii_lower(), from_char(lower))
i += 1;
}
}
-
#[test]
fn test_eq_ignore_ascii_case() {
- assert!(eq_ignore_ascii_case("url()URL()uRl()Ürl", "url()url()url()Ürl"));
- assert!(!eq_ignore_ascii_case("Ürl", "ürl"));
+ assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
+ assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
// Dotted capital I, Kelvin sign, Sharp S.
- assert!(eq_ignore_ascii_case("HİKß", "hİKß"));
- assert!(!eq_ignore_ascii_case("İ", "i"));
- assert!(!eq_ignore_ascii_case("K", "k"));
- assert!(!eq_ignore_ascii_case("ß", "s"));
+ assert!("HİKß".eq_ignore_ascii_case("hİKß"));
+ assert!(!"İ".eq_ignore_ascii_case("i"));
+ assert!(!"K".eq_ignore_ascii_case("k"));
+ assert!(!"ß".eq_ignore_ascii_case("s"));
let mut i = 0;
while i <= 500 {
let c = i as char;
let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c };
- assert!(eq_ignore_ascii_case(from_char(i as char), from_char(lower)));
+ assert!(from_char(i as char).eq_ignore_ascii_case(from_char(lower)));
i += 1;
}
}
impl FailWithCause for ~str {
fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! {
- do cause.to_c_str().with_ref |msg_buf| {
- do file.to_c_str().with_ref |file_buf| {
+ do cause.with_c_str |msg_buf| {
+ do file.with_c_str |file_buf| {
begin_unwind_(msg_buf, file_buf, line as libc::size_t)
}
}
impl FailWithCause for &'static str {
fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
- do cause.to_c_str().with_ref |msg_buf| {
- do file.to_c_str().with_ref |file_buf| {
+ do cause.with_c_str |msg_buf| {
+ do file.with_c_str |file_buf| {
begin_unwind_(msg_buf, file_buf, line as libc::size_t)
}
}
// above.
let data = match util::replace(entry, None) {
Some((_, data, _)) => data,
- None => libc::abort(),
+ None => abort(),
};
// Move `data` into transmute to get out the memory that it
}
}
}
- _ => libc::abort()
+ _ => abort()
}
// n.b. 'data' and 'loans' are both invalid pointers at the point
if return_loan {
match map[i] {
Some((_, _, ref mut loan)) => { *loan = NoLoan; }
- None => { libc::abort(); }
+ None => { abort(); }
}
}
return ret;
}
}
+fn abort() -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ unsafe { libc::abort() }
+}
+
pub unsafe fn local_set<T: 'static>(handle: Handle,
key: local_data::Key<T>,
data: T) {
spawn::spawn_raw(opts, f);
}
- /// Runs a task, while transfering ownership of one argument to the child.
+ /// Runs a task, while transferring ownership of one argument to the child.
pub fn spawn_with<A:Send>(&mut self, arg: A, f: ~fn(v: A)) {
let arg = Cell::new(arg);
do self.spawn {
pub fn spawn_with<A:Send>(arg: A, f: ~fn(v: A)) {
/*!
- * Runs a task, while transfering ownership of one argument to the
+ * Runs a task, while transferring ownership of one argument to the
* child.
*
- * This is useful for transfering ownership of noncopyables to
+ * This is useful for transferring ownership of noncopyables to
* another task.
*
* This function is equivalent to `task().spawn_with(arg, f)`.
}
}
-pub fn yield() {
+pub fn deschedule() {
//! Yield control to the task scheduler
use rt::local::Local;
*
* ~~~
* do task::unkillable {
- * // detach / yield / destroy must all be called together
+ * // detach / deschedule / destroy must all be called together
* rustrt::rust_port_detach(po);
* // This must not result in the current task being killed
- * task::yield();
+ * task::deschedule();
* rustrt::rust_port_destroy(po);
* }
* ~~~
let ch = ch.clone();
do spawn_unlinked {
// Give middle task a chance to fail-but-not-kill-us.
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
ch.send(()); // If killed first, grandparent hangs.
}
fail!(); // Shouldn't kill either (grand)parent or (grand)child.
do run_in_newsched_task {
do spawn_supervised { fail!(); }
// Give child a chance to fail-but-not-kill-us.
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
}
}
#[ignore(reason = "linked failure")]
do spawn_supervised {
do spawn_supervised { block_forever(); }
}
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
fail!();
};
assert!(result.is_err());
do spawn_supervised {
do spawn { block_forever(); } // linked
}
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
fail!();
};
assert!(result.is_err());
do spawn { // linked
do spawn_supervised { block_forever(); }
}
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
fail!();
};
assert!(result.is_err());
do spawn { // linked
do spawn { block_forever(); } // linked
}
- do 16.times { task::yield(); }
+ do 16.times { task::deschedule(); }
fail!();
};
assert!(result.is_err());
mod testrt {
use libc;
- #[nolink]
- extern {
- pub fn rust_dbg_lock_create() -> *libc::c_void;
- pub fn rust_dbg_lock_destroy(lock: *libc::c_void);
- pub fn rust_dbg_lock_lock(lock: *libc::c_void);
- pub fn rust_dbg_lock_unlock(lock: *libc::c_void);
- pub fn rust_dbg_lock_wait(lock: *libc::c_void);
- pub fn rust_dbg_lock_signal(lock: *libc::c_void);
- }
+ externfn!(fn rust_dbg_lock_create() -> *libc::c_void)
+ externfn!(fn rust_dbg_lock_destroy(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_lock(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_unlock(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_wait(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_signal(lock: *libc::c_void))
}
#[test]
// We want to do this after failing
do spawn_unlinked {
- do 10.times { yield() }
+ do 10.times { deschedule() }
ch.send(());
}
do spawn {
- yield();
+ deschedule();
// We want to fail after the unkillable task
// blocks on recv
fail!();
// We want to do this after failing
do spawn_unlinked || {
- do 10.times { yield() }
+ do 10.times { deschedule() }
ch.send(());
}
do spawn {
- yield();
+ deschedule();
// We want to fail after the unkillable task
// blocks on recv
fail!();
t.unlinked();
t.watched();
do t.spawn {
- task::yield();
+ task::deschedule();
fail!();
}
}
t.unwatched();
do t.spawn {
p3.recv();
- task::yield();
+ task::deschedule();
fail!();
}
c3.send(());
*/
use cast;
+use container::Container;
use io;
use io::Writer;
use iterator::Iterator;
use option::{None, Option, Some};
-use str::StrSlice;
-use vec::ImmutableVector;
+use str::{Str, StrSlice};
+use vec::{Vector, ImmutableVector};
pub type Cb<'self> = &'self fn(buf: &[u8]) -> bool;
-/**
- * A trait to implement in order to make a type hashable;
- * This works in combination with the trait `Hash::Hash`, and
- * may in the future be merged with that trait or otherwise
- * modified when default methods and trait inheritence are
- * completed.
- */
+///
+/// A trait to implement in order to make a type hashable;
+/// This works in combination with the trait `std::hash::Hash`, and
+/// may in the future be merged with that trait or otherwise
+/// modified when default methods and trait inheritance are
+/// completed.
+///
+/// IterBytes should be implemented so that the extent of the
+/// produced byte stream can be discovered, given the original
+/// type.
+/// For example, the IterBytes implementation for vectors emits
+/// its length first, and enums should emit their discriminant.
+///
pub trait IterBytes {
- /**
- * Call the provided callback `f` one or more times with
- * byte-slices that should be used when computing a hash
- * value or otherwise "flattening" the structure into
- * a sequence of bytes. The `lsb0` parameter conveys
- * whether the caller is asking for little-endian bytes
- * (`true`) or big-endian (`false`); this should only be
- * relevant in implementations that represent a single
- * multi-byte datum such as a 32 bit integer or 64 bit
- * floating-point value. It can be safely ignored for
- * larger structured types as they are usually processed
- * left-to-right in declaration order, regardless of
- * underlying memory endianness.
- */
+ /// Call the provided callback `f` one or more times with
+ /// byte-slices that should be used when computing a hash
+ /// value or otherwise "flattening" the structure into
+ /// a sequence of bytes. The `lsb0` parameter conveys
+ /// whether the caller is asking for little-endian bytes
+ /// (`true`) or big-endian (`false`); this should only be
+ /// relevant in implementations that represent a single
+ /// multi-byte datum such as a 32 bit integer or 64 bit
+ /// floating-point value. It can be safely ignored for
+ /// larger structured types as they are usually processed
+ /// left-to-right in declaration order, regardless of
+ /// underlying memory endianness.
+ ///
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool;
}
impl<'self,A:IterBytes> IterBytes for &'self [A] {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ self.len().iter_bytes(lsb0, |b| f(b)) &&
self.iter().advance(|elt| elt.iter_bytes(lsb0, |b| f(b)))
}
}
-impl<A:IterBytes,B:IterBytes> IterBytes for (A,B) {
- #[inline]
- fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
- match *self {
- (ref a, ref b) => { a.iter_bytes(lsb0, |b| f(b)) &&
- b.iter_bytes(lsb0, |b| f(b)) }
- }
- }
-}
-
-impl<A:IterBytes,B:IterBytes,C:IterBytes> IterBytes for (A,B,C) {
- #[inline]
- fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
- match *self {
- (ref a, ref b, ref c) => {
- a.iter_bytes(lsb0, |b| f(b)) &&
- b.iter_bytes(lsb0, |b| f(b)) &&
- c.iter_bytes(lsb0, |b| f(b))
- }
+impl<A: IterBytes> IterBytes for (A, ) {
+ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ match *self {
+ (ref a, ) => a.iter_bytes(lsb0, |b| f(b))
+ }
}
- }
}
-// Move this to vec, probably.
-fn borrow<'x,A>(a: &'x [A]) -> &'x [A] {
- a
-}
+macro_rules! iter_bytes_tuple(
+ ($($A:ident),+) => (
+ impl<$($A: IterBytes),+> IterBytes for ($($A),+) {
+ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ match *self {
+ ($(ref $A),+) => {
+ $(
+ $A .iter_bytes(lsb0, |b| f(b))
+ )&&+
+ }
+ }
+ }
+ }
+ )
+)
+
+iter_bytes_tuple!(A, B)
+iter_bytes_tuple!(A, B, C)
+iter_bytes_tuple!(A, B, C, D)
+iter_bytes_tuple!(A, B, C, D, E)
+iter_bytes_tuple!(A, B, C, D, E, F)
+iter_bytes_tuple!(A, B, C, D, E, F, G)
+iter_bytes_tuple!(A, B, C, D, E, F, G, H)
impl<A:IterBytes> IterBytes for ~[A] {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
- borrow(*self).iter_bytes(lsb0, f)
+ self.as_slice().iter_bytes(lsb0, f)
}
}
impl<A:IterBytes> IterBytes for @[A] {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
- borrow(*self).iter_bytes(lsb0, f)
+ self.as_slice().iter_bytes(lsb0, f)
}
}
impl<'self> IterBytes for &'self str {
#[inline]
fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool {
- f(self.as_bytes())
+ // Terminate the string with a byte that does not appear in UTF-8
+ f(self.as_bytes()) && f([0xFF])
}
}
impl IterBytes for ~str {
#[inline]
- fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool {
- // this should possibly include the null terminator, but that
- // breaks .find_equiv on hashmaps.
- f(self.as_bytes())
+ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ self.as_slice().iter_bytes(lsb0, f)
}
}
impl IterBytes for @str {
#[inline]
- fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool {
- // this should possibly include the null terminator, but that
- // breaks .find_equiv on hashmaps.
- f(self.as_bytes())
+ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ self.as_slice().iter_bytes(lsb0, f)
}
}
/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
- /// Cosume and convert to a string.
+ /// Consume and convert to a string.
fn into_str(self) -> ~str;
}
}
}
-impl<T, Iter: Iterator<(uint, T)>> FromIterator<(uint, T), Iter> for TrieMap<T> {
- fn from_iterator(iter: &mut Iter) -> TrieMap<T> {
+impl<T> FromIterator<(uint, T)> for TrieMap<T> {
+ fn from_iterator<Iter: Iterator<(uint, T)>>(iter: &mut Iter) -> TrieMap<T> {
let mut map = TrieMap::new();
map.extend(iter);
map
}
}
-impl<T, Iter: Iterator<(uint, T)>> Extendable<(uint, T), Iter> for TrieMap<T> {
- fn extend(&mut self, iter: &mut Iter) {
+impl<T> Extendable<(uint, T)> for TrieMap<T> {
+ fn extend<Iter: Iterator<(uint, T)>>(&mut self, iter: &mut Iter) {
for (k, v) in *iter {
self.insert(k, v);
}
}
}
-impl<Iter: Iterator<uint>> FromIterator<uint, Iter> for TrieSet {
- fn from_iterator(iter: &mut Iter) -> TrieSet {
+impl FromIterator<uint> for TrieSet {
+ fn from_iterator<Iter: Iterator<uint>>(iter: &mut Iter) -> TrieSet {
let mut set = TrieSet::new();
set.extend(iter);
set
}
}
-impl<Iter: Iterator<uint>> Extendable<uint, Iter> for TrieSet {
- fn extend(&mut self, iter: &mut Iter) {
+impl Extendable<uint> for TrieSet {
+ fn extend<Iter: Iterator<uint>>(&mut self, iter: &mut Iter) {
for elem in *iter {
self.insert(elem);
}
#[allow(missing_doc)];
use clone::Clone;
-use vec;
-use vec::ImmutableVector;
-use iterator::Iterator;
pub use self::inner::*;
}
}
-pub trait ExtendedTupleOps<A,B> {
- fn zip(&self) -> ~[(A, B)];
- fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C];
-}
-
-impl<'self,
- A:Clone,
- B:Clone>
- ExtendedTupleOps<A,B> for
- (&'self [A], &'self [B]) {
- #[inline]
- fn zip(&self) -> ~[(A, B)] {
- match *self {
- (ref a, ref b) => {
- vec::zip_slice(*a, *b)
- }
- }
- }
-
- #[inline]
- fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] {
- match *self {
- (ref a, ref b) => {
- a.iter().zip(b.iter()).map(|(aa, bb)| f(aa, bb)).collect()
- }
- }
- }
-}
-
-impl<A:Clone, B:Clone> ExtendedTupleOps<A,B> for (~[A], ~[B]) {
- #[inline]
- fn zip(&self) -> ~[(A, B)] {
- match *self {
- (ref a, ref b) => {
- vec::zip_slice(*a, *b)
- }
- }
- }
-
- #[inline]
- fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] {
- match *self {
- (ref a, ref b) => {
- a.iter().zip(b.iter()).map(|(aa, bb)| f(aa, bb)).collect()
- }
- }
- }
-}
-
// macro for implementing n-ary tuple functions and operations
macro_rules! tuple_impls {
--- /dev/null
+// 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.
+
+/*!
+
+Functions for the unit type.
+
+*/
+
+#[cfg(not(test))]
+use prelude::*;
+#[cfg(not(test))]
+use num::Zero;
+
+#[cfg(not(test))]
+impl Eq for () {
+ #[inline]
+ fn eq(&self, _other: &()) -> bool { true }
+ #[inline]
+ fn ne(&self, _other: &()) -> bool { false }
+}
+
+#[cfg(not(test))]
+impl Ord for () {
+ #[inline]
+ fn lt(&self, _other: &()) -> bool { false }
+}
+
+#[cfg(not(test))]
+impl TotalOrd for () {
+ #[inline]
+ fn cmp(&self, _other: &()) -> Ordering { Equal }
+}
+
+#[cfg(not(test))]
+impl TotalEq for () {
+ #[inline]
+ fn equals(&self, _other: &()) -> bool { true }
+}
+
+#[cfg(not(test))]
+impl Zero for () {
+ #[inline]
+ fn zero() -> () { () }
+ #[inline]
+ fn is_zero(&self) -> bool { true }
+}
}
/**
- * A signed atomic integer type, supporting basic atomic aritmetic operations
+ * A signed atomic integer type, supporting basic atomic arithmetic operations
*/
pub struct AtomicInt {
priv v: int
}
/**
- * An unsigned atomic integer type, supporting basic atomic aritmetic operations
+ * An unsigned atomic integer type, supporting basic atomic arithmetic operations
*/
pub struct AtomicUint {
priv v: uint
* A fence 'A' which has `Release` ordering semantics, synchronizes with a
* fence 'B' with (at least) `Acquire` semantics, if and only if there exists
* atomic operations X and Y, both operating on some atomic object 'M' such
- * that A is sequenced before X, Y is synchronized before B and Y obsevers
+ * that A is sequenced before X, Y is synchronized before B and Y observers
* the change to M. This provides a happens-before dependence between A and B.
*
* Atomic operations with `Release` or `Acquire` semantics can also synchronize
// T but that feature is still unimplemented
let maybe_symbol_value = do dl::check_for_errors_in {
- do symbol.to_c_str().with_ref |raw_string| {
+ do symbol.with_c_str |raw_string| {
dl::symbol(self.handle, raw_string)
}
};
use result::*;
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
- do filename.to_c_str().with_ref |raw_name| {
+ #[fixed_stack_segment]; #[inline(never)];
+ do filename.with_c_str |raw_name| {
dlopen(raw_name, Lazy as libc::c_int)
}
}
pub unsafe fn open_internal() -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
dlopen(ptr::null(), Lazy as libc::c_int)
}
pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do atomically {
let _old_error = dlerror();
}
pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
dlsym(handle, symbol)
}
pub unsafe fn close(handle: *libc::c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
dlclose(handle); ()
}
use result::*;
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
do os::win32::as_utf16_p(filename.to_str()) |raw_name| {
LoadLibraryW(raw_name)
}
}
pub unsafe fn open_internal() -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
let handle = ptr::null();
GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void);
handle
}
pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do atomically {
SetLastError(0);
}
}
pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
GetProcAddress(handle, symbol)
}
pub unsafe fn close(handle: *libc::c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
FreeLibrary(handle); ()
}
use str;
use sys;
use num;
- use uint;
use vec;
use option::{Some, None, Option};
return if prec == 0u && num == 0u {
~""
} else {
- let s = uint::to_str_radix(num, radix);
+ let s = num.to_str_radix(radix);
let len = s.char_len();
if len < prec {
let diff = prec - len;
do || {
...
}.finally {
- alway_run_this();
+ always_run_this();
}
~~~
*/
A quick refresher on memory ordering:
-* Acquire - a barrier for aquiring a lock. Subsequent reads and writes
+* Acquire - a barrier for acquiring a lock. Subsequent reads and writes
take place after the barrier.
* Release - a barrier for releasing a lock. Preceding reads and writes
take place before the barrier.
index: size_t, len: size_t) {
let msg = fmt!("index out of bounds: the len is %d but the index is %d",
len as int, index as int);
- do msg.to_c_str().with_ref |buf| {
+ do msg.with_c_str |buf| {
fail_(buf, file, line);
}
}
borrowck::check_not_borrowed(a, file, line)
}
-#[lang="annihilate"]
-pub unsafe fn annihilate() {
- ::cleanup::annihilate()
-}
-
#[lang="start"]
pub fn start(main: *u8, argc: int, argv: **c_char,
crate_map: *u8) -> int {
use comm;
use prelude::*;
use task;
+use libc::uintptr_t;
pub mod dynamic_lib;
/// can lead to deadlock. Calling change_dir_locked recursively will
/// also deadlock.
pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
use os;
use os::change_dir;
use unstable::sync::atomically;
fn rust_drop_change_dir_lock();
}
}
+
+
+/// Dynamically inquire about whether we're running under V.
+/// You should usually not use this unless your test definitely
+/// can't run correctly un-altered. Valgrind is there to help
+/// you notice weirdness in normal, un-doctored code paths!
+pub fn running_on_valgrind() -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { rust_running_on_valgrind() != 0 }
+}
+
+extern {
+ fn rust_running_on_valgrind() -> uintptr_t;
+}
/**
* Enables a runtime assertion that no operation in the argument closure shall
- * use scheduler operations (yield, recv, spawn, etc). This is for use with
+ * use scheduler operations (deschedule, recv, spawn, etc). This is for use with
* pthread mutexes, which may block the entire scheduler thread, rather than
- * just one task, and is hence prone to deadlocks if mixed with yielding.
+ * just one task, and is hence prone to deadlocks if mixed with descheduling.
*
* NOTE: THIS DOES NOT PROVIDE LOCKING, or any sort of critical-section
* synchronization whatsoever. It only makes sense to use for CPU-local issues.
if in_green_task_context() {
let t = Local::unsafe_borrow::<Task>();
do (|| {
- (*t).death.inhibit_yield();
+ (*t).death.inhibit_deschedule();
f()
}).finally {
- (*t).death.allow_yield();
+ (*t).death.allow_deschedule();
}
} else {
f()
}
}
- #[inline]
pub unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
do atomically {
rust_lock_little_lock(self.l);
* This uses a pthread mutex, not one that's aware of the userspace scheduler.
* The user of an Exclusive must be careful not to invoke any functions that may
* reschedule the task while holding the lock, or deadlock may result. If you
- * need to block or yield while accessing shared state, use extra::sync::RWArc.
+ * need to block or deschedule while accessing shared state, use extra::sync::RWArc.
*/
pub struct Exclusive<T> {
x: UnsafeAtomicRcBox<ExData<T>>
// Exactly like std::arc::MutexArc,access(), but with the LittleLock
// instead of a proper mutex. Same reason for being unsafe.
//
- // Currently, scheduling operations (i.e., yielding, receiving on a pipe,
+ // Currently, scheduling operations (i.e., descheduling, receiving on a pipe,
// accessing the provided condition variable) are prohibited while inside
// the Exclusive. Supporting that is a work in progress.
#[inline]
}
}
-extern {
- fn rust_create_little_lock() -> rust_little_lock;
- fn rust_destroy_little_lock(lock: rust_little_lock);
- fn rust_lock_little_lock(lock: rust_little_lock);
- fn rust_unlock_little_lock(lock: rust_little_lock);
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+ (fn $name:ident () $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ );
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ )
+)
}
+externfn!(fn rust_create_little_lock() -> rust_little_lock)
+externfn!(fn rust_destroy_little_lock(lock: rust_little_lock))
+externfn!(fn rust_lock_little_lock(lock: rust_little_lock))
+externfn!(fn rust_unlock_little_lock(lock: rust_little_lock))
+
#[cfg(test)]
mod tests {
use cell::Cell;
fn test_atomically() {
// NB. The whole runtime will abort on an 'atomic-sleep' violation,
// so we can't really test for the converse behaviour.
- unsafe { do atomically { } } task::yield(); // oughtn't fail
+ unsafe { do atomically { } } task::deschedule(); // oughtn't fail
}
#[test]
c.send(());
}
p.recv();
- task::yield(); // Try to make the unwrapper get blocked first.
+ task::deschedule(); // Try to make the unwrapper get blocked first.
let left_x = x.try_unwrap();
assert!(left_x.is_left());
util::ignore(left_x);
do task::spawn {
let x2 = x2.take();
unsafe { do x2.with |_hello| { } }
- task::yield();
+ task::deschedule();
}
assert!(x.unwrap() == ~~"hello");
let x = Exclusive::new(~~"hello");
let x2 = x.clone();
do task::spawn {
- do 10.times { task::yield(); } // try to let the unwrapper go
+ do 10.times { task::deschedule(); } // try to let the unwrapper go
fail!(); // punt it awake from its deadlock
}
let _z = x.unwrap();
(ts, us)
}
-/**
- * Convert two vectors to a vector of pairs, by reference. As zip().
- */
-pub fn zip_slice<T:Clone,U:Clone>(v: &[T], u: &[U]) -> ~[(T, U)] {
- let mut zipped = ~[];
- let sz = v.len();
- let mut i = 0u;
- assert_eq!(sz, u.len());
- while i < sz {
- zipped.push((v[i].clone(), u[i].clone()));
- i += 1u;
- }
- zipped
-}
-
-/**
- * Convert two vectors to a vector of pairs.
- *
- * Returns a vector of tuples, where the i-th tuple contains the
- * i-th elements from each of the input vectors.
- */
-pub fn zip<T, U>(mut v: ~[T], mut u: ~[U]) -> ~[(T, U)] {
- let mut i = v.len();
- assert_eq!(i, u.len());
- let mut w = with_capacity(i);
- while i > 0 {
- w.push((v.pop(),u.pop()));
- i -= 1;
- }
- w.reverse();
- w
-}
-
/**
* Iterate over all permutations of vector `v`.
*
/// elements at a time).
///
/// When the vector len is not evenly divided by the chunk size,
-/// the last slice of the iteration will be the remainer.
+/// the last slice of the iteration will be the remainder.
#[deriving(Clone)]
pub struct ChunkIter<'self, T> {
priv v: &'self [T],
/// Work with `self` as a slice.
fn as_slice<'a>(&'a self) -> &'a [T];
}
+
impl<'self,T> Vector<T> for &'self [T] {
#[inline(always)]
fn as_slice<'a>(&'a self) -> &'a [T] { *self }
}
+
impl<T> Vector<T> for ~[T] {
#[inline(always)]
fn as_slice<'a>(&'a self) -> &'a [T] { let v: &'a [T] = *self; v }
}
+
impl<T> Vector<T> for @[T] {
#[inline(always)]
fn as_slice<'a>(&'a self) -> &'a [T] { let v: &'a [T] = *self; v }
}
impl<'self, T> Container for &'self [T] {
- /// Returns true if a vector contains no elements
- #[inline]
- fn is_empty(&self) -> bool {
- self.as_imm_buf(|_p, len| len == 0u)
- }
-
/// Returns the length of a vector
#[inline]
fn len(&self) -> uint {
}
impl<T> Container for ~[T] {
- /// Returns true if a vector contains no elements
- #[inline]
- fn is_empty(&self) -> bool {
- self.as_imm_buf(|_p, len| len == 0u)
- }
-
/// Returns the length of a vector
#[inline]
fn len(&self) -> uint {
}
}
-#[allow(missing_doc)]
+/// Extension methods for vector slices with copyable elements
pub trait CopyableVector<T> {
+ /// Copy `self` into a new owned vector
fn to_owned(&self) -> ~[T];
+
+ /// Convert `self` into a owned vector, not making a copy if possible.
+ fn into_owned(self) -> ~[T];
}
-/// Extension methods for vectors
-impl<'self,T:Clone> CopyableVector<T> for &'self [T] {
+/// Extension methods for vector slices
+impl<'self, T: Clone> CopyableVector<T> for &'self [T] {
/// Returns a copy of `v`.
#[inline]
fn to_owned(&self) -> ~[T] {
}
result
}
+
+ #[inline(always)]
+ fn into_owned(self) -> ~[T] { self.to_owned() }
+}
+
+/// Extension methods for owned vectors
+impl<T: Clone> CopyableVector<T> for ~[T] {
+ #[inline]
+ fn to_owned(&self) -> ~[T] { self.clone() }
+
+ #[inline(always)]
+ fn into_owned(self) -> ~[T] { self }
+}
+
+/// Extension methods for managed vectors
+impl<T: Clone> CopyableVector<T> for @[T] {
+ #[inline]
+ fn to_owned(&self) -> ~[T] { self.as_slice().to_owned() }
+
+ #[inline(always)]
+ fn into_owned(self) -> ~[T] { self.to_owned() }
}
#[allow(missing_doc)]
fn reserve(&mut self, n: uint);
fn reserve_at_least(&mut self, n: uint);
fn capacity(&self) -> uint;
+ fn shrink_to_fit(&mut self);
fn push(&mut self, t: T);
unsafe fn push_fast(&mut self, t: T);
*
* * n - The number of elements to reserve space for
*/
+ #[inline]
fn reserve_at_least(&mut self, n: uint) {
self.reserve(uint::next_power_of_two(n));
}
}
}
+ /// Shrink the capacity of the vector to match the length
+ fn shrink_to_fit(&mut self) {
+ unsafe {
+ let ptr: *mut *mut Vec<()> = cast::transmute(self);
+ let alloc = (**ptr).fill;
+ let size = alloc + sys::size_of::<Vec<()>>();
+ *ptr = realloc_raw(*ptr as *mut c_void, size) as *mut Vec<()>;
+ (**ptr).alloc = alloc;
+ }
+ }
+
/// Append an element to a vector
#[inline]
fn push(&mut self, t: T) {
* 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
+ * modifying its buffers, so it is up to the caller to ensure that
* the vector is actually the specified size.
*/
#[inline]
}
}
-impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
- fn from_iterator(iterator: &mut T) -> ~[A] {
+impl<A> FromIterator<A> for ~[A] {
+ fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
let (lower, _) = iterator.size_hint();
let mut xs = with_capacity(lower);
for x in *iterator {
}
}
-impl<A, T: Iterator<A>> Extendable<A, T> for ~[A] {
- fn extend(&mut self, iterator: &mut T) {
+impl<A> Extendable<A> for ~[A] {
+ fn extend<T: Iterator<A>>(&mut self, iterator: &mut T) {
let (lower, _) = iterator.size_hint();
let len = self.len();
self.reserve(len + lower);
use sys;
use vec::*;
use cmp::*;
+ use prelude::*;
fn square(n: uint) -> uint { n * n }
#[test]
fn test_zip_unzip() {
- let v1 = ~[1, 2, 3];
- let v2 = ~[4, 5, 6];
-
- let z1 = zip(v1, v2);
-
- assert_eq!((1, 4), z1[0]);
- assert_eq!((2, 5), z1[1]);
- assert_eq!((3, 6), z1[2]);
+ let z1 = ~[(1, 4), (2, 5), (3, 6)];
let (left, right) = unzip(z1);
}
assert!(cnt == 3);
}
+
+ #[test]
+ fn test_shrink_to_fit() {
+ let mut xs = ~[0, 1, 2, 3];
+ for i in range(4, 100) {
+ xs.push(i)
+ }
+ assert_eq!(xs.capacity(), 128);
+ xs.shrink_to_fit();
+ assert_eq!(xs.capacity(), 100);
+ assert_eq!(xs, range(0, 100).to_owned_vec());
+ }
}
#[cfg(test)]
}
// a "Path" is essentially Rust's notion of a name;
-// for instance: core::cmp::Eq . It's represented
+// for instance: std::cmp::Eq . It's represented
// as a sequence of identifiers, along with a bunch
// of supporting information.
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
/* hold off on tests ... they appear in a later merge.
#[cfg(test)]
mod test {
- use core::option::{None, Option, Some};
- use core::uint;
+ use std::option::{None, Option, Some};
+ use std::uint;
use extra;
use codemap::*;
use super::*;
}
impl Ctx {
- fn extend(@mut self, elt: ident) -> @path {
+ fn extend(&self, elt: ident) -> @path {
@vec::append(self.path.clone(), [path_name(elt)])
}
- fn map_method(@mut self,
+ fn map_method(&mut self,
impl_did: def_id,
impl_path: @path,
m: @method,
self.map.insert(m.self_id, node_local(special_idents::self_));
}
- fn map_struct_def(@mut self,
+ fn map_struct_def(&mut self,
struct_def: @ast::struct_def,
parent_node: ast_node,
ident: ast::ident) {
}
}
- fn map_expr(@mut self, ex: @expr) {
+ fn map_expr(&mut self, ex: @expr) {
self.map.insert(ex.id, node_expr(ex));
// Expressions which are or might be calls:
}
}
- visit::visit_expr(self as @mut Visitor<()>, ex, ());
+ visit::walk_expr(self, ex, ());
}
- fn map_fn(@mut self,
+ fn map_fn(&mut self,
fk: &visit::fn_kind,
decl: &fn_decl,
body: &Block,
for a in decl.inputs.iter() {
self.map.insert(a.id, node_arg);
}
- visit::visit_fn(self as @mut Visitor<()>, fk, decl, body, sp, id, ());
+ visit::walk_fn(self, fk, decl, body, sp, id, ());
}
- fn map_stmt(@mut self, stmt: @stmt) {
+ fn map_stmt(&mut self, stmt: @stmt) {
self.map.insert(stmt_id(stmt), node_stmt(stmt));
- visit::visit_stmt(self as @mut Visitor<()>, stmt, ());
+ visit::walk_stmt(self, stmt, ());
}
- fn map_block(@mut self, b: &Block) {
+ fn map_block(&mut self, b: &Block) {
// clone is FIXME #2543
self.map.insert(b.id, node_block((*b).clone()));
- visit::visit_block(self as @mut Visitor<()>, b, ());
+ visit::walk_block(self, b, ());
}
- fn map_pat(@mut self, pat: @pat) {
+ fn map_pat(&mut self, pat: @pat) {
match pat.node {
pat_ident(_, ref path, _) => {
// Note: this is at least *potentially* a pattern...
_ => ()
}
- visit::visit_pat(self as @mut Visitor<()>, pat, ());
+ visit::walk_pat(self, pat, ());
}
}
impl Visitor<()> for Ctx {
- fn visit_item(@mut self, i: @item, _: ()) {
+ fn visit_item(&mut self, i: @item, _: ()) {
// clone is FIXME #2543
let item_path = @self.path.clone();
self.map.insert(i.id, node_item(i, item_path));
item_impl(_, _, _, ref ms) => {
let impl_did = ast_util::local_def(i.id);
for m in ms.iter() {
- self.map_method(impl_did, self.extend(i.ident), *m, false)
+ let extended = { self.extend(i.ident) };
+ self.map_method(impl_did, extended, *m, false)
}
}
item_enum(ref enum_definition, _) => {
}
_ => self.path.push(path_name(i.ident))
}
- visit::visit_item(self as @mut Visitor<()>, i, ());
+ visit::walk_item(self, i, ());
self.path.pop();
}
- fn visit_pat(@mut self, pat: @pat, _: ()) {
+ fn visit_pat(&mut self, pat: @pat, _: ()) {
self.map_pat(pat);
- visit::visit_pat(self as @mut Visitor<()>, pat, ())
+ visit::walk_pat(self, pat, ())
}
- fn visit_expr(@mut self, expr: @expr, _: ()) {
+ fn visit_expr(&mut self, expr: @expr, _: ()) {
self.map_expr(expr)
}
- fn visit_stmt(@mut self, stmt: @stmt, _: ()) {
+ fn visit_stmt(&mut self, stmt: @stmt, _: ()) {
self.map_stmt(stmt)
}
- fn visit_fn(@mut self,
+ fn visit_fn(&mut self,
function_kind: &fn_kind,
function_declaration: &fn_decl,
block: &Block,
self.map_fn(function_kind, function_declaration, block, span, node_id)
}
- fn visit_block(@mut self, block: &Block, _: ()) {
+ fn visit_block(&mut self, block: &Block, _: ()) {
self.map_block(block)
}
// XXX: Methods below can become default methods.
- fn visit_mod(@mut self, module: &_mod, _: span, _: NodeId, _: ()) {
- visit::visit_mod(self as @mut Visitor<()>, module, ())
+ fn visit_mod(&mut self, module: &_mod, _: span, _: NodeId, _: ()) {
+ visit::walk_mod(self, module, ())
}
- fn visit_view_item(@mut self, view_item: &view_item, _: ()) {
- visit::visit_view_item(self as @mut Visitor<()>, view_item, ())
+ fn visit_view_item(&mut self, view_item: &view_item, _: ()) {
+ visit::walk_view_item(self, view_item, ())
}
- fn visit_foreign_item(@mut self, foreign_item: @foreign_item, _: ()) {
- visit::visit_foreign_item(self as @mut Visitor<()>, foreign_item, ())
+ fn visit_foreign_item(&mut self, foreign_item: @foreign_item, _: ()) {
+ visit::walk_foreign_item(self, foreign_item, ())
}
- fn visit_local(@mut self, local: @Local, _: ()) {
- visit::visit_local(self as @mut Visitor<()>, local, ())
+ fn visit_local(&mut self, local: @Local, _: ()) {
+ visit::walk_local(self, local, ())
}
- fn visit_arm(@mut self, arm: &arm, _: ()) {
- visit::visit_arm(self as @mut Visitor<()>, arm, ())
+ fn visit_arm(&mut self, arm: &arm, _: ()) {
+ visit::walk_arm(self, arm, ())
}
- fn visit_decl(@mut self, decl: @decl, _: ()) {
- visit::visit_decl(self as @mut Visitor<()>, decl, ())
+ fn visit_decl(&mut self, decl: @decl, _: ()) {
+ visit::walk_decl(self, decl, ())
}
- fn visit_expr_post(@mut self, _: @expr, _: ()) {
+ fn visit_expr_post(&mut self, _: @expr, _: ()) {
// Empty!
}
- fn visit_ty(@mut self, typ: &Ty, _: ()) {
- visit::visit_ty(self as @mut Visitor<()>, typ, ())
+ fn visit_ty(&mut self, typ: &Ty, _: ()) {
+ visit::walk_ty(self, typ, ())
}
- fn visit_generics(@mut self, generics: &Generics, _: ()) {
- visit::visit_generics(self as @mut Visitor<()>, generics, ())
+ fn visit_generics(&mut self, generics: &Generics, _: ()) {
+ visit::walk_generics(self, generics, ())
}
- fn visit_fn(@mut self,
+ fn visit_fn(&mut self,
function_kind: &fn_kind,
function_declaration: &fn_decl,
block: &Block,
span: span,
node_id: NodeId,
_: ()) {
- visit::visit_fn(self as @mut Visitor<()>,
+ visit::walk_fn(self,
function_kind,
function_declaration,
block,
())
}
- fn visit_ty_method(@mut self, ty_method: &TypeMethod, _: ()) {
- visit::visit_ty_method(self as @mut Visitor<()>, ty_method, ())
+ fn visit_ty_method(&mut self, ty_method: &TypeMethod, _: ()) {
+ visit::walk_ty_method(self, ty_method, ())
}
- fn visit_trait_method(@mut self, trait_method: &trait_method, _: ()) {
- visit::visit_trait_method(self as @mut Visitor<()>, trait_method, ())
+ fn visit_trait_method(&mut self, trait_method: &trait_method, _: ()) {
+ visit::walk_trait_method(self, trait_method, ())
}
- fn visit_struct_def(@mut self,
+ fn visit_struct_def(&mut self,
struct_def: @struct_def,
ident: ident,
generics: &Generics,
node_id: NodeId,
_: ()) {
- visit::visit_struct_def(self as @mut Visitor<()>,
+ visit::walk_struct_def(self,
struct_def,
ident,
generics,
())
}
- fn visit_struct_field(@mut self, struct_field: @struct_field, _: ()) {
- visit::visit_struct_field(self as @mut Visitor<()>, struct_field, ())
+ fn visit_struct_field(&mut self, struct_field: @struct_field, _: ()) {
+ visit::walk_struct_field(self, struct_field, ())
}
}
path: ~[],
diag: diag,
};
- visit::visit_crate(cx as @mut Visitor<()>, c, ());
+ visit::walk_crate(cx, c, ());
cx.map
}
}
// visit the item / method contents and add those to the map:
- ii.accept((), cx as @mut Visitor<()>);
+ ii.accept((), cx);
}
pub fn node_id_to_str(map: map, id: NodeId, itr: @ident_interner) -> ~str {
pub trait inlined_item_utils {
fn ident(&self) -> ident;
fn id(&self) -> ast::NodeId;
- fn accept<E: Clone>(&self, e: E, v: @mut Visitor<E>);
+ fn accept<E: Clone, V:Visitor<E>>(&self, e: E, v: &mut V);
}
impl inlined_item_utils for inlined_item {
}
}
- fn accept<E: Clone>(&self, e: E, v: @mut Visitor<E>) {
+ fn accept<E: Clone, V:Visitor<E>>(&self, e: E, v: &mut V) {
match *self {
ii_item(i) => v.visit_item(i, e),
ii_foreign(i) => v.visit_foreign_item(i, e),
- ii_method(_, _, m) => visit::visit_method_helper(v, m, e),
+ ii_method(_, _, m) => visit::walk_method_helper(v, m, e),
}
}
}
}
}
-struct IdVisitor {
+pub fn id_visitor(vfn: @fn(NodeId), pass_through_items: bool)
+ -> @mut Visitor<()> {
+ let visitor = @mut IdVisitor {
+ visit_callback: vfn,
+ pass_through_items: pass_through_items,
+ visited_outermost: false,
+ };
+ visitor as @mut Visitor<()>
+}
+
+pub struct IdVisitor {
visit_callback: @fn(NodeId),
pass_through_items: bool,
visited_outermost: bool,
}
impl IdVisitor {
- fn visit_generics_helper(@mut self, generics: &Generics) {
+ fn visit_generics_helper(&self, generics: &Generics) {
for type_parameter in generics.ty_params.iter() {
(self.visit_callback)(type_parameter.id)
}
}
impl Visitor<()> for IdVisitor {
- fn visit_mod(@mut self,
+ fn visit_mod(&mut self,
module: &_mod,
_span: span,
node_id: NodeId,
env: ()) {
(self.visit_callback)(node_id);
- visit::visit_mod(self as @mut Visitor<()>, module, env)
+ visit::walk_mod(self, module, env)
}
- fn visit_view_item(@mut self, view_item: &view_item, env: ()) {
+ fn visit_view_item(&mut self, view_item: &view_item, env: ()) {
match view_item.node {
view_item_extern_mod(_, _, _, node_id) => {
(self.visit_callback)(node_id)
}
}
}
- visit::visit_view_item(self as @mut Visitor<()>, view_item, env)
+ visit::walk_view_item(self, view_item, env)
}
- fn visit_foreign_item(@mut self, foreign_item: @foreign_item, env: ()) {
+ fn visit_foreign_item(&mut self, foreign_item: @foreign_item, env: ()) {
(self.visit_callback)(foreign_item.id);
- visit::visit_foreign_item(self as @mut Visitor<()>, foreign_item, env)
+ visit::walk_foreign_item(self, foreign_item, env)
}
- fn visit_item(@mut self, item: @item, env: ()) {
+ fn visit_item(&mut self, item: @item, env: ()) {
if !self.pass_through_items {
if self.visited_outermost {
return
_ => {}
}
- visit::visit_item(self as @mut Visitor<()>, item, env);
+ visit::walk_item(self, item, env);
self.visited_outermost = false
}
- fn visit_local(@mut self, local: @Local, env: ()) {
+ fn visit_local(&mut self, local: @Local, env: ()) {
(self.visit_callback)(local.id);
- visit::visit_local(self as @mut Visitor<()>, local, env)
+ visit::walk_local(self, local, env)
}
- fn visit_block(@mut self, block: &Block, env: ()) {
+ fn visit_block(&mut self, block: &Block, env: ()) {
(self.visit_callback)(block.id);
- visit::visit_block(self as @mut Visitor<()>, block, env)
+ visit::walk_block(self, block, env)
}
- fn visit_stmt(@mut self, statement: @stmt, env: ()) {
+ fn visit_stmt(&mut self, statement: @stmt, env: ()) {
(self.visit_callback)(ast_util::stmt_id(statement));
- visit::visit_stmt(self as @mut Visitor<()>, statement, env)
+ visit::walk_stmt(self, statement, env)
}
// XXX: Default
- fn visit_arm(@mut self, arm: &arm, env: ()) {
- visit::visit_arm(self as @mut Visitor<()>, arm, env)
+ fn visit_arm(&mut self, arm: &arm, env: ()) {
+ visit::walk_arm(self, arm, env)
}
- fn visit_pat(@mut self, pattern: @pat, env: ()) {
+ fn visit_pat(&mut self, pattern: @pat, env: ()) {
(self.visit_callback)(pattern.id);
- visit::visit_pat(self as @mut Visitor<()>, pattern, env)
+ visit::walk_pat(self, pattern, env)
}
// XXX: Default
- fn visit_decl(@mut self, declaration: @decl, env: ()) {
- visit::visit_decl(self as @mut Visitor<()>, declaration, env)
+ fn visit_decl(&mut self, declaration: @decl, env: ()) {
+ visit::walk_decl(self, declaration, env)
}
- fn visit_expr(@mut self, expression: @expr, env: ()) {
+ fn visit_expr(&mut self, expression: @expr, env: ()) {
{
let optional_callee_id = expression.get_callee_id();
for callee_id in optional_callee_id.iter() {
}
}
(self.visit_callback)(expression.id);
- visit::visit_expr(self as @mut Visitor<()>, expression, env)
+ visit::walk_expr(self, expression, env)
}
// XXX: Default
- fn visit_expr_post(@mut self, _: @expr, _: ()) {
+ fn visit_expr_post(&mut self, _: @expr, _: ()) {
// Empty!
}
- fn visit_ty(@mut self, typ: &Ty, env: ()) {
+ fn visit_ty(&mut self, typ: &Ty, env: ()) {
(self.visit_callback)(typ.id);
match typ.node {
ty_path(_, _, id) => (self.visit_callback)(id),
_ => {}
}
- visit::visit_ty(self as @mut Visitor<()>, typ, env)
+ visit::walk_ty(self, typ, env)
}
- fn visit_generics(@mut self, generics: &Generics, env: ()) {
+ fn visit_generics(&mut self, generics: &Generics, env: ()) {
self.visit_generics_helper(generics);
- visit::visit_generics(self as @mut Visitor<()>, generics, env)
+ visit::walk_generics(self, generics, env)
}
- fn visit_fn(@mut self,
+ fn visit_fn(&mut self,
function_kind: &visit::fn_kind,
function_declaration: &fn_decl,
block: &Block,
(self.visit_callback)(argument.id)
}
- visit::visit_fn(self as @mut Visitor<()>,
+ visit::walk_fn(self,
function_kind,
function_declaration,
block,
}
// XXX: Default
- fn visit_ty_method(@mut self, type_method: &TypeMethod, env: ()) {
- visit::visit_ty_method(self as @mut Visitor<()>, type_method, env)
+ fn visit_ty_method(&mut self, type_method: &TypeMethod, env: ()) {
+ visit::walk_ty_method(self, type_method, env)
}
// XXX: Default
- fn visit_trait_method(@mut self, trait_method: &trait_method, env: ()) {
- visit::visit_trait_method(self as @mut Visitor<()>, trait_method, env)
+ fn visit_trait_method(&mut self, trait_method: &trait_method, env: ()) {
+ visit::walk_trait_method(self, trait_method, env)
}
// XXX: Default
- fn visit_struct_def(@mut self,
+ fn visit_struct_def(&mut self,
struct_definition: @struct_def,
identifier: ident,
generics: &Generics,
node_id: NodeId,
env: ()) {
- visit::visit_struct_def(self as @mut Visitor<()>,
+ visit::walk_struct_def(self,
struct_definition,
identifier,
generics,
env)
}
- fn visit_struct_field(@mut self, struct_field: @struct_field, env: ()) {
+ fn visit_struct_field(&mut self, struct_field: @struct_field, env: ()) {
(self.visit_callback)(struct_field.node.id);
- visit::visit_struct_field(self as @mut Visitor<()>, struct_field, env)
+ visit::walk_struct_field(self, struct_field, env)
}
}
-pub fn id_visitor(vfn: @fn(NodeId), pass_through_items: bool)
- -> @mut Visitor<()> {
- let visitor = @mut IdVisitor {
+pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(NodeId)) {
+ let mut id_visitor = IdVisitor {
visit_callback: vfn,
- pass_through_items: pass_through_items,
+ pass_through_items: true,
visited_outermost: false,
};
- visitor as @mut Visitor<()>
-}
-
-pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(NodeId)) {
- item.accept((), id_visitor(|id| vfn(id), true));
+ item.accept((), &mut id_visitor);
}
pub fn compute_id_range(visit_ids_fn: &fn(@fn(NodeId))) -> id_range {
}
impl SimpleVisitor for EachViewItemData {
- fn visit_mod(@mut self, _: &_mod, _: span, _: NodeId) {
+ fn visit_mod(&mut self, _: &_mod, _: span, _: NodeId) {
// XXX: Default method.
}
- fn visit_view_item(@mut self, view_item: &view_item) {
+ fn visit_view_item(&mut self, view_item: &view_item) {
let _ = (self.callback)(view_item);
}
- fn visit_foreign_item(@mut self, _: @foreign_item) {
+ fn visit_foreign_item(&mut self, _: @foreign_item) {
// XXX: Default method.
}
- fn visit_item(@mut self, _: @item) {
+ fn visit_item(&mut self, _: @item) {
// XXX: Default method.
}
- fn visit_local(@mut self, _: @Local) {
+ fn visit_local(&mut self, _: @Local) {
// XXX: Default method.
}
- fn visit_block(@mut self, _: &Block) {
+ fn visit_block(&mut self, _: &Block) {
// XXX: Default method.
}
- fn visit_stmt(@mut self, _: @stmt) {
+ fn visit_stmt(&mut self, _: @stmt) {
// XXX: Default method.
}
- fn visit_arm(@mut self, _: &arm) {
+ fn visit_arm(&mut self, _: &arm) {
// XXX: Default method.
}
- fn visit_pat(@mut self, _: @pat) {
+ fn visit_pat(&mut self, _: @pat) {
// XXX: Default method.
}
- fn visit_decl(@mut self, _: @decl) {
+ fn visit_decl(&mut self, _: @decl) {
// XXX: Default method.
}
- fn visit_expr(@mut self, _: @expr) {
+ fn visit_expr(&mut self, _: @expr) {
// XXX: Default method.
}
- fn visit_expr_post(@mut self, _: @expr) {
+ fn visit_expr_post(&mut self, _: @expr) {
// XXX: Default method.
}
- fn visit_ty(@mut self, _: &Ty) {
+ fn visit_ty(&mut self, _: &Ty) {
// XXX: Default method.
}
- fn visit_generics(@mut self, _: &Generics) {
+ fn visit_generics(&mut self, _: &Generics) {
// XXX: Default method.
}
- fn visit_fn(@mut self,
+ fn visit_fn(&mut self,
_: &visit::fn_kind,
_: &fn_decl,
_: &Block,
_: NodeId) {
// XXX: Default method.
}
- fn visit_ty_method(@mut self, _: &TypeMethod) {
+ fn visit_ty_method(&mut self, _: &TypeMethod) {
// XXX: Default method.
}
- fn visit_trait_method(@mut self, _: &trait_method) {
+ fn visit_trait_method(&mut self, _: &trait_method) {
// XXX: Default method.
}
- fn visit_struct_def(@mut self,
+ fn visit_struct_def(&mut self,
_: @struct_def,
_: ident,
_: &Generics,
_: NodeId) {
// XXX: Default method.
}
- fn visit_struct_field(@mut self, _: @struct_field) {
+ fn visit_struct_field(&mut self, _: @struct_field) {
// XXX: Default method.
}
- fn visit_struct_method(@mut self, _: @method) {
+ fn visit_struct_method(&mut self, _: @method) {
// XXX: Default method.
}
}
let visitor = @mut SimpleVisitorVisitor {
simple_visitor: data as @mut SimpleVisitor,
};
- visit::visit_crate(visitor as @mut Visitor<()>, self, ());
+ visit::walk_crate(visitor, self, ());
true
}
}
self.expr(span, ast::expr_fn_block(fn_decl, blk))
}
+ #[cfg(stage0)]
fn lambda0(&self, _span: span, blk: ast::Block) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|| $blk_e )
}
+ #[cfg(not(stage0))]
+ fn lambda0(&self, _span: span, blk: ast::Block) -> @ast::expr {
+ let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
+ quote_expr!(*self, || $blk_e )
+ }
+ #[cfg(stage0)]
fn lambda1(&self, _span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|$ident| $blk_e )
}
+ #[cfg(not(stage0))]
+ fn lambda1(&self, _span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr {
+ let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
+ quote_expr!(*self, |$ident| $blk_e )
+ }
fn lambda_expr(&self, span: span, ids: ~[ast::ident], expr: @ast::expr) -> @ast::expr {
self.lambda(span, ids, self.block_expr(expr))
use std::os;
+#[cfg(stage0)]
pub fn expand_option_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
let var = get_single_str_from_tts(ext_cx, sp, tts, "option_env!");
let e = match os::getenv(var) {
- None => quote_expr!(::std::option::None),
+ None => quote_expr!(::std::option::None::<&'static str>),
Some(s) => quote_expr!(::std::option::Some($s))
};
MRExpr(e)
}
+#[cfg(not(stage0))]
+pub fn expand_option_env(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
+ -> base::MacResult {
+ let var = get_single_str_from_tts(cx, sp, tts, "option_env!");
+
+ let e = match os::getenv(var) {
+ None => quote_expr!(cx, ::std::option::None::<&'static str>),
+ Some(s) => quote_expr!(cx, ::std::option::Some($s))
+ };
+ MRExpr(e)
+}
-pub fn expand_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
+pub fn expand_env(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
- let exprs = get_exprs_from_tts(ext_cx, sp, tts);
+ let exprs = get_exprs_from_tts(cx, sp, tts);
if exprs.len() == 0 {
- ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments");
+ cx.span_fatal(sp, "env! takes 1 or 2 arguments");
}
- let var = expr_to_str(ext_cx, exprs[0], "expected string literal");
+ let var = expr_to_str(cx, exprs[0], "expected string literal");
let msg = match exprs.len() {
1 => fmt!("Environment variable %s not defined", var).to_managed(),
- 2 => expr_to_str(ext_cx, exprs[1], "expected string literal"),
- _ => ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments")
+ 2 => expr_to_str(cx, exprs[1], "expected string literal"),
+ _ => cx.span_fatal(sp, "env! takes 1 or 2 arguments")
};
let e = match os::getenv(var) {
- None => ext_cx.span_fatal(sp, msg),
- Some(s) => ext_cx.expr_str(sp, s.to_managed())
+ None => cx.span_fatal(sp, msg),
+ Some(s) => cx.expr_str(sp, s.to_managed())
};
MRExpr(e)
}
}
impl Visitor<()> for NewNameFinderContext {
- fn visit_pat(@mut self, pattern: @ast::pat, _: ()) {
+ fn visit_pat(&mut self, pattern: @ast::pat, _: ()) {
match *pattern {
// we found a pat_ident!
ast::pat {
}
}
// use the default traversal for non-pat_idents
- _ => visit::visit_pat(self as @mut Visitor<()>, pattern, ())
+ _ => visit::walk_pat(self, pattern, ())
}
}
// XXX: Methods below can become default methods.
- fn visit_mod(@mut self, module: &ast::_mod, _: span, _: NodeId, _: ()) {
- visit::visit_mod(self as @mut Visitor<()>, module, ())
+ fn visit_mod(&mut self, module: &ast::_mod, _: span, _: NodeId, _: ()) {
+ visit::walk_mod(self, module, ())
}
- fn visit_view_item(@mut self, view_item: &ast::view_item, _: ()) {
- visit::visit_view_item(self as @mut Visitor<()>, view_item, ())
+ fn visit_view_item(&mut self, view_item: &ast::view_item, _: ()) {
+ visit::walk_view_item(self, view_item, ())
}
- fn visit_item(@mut self, item: @ast::item, _: ()) {
- visit::visit_item(self as @mut Visitor<()>, item, ())
+ fn visit_item(&mut self, item: @ast::item, _: ()) {
+ visit::walk_item(self, item, ())
}
- fn visit_foreign_item(@mut self,
+ fn visit_foreign_item(&mut self,
foreign_item: @ast::foreign_item,
_: ()) {
- visit::visit_foreign_item(self as @mut Visitor<()>, foreign_item, ())
+ visit::walk_foreign_item(self, foreign_item, ())
}
- fn visit_local(@mut self, local: @ast::Local, _: ()) {
- visit::visit_local(self as @mut Visitor<()>, local, ())
+ fn visit_local(&mut self, local: @ast::Local, _: ()) {
+ visit::walk_local(self, local, ())
}
- fn visit_block(@mut self, block: &ast::Block, _: ()) {
- visit::visit_block(self as @mut Visitor<()>, block, ())
+ fn visit_block(&mut self, block: &ast::Block, _: ()) {
+ visit::walk_block(self, block, ())
}
- fn visit_stmt(@mut self, stmt: @ast::stmt, _: ()) {
- visit::visit_stmt(self as @mut Visitor<()>, stmt, ())
+ fn visit_stmt(&mut self, stmt: @ast::stmt, _: ()) {
+ visit::walk_stmt(self, stmt, ())
}
- fn visit_arm(@mut self, arm: &ast::arm, _: ()) {
- visit::visit_arm(self as @mut Visitor<()>, arm, ())
+ fn visit_arm(&mut self, arm: &ast::arm, _: ()) {
+ visit::walk_arm(self, arm, ())
}
- fn visit_decl(@mut self, decl: @ast::decl, _: ()) {
- visit::visit_decl(self as @mut Visitor<()>, decl, ())
+ fn visit_decl(&mut self, decl: @ast::decl, _: ()) {
+ visit::walk_decl(self, decl, ())
}
- fn visit_expr(@mut self, expr: @ast::expr, _: ()) {
- visit::visit_expr(self as @mut Visitor<()>, expr, ())
+ fn visit_expr(&mut self, expr: @ast::expr, _: ()) {
+ visit::walk_expr(self, expr, ())
}
- fn visit_expr_post(@mut self, _: @ast::expr, _: ()) {
+ fn visit_expr_post(&mut self, _: @ast::expr, _: ()) {
// Empty!
}
- fn visit_ty(@mut self, typ: &ast::Ty, _: ()) {
- visit::visit_ty(self as @mut Visitor<()>, typ, ())
+ fn visit_ty(&mut self, typ: &ast::Ty, _: ()) {
+ visit::walk_ty(self, typ, ())
}
- fn visit_generics(@mut self, generics: &ast::Generics, _: ()) {
- visit::visit_generics(self as @mut Visitor<()>, generics, ())
+ fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
+ visit::walk_generics(self, generics, ())
}
- fn visit_fn(@mut self,
+ fn visit_fn(&mut self,
function_kind: &visit::fn_kind,
function_declaration: &ast::fn_decl,
block: &ast::Block,
span: span,
node_id: NodeId,
_: ()) {
- visit::visit_fn(self as @mut Visitor<()>,
+ visit::walk_fn(self,
function_kind,
function_declaration,
block,
())
}
- fn visit_ty_method(@mut self, ty_method: &ast::TypeMethod, _: ()) {
- visit::visit_ty_method(self as @mut Visitor<()>, ty_method, ())
+ fn visit_ty_method(&mut self, ty_method: &ast::TypeMethod, _: ()) {
+ visit::walk_ty_method(self, ty_method, ())
}
- fn visit_trait_method(@mut self,
+ fn visit_trait_method(&mut self,
trait_method: &ast::trait_method,
_: ()) {
- visit::visit_trait_method(self as @mut Visitor<()>, trait_method, ())
+ visit::walk_trait_method(self, trait_method, ())
}
- fn visit_struct_def(@mut self,
+ fn visit_struct_def(&mut self,
struct_def: @ast::struct_def,
ident: ident,
generics: &ast::Generics,
node_id: NodeId,
_: ()) {
- visit::visit_struct_def(self as @mut Visitor<()>,
+ visit::walk_struct_def(self,
struct_def,
ident,
generics,
())
}
- fn visit_struct_field(@mut self,
+ fn visit_struct_field(&mut self,
struct_field: @ast::struct_field,
_: ()) {
- visit::visit_struct_field(self as @mut Visitor<()>, struct_field, ())
+ visit::walk_struct_field(self, struct_field, ())
}
}
println(fmt!($($arg),+))
)
)
+
+ // NOTE: use this after a snapshot lands to abstract the details
+ // of the TLS interface.
+ macro_rules! local_data_key (
+ ($name:ident: $ty:ty) => (
+ static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
+ );
+ (pub $name:ident: $ty:ty) => (
+ pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
+ )
+ )
+
+ // externfn! declares a wrapper for an external function.
+ // It is intended to be used like:
+ //
+ // externfn!(#[nolink]
+ // #[abi = \"cdecl\"]
+ // fn memcmp(cx: *u8, ct: *u8, n: u32) -> u32)
+ //
+ // Due to limitations in the macro parser, this pattern must be
+ // implemented with 4 distinct patterns (with attrs / without
+ // attrs CROSS with args / without ARGS).
+ //
+ // Also, this macro grammar allows for any number of return types
+ // because I couldn't figure out the syntax to specify at most one.
+ macro_rules! externfn(
+ (fn $name:ident () $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name() $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name();
+
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ }
+ );
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name($($arg_name),*);
+
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ }
+ );
+ ($($attrs:attr)* fn $name:ident () $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name() $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name();
+
+ $($attrs)*
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ }
+ );
+ ($($attrs:attr)* fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name($($arg_name),*);
+
+ $($attrs)*
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ }
+ )
+ )
+
}";
}
fn format_arg(&self, sp: span, arg: Either<uint, @str>,
ident: ast::ident) -> @ast::expr {
- let mut ty = match arg {
+ let ty = match arg {
Left(i) => self.arg_types[i].unwrap(),
Right(s) => *self.name_types.get(&s)
};
- // Default types to '?' if nothing else is specified.
- if ty == Unknown {
- ty = Known(@"?");
- }
let argptr = self.ecx.expr_addr_of(sp, self.ecx.expr_ident(sp, ident));
- match ty {
+ let fmt_trait = match ty {
+ Unknown => "Default",
Known(tyname) => {
- let fmt_trait = match tyname.as_slice() {
+ match tyname.as_slice() {
"?" => "Poly",
"b" => "Bool",
"c" => "Char",
`%s`", tyname));
"Dummy"
}
- };
- let format_fn = self.ecx.path_global(sp, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of(fmt_trait),
- self.ecx.ident_of("fmt"),
- ]);
- self.ecx.expr_call_global(sp, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of("argument"),
- ], ~[self.ecx.expr_path(format_fn), argptr])
+ }
}
String => {
- self.ecx.expr_call_global(sp, ~[
+ return self.ecx.expr_call_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of("argumentstr"),
], ~[argptr])
}
Unsigned => {
- self.ecx.expr_call_global(sp, ~[
+ return self.ecx.expr_call_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of("argumentuint"),
], ~[argptr])
}
- Unknown => { fail!() }
- }
+ };
+
+ let format_fn = self.ecx.path_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of(fmt_trait),
+ self.ecx.ident_of("fmt"),
+ ]);
+ self.ecx.expr_call_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("argument"),
+ ], ~[self.ecx.expr_path(format_fn), argptr])
}
}
// Alas ... we write these out instead. All redundant.
- impl ToTokens for ast::ident {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for @ast::item {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl<'self> ToTokens for &'self [@ast::item] {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for ast::Ty {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl<'self> ToTokens for &'self [ast::Ty] {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for Generics {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for @ast::expr {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for ast::Block {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl<'self> ToTokens for &'self str {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for int {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for i8 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for i16 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for i32 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for i64 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for uint {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for u8 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for u16 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for u32 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
-
- impl ToTokens for u64 {
- fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
- cx.parse_tts(self.to_source())
- }
- }
+ macro_rules! impl_to_tokens(
+ ($t:ty) => (
+ impl ToTokens for $t {
+ fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
+ cx.parse_tts(self.to_source())
+ }
+ }
+ )
+ )
+
+ macro_rules! impl_to_tokens_self(
+ ($t:ty) => (
+ impl<'self> ToTokens for $t {
+ fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
+ cx.parse_tts(self.to_source())
+ }
+ }
+ )
+ )
+
+ impl_to_tokens!(ast::ident)
+ impl_to_tokens!(@ast::item)
+ impl_to_tokens_self!(&'self [@ast::item])
+ impl_to_tokens!(ast::Ty)
+ impl_to_tokens_self!(&'self [ast::Ty])
+ impl_to_tokens!(Generics)
+ impl_to_tokens!(@ast::expr)
+ impl_to_tokens!(ast::Block)
+ impl_to_tokens_self!(&'self str)
+ impl_to_tokens!(int)
+ impl_to_tokens!(i8)
+ impl_to_tokens!(i16)
+ impl_to_tokens!(i32)
+ impl_to_tokens!(i64)
+ impl_to_tokens!(uint)
+ impl_to_tokens!(u8)
+ impl_to_tokens!(u16)
+ impl_to_tokens!(u32)
+ impl_to_tokens!(u64)
pub trait ExtParseUtils {
fn parse_item(&self, s: @str) -> @ast::item;
pub fn expand_quote_tokens(cx: @ExtCtxt,
sp: span,
tts: &[ast::token_tree]) -> base::MacResult {
- base::MRExpr(expand_tts(cx, sp, tts))
+ let (cx_expr, expr) = expand_tts(cx, sp, tts);
+ base::MRExpr(expand_wrapper(cx, sp, cx_expr, expr))
}
pub fn expand_quote_expr(cx: @ExtCtxt,
fn expand_tts(cx: @ExtCtxt,
sp: span,
- tts: &[ast::token_tree]) -> @ast::expr {
+ tts: &[ast::token_tree]) -> (@ast::expr, @ast::expr) {
// NB: It appears that the main parser loses its mind if we consider
// $foo as a tt_nonterminal during the main parse, so we have to re-parse
tts.to_owned()
);
*p.quote_depth += 1u;
- let tts = p.parse_all_token_trees();
- p.abort_if_errors();
- // We want to emit a block expression that does a sequence of 'use's to
- // import the runtime module, followed by a tt-building expression.
+ let cx_expr = p.parse_expr();
+ if !p.eat(&token::COMMA) {
+ p.fatal("Expected token `,`");
+ }
- let uses = ~[ cx.view_use_glob(sp, ast::public,
- ids_ext(~[~"syntax",
- ~"ext",
- ~"quote",
- ~"rt"])) ];
+ let tts = p.parse_all_token_trees();
+ p.abort_if_errors();
// We also bind a single value, sp, to ext_cx.call_site()
//
// the site the string literal occurred, which was in a source file
// _other_ than the one the user has control over. For example, an
// error in a quote from the protocol compiler, invoked in user code
- // using macro_rules! for example, will be attributed to the macro_rules.rs file in
- // libsyntax, which the user might not even have source to (unless they
- // happen to have a compiler on hand). Over all, the phase distinction
+ // using macro_rules! for example, will be attributed to the macro_rules.rs
+ // file in libsyntax, which the user might not even have source to (unless
+ // they happen to have a compiler on hand). Over all, the phase distinction
// just makes quotes "hard to attribute". Possibly this could be fixed
// by recreating some of the original qq machinery in the tt regime
// (pushing fake FileMaps onto the parser to account for original sites
id_ext("tt"),
cx.expr_vec_uniq(sp, ~[]));
- cx.expr_block(
- cx.block_all(sp, uses,
- ~[stmt_let_sp,
- stmt_let_tt] + mk_tts(cx, sp, tts),
- Some(cx.expr_ident(sp, id_ext("tt")))))
+ let block = cx.expr_block(
+ cx.block_all(sp,
+ ~[],
+ ~[stmt_let_sp, stmt_let_tt] + mk_tts(cx, sp, tts),
+ Some(cx.expr_ident(sp, id_ext("tt")))));
+
+ (cx_expr, block)
+}
+
+fn expand_wrapper(cx: @ExtCtxt,
+ sp: span,
+ cx_expr: @ast::expr,
+ expr: @ast::expr) -> @ast::expr {
+ let uses = ~[ cx.view_use_glob(sp, ast::public,
+ ids_ext(~[~"syntax",
+ ~"ext",
+ ~"quote",
+ ~"rt"])) ];
+
+ let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr);
+
+ cx.expr_block(cx.block_all(sp, uses, ~[stmt_let_ext_cx], Some(expr)))
}
fn expand_parse_call(cx: @ExtCtxt,
parse_method: &str,
arg_exprs: ~[@ast::expr],
tts: &[ast::token_tree]) -> @ast::expr {
- let tts_expr = expand_tts(cx, sp, tts);
+ let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
let cfg_call = || cx.expr_method_call(
sp, cx.expr_ident(sp, id_ext("ext_cx")),
id_ext("parse_sess"), ~[]);
let new_parser_call =
- cx.expr_call_global(sp,
- ids_ext(~[~"syntax",
- ~"ext",
- ~"quote",
- ~"rt",
- ~"new_parser_from_tts"]),
- ~[parse_sess_call(),
- cfg_call(),
- tts_expr]);
-
- cx.expr_method_call(sp, new_parser_call,
- id_ext(parse_method),
- arg_exprs)
+ cx.expr_call(sp,
+ cx.expr_ident(sp, id_ext("new_parser_from_tts")),
+ ~[parse_sess_call(), cfg_call(), tts_expr]);
+
+ let expr = cx.expr_method_call(sp, new_parser_call, id_ext(parse_method),
+ arg_exprs);
+
+ expand_wrapper(cx, sp, cx_expr, expr)
}
use ast;
use codemap::{spanned, mk_sp};
-use codemap::BytePos;
use parse::common::*; //resolve bug?
use parse::token;
use parse::parser::Parser;
c => {
// So the error span points to the unrecognized character
rdr.peek_span = codemap::mk_sp(rdr.last_pos, rdr.pos);
- rdr.fatal(fmt!("unknown start of token: %d", c as int));
+ let mut cs = ~"";
+ char::escape_default(c, |c| cs.push_char(c));
+ rdr.fatal(fmt!("unknown start of token: %s", cs));
}
}
}
pub enum ObsoleteSyntax {
ObsoleteLet,
ObsoleteFieldTerminator,
- ObsoleteStructCtor,
ObsoleteWith,
ObsoleteClassTraits,
ObsoletePrivSection,
fn token_is_obsolete_ident(&self, ident: &str, token: &Token) -> bool;
fn is_obsolete_ident(&self, ident: &str) -> bool;
fn eat_obsolete_ident(&self, ident: &str) -> bool;
- fn try_parse_obsolete_struct_ctor(&self) -> bool;
fn try_parse_obsolete_with(&self) -> bool;
fn try_parse_obsolete_priv_section(&self, attrs: &[Attribute]) -> bool;
}
"field declaration terminated with semicolon",
"fields are now separated by commas"
),
- ObsoleteStructCtor => (
- "struct constructor",
- "structs are now constructed with `MyStruct { foo: val }` \
- syntax. Structs with private fields cannot be created \
- outside of their defining module"
- ),
ObsoleteWith => (
"with",
"record update is done with `..`, e.g. \
}
}
- fn try_parse_obsolete_struct_ctor(&self) -> bool {
- if self.eat_obsolete_ident("new") {
- self.obsolete(*self.last_span, ObsoleteStructCtor);
- self.parse_fn_decl();
- self.parse_block();
- true
- } else {
- false
- }
- }
-
fn try_parse_obsolete_with(&self) -> bool {
if *self.token == token::COMMA
&& self.look_ahead(1,
_ => {
p.fatal(
fmt!(
- "expected `;` or `}` but found `%s`",
+ "expected `;` or `{` but found `%s`",
self.this_token_to_str()
)
);
|p| p.parse_arg()
);
- let inputs = either::lefts(args_or_capture_items);
+ let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
let (ret_style, ret_ty) = self.parse_ret_ty();
ast::fn_decl {
let hi = self.span.hi;
- let inputs = either::lefts(args_or_capture_items);
+ let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
let (ret_style, ret_ty) = self.parse_ret_ty();
let fn_decl = ast::fn_decl {
};
ast::fn_decl {
- inputs: either::lefts(inputs_captures),
+ inputs: either::lefts(inputs_captures.move_iter()).collect(),
output: output,
cf: return_val,
}
return ~[self.parse_single_struct_field(public, attrs)];
}
- if self.try_parse_obsolete_struct_ctor() {
- return ~[];
- }
-
return ~[self.parse_single_struct_field(inherited, attrs)];
}
"be", // 64
"pure", // 65
+ "yield", // 66
];
@ident_interner {
Once,
Priv,
Pub,
- Pure,
Ref,
Return,
Static,
// Reserved keywords
Be,
+ Pure,
+ Yield,
}
impl Keyword {
Once => ident { name: 50, ctxt: 0 },
Priv => ident { name: 51, ctxt: 0 },
Pub => ident { name: 52, ctxt: 0 },
- Pure => ident { name: 65, ctxt: 0 },
Ref => ident { name: 53, ctxt: 0 },
Return => ident { name: 54, ctxt: 0 },
Static => ident { name: 27, ctxt: 0 },
Use => ident { name: 61, ctxt: 0 },
While => ident { name: 62, ctxt: 0 },
Be => ident { name: 64, ctxt: 0 },
+ Pure => ident { name: 65, ctxt: 0 },
+ Yield => ident { name: 66, ctxt: 0 },
}
}
}
pub fn is_any_keyword(tok: &Token) -> bool {
match *tok {
token::IDENT(sid, false) => match sid.name {
- 8 | 27 | 32 .. 65 => true,
+ 8 | 27 | 32 .. 66 => true,
_ => false,
},
_ => false
pub fn is_reserved_keyword(tok: &Token) -> bool {
match *tok {
token::IDENT(sid, false) => match sid.name {
- 64 .. 65 => true,
+ 64 .. 66 => true,
_ => false,
},
_ => false,
use print::pprust;
use std::io;
-use std::u64;
// The @ps is stored here to prevent recursive type.
pub enum ann_node<'self> {
ast::lit_int(i, t) => {
if i < 0_i64 {
word(s.s,
- ~"-" + u64::to_str_radix(-i as u64, 10u)
+ ~"-" + (-i as u64).to_str_radix(10u)
+ ast_util::int_ty_to_str(t));
} else {
word(s.s,
- u64::to_str_radix(i as u64, 10u)
+ (i as u64).to_str_radix(10u)
+ ast_util::int_ty_to_str(t));
}
}
ast::lit_uint(u, t) => {
word(s.s,
- u64::to_str_radix(u, 10u)
+ u.to_str_radix(10u)
+ ast_util::uint_ty_to_str(t));
}
ast::lit_int_unsuffixed(i) => {
if i < 0_i64 {
- word(s.s, ~"-" + u64::to_str_radix(-i as u64, 10u));
+ word(s.s, ~"-" + (-i as u64).to_str_radix(10u));
} else {
- word(s.s, u64::to_str_radix(i as u64, 10u));
+ word(s.s, (i as u64).to_str_radix(10u));
}
}
ast::lit_float(f, t) => {
}
}
-pub trait Visitor<E> {
- fn visit_mod(@mut self, &_mod, span, NodeId, E);
- fn visit_view_item(@mut self, &view_item, E);
- fn visit_foreign_item(@mut self, @foreign_item, E);
- fn visit_item(@mut self, @item, E);
- fn visit_local(@mut self, @Local, E);
- fn visit_block(@mut self, &Block, E);
- fn visit_stmt(@mut self, @stmt, E);
- fn visit_arm(@mut self, &arm, E);
- fn visit_pat(@mut self, @pat, E);
- fn visit_decl(@mut self, @decl, E);
- fn visit_expr(@mut self, @expr, E);
- fn visit_expr_post(@mut self, @expr, E);
- fn visit_ty(@mut self, &Ty, E);
- fn visit_generics(@mut self, &Generics, E);
- fn visit_fn(@mut self, &fn_kind, &fn_decl, &Block, span, NodeId, E);
- fn visit_ty_method(@mut self, &TypeMethod, E);
- fn visit_trait_method(@mut self, &trait_method, E);
- fn visit_struct_def(@mut self, @struct_def, ident, &Generics, NodeId, E);
- fn visit_struct_field(@mut self, @struct_field, E);
-}
-
-pub fn visit_crate<E:Clone>(visitor: @mut Visitor<E>, crate: &Crate, env: E) {
+pub trait Visitor<E:Clone> {
+ fn visit_mod(&mut self, m:&_mod, _s:span, _n:NodeId, e:E) { walk_mod(self, m, e) }
+ fn visit_view_item(&mut self, i:&view_item, e:E) { walk_view_item(self, i, e) }
+ fn visit_foreign_item(&mut self, i:@foreign_item, e:E) { walk_foreign_item(self, i, e) }
+ fn visit_item(&mut self, i:@item, e:E) { walk_item(self, i, e) }
+ fn visit_local(&mut self, l:@Local, e:E) { walk_local(self, l, e) }
+ fn visit_block(&mut self, b:&Block, e:E) { walk_block(self, b, e) }
+ fn visit_stmt(&mut self, s:@stmt, e:E) { walk_stmt(self, s, e) }
+ fn visit_arm(&mut self, a:&arm, e:E) { walk_arm(self, a, e) }
+ fn visit_pat(&mut self, p:@pat, e:E) { walk_pat(self, p, e) }
+ fn visit_decl(&mut self, d:@decl, e:E) { walk_decl(self, d, e) }
+ fn visit_expr(&mut self, ex:@expr, e:E) { walk_expr(self, ex, e) }
+ fn visit_expr_post(&mut self, _ex:@expr, _e:E) { }
+ fn visit_ty(&mut self, _t:&Ty, _e:E) { }
+ fn visit_generics(&mut self, g:&Generics, e:E) { walk_generics(self, g, e) }
+ fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, b:&Block, s:span, n:NodeId, e:E) {
+ walk_fn(self, fk, fd, b, s, n , e)
+ }
+ fn visit_ty_method(&mut self, t:&TypeMethod, e:E) { walk_ty_method(self, t, e) }
+ fn visit_trait_method(&mut self, t:&trait_method, e:E) { walk_trait_method(self, t, e) }
+ fn visit_struct_def(&mut self, s:@struct_def, i:ident, g:&Generics, n:NodeId, e:E) {
+ walk_struct_def(self, s, i, g, n, e)
+ }
+ fn visit_struct_field(&mut self, s:@struct_field, e:E) { walk_struct_field(self, s, e) }
+}
+
+impl<E:Clone> Visitor<E> for @mut Visitor<E> {
+ fn visit_mod(&mut self, a:&_mod, b:span, c:NodeId, e:E) {
+ (*self).visit_mod(a, b, c, e)
+ }
+ fn visit_view_item(&mut self, a:&view_item, e:E) {
+ (*self).visit_view_item(a, e)
+ }
+ fn visit_foreign_item(&mut self, a:@foreign_item, e:E) {
+ (*self).visit_foreign_item(a, e)
+ }
+ fn visit_item(&mut self, a:@item, e:E) {
+ (*self).visit_item(a, e)
+ }
+ fn visit_local(&mut self, a:@Local, e:E) {
+ (*self).visit_local(a, e)
+ }
+ fn visit_block(&mut self, a:&Block, e:E) {
+ (*self).visit_block(a, e)
+ }
+ fn visit_stmt(&mut self, a:@stmt, e:E) {
+ (*self).visit_stmt(a, e)
+ }
+ fn visit_arm(&mut self, a:&arm, e:E) {
+ (*self).visit_arm(a, e)
+ }
+ fn visit_pat(&mut self, a:@pat, e:E) {
+ (*self).visit_pat(a, e)
+ }
+ fn visit_decl(&mut self, a:@decl, e:E) {
+ (*self).visit_decl(a, e)
+ }
+ fn visit_expr(&mut self, a:@expr, e:E) {
+ (*self).visit_expr(a, e)
+ }
+ fn visit_expr_post(&mut self, a:@expr, e:E) {
+ (*self).visit_expr_post(a, e)
+ }
+ fn visit_ty(&mut self, a:&Ty, e:E) {
+ (*self).visit_ty(a, e)
+ }
+ fn visit_generics(&mut self, a:&Generics, e:E) {
+ (*self).visit_generics(a, e)
+ }
+ fn visit_fn(&mut self, a:&fn_kind, b:&fn_decl, c:&Block, d:span, f:NodeId, e:E) {
+ (*self).visit_fn(a, b, c, d, f, e)
+ }
+ fn visit_ty_method(&mut self, a:&TypeMethod, e:E) {
+ (*self).visit_ty_method(a, e)
+ }
+ fn visit_trait_method(&mut self, a:&trait_method, e:E) {
+ (*self).visit_trait_method(a, e)
+ }
+ fn visit_struct_def(&mut self, a:@struct_def, b:ident, c:&Generics, d:NodeId, e:E) {
+ (*self).visit_struct_def(a, b, c, d, e)
+ }
+ fn visit_struct_field(&mut self, a:@struct_field, e:E) {
+ (*self).visit_struct_field(a, e)
+ }
+}
+
+pub fn walk_crate<E:Clone, V:Visitor<E>>(visitor: &mut V, crate: &Crate, env: E) {
visitor.visit_mod(&crate.module, crate.span, CRATE_NODE_ID, env)
}
-pub fn visit_mod<E:Clone>(visitor: @mut Visitor<E>, module: &_mod, env: E) {
+pub fn walk_mod<E:Clone, V:Visitor<E>>(visitor: &mut V, module: &_mod, env: E) {
for view_item in module.view_items.iter() {
visitor.visit_view_item(view_item, env.clone())
}
}
}
-pub fn visit_view_item<E:Clone>(_: @mut Visitor<E>, _: &view_item, _: E) {
+pub fn walk_view_item<E:Clone, V:Visitor<E>>(_: &mut V, _: &view_item, _: E) {
// Empty!
}
-pub fn visit_local<E:Clone>(visitor: @mut Visitor<E>, local: &Local, env: E) {
+pub fn walk_local<E:Clone, V:Visitor<E>>(visitor: &mut V, local: &Local, env: E) {
visitor.visit_pat(local.pat, env.clone());
visitor.visit_ty(&local.ty, env.clone());
match local.init {
}
}
-fn visit_trait_ref<E:Clone>(visitor: @mut Visitor<E>,
+fn walk_trait_ref<E:Clone, V:Visitor<E>>(visitor: &mut V,
trait_ref: &ast::trait_ref,
env: E) {
- visit_path(visitor, &trait_ref.path, env)
+ walk_path(visitor, &trait_ref.path, env)
}
-pub fn visit_item<E:Clone>(visitor: @mut Visitor<E>, item: &item, env: E) {
+pub fn walk_item<E:Clone, V:Visitor<E>>(visitor: &mut V, item: &item, env: E) {
match item.node {
item_static(ref typ, _, expr) => {
visitor.visit_ty(typ, env.clone());
}
item_enum(ref enum_definition, ref type_parameters) => {
visitor.visit_generics(type_parameters, env.clone());
- visit_enum_def(visitor, enum_definition, type_parameters, env)
+ walk_enum_def(visitor, enum_definition, type_parameters, env)
}
item_impl(ref type_parameters,
ref trait_references,
ref methods) => {
visitor.visit_generics(type_parameters, env.clone());
for trait_reference in trait_references.iter() {
- visit_trait_ref(visitor, trait_reference, env.clone())
+ walk_trait_ref(visitor, trait_reference, env.clone())
}
visitor.visit_ty(typ, env.clone());
for method in methods.iter() {
- visit_method_helper(visitor, *method, env.clone())
+ walk_method_helper(visitor, *method, env.clone())
}
}
item_struct(struct_definition, ref generics) => {
item_trait(ref generics, ref trait_paths, ref methods) => {
visitor.visit_generics(generics, env.clone());
for trait_path in trait_paths.iter() {
- visit_path(visitor, &trait_path.path, env.clone())
+ walk_path(visitor, &trait_path.path, env.clone())
}
for method in methods.iter() {
visitor.visit_trait_method(method, env.clone())
}
}
- item_mac(ref macro) => visit_mac(visitor, macro, env),
+ item_mac(ref macro) => walk_mac(visitor, macro, env),
}
}
-pub fn visit_enum_def<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_enum_def<E:Clone, V:Visitor<E>>(visitor: &mut V,
enum_definition: &ast::enum_def,
generics: &Generics,
env: E) {
}
}
-pub fn skip_ty<E>(_: @mut Visitor<E>, _: &Ty, _: E) {
+pub fn skip_ty<E, V:Visitor<E>>(_: &mut V, _: &Ty, _: E) {
// Empty!
}
-pub fn visit_ty<E:Clone>(visitor: @mut Visitor<E>, typ: &Ty, env: E) {
+pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
match typ.node {
ty_box(ref mutable_type) | ty_uniq(ref mutable_type) |
ty_vec(ref mutable_type) | ty_ptr(ref mutable_type) |
}
visitor.visit_ty(&function_declaration.decl.output, env.clone());
for bounds in function_declaration.bounds.iter() {
- visit_ty_param_bounds(visitor, bounds, env.clone())
+ walk_ty_param_bounds(visitor, bounds, env.clone())
}
}
ty_bare_fn(ref function_declaration) => {
visitor.visit_ty(&function_declaration.decl.output, env.clone())
}
ty_path(ref path, ref bounds, _) => {
- visit_path(visitor, path, env.clone());
+ walk_path(visitor, path, env.clone());
for bounds in bounds.iter() {
- visit_ty_param_bounds(visitor, bounds, env.clone())
+ walk_ty_param_bounds(visitor, bounds, env.clone())
}
}
ty_fixed_length_vec(ref mutable_type, expression) => {
}
}
-pub fn visit_path<E:Clone>(visitor: @mut Visitor<E>, path: &Path, env: E) {
+pub fn walk_path<E:Clone, V:Visitor<E>>(visitor: &mut V, path: &Path, env: E) {
for typ in path.types.iter() {
visitor.visit_ty(typ, env.clone())
}
}
-pub fn visit_pat<E:Clone>(visitor: @mut Visitor<E>, pattern: &pat, env: E) {
+pub fn walk_pat<E:Clone, V:Visitor<E>>(visitor: &mut V, pattern: &pat, env: E) {
match pattern.node {
pat_enum(ref path, ref children) => {
- visit_path(visitor, path, env.clone());
+ walk_path(visitor, path, env.clone());
for children in children.iter() {
for child in children.iter() {
visitor.visit_pat(*child, env.clone())
}
}
pat_struct(ref path, ref fields, _) => {
- visit_path(visitor, path, env.clone());
+ walk_path(visitor, path, env.clone());
for field in fields.iter() {
visitor.visit_pat(field.pat, env.clone())
}
visitor.visit_pat(subpattern, env)
}
pat_ident(_, ref path, ref optional_subpattern) => {
- visit_path(visitor, path, env.clone());
+ walk_path(visitor, path, env.clone());
match *optional_subpattern {
None => {}
Some(subpattern) => visitor.visit_pat(subpattern, env),
}
}
-pub fn visit_foreign_item<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_foreign_item<E:Clone, V:Visitor<E>>(visitor: &mut V,
foreign_item: &foreign_item,
env: E) {
match foreign_item.node {
foreign_item_fn(ref function_declaration, ref generics) => {
- visit_fn_decl(visitor, function_declaration, env.clone());
+ walk_fn_decl(visitor, function_declaration, env.clone());
visitor.visit_generics(generics, env)
}
foreign_item_static(ref typ, _) => visitor.visit_ty(typ, env),
}
}
-pub fn visit_ty_param_bounds<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_ty_param_bounds<E:Clone, V:Visitor<E>>(visitor: &mut V,
bounds: &OptVec<TyParamBound>,
env: E) {
for bound in bounds.iter() {
match *bound {
TraitTyParamBound(ref typ) => {
- visit_trait_ref(visitor, typ, env.clone())
+ walk_trait_ref(visitor, typ, env.clone())
}
RegionTyParamBound => {}
}
}
}
-pub fn visit_generics<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_generics<E:Clone, V:Visitor<E>>(visitor: &mut V,
generics: &Generics,
env: E) {
for type_parameter in generics.ty_params.iter() {
- visit_ty_param_bounds(visitor, &type_parameter.bounds, env.clone())
+ walk_ty_param_bounds(visitor, &type_parameter.bounds, env.clone())
}
}
-pub fn visit_fn_decl<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_fn_decl<E:Clone, V:Visitor<E>>(visitor: &mut V,
function_declaration: &fn_decl,
env: E) {
for argument in function_declaration.inputs.iter() {
// visit_fn() and check for fk_method(). I named this visit_method_helper()
// because it is not a default impl of any method, though I doubt that really
// clarifies anything. - Niko
-pub fn visit_method_helper<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_method_helper<E:Clone, V:Visitor<E>>(visitor: &mut V,
method: &method,
env: E) {
visitor.visit_fn(&fk_method(method.ident, &method.generics, method),
env)
}
-pub fn visit_fn<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_fn<E:Clone, V:Visitor<E>>(visitor: &mut V,
function_kind: &fn_kind,
function_declaration: &fn_decl,
function_body: &Block,
_: span,
_: NodeId,
env: E) {
- visit_fn_decl(visitor, function_declaration, env.clone());
+ walk_fn_decl(visitor, function_declaration, env.clone());
let generics = generics_of_fn(function_kind);
visitor.visit_generics(&generics, env.clone());
visitor.visit_block(function_body, env)
}
-pub fn visit_ty_method<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_ty_method<E:Clone, V:Visitor<E>>(visitor: &mut V,
method_type: &TypeMethod,
env: E) {
for argument_type in method_type.decl.inputs.iter() {
visitor.visit_ty(&method_type.decl.output, env.clone())
}
-pub fn visit_trait_method<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_trait_method<E:Clone, V:Visitor<E>>(visitor: &mut V,
trait_method: &trait_method,
env: E) {
match *trait_method {
required(ref method_type) => {
visitor.visit_ty_method(method_type, env)
}
- provided(method) => visit_method_helper(visitor, method, env),
+ provided(method) => walk_method_helper(visitor, method, env),
}
}
-pub fn visit_struct_def<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_struct_def<E:Clone, V:Visitor<E>>(visitor: &mut V,
struct_definition: @struct_def,
_: ast::ident,
_: &Generics,
}
}
-pub fn visit_struct_field<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_struct_field<E:Clone, V:Visitor<E>>(visitor: &mut V,
struct_field: &struct_field,
env: E) {
visitor.visit_ty(&struct_field.node.ty, env)
}
-pub fn visit_block<E:Clone>(visitor: @mut Visitor<E>, block: &Block, env: E) {
+pub fn walk_block<E:Clone, V:Visitor<E>>(visitor: &mut V, block: &Block, env: E) {
for view_item in block.view_items.iter() {
visitor.visit_view_item(view_item, env.clone())
}
for statement in block.stmts.iter() {
visitor.visit_stmt(*statement, env.clone())
}
- visit_expr_opt(visitor, block.expr, env)
+ walk_expr_opt(visitor, block.expr, env)
}
-pub fn visit_stmt<E>(visitor: @mut Visitor<E>, statement: &stmt, env: E) {
+pub fn walk_stmt<E:Clone, V:Visitor<E>>(visitor: &mut V, statement: &stmt, env: E) {
match statement.node {
stmt_decl(declaration, _) => visitor.visit_decl(declaration, env),
stmt_expr(expression, _) | stmt_semi(expression, _) => {
visitor.visit_expr(expression, env)
}
- stmt_mac(ref macro, _) => visit_mac(visitor, macro, env),
+ stmt_mac(ref macro, _) => walk_mac(visitor, macro, env),
}
}
-pub fn visit_decl<E:Clone>(visitor: @mut Visitor<E>, declaration: &decl, env: E) {
+pub fn walk_decl<E:Clone, V:Visitor<E>>(visitor: &mut V, declaration: &decl, env: E) {
match declaration.node {
decl_local(ref local) => visitor.visit_local(*local, env),
decl_item(item) => visitor.visit_item(item, env),
}
}
-pub fn visit_expr_opt<E>(visitor: @mut Visitor<E>,
+pub fn walk_expr_opt<E:Clone, V:Visitor<E>>(visitor: &mut V,
optional_expression: Option<@expr>,
env: E) {
match optional_expression {
}
}
-pub fn visit_exprs<E:Clone>(visitor: @mut Visitor<E>,
+pub fn walk_exprs<E:Clone, V:Visitor<E>>(visitor: &mut V,
expressions: &[@expr],
env: E) {
for expression in expressions.iter() {
}
}
-pub fn visit_mac<E>(_: @mut Visitor<E>, _: &mac, _: E) {
+pub fn walk_mac<E, V:Visitor<E>>(_: &mut V, _: &mac, _: E) {
// Empty!
}
-pub fn visit_expr<E:Clone>(visitor: @mut Visitor<E>, expression: @expr, env: E) {
+pub fn walk_expr<E:Clone, V:Visitor<E>>(visitor: &mut V, expression: @expr, env: E) {
match expression.node {
expr_vstore(subexpression, _) => {
visitor.visit_expr(subexpression, env.clone())
}
expr_vec(ref subexpressions, _) => {
- visit_exprs(visitor, *subexpressions, env.clone())
+ walk_exprs(visitor, *subexpressions, env.clone())
}
expr_repeat(element, count, _) => {
visitor.visit_expr(element, env.clone());
visitor.visit_expr(count, env.clone())
}
expr_struct(ref path, ref fields, optional_base) => {
- visit_path(visitor, path, env.clone());
+ walk_path(visitor, path, env.clone());
for field in fields.iter() {
visitor.visit_expr(field.expr, env.clone())
}
- visit_expr_opt(visitor, optional_base, env.clone())
+ walk_expr_opt(visitor, optional_base, env.clone())
}
expr_tup(ref subexpressions) => {
for subexpression in subexpressions.iter() {
visitor.visit_expr(callee_expression, env.clone())
}
expr_method_call(_, callee, _, ref types, ref arguments, _) => {
- visit_exprs(visitor, *arguments, env.clone());
+ walk_exprs(visitor, *arguments, env.clone());
for typ in types.iter() {
visitor.visit_ty(typ, env.clone())
}
expr_if(head_expression, ref if_block, optional_else) => {
visitor.visit_expr(head_expression, env.clone());
visitor.visit_block(if_block, env.clone());
- visit_expr_opt(visitor, optional_else, env.clone())
+ walk_expr_opt(visitor, optional_else, env.clone())
}
expr_while(subexpression, ref block) => {
visitor.visit_expr(subexpression, env.clone());
visitor.visit_expr(main_expression, env.clone());
visitor.visit_expr(index_expression, env.clone())
}
- expr_path(ref path) => visit_path(visitor, path, env.clone()),
+ expr_path(ref path) => walk_path(visitor, path, env.clone()),
expr_self | expr_break(_) | expr_again(_) => {}
expr_ret(optional_expression) => {
- visit_expr_opt(visitor, optional_expression, env.clone())
+ walk_expr_opt(visitor, optional_expression, env.clone())
}
expr_log(level, subexpression) => {
visitor.visit_expr(level, env.clone());
visitor.visit_expr(subexpression, env.clone());
}
- expr_mac(ref macro) => visit_mac(visitor, macro, env.clone()),
+ expr_mac(ref macro) => walk_mac(visitor, macro, env.clone()),
expr_paren(subexpression) => {
visitor.visit_expr(subexpression, env.clone())
}
visitor.visit_expr_post(expression, env.clone())
}
-pub fn visit_arm<E:Clone>(visitor: @mut Visitor<E>, arm: &arm, env: E) {
+pub fn walk_arm<E:Clone, V:Visitor<E>>(visitor: &mut V, arm: &arm, env: E) {
for pattern in arm.pats.iter() {
visitor.visit_pat(*pattern, env.clone())
}
- visit_expr_opt(visitor, arm.guard, env.clone());
+ walk_expr_opt(visitor, arm.guard, env.clone());
visitor.visit_block(&arm.body, env)
}
// calls the given functions on the nodes.
pub trait SimpleVisitor {
- fn visit_mod(@mut self, &_mod, span, NodeId);
- fn visit_view_item(@mut self, &view_item);
- fn visit_foreign_item(@mut self, @foreign_item);
- fn visit_item(@mut self, @item);
- fn visit_local(@mut self, @Local);
- fn visit_block(@mut self, &Block);
- fn visit_stmt(@mut self, @stmt);
- fn visit_arm(@mut self, &arm);
- fn visit_pat(@mut self, @pat);
- fn visit_decl(@mut self, @decl);
- fn visit_expr(@mut self, @expr);
- fn visit_expr_post(@mut self, @expr);
- fn visit_ty(@mut self, &Ty);
- fn visit_generics(@mut self, &Generics);
- fn visit_fn(@mut self, &fn_kind, &fn_decl, &Block, span, NodeId);
- fn visit_ty_method(@mut self, &TypeMethod);
- fn visit_trait_method(@mut self, &trait_method);
- fn visit_struct_def(@mut self, @struct_def, ident, &Generics, NodeId);
- fn visit_struct_field(@mut self, @struct_field);
- fn visit_struct_method(@mut self, @method);
+ fn visit_mod(&mut self, &_mod, span, NodeId);
+ fn visit_view_item(&mut self, &view_item);
+ fn visit_foreign_item(&mut self, @foreign_item);
+ fn visit_item(&mut self, @item);
+ fn visit_local(&mut self, @Local);
+ fn visit_block(&mut self, &Block);
+ fn visit_stmt(&mut self, @stmt);
+ fn visit_arm(&mut self, &arm);
+ fn visit_pat(&mut self, @pat);
+ fn visit_decl(&mut self, @decl);
+ fn visit_expr(&mut self, @expr);
+ fn visit_expr_post(&mut self, @expr);
+ fn visit_ty(&mut self, &Ty);
+ fn visit_generics(&mut self, &Generics);
+ fn visit_fn(&mut self, &fn_kind, &fn_decl, &Block, span, NodeId);
+ fn visit_ty_method(&mut self, &TypeMethod);
+ fn visit_trait_method(&mut self, &trait_method);
+ fn visit_struct_def(&mut self, @struct_def, ident, &Generics, NodeId);
+ fn visit_struct_field(&mut self, @struct_field);
+ fn visit_struct_method(&mut self, @method);
}
pub struct SimpleVisitorVisitor {
}
impl Visitor<()> for SimpleVisitorVisitor {
- fn visit_mod(@mut self,
+ fn visit_mod(&mut self,
module: &_mod,
span: span,
node_id: NodeId,
env: ()) {
self.simple_visitor.visit_mod(module, span, node_id);
- visit_mod(self as @mut Visitor<()>, module, env)
+ walk_mod(self, module, env)
}
- fn visit_view_item(@mut self, view_item: &view_item, env: ()) {
+ fn visit_view_item(&mut self, view_item: &view_item, env: ()) {
self.simple_visitor.visit_view_item(view_item);
- visit_view_item(self as @mut Visitor<()>, view_item, env)
+ walk_view_item(self, view_item, env)
}
- fn visit_foreign_item(@mut self, foreign_item: @foreign_item, env: ()) {
+ fn visit_foreign_item(&mut self, foreign_item: @foreign_item, env: ()) {
self.simple_visitor.visit_foreign_item(foreign_item);
- visit_foreign_item(self as @mut Visitor<()>, foreign_item, env)
+ walk_foreign_item(self, foreign_item, env)
}
- fn visit_item(@mut self, item: @item, env: ()) {
+ fn visit_item(&mut self, item: @item, env: ()) {
self.simple_visitor.visit_item(item);
- visit_item(self as @mut Visitor<()>, item, env)
+ walk_item(self, item, env)
}
- fn visit_local(@mut self, local: @Local, env: ()) {
+ fn visit_local(&mut self, local: @Local, env: ()) {
self.simple_visitor.visit_local(local);
- visit_local(self as @mut Visitor<()>, local, env)
+ walk_local(self, local, env)
}
- fn visit_block(@mut self, block: &Block, env: ()) {
+ fn visit_block(&mut self, block: &Block, env: ()) {
self.simple_visitor.visit_block(block);
- visit_block(self as @mut Visitor<()>, block, env)
+ walk_block(self, block, env)
}
- fn visit_stmt(@mut self, statement: @stmt, env: ()) {
+ fn visit_stmt(&mut self, statement: @stmt, env: ()) {
self.simple_visitor.visit_stmt(statement);
- visit_stmt(self as @mut Visitor<()>, statement, env)
+ walk_stmt(self, statement, env)
}
- fn visit_arm(@mut self, arm: &arm, env: ()) {
+ fn visit_arm(&mut self, arm: &arm, env: ()) {
self.simple_visitor.visit_arm(arm);
- visit_arm(self as @mut Visitor<()>, arm, env)
+ walk_arm(self, arm, env)
}
- fn visit_pat(@mut self, pattern: @pat, env: ()) {
+ fn visit_pat(&mut self, pattern: @pat, env: ()) {
self.simple_visitor.visit_pat(pattern);
- visit_pat(self as @mut Visitor<()>, pattern, env)
+ walk_pat(self, pattern, env)
}
- fn visit_decl(@mut self, declaration: @decl, env: ()) {
+ fn visit_decl(&mut self, declaration: @decl, env: ()) {
self.simple_visitor.visit_decl(declaration);
- visit_decl(self as @mut Visitor<()>, declaration, env)
+ walk_decl(self, declaration, env)
}
- fn visit_expr(@mut self, expression: @expr, env: ()) {
+ fn visit_expr(&mut self, expression: @expr, env: ()) {
self.simple_visitor.visit_expr(expression);
- visit_expr(self as @mut Visitor<()>, expression, env)
+ walk_expr(self, expression, env)
}
- fn visit_expr_post(@mut self, expression: @expr, _: ()) {
+ fn visit_expr_post(&mut self, expression: @expr, _: ()) {
self.simple_visitor.visit_expr_post(expression)
}
- fn visit_ty(@mut self, typ: &Ty, env: ()) {
+ fn visit_ty(&mut self, typ: &Ty, env: ()) {
self.simple_visitor.visit_ty(typ);
- visit_ty(self as @mut Visitor<()>, typ, env)
+ walk_ty(self, typ, env)
}
- fn visit_generics(@mut self, generics: &Generics, env: ()) {
+ fn visit_generics(&mut self, generics: &Generics, env: ()) {
self.simple_visitor.visit_generics(generics);
- visit_generics(self as @mut Visitor<()>, generics, env)
+ walk_generics(self, generics, env)
}
- fn visit_fn(@mut self,
+ fn visit_fn(&mut self,
function_kind: &fn_kind,
function_declaration: &fn_decl,
block: &Block,
block,
span,
node_id);
- visit_fn(self as @mut Visitor<()>,
+ walk_fn(self,
function_kind,
function_declaration,
block,
node_id,
env)
}
- fn visit_ty_method(@mut self, method_type: &TypeMethod, env: ()) {
+ fn visit_ty_method(&mut self, method_type: &TypeMethod, env: ()) {
self.simple_visitor.visit_ty_method(method_type);
- visit_ty_method(self as @mut Visitor<()>, method_type, env)
+ walk_ty_method(self, method_type, env)
}
- fn visit_trait_method(@mut self, trait_method: &trait_method, env: ()) {
+ fn visit_trait_method(&mut self, trait_method: &trait_method, env: ()) {
self.simple_visitor.visit_trait_method(trait_method);
- visit_trait_method(self as @mut Visitor<()>, trait_method, env)
+ walk_trait_method(self, trait_method, env)
}
- fn visit_struct_def(@mut self,
+ fn visit_struct_def(&mut self,
struct_definition: @struct_def,
identifier: ident,
generics: &Generics,
identifier,
generics,
node_id);
- visit_struct_def(self as @mut Visitor<()>,
+ walk_struct_def(self,
struct_definition,
identifier,
generics,
node_id,
env)
}
- fn visit_struct_field(@mut self, struct_field: @struct_field, env: ()) {
+ fn visit_struct_field(&mut self, struct_field: @struct_field, env: ()) {
self.simple_visitor.visit_struct_field(struct_field);
- visit_struct_field(self as @mut Visitor<()>, struct_field, env)
+ walk_struct_field(self, struct_field, env)
}
}
-Subproject commit f67442eee27d3d075a65cf7f9a70f7ec6649ffd1
+Subproject commit 0964c68ddf2c67ce455e7443a06f4bb3db9e92bb
#include "memory_region.h"
#include "boxed_region.h"
#include "rust_globals.h"
-#include "rust_env.h"
#include "rust_util.h"
// #define DUMP_BOXED_REGION
force_lazy_lock="1"
;;
+ *-*-linux-android*)
+ CFLAGS="$CFLAGS"
+ CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
+ abi="elf"
+ $as_echo "#define JEMALLOC_HAS_ALLOCA_H 1" >>confdefs.h
+
+ $as_echo "#define JEMALLOC_PURGE_MADVISE_DONTNEED " >>confdefs.h
+
+ $as_echo "#define JEMALLOC_THREADED_INIT " >>confdefs.h
+
+ default_munmap="0"
+ ;;
*-*-linux*)
CFLAGS="$CFLAGS"
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
CTARGET='-o $@'
LDTARGET='-o $@'
EXTRA_LDFLAGS=
-MKLIB='ar crus $@'
+MKLIB='$(AR) crus $@'
CC_MM=1
dnl Platform-specific settings. abi and RPATH can probably be determined
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
force_lazy_lock="1"
;;
+ *-*-linux-android*)
+ CFLAGS="$CFLAGS"
+ CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
+ abi="elf"
+ AC_DEFINE([JEMALLOC_HAS_ALLOCA_H])
+ AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ])
+ AC_DEFINE([JEMALLOC_THREADED_INIT], [ ])
+ default_munmap="0"
+ ;;
*-*-linux*)
CFLAGS="$CFLAGS"
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
return RUNNING_ON_VALGRIND;
}
-extern int get_num_cpus();
+#if defined(__WIN32__)
+int
+get_num_cpus() {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+
+ return (int) sysinfo.dwNumberOfProcessors;
+}
+#elif defined(__BSD__)
+int
+get_num_cpus() {
+ /* swiped from http://stackoverflow.com/questions/150355/
+ programmatically-find-the-number-of-cores-on-a-machine */
+
+ unsigned int numCPU;
+ int mib[4];
+ size_t len = sizeof(numCPU);
+
+ /* set the mib for hw.ncpu */
+ mib[0] = CTL_HW;
+ mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
+
+ /* get the number of CPUs from the system */
+ sysctl(mib, 2, &numCPU, &len, NULL, 0);
+
+ if( numCPU < 1 ) {
+ mib[1] = HW_NCPU;
+ sysctl( mib, 2, &numCPU, &len, NULL, 0 );
+
+ if( numCPU < 1 ) {
+ numCPU = 1;
+ }
+ }
+ return numCPU;
+}
+#elif defined(__GNUC__)
+int
+get_num_cpus() {
+ return sysconf(_SC_NPROCESSORS_ONLN);
+}
+#endif
extern "C" CDECL uintptr_t
rust_get_num_cpus() {
return 0;
}
+static lock_and_signal env_lock;
+
+extern "C" CDECL void
+rust_take_env_lock() {
+ env_lock.lock();
+}
+
+extern "C" CDECL void
+rust_drop_env_lock() {
+ env_lock.unlock();
+}
+
+extern "C" CDECL unsigned int
+rust_valgrind_stack_register(void *start, void *end) {
+ return VALGRIND_STACK_REGISTER(start, end);
+}
+
+extern "C" CDECL void
+rust_valgrind_stack_deregister(unsigned int id) {
+ VALGRIND_STACK_DEREGISTER(id);
+}
+
//
// Local Variables:
// mode: C++
+++ /dev/null
-// 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 runtime wants to pull a number of variables out of the
-// environment but calling getenv is not threadsafe, so every value
-// that might come from the environment is loaded here, once, during
-// init.
-
-#include "sync/lock_and_signal.h"
-#include "rust_env.h"
-
-// The environment variables that the runtime knows about
-#define RUST_THREADS "RUST_THREADS"
-#define RUST_MIN_STACK "RUST_MIN_STACK"
-#define RUST_MAX_STACK "RUST_MAX_STACK"
-#define RUST_LOG "RUST_LOG"
-#define DETAILED_LEAKS "DETAILED_LEAKS"
-#define RUST_SEED "RUST_SEED"
-#define RUST_POISON_ON_FREE "RUST_POISON_ON_FREE"
-#define RUST_DEBUG_MEM "RUST_DEBUG_MEM"
-#define RUST_DEBUG_BORROW "RUST_DEBUG_BORROW"
-
-#define DEFAULT_RUST_MIN_STACK_32 0x300
-#define DEFAULT_RUST_MIN_STACK_64 0x400000
-
-static lock_and_signal env_lock;
-
-extern "C" CDECL void
-rust_take_env_lock() {
- env_lock.lock();
-}
-
-extern "C" CDECL void
-rust_drop_env_lock() {
- env_lock.unlock();
-}
-
-#if defined(__WIN32__)
-int
-get_num_cpus() {
- SYSTEM_INFO sysinfo;
- GetSystemInfo(&sysinfo);
-
- return (int) sysinfo.dwNumberOfProcessors;
-}
-#elif defined(__BSD__)
-int
-get_num_cpus() {
- /* swiped from http://stackoverflow.com/questions/150355/
- programmatically-find-the-number-of-cores-on-a-machine */
-
- unsigned int numCPU;
- int mib[4];
- size_t len = sizeof(numCPU);
-
- /* set the mib for hw.ncpu */
- mib[0] = CTL_HW;
- mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
-
- /* get the number of CPUs from the system */
- sysctl(mib, 2, &numCPU, &len, NULL, 0);
-
- if( numCPU < 1 ) {
- mib[1] = HW_NCPU;
- sysctl( mib, 2, &numCPU, &len, NULL, 0 );
-
- if( numCPU < 1 ) {
- numCPU = 1;
- }
- }
- return numCPU;
-}
-#elif defined(__GNUC__)
-int
-get_num_cpus() {
- return sysconf(_SC_NPROCESSORS_ONLN);
-}
-#endif
-
-static int
-get_num_threads()
-{
- char *env = getenv(RUST_THREADS);
- if(env) {
- int num = atoi(env);
- if(num > 0)
- return num;
- }
- return get_num_cpus();
-}
-
-static size_t
-get_min_stk_size() {
- char *minsz = getenv(RUST_MIN_STACK);
- if(minsz) {
- return strtol(minsz, NULL, 0);
- }
- else if (sizeof(size_t) > 4) {
- return DEFAULT_RUST_MIN_STACK_64;
- } else {
- return DEFAULT_RUST_MIN_STACK_32;
- }
-}
-
-static size_t
-get_max_stk_size() {
- char *maxsz = getenv(RUST_MAX_STACK);
- if (maxsz) {
- return strtol(maxsz, NULL, 0);
- }
- else {
- return 1024*1024*1024;
- }
-}
-
-static char*
-copyenv(const char* name) {
- char *envvar = getenv(name);
- if (!envvar) {
- return NULL;
- } else {
- size_t slen = strlen(envvar);
- size_t buflen = slen + 1;
- char *var = (char*)malloc(buflen);
- memset(var, 0, buflen);
- strncpy(var, envvar, slen);
- return var;
- }
-}
-
-rust_env*
-load_env(int argc, char **argv) {
- scoped_lock with(env_lock);
-
- rust_env *env = (rust_env*)malloc(sizeof(rust_env));
-
- env->num_sched_threads = (size_t)get_num_threads();
- env->min_stack_size = get_min_stk_size();
- env->max_stack_size = get_max_stk_size();
- env->logspec = copyenv(RUST_LOG);
- env->detailed_leaks = getenv(DETAILED_LEAKS) != NULL;
- env->rust_seed = copyenv(RUST_SEED);
- env->poison_on_free = getenv(RUST_POISON_ON_FREE) != NULL;
- env->argc = argc;
- env->argv = argv;
- env->debug_mem = getenv(RUST_DEBUG_MEM) != NULL;
- env->debug_borrow = getenv(RUST_DEBUG_BORROW) != NULL;
- return env;
-}
-
-void
-free_env(rust_env *env) {
- free(env->logspec);
- free(env->rust_seed);
- free(env);
-}
+++ /dev/null
-// 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.
-
-
-#ifndef RUST_ENV_H
-#define RUST_ENV_H
-
-#include "rust_globals.h"
-
-// Avoiding 'bool' type here since I'm not sure it has a standard size
-typedef uint8_t rust_bool;
-
-struct rust_env {
- size_t num_sched_threads;
- size_t min_stack_size;
- size_t max_stack_size;
- char* logspec;
- rust_bool detailed_leaks;
- char* rust_seed;
- rust_bool poison_on_free;
- int argc;
- char **argv;
- rust_bool debug_mem;
- rust_bool debug_borrow;
-};
-
-rust_env* load_env(int argc, char **argv);
-void free_env(rust_env *rust_env);
-
-#endif
#define CDECL __cdecl
#endif
#ifndef FASTCALL
-#define FASTCALL __fastcall
#endif
#else
#define CDECL __attribute__((cdecl))
-#define FASTCALL __attribute__((fastcall))
#endif
#else
#define CDECL
-#define FASTCALL
#endif
#define CHECKED(call) \
} \
}
-#define MUST_CHECK __attribute__((warn_unused_result))
-
-#define PTR "0x%" PRIxPTR
-
-// This accounts for logging buffers.
-static size_t const BUF_BYTES = 2048;
-
-#define INIT_TASK_ID 1
-
-// The error status to use when the process fails
-#define PROC_FAIL_CODE 101
-
-// A cond(ition) is something we can block on. This can be a channel
-// (writing), a port (reading) or a task (waiting).
-struct rust_cond { };
-
-extern void* global_crate_map;
-
#endif /* RUST_GLOBALS_H */
*/
-#include "rust_log.h"
#include "rust_crate_map.h"
#include "util/array_list.h"
#include "rust_util.h"
size_t level;
};
+
+const uint32_t log_err = 1;
+const uint32_t log_warn = 2;
+const uint32_t log_info = 3;
+const uint32_t log_debug = 4;
+
const size_t max_log_directives = 255;
const size_t max_log_level = 255;
const size_t default_log_level = log_err;
// This is a rather ugly parser for strings in the form
// "crate1,crate2.mod3,crate3.x=1". Log levels are 0-255,
-// with the most likely ones being 0-3 (defined in core::).
+// with the most likely ones being 0-3 (defined in std::).
size_t parse_logging_spec(char* spec, log_directive* dirs) {
size_t dir = 0;
while (dir < max_log_directives && *spec) {
}
}
-void update_module_map(const mod_entry* map, log_directive* dirs,
- size_t n_dirs, size_t *n_matches) {
- update_entry_args args = { dirs, n_dirs, n_matches };
- iter_module_map(map, update_entry, &args);
-}
-
void update_crate_map(const cratemap* map, log_directive* dirs,
size_t n_dirs, size_t *n_matches) {
update_entry_args args = { dirs, n_dirs, n_matches };
iter_crate_map(map, print_mod_name, NULL);
}
-// These are pseudo-modules used to control logging in the runtime.
-
-uint32_t log_rt_mem;
-uint32_t log_rt_box;
-uint32_t log_rt_comm;
-uint32_t log_rt_task;
-uint32_t log_rt_dom;
-uint32_t log_rt_trace;
-uint32_t log_rt_cache;
-uint32_t log_rt_upcall;
-uint32_t log_rt_timer;
-uint32_t log_rt_gc;
-uint32_t log_rt_stdlib;
-uint32_t log_rt_kern;
-uint32_t log_rt_backtrace;
-uint32_t log_rt_callback;
-
-static const mod_entry _rt_module_map[] =
- {{"::rt::mem", &log_rt_mem},
- {"::rt::box", &log_rt_box},
- {"::rt::comm", &log_rt_comm},
- {"::rt::task", &log_rt_task},
- {"::rt::dom", &log_rt_dom},
- {"::rt::trace", &log_rt_trace},
- {"::rt::cache", &log_rt_cache},
- {"::rt::upcall", &log_rt_upcall},
- {"::rt::timer", &log_rt_timer},
- {"::rt::gc", &log_rt_gc},
- {"::rt::stdlib", &log_rt_stdlib},
- {"::rt::kern", &log_rt_kern},
- {"::rt::backtrace", &log_rt_backtrace},
- {"::rt::callback", &log_rt_callback},
- {NULL, NULL}};
-
void update_log_settings(void* crate_map, char* settings) {
char* buffer = NULL;
log_directive dirs[256];
}
size_t n_matches = 0;
- update_module_map(_rt_module_map, &dirs[0], n_dirs, &n_matches);
update_crate_map((const cratemap*)crate_map, &dirs[0],
n_dirs, &n_matches);
+++ /dev/null
-// 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.
-
-#ifndef RUST_LOG_H
-#define RUST_LOG_H
-
-#include "rust_globals.h"
-
-const uint32_t log_err = 1;
-const uint32_t log_warn = 2;
-const uint32_t log_info = 3;
-const uint32_t log_debug = 4;
-
-void update_log_settings(void* crate_map, char* settings);
-
-extern uint32_t log_rt_mem;
-extern uint32_t log_rt_box;
-extern uint32_t log_rt_comm;
-extern uint32_t log_rt_task;
-extern uint32_t log_rt_dom;
-extern uint32_t log_rt_trace;
-extern uint32_t log_rt_cache;
-extern uint32_t log_rt_upcall;
-extern uint32_t log_rt_timer;
-extern uint32_t log_rt_gc;
-extern uint32_t log_rt_stdlib;
-extern uint32_t log_rt_kern;
-extern uint32_t log_rt_backtrace;
-extern uint32_t log_rt_callback;
-
-#endif /* RUST_LOG_H */
+++ /dev/null
-// 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.
-
-
-#ifndef RUST_REFCOUNT_H
-#define RUST_REFCOUNT_H
-
-#include "sync/sync.h"
-
-// Refcounting defines
-typedef unsigned long ref_cnt_t;
-
-#define RUST_ATOMIC_REFCOUNT() \
-private: \
- intptr_t ref_count; \
-public: \
- void ref() { \
- intptr_t old = sync::increment(ref_count); \
- assert(old > 0); \
- } \
- void deref() { if(0 == sync::decrement(ref_count)) { delete_this(); } } \
- intptr_t get_ref_count() { return sync::read(ref_count); }
-
-#endif
+++ /dev/null
-// 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.
-
-#ifndef RUST_SIGNAL_H
-#define RUST_SIGNAL_H
-
-// Just an abstract class that represents something that can be signalled
-class rust_signal {
-public:
- virtual void signal() = 0;
- virtual ~rust_signal() {}
- rust_signal() {}
-
-private:
- // private and undefined to disable copying
- rust_signal(const rust_signal& rhs);
- rust_signal& operator=(const rust_signal& rhs);
-};
-
-#endif /* RUST_SIGNAL_H */
+++ /dev/null
-// 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.
-
-
-#include "rust_stack.h"
-#include "vg/valgrind.h"
-#include "vg/memcheck.h"
-
-#include <cstdio>
-
-#ifdef _LP64
-const uintptr_t canary_value = 0xABCDABCDABCDABCD;
-#else
-const uintptr_t canary_value = 0xABCDABCD;
-#endif
-
-void
-register_valgrind_stack(stk_seg *stk) {
- stk->valgrind_id =
- VALGRIND_STACK_REGISTER(&stk->data[0],
- stk->end);
-}
-
-void
-reuse_valgrind_stack(stk_seg *stk, uint8_t *sp) {
- // Establish that the stack is accessible. This must be done when reusing
- // old stack segments, since the act of popping the stack previously
- // caused valgrind to consider the whole thing inaccessible.
- assert(sp >= stk->data && sp <= (uint8_t*) stk->end
- && "Stack pointer must be inside stack segment");
- size_t sz = stk->end - (uintptr_t)sp;
- (void) VALGRIND_MAKE_MEM_UNDEFINED(sp, sz);
- (void) sz;
-}
-
-void
-deregister_valgrind_stack(stk_seg *stk) {
- VALGRIND_STACK_DEREGISTER(stk->valgrind_id);
-}
-
-void
-add_stack_canary(stk_seg *stk) {
- stk->canary = canary_value;
-}
-
-void
-check_stack_canary(stk_seg *stk) {
- assert(stk->canary == canary_value && "Somebody killed the canary");
-}
-
-// XXX: Duplication here between the local and exchange heap constructors
-
-stk_seg *
-create_stack(memory_region *region, size_t sz) {
- size_t total_sz = sizeof(stk_seg) + sz;
- stk_seg *stk = (stk_seg *)region->malloc(total_sz, "stack");
- memset(stk, 0, sizeof(stk_seg));
- stk->end = (uintptr_t) &stk->data[sz];
- stk->is_big = 0;
- add_stack_canary(stk);
- register_valgrind_stack(stk);
- return stk;
-}
-
-void
-destroy_stack(memory_region *region, stk_seg *stk) {
- deregister_valgrind_stack(stk);
- region->free(stk);
-}
-
-stk_seg *
-create_exchange_stack(rust_exchange_alloc *exchange, size_t sz) {
- size_t total_sz = sizeof(stk_seg) + sz;
- stk_seg *stk = (stk_seg *)exchange->malloc(total_sz);
- memset(stk, 0, sizeof(stk_seg));
- stk->end = (uintptr_t) &stk->data[sz];
- stk->is_big = 0;
- add_stack_canary(stk);
- register_valgrind_stack(stk);
- return stk;
-}
-
-void
-destroy_exchange_stack(rust_exchange_alloc *exchange, stk_seg *stk) {
- deregister_valgrind_stack(stk);
- exchange->free(stk);
-}
-
-
-extern "C" CDECL unsigned int
-rust_valgrind_stack_register(void *start, void *end) {
- return VALGRIND_STACK_REGISTER(start, end);
-}
-
-extern "C" CDECL void
-rust_valgrind_stack_deregister(unsigned int id) {
- VALGRIND_STACK_DEREGISTER(id);
-}
+++ /dev/null
-// 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.
-
-#ifndef RUST_STACK_H
-#define RUST_STACK_H
-
-#include "rust_globals.h"
-#include "rust_exchange_alloc.h"
-#include "memory_region.h"
-
-struct rust_task;
-
-struct stk_seg {
- stk_seg *prev;
- stk_seg *next;
- uintptr_t end;
- unsigned int valgrind_id;
- uint8_t is_big;
-
- rust_task *task;
- uintptr_t canary;
-
- uint8_t data[];
-};
-
-stk_seg *
-create_stack(memory_region *region, size_t sz);
-
-void
-destroy_stack(memory_region *region, stk_seg *stk);
-
-stk_seg *
-create_exchange_stack(rust_exchange_alloc *exchange, size_t sz);
-
-void
-destroy_exchange_stack(rust_exchange_alloc *exchange, stk_seg *stk);
-
-// Must be called before each time a stack is reused to tell valgrind
-// that the stack is accessible.
-void
-reuse_valgrind_stack(stk_seg *stk, uint8_t *sp);
-
-// Run a sanity check
-void
-check_stack_canary(stk_seg *stk);
-
-#endif /* RUST_STACK_H */
#define RUST_TYPE_H
#include "rust_globals.h"
-#include "rust_refcount.h"
struct rust_opaque_box;
typedef void CDECL (glue_fn)(void *,
void *);
+typedef unsigned long ref_cnt_t;
+
// Corresponds to the boxed data in the @ region. The body follows the
// header; you can obtain a ptr via box_body() below.
struct rust_opaque_box {
size_t borrow_offset;
};
-extern "C" type_desc *rust_clone_type_desc(type_desc*);
-
#endif
//
*/
#include "rust_globals.h"
-#include "rust_upcall.h"
#include "rust_util.h"
//Unwinding ABI declarations.
+++ /dev/null
-// 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.
-
-#ifndef RUST_UPCALL_H
-#define RUST_UPCALL_H
-
-#endif
#include <limits.h>
#include "rust_exchange_alloc.h"
#include "rust_type.h"
-#include "rust_env.h"
extern struct type_desc str_body_tydesc;
#include <malloc.h>
#endif
+#ifndef __WIN32__
+// for signal
+#include <signal.h>
+#endif
+
#include "uv.h"
#include "rust_globals.h"
-// extern fn pointers
-typedef void (*extern_async_op_cb)(uv_loop_t* loop, void* data,
- uv_async_t* op_handle);
-typedef void (*extern_simple_cb)(uint8_t* id_buf, void* loop_data);
-typedef void (*extern_close_cb)(uint8_t* id_buf, void* handle,
- void* data);
-
-// data types
-#define RUST_UV_HANDLE_LEN 16
-
-struct handle_data {
- uint8_t id_buf[RUST_UV_HANDLE_LEN];
- extern_simple_cb cb;
- extern_close_cb close_cb;
-};
-
-static void
-foreign_timer_cb(uv_timer_t* handle, int status) {
- handle_data* handle_d = (handle_data*)handle->data;
- void* loop_data = handle->loop->data;
- handle_d->cb(handle_d->id_buf, loop_data);
-}
-
-static void
-foreign_close_cb(uv_handle_t* handle) {
- handle_data* data = (handle_data*)handle->data;
- data->close_cb(data->id_buf, handle, handle->loop->data);
-}
extern "C" void*
rust_uv_loop_new() {
+// XXX libuv doesn't always ignore SIGPIPE even though we don't need it.
+#ifndef __WIN32__
+ signal(SIGPIPE, SIG_IGN);
+#endif
return (void*)uv_loop_new();
}
uv_walk(loop, cb, arg);
}
-extern "C" void
-rust_uv_hilvl_close(uv_handle_t* handle, extern_close_cb cb) {
- handle_data* data = (handle_data*)handle->data;
- data->close_cb = cb;
- uv_close(handle, foreign_close_cb);
-}
-
extern "C" void
rust_uv_async_send(uv_async_t* handle) {
uv_async_send(handle);
return uv_async_init(loop_handle, async_handle, cb);
}
-extern "C" void
-rust_uv_hilvl_timer_start(uv_timer_t* the_timer, uint32_t timeout,
- uint32_t repeat) {
- uv_timer_start(the_timer, foreign_timer_cb, timeout, repeat);
-}
-
extern "C" int
rust_uv_timer_init(uv_loop_t* loop, uv_timer_t* timer) {
return uv_timer_init(loop, timer);
return uv_accept(server, client);
}
-extern "C" size_t
-rust_uv_helper_uv_tcp_t_size() {
- return sizeof(uv_tcp_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_connect_t_size() {
- return sizeof(uv_connect_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_buf_t_size() {
- return sizeof(uv_buf_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_write_t_size() {
- return sizeof(uv_write_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_err_t_size() {
- return sizeof(uv_err_t);
-}
-extern "C" size_t
-rust_uv_helper_sockaddr_in_size() {
- return sizeof(sockaddr_in);
-}
-extern "C" size_t
-rust_uv_helper_sockaddr_in6_size() {
- return sizeof(sockaddr_in6);
-}
-extern "C" size_t
-rust_uv_helper_uv_async_t_size() {
- return sizeof(uv_async_t);
-}
-extern "C" size_t
-rust_uv_helper_uv_timer_t_size() {
- return sizeof(uv_timer_t);
-}
-extern "C" size_t
-rust_uv_helper_addr_in_size() {
- return sizeof(sockaddr_in6);
-}
-extern "C" size_t
-rust_uv_helper_uv_getaddrinfo_t_size() {
- return sizeof(uv_getaddrinfo_t);
-}
-extern "C" size_t
-rust_uv_helper_addrinfo_size() {
- return sizeof(addrinfo);
-}
-extern "C" unsigned int
-rust_uv_helper_get_INADDR_NONE() {
- return INADDR_NONE;
-}
extern "C" uv_stream_t*
rust_uv_get_stream_handle_from_connect_req(uv_connect_t* connect) {
return connect->handle;
rust_uv_loop_set_data
rust_uv_run
rust_uv_close
-rust_uv_hilvl_close
rust_uv_async_send
rust_uv_async_init
-rust_uv_hilvl_timer_start
rust_uv_timer_init
rust_uv_timer_start
rust_uv_timer_stop
rust_uv_get_next_addrinfo
rust_uv_addrinfo_as_sockaddr_in
rust_uv_addrinfo_as_sockaddr_in6
-rust_uv_helper_uv_tcp_t_size
-rust_uv_helper_uv_connect_t_size
-rust_uv_helper_uv_buf_t_size
-rust_uv_helper_uv_write_t_size
-rust_uv_helper_uv_err_t_size
-rust_uv_helper_sockaddr_in_size
-rust_uv_helper_sockaddr_in6_size
-rust_uv_helper_addr_in_size
-rust_uv_helper_addrinfo_size
-rust_uv_helper_uv_getaddrinfo_t_size
-rust_uv_helper_get_INADDR_NONE
-rust_uv_helper_uv_async_t_size
-rust_uv_helper_uv_timer_t_size
rust_uv_get_stream_handle_from_connect_req
rust_uv_get_stream_handle_from_write_req
rust_uv_get_loop_for_uv_handle
const char* path) {
PassManager *PM = unwrap<PassManager>(PMR);
std::string ErrorInfo;
- raw_fd_ostream OS(path, ErrorInfo, raw_fd_ostream::F_Binary);
+ raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
formatted_raw_ostream FOS(OS);
PM->add(createPrintModulePass(&FOS));
PM->run(*unwrap(M));
bool NoVerify = false;
std::string ErrorInfo;
raw_fd_ostream OS(path, ErrorInfo,
- raw_fd_ostream::F_Binary);
+ sys::fs::F_Binary);
if (ErrorInfo != "") {
LLVMRustError = ErrorInfo.c_str();
return false;
return wrap(Type::getMetadataTy(*unwrap(C)));
}
+extern "C" void LLVMAddFunctionAttrString(LLVMValueRef fn, const char *Name) {
+ unwrap<Function>(fn)->addFnAttr(Name);
+}
+
extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B,
LLVMValueRef source,
const char* Name,
return wrap(Builder->createFunction(
unwrapDI<DIScope>(Scope), Name, LinkageName,
unwrapDI<DIFile>(File), LineNo,
- unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine,
+ unwrapDI<DICompositeType>(Ty), isLocalToUnit, isDefinition, ScopeLine,
Flags, isOptimized,
unwrap<Function>(Fn),
unwrapDI<MDNode*>(TParam),
extern "C" void LLVMSetUnnamedAddr(LLVMValueRef Value, LLVMBool Unnamed) {
unwrap<GlobalValue>(Value)->setUnnamedAddr(Unnamed);
}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateTemplateTypeParameter(
+ DIBuilderRef Builder,
+ LLVMValueRef Scope,
+ const char* Name,
+ LLVMValueRef Ty,
+ LLVMValueRef File = 0,
+ unsigned LineNo = 0,
+ unsigned ColumnNo = 0)
+{
+ return wrap(Builder->createTemplateTypeParameter(
+ unwrapDI<DIDescriptor>(Scope),
+ Name,
+ unwrapDI<DIType>(Ty),
+ unwrapDI<MDNode*>(File),
+ LineNo,
+ ColumnNo));
+}
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2013-07-04
+2013-08-20
LLVMAddEarlyCSEPass
LLVMAddFunction
LLVMAddFunctionAttr
+LLVMAddFunctionAttrString
LLVMAddFunctionAttrsPass
LLVMAddFunctionInliningPass
LLVMAddGVNPass
LLVMDIBuilderCreateEnumerator
LLVMDIBuilderCreateEnumerationType
LLVMDIBuilderCreateUnionType
+LLVMDIBuilderCreateTemplateTypeParameter
LLVMSetUnnamedAddr
+S 2013-08-14 e7b5729
+ freebsd-x86_64 9de0b5583a5c4413f9e77df7071498385e936dd2
+ linux-i386 29119a9072f74c639c2bad998edc40e582da540e
+ linux-x86_64 319fb73727da9a8e4dd6debe37e7647e40ed361b
+ macos-i386 f74a0f02efec35e327a9c819c5c8347579d1b7fe
+ macos-x86_64 f44aba76e9d7a9a28b8a6dd78f14576e7c84fbf3
+ winnt-i386 49dd1f264e17e6cd929c827ccbe23ee09058c7fc
+
S 2013-08-12 ecfc9a8
freebsd-x86_64 ae903580d6328b8517dc64b013c1b0740bfa4e83
linux-i386 3076bf032ce980157a894a0a4446902ba8b1783d
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
use std::task;
pub fn foo<T:Send + Clone>(x: T) -> Port<T> {
// except according to those terms.
pub mod kitties {
- use std::uint;
-
pub struct cat {
priv meows : uint,
how_hungry : int,
how_hungry: in_y
}
}
-
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::to_str::*;
-
pub mod kitty {
pub struct cat {
priv meows : uint,
}
impl add for name_pool {
- fn add(&self, s: ~str) {
+ fn add(&self, _s: ~str) {
}
}
}
pub fn nominal() -> e { e_val }
-pub fn nominal_eq(e1: e, e2: e) -> bool { true }
+pub fn nominal_eq(_e1: e, _e2: e) -> bool { true }
impl Eq for e {
fn eq(&self, other: &e) -> bool { nominal_eq(*self, *other) }
pub fn nominal() -> e { e_val }
-pub fn nominal_neq(e1: e, e2: e) -> bool { false }
+pub fn nominal_neq(_e1: e, _e2: e) -> bool { false }
pub fn f() -> int { 20 }
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);
--- /dev/null
+// 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.
+
+#[link(name="iss6919_3", vers="0.1")];
+
+// part of issue-6919.rs
+
+struct C<'self> {
+ k: &'self fn(),
+}
+
+fn no_op() { }
+pub static D : C<'static> = C {
+ k: no_op
+};
+
}
fn init() -> arc_destruct<context_res> {
- unsafe {
- arc(context_res())
- }
+ arc(context_res())
}
struct context_res {
enum maybe<T> { just(T), nothing }
impl <T:Clone> Index<uint,T> for maybe<T> {
- fn index(&self, idx: &uint) -> T {
+ fn index(&self, _idx: &uint) -> T {
match self {
&just(ref t) => (*t).clone(),
¬hing => { fail!(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
extern mod issue_2316_a;
pub mod cloth {
--- /dev/null
+// 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.
+
+pub trait Foo {
+ fn bar();
+}
+
--- /dev/null
+// 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.
+
+// for this issue, this code must be built in a library
+
+use std::cast;
+
+trait A {}
+struct B;
+impl A for B {}
+
+fn bar<T>(_: &mut A, _: &T) {}
+
+fn foo<T>(t: &T) {
+ let b = B;
+ bar(unsafe { cast::transmute(&b as &A) }, t)
+}
+
pub fn f() {
let x = S { x: 1 };
let y = x;
- let z = y;
+ let _z = y;
}
trait B<T> {
fn thing<U>(&self, x: T, y: U) -> (T, U) { (x, y) }
- fn staticthing<U>(z: &Self, x: T, y: U) -> (T, U) { (x, y) }
+ fn staticthing<U>(_z: &Self, x: T, y: U) -> (T, U) { (x, y) }
}
impl<T> B<T> for int { }
--- /dev/null
+// 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="lib"];
+
+condition! {
+ pub oops: int -> int;
+}
+
+pub fn trouble() -> int {
+ oops::cond.raise(1)
+}
--- /dev/null
+// 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="lib"];
+
+condition! {
+ pub oops: int -> int;
+}
--- /dev/null
+// 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="lib"];
+
+condition! {
+ pub oops: int -> int;
+}
+
+pub fn guard(k: extern fn() -> int, x: int) -> int {
+ do oops::cond.trap(|i| i*x).inside {
+ k()
+ }
+}
--- /dev/null
+// 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="lib"];
+
+#[deriving(Eq)]
+pub enum Color {
+ Red, Green, Blue
+}
+
+condition! {
+ pub oops: (int,float,~str) -> ::Color;
+}
+
+pub trait Thunk<T> {
+ fn call(self) -> T;
+}
+
+pub fn callback<T,TH:Thunk<T>>(t:TH) -> T {
+ t.call()
+}
+
let mut set = f();
do timed(&mut self.sequential_strings) {
for i in range(0u, num_keys) {
- let s = uint::to_str(i);
- set.insert(s);
+ set.insert(i.to_str());
}
for i in range(0u, num_keys) {
- let s = uint::to_str(i);
- assert!(set.contains(&s));
+ assert!(set.contains(&i.to_str()));
}
}
}
let mut set = f();
do timed(&mut self.random_strings) {
for _ in range(0, num_keys) {
- let s = uint::to_str(rng.next() as uint);
+ let s = (rng.next() as uint).to_str();
set.insert(s);
}
}
{
let mut set = f();
for i in range(0u, num_keys) {
- set.insert(uint::to_str(i));
+ set.insert(i.to_str());
}
do timed(&mut self.delete_strings) {
for i in range(0u, num_keys) {
- assert!(set.remove(&uint::to_str(i)));
+ assert!(set.remove(&i.to_str()));
}
}
}
extern mod extra;
use extra::time::precise_time_s;
-use std::int;
use std::io;
use std::os;
use std::rand::RngUtil;
use std::rand;
-use std::result;
use std::str;
-use std::uint;
use std::util;
use std::vec;
let n = uint::from_str(args[1]).unwrap();
for i in range(0u, n) {
- let x = uint::to_str(i);
+ let x = i.to_str();
info!(x);
}
}
use extra::future;
use extra::time;
use std::cell::Cell;
-use std::io;
use std::os;
use std::uint;
use extra::future;
use extra::time;
use std::cell::Cell;
-use std::io;
use std::os;
use std::uint;
// Perlin noise benchmark from https://gist.github.com/1170424
use std::float;
-use std::int;
use std::rand::{Rng, RngUtil};
use std::rand;
fn gradient(orig: Vec2, grad: Vec2, p: Vec2) -> f32 {
let sp = Vec2 {x: p.x - orig.x, y: p.y - orig.y};
- grad.x * sp.x + grad.y + sp.y
+ grad.x * sp.x + grad.y * sp.y
}
struct Noise2DContext {
extern mod extra;
-use std::task::spawn;
use std::os;
use std::uint;
use std::rt::test::spawntask_later;
extern mod extra;
-use std::task::spawn;
use std::os;
use std::uint;
use std::rt::test::spawntask_later;
extern mod extra;
use std::int;
-use std::io;
use std::os;
fn ack(m: int, n: int) -> int {
use std::os;
use std::rand::Rng;
use std::rand;
-use std::result;
use std::str;
-use std::uint;
static LINE_LENGTH: uint = 60u;
extern mod extra;
use std::int;
-use std::io;
use std::os;
fn fib(n: int) -> int {
use std::io;
use std::option;
use std::os;
-use std::result;
use std::str;
use std::task;
use std::util;
let elapsed = stop - start;
out.write_line(fmt!("%d\t%d\t%s", n, fibn,
- u64::to_str(elapsed)));
+ elapsed.to_str()));
}
}
}
use std::io::{ReaderUtil, WriterUtil};
use std::io;
use std::os;
-use std::u8;
use std::uint;
use std::unstable::intrinsics::cttz16;
use std::vec;
do task::spawn_supervised {
let c = c.take();
if gens_left & 1 == 1 {
- task::yield(); // shake things up a bit
+ task::deschedule(); // shake things up a bit
}
if gens_left > 0 {
child_generation(gens_left - 1, c); // recurse
#[no_mangle]
fn test() {
- let x = foo(10);
+ let _x = foo(10);
}
use std::local_data;
-static key: local_data::Key<@&int> = &local_data::Key;
+local_data_key!(key: @&int)
//~^ ERROR only 'static is allowed
fn main() {}
+++ /dev/null
-// 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 std::uint;
-
-fn uuid() -> uint { fail!(); }
-
-fn from_str(s: ~str) -> uint { fail!(); }
-fn to_str(u: uint) -> ~str { fail!(); }
-fn uuid_random() -> uint { fail!(); }
-
-fn main() {
- do range(0u, 100000).advance |_i| { //~ ERROR Do-block body must return bool, but
- };
- // should get a more general message if the callback
- // doesn't return nil
- do range(0u, 100000).advance |_i| { //~ ERROR mismatched types
- ~"str"
- };
-}
+++ /dev/null
-// 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.
-
-fn main() {
- fn take_block(f: &fn() -> bool) -> bool { f() }
- do take_block {}; //~ ERROR Do-block body must return bool, but returns () here. Perhaps
-}
--- /dev/null
+// 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.
+
+// aux-build:issue_3907.rs
+extern mod issue_3907;
+
+type Foo = issue_3907::Foo; //~ ERROR: reference to trait
+
+struct S {
+ name: int
+}
+
+impl Foo for S { //~ ERROR: Foo is not a trait
+ fn bar() { }
+}
+
+fn main() {
+ let s = S {
+ name: 0
+ };
+ s.bar();
+}
+
--- /dev/null
+// 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.
+
+struct Foo {
+ foo: int,
+}
+
+struct Bar {
+ bar: int,
+}
+
+impl Bar {
+ fn make_foo (&self, i: int) -> ~Foo {
+ return ~Foo { nonexistent: self, foo: i }; //~ ERROR: no field named
+ }
+}
+
+fn main () {
+ let bar = Bar { bar: 1 };
+ let foo = bar.make_foo(2);
+ println(fmt!("%d", foo.foo));
+}
// except according to those terms.
// xfail-test
-use core::io::ReaderUtil;
-use core::io::Reader;
+use std::io::ReaderUtil;
+use std::io::Reader;
fn bar(r:@ReaderUtil) -> ~str { r.read_line() }
--- /dev/null
+// 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.
+
+trait Foo { fn a() } //~ ERROR expected `;` or `{` but found `}`
+
+fn main() {}
// Exercise the unused_unsafe attribute in some positive and negative cases
+#[allow(cstack)];
#[deny(unused_unsafe)];
mod foo {
}
}
}
+
unsafe fn good3() { foo::bar() }
fn good4() { unsafe { foo::bar() } }
--- /dev/null
+// 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.
+
+use std::local_data;
+
+// check that the local data keys are private by default.
+
+mod bar {
+ local_data_key!(baz: float)
+}
+
+fn main() {
+ local_data::set(bar::baz, -10.0);
+ //~^ ERROR unresolved name `bar::baz`
+}
//~^ ERROR obsolete syntax: `let` in field declaration
bar: ();
//~^ ERROR obsolete syntax: field declaration terminated with semicolon
- new() { }
- //~^ ERROR obsolete syntax: struct constructor
}
struct q : r {
_ => ()
}
match 'c' {
- S { _ } => (), //~ ERROR mismatched types: expected `char` but found struct
+ S { _ } => (), //~ ERROR mismatched types: expected `char` but found a structure pattern
+
_ => ()
}
f(true); //~ ERROR mismatched types: expected `char` but found `bool`
-}
\ No newline at end of file
+}
fn main() {
- let ext_cx = mk_ctxt();
+ let cx = mk_ctxt();
- let abc = quote_expr!(23);
+ let abc = quote_expr!(cx, 23);
check_pp(abc, pprust::print_expr, "23");
- let expr3 = quote_expr!(2 - $abcd + 7); //~ ERROR unresolved name: abcd
+ let expr3 = quote_expr!(cx, 2 - $abcd + 7); //~ ERROR unresolved name: abcd
check_pp(expr3, pprust::print_expr, "2 - 23 + 7");
}
fn main() {
- let ext_cx = mk_ctxt();
+ let cx = mk_ctxt();
- let stmt = quote_stmt!(let x int = 20;); //~ ERROR expected end-of-string
+ let stmt = quote_stmt!(cx, let x int = 20;); //~ ERROR expected end-of-string
check_pp(*stmt, pprust::print_stmt, "");
}
--- /dev/null
+// 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.
+
+fn foo() -> int { 23 }
+
+static a: [int, ..2] = [foo(), ..2]; //~ ERROR: function calls in constants are limited to struct and enum constructors
+
+fn main() {}
--- /dev/null
+// 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.
+
+struct a {
+ b: uint,
+ c: uint
+}
+
+impl a {
+ fn foo(&self) {
+ let a { x, y } = self.d; //~ ERROR attempted access of field `d`
+ //~^ ERROR struct `a` does not have a field named `x`
+ //~^^ ERROR struct `a` does not have a field named `y`
+ //~^^^ ERROR pattern does not mention field `b`
+ //~^^^^ ERROR pattern does not mention field `c`
+ }
+}
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//error-pattern:libc::c_int or libc::c_long should be used
+#[forbid(ctypes)];
+
mod xx {
extern {
- pub fn strlen(str: *u8) -> uint;
- pub fn foo(x: int, y: uint);
+ pub fn strlen(str: *u8) -> uint; //~ ERROR found rust type `uint`
+ pub fn foo(x: int, y: uint); //~ ERROR found rust type `int`
+ //~^ ERROR found rust type `uint`
}
}
fn main() {
- // let it fail to verify warning message
- fail!()
}
// debugger:print f64
// check:$15 = 3.5
+#[allow(unused_variable)];
+
fn main() {
let b: bool = false;
let i: int = -1;
// debugger:print *f64_ref
// check:$15 = 3.5
+#[allow(unused_variable)];
+
fn main() {
let bool_val: bool = true;
let bool_ref: &bool = &bool_val;
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *the_c_ref
// check:$3 = TheC
+#[allow(unused_variable)];
+
enum ABC { TheA, TheB, TheC }
fn main() {
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *univariant_ref
// check:$3 = {4820353753753434}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *f64_ref
// check:$15 = 3.5
+#[allow(unused_variable)];
fn main() {
let bool_box: @bool = @true;
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *unique_val_interior_ref_2
// check:$10 = 26.5
-
+#[allow(unused_variable)];
struct SomeStruct {
x: int,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *unique_val_ref
// check:$4 = {-17, -22}
+#[allow(unused_variable)];
+
fn main() {
let stack_val: (i16, f32) = (-14, -19f32);
let stack_val_ref: &(i16, f32) = &stack_val;
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *f64_ref
// check:$15 = 3.5
+#[allow(unused_variable)];
+
fn main() {
let bool_box: ~bool = ~true;
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print d->val
// check:$4 = false
+#[allow(unused_variable)];
+
fn main() {
let a = ~1;
let b = ~(2, 3.5);
// debugger:print managed_dtor->val
// check:$4 = {x = 33, y = 333, z = 3333, w = 33333}
+#[allow(unused_variable)];
+
struct StructWithSomePadding {
x: i16,
y: i32,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *((uint64_t[4]*)(unique->elements))
// check:$4 = {10, 11, 12, 13}
+#[allow(unused_variable)];
+
fn main() {
let managed: @[i64] = @[7, 8, 9];
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// Does not work yet, see issue #8512
+// xfail-test
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print s
+// check:$1 = {a = 1, b = 2.5}
+// debugger:continue
+
+#[deriving(Clone)]
+struct Struct {
+ a: int,
+ b: float
+}
+
+fn fun(s: Struct) {
+ zzz();
+}
+
+fn main() {
+ fun(Struct { a: 1, b: 2.5 });
+}
+
+fn zzz() {()}
// debugger:print struct_with_drop
// check:$7 = {{a = OneHundred, b = Vienna}, 9}
+#[allow(unused_variable)];
+
enum AnEnum {
OneHundred = 100,
OneThousand = 1000,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print single_variant
// check:$7 = TheOnlyVariant
+#[allow(unused_variable)];
+
enum AutoDiscriminant {
One,
Two,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print x
+// check:$1 = 0.5
+// debugger:print y
+// check:$2 = 10
+// debugger:continue
+
+// debugger:finish
+// debugger:print *x
+// check:$3 = 29
+// debugger:print *y
+// check:$4 = 110
+// debugger:continue
+
+fn some_generic_fun<T1, T2>(a: T1, b: T2) -> (T2, T1) {
+
+ let closure = |x, y| {
+ zzz();
+ (y, x)
+ };
+
+ closure(a, b)
+}
+
+fn main() {
+ some_generic_fun(0.5, 10);
+ some_generic_fun(&29, ~110);
+}
+
+fn zzz() {()}
// check:$49 = 62
// debugger:continue
+#[allow(unused_variable)];
struct Struct {
a: i64,
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *nn
// check:$43 = 56
+#[allow(unused_variable)];
struct Struct {
a: i64,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print struct_padded_at_end
// check:$5 = {x = {22, 23}, y = {24, 25}}
+#[allow(unused_variable)];
+
struct NoPadding1 {
x: [u32, ..3],
y: i32,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print *t0
+// check:$1 = 1
+// debugger:print *t1
+// check:$2 = 2.5
+// debugger:print ret
+// check:$3 = {{1, 2.5}, {2.5, 1}}
+// debugger:continue
+
+// debugger:finish
+// debugger:print *t0
+// check:$4 = 3.5
+// debugger:print *t1
+// check:$5 = 4
+// debugger:print ret
+// check:$6 = {{3.5, 4}, {4, 3.5}}
+// debugger:continue
+
+// debugger:finish
+// debugger:print *t0
+// check:$7 = 5
+// debugger:print *t1
+// check:$8 = {a = 6, b = 7.5}
+// debugger:print ret
+// check:$9 = {{5, {a = 6, b = 7.5}}, {{a = 6, b = 7.5}, 5}}
+// debugger:continue
+
+#[deriving(Clone)]
+struct Struct {
+ a: int,
+ b: float
+}
+
+fn dup_tup<T0: Clone, T1: Clone>(t0: &T0, t1: &T1) -> ((T0, T1), (T1, T0)) {
+ let ret = ((t0.clone(), t1.clone()), (t1.clone(), t0.clone()));
+ zzz();
+ ret
+}
+
+fn main() {
+
+ let _ = dup_tup(&1, &2.5);
+ let _ = dup_tup(&3.5, &4_u16);
+ let _ = dup_tup(&5, &Struct { a: 6, b: 7.5 });
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print x
+// check:$1 = -1
+// debugger:print y
+// check:$2 = 1
+// debugger:continue
+
+// debugger:finish
+// debugger:print x
+// check:$3 = -1
+// debugger:print y
+// check:$4 = 2.5
+// debugger:continue
+
+// debugger:finish
+// debugger:print x
+// check:$5 = -2.5
+// debugger:print y
+// check:$6 = 1
+// debugger:continue
+
+// debugger:finish
+// debugger:print x
+// check:$7 = -2.5
+// debugger:print y
+// check:$8 = 2.5
+// debugger:continue
+
+fn outer<TA: Clone>(a: TA) {
+ inner(a.clone(), 1);
+ inner(a.clone(), 2.5);
+
+ fn inner<TX, TY>(x: TX, y: TY) {
+ zzz();
+ }
+}
+
+fn main() {
+ outer(-1);
+ outer(-2.5);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = {8888, -8888}}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print/d arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = {8888, -8888}}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 1234.5}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 1234.5}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 1234.5}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10.5
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = -1}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12.5
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = -1}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print *arg2
+// check:$18 = {-14, 14}
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = -1}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print *arg2
+// check:$21 = {-16, 16.5}
+// debugger:continue
+
+struct Struct<T> {
+ x: T
+}
+
+impl<T1> Struct<T1> {
+
+ fn self_by_ref<T2>(&self, arg1: int, arg2: T2) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_by_val<T2>(self, arg1: int, arg2: T2) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_owned<T2>(~self, arg1: int, arg2: T2) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_managed<T2>(@self, arg1: int, arg2: T2) -> int {
+ zzz();
+ arg1
+ }
+}
+
+fn main() {
+ let stack = Struct { x: (8888_u32, -8888_i32) };
+ let _ = stack.self_by_ref(-1, -2_i8);
+ let _ = stack.self_by_val(-3, -4_i16);
+
+ let owned = ~Struct { x: 1234.5 };
+ let _ = owned.self_by_ref(-5, -6_i32);
+ let _ = owned.self_by_val(-7, -8_i64);
+ let _ = owned.self_owned(-9, -10.5_f32);
+
+ let managed = @Struct { x: -1_i16 };
+ let _ = managed.self_by_ref(-11, -12.5_f64);
+ let _ = managed.self_by_val(-13, &(-14, 14));
+ let _ = managed.self_managed(-15, &(-16, 16.5));
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STRUCT
+// debugger:finish
+// debugger:print arg1
+// check:$1 = 1
+// debugger:print arg2
+// check:$2 = 2
+// debugger:continue
+
+// ENUM
+// debugger:finish
+// debugger:print arg1
+// check:$3 = -3
+// debugger:print arg2
+// check:$4 = 4.5
+// debugger:print arg3
+// check:$5 = 5
+// debugger:continue
+
+
+struct Struct {
+ x: int
+}
+
+impl Struct {
+
+ fn static_method<T1, T2>(arg1: T1, arg2: T2) -> int {
+ zzz();
+ return 0;
+ }
+}
+
+enum Enum {
+ Variant1 { x: int },
+ Variant2,
+ Variant3(float, int, char),
+}
+
+impl Enum {
+
+ fn static_method<T1, T2, T3>(arg1: T1, arg2: T2, arg3: T3) -> int {
+ zzz();
+ return 1;
+ }
+}
+
+fn main() {
+ Struct::static_method(1, 2);
+ Enum::static_method(-3, 4.5, 5);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:set print union on
+// debugger:break zzz
+// debugger:run
+// debugger:finish
+
+// debugger:print case1
+// check:$1 = {{Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {Case1, a = 0, b = 2088533116, c = 2088533116}, {Case1, a = 0, b = 8970181431921507452}}
+
+// debugger:print case2
+// check:$2 = {{Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {Case2, a = 0, b = 286331153, c = 286331153}, {Case2, a = 0, b = 1229782938247303441}}
+
+// debugger:print case3
+// check:$3 = {{Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {Case3, a = 0, b = 1499027801, c = 1499027801}, {Case3, a = 0, b = 6438275382588823897}}
+
+// debugger:print univariant
+// check:$4 = {a = -1}
+
+// NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be
+// substituted with something of size `xx` bits and the same alignment as an integer type of the
+// same size.
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular<T16, T32, T64> {
+ Case1 { a: T64, b: T16, c: T16, d: T16, e: T16},
+ Case2 { a: T64, b: T32, c: T32},
+ Case3 { a: T64, b: T64 }
+}
+
+enum Univariant<T> {
+ TheOnlyCase { a: T }
+}
+
+fn main() {
+
+ // In order to avoid endianess trouble all of the following test values consist of a single
+ // repeated byte. This way each interpretation of the union should look the same, no matter if
+ // this is a big or little endian machine.
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let case1: Regular<u16, u32, i64> = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 };
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let case2: Regular<i16, u32, i64> = Case2 { a: 0, b: 286331153, c: 286331153 };
+
+ // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+ // 0b01011001010110010101100101011001 = 1499027801
+ // 0b0101100101011001 = 22873
+ // 0b01011001 = 89
+ let case3: Regular<u16, i32, u64> = Case3 { a: 0, b: 6438275382588823897 };
+
+ let univariant = TheOnlyCase { a: -1 };
+
+ zzz();
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print int_int
+// check:$1 = {key = 0, value = 1}
+// debugger:print int_float
+// check:$2 = {key = 2, value = 3.5}
+// debugger:print float_int
+// check:$3 = {key = 4.5, value = 5}
+// debugger:print float_int_float
+// check:$4 = {key = 6.5, value = {key = 7, value = 8.5}}
+
+struct AGenericStruct<TKey, TValue> {
+ key: TKey,
+ value: TValue
+}
+
+fn main() {
+
+ let int_int = AGenericStruct { key: 0, value: 1 };
+ let int_float = AGenericStruct { key: 2, value: 3.5 };
+ let float_int = AGenericStruct { key: 4.5, value: 5 };
+ let float_int_float = AGenericStruct { key: 6.5, value: AGenericStruct { key: 7, value: 8.5 } };
+
+ zzz();
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print arg1
+// check:$1 = 1000
+// debugger:print *arg2
+// check:$2 = {1, 2.5}
+// debugger:continue
+
+// debugger:finish
+// debugger:print arg1
+// check:$3 = 2000
+// debugger:print *arg2
+// check:$4 = {3.5, {4, 5, 6}}
+// debugger:continue
+
+
+struct Struct {
+ x: int
+}
+
+trait Trait<T1> {
+ fn generic_static_default_method<T2>(arg1: int, arg2: &(T1, T2)) -> int {
+ zzz();
+ arg1
+ }
+}
+
+impl<T> Trait<T> for Struct;
+
+fn main() {
+
+ // Is this really how to use these?
+ Trait::generic_static_default_method::<int, Struct, float>(1000, &(1, 2.5));
+ Trait::generic_static_default_method::<float, Struct, (int, int, int)>(2000, &(3.5, (4, 5, 6)));
+
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:set print union on
+// debugger:break zzz
+// debugger:run
+// debugger:finish
+
+// debugger:print case1
+// check:$1 = {{Case1, 0, 31868, 31868, 31868, 31868}, {Case1, 0, 2088533116, 2088533116}, {Case1, 0, 8970181431921507452}}
+
+// debugger:print case2
+// check:$2 = {{Case2, 0, 4369, 4369, 4369, 4369}, {Case2, 0, 286331153, 286331153}, {Case2, 0, 1229782938247303441}}
+
+// debugger:print case3
+// check:$3 = {{Case3, 0, 22873, 22873, 22873, 22873}, {Case3, 0, 1499027801, 1499027801}, {Case3, 0, 6438275382588823897}}
+
+// debugger:print univariant
+// check:$4 = {-1}
+
+
+// NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be
+// substituted with something of size `xx` bits and the same alignment as an integer type of the
+// same size.
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular<T16, T32, T64> {
+ Case1(T64, T16, T16, T16, T16),
+ Case2(T64, T32, T32),
+ Case3(T64, T64)
+}
+
+enum Univariant<T64> {
+ TheOnlyCase(T64)
+}
+
+fn main() {
+
+ // In order to avoid endianess trouble all of the following test values consist of a single
+ // repeated byte. This way each interpretation of the union should look the same, no matter if
+ // this is a big or little endian machine.
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let case1: Regular<u16, u32, u64> = Case1(0_u64, 31868_u16, 31868_u16, 31868_u16, 31868_u16);
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let case2: Regular<i16, i32, i64> = Case2(0_i64, 286331153_i32, 286331153_i32);
+
+ // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+ // 0b01011001010110010101100101011001 = 1499027801
+ // 0b0101100101011001 = 22873
+ // 0b01011001 = 89
+ let case3: Regular<i16, i32, i64> = Case3(0_i64, 6438275382588823897_i64);
+
+ let univariant = TheOnlyCase(-1_i64);
+
+ zzz();
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z debug-info
+// debugger:run
+
+// Nothing to do here really, just make sure it compiles. See issue #8513.
+fn main() {
+ let _ = ||();
+ let _ = range(1u,3).map(|_| 5);
+}
+
// debugger:print univariant->val
// check:$3 = {-9747455}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print unique->val.elements[3]->val
// check:$4 = 13
+#[allow(unused_variable)];
+
fn main() {
let unique: ~[@i64] = ~[@10, @11, @12, @13];
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print managed_within_unique.val->y->val
// check:$3 = -4
+#[allow(unused_variable)];
+
struct ContainsManaged
{
x: int,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {{Variant1, x = 1799, y = 1799}, {Variant1, 117901063}}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {{Variant1, x = 1799, y = 1799}, {Variant1, 117901063}}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {{Variant1, x = 1799, y = 1799}, {Variant1, 117901063}}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+enum Enum {
+ Variant1 { x: u16, y: u16 },
+ Variant2 (u32)
+}
+
+impl Enum {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = Variant2(117901063);
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Variant1{ x: 1799, y: 1799 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Variant2(117901063);
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = {8888, -8888}}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = {8888, -8888}}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 1234.5}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 1234.5}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 1234.5}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = -1}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = -1}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = -1}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct Struct<T> {
+ x: T
+}
+
+impl<T> Struct<T> {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = Struct { x: (8888_u32, -8888_i32) };
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Struct { x: 1234.5 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Struct { x: -1_i16 };
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = 100}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 100}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 200}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 200}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 200}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = 300}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 300}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = 300}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct Struct {
+ x: int
+}
+
+impl Struct {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = Struct { x: 100 };
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Struct { x: 200 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Struct { x: 300 };
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = 100}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 100}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 200}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 200}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 200}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = 300}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 300}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = 300}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct Struct {
+ x: int
+}
+
+trait Trait {
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int;
+ fn self_by_val(self, arg1: int, arg2: int) -> int;
+ fn self_owned(~self, arg1: int, arg2: int) -> int;
+ fn self_managed(@self, arg1: int, arg2: int) -> int;
+}
+
+impl Trait for Struct {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ self.x + arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = Struct { x: 100 };
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Struct { x: 200 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Struct { x: 300 };
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {100, -100.5}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {100, -100.5}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {200, -200.5}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {200, -200.5}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {200, -200.5}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {300, -300.5}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {300, -300.5}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {300, -300.5}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct TupleStruct(int, float);
+
+impl TupleStruct {
+
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+fn main() {
+ let stack = TupleStruct(100, -100.5);
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~TupleStruct(200, -200.5);
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @TupleStruct(300, -300.5);
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
// debugger:print abc
// check:$3 = 30303
+#[allow(unused_variable)];
+
fn function_one() {
let abc = 10101;
zzz();
// debugger:print c
// check:$3 = 30303
+#[allow(unused_variable)];
+
fn function_one() {
let a = 10101;
zzz();
// debugger:print second
// check:$2 = {<No data fields>}
+#[allow(unused_variable)];
+
enum ANilEnum {}
enum AnotherNilEnum {}
}
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// except according to those terms.
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-// xfail-test broken in newrt?
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:print full
// check:$3 = {454545, 0x87654321, 9988}
-// debugger:print empty
-// check:$4 = {0, 0x0, 0}
+// debugger:print empty->discr
+// check:$4 = (int *) 0x0
// debugger:print droid
// check:$5 = {id = 675675, range = 10000001, internals = 0x43218765}
-// debugger:print void_droid
-// check:$6 = {id = 0, range = 0, internals = 0x0}
+// debugger:print void_droid->internals
+// check:$6 = (int *) 0x0
+// debugger:continue
// If a struct has exactly two variants, one of them is empty, and the other one
// contains a non-nullable pointer, then this value is used as the discriminator.
// The test cases in this file make sure that something readable is generated for
// this kind of types.
+// Unfortunately (for these test cases) the content of the non-discriminant fields
+// in the null-case is not defined. So we just read the discriminator field in
+// this case (by casting the value to a memory-equivalent struct).
enum MoreFields<'self> {
Full(u32, &'self int, i16),
Empty
}
+struct MoreFieldsRepr<'self> {
+ a: u32,
+ discr: &'self int,
+ b: i16
+}
+
enum NamedFields<'self> {
Droid { id: i32, range: i64, internals: &'self int },
Void
}
+struct NamedFieldsRepr<'self> {
+ id: i32,
+ range: i64,
+ internals: &'self int
+}
+
fn main() {
let some: Option<&u32> = Some(unsafe { std::cast::transmute(0x12345678) });
let full = Full(454545, unsafe { std::cast::transmute(0x87654321) }, 9988);
let int_val = 0;
- let mut empty = Full(0, &int_val, 0);
- empty = Empty;
+ let empty: &MoreFieldsRepr = unsafe { std::cast::transmute(&Empty) };
- let droid = Droid { id: 675675, range: 10000001, internals: unsafe { std::cast::transmute(0x43218765) } };
+ let droid = Droid {
+ id: 675675,
+ range: 10000001,
+ internals: unsafe { std::cast::transmute(0x43218765) }
+ };
- let mut void_droid = Droid { id: 0, range: 0, internals: &int_val };
- void_droid = Void;
+ let void_droid: &NamedFieldsRepr = unsafe { std::cast::transmute(&Void) };
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print deeplyNested
// check:$8 = {a = {a = 1, b = {x = 2, y = 3, z = 4}, c = 5, d = {x = 6, y = 7, z = 8}}, b = {a = 9, b = {x = 10, y = 11, z = 12}, c = {x = 13, y = 14, z = 15}, d = 16}, c = {a = 17, b = {x = 18, y = 19, z = 20}, c = 21, d = {x = 22, y = 23, z = 24}}, d = {a = 25, b = {x = 26, y = 27, z = 28}, c = 29, d = {x = 30, y = 31, z = 32}}, e = {a = 33, b = {x = 34, y = 35, z = 36}, c = {x = 37, y = 38, z = 39}, d = 40}, f = {a = 41, b = {x = 42, y = 43, z = 44}, c = 45, d = {x = 46, y = 47, z = 48}}}
+#[allow(unused_variable)];
+
#[packed]
struct Packed {
x: i16,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print sizeof(packedInPacked)
// check:$6 = 40
+#[allow(unused_variable)];
+
#[packed]
struct Packed {
x: i16,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = 100}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 100}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 200}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 200}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 200}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = 300}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 300}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print arg2
+// check:$18 = -14
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = 300}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print arg2
+// check:$21 = -16
+// debugger:continue
+
+struct Struct {
+ x: int
+}
+
+trait Trait {
+ fn self_by_ref(&self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_by_val(self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_owned(~self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+
+ fn self_managed(@self, arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+impl Trait for Struct;
+
+fn main() {
+ let stack = Struct { x: 100 };
+ let _ = stack.self_by_ref(-1, -2);
+ let _ = stack.self_by_val(-3, -4);
+
+ let owned = ~Struct { x: 200 };
+ let _ = owned.self_by_ref(-5, -6);
+ let _ = owned.self_by_val(-7, -8);
+ let _ = owned.self_owned(-9, -10);
+
+ let managed = @Struct { x: 300 };
+ let _ = managed.self_by_ref(-11, -12);
+ let _ = managed.self_by_val(-13, -14);
+ let _ = managed.self_managed(-15, -16);
+}
+
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STACK BY REF
+// debugger:finish
+// debugger:print *self
+// check:$1 = {x = 987}
+// debugger:print arg1
+// check:$2 = -1
+// debugger:print/d arg2
+// check:$3 = -2
+// debugger:continue
+
+// STACK BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 987}
+// debugger:print arg1
+// check:$4 = -3
+// debugger:print arg2
+// check:$5 = -4
+// debugger:continue
+
+// OWNED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$6 = {x = 879}
+// debugger:print arg1
+// check:$7 = -5
+// debugger:print arg2
+// check:$8 = -6
+// debugger:continue
+
+// OWNED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 879}
+// debugger:print arg1
+// check:$9 = -7
+// debugger:print arg2
+// check:$10 = -8
+// debugger:continue
+
+// OWNED MOVED
+// debugger:finish
+// debugger:print *self
+// check:$11 = {x = 879}
+// debugger:print arg1
+// check:$12 = -9
+// debugger:print arg2
+// check:$13 = -10.5
+// debugger:continue
+
+// MANAGED BY REF
+// debugger:finish
+// debugger:print *self
+// check:$14 = {x = 897}
+// debugger:print arg1
+// check:$15 = -11
+// debugger:print arg2
+// check:$16 = -12.5
+// debugger:continue
+
+// MANAGED BY VAL
+// debugger:finish
+// d ebugger:print self -- ignored for now because of issue #8512
+// c heck:$X = {x = 897}
+// debugger:print arg1
+// check:$17 = -13
+// debugger:print *arg2
+// check:$18 = {-14, 14}
+// debugger:continue
+
+// MANAGED SELF
+// debugger:finish
+// debugger:print self->val
+// check:$19 = {x = 897}
+// debugger:print arg1
+// check:$20 = -15
+// debugger:print *arg2
+// check:$21 = {-16, 16.5}
+// debugger:continue
+
+struct Struct {
+ x: int
+}
+
+trait Trait {
+
+ fn self_by_ref<T>(&self, arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_by_val<T>(self, arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_owned<T>(~self, arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+
+ fn self_managed<T>(@self, arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+}
+
+impl Trait for Struct;
+
+fn main() {
+ let stack = Struct { x: 987 };
+ let _ = stack.self_by_ref(-1, -2_i8);
+ let _ = stack.self_by_val(-3, -4_i16);
+
+ let owned = ~Struct { x: 879 };
+ let _ = owned.self_by_ref(-5, -6_i32);
+ let _ = owned.self_by_val(-7, -8_i64);
+ let _ = owned.self_owned(-9, -10.5_f32);
+
+ let managed = @Struct { x: 897 };
+ let _ = managed.self_by_ref(-11, -12.5_f64);
+ let _ = managed.self_by_val(-13, &(-14, 14));
+ let _ = managed.self_managed(-15, &(-16, 16.5));
+}
+
+fn zzz() {()}
// debugger:print padding_at_end
// check:$6 = {x = -10014, y = 10015}
+#[allow(unused_variable)];
struct NoPadding16 {
x: u16,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print paddingAtEnd
// check:$7 = {15, 16}
+#[allow(unused_variable)];
fn main() {
let noPadding8: (i8, u8) = (-100, 100);
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// STRUCT
+// debugger:finish
+// debugger:print arg1
+// check:$1 = 1
+// debugger:print arg2
+// check:$2 = 2
+// debugger:continue
+
+// ENUM
+// debugger:finish
+// debugger:print arg1
+// check:$3 = -3
+// debugger:print arg2
+// check:$4 = 4.5
+// debugger:print arg3
+// check:$5 = 5
+// debugger:continue
+
+
+struct Struct {
+ x: int
+}
+
+impl Struct {
+
+ fn static_method(arg1: int, arg2: int) -> int {
+ zzz();
+ arg1 + arg2
+ }
+}
+
+enum Enum {
+ Variant1 { x: int },
+ Variant2,
+ Variant3(float, int, char),
+}
+
+impl Enum {
+
+ fn static_method(arg1: int, arg2: float, arg3: uint) -> int {
+ zzz();
+ arg1
+ }
+}
+
+fn main() {
+ Struct::static_method(1, 2);
+ Enum::static_method(-3, 4.5, 5);
+}
+
+fn zzz() {()}
// debugger:print univariant
// check:$3 = {{x = 123, y = 456, z = 789}}
+#[allow(unused_variable)];
+
struct Struct {
x: u32,
y: i32,
// debugger:print padding_at_end_parent
// check:$3 = {x = {x = 10, y = 11}, y = {x = 12, y = 13}, z = {x = 14, y = 15}}
+#[allow(unused_variable)];
struct Simple {
x: i32
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print univariant
// check:$4 = {a = -1}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print nested
// check:$4 = {a = {a = {x = 7890, y = 9870}}}
+#[allow(unused_variable)];
+
struct NoDestructor {
x: i32,
y: i64
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+
+// debugger:finish
+// debugger:print arg1
+// check:$1 = 1000
+// debugger:print arg2
+// check:$2 = 0.5
+// debugger:continue
+
+// debugger:finish
+// debugger:print arg1
+// check:$3 = 2000
+// debugger:print *arg2
+// check:$4 = {1, 2, 3}
+// debugger:continue
+
+
+struct Struct {
+ x: int
+}
+
+trait Trait {
+ fn generic_static_default_method<T>(arg1: int, arg2: T) -> int {
+ zzz();
+ arg1
+ }
+}
+
+impl Trait for Struct;
+
+fn main() {
+
+ // Is this really how to use these?
+ Trait::generic_static_default_method::<Struct, float>(1000, 0.5);
+ Trait::generic_static_default_method::<Struct, &(int, int, int)>(2000, &(1, 2, 3));
+
+}
+
+fn zzz() {()}
// debugger:print mixed_padding
// check:$10 = {x = {{40, 41, 42}, {43, 44}}, y = {45, 46, 47, 48}}
+#[allow(unused_variable)];
+
struct NoPadding1 {
x: (i32, i32),
y: i32,
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print padding_at_end2
// check:$7 = {{21, 22}, 23}
+#[allow(unused_variable)];
+
fn main() {
let no_padding1: ((u32, u32), u32, u32) = ((0, 1), 2, 3);
let no_padding2: (u32, (u32, u32), u32) = (4, (5, 6), 7);
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
--- /dev/null
+// 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.
+
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+
+// compile-flags:-Z extra-debug-info
+// debugger:set print pretty off
+// debugger:break zzz
+// debugger:run
+// debugger:finish
+
+// debugger:print no_padding16
+// check:$1 = {10000, -10001}
+
+// debugger:print no_padding32
+// check:$2 = {-10002, -10003.5, 10004}
+
+// debugger:print no_padding64
+// check:$3 = {-10005.5, 10006, 10007}
+
+// debugger:print no_padding163264
+// check:$4 = {-10008, 10009, 10010, 10011}
+
+// debugger:print internal_padding
+// check:$5 = {10012, -10013}
+
+// debugger:print padding_at_end
+// check:$6 = {-10014, 10015}
+
+
+// This test case mainly makes sure that no field names are generated for tuple structs (as opposed
+// to all fields having the name "__field__"). Otherwise they are handled the same a normal structs.
+
+struct NoPadding16(u16, i16);
+struct NoPadding32(i32, f32, u32);
+struct NoPadding64(f64, i64, u64);
+struct NoPadding163264(i16, u16, i32, u64);
+struct InternalPadding(u16, i64);
+struct PaddingAtEnd(i64, u16);
+
+fn main() {
+ let no_padding16 = NoPadding16(10000, -10001);
+ let no_padding32 = NoPadding32(-10002, -10003.5, 10004);
+ let no_padding64 = NoPadding64(-10005.5, 10006, 10007);
+ let no_padding163264 = NoPadding163264(-10008, 10009, 10010, 10011);
+
+ let internal_padding = InternalPadding(10012, -10013);
+ let padding_at_end = PaddingAtEnd(-10014, 10015);
+
+ zzz();
+}
+
+fn zzz() {()}
// debugger:print univariant
// check:$4 = {-1}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print *univariant
// check:$3 = {123234}
+#[allow(unused_variable)];
+
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
zzz();
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// debugger:print padded_struct.data_ptr[1]
// check:$13 = {x = 13, y = 14, z = 15}
+#[allow(unused_variable)];
+
struct AStruct {
x: i16,
y: i32,
// debugger:print a
// check:$1 = {1, 2, 3}
+#[allow(unused_variable)];
+
fn main() {
let a = [1, 2, 3];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn blk1(b: &fn()) -> @fn() { return || { }; }
+fn blk1(_b: &fn()) -> @fn() { return || { }; }
fn test1() { (do blk1 { info!("hi"); })(); }
fn id(f: &fn() -> int) -> int { f() }
-fn wsucc(n: int) -> int { (do id || { 1 }) - 0 }
+fn wsucc(_n: int) -> int { (do id || { 1 }) - 0 }
fn main() { }
// pp-exact
-fn from_foreign_fn(x: extern "Rust" fn()) { }
-fn from_stack_closure(x: &fn()) { }
-fn from_box_closure(x: @fn()) { }
-fn from_unique_closure(x: ~fn()) { }
+fn from_foreign_fn(_x: extern "Rust" fn()) { }
+fn from_stack_closure(_x: &fn()) { }
+fn from_box_closure(_x: @fn()) { }
+fn from_unique_closure(_x: ~fn()) { }
fn main() { }
// pp-exact
-fn f(v: &[int]) {
+fn f(v: &[int]) -> int {
let mut n = 0;
for e in v.iter() {
n = *e; // This comment once triggered pretty printer bug
}
+
+ n
}
fn main() {
let x = Some(3);
- let y =
+ let _y =
match x {
Some(_) =>
- ~"some" + ~"very" + ~"very" + ~"very" + ~"very" + ~"very" +
- ~"very" + ~"very" + ~"very" + ~"long" + ~"string",
+ ~"some" + "very" + "very" + "very" + "very" + "very" + "very" +
+ "very" + "very" + "long" + "string",
None => ~"none"
};
}
fn main() {
let x = Some(3);
- let y = match x { Some(_) => ~"some(_)", None => ~"none" };
+ let _y = match x { Some(_) => ~"some(_)", None => ~"none" };
}
fn main() {
struct Foo2;
struct Bar2(int, int, int);
- let a = Bar(5, 5);
- let b = Foo;
+ let _a = Bar(5, 5);
+ let _b = Foo;
}
// Testing that comments are correctly interleaved
// pp-exact:vec-comments.pp
fn main() {
- let v1 =
+ let _v1 =
~[
// Comment
0,
1,
// Comment
2];
- let v2 =
+ let _v2 =
~[0, // Comment
1, // Comment
2]; // Comment
- let v3 =
+ let _v3 =
~[
/* Comment */
0,
1,
/* Comment */
2];
- let v4 =
+ let _v4 =
~[0, /* Comment */
1, /* Comment */
2]; /* Comment */
// Testing that comments are correctly interleaved
// pp-exact:vec-comments.pp
fn main() {
- let v1 =
+ let _v1 =
~[
// Comment
0,
1,
// Comment
2];
- let v2 =
+ let _v2 =
~[0, // Comment
1, // Comment
2]; // Comment
- let v3 =
+ let _v3 =
~[
/* Comment */
0,
1,
/* Comment */
2];
- let v4 =
+ let _v4 =
~[0, /* Comment */
1, /* Comment */
2]; /* Comment */
// pp-exact:vec-type.pp
-fn f1(x: ~[int]) { }
+fn f1(_x: ~[int]) { }
fn g1() { f1(~[1, 2, 3]); }
// pp-exact:vec-type.pp
-fn f1(x: ~[int]) { }
+fn f1(_x: ~[int]) { }
fn g1() { f1(~[1, 2, 3]); }
// except according to those terms.
// error-pattern:meep
-fn f(a: int, b: int, c: @int) { fail!("moop"); }
+fn f(_a: int, _b: int, _c: @int) { fail!("moop"); }
fn main() { f(1, fail!("meep"), @42); }
let c = @mut b;
// this should freeze `a` only
- let x: &mut [int] = c[0];
+ let _x: &mut [int] = c[0];
// hence this should fail
a[0] = a[0];
fn main() {
let x = @mut S { x: 3 };
- let y: &S = x;
+ let _y: &S = x;
let z = x;
z.x = 5;
}
fn main() {
let x = @mut 3;
- let y: &mut int = x;
+ let _y: &mut int = x;
let z = x;
*z = 5;
}
}
}
-fn it_takes_two(f: &Foo, g: &mut Foo) {
+fn it_takes_two(_f: &Foo, _g: &mut Foo) {
}
fn main() {
pub fn main()
{
let a = @mut 3;
- let b = &*a; // freezes a
+ let _b = &*a; // freezes a
add1(a);
}
pub fn main()
{
let a = @mut 3;
- let b = &mut *a; // freezes a
+ let _b = &mut *a; // freezes a
add1(a);
}
port: port_id,
}
-fn send<T:Send>(ch: chan_t<T>, data: T) { fail!(); }
+fn send<T:Send>(_ch: chan_t<T>, _data: T) { fail!(); }
fn main() { fail!("quux"); }
// error-pattern:test
fn main() {
- let i: int = fail!("test");
+ let _i: int = fail!("test");
}
// error-pattern:attempted to divide by zero
fn main() {
let y = 0;
- let z = 1 / y;
+ let _z = 1 / y;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unreachable_code)];
+
//error-pattern:One
fn main() {
fail!("One");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+
// error-pattern:wooooo
fn main() {
- let mut a = 1; if 1 == 1 { a = 2; } fail!(~"woooo" + "o");
+ let mut a = 1;
+ if 1 == 1 { a = 2; }
+ fail!(~"woooo" + "o");
}
// error-pattern:explicit failure
-fn main() { let x = if false { 0 } else if true { fail!() } else { 10 }; }
+fn main() { let _x = if false { 0 } else if true { fail!() } else { 10 }; }
// error-pattern:explicit failure
-fn main() { let x = match true { false => { 0 } true => { fail!() } }; }
+fn main() { let _x = match true { false => { 0 } true => { fail!() } }; }
fn count(n: uint) -> uint {
unsafe {
- task::yield();
+ task::deschedule();
rustrt::rust_dbg_call(cb, n)
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unnecessary_allocation)];
+
// error-pattern:explicit failure
// Don't double free the string
extern mod extra;
fn foo() -> e<int> {fail!();}
fn main() {
- let f = foo();
+ let _f = foo();
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unnecessary_allocation)];
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
// error-pattern:so long
fn main() {
let mut x = ~[];
// error-pattern:beep boop
+#[allow(unused_variable)];
+
struct Point { x: int, y: int }
fn main() {
fn main() {
let (p, _c) = comm::stream::<()>();
task::spawn(|| child() );
- task::yield();
+ task::deschedule();
}
// error-pattern:explicit failure
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
fn foo(s: ~str) { }
fn main() {
// error-pattern:attempted remainder with a divisor of zero
fn main() {
let y = 0;
- let z = 1 % y;
+ let _z = 1 % y;
}
// as a _|_-typed thing, not a str-typed thing
// error-pattern:bye
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
struct T { t: ~str }
-fn main() { let pth = fail!("bye"); let rs: T = T {t: pth}; }
+fn main() {
+ let pth = fail!("bye");
+ let _rs: T = T {t: pth};
+}
fn main() {
error!(~"whatever");
do task::spawn {
- let i = r(5);
+ let _i = r(5);
};
fail!();
}
use std::task;
fn goodfail() {
- task::yield();
+ task::deschedule();
fail!("goodfail");
}
// error-pattern:Ensure that the child task runs by failing
-use std::str;
use std::task;
fn main() {
// error-pattern:fail
fn main() {
- let a = @0;
+ let _a = @0;
assert!(false);
}
// error-pattern:fail
-fn f(a: @int) {
+fn f(_a: @int) {
fail!();
}
fn f() -> @int { fail!(); }
fn main() {
- let a: @int = f();
+ let _a: @int = f();
}
// error-pattern:fail
fn main() {
- let a: @int = {
+ let _a: @int = {
fail!();
};
}
fn b() { fail!(); }
fn main() {
- let x = ~[0];
+ let _x = ~[0];
a();
- let y = ~[0];
+ let _y = ~[0];
b();
}
// error-pattern:fail
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
fn x(it: &fn(int)) {
fail!();
it(0);
// error-pattern:fail
fn x(it: &fn(int)) {
- let a = @0;
+ let _a = @0;
it(1);
}
let mush = food + cheese;
let cheese = cheese.clone();
let f: &fn() = || {
- let chew = mush + cheese;
+ let _chew = mush + cheese;
fail!("so yummy")
};
f();
// error-pattern:fail
fn main() {
- let count = @mut 0u;
+ let _count = @mut 0u;
let mut map = std::hashmap::HashMap::new();
let mut arr = ~[];
- for i in range(0u, 10u) {
+ for _i in range(0u, 10u) {
arr.push(@~"key stuff");
map.insert(arr.clone(), arr + &[@~"value stuff"]);
if arr.len() == 5 {
// error-pattern:fail
fn main() {
- let a = @0;
+ let _a = @0;
{
- let b = @0;
+ let _b = @0;
{
fail!();
}
}
fn partial() {
- let x = @f();
+ let _x = @f();
}
fn main() {
}
fn partial() {
- let x = ~f();
+ let _x = ~f();
}
fn main() {
}
fn partial() {
- let x = ~[~[0], f(), ~[0]];
+ let _x = ~[~[0], f(), ~[0]];
}
fn main() {
struct Blk { node: ~[int] }
fn main() {
- let blk = Blk {
+ let _blk = Blk {
node: build()
};
}
struct Blk { node: ~[int], span: ~[int] }
fn main() {
- let blk = Blk {
+ let _blk = Blk {
node: build1(),
span: build2()
};
fn main() {
@0;
- let r = r(0);
+ let _r = r(0);
}
// error-pattern:fail
fn f() {
- let a = @0;
+ let _a = @0;
fail!();
}
fn g() {
- let b = @0;
+ let _b = @0;
f();
}
fn main() {
- let a = @0;
+ let _a = @0;
g();
}
}
fn main() {
- let lss = (fold_local(), 0);
+ let _lss = (fold_local(), 0);
}
}
fn main() {
- let lss = (fold_local(), fold_remote());
+ let _lss = (fold_local(), fold_remote());
}
fn main() {
f();
- let a = @0;
+ let _a = @0;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(while_true)];
+
// error-pattern:quux
-fn main() { let x: int = { while true { fail!("quux"); } ; 8 } ; }
+fn main() { let _x: int = { while true { fail!("quux"); } ; 8 } ; }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(while_true)];
+
// error-pattern:giraffe
fn main() {
fail!({ while true { fail!("giraffe") }; "clandestine" });
+++ /dev/null
-// 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.
-
-// In this case, the code should compile but
-// the assert should fail at runtime
-// error-pattern:assertion failed
-extern mod extra;
-use std::vec::{same_length, zip};
-
-fn enum_chars(start: u8, end: u8) -> ~[char] {
- assert!(start < end);
- let mut i = start;
- let mut r = ~[];
- while i <= end { r.push(i as char); i += 1 as u8; }
- return r;
-}
-
-fn enum_uints(start: uint, end: uint) -> ~[uint] {
- assert!(start < end);
- let mut i = start;
- let mut r = ~[];
- while i <= end { r.push(i); i += 1; }
- return r;
-}
-
-fn main() {
- let a = 'a' as u8;
- let j = 'j' as u8;
- let k = 1;
- let l = 9;
- let chars = enum_chars(a, j);
- let ints = enum_uints(k, l);
-
- assert!(same_length(chars, ints));
- let ps = zip(chars, ints);
- fail!("the impossible happened");
-}
fn main() {
- let ext_cx = mk_ctxt();
- let s = quote_expr!(__s);
- let e = quote_expr!(__e);
- let f = quote_expr!($s.foo {|__e| $e});
+ let cx = mk_ctxt();
+ let s = quote_expr!(cx, __s);
+ let e = quote_expr!(cx, __e);
+ let f = quote_expr!(cx, $s.foo {|__e| $e});
log(error, pprust::expr_to_str(f));
}
}
fn main() {
- let ext_cx = mk_ctxt();
+ let cx = mk_ctxt();
- let abc = quote_expr!(23);
+ let abc = quote_expr!(cx, 23);
check_pp(ext_cx, abc, pprust::print_expr, ~"23");
- let ty = quote_ty!(int);
+ let ty = quote_ty!(cx, int);
check_pp(ext_cx, ty, pprust::print_type, ~"int");
- let item = quote_item!(static x : int = 10;).get();
+ let item = quote_item!(cx, static x : int = 10;).get();
check_pp(ext_cx, item, pprust::print_item, ~"static x: int = 10;");
- let stmt = quote_stmt!(let x = 20;);
+ let stmt = quote_stmt!(cx, let x = 20;);
check_pp(ext_cx, *stmt, pprust::print_stmt, ~"let x = 20;");
- let pat = quote_pat!(Some(_));
+ let pat = quote_pat!(cx, Some(_));
check_pp(ext_cx, pat, pprust::print_pat, ~"Some(_)");
}
use syntax::ext::base::ExtCtxt;
-fn syntax_extension(ext_cx: @ExtCtxt) {
- let e_toks : ~[syntax::ast::token_tree] = quote_tokens!(1 + 2);
- let p_toks : ~[syntax::ast::token_tree] = quote_tokens!((x, 1 .. 4, *));
+fn syntax_extension(cx: @ExtCtxt) {
+ let e_toks : ~[syntax::ast::token_tree] = quote_tokens!(cx, 1 + 2);
+ let p_toks : ~[syntax::ast::token_tree] = quote_tokens!(cx, (x, 1 .. 4, *));
- let a: @syntax::ast::expr = quote_expr!(1 + 2);
- let _b: Option<@syntax::ast::item> = quote_item!( static foo : int = $e_toks; );
- let _c: @syntax::ast::pat = quote_pat!( (x, 1 .. 4, *) );
- let _d: @syntax::ast::stmt = quote_stmt!( let x = $a; );
- let _e: @syntax::ast::expr = quote_expr!( match foo { $p_toks => 10 } );
+ let a: @syntax::ast::expr = quote_expr!(cx, 1 + 2);
+ let _b: Option<@syntax::ast::item> = quote_item!(cx, static foo : int = $e_toks; );
+ let _c: @syntax::ast::pat = quote_pat!(cx, (x, 1 .. 4, *) );
+ let _d: @syntax::ast::stmt = quote_stmt!(cx, let x = $a; );
+ let _e: @syntax::ast::expr = quote_expr!(cx, match foo { $p_toks => 10 } );
}
fn main() {
use anonexternmod::*;
+#[fixed_stack_segment]
pub fn main() {
unsafe {
rust_get_test_int();
fn rust_get_test_int() -> libc::intptr_t;
}
+#[fixed_stack_segment]
pub fn main() {
unsafe {
let _ = rust_get_test_int();
pub fn main() {
let mut a = X {x: 1};
let mut b = 2;
- let mut c = 3;
+ let c = 3;
assert_eq!(f1(&mut a, &mut b, c), 6);
assert_eq!(a.x, 0);
assert_eq!(b, 10);
- assert_eq!(f2(a.x, |x| a.x = 50), 0);
+ assert_eq!(f2(a.x, |_| a.x = 50), 0);
assert_eq!(a.x, 50);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-
+#[allow(type_limits)];
// Unsigned integer operations
pub fn main() {
// Issue 483 - Assignment expressions result in nil
fn test_assign() {
let mut x: int;
- let mut y: () = x = 10;
+ let y: () = x = 10;
assert_eq!(x, 10);
+ assert_eq!(y, ());
let mut z = x = 11;
assert_eq!(x, 11);
+ assert_eq!(z, ());
z = x = 12;
assert_eq!(x, 12);
+ assert_eq!(z, ());
}
fn test_assign_op() {
let mut x: int = 0;
- let mut y: () = x += 10;
+ let y: () = x += 10;
assert_eq!(x, 10);
+ assert_eq!(y, ());
let mut z = x += 11;
assert_eq!(x, 21);
+ assert_eq!(z, ());
z = x += 12;
assert_eq!(x, 33);
+ assert_eq!(z, ());
}
pub fn main() { test_assign(); test_assign_op(); }
//xfail-fast
#[start]
-fn start(argc:int, argv: **u8, crate_map: *u8) -> int {
+fn start(_argc: int, _argv: **u8, _crate_map: *u8) -> int {
return 0;
}
// xfail-fast
extern mod extra;
use extra::arc;
-fn dispose(_x: arc::Arc<bool>) { unsafe { } }
+fn dispose(_x: arc::Arc<bool>) { }
pub fn main() {
let p = arc::Arc::new(true);
// Binop corner cases
-use std::libc;
-
fn test_nil() {
assert_eq!((), ());
assert!((!(() != ())));
}
fn test_class() {
- let mut q = p(1, 2);
+ let q = p(1, 2);
let mut r = p(1, 2);
unsafe {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::vec;
-
fn w_semi(v: ~[int]) -> int {
// the semicolon causes compiler not to
// complain about the ignored return value:
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::vec;
-
// Check usage and precedence of block arguments in expressions:
pub fn main() {
let v = ~[-1f, 0f, 1f, 2f, 3f];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::uint;
use std::util;
struct Ints {sum: ~int, values: ~[int]}
}
Some(_) => { }
}
+ assert_eq!(x, Some(0));
}
pub fn main() {
let x: @mut @Option<~int> = @mut @None;
match x {
- @@Some(ref y) => {
+ @@Some(ref _y) => {
// here, the refcount of `*x` is bumped so
- // `y` remains valid even if `*x` is modified.
+ // `_y` remains valid even if `*x` is modified.
*x = @None;
}
@@None => {
struct F { f: ~int }
pub fn main() {
- let mut x = @mut @F {f: ~3};
+ let x = @mut @F {f: ~3};
match x {
@@F{f: ref b_x} => {
assert_eq!(**b_x, 3);
fn switcher(x: Option<@int>) {
let mut x = x;
match x {
- Some(@y) => { y.clone(); x = None; }
- None => { }
+ Some(@y) => { y.clone(); x = None; }
+ None => { }
}
+ assert_eq!(x, None);
}
pub fn main() {
let mut y = @4;
// borrow x and y
- let mut r_x = &*x;
- let mut r_y = &*y;
+ let r_x = &*x;
+ let r_y = &*y;
let mut r = r_x;
let mut exp = 3;
info!("*r = %d, exp = %d", *r, exp);
assert_eq!(*r, exp);
+ assert_eq!(x, @5);
+ assert_eq!(y, @6);
}
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub fn main() { let i: (@int, int) = (@10, 10); let (a, _) = i; }
+pub fn main() {
+ let i: (@int, int) = (@10, 10);
+ let (_a, _) = i;
+}
fn some_box(x: int) -> @int { return @x; }
-fn is_odd(n: int) -> bool { return true; }
+fn is_odd(_n: int) -> bool { return true; }
-fn length_is_even(vs: @int) -> bool { return true; }
+fn length_is_even(_vs: @int) -> bool { return true; }
-fn foo(acc: int, n: int) {
+fn foo(_acc: int, n: int) {
if is_odd(n) && length_is_even(some_box(1)) { error!("bloop"); }
}
fn some_box(x: int) -> @int { return @x; }
-fn is_odd(n: int) -> bool { return true; }
+fn is_odd(_n: int) -> bool { return true; }
-fn length_is_even(vs: @int) -> bool { return true; }
+fn length_is_even(_vs: @int) -> bool { return true; }
-fn foo(acc: int, n: int) {
+fn foo(_acc: int, n: int) {
if is_odd(n) || length_is_even(some_box(1)) { error!("bloop"); }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::vec;
-
pub fn main() {
let mut i = 0;
while i < 20 { i += 1; if i == 10 { break; } }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::libc;
-
mod rustrt {
use std::libc;
}
pub fn main() {
- unsafe {
- let _foo = rustrt::rust_get_test_int;
- }
+ let _foo = rustrt::rust_get_test_int;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::str;
-
mod libc {
+ use std::libc::{c_char, c_long, c_longlong};
+
#[abi = "cdecl"]
#[nolink]
extern {
- pub fn atol(x: *u8) -> int;
- pub fn atoll(x: *u8) -> i64;
+ pub fn atol(x: *c_char) -> c_long;
+ pub fn atoll(x: *c_char) -> c_longlong;
}
}
+#[fixed_stack_segment]
fn atol(s: ~str) -> int {
- s.to_c_str().with_ref(|x| unsafe { libc::atol(x as *u8) })
+ s.with_c_str(|x| unsafe { libc::atol(x) as int })
}
+#[fixed_stack_segment]
fn atoll(s: ~str) -> i64 {
- s.to_c_str().with_ref(|x| unsafe { libc::atoll(x as *u8) })
+ s.with_c_str(|x| unsafe { libc::atoll(x) as i64 })
}
pub fn main() {
- unsafe {
- assert_eq!(atol(~"1024") * 10, atol(~"10240"));
- assert!((atoll(~"11111111111111111") * 10i64)
- == atoll(~"111111111111111110"));
- }
+ assert_eq!(atol(~"1024") * 10, atol(~"10240"));
+ assert!((atoll(~"11111111111111111") * 10) == atoll(~"111111111111111110"));
}
// course preferable, as the value itself is
// irrelevant).
-use std::comm::*;
use std::task;
fn foo(x: ()) -> Port<()> {
pub fn main() {
//let bt0 = sys::rusti::frame_address(1u32);
//info!("%?", bt0);
- do cci_iter_lib::iter(~[1, 2, 3]) |i| {
+ do cci_iter_lib::iter([1, 2, 3]) |i| {
printf!("%d", *i);
//assert!(bt0 == sys::rusti::frame_address(2u32));
}
use std::task;
-fn child2(s: ~str) { }
+fn child2(_s: ~str) { }
pub fn main() {
- let x = task::spawn(|| child2(~"hi"));
+ let _x = task::spawn(|| child2(~"hi"));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::uint;
-
trait noisy {
fn speak(&self) -> int;
}
fn annoy_neighbors(critter: @noisy) {
- for i in range(0u, 10) { critter.speak(); }
+ for _i in range(0u, 10) { critter.speak(); }
}
pub fn main() {
// xfail-fast
use std::cmp;
-use std::int;
-use std::uint;
enum cat_type { tuxedo, tabby, tortoiseshell }
extern mod cci_class_trait;
use cci_class_trait::animals::*;
-use std::uint;
-
struct cat {
priv meows: uint,
// xfail-fast
-use std::uint;
-
trait noisy {
fn speak(&mut self);
}
pub fn main() {
let mut nyan : cat = cat(52u, 99);
- let mut kitty = cat(1000u, 2);
+ let kitty = cat(1000u, 2);
assert_eq!(nyan.how_hungry, 99);
assert_eq!(kitty.how_hungry, 2);
nyan.speak();
pub fn main() {
let mut nyan: cat = cat(52u, 99);
- let mut kitty = cat(1000u, 2);
+ let kitty = cat(1000u, 2);
assert_eq!(nyan.how_hungry, 99);
assert_eq!(kitty.how_hungry, 2);
nyan.speak();
impl ToStr for cat {
fn to_str(&self) -> ~str {
- // FIXME #5384: this unsafe block is to work around purity
- unsafe {
- self.name.clone()
- }
+ self.name.clone()
}
}
}
pub fn main() {
- let mut nyan : @ToStr = @cat(0u, 2, ~"nyan") as @ToStr;
+ let nyan : @ToStr = @cat(0u, 2, ~"nyan") as @ToStr;
print_out(nyan, ~"nyan");
}
}
pub fn main() {
- let nyan = cat(~"nyan");
+ let _nyan = cat(~"nyan");
}
pub fn main() {
- let mut _nyan : cat<int> = cat::<int>(52u, 99);
+ let _nyan : cat<int> = cat::<int>(52u, 99);
// let mut kitty = cat(1000u, 2);
}
extern mod cci_class_4;
use cci_class_4::kitties::*;
-use std::uint;
-
pub fn main() {
let mut nyan = cat(0u, 2, ~"nyan");
nyan.eat();
pub fn main() {
let mut nyan : cat = cat(52u, 99);
- let mut kitty = cat(1000u, 2);
+ let kitty = cat(1000u, 2);
assert_eq!(nyan.how_hungry, 99);
assert_eq!(kitty.how_hungry, 2);
nyan.speak();
}
pub fn main() {
- let mut nyan : cat = cat(52u, 99);
- let mut kitty = cat(1000u, 2);
+ let nyan : cat = cat(52u, 99);
+ let kitty = cat(1000u, 2);
assert_eq!(nyan.how_hungry, 99);
assert_eq!(kitty.how_hungry, 2);
}
// xfail-win32
-use std::result;
use std::task;
fn adder(x: @int, y: @int) -> int { return *x + *y; }
}
pub fn main() {
- let mut lincoln = SpeechMaker {speeches: 22};
+ let lincoln = SpeechMaker {speeches: 22};
assert_eq!(foo(&const lincoln), 55);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
use std::task;
pub fn main() {
let (p, ch) = stream();
- let t = task::spawn(|| child(&ch) );
+ let _t = task::spawn(|| child(&ch) );
let y = p.recv();
error!("received");
error!(y);
fn nothing() { }
-fn putstr(s: ~str) { }
+fn putstr(_s: ~str) { }
-fn putint(i: int) {
+fn putint(_i: int) {
let mut i: int = 33;
while i < 36 { putstr(~"hi"); i = i + 1; }
}
// Exercise some of the configured items in ways that wouldn't be possible
// if they had the bogus definition
assert!((b));
- let x: t = true;
- let y: tg = bar;
+ let _x: t = true;
+ let _y: tg = bar;
test_in_fn_ctxt();
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::io;
-
static x : [int, ..4] = [1,2,3,4];
static p : int = x[2];
static y : &'static [int] = &[1,2,3,4];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::io;
-
struct Pair<'self> { a: int, b: &'self int }
static x: &'static int = &10;
// except according to those terms.
use std::cmp;
-use std::io;
struct foo { a: int, b: int, c: int }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::io;
-
static x : [int, ..4] = [1,2,3,4];
static y : &'static [int] = &[1,2,3,4];
// instead of in std.
use std::libc;
-use std::os;
use std::run::*;
use std::run;
use std::str;
// except according to those terms.
pub fn main() {
- let x = ~[
+ let _x = ~[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-pub fn main() { let x: @int = @10; let y: int = *x; }
+pub fn main() {
+ let x: @int = @10;
+ let _y: int = *x;
+}
}
pub fn main() {
- use std::hash::{Hash, HashUtil}; // necessary for IterBytes check
+ use std::hash::HashUtil; // necessary for IterBytes check
let a = Foo {bar: 4, baz: -3};
}
pub fn main() {
- use std::hash::{Hash, HashUtil}; // necessary for IterBytes check
+ use std::hash::HashUtil; // necessary for IterBytes check
let a = Foo {bar: 4, baz: -3};
// Just testing that fail!() type checks in statement or expr
+#[allow(unreachable_code)];
+
fn f() {
fail!();
- let x: int = fail!();
+ let _x: int = fail!();
}
pub fn main() {
// no-reformat
// Testing various forms of `do` with empty arg lists
-fn f(f: &fn() -> bool) -> bool {
+fn f(_f: &fn() -> bool) -> bool {
true
}
// Testing that we can drop the || in do exprs
-fn f(f: @fn() -> bool) -> bool { true }
+fn f(_f: @fn() -> bool) -> bool { true }
-fn d(f: @fn()) { }
+fn d(_f: @fn()) { }
pub fn main() {
do d { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f(f: &fn()) {
+fn f(_f: &fn()) {
}
fn g() {
bar: int
}
-fn g(i: int) { }
+fn g(_i: int) { }
fn f(foo: @@Quux) { g(foo.bar); }
pub fn main() { }
enum t { foo(@int), }
-pub fn main() { let tt = foo(@10); match tt { foo(z) => { } } }
+pub fn main() {
+ let tt = foo(@10);
+ match tt { foo(_z) => { } }
+}
// -*- rust -*-
-fn f() -> int { if true { let s: ~str = ~"should not leak"; return 1; } return 0; }
+fn f() -> int {
+ if true {
+ let _s: ~str = ~"should not leak";
+ return 1;
+ }
+ return 0;
+}
pub fn main() { f(); }
}
pub fn main() {
- let x = S { x: 1 };
+ let _x = S { x: 1 };
}
}
pub fn main() {
- let x: Foo = Foo { x: 3 };
+ let _x: Foo = Foo { x: 3 };
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_mut)];
-
-pub fn main() { let mut v: ~[int] = ~[]; }
+pub fn main() { let mut _v: ~[int] = ~[]; }
fn addr_of<T>(ptr: &T) -> uint {
let ptr = ptr::to_unsafe_ptr(ptr);
- unsafe { ptr as uint }
+ ptr as uint
}
fn is_aligned<T>(ptr: &T) -> bool {
test_color(imaginary, -1, ~"imaginary");
}
-fn test_color(color: color, val: int, name: ~str) {
+fn test_color(color: color, val: int, _name: ~str) {
assert!(color as int == val);
assert!(color as float == val as float);
}
}
pub fn main() {
- let x = a::Bar;
+ let _x = a::Bar;
}
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+
enum Animal {
Dog (~str, float),
Cat { name: ~str, weight: float }
let mut a: Animal = Dog(~"Cocoa", 37.2);
a = Cat{ name: ~"Spotty", weight: 2.7 };
// permuting the fields should work too
- let c = Cat { weight: 3.1, name: ~"Spreckles" };
+ let _c = Cat { weight: 3.1, name: ~"Spreckles" };
}
static BAR2:uint = BAR;
fn main() {
- let v = [0, .. Bunny as uint];
- let v = [0, .. BAR];
- let v = [0, .. BAR2];
+ let _v = [0, .. Bunny as uint];
+ let _v = [0, .. BAR];
+ let _v = [0, .. BAR2];
static BAR3:uint = BAR2;
- let v = [0, .. BAR3];
-}
\ No newline at end of file
+ let _v = [0, .. BAR3];
+}
pub fn main() {
let x = &"hello";
let v = &"hello";
- let mut y : &str = &"there";
+ let y : &str = &"there";
info!(x);
info!(y);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let x : ~str = ~"hello";
let _y : ~str = ~"there";
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let x : [@int, ..5] = [@1,@2,@3,@4,@5];
let _y : [@int, ..5] = [@1,@2,@3,@4,@5];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let x : &[int] = &[1,2,3,4,5];
let mut z = &[1,2,3,4,5];
use std::os;
pub fn main() {
- assert_eq!(os::getenv(~"TEST_EXEC_ENV"), Some(~"22"));
+ assert_eq!(os::getenv("TEST_EXEC_ENV"), Some(~"22"));
}
pub fn f() -> t { return t1; }
}
-pub fn main() { let v: foo::t = foo::f(); }
+pub fn main() { let _v: foo::t = foo::f(); }
pub static a : int = 10;
}
pub fn zum() {
- let b = a;
+ let _b = a;
}
}
pub enum t { t1, }
}
-pub fn main() { let v = foo::t1; }
+pub fn main() { let _v = foo::t1; }
type t = @fn() -> int;
fn ten() -> int { return 10; }
let rs: t = { ten };
- //assert!((rs() == 10));
+ assert!((rs() == 10));
}
pub fn main() { test_fn(); }
// except according to those terms.
// Regression test for issue #388
-pub fn main() { let x = { { @10 } }; }
+pub fn main() { let _x = { { @10 } }; }
// values from the else if branch
pub fn main() {
let y: @uint = @10u;
- let x = if false { y } else if true { y } else { y };
+ let _x = if false { y } else if true { y } else { y };
assert_eq!(*y, 10u);
}
// except according to those terms.
// Regression test for issue #388
-pub fn main() { let x = if false { @0u } else if true { @10u } else { @0u }; }
+pub fn main() {
+ let _x = if false {
+ @0u
+ } else if true {
+ @10u
+ } else {
+ @0u
+ };
+}
// Issue #521
-fn f() { let x = match true { true => { 10 } false => { return } }; }
+fn f() {
+ let _x = match true {
+ true => { 10 }
+ false => { return }
+ };
+}
pub fn main() { }
// When all branches of an if expression result in fail, the entire if
// expression results in fail.
-pub fn main() { let x = if true { 10 } else { if true { fail!() } else { fail!() } }; }
+pub fn main() {
+ let _x = if true {
+ 10
+ } else {
+ if true { fail!() } else { fail!() }
+ };
+}
// When all branches of an match expression result in fail, the entire
// match expression results in fail.
pub fn main() {
- let x =
+ let _x =
match true {
true => { 10 }
false => { match true { true => { fail!() } false => { fail!() } } }
}
fn test_inferrence() {
- let mut rs = match true { true => { true } false => { false } };
+ let rs = match true { true => { true } false => { false } };
assert!((rs));
}
}
}
+#[fixed_stack_segment]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);
extern mod externcallback(vers = "0.1");
+#[fixed_stack_segment] #[inline(never)]
fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
extern mod extra;
use extra::json::Object;
pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU32s {one: 22, two: 23};
pub fn rust_dbg_extern_identity_TwoU64s(u: TwoU64s) -> TwoU64s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU64s {one: 22, two: 23};
pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU64s {one: 22, two: 23};
pub fn rust_dbg_extern_identity_u8(v: u8) -> u8;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u8, rust_dbg_extern_identity_u8(22_u8));
pub fn rust_dbg_extern_identity_double(v: f64) -> f64;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64));
pub fn rust_dbg_extern_identity_u32(v: u32) -> u32;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u32, rust_dbg_extern_identity_u32(22_u32));
pub fn rust_dbg_extern_identity_u64(v: u64) -> u64;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u64, rust_dbg_extern_identity_u64(22_u64));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 #5745
-// xfail-macos Broken on mac i686
-
struct TwoU16s {
one: u16, two: u16
}
pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU16s();
pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU32s();
pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU64s();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 #5745
-// xfail-macos Broken on mac i686
-
struct TwoU8s {
one: u8, two: u8
}
pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU8s();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// This creates a bunch of yielding tasks that run concurrently
+// This creates a bunch of descheduling tasks that run concurrently
// while holding onto C stacks
use std::libc;
if data == 1u {
data
} else {
- task::yield();
+ task::deschedule();
count(data - 1u) + count(data - 1u)
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
rustrt::rust_dbg_call(cb, n)
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
- task::yield();
+ task::deschedule();
rustrt::rust_dbg_call(cb, n)
}
}
// except according to those terms.
fn main() {
- let opt: Option<&'static str> = option_env!("__HOPEFULLY_DOESNT_EXIST__");
- assert!(opt.is_none());
+ assert!(option_env!("__HOPEFULLY_DOESNT_EXIST__").is_none());
}
pub fn main() {
fn f() {}
- let i: r = r {field: f};
+ let _i: r = r {field: f};
}
// -*- rust -*-
-fn foo(f: extern fn(int) -> int) { }
+fn foo(_f: extern fn(int) -> int) { }
fn id(x: int) -> int { return x; }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_variable)];
+
pub fn main() {
// We should be able to type infer inside of @fns.
- let f = || {
+ let _f = || {
let i = 10;
};
}
use std::libc;
use std::unstable::run_in_bare_thread;
-extern {
- pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t;
-}
+externfn!(fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t)
pub fn main() {
unsafe {
do run_in_bare_thread() {
- unsafe {
- let i = &100;
- rust_dbg_call(callback, cast::transmute(i));
- }
+ let i = &100;
+ rust_dbg_call(callback, cast::transmute(i));
}
}
}
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
rustrt1::rust_get_test_int();
extern mod extra;
-use std::libc;
-use std::str;
-use std::vec;
-
mod libc {
+ use std::libc::{c_char, size_t};
+
#[nolink]
#[abi = "cdecl"]
extern {
#[link_name = "strlen"]
- pub fn my_strlen(str: *u8) -> uint;
+ pub fn my_strlen(str: *c_char) -> size_t;
}
}
+#[fixed_stack_segment] #[inline(never)]
fn strlen(str: ~str) -> uint {
- unsafe {
- // C string is terminated with a zero
- do str.to_c_str().with_ref |buf| {
- libc::my_strlen(buf as *u8)
+ // C string is terminated with a zero
+ do str.with_c_str |buf| {
+ unsafe {
+ libc::my_strlen(buf) as uint
}
}
}
// except according to those terms.
mod foo {
+ use std::libc::c_int;
+
#[nolink]
extern {
- pub static errno: int;
+ pub static errno: c_int;
}
}
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
rustrt::rust_get_test_int();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32
// Passing enums by value
pub enum void { }
}
mod libc {
+ use std::libc::{c_int, c_void, size_t, ssize_t};
+
#[abi = "cdecl"]
#[nolink]
extern {
- pub fn write(fd: int, buf: *u8, count: ::std::libc::size_t)
- -> ::std::libc::ssize_t;
+ pub fn write(fd: c_int, buf: *c_void, count: size_t) -> ssize_t;
}
}
struct Pair { x: @int, y: @int }
-fn f<T>(t: T) { let t1: T = t; }
+fn f<T>(t: T) { let _t1: T = t; }
pub fn main() { let x = Pair {x: @10, y: @12}; f(x); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-
+#[allow(dead_assignment)];
// -*- rust -*-
fn id<T>(x: T) -> T { return x; }
enum wrapper<T> { wrapped(T), }
-pub fn main() { let w = wrapped(~[1, 2, 3, 4, 5]); }
+pub fn main() { let _w = wrapped(~[1, 2, 3, 4, 5]); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f<T>(v: @T) { }
+fn f<T>(_v: @T) { }
pub fn main() { f(@~[1, 2, 3, 4, 5]); }
enum list<T> { cons(@T, @list<T>), nil, }
pub fn main() {
- let a: list<int> =
+ let _a: list<int> =
cons::<int>(@10, @cons::<int>(@12, @cons::<int>(@13, @nil::<int>)));
}
// This causes memory corruption in stage0.
enum thing<K> { some(K), }
-pub fn main() { let x = some(~"hi"); }
+pub fn main() { let _x = some(~"hi"); }
enum clam<T> { a(T), }
-pub fn main() { let c = a(3); }
+pub fn main() { let _c = a(3); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
enum foo<T> { arm(T), }
fn altfoo<T>(f: foo<T>) {
let mut hit = false;
- match f { arm::<T>(x) => { info!("in arm"); hit = true; } }
+ match f { arm::<T>(_x) => { info!("in arm"); hit = true; } }
assert!((hit));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
enum option<T> { some(@T), none, }
-pub fn main() { let mut a: option<int> = some::<int>(@10); a = none::<int>; }
+pub fn main() {
+ let mut a: option<int> = some::<int>(@10);
+ a = none::<int>;
+}
type Bar<T> = Foo<T>;
-fn takebar<T>(b: Bar<T>) { }
+fn takebar<T>(_b: Bar<T>) { }
pub fn main() { }
pub fn main() {
let args = ~[];
- let opts = ~[optopt(~"b")];
+ let opts = ~[optopt("b")];
match getopts(args, opts) {
Ok(ref m) =>
match Pair {x: 10, y: 20} {
x if x.x < 5 && x.y < 5 => { 1 }
Pair {x: x, y: y} if x == 10 && y == 20 => { 2 }
- Pair {x: x, y: y} => { 3 }
+ Pair {x: _x, y: _y} => { 3 }
};
assert_eq!(b, 2);
}
)
pub fn main() {
- let page = html! (
+ let _page = html! (
<html>
<head><title>This is the title.</title></head>
<body>
macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) })
// Make sure there's a poly formatter that takes anything
- t!(ifmt!("{}", 1), "1");
- t!(ifmt!("{}", A), "{}");
- t!(ifmt!("{}", ()), "()");
- t!(ifmt!("{}", @(~1, "foo")), "@(~1, \"foo\")");
+ t!(ifmt!("{:?}", 1), "1");
+ t!(ifmt!("{:?}", A), "{}");
+ t!(ifmt!("{:?}", ()), "()");
+ t!(ifmt!("{:?}", @(~1, "foo")), "@(~1, \"foo\")");
// Various edge cases without formats
t!(ifmt!(""), "");
t!(ifmt!("hello"), "hello");
t!(ifmt!("hello \\{"), "hello {");
+ // default formatters should work
+ t!(ifmt!("{}", 1i), "1");
+ t!(ifmt!("{}", 1i8), "1");
+ t!(ifmt!("{}", 1i16), "1");
+ t!(ifmt!("{}", 1i32), "1");
+ t!(ifmt!("{}", 1i64), "1");
+ t!(ifmt!("{}", 1u), "1");
+ t!(ifmt!("{}", 1u8), "1");
+ t!(ifmt!("{}", 1u16), "1");
+ t!(ifmt!("{}", 1u32), "1");
+ t!(ifmt!("{}", 1u64), "1");
+ t!(ifmt!("{}", 1.0f), "1");
+ t!(ifmt!("{}", 1.0f32), "1");
+ t!(ifmt!("{}", 1.0f64), "1");
+ t!(ifmt!("{}", "a"), "a");
+ t!(ifmt!("{}", ~"a"), "a");
+ t!(ifmt!("{}", @"a"), "a");
+ t!(ifmt!("{}", false), "false");
+ t!(ifmt!("{}", 'a'), "a");
+
// At least exercise all the formats
t!(ifmt!("{:b}", true), "true");
t!(ifmt!("{:c}", '☃'), "☃");
t!(ifmt!("{:x}", 10u), "a");
t!(ifmt!("{:X}", 10u), "A");
t!(ifmt!("{:s}", "foo"), "foo");
+ t!(ifmt!("{:s}", ~"foo"), "foo");
+ t!(ifmt!("{:s}", @"foo"), "foo");
t!(ifmt!("{:p}", 0x1234 as *int), "0x1234");
t!(ifmt!("{:p}", 0x1234 as *mut int), "0x1234");
t!(ifmt!("{:d}", A), "aloha");
t!(ifmt!("{foo} {bar}", foo=0, bar=1), "0 1");
t!(ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
t!(ifmt!("{} {0:s}", "a"), "a a");
- t!(ifmt!("{} {0}", "a"), "\"a\" \"a\"");
+ t!(ifmt!("{} {0}", "a"), "a a");
// Methods should probably work
t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
extern mod extra;
use std::vec::*;
pub fn main() {
let mut v = from_elem(0u, 0);
- v = append(v, ~[4, 2]);
+ v = append(v, [4, 2]);
assert_eq!(from_fn(2, |i| 2*(i+1)), ~[2, 4]);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
use baz::zed;
use baz::zed::bar;
pub fn bar() { info!("bar"); }
}
-pub fn main() { let zed = 42; bar(); }
+pub fn main() { let _zed = 42; bar(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
use foo::zed;
use bar::baz;
+
mod foo {
pub mod zed {
pub fn baz() { info!("baz"); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
use foo::zed;
use bar::baz;
+
mod foo {
pub mod zed {
pub fn baz() { info!("baz"); }
#[unsafe_destructor]
impl Drop for r {
fn drop(&self) {
- unsafe {
- *(self.i) = *(self.i) + 1;
- }
+ *(self.i) = *(self.i) + 1;
}
}
fn test_box() {
let i = @mut 0;
{
- let a = @r(i);
+ let _a = @r(i);
}
assert_eq!(*i, 1);
}
fn test_rec() {
let i = @mut 0;
{
- let a = Box {x: r(i)};
+ let _a = Box {x: r(i)};
}
assert_eq!(*i, 1);
}
let i = @mut 0;
{
- let a = t0(r(i));
+ let _a = t0(r(i));
}
assert_eq!(*i, 1);
}
fn test_tup() {
let i = @mut 0;
{
- let a = (r(i), 0);
+ let _a = (r(i), 0);
}
assert_eq!(*i, 1);
}
fn test_unique() {
let i = @mut 0;
{
- let a = ~r(i);
+ let _a = ~r(i);
}
assert_eq!(*i, 1);
}
fn test_box_rec() {
let i = @mut 0;
{
- let a = @Box {
+ let _a = @Box {
x: r(i)
};
}
struct X { x: uint, nxt: *foo }
pub fn main() {
- let x = foo(X {x: 0, nxt: ptr::null()});
+ let _x = foo(X {x: 0, nxt: ptr::null()});
}
// -*- rust -*-
-pub fn main() { let x: int = 10; }
+pub fn main() { let _x: int = 10; }
use cci_intrinsic::atomic_xchg;
pub fn main() {
- unsafe {
- let mut x = 1;
- atomic_xchg(&mut x, 5);
- assert_eq!(x, 5);
- }
+ let mut x = 1;
+ atomic_xchg(&mut x, 5);
+ assert_eq!(x, 5);
}
pub fn main() {
unsafe {
- let mut x = @1;
+ let x = @1;
let mut y = @2;
rusti::move_val(&mut y, x);
assert_eq!(*y, 1);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::f64;
-
mod rusti {
#[abi = "rust-intrinsic"]
extern "rust-intrinsic" {
extern mod foreign_lib;
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
- let foo = foreign_lib::rustrt::rust_get_test_int();
+ let _foo = foreign_lib::rustrt::rust_get_test_int();
}
}
// except according to those terms.
use std::hashmap::HashMap;
-use std::str;
pub fn main() {
let mut m = HashMap::new();
use std::cast;
use std::libc::{c_double, c_int};
-use std::f64::*;
fn to_c_int(v: &mut int) -> &mut c_int {
unsafe {
}
}
+#[fixed_stack_segment] #[inline(never)]
fn lgamma(n: c_double, value: &mut int) -> c_double {
unsafe {
return m::lgamma(n, to_c_int(value));
}
impl<A> clam<A> for foo<A> {
- fn chowder(&self, y: A) {
+ fn chowder(&self, _y: A) {
}
}
}
impl<A> foo<A> {
- pub fn bar<B,C:clam<A>>(&self, c: C) -> B {
+ pub fn bar<B,C:clam<A>>(&self, _c: C) -> B {
fail!();
}
}
struct foo(int);
impl foo {
- pub fn bar<B,C:clam<B>>(&self, c: C) -> B { fail!(); }
+ pub fn bar<B,C:clam<B>>(&self, _c: C) -> B { fail!(); }
}
pub fn main() { }
// except according to those terms.
pub fn main() {
- let foo = 100;
+ let _foo = 100;
static quux: int = 5;
enum Stuff {
}
impl<T> c1<T> {
- pub fn f1(&self, x: int) {
+ pub fn f1(&self, _x: int) {
}
}
}
impl<T> c1<T> {
- pub fn f2(&self, x: int) {
+ pub fn f2(&self, _x: int) {
}
}
}
impl<T> c1<T> {
- pub fn f1(&self, x: T) {}
+ pub fn f1(&self, _x: T) {}
}
fn c1<T>(x: T) -> c1<T> {
}
impl<T> c1<T> {
- pub fn f2(&self, x: T) {}
+ pub fn f2(&self, _x: T) {}
}
g: 0,
};
- let y = Pair {
+ let _y = Pair {
f: 1,
g: 1,
.. x
};
- let z = Pair {
+ let _z = Pair {
f: 1,
.. x
};
// xfail-fast
// aux-build:issue-2526.rs
+#[allow(unused_imports)];
+
extern mod issue_2526;
use issue_2526::*;
}
pub fn main() {
- let mut kitty = cat();
+ let kitty = cat();
nyan(kitty, KittyInfo {kitty: kitty});
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::util;
-
pub type Task = int;
// tjc: I don't know why
// We should consider moving this to ::std::unsafe, although I
// suspect graydon would want us to use void pointers instead.
pub unsafe fn uniquify<T>(x: *T) -> ~T {
- unsafe { cast::transmute(x) }
+ cast::transmute(x)
}
pub fn swap_state_acq(dst: &mut state, src: state) -> state {
}
pub fn send<T:Send>(mut p: send_packet<T>, payload: T) {
- let mut p = p.unwrap();
+ let p = p.unwrap();
let mut p = unsafe { uniquify(p) };
assert!((*p).payload.is_none());
(*p).payload = Some(payload);
}
pub fn recv<T:Send>(mut p: recv_packet<T>) -> Option<T> {
- let mut p = p.unwrap();
+ let p = p.unwrap();
let mut p = unsafe { uniquify(p) };
loop {
let old_state = swap_state_acq(&mut (*p).state,
blocked);
match old_state {
- empty | blocked => { task::yield(); }
+ empty | blocked => { task::deschedule(); }
full => {
let payload = util::replace(&mut p.payload, None);
return Some(payload.unwrap())
}
}
- pub fn sender_terminate<T:Send>(mut p: *packet<T>) {
+ pub fn sender_terminate<T:Send>(p: *packet<T>) {
let mut p = unsafe { uniquify(p) };
match swap_state_rel(&mut (*p).state, terminated) {
empty | blocked => {
}
}
- pub fn receiver_terminate<T:Send>(mut p: *packet<T>) {
+ pub fn receiver_terminate<T:Send>(p: *packet<T>) {
let mut p = unsafe { uniquify(p) };
match swap_state_rel(&mut (*p).state, terminated) {
empty => {
pub mod pingpong {
use std::cast;
- use std::ptr;
- use std::util;
pub struct ping(::pipes::send_packet<pong>);
pub struct pong(::pipes::send_packet<ping>);
pub fn liberate_ping(p: ping) -> ::pipes::send_packet<pong> {
unsafe {
- let addr : *::pipes::send_packet<pong> = match &p {
+ let _addr : *::pipes::send_packet<pong> = match &p {
&ping(ref x) => { cast::transmute(x) }
};
fail!()
pub fn liberate_pong(p: pong) -> ::pipes::send_packet<ping> {
unsafe {
- let addr : *::pipes::send_packet<ping> = match &p {
+ let _addr : *::pipes::send_packet<ping> = match &p {
&pong(ref x) => { cast::transmute(x) }
};
fail!()
}
pub mod client {
- use std::option;
use pingpong;
pub type ping = ::pipes::send_packet<pingpong::ping>;
}
}
-fn add_interface(store: int, managed_ip: ~str, data: extra::json::Json) -> (~str, object)
+fn add_interface(_store: int, managed_ip: ~str, data: extra::json::Json) -> (~str, object)
{
match &data {
&extra::json::Object(ref interface) => {
use std::io::ReaderUtil;
use std::io;
-use std::str;
use std::to_str;
enum square {
extern mod extra;
-use std::io;
use std::vec;
trait methods {
pub fn main() {
let fd: libc::c_int = 1 as libc::c_int;
- let sock = @socket::socket_handle(fd);
+ let _sock = @socket::socket_handle(fd);
}
pub fn main() {
let x = 1;
let y: @fn() -> int = || x;
- let z = y();
+ let _z = y();
}
// Extern mod controls linkage. Use controls the visibility of names to modules that are
// already linked in. Using WriterUtil allows us to use the write_line method.
-use std::int;
use std::io::WriterUtil;
use std::io;
use std::str;
fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt {
// Use an anonymous function to build a vector of vectors containing
// blank characters for each position in our canvas.
- let mut lines = do vec::build_sized(height) |push| {
+ let lines = do vec::build_sized(height) |push| {
do height.times {
push(vec::from_elem(width, '.'));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unnecessary_allocation)];
+
// rustc --test match_borrowed_str.rs.rs && ./match_borrowed_str.rs
extern mod extra;
pub fn main()
{
assert!(compare("foo", "foo"));
+ assert!(compare(~"foo", ~"foo"));
assert!(compare(@"foo", @"foo"));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::io;
-
struct Vec2 {
x: float,
y: float
}
pub fn main() {
- let mut x = @mut Foo { x: 3 };
+ let x = @mut Foo { x: 3 };
// Neither of the next two lines should cause an error
let _ = x.stuff();
x.stuff();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub fn main()
-{
+#[allow(path_statement)];
+
+pub fn main() {
let y = ~1;
y;
}
// except according to those terms.
pub fn main() {
- let id: &Mat2<float> = &Matrix::identity();
+ let _id: &Mat2<float> = &Matrix::identity();
}
pub trait Index<Index,Result> { }
// except according to those terms.
pub fn main() {
- let foo = [0, ..2*4];
+ let _foo = [0, ..2*4];
}
--- /dev/null
+// 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.
+
+fn broken<'r>(v: &'r [u8], i: uint, j: uint) -> &'r [u8] { v.slice(i, j) }
+
+pub fn main() {}
let x = os::args();
for arg in x.iter() {
match arg.clone() {
- s => { }
+ _s => { }
}
}
}
impl Drop for NonCopyable {
fn drop(&self) {
let p = **self;
- let v = unsafe { transmute::<*c_void, ~int>(p) };
+ let _v = unsafe { transmute::<*c_void, ~int>(p) };
}
}
fn main() {
let t = ~0;
let p = unsafe { transmute::<~int, *c_void>(t) };
- let z = NonCopyable(p);
+ let _z = NonCopyable(p);
}
--- /dev/null
+// 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.
+
+trait U { fn f(self); }
+impl U for int { fn f(self) {} }
+pub fn main() { 4.f(); }
--- /dev/null
+// 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.
+
+struct T { a: ~int }
+
+trait U {
+ fn f(self);
+}
+
+impl U for ~int {
+ fn f(self) { }
+}
+
+pub fn main() {
+ let T { a: a } = T { a: ~0 };
+ a.f();
+}
+
--- /dev/null
+// 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.
+
+fn make_adder(x: int) -> @fn(int) -> int { |y| x + y }
+pub fn main() { }
}
fn main() {
- let mut sched = Scheduler::new(~UvEventLoop::new() as ~EventLoop);
+ let _sched = Scheduler::new(~UvEventLoop::new() as ~EventLoop);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
fn main() {
let s: ~str = ~"foobar";
let mut t: &str = s;
-fn foo<T: ::std::cmp::Eq>(t: T) { }
+fn foo<T: ::std::cmp::Eq>(_t: T) { }
fn main() { }
--- /dev/null
+// 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.
+
+struct Dog {
+ name : ~str
+}
+
+trait Barks {
+ fn bark(&self) -> ~str;
+}
+
+impl Barks for Dog {
+ fn bark(&self) -> ~str {
+ return fmt!("woof! (I'm %s)", self.name);
+ }
+}
+
+
+pub fn main() {
+ let snoopy = ~Dog{name: ~"snoopy"};
+ let bubbles = ~Dog{name: ~"bubbles"};
+ let barker = [snoopy as ~Barks, bubbles as ~Barks];
+
+ for pup in barker.iter() {
+ println(fmt!("%s", pup.bark()));
+ }
+}
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unreachable_code)];
+
use std::io;
fn main() {
--- /dev/null
+// 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.
+
+pub struct Foo {
+ a: int,
+}
+
+struct Bar<'self> {
+ a: ~Option<int>,
+ b: &'self Foo,
+}
+
+fn check(a: @Foo) {
+ let _ic = Bar{ b: a, a: ~None };
+}
+
+pub fn main(){}
--- /dev/null
+// 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.
+
+// xfail-test
+
+use std::io;
+
+struct T (&'static [int]);
+static t : T = T (&'static [5, 4, 3]);
+fn main () {
+ assert_eq!(t[0], 5);
+}
\ No newline at end of file
--- /dev/null
+// 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.
+
+#[allow(unused_mut)];
+
+pub fn main() {
+ let mut your_favorite_numbers = @[1,2,3];
+ let mut my_favorite_numbers = @[4,5,6];
+ let f = your_favorite_numbers + my_favorite_numbers;
+ println(fmt!("The third favorite number is %?.", f))
+}
+
--- /dev/null
+// 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.
+
+pub enum Thing {
+ A(~Foo)
+}
+
+pub trait Foo {}
+
+pub struct Struct;
+
+impl Foo for Struct {}
+
+pub fn main() {
+ match A(~Struct as ~Foo) {
+ A(_a) => 0,
+ };
+}
+
--- /dev/null
+// 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.
+
+// xfail-test
+
+pub mod Bar {
+ pub struct Foo {
+ v: int,
+ }
+
+ extern {
+ #[rust_stack]
+ pub fn foo(v: *Foo) -> Foo;
+ }
+}
+
+fn main() { }
+
--- /dev/null
+// 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.
+
+fn foo(~(_x, _y): ~(int, int)) {}
+
+pub fn main() {}
--- /dev/null
+// 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.
+
+use std::unstable::intrinsics;
+
+/// Returns the size of a type
+pub fn size_of<T>() -> uint {
+ TypeInfo::size_of::<T>()
+}
+
+/// Returns the size of the type that `val` points to
+pub fn size_of_val<T>(val: &T) -> uint {
+ val.size_of_val()
+}
+
+pub trait TypeInfo {
+ fn size_of() -> uint;
+ fn size_of_val(&self) -> uint;
+}
+
+impl<T> TypeInfo for T {
+ /// The size of the type in bytes.
+ fn size_of() -> uint {
+ unsafe { intrinsics::size_of::<T>() }
+ }
+
+ /// Returns the size of the type of `self` in bytes.
+ fn size_of_val(&self) -> uint {
+ TypeInfo::size_of::<T>()
+ }
+}
+
+pub fn main() {}
--- /dev/null
+// 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.
+
+// aux-build:iss.rs
+// xfail-fast
+
+extern mod iss ( name = "iss6919_3" );
+
+pub fn main() {
+ iss::D.k;
+}
+
--- /dev/null
+// 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.
+
+pub fn main() {
+ static FOO: float = 10.0;
+
+ match 0.0 {
+ 0.0 .. FOO => (),
+ _ => ()
+ }
+}
+
--- /dev/null
+// 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.
+
+trait A {}
+struct B;
+impl A for B {}
+
+fn foo(_: &mut A) {}
+
+fn main() {
+ let mut b = B;
+ foo(&mut b as &mut A);
+}
+
--- /dev/null
+// 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.
+
+trait A {}
+struct B;
+impl A for B {}
+
+struct C<'self> {
+ foo: &'self mut A,
+}
+
+fn foo(a: &mut A) {
+ C{ foo: a };
+}
+
+fn main() {
+}
+
--- /dev/null
+// 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.
+
+use std::rt::io;
+
+fn foo(a: &mut io::Writer) {
+ a.write([])
+}
+
+fn main(){}
+
--- /dev/null
+// 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.
+
+// aux-build:issue_8401.rs
+// xfail-fast
+
+extern mod issue_8401;
+
+pub fn main() {}
--- /dev/null
+// 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.
+
+// xfail-test
+use std::io;
+
+fn main() {
+// This is ok
+ match &[(~5,~7)] {
+ ps => {
+ let (ref y, _) = ps[0];
+ io::println(fmt!("1. y = %d", **y));
+ assert!(**y == 5);
+ }
+ }
+
+// This is not entirely ok
+ match Some(&[(~5,)]) {
+ Some(ps) => {
+ let (ref y,) = ps[0];
+ io::println(fmt!("2. y = %d", **y));
+ if **y != 5 { io::println("sadness"); }
+ }
+ None => ()
+ }
+
+// This is not ok
+ match Some(&[(~5,~7)]) {
+ Some(ps) => {
+ let (ref y, ref z) = ps[0];
+ io::println(fmt!("3. y = %d z = %d", **y, **z));
+ assert!(**y == 5);
+ }
+ None => ()
+ }
+}
+
#[unsafe_destructor]
impl Drop for r {
fn drop(&self) {
- unsafe {
- *(self.b) += 1;
- }
+ *(self.b) += 1;
}
}
pub fn main() {
let b = @mut 0;
{
- let p = Some(r(b));
+ let _p = Some(r(b));
}
assert_eq!(*b, 1);
fn test_heap_log() { let s = ~"a big ol' string"; info!(s); }
fn test_stack_add() {
- assert_eq!(~"a" + ~"b", ~"ab");
+ assert_eq!(~"a" + "b", ~"ab");
let s: ~str = ~"a";
assert_eq!(s + s, ~"aa");
- assert_eq!(~"" + ~"", ~"");
+ assert_eq!(~"" + "", ~"");
}
-fn test_stack_heap_add() { assert!((~"a" + ~"bracadabra" == ~"abracadabra")); }
+fn test_stack_heap_add() { assert!((~"a" + "bracadabra" == ~"abracadabra")); }
fn test_heap_add() {
- assert_eq!(~"this should" + ~" totally work", ~"this should totally work");
+ assert_eq!(~"this should" + " totally work", ~"this should totally work");
}
fn test_append() {
let mut s = ~"";
- s.push_str(~"a");
+ s.push_str("a");
assert_eq!(s, ~"a");
let mut s = ~"a";
- s.push_str(~"b");
+ s.push_str("b");
info!(s.clone());
assert_eq!(s, ~"ab");
let mut s = ~"c";
- s.push_str(~"offee");
+ s.push_str("offee");
assert!(s == ~"coffee");
- s.push_str(~"&tea");
+ s.push_str("&tea");
assert!(s == ~"coffee&tea");
}
extern mod extra;
pub fn f() {
- fmt!("test%s", ~"s");
+ fmt!("test%s", "s");
#[attr = "val"]
fn g() { }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f(a: ~[int]) { }
+fn f(_a: ~[int]) { }
pub fn main() { f(~[1, 2, 3, 4, 5]); }
-use std::comm::*;
use std::task;
fn producer(c: &Chan<~[u8]>) {
pub fn main() {
let (p, ch) = stream::<~[u8]>();
- let prod = task::spawn(|| producer(&ch) );
+ let _prod = task::spawn(|| producer(&ch) );
- let data: ~[u8] = p.recv();
+ let _data: ~[u8] = p.recv();
}
pub fn main() {
let e = @mut Refs{refs: ~[], n: 0};
- let f: @fn() = || error!(e.n);
+ let _f: @fn() = || error!(e.n);
e.refs.push(1);
}
k: int,
l: int}
fn f() {
- let foo: Large =
+ let _foo: Large =
Large {a: 0,
b: 0,
c: 0,
-fn leaky<T>(t: T) { }
+fn leaky<T>(_t: T) { }
pub fn main() { let x = @10; leaky::<@int>(x); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
enum t { a, b(@int), }
-fn leaky<T>(t: T) { }
+fn leaky<T>(_t: T) { }
pub fn main() { let x = ~10; leaky::<~int>(x); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
struct X { x: int, y: @A }
struct A { a: int }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn test(cond: bool) {
+#[allow(dead_assignment)];
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
+
+fn test(_cond: bool) {
let v: int;
v = 1;
loop { } // loop never terminates, so no error is reported
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unreachable_code)];
+
fn test() {
let _v: int;
_v = 1;
-pub fn main() { if false { error!(~"foo" + ~"bar"); } }
+pub fn main() { if false { error!(~"foo" + "bar"); } }
}
pub fn main() {
- let x = list::from_vec(~[a(22u), b(~"hi")]);
+ let x = list::from_vec([a(22u), b(~"hi")]);
let exp = ~"@Cons(a(22), @Cons(b(~\"hi\"), @Nil))";
let act = fmt!("%?", x);
assert!(act == exp);
struct V<T> { v: ~[option<T>] }
fn mk<T:'static>() -> @mut Smallintmap<T> {
- let mut v: ~[option<T>] = ~[];
+ let v: ~[option<T>] = ~[];
return @mut Smallintmap {v: v};
}
fn f<T,U:'static>() {
- let mut sim = mk::<U>();
+ let sim = mk::<U>();
error!(sim);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_variable)];
-
-pub fn main() { let mut i: int = 0; while i < 1000000 { i += 1; let x = 3; } }
+pub fn main() {
+ let mut i: int = 0;
+ while i < 1000000 {
+ i += 1;
+ let x = 3;
+ }
+}
// except according to those terms.
pub fn main() {
- let i = 0u;
+ let _i = 0u;
loop {
break;
}
--- /dev/null
+// 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.
+
+use std::local_data;
+
+local_data_key!(foo: int)
+
+mod bar {
+ local_data_key!(pub baz: float)
+}
+
+fn main() {
+ local_data::get(foo, |x| assert!(x.is_none()));
+ local_data::get(bar::baz, |y| assert!(y.is_none()));
+
+ local_data::set(foo, 3);
+ local_data::set(bar::baz, -10.0);
+
+ local_data::get(foo, |x| assert_eq!(*x.unwrap(), 3));
+ local_data::get(bar::baz, |y| assert_eq!(*y.unwrap(), -10.0));
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unnecessary_allocation)];
+
fn f1(ref_string: &str) -> ~str {
match ref_string {
"a" => ~"found a",
pub fn main() {
let mut x = ~Pair {a: ~10, b: ~20};
match x {
- ~Pair {a: ref mut a, b: ref mut b} => {
+ ~Pair {a: ref mut a, b: ref mut _b} => {
assert!(**a == 10); *a = ~30; assert!(**a == 30);
}
}
struct X { x: int }
pub fn main() {
- let x = match 0 {
+ let _x = match 0 {
_ => X {
x: 0
}.x
struct X { x: int }
pub fn main() {
- let x = match 0 {
+ let _x = match 0 {
_ => X {
x: 0
}
enum maybe<T> { nothing, just(T), }
fn foo(x: maybe<int>) {
- match x { nothing => { error!("A"); } just(a) => { error!("B"); } }
+ match x {
+ nothing => { error!("A"); }
+ just(_a) => { error!("B"); }
+ }
}
pub fn main() { }
-fn altsimple(f: int) { match f { x => () } }
+fn altsimple(f: int) { match f { _x => () } }
pub fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
enum thing { a, b, c, }
--- /dev/null
+// 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.
+
+fn test1() {
+ // from issue 6338
+ match ((1, ~"a"), (2, ~"b")) {
+ ((1, a), (2, b)) | ((2, b), (1, a)) => {
+ assert_eq!(a, ~"a");
+ assert_eq!(b, ~"b");
+ },
+ _ => fail!(),
+ }
+}
+
+fn test2() {
+ match (1, 2, 3) {
+ (1, a, b) | (2, b, a) => {
+ assert_eq!(a, 2);
+ assert_eq!(b, 3);
+ },
+ _ => fail!(),
+ }
+}
+
+fn test3() {
+ match (1, 2, 3) {
+ (1, ref a, ref b) | (2, ref b, ref a) => {
+ assert_eq!(*a, 2);
+ assert_eq!(*b, 3);
+ },
+ _ => fail!(),
+ }
+}
+
+fn test4() {
+ match (1, 2, 3) {
+ (1, a, b) | (2, b, a) if a == 2 => {
+ assert_eq!(a, 2);
+ assert_eq!(b, 3);
+ },
+ _ => fail!(),
+ }
+}
+
+fn test5() {
+ match (1, 2, 3) {
+ (1, ref a, ref b) | (2, ref b, ref a) if *a == 2 => {
+ assert_eq!(*a, 2);
+ assert_eq!(*b, 3);
+ },
+ _ => fail!(),
+ }
+}
+
+fn main() {
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+}
// sometimes we have had trouble finding
// the right type for f, as we unified
// bot and u32 here
- let f = match uint::from_str(~"1234") {
+ let f = match uint::from_str("1234") {
None => return (),
Some(num) => num as u32
};
pub fn f() -> ~[int] { vec::from_elem(1u, 0) }
}
-pub fn main() { let x = m::f(); }
+pub fn main() { let _x = m::f(); }
pub fn main() {
let x = m::S { x: 1, y: 2 };
- let m::S { x: a, y: b } = x;
+ let m::S { x: _a, y: _b } = x;
}
}
fn transform(x: Option<int>) -> Option<~str> {
- x.bind(|n| Some(*n + 1) ).bind(|n| Some(int::to_str(*n)) )
+ x.bind(|n| Some(*n + 1) ).bind(|n| Some(n.to_str()) )
}
pub fn main() {
assert_eq!(transform(Some(10)), Some(~"11"));
assert_eq!(transform(None), None);
assert!((~[~"hi"])
- .bind(|x| ~[x.clone(), *x + ~"!"] )
- .bind(|x| ~[x.clone(), *x + ~"?"] ) ==
+ .bind(|x| ~[x.clone(), *x + "!"] )
+ .bind(|x| ~[x.clone(), *x + "?"] ) ==
~[~"hi", ~"hi?", ~"hi!", ~"hi!?"]);
}
pub fn main() {
let x = @Triple{x: 1, y: 2, z: 3};
- for i in range(0u, 10000u) {
+ for _i in range(0u, 10000u) {
assert_eq!(test(true, x), 2);
}
assert_eq!(test(false, x), 5);
// except according to those terms.
// Issue #922
-fn f2(thing: @fn()) { }
+fn f2(_thing: @fn()) { }
fn f(thing: @fn()) {
f2(thing);
-use std::str;
-
struct StringBuffer {
s: ~str
}
sb.append("World!");
let str = to_str(sb);
assert_eq!(str, ~"Hello, World!");
-}
\ No newline at end of file
+}
// except according to those terms.
pub fn main() {
- let x: &mut [int] = &mut [ 1, 2, 3 ];
+ let _x: &mut [int] = &mut [ 1, 2, 3 ];
}
// -*- rust -*-
extern mod extra;
-use std::vec;
-
fn grow(v: &mut ~[int]) {
v.push(1);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_mut)];
struct Pair { a: int, b: int}
pub fn main() {
// This just tests whether the vec leaks its members.
- let mut pvec: ~[@Pair] =
+ let mut _pvec: ~[@Pair] =
~[@Pair{a: 1, b: 2}, @Pair{a: 3, b: 4}, @Pair{a: 5, b: 6}];
}
fn foo() {
match Some::<int>(5) {
- Some::<int>(x) => {
+ Some::<int>(_x) => {
let mut bar;
match None::<int> { None::<int> => { bar = 5; } _ => { baz(); } }
info!(bar);
fn nested(o: t) {
match o {
- bar(i, Some::<int>(_)) => { error!("wrong pattern matched"); fail!(); }
- _ => { error!("succeeded"); }
+ bar(_i, Some::<int>(_)) => { error!("wrong pattern matched"); fail!(); }
+ _ => { error!("succeeded"); }
}
}
pub fn main() {
match A {a: 10, b: @20} {
x@A {a, b: @20} => { assert!(x.a == 10); assert!(a == 10); }
- A {b, _} => { fail!(); }
+ A {b: _b, _} => { fail!(); }
}
let mut x@B {b, _} = B {a: 10, b: C {c: 20}};
x.b.c = 30;
// except according to those terms.
pub fn main() {
- let x: @mut [int] = @mut [ 1, 2, 3 ];
+ let _x: @mut [int] = @mut [ 1, 2, 3 ];
}
fn f(i: int, f: &fn(int) -> int) -> int { f(i) }
-fn g(g: &fn()) { }
+fn g(_g: &fn()) { }
fn ff() -> @fn(int) -> int {
return |x| x + 1;
fn main() {
let y = @mut 32;
{
- let x = Foo(y);
+ let _x = Foo(y);
}
assert_eq!(*y, 23);
}
pub struct Fd(c_int);
impl Drop for Fd {
+ #[fixed_stack_segment] #[inline(never)]
fn drop(&self) {
unsafe {
libc::close(**self);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::str;
-
pub fn main() {
let thing = ~"{{ f }}";
- let f = thing.find_str(~"{{");
+ let f = thing.find_str("{{");
if f.is_none() {
- println(~"None!");
+ println("None!");
}
}
impl Drop for dtor {
fn drop(&self) {
// abuse access to shared mutable state to write this code
- unsafe {
- *self.x -= 1;
- }
+ *self.x -= 1;
}
}
{
let b = Some(dtor { x:x });
- let c = unwrap(b);
+ let _c = unwrap(b);
}
assert_eq!(*x, 0);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+
struct A { a: int, b: int }
struct Abox { a: @int, b: @int }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-
+#[allow(unreachable_code)];
// -*- rust -*-
fn dont_call_me() { fail!(); info!(1); }
mod foo {
- pub fn bar(offset: uint) { }
+ pub fn bar(_offset: uint) { }
}
pub fn main() { foo::bar(0u); }
match Some(src) {
Some(src_id) => {
- for i in range(0u, 10u) {
+ for _i in range(0u, 10u) {
let yyy = src_id;
assert_eq!(yyy, 0u);
}
pub fn main() {
let f = |(x, _): (int, int)| println((x + 1).to_str());
- let g = |Foo { x: x, y: y }: Foo| println((x + 1).to_str());
+ let g = |Foo { x: x, y: _y }: Foo| println((x + 1).to_str());
f((2, 3));
g(Foo { x: 1, y: 2 });
}
// this checks that a pred with a non-bool return
// type is rejected, even if the pred is never used
-fn bad(a: int) -> int { return 37; } //~ ERROR Non-boolean return type
+fn bad(_a: int) -> int { return 37; } //~ ERROR Non-boolean return type
pub fn main() { }
}
}
+#[fixed_stack_segment] #[inline(never)]
fn main() {
unsafe {
a::free(transmute(0));
use pub_use_xcrate2::Foo;
pub fn main() {
- let foo: Foo = Foo {
+ let _foo: Foo = Foo {
name: 0
};
}
// xfail-fast
// aux-build:pub_use_mods_xcrate.rs
+#[allow(unused_imports)];
+
extern mod pub_use_mods_xcrate;
use pub_use_mods_xcrate::a::c;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::vec;
-
trait sum {
fn sum_(self) -> int;
}
info!("y==%d", y);
assert_eq!(y, 6);
- let mut x = ~[1, 2, 3];
+ let x = ~[1, 2, 3];
let y = x.sum_();
info!("y==%d", y);
assert_eq!(y, 6);
}
fn visit_int(&self) -> bool {
do self.get::<int>() |i| {
- self.vals.push(int::to_str(i));
+ self.vals.push(i.to_str());
};
true
}
&foo.v3[i]
}
-fn get_v4<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v4<'v>(a: &'v A, _i: uint) -> &'v int {
let foo = &a.value;
&foo.v4.f
}
-fn get_v5<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v5<'v>(a: &'v A, _i: uint) -> &'v int {
let foo = &a.value;
&foo.v5.f
}
-fn get_v6_a<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v6_a<'v>(a: &'v A, _i: uint) -> &'v int {
match a.value.v6 {
Some(ref v) => &v.f,
None => fail!()
}
}
-fn get_v6_b<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v6_b<'v>(a: &'v A, _i: uint) -> &'v int {
match *a {
A { value: B { v6: Some(ref v), _ } } => &v.f,
_ => fail!()
}
}
-fn get_v6_c<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v6_c<'v>(a: &'v A, _i: uint) -> &'v int {
match a {
&A { value: B { v6: Some(ref v), _ } } => &v.f,
_ => fail!()
}
}
-fn get_v5_ref<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v5_ref<'v>(a: &'v A, _i: uint) -> &'v int {
match &a.value {
&B {v5: ~C {f: ref v}, _} => v
}
x = @5;
y = @6;
assert_eq!(*a, exp);
+ assert_eq!(x, @5);
+ assert_eq!(y, @6);
}
pub fn main() {
fn produce_static<T>() -> &'static T { fail!(); }
-fn foo<T>(x: &T) -> &uint { produce_static() }
+fn foo<T>(_x: &T) -> &uint { produce_static() }
pub fn main() {
}
add(&'self ast<'self>, &'self ast<'self>)
}
-fn mk_add_ok<'a>(x: &'a ast<'a>, y: &'a ast<'a>, z: &ast) -> ast<'a> {
+fn mk_add_ok<'a>(x: &'a ast<'a>, y: &'a ast<'a>, _z: &ast) -> ast<'a> {
add(x, y)
}
// Issue #2263.
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+
// Should pass region checking.
fn ok(f: @fn(x: &uint)) {
// Here, g is a function that can accept a uint pointer with
x: int
}
+#[fixed_stack_segment] #[inline(never)]
fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
unsafe {
cast::transmute(libc::malloc(sys::size_of::<Bcx<'blk>>()
return alloc(bcx.fcx.arena);
}
+#[fixed_stack_segment] #[inline(never)]
fn g(fcx : &Fcx) {
let bcx = Bcx { fcx: fcx };
let bcx2 = h(&bcx);
--- /dev/null
+// 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.
+
+static FOO: [int, ..4] = [32, ..4];
+static BAR: [int, ..4] = [32, 32, 32, 32];
+
+pub fn main() {
+ assert_eq!(FOO, BAR);
+}
#[unsafe_destructor]
impl Drop for r {
fn drop(&self) {
- unsafe {
- *(self.i) += 1;
- }
+ *(self.i) += 1;
}
}
impl Drop for r {
fn drop(&self) {
unsafe {
- let v2: ~int = cast::transmute(self.v.c);
+ let _v2: ~int = cast::transmute(self.v.c);
}
}
}
#[unsafe_destructor]
impl Drop for shrinky_pointer {
fn drop(&self) {
- unsafe {
- error!(~"Hello!"); **(self.i) -= 1;
- }
+ error!(~"Hello!"); **(self.i) -= 1;
}
}
#[unsafe_destructor]
impl Drop for close_res {
fn drop(&self) {
- unsafe {
- *(self.i) = false;
- }
+ *(self.i) = false;
}
}
enum option<T> { none, some(T), }
-fn sink(res: option<close_res>) { }
+fn sink(_res: option<close_res>) { }
pub fn main() {
let c = @mut true;
fn f() { let x: () = (); return x; }
-pub fn main() { let x = f(); }
+pub fn main() { let _x = f(); }
task::spawn(|| die() );
let (p, c) = comm::stream::<()>();
loop {
- // Sending and receiving here because these actions yield,
+ // Sending and receiving here because these actions deschedule,
// at which point our child can kill us.
c.send(());
p.recv();
// The above comment no longer makes sense but I'm
// reluctant to remove a linked failure test case.
- task::yield();
+ task::deschedule();
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
use std::task;
struct test {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
-
// tests that ctrl's type gets inferred properly
struct Command<K, V> {
key: K,
}
fn cache_server<K:Send,V:Send>(c: Chan<Chan<Command<K, V>>>) {
- let (ctrl_port, ctrl_chan) = stream();
+ let (_ctrl_port, ctrl_chan) = stream();
c.send(ctrl_chan);
}
pub fn main() { }
match none::<int> {
some::<int>(_) => {
- for i in c.iter() {
+ for _i in c.iter() {
info!(a);
let a = 17;
b.push(a);
fn uhoh<T>(v: ~[clam<T>]) {
match v[1] {
- a::<T>(ref t, ref u) => { info!("incorrect"); info!(u); fail!(); }
+ a::<T>(ref _t, ref u) => { info!("incorrect"); info!(u); fail!(); }
b::<T> => { info!("correct"); }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test - FIXME(#8538) some kind of problem linking induced by extern "C" fns that I do not understand
// xfail-fast - windows doesn't like this
// Smallest hello world with no runtime
task::spawn(|| x(~"hello from second spawned fn", 66) );
task::spawn(|| x(~"hello from third spawned fn", 67) );
let mut i: int = 30;
- while i > 0 { i = i - 1; info!("parent sleeping"); task::yield(); }
+ while i > 0 { i = i - 1; info!("parent sleeping"); task::deschedule(); }
}
Arnold.
*/
-use std::comm::*;
use std::task;
type ctx = Chan<int>;
-fn iotask(cx: &ctx, ip: ~str) {
+fn iotask(_cx: &ctx, ip: ~str) {
assert_eq!(ip, ~"localhost");
}
pub fn main() {
- let (p, ch) = stream::<int>();
+ let (_p, ch) = stream::<int>();
task::spawn(|| iotask(&ch, ~"localhost") );
}
use std::io::WriterUtil;
use std::io;
use std::os;
-use std::uint;
pub fn main() {
let dir = tempfile::mkdtemp(&Path("."), "").unwrap();
// xfail-fast
use std::uint;
-use std::vec;
pub trait plus {
fn plus(&self) -> int;
}
impl uint_utils for uint {
- fn str(&self) -> ~str { uint::to_str(*self) }
+ fn str(&self) -> ~str { self.to_str() }
fn multi(&self, f: &fn(uint)) {
let mut c = 0u;
while c < *self { f(c); c += 1u; }
*a = 3;
}
+#[fixed_stack_segment] #[inline(never)]
unsafe fn run() {
assert!(debug_static_mut == 3);
debug_static_mut = 4;
// This tests for issue #163
let ff: ~str = ~"abc";
- let a: ~str = ff + ~"ABC" + ff;
- let b: ~str = ~"ABC" + ff + ~"ABC";
+ let a: ~str = ff + "ABC" + ff;
+ let b: ~str = ~"ABC" + ff + "ABC";
info!(a.clone());
info!(b.clone());
assert_eq!(a, ~"abcABCabc");
extern mod extra;
-use std::str;
-
pub fn main() {
// Make sure we properly handle repeated self-appends.
let mut a: ~str = ~"A";
}
pub fn main() {
- let x = Bar { a: 2, b: 3 };
+ let _x = Bar { a: 2, b: 3 };
}
--- /dev/null
+struct Foo {
+ new: int,
+}
+
+pub fn main() {
+ let foo = Foo{ new: 3 };
+ assert_eq!(foo.new, 3);
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::str;
-
struct S { f0: ~str, f1: int }
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::str;
-
struct S { f0: ~str, f1: ~str }
pub fn main() {
}
}
+#[fixed_stack_segment] #[inline(never)]
fn test1() {
unsafe {
let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa_u64,
}
#[cfg(target_arch = "x86_64")]
+#[fixed_stack_segment]
+#[inline(never)]
fn test2() {
unsafe {
let f = Floats { a: 1.234567890e-15_f64,
// Issue #5041 - avoid overlapping memcpy when src and dest of a swap are the same
use std::ptr;
-use std::util;
pub fn main() {
let mut test = TestDescAndFn {
}
pub fn main() {
- test(fmt!("hello %d friends and %s things", 10, ~"formatted"),
+ test(fmt!("hello %d friends and %s things", 10, "formatted"),
~"hello 10 friends and formatted things");
test(fmt!("test"), ~"test");
test(fmt!("%i", 2), ~"2");
test(fmt!("%i", -1), ~"-1");
test(fmt!("%u", 10u), ~"10");
- test(fmt!("%s", ~"test"), ~"test");
+ test(fmt!("%s", "test"), ~"test");
test(fmt!("%b", true), ~"true");
test(fmt!("%b", false), ~"false");
test(fmt!("%c", 'A'), ~"A");
test(fmt!("%10d", 500), ~" 500");
test(fmt!("%10d", -500), ~" -500");
test(fmt!("%10u", 500u), ~" 500");
- test(fmt!("%10s", ~"test"), ~" test");
+ test(fmt!("%10s", "test"), ~" test");
test(fmt!("%10b", true), ~" true");
test(fmt!("%10x", 0xff_u), ~" ff");
test(fmt!("%10X", 0xff_u), ~" FF");
test(fmt!("%-10d", 500), ~"500 ");
test(fmt!("%-10d", -500), ~"-500 ");
test(fmt!("%-10u", 500u), ~"500 ");
- test(fmt!("%-10s", ~"test"), ~"test ");
+ test(fmt!("%-10s", "test"), ~"test ");
test(fmt!("%-10b", true), ~"true ");
test(fmt!("%-10x", 0xff_u), ~"ff ");
test(fmt!("%-10X", 0xff_u), ~"FF ");
test(fmt!("%.d", 10), ~"10");
test(fmt!("%.d", -10), ~"-10");
test(fmt!("%.u", 10u), ~"10");
- test(fmt!("%.s", ~"test"), ~"");
+ test(fmt!("%.s", "test"), ~"");
test(fmt!("%.x", 127u), ~"7f");
test(fmt!("%.o", 10u), ~"12");
test(fmt!("%.t", 3u), ~"11");
test(fmt!("%.0d", 10), ~"10");
test(fmt!("%.0d", -10), ~"-10");
test(fmt!("%.0u", 10u), ~"10");
- test(fmt!("%.0s", ~"test"), ~"");
+ test(fmt!("%.0s", "test"), ~"");
test(fmt!("%.0x", 127u), ~"7f");
test(fmt!("%.0o", 10u), ~"12");
test(fmt!("%.0t", 3u), ~"11");
test(fmt!("%.1d", 10), ~"10");
test(fmt!("%.1d", -10), ~"-10");
test(fmt!("%.1u", 10u), ~"10");
- test(fmt!("%.1s", ~"test"), ~"t");
+ test(fmt!("%.1s", "test"), ~"t");
test(fmt!("%.1x", 127u), ~"7f");
test(fmt!("%.1o", 10u), ~"12");
test(fmt!("%.1t", 3u), ~"11");
test(fmt!("%.5d", 10), ~"00010");
test(fmt!("%.5d", -10), ~"-00010");
test(fmt!("%.5u", 10u), ~"00010");
- test(fmt!("%.5s", ~"test"), ~"test");
+ test(fmt!("%.5s", "test"), ~"test");
test(fmt!("%.5x", 127u), ~"0007f");
test(fmt!("%.5o", 10u), ~"00012");
test(fmt!("%.5t", 3u), ~"00011");
test(fmt!("%05f", 5.82), ~"05.82");
// 0-padding a string is undefined but glibc does this:
- test(fmt!("%05s", ~"test"), ~" test");
+ test(fmt!("%05s", "test"), ~" test");
test(fmt!("%05c", 'A'), ~" A");
test(fmt!("%05b", true), ~" true");
// Left-justify overrides 0-padding
test(fmt!("%-05X", 127u), ~"7F ");
test(fmt!("%-05o", 10u), ~"12 ");
test(fmt!("%-05t", 3u), ~"11 ");
- test(fmt!("%-05s", ~"test"), ~"test ");
+ test(fmt!("%-05s", "test"), ~"test ");
test(fmt!("%-05c", 'A'), ~"A ");
test(fmt!("%-05b", true), ~"true ");
test(fmt!("%-05f", 5.82), ~"5.82 ");
test(fmt!("%06.5d", 10), ~" 00010");
test(fmt!("%06.5d", -10), ~"-00010");
test(fmt!("%06.5u", 10u), ~" 00010");
- test(fmt!("%06.5s", ~"test"), ~" test");
+ test(fmt!("%06.5s", "test"), ~" test");
test(fmt!("%06.5c", 'A'), ~" A");
test(fmt!("%06.5x", 127u), ~" 0007f");
test(fmt!("%06.5X", 127u), ~" 0007F");
assert_eq!(concat_idents!(asd, f_f, dsa), ~"<.<");
assert!(stringify!(use_mention_distinction) ==
- ~"use_mention_distinction");
+ "use_mention_distinction");
}
assert_eq!(line!(), 23);
//assert!((col!() == 11));
assert_eq!(indirect_line!(), 25);
- assert!((file!().to_owned().ends_with(~"syntax-extension-source-utils.rs")));
+ assert!((file!().to_owned().ends_with("syntax-extension-source-utils.rs")));
assert_eq!(stringify!((2*3) + 5).to_owned(), ~"( 2 * 3 ) + 5");
assert!(include!("syntax-extension-source-utils-files/includeme.fragment").to_owned()
== ~"victory robot 6");
assert!(
include_str!("syntax-extension-source-utils-files/includeme.fragment").to_owned()
- .starts_with(~"/* this is for "));
+ .starts_with("/* this is for "));
assert!(
include_bin!("syntax-extension-source-utils-files/includeme.fragment")
[1] == (42 as u8)); // '*'
// The Windows tests are wrapped in an extra module for some reason
- assert!((m1::m2::where_am_i().ends_with(~"m1::m2")));
+ assert!((m1::m2::where_am_i().ends_with("m1::m2")));
}
fn foo() {
- fn zed(z: bar) { }
+ fn zed(_z: bar) { }
enum bar { nil, }
fn baz() { zed(nil); }
}
extern mod extra;
use std::comm::Chan;
-use std::comm::Port;
use std::comm;
use std::task;
pub fn main() {
let (p, ch) = comm::stream();
- let child = task::spawn(|| start(&ch) );
+ let _child = task::spawn(|| start(&ch) );
let c = p.recv();
c.send(~"A");
c.send(~"B");
- task::yield();
+ task::deschedule();
}
use std::task;
fn start(c: &comm::Chan<comm::Chan<int>>) {
- let (p, ch) = comm::stream();
+ let (_p, ch) = comm::stream();
c.send(ch);
}
pub fn main() {
let (p, ch) = comm::stream();
- let child = task::spawn(|| start(&ch) );
- let c = p.recv();
+ let _child = task::spawn(|| start(&ch) );
+ let _c = p.recv();
}
pub fn main() { test00(); }
-fn start(task_number: int) { info!("Started / Finished task."); }
+fn start(_task_number: int) { info!("Started / Finished task."); }
fn test00() {
let i: int = 0;
// Sleep long enough for the task to finish.
let mut i = 0;
while i < 10000 {
- task::yield();
+ task::deschedule();
i += 1;
}
pub fn main() {
info!("Check that we don't deadlock.");
- let (p, ch) = comm::stream();
+ let (_p, ch) = comm::stream();
task::try(|| start(&ch, 0, 10) );
info!("Joined task");
}
// Read from spawned tasks...
let mut sum = 0;
- for r in results.iter() {
+ for _r in results.iter() {
i = 0;
while i < number_of_messages {
let value = po.recv();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
use std::comm;
pub fn main() { test00(); }
pub fn main() { test00(); }
fn test00() {
- let r: int = 0;
+ let _r: int = 0;
let mut sum: int = 0;
let (p, c) = comm::stream();
let number_of_messages: int = 1000;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
use std::comm::SharedChan;
use std::comm;
// xfail-fast
+#[allow(dead_assignment)];
+
extern mod extra;
use std::comm;
}
fn supervised() {
- // Yield to make sure the supervisor joins before we
+ // Deschedule to make sure the supervisor joins before we
// fail. This is currently not needed because the supervisor
// runs first, but I can imagine that changing.
error!("supervised task=%?", 0);
- task::yield();
+ task::deschedule();
fail!();
}
use std::task;
fn supervised() {
- // Yield to make sure the supervisor joins before we fail. This is
+ // Deschedule to make sure the supervisor joins before we fail. This is
// currently not needed because the supervisor runs first, but I can
// imagine that changing.
- task::yield();
+ task::deschedule();
fail!();
}
task::spawn(|| child(~"Hello") );
}
-fn child(s: ~str) {
+fn child(_s: ~str) {
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
use std::ptr;
use std::task;
use std::task;
-fn test_break() { loop { let x: @int = break; } }
+fn test_break() { loop { let _x: @int = break; } }
-fn test_cont() { let mut i = 0; while i < 1 { i += 1; let x: @int = loop; } }
+fn test_cont() { let mut i = 0; while i < 1 { i += 1; let _x: @int = loop; } }
-fn test_ret() { let x: @int = return; }
+fn test_ret() { let _x: @int = return; }
fn test_fail() {
- fn f() { let x: @int = fail!(); }
+ fn f() { let _x: @int = fail!(); }
task::try(|| f() );
}
fn test_fail_indirect() {
fn f() -> ! { fail!(); }
- fn g() { let x: @int = f(); }
+ fn g() { let _x: @int = f(); }
task::try(|| g() );
}
assert_eq!(i.g(), 10);
}
-fn welp<T>(i: int, x: &T) -> int {
+fn welp<T>(i: int, _x: &T) -> int {
i.g()
}
use std::int;
trait to_str {
- fn to_str(&self) -> ~str;
+ fn to_string(&self) -> ~str;
}
impl to_str for int {
- fn to_str(&self) -> ~str { int::to_str(*self) }
+ fn to_string(&self) -> ~str { self.to_str() }
}
impl to_str for ~str {
- fn to_str(&self) -> ~str { self.clone() }
+ fn to_string(&self) -> ~str { self.clone() }
}
impl to_str for () {
- fn to_str(&self) -> ~str { ~"()" }
+ fn to_string(&self) -> ~str { ~"()" }
}
trait map<T> {
x.map(|_e| ~"hi" )
}
fn bar<U:to_str,T:map<U>>(x: T) -> ~[~str] {
- x.map(|_e| _e.to_str() )
+ x.map(|_e| _e.to_string() )
}
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::cmp::{Eq, Ord};
+use std::cmp::Eq;
use std::num::NumCast;
pub trait NumExt: Eq + Num + NumCast {}
impl ::base::HasNew<Foo> for Foo {
fn new() -> Foo {
- unsafe { println("Foo"); }
+ println("Foo");
Foo { dummy: () }
}
}
impl ::base::HasNew<Bar> for Bar {
fn new() -> Bar {
- unsafe { io::println("Bar"); }
+ io::println("Bar");
Bar { dummy: () }
}
}
}
pub fn main() {
- let f: base::Foo = base::HasNew::new::<base::Foo, base::Foo>();
- let b: base::Bar = base::HasNew::new::<base::Bar, base::Bar>();
+ let _f: base::Foo = base::HasNew::new::<base::Foo, base::Foo>();
+ let _b: base::Bar = base::HasNew::new::<base::Bar, base::Bar>();
}
// xfail-fast
-#[no_std];
-
-extern mod std;
-
-use std::str::StrVector;
-use std::vec::ImmutableVector;
-use std::iterator::Iterator;
-use std::int;
-
trait to_str {
- fn to_str(&self) -> ~str;
+ fn to_string(&self) -> ~str;
}
impl to_str for int {
- fn to_str(&self) -> ~str { int::to_str(*self) }
+ fn to_string(&self) -> ~str { self.to_str() }
}
impl<T:to_str> to_str for ~[T] {
- fn to_str(&self) -> ~str {
- fmt!("[%s]", self.iter().map(|e| e.to_str()).collect::<~[~str]>().connect(", "))
+ fn to_string(&self) -> ~str {
+ fmt!("[%s]", self.iter().map(|e| e.to_string()).collect::<~[~str]>().connect(", "))
}
}
pub fn main() {
- assert!(1.to_str() == ~"1");
- assert!((~[2, 3, 4]).to_str() == ~"[2, 3, 4]");
+ assert!(1.to_string() == ~"1");
+ assert!((~[2, 3, 4]).to_string() == ~"[2, 3, 4]");
fn indirect<T:to_str>(x: T) -> ~str {
- x.to_str() + ~"!"
+ x.to_string() + "!"
}
assert!(indirect(~[10, 20]) == ~"[10, 20]!");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
trait Foo {
fn foo(&self, mut v: int) { v = 1; }
--- /dev/null
+// 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.
+
+#[deriving(Eq)]
+struct Foo(int);
+#[deriving(Eq)]
+struct Bar(int, int);
+
+fn main() {
+ let f: extern fn(int) -> Foo = Foo;
+ let g: extern fn(int, int) -> Bar = Bar;
+ assert_eq!(f(42), Foo(42));
+ assert_eq!(g(4, 7), Bar(4, 7));
+}
pub mod b {
pub type t = int;
- pub fn foo() { let x: t = 10; }
+ pub fn foo() { let _x: t = 10; }
}
}
// xfail-fast
-fn p_foo<T>(pinned: T) { }
-fn s_foo<T>(shared: T) { }
-fn u_foo<T:Send>(unique: T) { }
+fn p_foo<T>(_pinned: T) { }
+fn s_foo<T>(_shared: T) { }
+fn u_foo<T:Send>(_unique: T) { }
struct r {
i: int,
while lo_ < hi { it(lo_); lo_ += 1u; }
}
-fn create_index<T>(index: ~[S<T>], hash_fn: extern fn(T) -> uint) {
- range_(0u, 256u, |_i| { let bucket: ~[T] = ~[]; } )
+fn create_index<T>(_index: ~[S<T>], _hash_fn: extern fn(T) -> uint) {
+ do range_(0u, 256u) |_i| {
+ let _bucket: ~[T] = ~[];
+ }
}
pub fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
fn f() {
let x = 10; let mut y = 11;
// -*- rust -*-
-pub fn main() { let x: uint = 10 as uint; }
+pub fn main() { let _x: uint = 10 as uint; }
let c = 1;
let c_neg: i32 = -c;
- error!(b_neg);
+ error!(c_neg);
let d = 1;
let d_neg: i64 = -d;
- error!(b_neg);
+ error!(d_neg);
let e = 1;
let e_neg: int = -e;
- error!(b_neg);
+ error!(e_neg);
// intentional overflows
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let i = ~1;
let mut j = ~2;
pub fn main() {
enum t { t1(int), t2(int), }
- let x = ~t1(10);
+ let _x = ~t1(10);
/*alt *x {
t1(a) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_variable)];
+
use std::sys;
pub fn main() {
- unsafe {
- let i = ~@1;
- let j = ~@2;
- let rc1 = sys::refcount(*i);
- let j = i.clone();
- let rc2 = sys::refcount(*i);
- error!("rc1: %u rc2: %u", rc1, rc2);
- assert_eq!(rc1 + 1u, rc2);
- }
+ let i = ~@1;
+ let j = ~@2;
+ let rc1 = sys::refcount(*i);
+ let j = i.clone();
+ let rc2 = sys::refcount(*i);
+ error!("rc1: %u rc2: %u", rc1, rc2);
+ assert_eq!(rc1 + 1u, rc2);
}
let _: ~int;
}
-fn f(i: ~int) -> ~int {
+fn f(_i: ~int) -> ~int {
fail!();
}
// except according to those terms.
pub fn main() {
- let x = ~~[0,0,0,0,0];
+ let _x = ~~[0,0,0,0,0];
}
// except according to those terms.
pub fn main() {
- let i = ~100;
+ let _i = ~100;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_variable)];
+
pub fn main() {
let i = ~100;
let j = ~200;
pub fn main() {
let loop_: ~EventLoop = ~UvEventLoop { uvio: 0 } as ~EventLoop;
- let loop2_ = loop_;
-}
\ No newline at end of file
+ let _loop2_ = loop_;
+}
#[unsafe_destructor]
impl Drop for r {
fn drop(&self) {
- unsafe {
- *(self.i) = *(self.i) + 1;
- }
+ *(self.i) = *(self.i) + 1;
}
}
pub fn main() {
let i = @mut 0;
{
- let j = ~r(i);
+ let _j = ~r(i);
}
assert_eq!(*i, 1);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::comm::*;
-
pub fn main() {
let (p, c) = stream();
c.send(~100);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-
+#[allow(unused_variable)];
+#[allow(dead_assignment)];
// -*- rust -*-
fn f(u: ()) { return u; }
-fn good(a: &int) {
+fn good(_a: &int) {
}
// unnamed argument &int is now parse x: &int
-fn called(f: &fn(&int)) {
+fn called(_f: &fn(&int)) {
}
pub fn main() {
-called(good);
+ called(good);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
fn id(x: bool) -> bool { x }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(path_statement)];
+#[allow(unreachable_code)];
+#[allow(unused_variable)];
fn id(x: bool) -> bool { x }
// except according to those terms.
pub fn main() {
- let x = ~1;
+ let _x = ~1;
let lam_move: @fn() = || {};
lam_move();
}
// Issue Name: Unused move causes a crash
// Abstract: zero-fill to block after drop
+#[allow(path_statement)];
+
pub fn main()
{
let y = ~1;
use std::task;
fn f() {
- let a = @0;
+ let _a = @0;
fail!();
}
}
fn f() {
- let c = complainer(@0);
+ let _c = complainer(@0);
fail!();
}
use std::task;
fn f() {
- let a = ~0;
+ let _a = ~0;
fail!();
}
fn foo<T>(o: myoption<T>) -> int {
let mut x: int = 5;
- match o { none::<T> => { } some::<T>(t) => { x += 1; } }
+ match o {
+ none::<T> => { }
+ some::<T>(_t) => { x += 1; }
+ }
return x;
}
fn foo<T>(o: myoption<T>) -> int {
let mut x: int;
- match o { none::<T> => { fail!(); } some::<T>(t) => { x = 5; } }
+ match o {
+ none::<T> => { fail!(); }
+ some::<T>(_t) => { x = 5; }
+ }
return x;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(unused_imports)];
+
#[no_std];
extern mod std;
extern mod zed(name = "std");
extern mod extra;
use std::str;
-use std::vec;
pub fn main() {
// Chars of 1, 2, 3, and 4 bytes
assert!((str::is_utf8(s.as_bytes())));
// invalid prefix
- assert!((!str::is_utf8(~[0x80_u8])));
+ assert!((!str::is_utf8([0x80_u8])));
// invalid 2 byte prefix
- assert!((!str::is_utf8(~[0xc0_u8])));
- assert!((!str::is_utf8(~[0xc0_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xc0_u8])));
+ assert!((!str::is_utf8([0xc0_u8, 0x10_u8])));
// invalid 3 byte prefix
- assert!((!str::is_utf8(~[0xe0_u8])));
- assert!((!str::is_utf8(~[0xe0_u8, 0x10_u8])));
- assert!((!str::is_utf8(~[0xe0_u8, 0xff_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xe0_u8])));
+ assert!((!str::is_utf8([0xe0_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xe0_u8, 0xff_u8, 0x10_u8])));
// invalid 4 byte prefix
- assert!((!str::is_utf8(~[0xf0_u8])));
- assert!((!str::is_utf8(~[0xf0_u8, 0x10_u8])));
- assert!((!str::is_utf8(~[0xf0_u8, 0xff_u8, 0x10_u8])));
- assert!((!str::is_utf8(~[0xf0_u8, 0xff_u8, 0xff_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xf0_u8])));
+ assert!((!str::is_utf8([0xf0_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xf0_u8, 0xff_u8, 0x10_u8])));
+ assert!((!str::is_utf8([0xf0_u8, 0xff_u8, 0xff_u8, 0x10_u8])));
let mut stack = ~"a×c€";
assert_eq!(stack.pop_char(), '€');
pub fn main() {
// This just tests whether the vec leaks its members.
- let pvec: ~[@Pair] =
+ let _pvec: ~[@Pair] =
~[@Pair{x: 1, y: 2}, @Pair{x: 3, y: 4}, @Pair{x: 5, y: 6}];
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[allow(dead_assignment)];
+
pub fn main() {
let a = ~[1, 2, 3, 4, 5];
let mut b = ~[a.clone(), a.clone()];
assert_eq!(b, 2);
assert!(tail.is_empty());
}
- ([..tail], _) => fail!()
+ ([.._tail], _) => fail!()
}
}
#[unsafe_destructor]
impl Drop for foo {
fn drop(&self) {
- unsafe {
- *self.x += 1;
- }
+ *self.x += 1;
}
}
assert!(tail[1].string == ~"baz");
match tail {
- [Foo { _ }, _, Foo { _ }, ..tail] => {
+ [Foo { _ }, _, Foo { _ }, .. _tail] => {
::std::util::unreachable();
}
[Foo { string: ref a }, Foo { string: ref b }] => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub fn main() { let quux: @~[uint] = @~[]; }
+pub fn main() { let _quux: @~[uint] = @~[]; }
break; }
}
-fn evil_lincoln() { let evil = info!("lincoln"); }
+fn evil_lincoln() { let _evil = info!("lincoln"); }
pub fn main() {
strange();
-pub fn main() { let x: int = 10; while x == 10 && x == 11 { let y = 0xf00; } }
+pub fn main() { let x: int = 10; while x == 10 && x == 11 { let _y = 0xf00; } }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub fn main() {
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+pub fn main() {
let mut y: int = 42;
let mut z: int = 42;
let mut x: int;
info!(i);
i = i + 1;
if i == 95 {
- let v: ~[int] =
+ let _v: ~[int] =
~[1, 2, 3, 4, 5]; // we check that it is freed by break
info!("breaking");
pub type LPVOID = uint;
pub type BOOL = u8;
+#[cfg(target_os = "win32")]
mod kernel32 {
use super::{HANDLE, DWORD, SIZE_T, LPVOID, BOOL};
- #[cfg(target_os = "win32")]
#[abi = "stdcall"]
extern "stdcall" {
pub fn GetProcessHeap() -> HANDLE;
#[cfg(target_os = "win32")]
+#[fixed_stack_segment]
pub fn main() {
let heap = unsafe { kernel32::GetProcessHeap() };
let mem = unsafe { kernel32::HeapAlloc(heap, 0u32, 100u32) };
--- /dev/null
+// 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.
+
+// xfail-fast
+// aux-build:xc_conditions.rs
+
+extern mod xc_conditions;
+use xc_conditions::oops;
+use xc_conditions::trouble;
+
+// Tests of cross-crate conditions; the condition is
+// defined in lib, and we test various combinations
+// of `trap` and `raise` in the client or the lib where
+// the condition was defined. Also in test #4 we use
+// more complex features (generics, traits) in
+// combination with the condition.
+//
+// trap raise
+// ------------
+// xc_conditions : client lib
+// xc_conditions_2: client client
+// xc_conditions_3: lib client
+// xc_conditions_4: client client (with traits)
+//
+// the trap=lib, raise=lib case isn't tested since
+// there's no cross-crate-ness to test in that case.
+
+pub fn main() {
+ do oops::cond.trap(|_i| 12345).inside {
+ let x = trouble();
+ assert_eq!(x,12345);
+ }
+}
\ No newline at end of file
--- /dev/null
+// 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.
+
+// xfail-fast
+// aux-build:xc_conditions_2.rs
+
+extern mod xc_conditions_2;
+use xcc = xc_conditions_2;
+
+pub fn main() {
+ do xcc::oops::cond.trap(|_| 1).inside {
+ xcc::oops::cond.raise(1);
+ }
+}
--- /dev/null
+// 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.
+
+// xfail-fast
+// aux-build:xc_conditions_3.rs
+
+extern mod xc_conditions_3;
+use xcc = xc_conditions_3;
+
+pub fn main() {
+ assert_eq!(xcc::guard(a, 1), 40);
+}
+
+pub fn a() -> int {
+ assert_eq!(xcc::oops::cond.raise(7), 7);
+ xcc::guard(b, 2)
+}
+
+pub fn b() -> int {
+ assert_eq!(xcc::oops::cond.raise(8), 16);
+ xcc::guard(c, 3)
+}
+
+pub fn c() -> int {
+ assert_eq!(xcc::oops::cond.raise(9), 27);
+ xcc::guard(d, 4)
+}
+
+pub fn d() -> int {
+ xcc::oops::cond.raise(10)
+}
--- /dev/null
+// 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.
+
+// xfail-fast
+// aux-build:xc_conditions_4.rs
+
+extern mod xc_conditions_4;
+use xcc = xc_conditions_4;
+
+struct SThunk {
+ x: int
+}
+
+impl xcc::Thunk<xcc::Color> for SThunk {
+ fn call(self) -> xcc::Color {
+ xcc::oops::cond.raise((self.x, 1.23, ~"oh no"))
+ }
+}
+
+pub fn main() {
+ do xcc::oops::cond.trap(|_| xcc::Red).inside {
+ let t = SThunk { x : 10 };
+ assert_eq!(xcc::callback(t), xcc::Red)
+ }
+}
\ No newline at end of file
// xfail-fast
extern mod xcrate_unit_struct;
-use std::util;
-
static s1: xcrate_unit_struct::Struct = xcrate_unit_struct::Struct;
static s2: xcrate_unit_struct::Unit = xcrate_unit_struct::Unit;
static s3: xcrate_unit_struct::Unit =
builder.future_result(|r| { result = Some(r); });
builder.spawn(child);
error!("1");
- task::yield();
+ task::deschedule();
error!("2");
- task::yield();
+ task::deschedule();
error!("3");
result.unwrap().recv();
}
fn child() {
- error!("4"); task::yield(); error!("5"); task::yield(); error!("6");
+ error!("4"); task::deschedule(); error!("5"); task::deschedule(); error!("6");
}
builder.future_result(|r| { result = Some(r); });
builder.spawn(child);
error!("1");
- task::yield();
+ task::deschedule();
result.unwrap().recv();
}
pub fn main() {
let mut i: int = 0;
- while i < 100 { i = i + 1; error!(i); task::yield(); }
+ while i < 100 { i = i + 1; error!(i); task::deschedule(); }
}
+++ /dev/null
-// 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.
-
-// In this case, the code should compile and should
-// succeed at runtime
-
-use std::vec;
-
-fn enum_chars(start: u8, end: u8) -> ~[char] {
- assert!(start < end);
- let mut i = start;
- let mut r = ~[];
- while i <= end { r.push(i as char); i += 1u as u8; }
- return r;
-}
-
-fn enum_uints(start: uint, end: uint) -> ~[uint] {
- assert!(start < end);
- let mut i = start;
- let mut r = ~[];
- while i <= end { r.push(i); i += 1u; }
- return r;
-}
-
-pub fn main() {
- let a = 'a' as u8;
- let j = 'j' as u8;
- let k = 1u;
- let l = 10u;
- let chars = enum_chars(a, j);
- let ints = enum_uints(k, l);
-
- let ps = vec::zip(chars, ints);
-
- assert_eq!(ps.head(), &('a', 1u));
- assert_eq!(ps.last(), &(j as char, 10u));
-}