diff --git a/.gitignore b/.gitignore index 4f7a0df549..482a026d21 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +bin/* stage/* diff --git a/Makefile b/Makefile index bdd60e3b0d..436c213537 100644 --- a/Makefile +++ b/Makefile @@ -2,25 +2,33 @@ GITBOOK = gitbook RUSTC = rustc QUIET = -A unused-variable -A dead-code -A dead-assignment -A experimental RUSTC_NT = $(RUSTC) --no-trans --test $(QUIET) -WHITELIST = examples/borrow/freeze.rs \ - examples/attribute/custom.rs \ - examples/crates/executable.rs \ - examples/lifetime/lifetime.rs \ - examples/lifetime/reference-bad.rs \ - examples/mod/nested.rs \ - examples/move/assignment.rs \ - examples/move/pass-by-value.rs \ - examples/variables/declare.rs \ - examples/variables/variables.rs +WHITELIST = examples/attribute/cfg/custom/custom.rs \ + examples/borrow/borrow.rs \ + examples/borrow/freeze/freeze.rs \ + examples/borrow/mut/mut.rs \ + examples/bounds/bounds.rs \ + examples/constants/constants.rs \ + examples/crates/link/executable.rs \ + examples/lifetime/lifetime.rs \ + examples/mod/mod.rs \ + examples/print/print.rs \ + examples/type/cast/cast.rs \ + examples/type/type.rs \ + examples/variables/declare/declare.rs \ + examples/variables/mut/mut.rs \ + examples/variables/scope/scope.rs \ + examples/vec/vec.rs \ + temporary-whitelist-below-this-point-remove-later \ + examples/lifetime/reference-bad.rs + srcs = $(filter-out $(WHITELIST),$(shell find examples -name '*.rs')) .PHONY: all book clean test serve all: ./setup-stage.sh - $(RUSTC) src/update.rs - ./update - rm update + $(RUSTC) src/update.rs --out-dir bin + bin/update book: cd stage && $(GITBOOK) build @@ -28,7 +36,7 @@ book: ./add-relinks.sh clean: - rm -rf stage + rm -rf {bin,stage} test: $(foreach src,$(srcs),$(RUSTC_NT) $(src) || exit;) diff --git a/examples/array/array.rs b/examples/array/array.rs index 0db044e5cd..03160baaa3 100644 --- a/examples/array/array.rs +++ b/examples/array/array.rs @@ -1,4 +1,4 @@ -use std::mem::size_of_val; +use std::mem; // This function borrows a slice fn analyze_slice(slice: &[int]) { @@ -7,27 +7,27 @@ fn analyze_slice(slice: &[int]) { } fn main() { - // fixed-size array (type signature is superfluous) + // Fixed-size array (type signature is superfluous) let xs: [int, ..5] = [1, 2, 3, 4, 5]; - // indexing starts at 0 + // Indexing starts at 0 println!("first element of the array: {}", xs[0]); println!("second element of the array: {}", xs[1]); - // len() returns the size of the array + // `len` returns the size of the array println!("array size: {}", xs.len()); - // arrays are stack allocated - println!("array occupies {} bytes", size_of_val(&xs)); + // Arrays are stack allocated + println!("array occupies {} bytes", mem::size_of_val(&xs)); - // arrays can be automatically borrowed as slices + // Arrays can be automatically borrowed as slices println!("borrow the whole array as a slice"); analyze_slice(xs); - // slices can point to a section of an array + // Slices can point to a section of an array println!("borrow a section of the array as a slice"); analyze_slice(xs.slice(1, 4)); - // out of bound indexing yields a runtime failure + // Out of bound indexing yields a task failure println!("{}", xs[5]); } diff --git a/examples/attribute/conditional.rs b/examples/attribute/cfg/cfg.rs similarity index 63% rename from examples/attribute/conditional.rs rename to examples/attribute/cfg/cfg.rs index 6f941f1967..95dd647bfa 100644 --- a/examples/attribute/conditional.rs +++ b/examples/attribute/cfg/cfg.rs @@ -1,10 +1,10 @@ -// this function only gets compiled if the target OS is linux +// This function only gets compiled if the target OS is linux #[cfg(target_os = "linux")] fn are_you_on_linux() { println!("You are running linux!") } -// this function only gets compiled if the target OS is *not* linux +// And this function only gets compiled if the target OS is *not* linux #[cfg(not(target_os = "linux"))] fn are_you_on_linux() { println!("You are *not* running linux!") diff --git a/examples/attribute/custom.rs b/examples/attribute/cfg/custom/custom.rs similarity index 100% rename from examples/attribute/custom.rs rename to examples/attribute/cfg/custom/custom.rs diff --git a/examples/attribute/cfg/custom/input.md b/examples/attribute/cfg/custom/input.md new file mode 100644 index 0000000000..75b04dd853 --- /dev/null +++ b/examples/attribute/cfg/custom/input.md @@ -0,0 +1,15 @@ +Some conditionals like `target_os` are implicitly provided by `rustc`, but +custom conditionals must be passed to `rustc` using the `--cfg` flag. + +{custom.rs} + +Without the custom `cfg` flag: + +{custom.out} + +With the custom `cfg` flag: + +``` +$ rustc --cfg some_condition custom.rs && ./custom +condition met! +``` diff --git a/examples/attribute/cfg/input.md b/examples/attribute/cfg/input.md new file mode 100644 index 0000000000..1d473f39f4 --- /dev/null +++ b/examples/attribute/cfg/input.md @@ -0,0 +1,3 @@ +The `cfg` attribute can be use to achieve conditional compilation. + +{cfg.play} diff --git a/examples/attribute/crate/input.md b/examples/attribute/crate/input.md new file mode 100644 index 0000000000..f613b8cc98 --- /dev/null +++ b/examples/attribute/crate/input.md @@ -0,0 +1,14 @@ +The `crate_type` attribute can be used to tell the compiler whether a crate is +a binary or a library (and even which type of library). And the `crate_id` +attribute can be used to set the name and the version of the crate. + +{lib.rs} + +When the `crate_type` attribute is used, we no longer need to pass the +`--crate-type` flag to `rustc`. + +``` +$ rustc lib.rs +$ ls lib* +liberty-a1e7dc98-0.1.rlib +``` diff --git a/examples/attribute/crate/lib.rs b/examples/attribute/crate/lib.rs new file mode 100644 index 0000000000..85cd0a356d --- /dev/null +++ b/examples/attribute/crate/lib.rs @@ -0,0 +1,18 @@ +// This crate is a library +#![crate_type = "lib"] +// The library is named "erty", and its version is 0.1 +#![crate_id = "erty#0.1"] + +pub fn public_function() { + println!("called erty's `public_function()`"); +} + +fn private_function() { + println!("called erty's `private_function()`"); +} + +pub fn indirect_access() { + print!("called erty's `indirect_access()`, that\n> "); + + private_function(); +} diff --git a/examples/attribute/input.md b/examples/attribute/input.md index dc1443b221..55d9930a6c 100644 --- a/examples/attribute/input.md +++ b/examples/attribute/input.md @@ -1,48 +1,22 @@ An attribute is metadata applied to some module, crate or item. This metadata can be used to/for: -* conditional compilation of code + +* [conditional compilation of code](/attribute/cfg.html) +* [set crate name, version and type (binary or library)](/attribute/crate.html) * disable lints (warnings) * enable compiler features (macros, glob imports, etc.) * link to a foreign library * mark functions as unit tests * mark functions that will be part of a benchmark -* select crate type -* set library name and version +* set name and version of a crate When attributes apply to a whole crate, their syntax is `#![crate_attribute]`, and when they apply to a module or item, the syntax is `#[item_attribute]` -(notice the missing bang `!`). Some attributes can take key-value arguments -like `#[attribute(key = "value")]`, or string arguments like -`#[attribute = "value"]`. +(notice the missing bang `!`). -Let's add metadata to the library we created in the previous chapter. +Attributes can take arguments with different syntaxes: -{lib.rs} - -``` -# we don't need the --crate-type flag this time -$ rustc lib.rs -$ ls lib* -liberty-a1e7dc98-0.1.rlib -``` - -Here's an example of conditional compilation. - -{conditional.rs} - -{conditional.out} - -Some conditionals like `target_os` are implicitly provided by `rustc`, but -custom conditionals must be passed to `rustc` using the `--cfg` flag. - -{custom.rs} - -{custom.out} - -``` -$ rustc --cfg some_condition custom.rs && ./custom -condition met! -``` - -More usages of attributes will be covered in other chapters. +* `#[attribute = "value"]` +* `#[attribute(key = "value")]` +* `#[attribute(value)]` diff --git a/examples/attribute/lib.rs b/examples/attribute/lib.rs deleted file mode 100644 index d8a62f19c8..0000000000 --- a/examples/attribute/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -// this crate is a library -#![crate_type = "lib"] -// the library is named "erty", and its version is 0.1 -#![crate_id = "erty#0.1"] - -pub fn public_function() { - println!("called erty's public_function()"); -} - -fn private_function() { - println!("called erty's private_function()"); -} - -pub fn indirect_access() { - print!("called erty's indirect_access(), that\n> "); - - private_function(); -} diff --git a/examples/borrow/alias/alias.rs b/examples/borrow/alias/alias.rs new file mode 100644 index 0000000000..1f9b47deb2 --- /dev/null +++ b/examples/borrow/alias/alias.rs @@ -0,0 +1,43 @@ +struct Point { x: int, y: int, z: int } + +fn main() { + let mut point = Point { x: 0, y: 0, z: 0 }; + + { + let borrowed_point = &point; + let another_borrow = &point; + + // Data can be accessed via the references and the original owner + println!("Point has coordinates: ({}, {}, {})", + borrowed_point.x, another_borrow.y, point.z); + + // Error! Can't borrow point as mutable because it's also borrowed as + // immutable + //let mutable_borrow = &mut point; + // TODO ^ Try uncommenting this line + + // Immutable references go out of scope + } + + { + let mutable_borrow = &mut point; + + // Change data via mutable reference + mutable_borrow.x = 5; + + // Error! Can't borrow `point` as immutable because it's also borrowed + // as mutable + //let y = &point.y; + // TODO ^ Try uncommenting this line + + // Error! Can't print, because println! takes an immutable reference + //println!("Point Z coordinate is {}", point.z); + // TODO ^ Try uncommenting this line + + // Mutable reference goes out of scope + } + + // Immutable references to point are allowed again + println!("Point now has coordinates: ({}, {}, {})", + point.x, point.y, point.z); +} diff --git a/examples/borrow/alias/input.md b/examples/borrow/alias/input.md new file mode 100644 index 0000000000..3a93626933 --- /dev/null +++ b/examples/borrow/alias/input.md @@ -0,0 +1,6 @@ +Data can be immutably borrowed any number of times, but once immutably +borrowed, the original data can't be mutably borrowed. On the other side, data +can be mutably borrowed *once*, and until the mutable reference goes out of +scope, the original data can't be borrowed again. + +{alias.play} diff --git a/examples/borrow/borrow.rs b/examples/borrow/borrow.rs index fa74d7d0b1..57bbcb8531 100644 --- a/examples/borrow/borrow.rs +++ b/examples/borrow/borrow.rs @@ -1,22 +1,35 @@ -use std::owned::Box; - -// this function takes ownership of the box +// This function takes ownership of the box fn eat_box(boxed_int: Box) { - // the box gets destroyed in this scope + println!("destroying box that contains {}", boxed_int); } -// this function borrows the box +// This function borrows the box fn peep_inside_box(borrowed_box: &Box) { println!("This box contains {}", borrowed_box); } fn main() { - // boxed integer + // A boxed integer let boxed_int = box 5; - // borrow the box, ownership is not taken + // Borrow the box, ownership is not taken + peep_inside_box(&boxed_int); + + // The box can be borrowed again peep_inside_box(&boxed_int); - // give up ownership of the box + { + // Take a reference to the data contained inside the box + let _ref_to_int: &int = &*boxed_int; + + // Error! Can't destroy boxed_int, while the inner value has been + // borrowed + eat_box(boxed_int); + // FIXME ^ Comment out this line + + // `_ref_to_int` goes out of scope + } + + // Give up ownership of the box eat_box(boxed_int); } diff --git a/examples/borrow/freeze.rs b/examples/borrow/freeze.rs deleted file mode 100644 index 32bc2fb3ef..0000000000 --- a/examples/borrow/freeze.rs +++ /dev/null @@ -1,16 +0,0 @@ -fn main() { - let mut integer = 5; - - if true { - // borrow integer - let ref_to_integer = &integer; - - // Error: integer is frozen - integer = 4; - - // ref_to_integer goes out of scope - } - - // Ok: integer is not borrowed in this scope - integer = 4; -} diff --git a/examples/borrow/freeze/freeze.rs b/examples/borrow/freeze/freeze.rs new file mode 100644 index 0000000000..959a504049 --- /dev/null +++ b/examples/borrow/freeze/freeze.rs @@ -0,0 +1,17 @@ +fn main() { + let mut _integer = 5; + + { + // Borrow `integer` + let _ref_to_integer = &_integer; + + // Error! `integer` is frozen in this scope + _integer = 4; + // FIXME ^ Comment out this line + + // `ref_to_integer` goes out of scope + } + + // Ok! `integer` is not frozen in this scope + _integer = 4; +} diff --git a/examples/borrow/freeze/input.md b/examples/borrow/freeze/input.md new file mode 100644 index 0000000000..ca10763179 --- /dev/null +++ b/examples/borrow/freeze/input.md @@ -0,0 +1,4 @@ +When data is borrowed, it also *freezes*. *Frozen* data can't be modified via +the original object, until all the references to it go out of scope. + +{freeze.play} diff --git a/examples/borrow/input.md b/examples/borrow/input.md index 5a6cc67178..2c73707a51 100644 --- a/examples/borrow/input.md +++ b/examples/borrow/input.md @@ -1,39 +1,9 @@ Most of times, we'll like to access some data, without taking ownership over it. To accomplish this, Rust provides a *borrowing* mechanism. Instead of -passing objects by-value (`T`), objects can be passed by reference (`&T`). The -compiler statically guarantees that references *always* point to valid objects, -via its borrow checker. +passing objects by-value (`T`), objects can be passed by reference (`&T`). {borrow.play} -`&T` borrows the data via an immutable reference, and the borrower can read the -data but not modify it. Mutable data can be immutably borrowed, but can also be -mutably borrowed via a mutable reference `&mut T`, giving read/write access to -the borrower. - -{mut.rs} - -{mut.out} - -When data is borrowed, it also *freezes*. "Frozen" data can't be modified via -the original object, until all the references to it go out of scope. - -{freeze.rs} - -{freeze.out} - -Data can be immutably borrowed any number of times, but once immutably -borrowed, the original data can't be mutably borrowed. On the other side, data -can be mutably borrowed *once*, and until the mutable reference goes out of -scope, the original data can't be borrowed again. - -{re-borrow.rs} - -{re-borrow.out} - -When doing pattern matching or destructuring via the `let` binding, the `ref` -keyword can be used to take references to the fields of a struct. - -{ref.rs} - -{ref.out} +The compiler statically guarantees that references *always* point to valid +objects, via its borrow checker. For example, the original object can't be +destroyed, while references to it exists. diff --git a/examples/borrow/mut/input.md b/examples/borrow/mut/input.md new file mode 100644 index 0000000000..c3370d6832 --- /dev/null +++ b/examples/borrow/mut/input.md @@ -0,0 +1,5 @@ +`&T` borrows the data via an immutable reference, and the borrower can read the +data but not modify it. Mutable data can be mutably borrowed via a mutable +reference `&mut T`, giving read/write access to the borrower. + +{mut.play} diff --git a/examples/borrow/mut.rs b/examples/borrow/mut/mut.rs similarity index 54% rename from examples/borrow/mut.rs rename to examples/borrow/mut/mut.rs index f60dfedfef..b0bf0c7d38 100644 --- a/examples/borrow/mut.rs +++ b/examples/borrow/mut/mut.rs @@ -1,3 +1,4 @@ +#[allow(dead_code)] struct Book { // `&'static str` is a reference to a string allocated in read only memory author: &'static str, @@ -5,41 +6,39 @@ struct Book { year: uint, } -// this function takes a reference to a book +// This function takes a reference to a book fn borrow_book(book: &Book) { println!("I borrowed {} {} edition", book.title, book.year); } -// this function, takes a reference to a mutable book +// This function takes a reference to a mutable book fn new_edition(book: &mut Book) { // the fields of the book can be modified book.year = 2014; } fn main() { - // an immutable Book + // An immutable Book let geb = Book { // string literals have type `&'static str` author: "Douglas Hofstadter", - title: "Godel, Escher, Bach", + title: "Gödel, Escher, Bach", year: 1979, }; - // borrow geb, geb can still be used afterwards + // Immutably borrow `geb` borrow_book(&geb); - // geb can be borrowed again, and again, and again ... - borrow_book(&geb); - - // Error: can't borrow immutable object as mutable - //new_edition(&mut geb); + // Error! Can't borrow an immutable object as mutable + new_edition(&mut geb); + // FIXME ^ Comment out this line - // pass ownership of geb to mutable_geb, changing mutability + // Move `geb` into `mutable_geb`, changing mutability let mut mutable_geb = geb; - // Ok: borrow a mutable object as mutable + // Borrow a mutable object as mutable new_edition(&mut mutable_geb); - // Ok: mutable objects can be immutably borrowed + // Mutable objects can be immutably borrowed borrow_book(&mutable_geb); } diff --git a/examples/borrow/re-borrow.rs b/examples/borrow/re-borrow.rs deleted file mode 100644 index 98e52e009e..0000000000 --- a/examples/borrow/re-borrow.rs +++ /dev/null @@ -1,50 +0,0 @@ -struct Point { - x: int, - y: int, - z: int, -} - -fn main() { - let mut point = Point { x: 0, y: 0, z: 0 }; - - if true { - let borrowed_point = &point; - let another_borrow = &point; - - // data can be accessed via the references and the original owner - println!("Point has coordinates: ({}, {}, {})", - borrowed_point.x, - another_borrow.y, - point.z); - - // Error: cannot borrow `point` as mutable because it is also - // borrowed as immutable - //let mutable_borrow = &mut point; - - // immutables references go out of scope - } - - if true { - let mutable_borrow = &mut point; - - // change data via mutable reference - mutable_borrow.x = 5; - - // copies of the mutably borrowed struct are allowed - let copied_point = point; - - // Error: cannot borrow `point` as immutable because it is also - // borrowed as mutable - //let y = &point.y; - - // Error: can't print, because println! takes an immutable - // reference - //println!("Point Z coordinate is {}", point.z); - - // mutable reference goes out of scope - } - - // immutable references to point are allowed again - println!("Point now has coordinates: ({}, {}, {})", - point.x, point.y, point.z); -} diff --git a/examples/borrow/ref.rs b/examples/borrow/ref.rs deleted file mode 100644 index 5ba4fd379e..0000000000 --- a/examples/borrow/ref.rs +++ /dev/null @@ -1,33 +0,0 @@ -struct Point { - x: int, - y: int, -} - -fn main() { - let point = Point { x: 0, y: 0 }; - - // superfluous type annotation - let copy_of_x: int = { - // ref_to_x is a reference to the x field of point - // ref_to_x type signature is &int - let Point { x: ref ref_to_x, y: _ } = point; - - // return a copy of the x field of point - *ref_to_x - }; - - // a mutable copy of point - let mut mutable_point = point; - - if true { - // ref can be paired with mut to take mutable references - let Point { x: _, y: ref mut mut_ref_to_y } = mutable_point; - - // mutate y field of mutable_point, via a mutable reference - *mut_ref_to_y = 1; - } - - println!("point is ({}, {})", point.x, point.y); - println!("mutable_point is ({}, {})", - mutable_point.x, mutable_point.y); -} diff --git a/examples/borrow/ref/input.md b/examples/borrow/ref/input.md new file mode 100644 index 0000000000..7eca8f7256 --- /dev/null +++ b/examples/borrow/ref/input.md @@ -0,0 +1,4 @@ +When doing pattern matching or destructuring via the `let` binding, the `ref` +keyword can be used to take references to the fields of a struct/tuple. + +{ref.play} diff --git a/examples/borrow/ref/ref.rs b/examples/borrow/ref/ref.rs new file mode 100644 index 0000000000..93888eedee --- /dev/null +++ b/examples/borrow/ref/ref.rs @@ -0,0 +1,39 @@ +struct Point { x: int, y: int } + +fn main() { + let point = Point { x: 0, y: 0 }; + + let _copy_of_x = { + // `ref_to_x` is a reference to the `x` field of `point` + let Point { x: ref ref_to_x, y: _ } = point; + + // Return a copy of the `x` field of `point` + *ref_to_x + }; + + // A mutable copy of `point` + let mut mutable_point = point; + + { + // `ref` can be paired with `mut` to take mutable references + let Point { x: _, y: ref mut mut_ref_to_y } = mutable_point; + + // Mutate the `y` field of `mutable_point`, via a mutable reference + *mut_ref_to_y = 1; + } + + println!("point is ({}, {})", point.x, point.y); + println!("mutable_point is ({}, {})", mutable_point.x, mutable_point.y); + + let mut tuple = (box 5, 3); + + { + // `ref` can also be paired with `box` to take a mutable reference to + // the data contained in the box + let (box ref mut i, _) = tuple; + + *i = 3; + } + + println!("tuple is {}", tuple); +} diff --git a/examples/bounds/bounds.rs b/examples/bounds/bounds.rs index 27886f5026..6f368e5a1a 100644 --- a/examples/bounds/bounds.rs +++ b/examples/bounds/bounds.rs @@ -5,22 +5,22 @@ struct Vec2 { } impl< - // bound: T implements the Add trait + // Bound: `T` must implement the `Add` trait T: Add > Add, Vec2> for Vec2 { fn add(&self, rhs: &Vec2) -> Vec2 { Vec2 { - // x and y are of type T, and implement the add() method + // `x` and `y` are of type `T`, and implement the `add` method x: self.x.add(&rhs.x), - // the sugary + operator can also be used + // The sugary `+` operator can also be used y: self.y + rhs.y, } } } impl< - // bound: T implements the Sub trait + // Bound: `T` must implement the `Sub` trait T: Sub > Sub, Vec2> for Vec2 { @@ -33,7 +33,7 @@ for Vec2 { } impl< - // bound: T implements *both* the Add trait and the Mul trait + // Bound: `T` must implement *both* the `Add` trait and the ` ` trait T: Add + Mul > Vec2 { fn dot(&self, rhs: &Vec2) -> T { @@ -42,10 +42,15 @@ impl< } fn main() { - let v1 = Vec2 { x: 1.0, y: 2.0 }; - let v2 = Vec2 { x: 2.0, y: 1.0 }; + // Floats implement the `Add`, `Mul` and `Sub` traits + let v1 = Vec2 { x: 1.2, y: 3.4 }; + let v2 = Vec2 { x: 5.6, y: 7.8 }; println!("{} + {} = {}", v1, v2, v1 + v2); println!("{} - {} = {}", v1, v2, v1 - v2); println!("{} . {} = {}", v1, v2, v1.dot(&v2)); + + // Error! `char` doesn't implement the `Add` trait + println!("{}", Vec2 { x: ' ', y: 'b' } + Vec2 { x: 'c', y: 'd' }); + // FIXME ^ Comment out this line } diff --git a/examples/bounds/input.md b/examples/bounds/input.md index b5e8ea6b90..0caf2845d9 100644 --- a/examples/bounds/input.md +++ b/examples/bounds/input.md @@ -1,5 +1,10 @@ -When writing generic code, it's important to *bound* the generic data to -conform to some traits. This allows using the trait methods in these bounded -implementations. +When working with generics, the type parameters (e.g. `Ty`) may use traits +(e.g. `Tr`) as *bounds* (e.g. `Ty: Tr`, which reads as: `Ty` must implement the +`Tr` trait). Bounding has two effects: + +* Generics instances (`let ty: Ty = (...)`) can now access the methods + (`ty.tr()`) of the traits specified in the bounds. +* The generic can only be specialized for type parameters that conform to the + bounds. {bounds.play} diff --git a/examples/box/box.rs b/examples/box/box.rs index 6f1f670b6c..ce0ce289a7 100644 --- a/examples/box/box.rs +++ b/examples/box/box.rs @@ -1,11 +1,12 @@ -use std::mem::size_of_val; -use std::owned::Box; +use std::mem; +#[allow(dead_code)] struct Point { x: f64, y: f64, } +#[allow(dead_code)] struct Rectangle { p1: Point, p2: Point, @@ -16,52 +17,51 @@ fn origin() -> Point { } fn boxed_origin() -> Box { - // heap allocate this point, and return a pointer to it + // Allocate this point in the heap, and return a pointer to it box Point { x: 0.0, y: 0.0 } } fn main() { - // all type annotations are superfluous - // stack allocated variables + // (all the type annotations are superfluous) + // Stack allocated variables let point: Point = origin(); let rectangle: Rectangle = Rectangle { p1: origin(), p2: Point { x: 3.0, y: 4.0 } }; - // heap allocated rectangle + // Heap allocated rectangle let boxed_rectangle: Box = box Rectangle { p1: origin(), p2: origin() }; - // function output can be boxed + // The output of functions can be boxed let boxed_point: Box = box origin(); - // double indirection + // Double indirection let box_in_a_box: Box> = box boxed_origin(); println!("Point occupies {} bytes in the stack", - size_of_val(&point)); - // The `&` means that we are passing the object by reference, rather - // than by value. In Rust, this is known as *borrowing* and will be - // covered in detail in its own section. + mem::size_of_val(&point)); println!("Rectangle occupies {} bytes in the stack", - size_of_val(&rectangle)); + mem::size_of_val(&rectangle)); // box size = pointer size println!("Boxed point occupies {} bytes in the stack", - size_of_val(&boxed_point)); + mem::size_of_val(&boxed_point)); println!("Boxed rectangle occupies {} bytes in the stack", - size_of_val(&boxed_rectangle)); + mem::size_of_val(&boxed_rectangle)); + println!("Boxed box occupies {} bytes in the stack", + mem::size_of_val(&box_in_a_box)); - // copy data of boxed_point into the stack + // Copy the data contained in `boxed_point` into `unboxed_point` let unboxed_point: Point = *boxed_point; println!("Unboxed point occupies {} bytes in the stack", - size_of_val(&unboxed_point)); + mem::size_of_val(&unboxed_point)); - // unboxing via deconstruction + // Unboxing via a destructuring pattern let box another_unboxed_point = boxed_point; println!("Another unboxed point occupies {} bytes in the stack", - size_of_val(&another_unboxed_point)); + mem::size_of_val(&another_unboxed_point)); } diff --git a/examples/box/input.md b/examples/box/input.md index 1300221fc6..ae4cb9bbb5 100644 --- a/examples/box/input.md +++ b/examples/box/input.md @@ -4,8 +4,8 @@ All values in Rust are stack allocated by default. Values can be *boxed* goes out of scope, its destructor is called, the inner object is destroyed, and the memory in the heap is freed. -Boxed values can be dereferenced (unboxed) using the `*` operator, this removes -one layer of indirection. Alternatively, `let box x = y` can be used to unbox -`y` into `x`. +Boxed values can be dereferenced using the `*` operator, this removes one layer +of indirection. Alternatively, the `let box x = y` pattern can be used to +"unbox" `y` into `x`. {box.play} diff --git a/examples/channels/channels.rs b/examples/channels/channels.rs index 6996274e8e..cd9a333dc4 100644 --- a/examples/channels/channels.rs +++ b/examples/channels/channels.rs @@ -1,39 +1,37 @@ -use std::comm::channel; +use std::comm; -static NTASKS: int = 5; +static NTASKS: uint = 3; fn main() { - // channels have two endpoints: the Sender and the Receiver, - // where T is the type of the message to be transfer + // Channels have two endpoints: the `Sender` and the `Receiver`, + // where `T` is the type of the message to be transfer // (type annotation is superfluous) - let (tx, rx): (Sender<_>, Receiver<_>) = channel(); + let (tx, rx): (Sender, Receiver) = comm::channel(); for id in range(0, NTASKS) { - // the sender endpoint can be copied - let tx = tx.clone(); + // The sender endpoint can be copied + let task_tx = tx.clone(); - // each task will send its id via the channel + // Each task will send its id via the channel spawn(proc() { - // queue message in the channel - tx.send(id); + // The task takes ownership over `task_tx` + // Each task queues a message in the channel + task_tx.send(id); - // sending is a non-blocking operation, the task will continue + // Sending is a non-blocking operation, the task will continue // immediately after sending its message - println!("task number {} finished", id); + println!("task {} finished", id); }); } - // here, all the messages are collected + // Here, all the messages are collected + let mut ids = Vec::with_capacity(NTASKS); for _ in range(0, NTASKS) { - // the recv() methods picks a message from the channel - let id = rx.recv(); - - println!("task number {} reported", id); + // The `recv` method picks a message from the channel + // `recv` will block the current task if there no messages available + ids.push(rx.recv()); } - // receiving blocks the task if there is no message available, until a - // new message arrives - rx.recv(); - - println!("this point will never be reached!"); + // Show the order in which the messages were sent + println!("{}", ids); } diff --git a/examples/channels/fifo.rs b/examples/channels/fifo.rs deleted file mode 100644 index e7b8435e98..0000000000 --- a/examples/channels/fifo.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::comm::channel; - -static NMESSAGES: int = 5; - -fn main() { - let (tx, rx) = channel(); - - for i in range(0, NMESSAGES) { - tx.send(i); - } - - for _ in range(0, NMESSAGES) { - println!("{}", rx.recv()); - } -} diff --git a/examples/channels/input.md b/examples/channels/input.md index a3c9b721b9..7e5186a247 100644 --- a/examples/channels/input.md +++ b/examples/channels/input.md @@ -1,28 +1,5 @@ -Rust uses asynchronous `channels` to allow communication between tasks. -Channels allow an unidirectional flow of information between two end-points: -the `Sender` and the `Receiver`. +Rust provides asynchronous `channels` for communication between tasks. Channels +allow an unidirectional flow of information between two end-points: the +`Sender` and the `Receiver`. -{channels.rs} - -This is a sample output, order may vary because of task scheduling. - -``` -$ rustc channels.rs && ./channels -task number 1 finished -task number 3 finished -task number 4 finished -task number 2 finished -task number 0 finished -task number 1 reported -task number 2 reported -task number 0 reported -task number 3 reported -task number 4 reported - -``` - -Albeit non obvious from the output above, channels are actually FIFO. - -{fifo.play} - -The order is maintained, after removing the scheduler non-determinism. +{channels.play} diff --git a/examples/clone/clone.rs b/examples/clone/clone.rs index 7422120938..0fdcbd3023 100644 --- a/examples/clone/clone.rs +++ b/examples/clone/clone.rs @@ -1,49 +1,43 @@ -// a vanilla unit struct -struct Foo; +// A unit struct without resources +#[deriving(Show)] +struct Nil; -// a unit struct that implements the Clone trait -#[deriving(Clone)] -struct Dolly; - -fn destroy_string(string: String) { - // string gets destroyed in this scope -} +// A tuple struct with resources that implements the `Clone` trait +#[deriving(Clone,Show)] +struct Pair(Box, Box); fn main() { - // string is a reference to a global constant string - let string: &'static str = "Hello World"; - - // another_string is a copy of string, i.e. another reference to the - // same global constant - let another_string = string; - - // both can be used at the same time, there is no resource ownership - println!("{} and {}", string, another_string); - - // a heap allocated string - let boxed_string = String::from_str("Hello World"); + // Instantiate `Nil` + let nil = Nil; + // Copy `Nil`, there are no resources to move + let copied_nil = nil; - // this moves the ownership - let new_boxed_string = boxed_string; + // Both `Nil`s can be used independently + println!("original: {}", nil); + println!("copy: {}", copied_nil); - // Error: the original boxed_string can't be used anymore - //println!("{}", boxed_string); + // Instantiate a `Pair` + let pair = Pair(box 1, box 2); + println!("original: {}", pair); - // this allocates memory and copies the string into it - let copied_boxed_string = new_boxed_string.clone(); + // Copy `pair` into `moved_pair`, moves resources + let moved_pair = pair; + println!("copy: {}", moved_pair); - // destroy the original string - destroy_string(new_boxed_string); + // Error! `pair` has lost it resources + //println!("original: {}", pair); + // TODO ^ Try uncommenting this line - // copy can still be used - println!("{}", copied_boxed_string); + // "Clone" `moved_pair` into `cloned_pair` (resources included) + let cloned_pair = moved_pair.clone(); - // instantiate unit structs - let (foo, dolly) = (Foo, Dolly); + // `Drop` the original pair + drop(moved_pair); - // Error: Foo is not cloneable - //let cloned_foo = Foo.clone(); + // Error! `moved_pair` has been `drop`ed + //println!("copy: {}", moved_pair); + // TODO ^ Try uncommenting this line - // Ok: bar implements the Clone trait - let cloned_dolly = dolly.clone(); + // Clone can still be used + println!("clone: {}", cloned_pair); } diff --git a/examples/clone/input.md b/examples/clone/input.md index 734061106f..41619ffdbc 100644 --- a/examples/clone/input.md +++ b/examples/clone/input.md @@ -1,6 +1,6 @@ When dealing with resources, the default behavior is to transfer them during assignments or function calls. Sometimes the intention is to make a copy of the -resource, this can be accomplish by calling the `clone()` method, defined in +resource, this can be accomplish by calling the `clone` method, defined in the `Clone` trait. {clone.play} diff --git a/examples/closures/closures.rs b/examples/closures/closures.rs index 939c6c1372..69b6efd001 100644 --- a/examples/closures/closures.rs +++ b/examples/closures/closures.rs @@ -3,9 +3,10 @@ fn main() { let closure = |argument| { println!("I captured this: {}", captured_value); - println!("argument passed was: {}", argument); + println!("Argument passed was: {}", argument); + true }; - println!("closure returned: {}", closure("a string")); + println!("Closure returned: {}", closure("a string")); } diff --git a/examples/closures/input.md b/examples/closures/input.md index c09714304c..835b824600 100644 --- a/examples/closures/input.md +++ b/examples/closures/input.md @@ -1,10 +1,10 @@ Closures are special functions that can capture the variables available in the surrounding scope. Closures consist of three parts: -* a list of arguments enclosed by pipes `|`, these arguments can optionally be +* A list of arguments enclosed by pipes `|`, these arguments can optionally be type annotated, but usually the compiler will infer their types -* optionally the return type using an arrow `->`, again this usually gets +* Optionally the return type using an arrow `->`, again this usually gets inferred -* a block, the last expression is the return value +* A block, the last expression is the return value {closures.play} diff --git a/examples/constants/constants.rs b/examples/constants/constants.rs index 1d50ba65cc..af00383f83 100644 --- a/examples/constants/constants.rs +++ b/examples/constants/constants.rs @@ -2,26 +2,27 @@ static LANGUAGE: &'static str = "Rust"; static THRESHOLD: int = 10; fn is_big(n: int) -> bool { - // access constant in some function + // Access constant in some function n > THRESHOLD } fn main() { let n = 16; - // access constant in the main loop + // Access constant in the main task println!("This is {}", LANGUAGE); println!("The threshold is {}", THRESHOLD); println!("{} is {}", n, if is_big(n) { "big" } else { "small" }); - // Error: cannot modify static item - //THRESHOLD = 5; + // Error! Cannot modify an static item + THRESHOLD = 5; + // FIXME ^ Comment out this line - if true { - // string literals are references to read-only memory - let static_string: &'static str = "In read-only memory"; + { + // String literals are references to read-only memory + let _static_string: &'static str = "In read-only memory"; - // when static_string goes out of scope, we can no longer refer to the - // underlying data, but the string remains in the read-only memory + // When `_static_string` goes out of scope, we can no longer refer to + // the underlying data, but the string remains in the read-only memory } } diff --git a/examples/crates/erty.rs b/examples/crates/erty.rs deleted file mode 100644 index 634e74b1d6..0000000000 --- a/examples/crates/erty.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub fn public_function() { - println!("called erty's public_function()"); -} - -fn private_function() { - println!("called erty's private_function()"); -} - -pub fn indirect_access() { - print!("called erty's indirect_access(), that\n> "); - - private_function(); -} diff --git a/examples/crates/input.md b/examples/crates/input.md index c031add5e9..1fa3ad9809 100644 --- a/examples/crates/input.md +++ b/examples/crates/input.md @@ -1,38 +1,9 @@ A crate is a compilation unit in Rust. Whenever `rustc some_file.rs` is called, -`some_file.rs` is treated as the crate file. If `some_file.rs` has `mod` +`some_file.rs` is treated as the *crate file*. If `some_file.rs` has `mod` declarations in it, then the contents of the module files will get merged with -the crate file before running the compiler over it. In other words, modules +the crate file *before* running the compiler over it. In other words, modules do *not* get compiled individually, only crates get compiled. A crate can be compiled into a binary or into a library. By default, `rustc` -will produce a binary from a crate. This behavior can be overridden passing the -`--crate-type` flag to `rustc`. - -Let's create a library, and then see how to link it to another crate. - -{erty.rs} - -``` -$ rustc --crate-type=lib erty.rs -$ ls lib* -liberty-e6eaab2e-0.0.rlib -``` - -Libraries get prefixed with "lib", and contain a hash and their version in -their name. The version and name of the library can be changed using -*attributes* (which are covered in the next section). - -To link a crate to this new library, the `extern crate` declaration must be -used. This will not only link the library, but also import all its items -under a module named the same as the library. The visibility rules that apply -to modules also apply to libraries. - -{executable.rs} - -``` -# -L . adds the current directory to the library search path -$ rustc -L . executable.rs && ./executable -called erty's public_function() -called erty's indirect_access(), that -> called erty's private_function() -``` +will produce a binary from a crate. This behavior can be overridden by passing +the `--crate-type` flag to `rustc`. diff --git a/examples/crates/lib/erty.rs b/examples/crates/lib/erty.rs new file mode 100644 index 0000000000..6104f64ea3 --- /dev/null +++ b/examples/crates/lib/erty.rs @@ -0,0 +1,13 @@ +pub fn public_function() { + println!("called erty's `public_function()`"); +} + +fn private_function() { + println!("called erty's `private_function()`"); +} + +pub fn indirect_access() { + print!("called erty's `indirect_access()`, that\n> "); + + private_function(); +} diff --git a/examples/crates/lib/input.md b/examples/crates/lib/input.md new file mode 100644 index 0000000000..ef74e14121 --- /dev/null +++ b/examples/crates/lib/input.md @@ -0,0 +1,13 @@ +Let's create a library, and then see how to link it to another crate. + +{erty.rs} + +``` +$ rustc --crate-type=lib erty.rs +$ ls lib* +liberty-e6eaab2e-0.0.rlib +``` + +Libraries get prefixed with "lib", and contain a hash and their version in +their name. The version and name of the library can be changed using +[attributes](/attribute/crate.html). diff --git a/examples/crates/executable.rs b/examples/crates/link/executable.rs similarity index 55% rename from examples/crates/executable.rs rename to examples/crates/link/executable.rs index 86fabff873..42c83c39f5 100644 --- a/examples/crates/executable.rs +++ b/examples/crates/link/executable.rs @@ -1,10 +1,10 @@ -// link to liberty, import items under the "erty" module +// Link to `liberty`, import items under the `erty` module extern crate erty; fn main() { erty::public_function(); - // Error: private function is private + // Error! `private_function` is private //erty::private_function(); erty::indirect_access(); diff --git a/examples/crates/link/input.md b/examples/crates/link/input.md new file mode 100644 index 0000000000..043852b79e --- /dev/null +++ b/examples/crates/link/input.md @@ -0,0 +1,14 @@ +To link a crate to this new library, the `extern crate` declaration must be +used. This will not only link the library, but also import all its items +under a module named the same as the library. The visibility rules that apply +to modules also apply to libraries. + +{executable.rs} + +``` +# The `-L .` argument adds the current directory to the library search path +$ rustc -L . executable.rs && ./executable +called erty's `public_function()` +called erty's `indirect_access()`, that +> called erty's `private_function()` +``` diff --git a/examples/drop/drop b/examples/drop/drop deleted file mode 100755 index 24c2512eda..0000000000 Binary files a/examples/drop/drop and /dev/null differ diff --git a/examples/drop/drop.rs b/examples/drop/drop.rs index 360bf1ac94..622c5b11a1 100644 --- a/examples/drop/drop.rs +++ b/examples/drop/drop.rs @@ -1,93 +1,41 @@ -use std::io::fs; -use std::io::process::{Command,ProcessOutput}; - -struct Executable { - path: Path, -} - -impl Executable { - // compile source and return the executable created - fn new(source: &Path) -> Option { - let display = source.display(); - - println!("compiling {}...", display); - - match Command::new("rustc").arg(source).output() { - Err(why) => { - println!("couldn't spawn rustc: {}", why.desc) - - return None; - }, - Ok(ProcessOutput { output: _, error: err, status: exit }) => { - if !exit.success() { - print!("compilation failed: \n{}", - String::from_utf8(err).unwrap()); - - return None; - } else { - println!("successfully compiled {}", display); - } - }, - } - - source.filename_str().and_then(|string| { - Some(Executable { - path: Path::new(string.split('.').next().unwrap()) - }) - }) - } - - // run executable - fn run(&self) { - let display = self.path.display(); - - match Command::new(format!("./{}", display)).output() { - Err(why) => { - println!("couldn't execute ./{}: {}", display, why); - }, - Ok(ProcessOutput { output: out, error: err, status: exit }) => { - if exit.success() { - print!("output was:\n{}", String::from_utf8(out).unwrap()) - } else { - let out = String::from_utf8(out).unwrap(); - let err = String::from_utf8(err).unwrap(); - - print!("runtime error:\n{}{}", out, err); - } - }, - } - } +struct Droppable { + name: &'static str, } -// this Drop implementation will take care of removing the executable file -impl Drop for Executable { +// This `drop` implementation doesn't free resources; but instead reports its +// usage via a print to the console +impl Drop for Droppable { fn drop(&mut self) { - let display = self.path.display(); - - match fs::unlink(&self.path) { - Err(_) => println!("couldn't remove {}", display), - Ok(_) => println!("deleted {}", display), - } + println!("> Dropping {}", self.name); } } fn main() { - if true { - match Executable::new(&Path::new("hello.rs")) { - None => {}, - Some(executable) => { - executable.run(); + let _a = Droppable { name: "a" }; - println!("end of the match block"); + // block A + { + let _b = Droppable { name: "b" }; - // executable gets "dropped" here - }, - }; + // block B + { + let _c = Droppable { name: "c" }; + let _d = Droppable { name: "d" }; - println!("end of the if block") - } + println!("Exiting block B"); + } + println!("Just exited block B"); - if !Path::new("hello").exists() { - println!("hello no longer exists") + println!("Exiting block A"); } + println!("Just exited block A"); + + // Variable can be manually dropped using the `drop` function + drop(_a); + // TODO ^ Try uncommenting this line + + println!("end of the main function"); + + // `_a` *won't* be `drop`ed again here, because it already has been + // (manually) `drop`ed } diff --git a/examples/drop/hello.rs b/examples/drop/hello.rs deleted file mode 100644 index 47ad8c6341..0000000000 --- a/examples/drop/hello.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello World!"); -} diff --git a/examples/drop/input.md b/examples/drop/input.md index 90acb483c3..2e7b4c28d3 100644 --- a/examples/drop/input.md +++ b/examples/drop/input.md @@ -1,25 +1,9 @@ The `Drop` trait only has one method: `drop`, and this method is called when -an object goes out of scope. One use of the `Drop` trait is to free -resources that an object own. +an object goes out of scope. The main use of the `Drop` trait is to free the +resources that the implementor instance owns. -`Box`, `File` and `Process` are some examples of types that implement the -`Drop` trait to free resources. The `Drop` trait can also be implemented by -custom data types. +`Box`, `Vec`, `String`, `File` and `Process` are some examples of types that +implement the `Drop` trait to free resources. The `Drop` trait can be +implemented for any custom data type. -{drop.rs} - -``` -$ rustc drop.rs && ./drop -compiling hello.rs... -successfully compiled hello.rs -output was: -Hello World! -end of the match block -deleted hello -end of the if block -hello no longer exists -``` - -Where: - -{hello.rs} +{drop.play} diff --git a/examples/enum/c-like.rs b/examples/enum/c-like/c-like.rs similarity index 100% rename from examples/enum/c-like.rs rename to examples/enum/c-like/c-like.rs diff --git a/examples/enum/c-like/input.md b/examples/enum/c-like/input.md new file mode 100644 index 0000000000..be1e0cad2b --- /dev/null +++ b/examples/enum/c-like/input.md @@ -0,0 +1,3 @@ +`enum` can also be used as C-like enums. + +{c-like.play} diff --git a/examples/enum/enum.rs b/examples/enum/enum.rs index bc3bf3d3b0..48a80b7507 100644 --- a/examples/enum/enum.rs +++ b/examples/enum/enum.rs @@ -1,82 +1,66 @@ -use std::owned::Box; - -// linked list node, can take on any of these two values +// A linked list node, which can take on any of these two variants enum Node { - // data, [ ] -> next_node + // Cons: Tuple struct that wraps an element and a pointer to the next node + // element, [ ] -> next_node Cons(uint, Box), - // terminal node + // Nil: A node that signifies the end of the linked list Nil, } +// Methods can be attached to an enum impl Node { - // create an empty list + // Create an empty list fn new() -> Node { + // `Nil` has type `Node` Nil } - // consume list, and return the same list with a new element appended + // Consume a list, and return the same list with a new element at its front fn append(self, elem: uint) -> Node { + // `Cons` also has type Node Cons(elem, box self) } - // return the head of the list - fn head(&self) -> Option { - match *self { - // head gets copied, copy is returned wrapped in Some - Cons(head, _) => Some(head), - // if the list is empty, return None - Nil => None, - } - } - - // return the length of the list + // Return the length of the list fn len(&self) -> uint { + // `self` has to be matched, because the behavior of this method + // depends on the variant of `self` + // `self` has type `&Node`, and `*self` has type `Node`, matching on a + // concrete type `T` is preferred over a match on a reference `&T` match *self { - // can't take ownership of the tail, because self is borrowed + // Can't take ownership of the tail, because `self` is borrowed; // instead take a reference to the tail Cons(_, ref tail) => 1 + tail.len(), - // empty list has zero length + // An empty list has zero length Nil => 0 } } - // this method consumes the list and returns the tail - fn tail(self) -> Option { - match self { - // if the list is empty, return None - Nil => None, - // unbox the tail, return it wrapped in Some - Cons(_, box tail) => Some(tail), + // Return representation of the list as a (heap allocated) string + fn stringify(&self) -> String { + match *self { + Cons(head, ref tail) => { + // `format!` is similar to `print!`, but returns a heap + // allocated string instead of printing to the console + format!("{}, [ ] -> {}", head, tail.stringify()) + }, + Nil => { + format!("Nil") + }, } } } fn main() { - // linked list: 3, [ ] -> 2, [ ] -> 1, [ ] -> Nil + // Create an empty linked list let mut list = Node::new(); + + // Append some elements list = list.append(1); list = list.append(2); list = list.append(3); - println!("list size: {}", list.len()); - - // continuously behead list until it's empty - loop { - // look at the list head - let head = list.head(); - - list = match list.tail() { - // if list is empty, break this loop - None => break, - // unwrap tail - Some(tail) => { - // show the list head - println!("list head: {}", head.unwrap()); - - // tail is the new list - tail - }, - }; - - } + // Show the final state of the list + println!("linked list has length: {}", list.len()); + println!("{}", list.stringify()); } diff --git a/examples/enum/input.md b/examples/enum/input.md index ec922916f4..35aa59c8c3 100644 --- a/examples/enum/input.md +++ b/examples/enum/input.md @@ -1,10 +1,6 @@ -The `enum` keyword allows the creation of tagged unions, which can be used as -algebraic data types. +The `enum` keyword allows the creation of +[tagged unions](http://en.wikipedia.org/wiki/Tagged_union), which can be used +as algebraic data types +([ADT](http://en.wikipedia.org/wiki/Algebraic_data_type)). {enum.play} - -`enum` can also be used to represent C-like enums. - -{c-like.rs} - -{c-like.out} diff --git a/examples/expression/expression.rs b/examples/expression/expression.rs index 359e73a3ae..6af5057814 100644 --- a/examples/expression/expression.rs +++ b/examples/expression/expression.rs @@ -1,19 +1,16 @@ fn main() { - // all the type annotations are superfluous - let x: int = 5; + let x = 5; - let y: int = { - // assignment statements are allowed inside blocks + let y = { let x_squared = x * x; let x_cube = x_squared * x; - // this expression will be assigned to y + // This expression will be assigned to `y` x_cube + x_squared + x }; - let z: () = { - // the semicolon suppresses this expression, - // and `()` is assigned to z + let z = { + // The semicolon suppresses this expression and `()` is assigned to `z` 2 * x; }; diff --git a/examples/expression/input.md b/examples/expression/input.md index 62cefd8d0e..76576c3698 100644 --- a/examples/expression/input.md +++ b/examples/expression/input.md @@ -2,9 +2,8 @@ In Rust, almost every statement is an expression, this means that the statement returns a value. This may not always be desired, so the output can be suppressed by ending the expression with a semicolon `;`. -A block is a collection of statements and expressions enclosed by braces `{}`. -Block are expressions too, so they can be used as rvalues in assignments. The -last expression in the block will be assigned to the lvalue. If the last +Block are expressions too, so they can be used as r-values in assignments. The +last expression in the block will be assigned to the l-value. But, if the last expression of the block ends with a semicolon, the return value will be `()`. {expression.play} diff --git a/examples/fail/fail.rs b/examples/fail/fail.rs new file mode 100644 index 0000000000..b496c212c6 --- /dev/null +++ b/examples/fail/fail.rs @@ -0,0 +1,22 @@ +// Re-implementation of integer division (/) +fn division(dividend: int, divisor: int) -> int { + if divisor == 0 { + // Division by zero triggers a task failure + fail!("division by zero"); + } else { + dividend / divisor + } +} + +// The `main` task +fn main() { + // Heap allocated integer + let _x = box 0; + + // This operation will trigger a task failure + division(3, 0); + + println!("This point won't be reached!"); + + // `_x` should get destroyed at this point +} diff --git a/examples/fail/input.md b/examples/fail/input.md new file mode 100644 index 0000000000..b63f5d2f49 --- /dev/null +++ b/examples/fail/input.md @@ -0,0 +1,29 @@ +The `fail!` macro can be used to generate a *task* failure and start unwinding +its stack. While unwinding, the runtime will take care of freeing all the +resources *owned* by the task by calling the destructor of all its objects. + +Since we are dealing with programs with only one task, `fail!` will cause the +program to report the failure message and exit. + +{fail.play} + +Let's check that `fail!` doesn't leak memory. + +``` +$ rustc fail.rs && valgrind ./fail +==2614== Memcheck, a memory error detector +==2614== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. +==2614== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info +==2614== Command: ./fail +==2614== +task '
' failed at 'division by zero', fail.rs:5 +==2614== +==2614== HEAP SUMMARY: +==2614== in use at exit: 0 bytes in 0 blocks +==2614== total heap usage: 15 allocs, 15 frees, 928 bytes allocated +==2614== +==2614== All heap blocks were freed -- no leaks are possible +==2614== +==2614== For counts of detected and suppressed errors, rerun with: -v +==2614== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2) +``` diff --git a/examples/file/create.rs b/examples/file/create/create.rs similarity index 63% rename from examples/file/create.rs rename to examples/file/create/create.rs index 71a5d59b9d..cd5bb7ef71 100644 --- a/examples/file/create.rs +++ b/examples/file/create/create.rs @@ -11,19 +11,19 @@ proident, sunt in culpa qui officia deserunt mollit anim id est laborum. fn main() { let path = Path::new("out/lorem_ipsum.txt"); + let display = path.display(); - // create a file and open it in write mode, if the file exists then it'll - // get overwritten from the start, returns IoResult + // Open a file in write-only mode, returns `IoResult` let mut file = match File::create(&path) { - Err(why) => fail!("couldn't create {}: {}", path.display(), why.desc), + Err(why) => fail!("couldn't create {}: {}", display, why.desc), Ok(file) => file, }; - // write LOREM_IPSUM to file, returns IoResult<()> + // Write the `LOREM_IPSUM` string to `file`, returns `IoResult<()>` match file.write_str(LOREM_IPSUM) { Err(why) => { - fail!("couldn't write to {}: {}", path.display(), why.desc) + fail!("couldn't write to {}: {}", display, why.desc) }, - Ok(_) => println!("successfully wrote to {}", path.display()), + Ok(_) => println!("successfully wrote to {}", display), } } diff --git a/examples/file/create/input.md b/examples/file/create/input.md new file mode 100644 index 0000000000..89a34d883d --- /dev/null +++ b/examples/file/create/input.md @@ -0,0 +1,27 @@ +The `create` static method opens a file in write-only mode. If the file already +existed, the old content is destroyed, otherwise a new file is created. + +{create.play} + +As in the previous example, the playpen won't allow file I/O, so you'll hit one +of the failure paths. Here's the expected successful output: + +``` +$ mkdir out +$ rustc create.rs && ./create +successfully wrote to out/lorem_ipsum.txt +$ cat out/lorem_ipsum.txt +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +``` + +(As in the previous example, you are encouraged to test this example under +failure conditions) + +There is also a more generic +[`open_mode`](http://static.rust-lang.org/doc/master/std/io/fs/struct.File.html#method.open_mode) +method that can open files in other modes like: read+write, append, etc. diff --git a/examples/file/input.md b/examples/file/input.md index 402bceb36f..5f2166bcf4 100644 --- a/examples/file/input.md +++ b/examples/file/input.md @@ -1,48 +1,9 @@ -File I/O in Rust is handled with the `File` struct. Several methods are -associated with `File` for opening, reading or writing a file. Most of these -methods return the `IoResult` type, which is an alias for `Result`. This makes the failure of all I/O operations *explicit*, thanks to -this the programmer can see all the failure paths, and is encouraged to handle -them in a proactive manner. - -A `File` owns a resource (the file handle), and take cares of closing the file -when the `File` value goes out of scope. - -Let's see how to open a file in read-only mode. - -{open.rs} - -``` -$ echo "Hello World!" > hello.txt -$ rustc open.rs && ./open -hello.txt contains: -Hello World! -``` +The `File` struct represents a file that has been opened (it wraps a file +descriptor), and gives read and/or write access to the underlying file. -(You are encouraged to test the previous example under failure conditions: -without the hello.txt file, or a hello.txt file without the right permissions, -etc.) +Since many things can go wrong when doing file I/O, all the `File` methods +return the `IoResult` type, which is an alias for `Result`. -Now let's see how to write to a file. - -{create.rs} - -``` -$ mkdir out -$ rustc create.rs && ./create -successfully wrote to out/lorem_ipsum.txt -$ cat out/lorem_ipsum.txt -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod -tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, -quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo -consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse -cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non -proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -``` - -(As in the previous example, you are encouraged to test this example under -failure conditions) - -There is also a more generic -[`open_mode`](http://static.rust-lang.org/doc/master/std/io/fs/struct.File.html#method.open_mode) -function that can open files in read/write mode or append mode. +This makes the failure of all I/O operations *explicit*, thanks to +this the programmer can see all the failure paths, and is encouraged to handle +them in a proactive manner. diff --git a/examples/file/open.rs b/examples/file/open.rs deleted file mode 100644 index d638f5dc33..0000000000 --- a/examples/file/open.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::io::File; - -fn main() { - // create a path - let path = Path::new("hello.txt"); - - // open the path in read-only mode, returns IoResult - let mut file = match File::open(&path) { - // the desc field of IoError is a string that describes the problem - Err(why) => fail!("couldn't open {}: {}", path.display(), why.desc), - Ok(file) => file, - }; - - // read the file contents into a string, returns IoResult - match file.read_to_str() { - Err(why) => fail!("couldn't read {}: {}", path.display(), why.desc), - Ok(string) => print!("{} contains:\n{}", path.display(), string), - } - - // `file` goes out of scope, and the "hello.txt" file gets closed -} diff --git a/examples/file/open/input.md b/examples/file/open/input.md new file mode 100644 index 0000000000..8200b3a5bc --- /dev/null +++ b/examples/file/open/input.md @@ -0,0 +1,20 @@ +The `open` static method can be used to open a file in read-only mode. + +A `File` owns a resource, the file descriptor, and take cares of closing the +file when its `drop`ed. + +{open.play} + +The playpen doesn't allow file I/O, so you'll hit one of the failure paths. +Here's the expected successful output: + +``` +$ echo "Hello World!" > hello.txt +$ rustc open.rs && ./open +hello.txt contains: +Hello World! +``` + +(You are encouraged to test the previous example under different failure +conditions: `hello.txt` doesn't exist, or `hello.txt` is not readable, +etc.) diff --git a/examples/file/open/open.rs b/examples/file/open/open.rs new file mode 100644 index 0000000000..d819de6904 --- /dev/null +++ b/examples/file/open/open.rs @@ -0,0 +1,22 @@ +use std::io::File; + +fn main() { + // Create a path to the desired file + let path = Path::new("hello.txt"); + let display = path.display(); + + // Open the path in read-only mode, returns `IoResult` + let mut file = match File::open(&path) { + // The `desc` field of `IoError` is a string that describes the error + Err(why) => fail!("couldn't open {}: {}", display, why.desc), + Ok(file) => file, + }; + + // Read the file contents into a string, returns `IoResult` + match file.read_to_str() { + Err(why) => fail!("couldn't read {}: {}", display, why.desc), + Ok(string) => print!("{} contains:\n{}", display, string), + } + + // `file` goes out of scope, and the "hello.txt" file gets closed +} diff --git a/examples/fn/fn.rs b/examples/fn/fn.rs new file mode 100644 index 0000000000..1efb9a2def --- /dev/null +++ b/examples/fn/fn.rs @@ -0,0 +1,35 @@ +// Function that returns a boolean value +fn is_divisible_by(lhs: uint, rhs: uint) -> bool { + // Corner case, early return + if rhs == 0 { + return false; + } + + // This is an expression, the `return` keyword is not necessary here + lhs % rhs == 0 +} + +// Functions that "don't" return a value, actually return the unit type `()` +fn fizzbuzz(n: uint) -> () { + if is_divisible_by(n, 15) { + println!("fizzbuzz"); + } else if is_divisible_by(n, 3) { + println!("fizz"); + } else if is_divisible_by(n, 5) { + println!("buzz"); + } else { + println!("{}", n); + } +} + +// When a function returns `()`, the return type can be omitted from the +// signature +fn fizzbuzz_to(n: uint) { + for n in range(1, n + 1) { + fizzbuzz(n); + } +} + +fn main() { + fizzbuzz_to(100); +} diff --git a/examples/fn/input.md b/examples/fn/input.md new file mode 100644 index 0000000000..b2de5ac5a2 --- /dev/null +++ b/examples/fn/input.md @@ -0,0 +1,11 @@ +Functions are declared using the `fn` keyword. Its arguments are type +annotated, just like variables; and, if the function returns a value, the +return type must be specified after an arrow `->`. + +The final expression in the function will be used as return value. +Alternatively, the `return` statement can be used to return a value earlier +from within the function, even from inside loops or ifs. + +Let's rewrite fizzbuzz using functions! + +{fn.play} diff --git a/examples/fn/unused/input.md b/examples/fn/unused/input.md new file mode 100644 index 0000000000..4878490a4d --- /dev/null +++ b/examples/fn/unused/input.md @@ -0,0 +1,8 @@ +The compiler provides a `dead_code` *lint* that will warn about unused +functions. An *attribute* can be used to disable the lint. + +{unused.play} + +Note that in real programs, you should eliminate dead code. In these examples +we'll allow dead code in some places because of the interactive nature of the +examples. diff --git a/examples/fn/unused/unused.rs b/examples/fn/unused/unused.rs new file mode 100644 index 0000000000..bae5665576 --- /dev/null +++ b/examples/fn/unused/unused.rs @@ -0,0 +1,12 @@ +fn used_function() {} + +// `#[allow(dead_code)]` is an attribute that disables the `dead_code` lint +#[allow(dead_code)] +fn unused_function() {} + +fn noisy_unused_function() {} +// FIXME ^ Add an attribute to suppress the warning + +fn main() { + used_function(); +} diff --git a/examples/for/for.rs b/examples/for/for.rs index 496eb28833..d13d299234 100644 --- a/examples/for/for.rs +++ b/examples/for/for.rs @@ -1,5 +1,5 @@ fn main() { - // n will take the values: 1, 2, ..., 100 in each iteration + // `n` will take the values: 1, 2, ..., 100 in each iteration for n in range(1, 101) { if n % 15 == 0 { println!("fizzbuzz"); diff --git a/examples/for/input.md b/examples/for/input.md index 57d2272309..13662c44c0 100644 --- a/examples/for/input.md +++ b/examples/for/input.md @@ -1,7 +1,7 @@ -The `for` `in` construct can be used to iterate an `Iterator`, a lazy value +The `for in` construct can be used to iterate an `Iterator`, a lazy value generator (more details later). One of the most common iterators is the `range` function. `range(a, b)` will yield values from `a` (inclusive) to `b` -(exclusive). +(exclusive) in steps of one. Let's write fizzbuzz using `for` instead of `while`. diff --git a/examples/fs/fs.rs b/examples/fs/fs.rs index c85e838981..dd54ce466e 100644 --- a/examples/fs/fs.rs +++ b/examples/fs/fs.rs @@ -1,17 +1,17 @@ use std::io::fs; use std::io::{File,IoResult,UserRWX}; -// a simple implementation of `$ cat path` +// A simple implementation of `$ cat path` fn cat(path: &Path) -> IoResult { File::open(path).and_then(|mut f| f.read_to_str()) } -// a simple implementation of `$ echo s > path` +// A simple implementation of `$ echo s > path` fn echo(s: &str, path: &Path) -> IoResult<()> { File::create(path).and_then(|mut f| f.write_str(s)) } -// a simple implementation of `$ touch path` +// A simple implementation of `$ touch path` (ignores existing files) fn touch(path: &Path) -> IoResult<()> { if !path.exists() { File::create(path).and_then(|_| Ok(())) @@ -22,20 +22,20 @@ fn touch(path: &Path) -> IoResult<()> { fn main() { println!("`mkdir a`"); - // create a directory, returns IoResult<()> + // Create a directory, returns `IoResult<()>` match fs::mkdir(&Path::new("a"), UserRWX) { Err(why) => println!("! {}", why.kind), Ok(_) => {}, } println!("`echo hello > a/b.txt`"); - // the previous match can be simplified using `unwrap_or_else`, like this + // The previous match can be simplified using the `unwrap_or_else` method echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| { println!("! {}", why.kind); }); println!("`mkdir -p a/c/d`"); - // recursively create a directory, returns IoResult<()> + // Recursively create a directory, returns `IoResult<()>` fs::mkdir_recursive(&Path::new("a/c/d"), UserRWX).unwrap_or_else(|why| { println!("! {}", why.kind); }); @@ -46,7 +46,7 @@ fn main() { }); println!("`ln -s ../b.txt a/c/b.txt`"); - // create a symbolic link, returns IoResult<()> + // Create a symbolic link, returns `IoResult<()>` fs::symlink(&Path::new("../b.txt"), &Path::new("a/c/b.txt")).unwrap_or_else(|why| { println!("! {}", why.kind); @@ -59,7 +59,7 @@ fn main() { } println!("`ls a`"); - // read the contents of a directory, returns Vec + // Read the contents of a directory, returns `IoResult>` match fs::readdir(&Path::new("a")) { Err(why) => println!("! {}", why.kind), Ok(paths) => for path in paths.iter() { @@ -68,8 +68,8 @@ fn main() { } println!("`walk a`"); - // recursively walk over the contents of a directory, returns Directories, - // which implements Iterator + // Recursively walk over the contents of a directory, returns + // `Directories`, which implements the `Iterator trait match fs::walk_dir(&Path::new("a")) { Err(why) => println!("! {}", why.kind), Ok(mut paths) => for path in paths { @@ -78,13 +78,13 @@ fn main() { } println!("`rm a/c/e.txt`"); - // remove a file, returns IoResult<()> + // Remove a file, returns `IoResult<()>` fs::unlink(&Path::new("a/c/e.txt")).unwrap_or_else(|why| { println!("! {}", why.kind); }); println!("`rmdir a/c/d`"); - // remove a directory, returns IoResult<()> + // Remove an empty directory, returns `IoResult<()>` fs::rmdir(&Path::new("a/c/d")).unwrap_or_else(|why| { println!("! {}", why.kind); }); diff --git a/examples/fs/input.md b/examples/fs/input.md index 8218af73cd..3a53e915aa 100644 --- a/examples/fs/input.md +++ b/examples/fs/input.md @@ -1,8 +1,10 @@ -The -[`std::io::fs`](http://static.rust-lang.org/doc/master/std/io/fs/index.html) -module contains all the functions you would expect to deal with the filesystem. +The [`std::io::fs`](http://static.rust-lang.org/doc/master/std/io/fs/index.html) +module contains several functions that deal with the filesystem. -{fs.rs} +{fs.play} + +You won't be able to run the previous code, because the playpen doesn't allow +file operations. Here's the expected successful output: ``` $ rustc fs.rs && ./fs @@ -26,7 +28,7 @@ $ rustc fs.rs && ./fs `rmdir a/c/d` ``` -The final state of the `a` directory is: +And the final state of the `a` directory is: ``` $ tree a diff --git a/examples/functions/functions.rs b/examples/functions/functions.rs deleted file mode 100644 index e92edfe2c4..0000000000 --- a/examples/functions/functions.rs +++ /dev/null @@ -1,29 +0,0 @@ -// function that returns a bool value -fn is_divisible_by(lhs: uint, rhs: uint) -> bool { - // corner case, early return - if rhs == 0 { - return false - } - - // this is an expression, the `return` keyword is not necessary here - lhs % rhs == 0 -} - -// function that doesn't return a value -fn fizzbuzz(n: uint) { - if is_divisible_by(n, 15) { - println!("fizzbuzz"); - } else if is_divisible_by(n, 3) { - println!("fizz"); - } else if is_divisible_by(n, 5) { - println!("buzz"); - } else { - println!("{}", n); - } -} - -fn main() { - for n in range(1u, 101) { - fizzbuzz(n); - } -} diff --git a/examples/functions/input.md b/examples/functions/input.md deleted file mode 100644 index ce2e1d64b1..0000000000 --- a/examples/functions/input.md +++ /dev/null @@ -1,11 +0,0 @@ -Functions in Rust are declared using the `fn` keyword, arguments are type -annotated just like variables and if the function returns a value, the return -type must be specified after an arrow `->`. - -The final expression in the function will be used as return value, unless is -terminated by a semicolon. Alternatively, the `return` keyword can be used to -return a value earlier from the function, even from inside loops or ifs. - -Let's rewrite fizzbuzz using functions! - -{functions.play} diff --git a/examples/generics/generics.rs b/examples/generics/generics.rs index 20b20ed4aa..630252fb73 100644 --- a/examples/generics/generics.rs +++ b/examples/generics/generics.rs @@ -1,33 +1,33 @@ -// generic struct +// A generic struct struct Pair { first: T, second: T, } -// generic function +// A generic function fn swap(pair: Pair) -> Pair { let Pair { first: first, second: second } = pair; Pair { first: second, second: first } } -// reimplementation of a 2-element Tuple +// Reimplementation of a 2-element tuple struct Tuple2(T, U); fn main() { - // explicitly specialize Pair + // Explicitly specialize `Pair` let pair_of_chars: Pair = Pair { first: 'a', second: 'b' }; - // implicitly specialize Pair + // Implicitly specialize `Pair` let pair_of_ints = Pair { first: 1, second: 2 }; - // explicitly specialize Tuple2 - let tuple: Tuple2 = Tuple2('R', 2); + // Explicitly specialize `Tuple2` + let _tuple: Tuple2 = Tuple2('R', 2); - // explicitly specialize swap - let swapped_pair_of_chars = swap::(pair_of_chars); + // Explicitly specialize `swap` + let _swapped_pair_of_chars = swap::(pair_of_chars); - // implicitly specialize swap - let swapped_pair_of_ints = swap(pair_of_ints); + // Implicitly specialize `swap` + let _swapped_pair_of_ints = swap(pair_of_ints); } diff --git a/examples/generics/input.md b/examples/generics/input.md index d284c10878..48e710daf3 100644 --- a/examples/generics/input.md +++ b/examples/generics/input.md @@ -1,7 +1,7 @@ Generic structs can be declared to hold generics types, and generic functions can be declared to take generic types as arguments. -Generics must be specialized when used, but because of type inference, +Generics must be specialized when used; but, because of type inference, annotation is usually not required. When that's not the case, structs can be specialized via type annotation, and functions can be specialized passing the generic arguments using this syntax `::`. diff --git a/examples/hello/hello.rs b/examples/hello/hello.rs index f5b35f233c..4404d43824 100644 --- a/examples/hello/hello.rs +++ b/examples/hello/hello.rs @@ -1,5 +1,13 @@ -// the main function +// This is a comment, and will be ignored by the compiler +// You can test this code by clicking the "Run" button over there -> + +// This code is editable, feel free to hack it! +// You can always return to the original code by clicking the "Reset" button -> + +// This is the main function fn main() { - // print to the console + // The statements here will be executed when the compiled binary is called + + // Print text to the console println!("Hello World!"); } diff --git a/examples/hello/input.md b/examples/hello/input.md index 493223f8ab..926ea7c897 100644 --- a/examples/hello/input.md +++ b/examples/hello/input.md @@ -5,7 +5,7 @@ This is the source code of the traditional Hello World program. `println!` is a *macro* (we'll cover them later) that prints text to the console. -A binary can be generated using the rust compiler `rustc`. +A binary can be generated using the rust compiler: `rustc`. ``` $ rustc hello.rs diff --git a/examples/hof/hof.rs b/examples/hof/hof.rs index 4ee3abdc18..834ae26d2e 100644 --- a/examples/hof/hof.rs +++ b/examples/hof/hof.rs @@ -1,43 +1,44 @@ extern crate num; -// the AdditiveIterator trait adds the sum() method to iterators -use std::iter::{AdditiveIterator,count}; -// the Integer trait adds the is_odd() method to integer primitives +// The `AdditiveIterator` trait adds the `sum` method to iterators +use std::iter::AdditiveIterator; +use std::iter; +// The `Integer` trait adds the `is_odd` method to integer primitives use num::Integer; fn main() { println!("Find the sum of all the squared odd numbers under 1000"); let upper: int = 1000; - // imperative approach - // declare accumulator variable + // Imperative approach + // Declare accumulator variable let mut acc = 0; - // iterate 0, 1, 2, ... to infinity - for n in count(0, 1) { - // square the number + // Iterate: 0, 1, 2, ... to infinity + for n in iter::count(0, 1) { + // Square the number let n_squared = n * n; if n_squared >= upper { - // break loop if exceeded the upper limit + // Break loop if exceeded the upper limit break; } else if n_squared.is_odd() { - // accumulate value, if it's odd + // Accumulate value, if it's odd acc += n_squared; } } println!("imperative style: {}", acc); - // functional approach + // Functional approach let sum_of_squared_odd_numbers = - // all natural numbers - count(0, 1). - // squared + // All natural numbers + iter::count(0, 1). + // Squared map(|n| n * n). - // below upper limit + // Below upper limit take_while(|&n| n < upper). - // that are odd + // That are odd filter(|n| n.is_odd()). - // sum them + // Sum them sum(); println!("functional style: {}", sum_of_squared_odd_numbers); } diff --git a/examples/if-else/if-else-expr.rs b/examples/if-else/if-else-expr.rs deleted file mode 100644 index 3dfeeb8d92..0000000000 --- a/examples/if-else/if-else-expr.rs +++ /dev/null @@ -1,19 +0,0 @@ -fn main() { - // all type annotations are superfluous - let n: int = 5; - - let big_n: int = - if n < 10 { - println!("small number, increase ten-fold"); - - // this expression returns an int - 10 * n - } else { - println!("big number, reduce by two"); - - // this expression must return an int as well - n / 2 - }; - - println!("{} -> {}", n, big_n); -} diff --git a/examples/if-else/if-else.rs b/examples/if-else/if-else.rs index 9eeb7e3469..042ac2510e 100644 --- a/examples/if-else/if-else.rs +++ b/examples/if-else/if-else.rs @@ -2,10 +2,26 @@ fn main() { let n = 5; if n < 0 { - println!("{} is negative", n); + print!("{} is negative", n); } else if n > 0 { - println!("{} is positive", n); + print!("{} is positive", n); } else { - println!("{} is zero", n); + print!("{} is zero", n); } + + let big_n = + if n < 10 && n > -10 { + println!(", and is a small number, increase ten-fold"); + + // This expression returns an `int` + 10 * n + } else { + println!(", and is a big number, reduce by two"); + + // This expression must return an `int` as well + n / 2 + // TODO ^ Try suppressing this expression with a semicolon + }; + + println!("{} -> {}", n, big_n); } diff --git a/examples/if-else/input.md b/examples/if-else/input.md index 7ad570d747..755ab1eb9f 100644 --- a/examples/if-else/input.md +++ b/examples/if-else/input.md @@ -1,11 +1,6 @@ Branching with if-else is similar to C. Unlike C, the boolean condition doesn't -need to be surrounded by parentheses. Each condition is followed by a block. +need to be surrounded by parentheses, and each condition is followed by a +block. If-else conditionals are expressions too; and, because of Rust type +safety, all the branches must return the same type. {if-else.play} - -If-else conditionals are expressions too. Because of Rust type safety, all the -branches must return the same type. - -{if-else-expr.rs} - -{if-else-expr.out} diff --git a/examples/iter/iter.rs b/examples/iter/iter.rs index 610e31217d..b7c7035561 100644 --- a/examples/iter/iter.rs +++ b/examples/iter/iter.rs @@ -1,64 +1,65 @@ -use std::mem::replace; +use std::mem; struct Fibonacci { curr: uint, next: uint, } -// implement Iterator for Fibonacci +// Implement 'Iterator' for 'Fibonacci' impl Iterator for Fibonacci { - // the Iterator trait only requires the next() method to be defined the - // return value is Option, None is returned when the Iterator is - // over, otherwise the next value is returned wrapped in Some + // The 'Iterator' trait only requires the 'next' method to be defined. The + // return type is 'Option', 'None' is returned when the 'Iterator' is + // over, otherwise the next value is returned wrapped in 'Some' fn next(&mut self) -> Option { let new_next = self.curr + self.next; - let new_curr = replace(&mut self.next, new_next); + let new_curr = mem::replace(&mut self.next, new_next); - // Some is always returned, this is an infinite value generator - Some(replace(&mut self.curr, new_curr)) + // 'Some' is always returned, this is an infinite value generator + Some(mem::replace(&mut self.curr, new_curr)) } } -// returns a fibonacci sequence generator +// Returns a fibonacci sequence generator fn fibonacci() -> Fibonacci { Fibonacci { curr: 1, next: 1 } } fn main() { - // iterator that generates: 0, 1 and 2 + // Iterator that generates: 0, 1 and 2 let mut sequence = range(0, 3); - println!("next in range(0, 3): {}", sequence.next()); - println!("next in range(0, 3): {}", sequence.next()); - println!("next in range(0, 3): {}", sequence.next()); - println!("next in range(0, 3): {}", sequence.next()); + println!("Four consecutive `next` calls on range(0, 3)") + println!("> {}", sequence.next()); + println!("> {}", sequence.next()); + println!("> {}", sequence.next()); + println!("> {}", sequence.next()); - // the for construct will iterate an Iterator until it returns None, - // all the Some values are unwrapped and bind to a variable - println!("iterate over range(0, 3) using for"); + // The for construct will iterate an 'Iterator' until it returns 'None', + // all the 'Some' values are unwrapped and bind to a variable + println!("Iterate over range(0, 3) using for"); for i in range(0, 3) { - println!("{}", i); + println!("> {}", i); } - // the take(n) method will reduce an iterator to its first n terms, - // pretty useful for infinite value generators - println!("The first five terms of the fibonacci sequence are: "); - for i in fibonacci().take(5) { - println!("{}", i); + // The 'take(n)' method will reduce an iterator to its first 'n' terms, + // which is pretty useful for infinite value generators + println!("The first four terms of the Fibonacci sequence are: "); + for i in fibonacci().take(4) { + println!("> {}", i); } - // the skip(n) method will shorten an iterator by dropping its first n + // The 'skip(n)' method will shorten an iterator by dropping its first 'n' // terms - println!("The next five terms of the fibonacci sequence are: "); - for i in fibonacci().skip(5).take(5) { - println!("{}", i); + println!("The next four terms of the Fibonacci sequence are: "); + for i in fibonacci().skip(4).take(4) { + println!("> {}", i); } let array = [1, 3, 3, 7]; - // the iter() method produces an iterator over an array/slice - println!("iterate the following array {}", array.as_slice()); + // The 'iter' method produces an 'Iterator' over an array/slice + println!("Iterate the following array {}", array.as_slice()); for i in array.iter() { - println!("{}", i); + println!("> {}", i); } } diff --git a/examples/literals/input.md b/examples/literals/input.md index 757685256d..597d403087 100644 --- a/examples/literals/input.md +++ b/examples/literals/input.md @@ -1,23 +1,13 @@ -This is a summary of the primitive types in Rust: +Integers `1`, floats `1.2`, characters `'a'`, strings `"abc"`, booleans `true` +and the unit type `()` can be expressed using literals. -* signed integers: `i8`, `i16`, `i32`, `i64` and `int` (machine word size) -* unsigned integers: `u8`, `u16`, `u32`, `u64` and `uint` (machine word size) -* floating point: `f32`, `f64` -* `char` Unicode scalar values like `'a'`, `'α'` and `'∞'` -* `bool` either `true` or `false` -* and the unit type `()`, whose only value is also `()` - -Numeric literals can suffix their type to indicate their precision, with the -exception of `uint` that uses the `u` suffix and `int` that uses the `i` -suffix. - -Integers can alternatively be expressed using hexadecimal, octal or binary +Integers can, alternatively, be expressed using hexadecimal, octal or binary notation using either of these prefixes: `0x`, `0o` or `0b`. -You can also insert underscores in your literals for improved readability, e.g. -`1_000_000` is the same as `1000000`. +Underscores can be inserted in numeric literals to improve readability, e.g. +`1_000` is the same as `1000`, and `0.000_001` is the same as `0.000001`. -The operators available and operator precedence are similar to other -[C-like languages](https://en.wikipedia.org/wiki/Operator_precedence#Programming_languages) +The operators available and their precedence are similar to other +[C-like languages](https://en.wikipedia.org/wiki/Operator_precedence#Programming_languages). {literals.play} diff --git a/examples/literals/literals.rs b/examples/literals/literals.rs index 9a8afe6c8d..68465ce8d7 100644 --- a/examples/literals/literals.rs +++ b/examples/literals/literals.rs @@ -1,22 +1,22 @@ fn main() { - // integer addition - println!("1 + 2 = {}", 1u + 2u); + // Integer addition + println!("1 + 2 = {}", 1 + 2); - // float division - println!("1.0 / 2.0 = {}", 1.0f32 / 2.0f32); + // Float division + println!("1.0 / 2.0 = {}", 1.0 / 2.0); - // short-circuiting boolean logic + // Short-circuiting boolean logic println!("true AND false is {}", true && false); println!("true OR false is {}", true || false); println!("NOT true is {}", !true); - // bitwise operations + // Bitwise operations println!("0011 AND 0101 is {:04t}", 0b0011 & 0b0101); println!("0011 OR 0101 is {:04t}", 0b0011 | 0b0101); println!("0011 XOR 0101 is {:04t}", 0b0011 ^ 0b0101); println!("1 << 5 is {}", 1 << 5); - println!("100 >> 2 is {}", 100 >> 2); + println!("0x80 >> 2 is 0x{:x}", 0x80 >> 2); - // use underscores to improve readability! + // Use underscores to improve readability! println!("One million is written as {}", 1_000_000); } diff --git a/examples/loop/input.md b/examples/loop/input.md new file mode 100644 index 0000000000..d79667783c --- /dev/null +++ b/examples/loop/input.md @@ -0,0 +1,7 @@ +Rust provides a `loop` keyword to indicate an infinite loop. + +The `break` statement can be used to exit a loop at anytime, whereas the +`continue` statement can be used to skip the rest of the iteration and start a +new one. + +{loop.play} diff --git a/examples/loops/loop.rs b/examples/loop/loop.rs similarity index 60% rename from examples/loops/loop.rs rename to examples/loop/loop.rs index 179fc401ad..62c5f2bc62 100644 --- a/examples/loops/loop.rs +++ b/examples/loop/loop.rs @@ -3,21 +3,24 @@ fn main() { println!("Let's count until infinity!"); - // infinite loop + // Infinite loop loop { count += 1; if count == 3 { - // skip this iteration - continue + println!("three"); + + // Skip the rest of this iteration + continue; } println!("{}", count); if count == 5 { println!("OK, that's enough"); - // exit this loop - break + + // Exit this loop + break; } } } diff --git a/examples/loop/nested/input.md b/examples/loop/nested/input.md new file mode 100644 index 0000000000..f128b7ad34 --- /dev/null +++ b/examples/loop/nested/input.md @@ -0,0 +1,5 @@ +It's possible to `break` or `continue` outer loops when dealing with nested +loops. In these cases, the loops must be annotated with some `'label`, and the +label must be passed to the `break`/`continue` statement. + +{nested.play} diff --git a/examples/loops/nested.rs b/examples/loop/nested/nested.rs similarity index 76% rename from examples/loops/nested.rs rename to examples/loop/nested/nested.rs index 1a52916548..786fabab0e 100644 --- a/examples/loops/nested.rs +++ b/examples/loop/nested/nested.rs @@ -5,10 +5,10 @@ fn main() { 'inner: loop { println!("Entered the inner loop"); - // this would break the inner loop + // This would break only the inner loop //break; - // this breaks the outer loop + // This breaks the outer loop break 'outer; } diff --git a/examples/loops/input.md b/examples/loops/input.md deleted file mode 100644 index fb5b461f45..0000000000 --- a/examples/loops/input.md +++ /dev/null @@ -1,20 +0,0 @@ -Rust provides a `loop` keyword to indicate an infinite loop. - -The `break` keyword can be used to exit a loop at anytime, whereas the -`continue` can be used to skip the rest of the iteration and start a new one. - -{loop.play} - -It's possible to `break` or `continue` outer loops when dealing with nested -loops. In these cases, the loops must be annotated with some `'label` and the -label must be passed to the `break`/`continue` statement. - -{nested.rs} - -{nested.out} - -The `while` keyword can be used for looping until a condition is met. - -Let's write the infamous fizzbuzz using a `while` loop. - -{while.rs} diff --git a/examples/match/guard/guard.rs b/examples/match/guard/guard.rs new file mode 100644 index 0000000000..255b4bc4e2 --- /dev/null +++ b/examples/match/guard/guard.rs @@ -0,0 +1,16 @@ +fn main() { + let pair = (2, -2); + // TODO ^ Try different values for `pair` + + println!("Tell me about {}", pair); + // Match can be used to destructure a tuple + match pair { + // Destructure the tuple + (x, y) if x == y => println!("These are twins"), + // The ^ `if condition` part is a guard + (x, y) if x + y == 0 => println!("Antimatter, kaboom!"), + // `_` means don't bind the value to a variable + (x, _) if x % 2 == 1 => println!("The first one is odd"), + _ => println!("No correlation..."), + } +} diff --git a/examples/match/guard/input.md b/examples/match/guard/input.md new file mode 100644 index 0000000000..8803a7b274 --- /dev/null +++ b/examples/match/guard/input.md @@ -0,0 +1,4 @@ +The arms of a `match` block can be destructured, and a *guard* can be added to +further filter the arm. + +{guard.play} diff --git a/examples/match/input.md b/examples/match/input.md index 1dcef3884e..53c52a8959 100644 --- a/examples/match/input.md +++ b/examples/match/input.md @@ -1,4 +1,4 @@ -Rust provides pattern matching via the `match` keyword, the syntax will be -covered in the code below. +Rust provides pattern matching via the `match` keyword, which can be used like +a C `switch`. {match.play} diff --git a/examples/match/match.rs b/examples/match/match.rs index 794bfd7b4d..ab8a0ebb72 100644 --- a/examples/match/match.rs +++ b/examples/match/match.rs @@ -1,40 +1,27 @@ fn main() { - let number = 23; + let number = 13; + // TODO ^ Try different values for `number` + println!("Tell me about {}", number); match number { - // match single value + // Match a single value 1 => println!("One!"), - // match several values + // Match several values 2 | 3 | 5 | 7 | 11 => println!("This is a prime"), - // match a range + // Match an inclusive range 13..19 => println!("A teen"), - // bind the rest of values to x - // and use a `guard` to pick odd numbers - x if x % 2 == 1 => println!("An odd one"), - // the rest of cases - x => println!("{} ain't special", x), + // Handle the rest of cases + _ => println!("Ain't special"), } - let pair = (2, 3); - // match can be used to destructure a tuple - match pair { - (x, y) if x == y => println!("These are twins"), - (x, y) if x + y == 0 => println!("Antimatter, kaboom"), - // _ means don't bind the value to a variable - (x, _) if x % 2 == 1 => println!("The first is odd"), - // _ can be used to match the rest of cases - _ => println!("No correlation..."), - } - - // match is an expression - let big_number = match number { - 0 => 9000, - // blocks are also valid branches - x if x < 10 => { - let y = x * x; - let z = x * x * x; - x + y + z - }, - x => x, + let boolean = true; + // Match is an expression too + let binary = match boolean { + // The arms of a match must cover all the possible values + false => 0, + true => 1, + // TODO ^ Try commenting out one of these arms }; + + println!("{} -> {}", boolean, binary); } diff --git a/examples/methods/input.md b/examples/methods/input.md index 6bb3dae716..c2bde12242 100644 --- a/examples/methods/input.md +++ b/examples/methods/input.md @@ -1,5 +1,5 @@ Methods are functions attached to objects, these methods have access to the -data of the object and its other methods via the `self` keyword. These methods -are grouped under a `impl` block. +data of the object and its other methods via the `self` keyword. Methods are +defined under a `impl` block. {methods.play} diff --git a/examples/methods/methods.rs b/examples/methods/methods.rs index f985f60089..71937c3d93 100644 --- a/examples/methods/methods.rs +++ b/examples/methods/methods.rs @@ -3,16 +3,16 @@ struct Point { y: f64, } -// implementation block, all Point methods go in here +// Implementation block, all `Point` methods go in here impl Point { - // this is a static method - // static methods don't need to be called by an instance - // these methods are generally used for constructors + // This is a static method + // Static methods don't need to be called by an instance + // These methods are generally used as constructors fn origin() -> Point { Point { x: 0.0, y: 0.0 } } - // another static method, that takes two arguments + // Another static method, that takes two arguments fn new(x: f64, y: f64) -> Point { Point { x: x, y: y } } @@ -24,15 +24,16 @@ struct Rectangle { } impl Rectangle { - // instance method, `&self` is sugar for `self: &Self` - // where Self is the type of the caller object - // in this case Self = Rectangle + // This is an instance method + // `&self` is sugar for `self: &Self`, where `Self` is the type of the + // caller object. In this case `Self` = `Rectangle` fn area(&self) -> f64 { // `self` gives access to the struct fields via the dot operator let Point { x: x1, y: y1 } = self.p1; let Point { x: x2, y: y2 } = self.p2; - // abs() is a method of f64 types + // `abs` is a `f64` method that returns the absolute value of the + // caller ((x1 - x2) * (y1 - y2)).abs() } @@ -43,7 +44,7 @@ impl Rectangle { 2.0 * (x1 - x2).abs() + 2.0 * (y1 - y2).abs() } - // this method requires the caller object to be mutable + // This method requires the caller object to be mutable // `&mut self` desugars to `self: &mut Self` fn move(&mut self, x: f64, y: f64) { self.p1.x += x; @@ -54,29 +55,32 @@ impl Rectangle { } } -// Bomb owns resources: one heap allocated string -struct Bomb { - name: String, -} +// `Pair` owns resources: two heap allocated integers +struct Pair(Box, Box); -impl Bomb { - // this method consumes the caller object +impl Pair { + // This method "consumes" the resources of the caller object // `self` desugars to `self: Self` - fn boom(self) { - println!("{} goes boom!", self.name); - // self goes out of scope and it's destroyed + fn destroy(self) { + // Destructure `self` + let Pair(first, second) = self; + + println!("Destroying Pair({}, {})", first, second); + + // `first` and `second` go out of scope and get freed } } fn main() { let rectangle = Rectangle { - // static methods are called using double colons + // Static methods are called using double colons p1: Point::origin(), p2: Point::new(3.0, 4.0), }; - // instance method are called using the dot operator - // note that the first argument `&self` is implicitly passed + // Instance method are called using the dot operator + // Note that the first argument `&self` is implicitly passed, i.e. + // `rectangle.perimeter()` === `perimeter(&rectangle)` println!("Rectangle perimeter: {}", rectangle.perimeter()); println!("Rectangle area: {}", rectangle.area()); @@ -85,16 +89,19 @@ fn main() { p2: Point::new(1.0, 1.0), }; - // Error: object is immutable, but method requires a mutable object + // Error! `rectangle` is immutable, but this method requires a mutable + // object //rectangle.move(1.0, 0.0); + // TODO ^ Try uncommenting this line - // Ok: mutable object can call mutable methods + // Ok, mutable object can call mutable methods square.move(1.0, 1.0); - let bomb = Bomb { name: String::from_str("C4") }; + let pair = Pair(box 1, box 2); - bomb.boom(); + pair.destroy(); - // Error: previous boom() call destroyed the bomb - //bomb.boom(); + // Error! Previous `destroy` call "consumed" `pair` + //pair.destroyed(); + // TODO ^ Try uncommenting this line } diff --git a/examples/mod/input.md b/examples/mod/input.md index ba8916c416..30fcc3518b 100644 --- a/examples/mod/input.md +++ b/examples/mod/input.md @@ -5,56 +5,4 @@ between them. A module is collection of items like: functions, structs, traits, impl blocks, and even other modules. -{nested.play} - -By default, the items in a module have private visibility, but this can be -overridden using the `pub` modifier. Only the public items of a module can be -accessed from outside the module scope. - -{visibility.rs} - -{visibility.out} - -The `use` declaration can be used to bind a full path to a new name, for easier -access. - -{use.rs} - -{use.out} - -The `super` and `self` keywords can be used in the path, to remove ambiguity -when accessing items. - -{super.rs} - -{super.out} - -Structs have an extra level of visibility, their fields can be public or -private. This allows encapsulation. - -{structs.rs} - -{structs.out} - -Modules can be mapped to a file/directory hierarchy. Let's break down the -second example in files: - -``` -$ tree . -. -|-- my -| |-- inaccessible.rs -| |-- mod.rs -| `-- nested.rs -`-- split.rs -``` - -{split.rs} - -{my/mod.rs} - -{my/nested.rs} - -{my/inaccessible.rs} - -{split.out} +{mod.play} diff --git a/examples/mod/mod.rs b/examples/mod/mod.rs new file mode 100644 index 0000000000..66b0508fd1 --- /dev/null +++ b/examples/mod/mod.rs @@ -0,0 +1,34 @@ +fn function() { + println!("called `function()`"); +} + +// A module named `my` +mod my { + // A module can contain items like functions + #[allow(dead_code)] + fn function() { + println!("called `my::function()`"); + } + + // Modules can be nested + mod nested { + #[allow(dead_code)] + fn function() { + println!("called `my::nested::function()`"); + } + } +} + +fn main() { + function(); + + // Items inside a module can be called using their full path + // The `println` function lives in the `stdio` module + // The `stdio` module lives in the `io` module + // And the `io` module lives in the `std` crate + std::io::stdio::println("Hello World!"); + + // Error! `my::function` is private + my::function(); + // TODO ^ Comment out this line +} diff --git a/examples/mod/my/inaccessible.rs b/examples/mod/my/inaccessible.rs deleted file mode 100644 index eae09c0592..0000000000 --- a/examples/mod/my/inaccessible.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn public_function() { - println!("called my::inaccessible::public_function()"); -} diff --git a/examples/mod/my/nested.rs b/examples/mod/my/nested.rs deleted file mode 100644 index 003431fcbe..0000000000 --- a/examples/mod/my/nested.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub fn function() { - println!("called my::nested::function()"); -} - -fn private_function() { - println!("called my::nested::private_function()"); -} diff --git a/examples/mod/nested.rs b/examples/mod/nested.rs deleted file mode 100644 index 07b21c95a9..0000000000 --- a/examples/mod/nested.rs +++ /dev/null @@ -1,25 +0,0 @@ -fn function() { - println!("called function()"); -} - -// a module named `my` -mod my { - // a module can contain items like functions - fn function() { - println!("called my::function()"); - } - - // modules can be nested - mod nested { - fn function() { - println!("called my::nested::function()"); - } - } -} - -fn main() { - function(); - - // items inside a module can be called using the full path - my::function(); -} diff --git a/examples/mod/split/input.md b/examples/mod/split/input.md new file mode 100644 index 0000000000..4684b0cd7e --- /dev/null +++ b/examples/mod/split/input.md @@ -0,0 +1,31 @@ +Modules can be mapped to a file/directory hierarchy. Let's break down the +[visibility example](/mod/visibility.html) in files: + +``` +$ tree . +. +|-- my +| |-- inaccessible.rs +| |-- mod.rs +| `-- nested.rs +`-- split.rs +``` + +{split.rs} + +{my/mod.rs} + +{my/nested.rs} + +{my/inaccessible.rs} + +Let's check that things still work as before: + +``` +$ rustc split.rs && ./split +called `my::function()` +called `function()` +called `my::indirect_access()`, that +> called `my::private_function()` +called `my::nested::function()` +``` diff --git a/examples/mod/split/my/inaccessible.rs b/examples/mod/split/my/inaccessible.rs new file mode 100644 index 0000000000..487a10e468 --- /dev/null +++ b/examples/mod/split/my/inaccessible.rs @@ -0,0 +1,4 @@ +#[allow(dead_code)] +pub fn public_function() { + println!("called `my::inaccessible::public_function()`"); +} diff --git a/examples/mod/my/mod.rs b/examples/mod/split/my/mod.rs similarity index 53% rename from examples/mod/my/mod.rs rename to examples/mod/split/my/mod.rs index 1fed3b8b97..5851229632 100644 --- a/examples/mod/my/mod.rs +++ b/examples/mod/split/my/mod.rs @@ -1,19 +1,19 @@ -// similarly `mod inaccessible` and `mod nested` will locate the `nested.rs` +// Similarly `mod inaccessible` and `mod nested` will locate the `nested.rs` // and `inaccessible.rs` files and insert them here under their respective // modules mod inaccessible; pub mod nested; pub fn function() { - println!("called my::function()"); + println!("called `my::function()`"); } fn private_function() { - println!("called my::private_function()"); + println!("called `my::private_function()`"); } pub fn indirect_access() { - print!("called my::indirect_access(), that\n> "); + print!("called `my::indirect_access()`, that\n> "); private_function(); } diff --git a/examples/mod/split/my/nested.rs b/examples/mod/split/my/nested.rs new file mode 100644 index 0000000000..e47cf9b07b --- /dev/null +++ b/examples/mod/split/my/nested.rs @@ -0,0 +1,8 @@ +pub fn function() { + println!("called `my::nested::function()`"); +} + +#[allow(dead_code)] +fn private_function() { + println!("called `my::nested::private_function()`"); +} diff --git a/examples/mod/split.rs b/examples/mod/split/split.rs similarity index 68% rename from examples/mod/split.rs rename to examples/mod/split/split.rs index 0718a041ac..812ff8042a 100644 --- a/examples/mod/split.rs +++ b/examples/mod/split/split.rs @@ -1,9 +1,9 @@ -// this declaration will look for a file named `my.rs` or `my/mod.rs` and will +// This declaration will look for a file named `my.rs` or `my/mod.rs` and will // insert its contents inside a module named `my` under this scope mod my; fn function() { - println!("called function()"); + println!("called `function()`"); } fn main() { diff --git a/examples/mod/super/input.md b/examples/mod/super/input.md new file mode 100644 index 0000000000..05b1415fa3 --- /dev/null +++ b/examples/mod/super/input.md @@ -0,0 +1,4 @@ +The `super` and `self` keywords can be used in the path, to remove ambiguity +when accessing items. + +{super.play} diff --git a/examples/mod/super.rs b/examples/mod/super/super.rs similarity index 56% rename from examples/mod/super.rs rename to examples/mod/super/super.rs index 2ff366f1f5..d9c2cb700e 100644 --- a/examples/mod/super.rs +++ b/examples/mod/super/super.rs @@ -1,27 +1,25 @@ fn function() { - println!("called function()"); + println!("called `function()`"); } mod my { pub fn indirect_call() { - // let's see how to access all the functions named `function` from this - // scope - print!("called my::indirect_call(), that\n> "); + // Let's access all the functions named `function` from this scope + print!("called `my::indirect_call()`, that\n> "); - // my::function() can be called directly + // `my::function` can be called directly function(); - if true { - // this will bind to the cool::function in the *root* scope - // (it's actually the crate scope, but we haven't talk about crates - // yet) + { + // This will bind to the `cool::function` in the *crate* scope + // In this case the crate scope is the outermost scope use root_cool_function = cool::function; print!("> "); root_cool_function(); } - if true { + { // `self` refers to the current module scope, in this case: `my` use my_cool_function = self::cool::function; @@ -29,7 +27,7 @@ mod my { my_cool_function(); } - if true { + { // `super` refers to the parent scope, i.e. outside of the `my` // module use root_function = super::function; @@ -40,19 +38,19 @@ mod my { } fn function() { - println!("called my::function()"); + println!("called `my::function()`"); } mod cool { pub fn function() { - println!("called my::cool::function()"); + println!("called `my::cool::function()`"); } } } mod cool { pub fn function() { - println!("called cool::function()"); + println!("called `cool::function()`"); } } diff --git a/examples/mod/use.rs b/examples/mod/use.rs deleted file mode 100644 index 8028131979..0000000000 --- a/examples/mod/use.rs +++ /dev/null @@ -1,33 +0,0 @@ -// bind Text to std::string::String -use Text = std::string::String; - -mod deeply { - pub mod nested { - pub fn function() { - println!("called deeply::nested::function") - } - } -} - -fn main() { - // Text can be used instead of StrBuf - let mut text = Text::new(); - text.push_str("Hello"); - text.push_char(' '); - text.push_str("World!"); - - println!("{}", text); - - if true { - // if a new name is omitted, the item name gets bound to the path - use deeply::nested::function; - - function(); - - // `use` bindings have a local scope, in this case the `function` - // binding can only be used inside this if block - } - - // Error: unresolved name `function` - //function(); -} diff --git a/examples/mod/use/input.md b/examples/mod/use/input.md new file mode 100644 index 0000000000..05b3657427 --- /dev/null +++ b/examples/mod/use/input.md @@ -0,0 +1,4 @@ +The `use` declaration can be used to bind a full path to a new name, for easier +access. + +{use.play} diff --git a/examples/mod/use/use.rs b/examples/mod/use/use.rs new file mode 100644 index 0000000000..c9dbe543ad --- /dev/null +++ b/examples/mod/use/use.rs @@ -0,0 +1,35 @@ +// Bind the `deeply::nested::function` path to `other_function` +use other_function = deeply::nested::function; + +fn function() { + println!("called `function()`"); +} + +mod deeply { + pub mod nested { + pub fn function() { + println!("called `deeply::nested::function()`") + } + } +} + +fn main() { + // Easier access to `deeply::nested::function` + other_function(); + + println!("Entering block"); + { + // This is equivalent to `use function = deeply::nested::function` + // This `function` will shadow the outer one + use deeply::nested::function; + + function(); + + println!("Leaving block"); + + // `use` bindings have a local scope, in this case the `function` + // shadowing is only available in this scope + } + + function(); +} diff --git a/examples/mod/visibility.rs b/examples/mod/visibility.rs deleted file mode 100644 index fb6955b0bb..0000000000 --- a/examples/mod/visibility.rs +++ /dev/null @@ -1,68 +0,0 @@ -fn function() { - println!("called function()"); -} - -mod my { - // a public function - pub fn function() { - println!("called my::function()"); - } - - // a private function - fn private_function() { - println!("called my::private_function()"); - } - - // items can access other items in the same module - pub fn indirect_access() { - print!("called my::indirect_access(), that\n> "); - - // regardless of their visibility - private_function(); - } - - // a public module - pub mod nested { - pub fn function() { - println!("called my::nested::function()"); - } - - fn private_function() { - println!("called my::nested::private_function()"); - } - } - - // a private module - mod inaccessible { - pub fn public_function() { - println!("called my::inaccessible::public_function()"); - } - } -} - -fn main() { - // the public items of a module can be accessed - my::function(); - - // modules allow disambiguation between items that have the same name - function(); - - // the private items of a module can't be directly accessed - // Error: private_function is private - //my::private_function(); - - my::indirect_access(); - - // public items inside public nested modules can be accessed from outside - // the parent module - my::nested::function(); - - // but private items inside public nested modules can't be accessed - // Error: private_function is private - //my::nested::private_function(); - - // items inside private nested modules can't be accessed, regardless of - // their visibility - // Error: inaccessible is a private module - //my::inaccessible::public_function(); -} diff --git a/examples/mod/visibility/input.md b/examples/mod/visibility/input.md new file mode 100644 index 0000000000..b334d7625e --- /dev/null +++ b/examples/mod/visibility/input.md @@ -0,0 +1,5 @@ +By default, the items in a module have private visibility, but this can be +overridden with the `pub` modifier. Only the public items of a module can be +accessed from outside the module scope. + +{visibility.play} diff --git a/examples/mod/visibility/visibility.rs b/examples/mod/visibility/visibility.rs new file mode 100644 index 0000000000..8081b1b8d2 --- /dev/null +++ b/examples/mod/visibility/visibility.rs @@ -0,0 +1,73 @@ +fn function() { + println!("called `function()`"); +} + +mod my { + // A public function + pub fn function() { + println!("called `my::function()`"); + } + + // A private function + fn private_function() { + println!("called `my::private_function()`"); + } + + // Items can access other items in the same module + pub fn indirect_access() { + print!("called `my::indirect_access()`, that\n> "); + + // regardless of their visibility + private_function(); + } + + // A public module + pub mod nested { + pub fn function() { + println!("called `my::nested::function()`"); + } + + #[allow(dead_code)] + fn private_function() { + println!("called `my::nested::private_function()`"); + } + } + + // A private module + mod inaccessible { + #[allow(dead_code)] + pub fn public_function() { + println!("called `my::inaccessible::public_function()`"); + } + } +} + +fn main() { + // The public items of a module can be accessed + my::function(); + + // modules allow disambiguation between items that have the same name + function(); + + // The private items of a module can't be directly accessed + // Error! `private_function` is private + //my::private_function(); + // TODO ^ Try uncommenting this line + + my::indirect_access(); + + // Public items inside public nested modules can be accessed from outside + // the parent module + my::nested::function(); + + // but private items inside public nested modules can't be accessed + // Error! `private_function` is private + //my::nested::private_function(); + // TODO ^ Try uncommenting this line + + // Items inside private nested modules can't be accessed, regardless of + // their visibility + // Error! `inaccessible` is a private module + //my::inaccessible::public_function(); + // TODO ^ Try uncommenting this line +} diff --git a/examples/move/assignment.rs b/examples/move/assignment.rs deleted file mode 100644 index 2e4adcbd40..0000000000 --- a/examples/move/assignment.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::owned::Box; - -fn main() { - // stack allocated integer - let x = 5; - - // copy `x` into `y`, there are no resources to move - let y = x; - - // both values can be used, because they are independent - println!("x is {}, and y is {}", x, y); - - // `a` is a pointer to a heap allocated integer - let a = box 5; - - // copy `b` into `a`, now both point to the same heap allocated data - // *but*, now b *owns* the heap allocated data - // `b` is now in charge of freeing the memory in the heap - let b = a; - - // Error: `a` can no longer access the data - // because the resource has been *moved* - println!("{} can not be used", a); - - // a goes out of scope - // b goes out of scope, and the memory is freed -} diff --git a/examples/move/input.md b/examples/move/input.md index 50338ad0dd..76280f3d29 100644 --- a/examples/move/input.md +++ b/examples/move/input.md @@ -1,22 +1,11 @@ Because variables are in charge of freeing their resources (if any), resources can only have *one* owner, otherwise resources would get freed more than once. -When doing assignments, `let x = y`, or passing function arguments by value +When doing assignments `let x = y`, or passing function arguments by value `foo(x)`, the data is copied, but the *ownership* of the resources is -transferred, this is know as *moving* in Rust-speak. +transferred, this is know as a *move* in Rust-speak. -{assignment.play} +{move.play} After moving resources, the previous owner loses access to the resource. This -avoids *dereferencing freed memory*. - -{pass-by-value.rs} - -{pass-by-value.out} - -Mutability of data depends on its owner. Mutability of data can change when -ownership is transferred. - -{mut.rs} - -{mut.out} +avoids the creation of *dangling pointers*. diff --git a/examples/move/move.rs b/examples/move/move.rs new file mode 100644 index 0000000000..082f55284a --- /dev/null +++ b/examples/move/move.rs @@ -0,0 +1,41 @@ +// This function takes ownership of the heap allocated memory +fn destroy_box(c: Box) { + println!("destroying a box that contains {}", c); + + // `c` will be destroyed in this scope, and the memory will be freed +} + +fn main() { + // Stack allocated integer + let x = 5; + + // Copy `x` into `y`, there are no resources to move + let y = x; + + // Both values can be independently used + println!("x is {}, and y is {}", x, y); + + // `a` is a pointer to a heap allocated integer + let a = box 5; + + println!("a contains: {}", a); + + // Copy `a` into `b`, now both are pointers to the same heap allocated + // data, but now, `b` owns the heap allocated data + // `b` is now in charge of freeing the memory in the heap + let b = a; + + // Error! `a` can no longer access the data, because it no longer owns the + // heap memory + //println!("a contains: {}", a); + // TODO ^ Try uncommenting this line + + // Pass a copy of `b` to the function, and give up ownership + destroy_box(b); + + // Error! For the same reason as the previous Error + // Since the heap memory has been freed at this point, this action would + // result in dereferencing freed memory + //println!("b contains: {}", b); + // TODO ^ Try uncommenting this line +} diff --git a/examples/move/mut/input.md b/examples/move/mut/input.md new file mode 100644 index 0000000000..239187aa28 --- /dev/null +++ b/examples/move/mut/input.md @@ -0,0 +1,3 @@ +Mutability of data can be changed when ownership is transferred. + +{mut.play} diff --git a/examples/move/mut.rs b/examples/move/mut/mut.rs similarity index 66% rename from examples/move/mut.rs rename to examples/move/mut/mut.rs index 32fddaf03c..dbc7eeb46a 100644 --- a/examples/move/mut.rs +++ b/examples/move/mut/mut.rs @@ -6,12 +6,12 @@ fn main() { // Mutability error //*immutable_box = 4; - // hand over box, change mutability + // Hand over the box, changing the mutability let mut mutable_box = immutable_box; - println!("mutable_box contains {}", mutable_box); + println!("mutable_box contained {}", mutable_box); - // modify contents of the box + // Modify the contents of the box *mutable_box = 4; println!("mutable_box now contains {}", mutable_box); diff --git a/examples/move/pass-by-value.rs b/examples/move/pass-by-value.rs deleted file mode 100644 index d687898894..0000000000 --- a/examples/move/pass-by-value.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::owned::Box; - -// this function takes ownership of the heap allocated memory -fn destroy_box(boxed_int: Box) { - // boxed_int will be destroyed in this scope, and the memory will be - // freed -} - -fn main() { - // heap allocated integer - let boxed_int = box 5; - - // boxed_int loses ownership of the heap allocated integer - destroy_box(boxed_int); - - // Error: this would dereference freed memory - // the compiler forbids it, because the resource has been moved - let invalid_dereference = *boxed_int; -} diff --git a/examples/operator/input.md b/examples/ops/input.md similarity index 81% rename from examples/operator/input.md rename to examples/ops/input.md index fc11a19863..fa219daa37 100644 --- a/examples/operator/input.md +++ b/examples/ops/input.md @@ -1,6 +1,6 @@ In Rust, many of the operators can be overloaded via traits. This is possible because operators are just sugar for method calls. For example, `a + b` -desugars to `a.add(&b)`. This `add()` method is part of the `Add` trait, hence +desugars to `a.add(&b)`. This `add` method is part of the `Add` trait, hence any implementor of the `Add` trait will be able to use the `+` operator. {operator.play} diff --git a/examples/operator/operator.rs b/examples/ops/operator.rs similarity index 73% rename from examples/operator/operator.rs rename to examples/ops/operator.rs index 508abb8c16..7efb7839ab 100644 --- a/examples/operator/operator.rs +++ b/examples/ops/operator.rs @@ -7,12 +7,12 @@ struct FooBar; #[deriving(Show)] struct BarFoo; -// the Add trait needs two generic parameters: -// T is the type of the RHS summand, and -// U is the type of the sum +// The `Add` trait needs two generic parameters: +// * T is the type of the RHS summand, and +// * U is the type of the sum // This block implements the operation: Foo + Bar = FooBar impl Add for Foo { - fn add(&self, rhs: &Bar) -> FooBar { + fn add(&self, _rhs: &Bar) -> FooBar { println!("> Foo.add(&Bar) was called"); FooBar @@ -22,7 +22,7 @@ impl Add for Foo { // Addition can be implemented in a non-commutative way // This block implements the operation: Bar + Foo = BarFoo impl Add for Bar { - fn add(&self, rhs: &Foo) -> BarFoo { + fn add(&self, _rhs: &Foo) -> BarFoo { println!("> Bar.add(&Foo) was called"); BarFoo diff --git a/examples/option/input.md b/examples/option/input.md index 7309dfdb47..2483eff161 100644 --- a/examples/option/input.md +++ b/examples/option/input.md @@ -1,13 +1,9 @@ -The `fail!` macro can be used to generate a runtime failure and start unwinding -the program. Upon unwinding, the runtime will take care of freeing all -the resources by calling the destructors of all the objects in scope. +Sometimes it's desirable to catch the failure of some parts of a program +instead of calling `fail!`, this can be accomplished using the `Option` enum. -Sometimes it is desirable to catch the failure of some parts of the program -instead of unwinding the whole program, this can be accomplished using the -`Option` enum (enums will be explained in detail in the next section). +The `Option` enum has two variants: -`Option` can take two values: `None`, to indicate failure or lack of value, or -`Some`, a tuple struct that wraps a value. The type `T` of the wrapped value is -part of the type signature of option `Option`. +* `None`, to indicate failure or lack of value, and +* `Some(value)`, a tuple struct that wraps a `value` with type `T`. {option.play} diff --git a/examples/option/option.rs b/examples/option/option.rs index beb9e24caa..eb97b8e498 100644 --- a/examples/option/option.rs +++ b/examples/option/option.rs @@ -1,29 +1,22 @@ -// re-implementation of division (/) -fn division(dividend: int, divisor: int) -> int { - if divisor == 0 { - fail!("division by zero"); - } else { - dividend / divisor - } -} - -// checked division +// An integer division that doesn't `fail!` fn checked_division(dividend: int, divisor: int) -> Option { if divisor == 0 { - // failure represented as None + // Failure is represented as the `None` variant None } else { - // result wrapped in a Some tuple struct + // Result is wrapped in a `Some` variant Some(dividend / divisor) } } +// This function handles a division that may not succeed fn try_division(dividend: int, divisor: int) { - // Option values can be pattern matched + // `Option` values can be pattern matched, just like other enums match checked_division(dividend, divisor) { None => println!("{} / {} failed!", dividend, divisor), - Some(quotient) => println!("{} / {} = {}", - dividend, divisor, quotient), + Some(quotient) => { + println!("{} / {} = {}", dividend, divisor, quotient) + }, } } @@ -31,13 +24,14 @@ fn main() { try_division(4, 2); try_division(1, 0); - // Binding None to a variable needs to be type annotated + // Binding `None` to a variable needs to be type annotated let none: Option = None; + let _equivalent_none = None::; let optional_float = Some(0.0); - // The unwrap() method will extract the wrapped value from Some() and - // will fail! if called on None - let unwrapped_float = optional_float.unwrap(); - let runtime_failure = none.unwrap(); + // The `unwrap` method will extract the value wrapped in a `Some` variant, + // or will `fail!` if called on a `None` variant + println!("{} unwraps to {}", optional_float, optional_float.unwrap()); + println!("{} unwraps to {}", none, none.unwrap()); } diff --git a/examples/order.json b/examples/order.json deleted file mode 100644 index fe7b0325b7..0000000000 --- a/examples/order.json +++ /dev/null @@ -1,69 +0,0 @@ -[ - { "id": "hello", "title": "Hello World" }, - { "id": "print", "title": "Formatted print" }, - { "id": "literals", "title": "Literals" }, - { "id": "variables", "title": "Variables" }, - { "id": "type", "title": "Types, casting and inference" }, - { "id": "expression", "title": "Blocks and expressions" }, - { "id": "if-else", "title": "if/else" }, - { "id": "loops", "title": "loop and while" }, - { "id": "for", "title": "for and range" }, - { "id": "functions", "title": "Functions" }, - { "id": "tuples", "title": "Tuples" }, - { "id": "match", "title": "Pattern matching" }, - { "id": "structs", "title": "Structs" }, - { "id": "generics", "title": "Generics" }, - { "id": "box", "title": "Box, stack and heap" }, - { "id": "raii", "title": "RAII" }, - { "id": "move", "title": "Ownership and moves" }, - { "id": "borrow", "title": "Borrowing" }, - { "id": "lifetime", "title": "Lifetimes" }, - { "id": "methods", "title": "Methods" }, - { "id": "constants", "title": "Global constants" }, - { "id": "option", "title": "fail! and Option" }, - { "id": "enum", "title": "Enums" }, - { "id": "array", "title": "Arrays and Slices" }, - { "id": "trait", "title": "Traits" }, - { "id": "clone", "title": "Clone" }, - { "id": "operator", "title": "Operator Overloading" }, - { "id": "bounds", "title": "Bounds" }, - { "id": "iter", "title": "Iterators" }, - { "id": "closures", "title": "Closures" }, - { "id": "hof", "title": "Higher Order Functions" }, - { "id": "vec", "title": "Vectors" }, - { "id": "str", "title": "Strings" }, - { "id": "tasks", "title": "Tasks" }, - { "id": "channels", "title": "Channels" }, - { "id": "timers", "title": "Timers" }, - { "id": "sockets", "title": "Unix sockets" }, - { "id": "mod", "title": "Modules" }, - { "id": "crates", "title": "Crates" }, - { "id": "attribute", "title": "Attributes" }, - { "id": "result", "title": "Result and try!" }, - { "id": "path", "title": "Path" }, - { "id": "file", "title": "File I/O" }, - { "id": "process", "title": "Child processes" }, - { "id": "fs", "title": "Filesystem Operations" }, - { "id": "drop", "title": "Drop" }, - { "id": "staging", "title": "Staging Area" }, - { "id": "bench", "title": "Benchmarking" }, - { "id": "ffi", "title": "Foreign Function Interface" }, - { "id": "macros", "title": "macro_rules!" }, - { "id": "rand", "title": "Random" }, - { "id": "simd", "title": "SIMD" }, - { "id": "test", "title": "Testing" }, - { "id": "unsafe", "title": "Unsafe operations" }, - { "id": "todo", "title": "TODO" }, - { "id": "arg", "title": "Program arguments" }, - { "id": "assert", "title": "assert! and debug_assert!" }, - { "id": "comment", "title": "Comments" }, - { "id": "green", "title": "Green threads" }, - { "id": "hash", "title": "Hasher and Hashmap" }, - { "id": "json", "title": "JSON parsing" }, - { "id": "log", "title": "Logging" }, - { "id": "rc", "title": "Reference counting" }, - { "id": "regex", "title": "Regex" }, - { "id": "rustdoc", "title": "rustdoc" }, - { "id": "select", "title": "select!" }, - { "id": "stdio", "title": "Standard I/O" } -] diff --git a/examples/path/input.md b/examples/path/input.md index b7b2d13ce4..131d82e566 100644 --- a/examples/path/input.md +++ b/examples/path/input.md @@ -1,6 +1,6 @@ -Rust provides a `Path` struct to deal with file paths in the underlying -filesystem. There are two flavors of `Path`: `posix::Path`, for UNIX-like -systems, and `windows::Path`, for Windows. The prelude exports the appropriate +The `Path` struct represents file paths in the underlying filesystem. There are +two flavors of `Path`: `posix::Path`, for UNIX-like systems, and +`windows::Path`, for Windows. The prelude exports the appropriate platform-specific `Path` variant. A `Path` can be created from almost any type that implements the @@ -11,15 +11,7 @@ Note that a `Path` is *not* internally represented as an UTF-8 string, but instead is stored as a vector of bytes (`Vec`). Therefore, converting a `Path` to a `&str` is *not* free and may fail (an `Option` is returned). -{path.rs} - -``` -$ rustc path.rs && ./path -path.rs exists -path.rs is a file -path.rs size is 1074 bytes -new path is a/path.rs -``` +{path.play} Be sure to check at other `Path` methods ([`posix::Path`](http://static.rust-lang.org/doc/master/std/path/posix/struct.Path.html) diff --git a/examples/path/path b/examples/path/path deleted file mode 100755 index 6f3eae2405..0000000000 Binary files a/examples/path/path and /dev/null differ diff --git a/examples/path/path.rs b/examples/path/path.rs index 6069d602b1..11f3646598 100644 --- a/examples/path/path.rs +++ b/examples/path/path.rs @@ -1,21 +1,23 @@ fn main() { - // create a Path from an &'static str - let path = Path::new("path.rs"); + // Create a `Path` from an `&'static str` + let path = Path::new("."); - // check if the path exists + // The `display` method returns a `Show`able structure + let display = path.display(); + + // Check if the path exists if path.exists() { - // the `display` method makes the path showable - println!("{} exists", path.display()); + println!("{} exists", display); } - // check if the path is a file + // Check if the path is a file if path.is_file() { - println!("{} is a file", path.display()); + println!("{} is a file", display); } - // check if the path is a dir + // Check if the path is a directory if path.is_dir() { - println!("{} is a directory", path.display()); + println!("{} is a directory", display); } // `stat` returns an IoResult === Result @@ -24,16 +26,15 @@ fn main() { Ok(stat) => stat, }; - println!("{} size is {} bytes", path.display(), stat.size); - - let dir = Path::new("a"); + println!("{} size is {} bytes", display, stat.size); // `join` merges a path with a byte container using the OS specific - // separator - let new_path = dir.join(path); + // separator, and returns the new path + let new_path = path.join("a").join("b"); + // Convert the path into a string slice match new_path.as_str() { None => fail!("new path is not a valid UTF-8 sequence"), - Some(string_slice) => println!("new path is {}", string_slice), + Some(s) => println!("new path is {}", s), } } diff --git a/examples/print/input.md b/examples/print/input.md index 2466173aa9..c3b6e49b15 100644 --- a/examples/print/input.md +++ b/examples/print/input.md @@ -1,4 +1,4 @@ -The `println!` macro not only prints to the console, but also is capable of +The `println!` macro not only prints to the console, but is also capable of formatting text and stringifying values. Plus, the formatting correctness will be checked at compile time. diff --git a/examples/print/print.rs b/examples/print/print.rs index aa71ce47f4..3eec3c62d0 100644 --- a/examples/print/print.rs +++ b/examples/print/print.rs @@ -1,22 +1,23 @@ fn main() { - // print! is like println! but without adding a newline at the end + // `print!` is like `println!` but it doesn't add a newline at the end print!("January has "); - // {} are placeholders for arguments that will be stringified + // `{}` are placeholders for arguments that will be stringified println!("{} days", 31); - // the positional arguments can be reused along the template + // The positional arguments can be reused along the template println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob"); - // named arguments can also be used + // Named arguments can also be used println!("{subject} {verb} {predicate}", predicate="over the lazy dog", subject="the quick brown fox", verb="jumps"); - // special formatting can be specified in the placeholder after a `:` + // Special formatting can be specified in the placeholder after a `:` println!("{} of {:t} people know binary, the other half don't", 1, 2); - // Error: you are missing an argument - //println!("My name is {0}, {1} {0}", "Bond"); + // Error! You are missing an argument + println!("My name is {0}, {1} {0}", "Bond"); + // FIXME ^ Add the missing argument: "James" } diff --git a/examples/process/input.md b/examples/process/input.md index bed1fd3a01..671388d83d 100644 --- a/examples/process/input.md +++ b/examples/process/input.md @@ -1,33 +1,7 @@ -The `Process` struct represents a running or finished child process. And the -`Command` struct is a process builder. +The `ProcessOutput` struct represents the output of a finished child process. +And the `Command` struct is a process builder. {process.play} -(You are encouraged to try the previous example with an incorrect flag) - -`Process` exposes the `stdin`, `stdout` and `stderr` handles for interaction -with the child process via pipes. - -{pipe.rs} - -{pipe.out} - -When a `Process` that owns a resource (a *runnig* child process) goes out of -scope the task will *wait* until the child process finishes before releasing -the resource. - -{wait.rs} - -``` -$ rustc wait.rs && ./wait -reached end of main -# `wait` keeps running for 5 seconds -# `sleep 5` command ends, and then our `wait` program finishes -``` - -Be sure to check the other methods of -[`Command`](http://static.rust-lang.org/doc/master/std/io/process/struct.Command.html) -that allow changing the environment and the working directory of the spawned -process. The -[`Process`](http://static.rust-lang.org/doc/master/std/io/process/struct.Process.html) -struct also provides several methods to send signals to the child process. +(You are encouraged to try the previous example with an incorrect flag passed +to `rustc`) diff --git a/examples/process/pipe/input.md b/examples/process/pipe/input.md new file mode 100644 index 0000000000..a24924510b --- /dev/null +++ b/examples/process/pipe/input.md @@ -0,0 +1,5 @@ +The `Process` struct represents a running child process, and exposes the +`stdin`, `stdout` and `stderr` handles for interaction with the underlying +process via pipes. + +{pipe.play} diff --git a/examples/process/pipe.rs b/examples/process/pipe/pipe.rs similarity index 54% rename from examples/process/pipe.rs rename to examples/process/pipe/pipe.rs index 3fa412469d..23330cea01 100644 --- a/examples/process/pipe.rs +++ b/examples/process/pipe/pipe.rs @@ -1,33 +1,35 @@ use std::io::process::Command; -static PANGRAM: &'static str = "the quick brown fox jumped over the lazy dog"; +static PANGRAM: &'static str = +"the quick brown fox jumped over the lazy dog\n"; fn main() { - // spawn the `wc` command + // Spawn the `wc` command let mut process = match Command::new("wc").spawn() { Err(why) => fail!("couldn't spawn wc: {}", why.desc), Ok(process) => process, }; - if true { - // the `stdin` field has type Option - // `take_unwrap` will take the value wrapped in a Some variant - // note that we take ownership of stdin here + { + // The `stdin` field has type `Option` + // `take_unwrap` will take the value wrapped in a `Some` variant + // Note that we take ownership of `stdin` here let mut stdin = process.stdin.take_unwrap(); - // write a string to the stdin of wc + // Write a string to the stdin of `wc` match stdin.write_str(PANGRAM) { Err(why) => fail!("couldn't write to wc stdin: {}", why.desc), Ok(_) => println!("sent pangram to wc"), } - // stdin goes out of scope here, and the pipe is closed - // this is very important, otherwise wc wouldn't start processing the + // `stdin` gets `drop`ed her, and the pipe is closed + // This is very important, otherwise `wc` wouldn't start processing the // input we just sent } - // the `stdout` field also has type Option - // the `get_mut_ref` method will return a mutable reference to the pipe + // The `stdout` field also has type `Option` + // the `get_mut_ref` method will return a mutable reference to the value + // wrapped in a `Some` variant match process.stdout.get_mut_ref().read_to_str() { Err(why) => fail!("couldn't read wc stdout: {}", why.desc), Ok(string) => print!("wc responded with:\n{}", string), diff --git a/examples/process/process.rs b/examples/process/process.rs index 575803b04a..c3822aad4a 100644 --- a/examples/process/process.rs +++ b/examples/process/process.rs @@ -1,27 +1,27 @@ use std::io::process::{Command,ProcessOutput}; +use std::str; fn main() { - // initial command "rustc" + // Initial command `rustc` let mut cmd = Command::new("rustc"); // append the "--version" flag to the command cmd.arg("--version"); - // the `output` method will spawn `rustc --version`, wait until the process + // The `output` method will spawn `rustc --version`, wait until the process // finishes and return the output of the process match cmd.output() { Err(why) => fail!("couldn't spawn rustc: {}", why.desc), - // destructure the ProcessOutput struct - Ok(ProcessOutput { error: error, output: output, status: status }) => { - // check if process succeeded, i.e. the exit code was 0 - if status.success() { - // output has type `Vec` - // convert to UTF-8 String (this operation could fail) - let s = String::from_utf8(output).unwrap(); + // Destructure `ProcessOutput` + Ok(ProcessOutput { error: err, output: out, status: exit }) => { + // Check if the process succeeded, i.e. the exit code was 0 + if exit.success() { + // `out` has type `Vec`, convert it to a UTF-8 `$str` + let s = str::from_utf8_lossy(out.as_slice()); print!("rustc succeeded and stdout was:\n{}", s); } else { - // error also has type `Vec` - let s = String::from_utf8(error).unwrap(); + // `err` also has type `Vec` + let s = str::from_utf8_lossy(err.as_slice()); print!("rustc failed and stderr was:\n{}", s); } diff --git a/examples/process/wait/input.md b/examples/process/wait/input.md new file mode 100644 index 0000000000..cdf87be219 --- /dev/null +++ b/examples/process/wait/input.md @@ -0,0 +1,11 @@ +When a `Process` goes out of scope, its `drop` method will *wait* until the +child process finishes before releasing the resource. + +{wait.rs} + +``` +$ rustc wait.rs && ./wait +reached end of main +# `wait` keeps running for 5 seconds +# `sleep 5` command ends, and then our `wait` program finishes +``` diff --git a/examples/process/wait.rs b/examples/process/wait/wait.rs similarity index 58% rename from examples/process/wait.rs rename to examples/process/wait/wait.rs index e615342086..714cc1fd06 100644 --- a/examples/process/wait.rs +++ b/examples/process/wait/wait.rs @@ -1,7 +1,7 @@ use std::io::process::Command; fn main() { - let process = Command::new("sleep").arg("5").spawn(); + let _process = Command::new("sleep").arg("5").spawn(); println!("reached end of main"); } diff --git a/examples/raii/input.md b/examples/raii/input.md index ba2ab3234f..370d5cc7f0 100644 --- a/examples/raii/input.md +++ b/examples/raii/input.md @@ -4,26 +4,26 @@ RAII discipline, whenever an object goes out of scope, its destructor is called and the resources *owned* by it are freed. This behavior shields against *resource leak* bugs. -Don't take my word for it, let's check using `valgrind` - {raii.play} +Don't take my word for it, let's check using `valgrind` + ``` $ rustc raii.rs && valgrind ./raii -==7619== Memcheck, a memory error detector -==7619== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. -==7619== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info -==7619== Command: ./raii -==7619== -==7619== -==7619== HEAP SUMMARY: -==7619== in use at exit: 0 bytes in 0 blocks -==7619== total heap usage: 1,032 allocs, 1,032 frees, 8,888 bytes allocated -==7619== -==7619== All heap blocks were freed -- no leaks are possible -==7619== -==7619== For counts of detected and suppressed errors, rerun with: -v -==7619== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2) +==26873== Memcheck, a memory error detector +==26873== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. +==26873== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info +==26873== Command: ./raii +==26873== +==26873== +==26873== HEAP SUMMARY: +==26873== in use at exit: 0 bytes in 0 blocks +==26873== total heap usage: 1,013 allocs, 1,013 frees, 8,696 bytes allocated +==26873== +==26873== All heap blocks were freed -- no leaks are possible +==26873== +==26873== For counts of detected and suppressed errors, rerun with: -v +==26873== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2) ``` You'll never have to manually free memory again or worry about memory leaks! diff --git a/examples/raii/raii.rs b/examples/raii/raii.rs index e50399a924..0c9a676374 100644 --- a/examples/raii/raii.rs +++ b/examples/raii/raii.rs @@ -1,26 +1,26 @@ fn create_box() { - let function_box = box 3; + // Allocate an integer in the heap + let _function_box = box 3; - // function_box gets destroyed here, memory gets freed + // `_function_box` gets destroyed here, memory gets freed } fn main() { - // allocate integer in the heap - let boxed_int = box 5; + // Allocate an integer in the heap + let _boxed_int = box 5; - if true { - // new (smaller) block scope + // new (smaller) scope + { + // Another heap allocated integer + let _short_lived_box = box 4; - // another heap allocated integer - let short_lived_box = box 4; - - // short_lived_box gets destroyed here, memory gets freed + // `_short_lived_box` gets destroyed here, memory gets freed } - // create lots of boxes + // Create lots of boxes for _ in range(0, 1_000) { create_box(); } - // boxed_int gets destroyed here, memory gets freed + // `_boxed_int` gets destroyed here, memory gets freed } diff --git a/examples/result/checked.rs b/examples/result/checked.rs deleted file mode 100644 index aeade7c043..0000000000 --- a/examples/result/checked.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Mathematical "errors" we want to catch -#[deriving(Show)] -pub enum MathError { - DivisionByZero, - NegativeLogarithm, - NegativeSquareRoot, -} - -// type is used to alias the LHS to the RHS, usually to reduce typing/verbosity -pub type MathResult = Result; - -pub fn div(x: f64, y: f64) -> MathResult { - if y == 0.0 { - // this operation would "fail", let's return the reason wrapped in Err - Err(DivisionByZero) - } else { - // this operation is valid, return the result wrapped in Ok - Ok(x / y) - } -} - -pub fn sqrt(x: f64) -> MathResult { - if x < 0.0 { - Err(NegativeSquareRoot) - } else { - Ok(x.sqrt()) - } -} - -pub fn ln(x: f64) -> MathResult { - if x < 0.0 { - Err(NegativeLogarithm) - } else { - Ok(x.ln()) - } -} - diff --git a/examples/result/input.md b/examples/result/input.md index 5646355e5c..5a8edab985 100644 --- a/examples/result/input.md +++ b/examples/result/input.md @@ -3,32 +3,11 @@ that may fail, where `None` can be returned to indicate failure. However, sometimes is important to express *why* an operation failed. To do this we have the `Result` enum. -The `Result` enum can take on two variants: `Ok` or `Err`. Each variant is a -tuple struct that wraps some value. The `Ok(value)` variant indicates that the -operation succeeded, and wraps the `value` returned by the operation; on the -other hand `Err(why)` indicates that the operation failed, and wraps `why` -which (hopefully) explains the cause of the failure. +The `Result` enum has two variants: -`Result` is a generic enum with type signature `Result`, and its variants -are also generic: `Ok(T)` and `Err(U)`. Hence, the `Result` enum has extensive -use in the Rust standard library, especially when dealing with I/O. +* `Ok(value)` which indicates that the operation succeeded, and wraps the + `value` returned by the operation. (`value` has type `T`) +* `Err(why)`, which indicates that the operation failed, and wraps `why`, + which (hopefully) explains the cause of the failure. (`why` has type `E`) -Let's use `Result` to catch undefined mathematical operations. - -{checked.rs} - -{result.rs} - -{result.out} - -Chaining results using match can get pretty untidy; luckily, the `try!` macro -can be used to make things pretty again. The `try!` macro expands to a match -expression, where the `Err(err)` branch expands to an early `return err`, and -the `Ok(ok)` branch expands to the `ok` expression. - -{try.rs} - -{try.out} - -Be sure to check the [documentation](http://static.rust-lang.org/doc/master/std/result/type.Result.html), -as there are many methods to map/compose `Result`. +{result.play} diff --git a/examples/result/result.rs b/examples/result/result.rs index 832f4aaa7f..a18d586be7 100644 --- a/examples/result/result.rs +++ b/examples/result/result.rs @@ -1,8 +1,44 @@ -mod checked; +mod checked { + // Mathematical "errors" we want to catch + #[deriving(Show)] + pub enum MathError { + DivisionByZero, + NegativeLogarithm, + NegativeSquareRoot, + } + + pub type MathResult = Result; + + pub fn div(x: f64, y: f64) -> MathResult { + if y == 0.0 { + // This operation would `fail`, instead let's return the reason of + // the failure wrapped in `Err` + Err(DivisionByZero) + } else { + // This operation is valid, return the result wrapped in `Ok` + Ok(x / y) + } + } + + pub fn sqrt(x: f64) -> MathResult { + if x < 0.0 { + Err(NegativeSquareRoot) + } else { + Ok(x.sqrt()) + } + } + + pub fn ln(x: f64) -> MathResult { + if x < 0.0 { + Err(NegativeLogarithm) + } else { + Ok(x.ln()) + } + } +} -// op(x, y) = sqrt(ln(x / y)) +// `op(x, y)` === `sqrt(ln(x / y))` fn op(x: f64, y: f64) -> f64 { - // Results can be matched, just like Options // This is a three level match pyramid! match checked::div(x, y) { Err(why) => fail!("{}", why), @@ -17,6 +53,6 @@ fn op(x: f64, y: f64) -> f64 { } fn main() { - // will this fail? + // Will this fail? println!("{}", op(1.0, 10.0)); } diff --git a/examples/result/try.rs b/examples/result/try.rs deleted file mode 100644 index fc566c57a8..0000000000 --- a/examples/result/try.rs +++ /dev/null @@ -1,25 +0,0 @@ -use checked::{DivisionByZero,MathResult,NegativeLogarithm,NegativeSquareRoot}; - -mod checked; - -// checked_op(x, y) = sqrt(ln(x / y))? -fn checked_op(x: f64, y: f64) -> MathResult { - // if `checked_div` "fails", then DivisionByZero will be `return`ed - let ratio = try!(checked::div(x, y)); - - // if `checked_ln` "fails", then NegativeLogarithm will be `return`ed - let ln = try!(checked::ln(ratio)); - - checked::sqrt(ln) -} - -fn main() { - match checked_op(1.0, 10.0) { - Err(why) => fail!(match why { - NegativeLogarithm => "logarithm of negative number", - DivisionByZero => "division by zero", - NegativeSquareRoot => "square root of negative number", - }), - Ok(value) => println!("{}", value), - } -} diff --git a/examples/result/try/input.md b/examples/result/try/input.md new file mode 100644 index 0000000000..70af98eeef --- /dev/null +++ b/examples/result/try/input.md @@ -0,0 +1,9 @@ +Chaining results using match can get pretty untidy; luckily, the `try!` macro +can be used to make things pretty again. The `try!` macro expands to a match +expression, where the `Err(err)` branch expands to an early `return err`, and +the `Ok(ok)` branch expands to an `ok` expression. + +{try.play} + +Be sure to check the [documentation](http://static.rust-lang.org/doc/master/std/result/type.Result.html), +as there are many methods to map/compose `Result`. diff --git a/examples/result/try/try.rs b/examples/result/try/try.rs new file mode 100644 index 0000000000..cf87d02728 --- /dev/null +++ b/examples/result/try/try.rs @@ -0,0 +1,60 @@ +mod checked { + #[deriving(Show)] + enum MathError { + DivisionByZero, + NegativeLogarithm, + NegativeSquareRoot, + } + + type MathResult = Result; + + fn div(x: f64, y: f64) -> MathResult { + if y == 0.0 { + Err(DivisionByZero) + } else { + Ok(x / y) + } + } + + fn sqrt(x: f64) -> MathResult { + if x < 0.0 { + Err(NegativeSquareRoot) + } else { + Ok(x.sqrt()) + } + } + + fn ln(x: f64) -> MathResult { + if x < 0.0 { + Err(NegativeLogarithm) + } else { + Ok(x.ln()) + } + } + + // Intermediate function + fn op_(x: f64, y: f64) -> MathResult { + // if `div` "fails", then `DivisionByZero` will be `return`ed + let ratio = try!(div(x, y)); + + // if `ln` "fails", then `NegativeLogarithm` will be `return`ed + let ln = try!(ln(ratio)); + + sqrt(ln) + } + + pub fn op(x: f64, y: f64) { + match op_(x, y) { + Err(why) => fail!(match why { + NegativeLogarithm => "logarithm of negative number", + DivisionByZero => "division by zero", + NegativeSquareRoot => "square root of negative number", + }), + Ok(value) => println!("{}", value), + } + } +} + +fn main() { + checked::op(1.0, 10.0); +} diff --git a/examples/sockets/client.rs b/examples/sockets/client.rs index 19e0a7f2d0..947e8404ab 100644 --- a/examples/sockets/client.rs +++ b/examples/sockets/client.rs @@ -5,7 +5,7 @@ use std::os; mod common; fn main() { - // args: is an array of the arguments passed to the program + // `args` returns the arguments passed to the program let args = os::args(); let socket = Path::new(SOCKET_PATH); diff --git a/examples/sockets/input.md b/examples/sockets/input.md index d23c0c832d..be37cc8f40 100644 --- a/examples/sockets/input.md +++ b/examples/sockets/input.md @@ -1,5 +1,6 @@ Inter-Process Communication (IPC) for client-server applications can be -accomplished using UNIX sockets. +accomplished using +[UNIX sockets](http://en.wikipedia.org/wiki/Unix_domain_socket). Both client and server need to use the same path for the socket. diff --git a/examples/bench/bench.rs b/examples/staging/bench/bench.rs similarity index 100% rename from examples/bench/bench.rs rename to examples/staging/bench/bench.rs diff --git a/examples/bench/input.md b/examples/staging/bench/input.md similarity index 100% rename from examples/bench/input.md rename to examples/staging/bench/input.md diff --git a/examples/ffi/ffi.rs b/examples/staging/ffi/ffi.rs similarity index 100% rename from examples/ffi/ffi.rs rename to examples/staging/ffi/ffi.rs diff --git a/examples/ffi/input.md b/examples/staging/ffi/input.md similarity index 100% rename from examples/ffi/input.md rename to examples/staging/ffi/input.md diff --git a/examples/ffi/safe.rs b/examples/staging/ffi/safe.rs similarity index 100% rename from examples/ffi/safe.rs rename to examples/staging/ffi/safe.rs diff --git a/examples/macros/designators.rs b/examples/staging/macros/designators.rs similarity index 100% rename from examples/macros/designators.rs rename to examples/staging/macros/designators.rs diff --git a/examples/macros/dry.rs b/examples/staging/macros/dry.rs similarity index 100% rename from examples/macros/dry.rs rename to examples/staging/macros/dry.rs diff --git a/examples/macros/input.md b/examples/staging/macros/input.md similarity index 100% rename from examples/macros/input.md rename to examples/staging/macros/input.md diff --git a/examples/macros/overload.rs b/examples/staging/macros/overload.rs similarity index 100% rename from examples/macros/overload.rs rename to examples/staging/macros/overload.rs diff --git a/examples/macros/repeat.rs b/examples/staging/macros/repeat.rs similarity index 100% rename from examples/macros/repeat.rs rename to examples/staging/macros/repeat.rs diff --git a/examples/macros/simple.rs b/examples/staging/macros/simple.rs similarity index 100% rename from examples/macros/simple.rs rename to examples/staging/macros/simple.rs diff --git a/examples/rand/deriving.rs b/examples/staging/rand/deriving.rs similarity index 100% rename from examples/rand/deriving.rs rename to examples/staging/rand/deriving.rs diff --git a/examples/rand/distributions.rs b/examples/staging/rand/distributions.rs similarity index 100% rename from examples/rand/distributions.rs rename to examples/staging/rand/distributions.rs diff --git a/examples/rand/gen.rs b/examples/staging/rand/gen.rs similarity index 100% rename from examples/rand/gen.rs rename to examples/staging/rand/gen.rs diff --git a/examples/rand/input.md b/examples/staging/rand/input.md similarity index 100% rename from examples/rand/input.md rename to examples/staging/rand/input.md diff --git a/examples/simd/input.md b/examples/staging/simd/input.md similarity index 100% rename from examples/simd/input.md rename to examples/staging/simd/input.md diff --git a/examples/simd/simd.rs b/examples/staging/simd/simd.rs similarity index 100% rename from examples/simd/simd.rs rename to examples/staging/simd/simd.rs diff --git a/examples/simd/simd_add.rs b/examples/staging/simd/simd_add.rs similarity index 100% rename from examples/simd/simd_add.rs rename to examples/staging/simd/simd_add.rs diff --git a/examples/test/fail.rs b/examples/staging/test/fail.rs similarity index 100% rename from examples/test/fail.rs rename to examples/staging/test/fail.rs diff --git a/examples/test/input.md b/examples/staging/test/input.md similarity index 100% rename from examples/test/input.md rename to examples/staging/test/input.md diff --git a/examples/test/unit-test.rs b/examples/staging/test/unit-test.rs similarity index 100% rename from examples/test/unit-test.rs rename to examples/staging/test/unit-test.rs diff --git a/examples/unsafe/asm.rs b/examples/staging/unsafe/asm.rs similarity index 100% rename from examples/unsafe/asm.rs rename to examples/staging/unsafe/asm.rs diff --git a/examples/unsafe/input.md b/examples/staging/unsafe/input.md similarity index 100% rename from examples/unsafe/input.md rename to examples/staging/unsafe/input.md diff --git a/examples/unsafe/pointer.rs b/examples/staging/unsafe/pointer.rs similarity index 100% rename from examples/unsafe/pointer.rs rename to examples/staging/unsafe/pointer.rs diff --git a/examples/unsafe/transmute.rs b/examples/staging/unsafe/transmute.rs similarity index 100% rename from examples/unsafe/transmute.rs rename to examples/staging/unsafe/transmute.rs diff --git a/examples/str/input.md b/examples/str/input.md index 7a4ca00102..fb427e4426 100644 --- a/examples/str/input.md +++ b/examples/str/input.md @@ -1,6 +1,6 @@ There are two types of strings in Rust: `String` and `&str`. -A `String` is stored as a collection of bytes (`Vec`), but guaranteed to +A `String` is stored as a vector of bytes (`Vec`), but guaranteed to always be a valid UTF-8 sequence. `String` is heap allocated, growable and not null terminated. diff --git a/examples/str/str.rs b/examples/str/str.rs index 74aa10207c..d5facecbe4 100644 --- a/examples/str/str.rs +++ b/examples/str/str.rs @@ -1,37 +1,37 @@ fn main() { // (all the type annotations are superfluous) - // a reference to a string allocated in read only memory + // A reference to a string allocated in read only memory let pangram: &'static str = "the quick brown fox jumps over the lazy dog"; - println!("pangram: {}", pangram); + println!("Pangram: {}", pangram); - // iterate over words in reverse, no new string is allocated - println!("words in reverse"); + // Iterate over words in reverse, no new string is allocated + println!("Words in reverse"); for word in pangram.words().rev() { - println!("{}", word); + println!("> {}", word); } - // copy chars into a vector, sort and remove duplicates + // Copy chars into a vector, sort and remove duplicates let mut chars: Vec = pangram.chars().collect(); chars.sort(); chars.dedup(); - // a growable `String` - let mut string: String = String::new(); + // Create an empty and growable `String` + let mut string = String::new(); for c in chars.move_iter() { - // insert a char at the end of string + // Insert a char at the end of string string.push_char(c); - // insert a string at the end of string + // Insert a string at the end of string string.push_str(", "); } - // the trimmed string is a slice to the original string, hence - // no new allocation is performed + // The trimmed string is a slice to the original string, hence no new + // allocation is performed let trimmed_str: &str = string.as_slice().trim_chars(&[',', ' ']); - println!("used characters: {}", trimmed_str); + println!("Used characters: {}", trimmed_str); - // heap allocate a string + // Heap allocate a string let alice = String::from_str("I like dogs"); - // allocate new memory and store the modified string there + // Allocate new memory and store the modified string there let bob: String = alice.replace("dog", "cat"); println!("Alice says: {}", alice); diff --git a/examples/structs/input.md b/examples/structs/input.md index 8586c53f5b..68511d5d09 100644 --- a/examples/structs/input.md +++ b/examples/structs/input.md @@ -1,11 +1,8 @@ -Rust allows the declaration of three types of structs using the `struct` -keyword: +There are three types of structures ("structs") that can be created using the +`struct` keyword: -* tuple structs, basically named tuples -* structs, like tuple structs but the internal values are named and called - fields -* unit structs, a struct without fields - -The syntax is shown below. +* Tuple structs, which are, basically, named tuples. +* The classic [C structs](http://en.wikipedia.org/wiki/Struct_(C_programming_language) +* Unit structs, which are field-less structs. {structs.play} diff --git a/examples/structs/structs.rs b/examples/structs/structs.rs index 9509cbb9a9..10e194ee0f 100644 --- a/examples/structs/structs.rs +++ b/examples/structs/structs.rs @@ -1,44 +1,45 @@ -// unit struct +// A unit struct struct Nil; -// tuple struct +// A tuple struct struct Pair(int, f64); -// a struct with two fields +// A struct with two fields struct Point { x: f64, y: f64, } -// reusing structs as fields +// Structs can be reused as fields of another struct +#[allow(dead_code)] struct Rectangle { p1: Point, p2: Point, } fn main() { - // instantiate a Point + // Instantiate a `Point` let point: Point = Point { x: 0.3, y: 0.4 }; - // access fields + // Access the fields of the point println!("point coordinates: ({}, {})", point.x, point.y); - // destructuring using let + // Destructure the point using a `let` binding let Point { x: my_x, y: my_y } = point; - let rectangle = Rectangle { - // structs are expressions too + let _rectangle = Rectangle { + // struct instantiation is an expression too p1: Point { x: my_y, y: my_x }, - p2: point + p2: point, }; - // instantiate a unit struct - let nil = Nil; + // Instantiate a unit struct + let _nil = Nil; - // instantiate a tuple struct + // Instantiate a tuple struct let pair = Pair(1, 0.1); - // destructure a tuple struct + // Destructure a tuple struct let Pair(integer, decimal) = pair; println!("pair contains {} and {}", integer, decimal); diff --git a/examples/structs/visibility/input.md b/examples/structs/visibility/input.md new file mode 100644 index 0000000000..20febe2b34 --- /dev/null +++ b/examples/structs/visibility/input.md @@ -0,0 +1,6 @@ +Structs have an extra level of visibility, their fields can be public or +private (which is the default). This visibility only matters when +structs are accessed from outside the module where they are defined, and its +goal is information hiding (encapsulation). + +{struct.play} diff --git a/examples/mod/structs.rs b/examples/structs/visibility/struct.rs similarity index 56% rename from examples/mod/structs.rs rename to examples/structs/visibility/struct.rs index 66e14c0193..e064d80d3e 100644 --- a/examples/mod/structs.rs +++ b/examples/structs/visibility/struct.rs @@ -1,16 +1,17 @@ mod my { - // a public struct with public fields + // A public struct with public fields pub struct WhiteBox { pub contents: T, } - // a public struct with private fields + // A public struct with private fields + #[allow(dead_code)] pub struct BlackBox { contents: T, } impl BlackBox { - // a public constructor + // A public constructor pub fn new(contents: T) -> BlackBox { BlackBox { contents: contents, @@ -20,21 +21,23 @@ mod my { } fn main() { - // public structs with public fields can be constructed as usual + // Public structs with public fields can be constructed as usual let white_box = my::WhiteBox { contents: "public information" }; // and their fields can be normally accessed println!("The white box contains: {}", white_box.contents); // but public structs with private fields can't be constructed - // Error: BlackBox has private fields + // Error! `BlackBox` has private fields //let black_box = my::BlackBox { contents: "classified information" }; + // TODO ^ Try uncommenting this line - // however, structs with private fields can still be created using + // However, structs with private fields can still be created using // constructors - let black_box = my::BlackBox::new("classified information"); + let _black_box = my::BlackBox::new("classified information"); - // the private fields of a struct can't be accessed - // Error: the contents field is private + // The private fields of a struct can't be accessed + // Error! The `contents` field is private //println!("The black box contains: {}", black_box.contents); + // TODO ^ Try uncommenting this line } diff --git a/examples/structure.json b/examples/structure.json new file mode 100644 index 0000000000..29313c2e27 --- /dev/null +++ b/examples/structure.json @@ -0,0 +1,122 @@ +[ + { "id": "hello", "title": "Hello World", "children": null }, + { "id": "print", "title": "Formatted print", "children": null }, + { "id": "literals", "title": "Literals and operators", "children": null }, + { "id": "variables", "title": "Variables", "children": [ + { "id": "mut", "title": "Mutability", "children": null }, + { "id": "scope", "title": "Scope and shadowing", "children": null }, + { "id": "declare", "title": "Declare first", "children": null } + ] }, + { "id": "type", "title": "Types", "children": [ + { "id": "cast", "title": "Casting", "children": null }, + { "id": "literals", "title": "Literals", "children": null }, + { "id": "inference", "title": "Inference", "children": null }, + { "id": "alias", "title": "Alias", "children": null } + ] }, + { "id": "expression", "title": "Expressions", "children": null }, + { "id": "if-else", "title": "If/else", "children": null }, + { "id": "loop", "title": "Loop", "children": [ + { "id": "nested", "title": "Nesting and labels", "children": null } + ] }, + { "id": "while", "title": "While", "children": null }, + { "id": "for", "title": "For and range", "children": null }, + { "id": "fn", "title": "Functions", "children": [ + { "id": "unused", "title": "Unused", "children": null } + ] }, + { "id": "mod", "title": "Modules", "children": [ + { "id": "visibility", "title": "Visibility", "children": null }, + { "id": "use", "title": "The `use` import", "children": null }, + { "id": "super", "title": "`super` and `self`", "children": null }, + { "id": "split", "title": "File hierarchy", "children": null } + ] }, + { "id": "crates", "title": "Crates", "children": [ + { "id": "lib", "title": "Library", "children": null }, + { "id": "link", "title": "`extern crate`", "children": null } + ] }, + { "id": "attribute", "title": "Attributes", "children": [ + { "id": "crate", "title": "Crates", "children": null }, + { "id": "cfg", "title": "`cfg`", "children": [ + { "id": "custom", "title": "Custom", "children": null } + ] } + ] }, + { "id": "tuples", "title": "Tuples", "children": null }, + { "id": "match", "title": "Pattern matching", "children": [ + { "id": "guard", "title": "Destructuring and guards", "children": null } + ] }, + { "id": "structs", "title": "Structures", "children": [ + { "id": "visibility", "title": "Visibility", "children": null } + ] }, + { "id": "generics", "title": "Generics", "children": null }, + { "id": "box", "title": "Box, stack and heap", "children": null }, + { "id": "raii", "title": "RAII", "children": null }, + { "id": "move", "title": "Ownership and moves", "children": [ + { "id": "mut", "title": "Mutability", "children": null } + ] }, + { "id": "borrow", "title": "Borrowing", "children": [ + { "id": "mut", "title": "Mutability", "children": null }, + { "id": "freeze", "title": "Freezing", "children": null }, + { "id": "alias", "title": "Aliasing", "children": null }, + { "id": "ref", "title": "The ref pattern", "children": null } + ] }, + { "id": "lifetime", "title": "Lifetimes", "children": null }, + { "id": "constants", "title": "Global constants", "children": null }, + { "id": "methods", "title": "Methods", "children": null }, + { "id": "enum", "title": "Enums", "children": [ + { "id": "c-like", "title": "C-like", "children": null } + ] }, + { "id": "fail", "title": "`fail!`", "children": null }, + { "id": "option", "title": "`Option`", "children": null }, + { "id": "array", "title": "Arrays and Slices", "children": null }, + { "id": "trait", "title": "Traits", "children": [ + { "id": "deriving", "title": "Deriving", "children": null } + ] }, + { "id": "ops", "title": "Operator Overloading", "children": null }, + { "id": "bounds", "title": "Bounds", "children": null }, + { "id": "drop", "title": "Drop", "children": null }, + { "id": "iter", "title": "Iterators", "children": null }, + { "id": "closures", "title": "Closures", "children": null }, + { "id": "hof", "title": "Higher Order Functions", "children": null }, + { "id": "vec", "title": "Vectors", "children": null }, + { "id": "str", "title": "Strings", "children": null }, + { "id": "clone", "title": "Clone", "children": null }, + { "id": "tasks", "title": "Tasks", "children": null }, + { "id": "channels", "title": "Channels", "children": null }, + { "id": "timers", "title": "Timers", "children": null }, + { "id": "sockets", "title": "Unix sockets", "children": null }, + { "id": "result", "title": "`Result`", "children": [ + { "id": "try", "title": "`try!`", "children": null } + ] }, + { "id": "path", "title": "Path", "children": null }, + { "id": "file", "title": "File I/O", "children": [ + { "id": "open", "title": "`open`", "children": null }, + { "id": "create", "title": "`create`", "children": null } + ] }, + { "id": "process", "title": "Child processes", "children": [ + { "id": "pipe", "title": "Pipes", "children": null }, + { "id": "wait", "title": "Wait", "children": null } + ] }, + { "id": "fs", "title": "Filesystem Operations", "children": null }, + { "id": "staging", "title": "Staging Area", "children": [ + { "id": "bench", "title": "Benchmarking", "children": null }, + { "id": "ffi", "title": "Foreign Function Interface", "children": null }, + { "id": "macros", "title": "macro_rules!", "children": null }, + { "id": "rand", "title": "Random", "children": null }, + { "id": "simd", "title": "SIMD", "children": null }, + { "id": "test", "title": "Testing", "children": null }, + { "id": "unsafe", "title": "Unsafe operations", "children": null } + ] }, + { "id": "todo", "title": "TODO", "children": [ + { "id": "arg", "title": "Program arguments", "children": null }, + { "id": "assert", "title": "assert! and debug_assert!", "children": null }, + { "id": "comment", "title": "Comments", "children": null }, + { "id": "green", "title": "Green threads", "children": null }, + { "id": "hash", "title": "Hasher and Hashmap", "children": null }, + { "id": "json", "title": "JSON parsing", "children": null }, + { "id": "log", "title": "Logging", "children": null }, + { "id": "rc", "title": "Reference counting", "children": null }, + { "id": "regex", "title": "Regex", "children": null }, + { "id": "rustdoc", "title": "rustdoc", "children": null }, + { "id": "select", "title": "select!", "children": null }, + { "id": "stdio", "title": "Standard I/O", "children": null } + ] } +] diff --git a/examples/tasks/tasks.rs b/examples/tasks/tasks.rs index d5a2751b43..d1cafaaf63 100644 --- a/examples/tasks/tasks.rs +++ b/examples/tasks/tasks.rs @@ -1,8 +1,9 @@ static NTASKS: int = 10; +// This is the `main` task fn main() { for i in range(0, NTASKS) { - // spin up a task + // Spin up another task spawn(proc() { println!("this is task number {}", i) }); diff --git a/examples/timers/input.md b/examples/timers/input.md index 5e60b60a24..1cf24cd382 100644 --- a/examples/timers/input.md +++ b/examples/timers/input.md @@ -1,5 +1,23 @@ -Rust provides timers in two flavors: `oneshot` for a single use and `periodic` -to receive notifications over time. These timers provide the `Receiver` part of -a channel and will block the task until they timeout. +A `Timer` represents an underlying OS timer, and can generate *one-shot* and +*periodic* notifications via the `Receiver` endpoint of a channel. -{timers.rs} +{timers.play} + +The playpen has a time limit, so you won't be able to see the (full) output in +the editor. Here's the output you should see, if you run this in a computer. + +``` +$ rustc timers.rs && time ./timers +Wait 1000 ms... +Done +Sleep for 1000 ms... +Done +Countdown +5 +4 +3 +2 +1 +Ignition! +./timers 0.00s user 0.00s system 0% cpu 8.003 total +``` diff --git a/examples/timers/timers.rs b/examples/timers/timers.rs index dca78c3b86..cc4ee0dc7a 100644 --- a/examples/timers/timers.rs +++ b/examples/timers/timers.rs @@ -1,27 +1,42 @@ -use std::io::timer::Timer; +use std::io::Timer; +use std::io::timer; +use std::iter; + +static INTERVAL: u64 = 1000; fn main() { - // create a timer object + // Create a timer object let mut timer = Timer::new().unwrap(); - // create a one shot notification (type annotation is superfluous) - let oneshot: Receiver<()> = timer.oneshot(3000); + // Create a one-shot notification + // (superfluous type annotation) + let oneshot: Receiver<()> = timer.oneshot(INTERVAL); - println!("hold on..."); + println!("Wait {} ms...", INTERVAL); - // block the task until timeout + // Block the task until notification arrives oneshot.recv(); - // the same timer can be used to generate periodic notifications - let metronome = timer.periodic(1000); + println!("Done"); + + println!("Sleep for {} ms...", INTERVAL); + + // This is equivalent to `timer.oneshot(INTERVAL).recv()` + timer::sleep(INTERVAL); + + println!("Done"); + + // The same timer can be used to generate periodic notifications + // (superfluous type annotation) + let metronome: Receiver<()> = timer.periodic(INTERVAL); - let mut count = 0; - println!("Start counting"); - loop { - // loop will run once every second + println!("Countdown"); + for i in iter::range_step(5, 0, -1) { + // This loop will run once every second metronome.recv(); - count += 1; - println!("{}", count); + println!("{}", i); } + metronome.recv(); + println!("Ignition!"); } diff --git a/examples/trait/deriving.rs b/examples/trait/deriving.rs deleted file mode 100644 index f9cbf4799d..0000000000 --- a/examples/trait/deriving.rs +++ /dev/null @@ -1,41 +0,0 @@ -// a tuple struct that can be compared -#[deriving(PartialEq, PartialOrd)] -struct Centimeters(f64); - -// a tuple struct that can be printed -#[deriving(Show)] -struct Inches(int); - -impl Inches { - fn to_centimeters(&self) -> Centimeters { - let &Inches(inches) = self; - - Centimeters(inches as f64 * 2.54) - } -} - -// a vanilla tuple struct -struct Seconds(int); - -fn main() { - let one_second = Seconds(1); - let another_second = Seconds(1); - - // Error: Seconds can't be printed (doesn't implement the Show trait) - //println!("{}", one_second); - - // Error: Seconds can't be compared - //let this_is_true = one_second == another_second; - - let foot = Inches(12); - - println!("{}", foot); - - let meter = Centimeters(100.0); - - if foot.to_centimeters() < meter { - println!("a foot is smaller than a meter") - } else { - println!("a foot is bigger than a meter") - } -} diff --git a/examples/trait/deriving/deriving.rs b/examples/trait/deriving/deriving.rs new file mode 100644 index 0000000000..7b2bd9abf9 --- /dev/null +++ b/examples/trait/deriving/deriving.rs @@ -0,0 +1,47 @@ +// A tuple struct that can be compared +#[deriving(PartialEq, PartialOrd)] +struct Centimeters(f64); + +// A tuple struct that can be printed +#[deriving(Show)] +struct Inches(int); + +impl Inches { + fn to_centimeters(&self) -> Centimeters { + let &Inches(inches) = self; + + Centimeters(inches as f64 * 2.54) + } +} + +// A vanilla tuple struct +struct Seconds(int); + +fn main() { + let _one_second = Seconds(1); + + // Error! `Seconds` can't be printed, because it doesn't implement the + // `Show` trait + //println!("One second looks like: {}", _one_second); + // TODO ^ Try uncommenting this line + + // Error: `Seconds` can't be compared, because it doesn't implement the + // `PartialEq` trait + //let _this_is_true = _one_second == _one_second; + // TODO ^ Try uncommenting this line + + let foot = Inches(12); + + println!("One foot === {}", foot); + + let meter = Centimeters(100.0); + + let cmp = + if foot.to_centimeters() < meter { + "smaller" + } else { + "bigger" + }; + + println!("one foot is {} than one meter", cmp); +} diff --git a/examples/trait/deriving/input.md b/examples/trait/deriving/input.md new file mode 100644 index 0000000000..161ca8f8f2 --- /dev/null +++ b/examples/trait/deriving/input.md @@ -0,0 +1,29 @@ +The compiler is capable of providing basic implementations for some traits via +the `#[deriving]` [attribute](/attribute.html). These traits can still be +manually implemented if a more complex behavior is required. + +{deriving.play} + +This is a list of the "derivable" traits: +* Comparison traits: + [`Eq`](http://static.rust-lang.org/doc/master/std/cmp/trait.Eq.html), + [`PartialEq`](http://static.rust-lang.org/doc/master/std/cmp/trait.PartialEq.html), + [`Ord`](http://static.rust-lang.org/doc/master/std/cmp/trait.Ord.html), + [`PartialOrd`](http://static.rust-lang.org/doc/master/std/cmp/trait.PartialOrd.html) +* Serialization: + [`Encodable`](http://static.rust-lang.org/doc/master/serialize/trait.Encodable.html), + [`Decodable`](http://static.rust-lang.org/doc/master/serialize/trait.Decodable.html) +* [`Clone`](http://static.rust-lang.org/doc/master/std/clone/trait.Clone.html), + to create `T` from `&T` via a copy. +* [`Hash`](http://static.rust-lang.org/doc/master/std/hash/trait.Hash.html), to + compute a hash from `&T`. +* [`Rand`](http://static.rust-lang.org/doc/master/rand/trait.Rand.html), to + create a random instance of a data type. +* [`Default`](http://static.rust-lang.org/doc/master/std/default/trait.Default.html), + to create an empty instance of a data type. +* [`Zero`](http://static.rust-lang.org/doc/master/std/num/trait.Zero.html), to + create a zero instance of a numeric data type. +* [`FromPrimitive`](http://static.rust-lang.org/doc/master/std/num/trait.FromPrimitive.html), + to create an instance from a numeric primitive. +* [`Show`](http://static.rust-lang.org/doc/master/std/fmt/trait.Show.html), to + format a value using the `{}` formatter. diff --git a/examples/trait/input.md b/examples/trait/input.md index 29aec594e6..a47bb8bbf8 100644 --- a/examples/trait/input.md +++ b/examples/trait/input.md @@ -1,37 +1,4 @@ -A `trait` is a collection of methods defined for an unknown type. A trait -can be implemented for any data type. When some instances implement the same -trait, they can be grouped in an array since they provide the same interface. +A `trait` is a collection of methods declared/defined for an unknown type: +`Self`. Traits can be implemented for any data type. {trait.play} - -The compiler is capable of providing basic implementations for some traits via -the `#[deriving]` attribute. These traits can still be manually implemented if -a more complex behavior is required. - -{deriving.rs} - -{deriving.out} - -This is a list of the "derivable" traits: -* Comparison traits: - [`Eq`](http://static.rust-lang.org/doc/master/std/cmp/trait.Eq.html), - [`TotalEq`](http://static.rust-lang.org/doc/master/std/cmp/trait.TotalEq.html), - [`Ord`](http://static.rust-lang.org/doc/master/std/cmp/trait.Ord.html), - [`TotalOrd`](http://static.rust-lang.org/doc/master/std/cmp/trait.TotalOrd.html) -* Serialization: - [`Encodable`](http://static.rust-lang.org/doc/master/serialize/trait.Encodable.html), - [`Decodable`](http://static.rust-lang.org/doc/master/serialize/trait.Decodable.html) -* [`Clone`](http://static.rust-lang.org/doc/master/std/clone/trait.Clone.html), - to create `T` from `&T` via a copy. -* [`Hash`](http://static.rust-lang.org/doc/master/std/hash/trait.Hash.html), to - compute a hash from `&T`. -* [`Rand`](http://static.rust-lang.org/doc/master/rand/trait.Rand.html), to - create a random instance of a data type. -* [`Default`](http://static.rust-lang.org/doc/master/std/default/trait.Default.html), - to create an empty instance of a data type. -* [`Zero`](http://static.rust-lang.org/doc/master/std/num/trait.Zero.html), to - create a zero instance of a numeric data type. -* [`FromPrimitive`](http://static.rust-lang.org/doc/master/std/num/trait.FromPrimitive.html), - to create an instance from a numeric primitive. -* [`Show`](http://static.rust-lang.org/doc/master/std/fmt/trait.Show.html), to - format a value using the `{}` formatter. diff --git a/examples/trait/trait.rs b/examples/trait/trait.rs index aa922a16a8..bd9e02c070 100644 --- a/examples/trait/trait.rs +++ b/examples/trait/trait.rs @@ -1,72 +1,53 @@ -struct Dog { - name: String, -} - -struct Sheep { - naked: bool, - name: String, -} - -// traits are collections of methods trait Animal { - // static method, Self refers to the implementor type - fn new(name: String) -> Self; + // Static method signature; `Self` refers to the implementor type + fn new(name: &'static str) -> Self; - // instance methods, only signatures - fn name<'a>(&'a self) -> &'a str; + // Instance methods, only signatures + fn name(&self) -> &'static str; fn noise(&self) -> &'static str; - // trait can provide method definitions + // A trait can provide default method definitions fn talk(&self) { - // trait method can access methods available in the same trait + // These definitions can access other methods declared in the same + // trait println!("{} says {}", self.name(), self.noise()); } } -// implement the Animal trait for the Dog struct -impl Animal for Dog { - // replace Self with implementor type (i.e. Dog) - fn new(name: String) -> Dog { - Dog { name: name } - } - - fn name<'a>(&'a self) -> &'a str { - self.name.as_slice() - } +struct Dog { name: &'static str } - fn noise(&self) -> &'static str { - "woof" - } -} - -// exclusive methods for Dogs impl Dog { fn wag_tail(&self) { - // struct methods can access trait methods - println!("{} wags tail", self.name()); + println!("{} wags tail", self.name); } } -impl Animal for Sheep { - fn new(name: String) -> Sheep { - Sheep { name: name, naked: false } +// Implement the `Animal` trait for `Dog` +impl Animal for Dog { + // Replace `Self` with the implementor type: `Dog` + fn new(name: &'static str) -> Dog { + Dog { name: name } } - fn name<'a>(&'a self) -> &'a str { - self.name.as_slice() + fn name(&self) -> &'static str { + self.name } fn noise(&self) -> &'static str { - // implemented traits methods can access struct methods - if self.is_naked() { - "baaah!" - } else { - "baaaaaaaaaaaah!" - } + "woof!" + } + + // Default trait methods can be overridden + fn talk(&self) { + // Traits methods can access the implementor methods + self.wag_tail(); + + println!("{} says {}", self.name, self.noise()); } } -// exclusive methods for Sheeps +struct Sheep { naked: bool, name: &'static str } + impl Sheep { fn is_naked(&self) -> bool { self.naked @@ -74,30 +55,43 @@ impl Sheep { fn shear(&mut self) { if self.is_naked() { + // Implementor methods can use the implementor's trait methods println!("{} is already naked!", self.name()); } else { - println!("{} gets a haircut", self.name()); + println!("{} gets a haircut", self.name); + self.talk(); self.naked = true; } } } -fn main() { - let mut dolly: Sheep = Animal::new(String::from_str("Dolly")); - let spike: Dog = Animal::new(String::from_str("Spike")); +impl Animal for Sheep { + fn new(name: &'static str) -> Sheep { + Sheep { name: name, naked: false } + } - spike.wag_tail(); - dolly.shear(); + fn name(&self) -> &'static str { + self.name + } + + fn noise(&self) -> &'static str { + if self.is_naked() { + "baaah" + } else { + "baaaaaaaaaaaah" + } + } +} - // dolly and spike can be borrowed as &Animal - let animals: [&Animal, ..2] = [&spike as &Animal, &dolly as &Animal]; +fn main() { + // Type annotation is necessary in this case + let mut dolly: Sheep = Animal::new("Dolly"); + let spike: Dog = Animal::new("Spike"); + // TODO ^ Try removing the type annotations - // Ok: Animal methods can be called on the array members - animals[0].talk(); - animals[1].talk(); + dolly.shear(); - // Error: Dog and Sheep methods can't be accessed via the Animal trait - //animals[0].wag_tail(); - //animals[1].shear(); + spike.talk(); + dolly.talk(); } diff --git a/examples/tuples/tuples.rs b/examples/tuples/tuples.rs index 95ef4b12b6..5df30b229b 100644 --- a/examples/tuples/tuples.rs +++ b/examples/tuples/tuples.rs @@ -1,4 +1,4 @@ -// tuples can be used as function arguments and as return values +// Tuples can be used as function arguments and as return values fn reverse(pair: (int, bool)) -> (bool, int) { // `let` can be used to bind the members of a tuple to variables let (integer, boolean) = pair; @@ -7,27 +7,29 @@ fn reverse(pair: (int, bool)) -> (bool, int) { } fn main() { - // a tuple with a bunch of different types + // A tuple with a bunch of different types let long_tuple = (1u8, 2u16, 3u32, 4u64, -1i8, -2i16, -3i32, -4i64, 0.1f32, 0.2f64, 'a', true); - // values can be extracted from the tuple using the valN methods + // Values can be extracted from the tuple using the `valN` methods println!("long tuple first value: {}", long_tuple.val0()); println!("long tuple second value: {}", long_tuple.val1()); - // tuples can be tuple members + // Tuples can be tuple members let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16); - // tuples are printable + // Tuples are printable + println!("tuple of tuples: {}", tuple_of_tuples); + let pair = (1, true); println!("pair is {}", pair); println!("the reversed pair is {}", reverse(pair)); - // to create one element tuples, the comma is required to tell them - // apart from a literal surrounded by parentheses + // To create one element tuples, the comma is required to tell them apart + // from a literal surrounded by parentheses println!("one element tuple: {}", (5,)) println!("just an integer: {}", (5)) } diff --git a/examples/type/alias/alias.rs b/examples/type/alias/alias.rs new file mode 100644 index 0000000000..3d5bd0fb9f --- /dev/null +++ b/examples/type/alias/alias.rs @@ -0,0 +1,21 @@ +// `NanoSecond` is a new name for `u64` +type NanoSecond = u64; +type Inch = u64; + +// Use an attribute to silence warning +#[allow(non_camel_case_types)] +type uint64_t = u64; +// TODO ^ Try removing the attribute + +fn main() { + // `NanoSecond` = `Inch` = `uint64_t` = `u64` + let nanoseconds: NanoSecond = 5 as uint64_t; + let inches: Inch = 2 as uint64_t; + + // Note that type aliases *don't* provide any extra type safety, because + // aliases are *not* new types + println!("{} nanoseconds + {} inches = {} unit?", + nanoseconds, + inches, + nanoseconds + inches); +} diff --git a/examples/type/alias/input.md b/examples/type/alias/input.md new file mode 100644 index 0000000000..0a92b56676 --- /dev/null +++ b/examples/type/alias/input.md @@ -0,0 +1,9 @@ +The `type` statement can be used to give a new name to an existing type. Types +must have `CamelCase` names, or the compiler will raise a warning. The +exception to this rule are the primitive types: `uint`, `f32`, etc. + +{alias.play} + +The main use of aliases is to reduce typing, for example the +[`IoResult`](http://static.rust-lang.org/doc/master/std/io/type.IoResult.html) +type is an alias for the `Result` type. diff --git a/examples/type/cast/cast.rs b/examples/type/cast/cast.rs new file mode 100644 index 0000000000..cca000bb50 --- /dev/null +++ b/examples/type/cast/cast.rs @@ -0,0 +1,13 @@ +fn main() { + let decimal = 65.4321; + + // Error! No implicit conversion + let integer: u8 = decimal; + // FIXME ^ Comment out this line + + // Explicit conversion + let integer = decimal as u8; + let character = integer as char; + + println!("Casting: {} -> {} -> {}", decimal, integer, character); +} diff --git a/examples/type/cast/input.md b/examples/type/cast/input.md new file mode 100644 index 0000000000..7a792d4ee5 --- /dev/null +++ b/examples/type/cast/input.md @@ -0,0 +1,4 @@ +Rust provides no implicit type conversion (coercion) between primitive types. +But, explicit type conversion (casting) can be achieved using the `as` keyword. + +{cast.play} diff --git a/examples/type/inference.rs b/examples/type/inference.rs deleted file mode 100644 index fc847872a6..0000000000 --- a/examples/type/inference.rs +++ /dev/null @@ -1,13 +0,0 @@ -fn main() { - // By local inference, the compiler knows that the type of `e` is uint - let e = 5u; - - // Create an empty vector (a growable array) - let mut v = Vec::new(); - // At this point the compiler doesn't know the exact type of `v`, it - // just knows that it's a vector of something - - // Insert `e` in the vector - v.push(e); - // Aha! Now the compiler knows that `v` is a vector of uints. -} diff --git a/examples/type/inference/inference.rs b/examples/type/inference/inference.rs new file mode 100644 index 0000000000..54131a2e38 --- /dev/null +++ b/examples/type/inference/inference.rs @@ -0,0 +1,16 @@ +fn main() { + // Using local inference, the compiler knows that `elem` has type u8 + let elem = 5u8; + + // Create an empty vector (a growable array) + let mut vec = Vec::new(); + // At this point the compiler doesn't know the exact type of `vec`, it + // just knows that it's a vector of something (`Vec<_>`) + + // Insert `elem` in the vector + vec.push(elem); + // Aha! Now the compiler knows that `vec` is a vector of `u8`s (`Vec`) + // TODO ^ Try commenting out the `vec.push(elem)` line + + println!("{}", vec); +} diff --git a/examples/type/inference/input.md b/examples/type/inference/input.md new file mode 100644 index 0000000000..9e2be8c289 --- /dev/null +++ b/examples/type/inference/input.md @@ -0,0 +1,9 @@ +The type inference engine is pretty smart. It does more than looking at the +type of the r-value during an initialization. It also looks how the variable is +used afterwards to infer its type. Here's an advanced example of type +inference: + +{inference.play} + +No type annotation of variables was needed, the compiler is happy and so is the +programmer! diff --git a/examples/type/input.md b/examples/type/input.md index 86ebe6f132..7920fb803f 100644 --- a/examples/type/input.md +++ b/examples/type/input.md @@ -1,21 +1,15 @@ Rust provides type safety via its static type-checker. Variables can be type -annotated using a colon `:` after the variable name in the `let` statement, -however in most cases the compiler will be able to infer the type of the -variable from the context, heavily reducing the annotation burden. - -Type conversion (a.k.a. casting) must be explicitly stated using the `as` -keyword. +annotated when declared. However, in most cases, the compiler will be able to +infer the type of the variable from the context, heavily reducing the +annotation burden. {type.play} -The type inference engine is pretty smart, it does more than looking at the -type of the rvalue of an initialization; it also looks how the variable is used -afterwards to infer its type. Here's an advanced example of type inference: - -{inference.rs} - -(You are encouraged to try the previous code with the `v.push` line commented -out) +This is a summary of the primitive types in Rust: -No type annotation of variables was needed, the compiler is happy and so is the -programmer! +* signed integers: `i8`, `i16`, `i32`, `i64` and `int` (machine word size) +* unsigned integers: `u8`, `u16`, `u32`, `u64` and `uint` (machine word size) +* floating point: `f32`, `f64` +* `char` Unicode scalar values like `'a'`, `'α'` and `'∞'` (4 bytes each) +* `bool` either `true` or `false` +* and the unit type `()`, whose only value is also `()` diff --git a/examples/type/literals/input.md b/examples/type/literals/input.md new file mode 100644 index 0000000000..ea8f4959f1 --- /dev/null +++ b/examples/type/literals/input.md @@ -0,0 +1,20 @@ +Numeric literals can be type annotated by adding the type as a suffix, with the +exception of `uint` that uses the `u` suffix and `int` that uses the `i` +suffix. + +The type of unsuffixed literals will depend on how they are used. If no +constraint exists, integer literals will default to `int`, and floating point +literals will default to `f64` . + +{literals.play} + +There are some concepts used in the previous code that haven't been explained +yet, here's a brief explanation for the impatient readers: + +* `fun(&foo)` is used to pass an argument to a function *by reference*, rather + than by value (`fun(foo)`). For more details see [borrowing](/borrow.html). +* `std::mem::size_of_val` is a function, but called with its *full path*. Code + can be splitted in logical units called *modules*. In this case the + `size_of_val` function is defined in the `mem` module, and the `mem` module + is defined in the `std` *crate*. For more details see + [modules](/modules.html) and [crates](/crates.html). diff --git a/examples/type/literals/literals.rs b/examples/type/literals/literals.rs new file mode 100644 index 0000000000..36e722f4e1 --- /dev/null +++ b/examples/type/literals/literals.rs @@ -0,0 +1,22 @@ +fn main() { + // Suffixed literals, their types is known at initialization + let x = 1u8; + let y = 2u; + let z = 3f32; + + // Unsuffixed literal, their types depend on how they are used + let i = 1; + let f = 1.0; + + // `size_of_val` returns the size of a variable in bytes + println!("size of `x` in bytes: {}", std::mem::size_of_val(&x)); + println!("size of `y` in bytes: {}", std::mem::size_of_val(&y)); + println!("size of `z` in bytes: {}", std::mem::size_of_val(&z)); + println!("size of `i` in bytes: {}", std::mem::size_of_val(&i)); + println!("size of `f` in bytes: {}", std::mem::size_of_val(&f)); + + // Constraints (summands must have the same type) for `i` and `f` + let _constraint_1 = x + i; + let _constraint_2 = z + f; + // TODO ^ Try commenting out these two lines +} diff --git a/examples/type/type.rs b/examples/type/type.rs index 7adad78d9d..b064bf62e0 100644 --- a/examples/type/type.rs +++ b/examples/type/type.rs @@ -1,8 +1,10 @@ fn main() { - // All the type annotations are superfluous - let decimal: f32 = 65.4321; - let integer: u8 = decimal as u8; - let character: char = integer as char; + // Type annotated variable + let a_float: f64 = 1.0; - println!("Casting: {} -> {} -> {}", decimal, integer, character); + // This variable is an `int`, the compiler can infer the type for us + let mut an_integer = 5; + + // Error! The type of a variable can't be changed + an_integer = true; } diff --git a/examples/variables/declare.rs b/examples/variables/declare.rs deleted file mode 100644 index 8bacb523a3..0000000000 --- a/examples/variables/declare.rs +++ /dev/null @@ -1,11 +0,0 @@ -fn main() { - // variable declaration - let declared_variable; - - // initialize variable - declared_variable = 3; - - // usage of uninitialized variable is forbidden - let uninitialized_variable: int; - println!("{}", uninitialized_variable); -} diff --git a/examples/variables/declare/declare.rs b/examples/variables/declare/declare.rs new file mode 100644 index 0000000000..e2e0c06537 --- /dev/null +++ b/examples/variables/declare/declare.rs @@ -0,0 +1,23 @@ +fn main() { + // Declare a variable + let a_variable; + + { + let x = 2; + + // Initialize the variable + a_variable = x * x; + } + + println!("a variable: {}", a_variable); + + let another_variable; + + // Error! Use of uninitialized variable + println!("another variable: {}", another_variable); + // FIXME ^ Comment out this line + + another_variable = 1; + + println!("another variable: {}", another_variable); +} diff --git a/examples/variables/declare/input.md b/examples/variables/declare/input.md new file mode 100644 index 0000000000..2bad0e6677 --- /dev/null +++ b/examples/variables/declare/input.md @@ -0,0 +1,7 @@ +It's possible to declare variables first, and initialize them later. But, this +form is seldom used, as it may lead to the use of uninitialized variables. + +{declare.play} + +The compiler forbids use of uninitialized variables, as this would lead to +undefined behavior. diff --git a/examples/variables/input.md b/examples/variables/input.md index 0c63b62f4d..22358bb6cf 100644 --- a/examples/variables/input.md +++ b/examples/variables/input.md @@ -1,14 +1,3 @@ -Variables in Rust are declared using the `let` keyword. Variables are immutable -by default, but this can be overridden using the `mut` qualifier. +Values (like literals) can be bound to variables, using the `let` binding. {variables.play} - -The compiler will throw a detailed diagnostic about mutability errors. - -It's possible to declare variables first, and initialize them later, but this -form is seldom used. Also, the compiler forbids usage of uninitialized -variables, as this would lead to undefined behavior. - -{declare.rs} - -{declare.out} diff --git a/examples/variables/mut/input.md b/examples/variables/mut/input.md new file mode 100644 index 0000000000..309d762dd3 --- /dev/null +++ b/examples/variables/mut/input.md @@ -0,0 +1,6 @@ +Variables are immutable by default, but this can be overridden using the `mut` +modifier. + +{mut.play} + +The compiler will throw a detailed diagnostic about mutability errors. diff --git a/examples/variables/mut/mut.rs b/examples/variables/mut/mut.rs new file mode 100644 index 0000000000..d2a8470a74 --- /dev/null +++ b/examples/variables/mut/mut.rs @@ -0,0 +1,15 @@ +fn main() { + let _immutable_variable = 1; + let mut mutable_variable = 1; + + println!("Before mutation: {}", mutable_variable); + + // Ok + mutable_variable += 1; + + println!("After mutation: {}", mutable_variable); + + // Error! + _immutable_variable += 1; + // FIXME ^ Comment out this line +} diff --git a/examples/variables/scope/input.md b/examples/variables/scope/input.md new file mode 100644 index 0000000000..da9f1911d4 --- /dev/null +++ b/examples/variables/scope/input.md @@ -0,0 +1,5 @@ +Variables have local scope, and are constrained to live in a *block* (a block +is a collection of statements enclosed by braces `{}`). This allows shadowing +of variables in inner blocks. + +{scope.play} diff --git a/examples/variables/scope/scope.rs b/examples/variables/scope/scope.rs new file mode 100644 index 0000000000..d60ffddf7a --- /dev/null +++ b/examples/variables/scope/scope.rs @@ -0,0 +1,24 @@ +fn main() { + // This variable lives in the main function + let long_lived_variable = 1; + + // This is a block, and has a smaller scope than the main function + { + // This variable only exists in this block + let short_lived_variable = 2; + + println!("inner short: {}", short_lived_variable); + + // This variable shadows the outer one + let long_lived_variable = 5; + + println!("inner long: {}", long_lived_variable); + } + // End of the block + + // Error! `short_lived_variable` doesn't exist in this scope + println!("outer short: {}", short_lived_variable); + // FIXME ^ Comment out this line + + println!("outer long: {}", long_lived_variable); +} diff --git a/examples/variables/variables.rs b/examples/variables/variables.rs index 7bfe19b599..a12573f58f 100644 --- a/examples/variables/variables.rs +++ b/examples/variables/variables.rs @@ -1,13 +1,18 @@ fn main() { - // immutable variable - let a_variable = 1; + let an_integer = 1; + let a_boolean = true; + let unit = (); - // mutable variable - let mut mutable_variable = 2; + // copy `an_integer` into `copied_integer` + let copied_integer = an_integer; - // Error: attempted to modify an immutable variable - a_variable += 1; + println!("An integer: {}", copied_integer); + println!("A boolean: {}", a_boolean); + println!("Meet the unit value: {}", unit); - // Ok - mutable_variable += 1; + // The compiler warns about unused variables; these warnings can be + // silenced by prefixing the variable name with an underscore + let _unused_variable = 3; + let noisy_unused_variable = 2; + // FIXME ^ Prefix with an underscore to suppress the warning } diff --git a/examples/vec/input.md b/examples/vec/input.md index 0846fbe7a5..84128a3de6 100644 --- a/examples/vec/input.md +++ b/examples/vec/input.md @@ -1,5 +1,5 @@ Vectors are re-sizable arrays, like slices their size is not known at compile -time, and they can be grow or shrink at anytime. A vector is represented using +time, but they can grow or shrink at anytime. A vector is represented using 3 words: a pointer to the data, its length and its capacity. The capacity indicates how much memory is reserved for the vector, the vector can grow as long as the length is smaller than the capacity, when this threshold needs to diff --git a/examples/vec/vec.rs b/examples/vec/vec.rs index 18b5fd8d7d..715e6bff16 100644 --- a/examples/vec/vec.rs +++ b/examples/vec/vec.rs @@ -1,30 +1,30 @@ fn main() { - // iterators can be collected into vectors + // Iterators can be collected into vectors let collected_iterator: Vec = range(0, 10).collect(); - println!("collected range(0, 10) into: {}", - collected_iterator.as_slice()); + println!("Collected range(0, 10) into: {}", collected_iterator); - // vec! can be used to initialize a vector + // The `vec!` macro can be used to initialize a vector let mut xs = vec![1, 2, 3]; - println!("vector: {}", xs.as_slice()); + println!("Initial vector: {}", xs); - // insert new element at the end of the vector - println!("push 4 into the vector") + // Insert new element at the end of the vector + println!("Push 4 into the vector") xs.push(4); - println!("vector: {}", xs.as_slice()); + println!("Vector: {}", xs); - // Error: immutable vectors can't be grow or shrink - //collected_iterator.push(0); + // Error! Immutable vectors can't grow + collected_iterator.push(0); + // FIXME ^ Comment out this line - // the len method yields the current size of the vector - println!("vector size: {}", xs.len()); + // The `len` method yields the current size of the vector + println!("Vector size: {}", xs.len()); - // indexing is done using the `get` method (indexing starts at 0) - println!("second element: {}", xs.get(1)); + // Indexing is done using the `get` method (indexing starts at 0) + println!("Second element: {}", xs.get(1)); - // remove last element from the vector and return it - println!("pop last element: {}", xs.pop()); + // `pop` removes the last element from the vector and returns it + println!("Pop last element: {}", xs.pop()); - // out of bounds indexing yields a runtime failure - println!("fourth element: {}", xs.get(3)); + // Out of bounds indexing yields a task failure + println!("Fourth element: {}", xs.get(3)); } diff --git a/examples/while/input.md b/examples/while/input.md new file mode 100644 index 0000000000..b7d0cf842e --- /dev/null +++ b/examples/while/input.md @@ -0,0 +1,5 @@ +The `while` keyword can be used to loop until a condition is met. + +Let's write the infamous fizzbuzz using a `while` loop. + +{while.play} diff --git a/examples/loops/while.rs b/examples/while/while.rs similarity index 77% rename from examples/loops/while.rs rename to examples/while/while.rs index eba9e8528b..3b37e550ad 100644 --- a/examples/loops/while.rs +++ b/examples/while/while.rs @@ -1,8 +1,8 @@ fn main() { - // a counter variable + // A counter variable let mut n = 1; - // loop while n is less than 101 + // Loop while `n` is less than 101 while n < 101 { if n % 15 == 0 { println!("fizzbuzz"); @@ -14,7 +14,7 @@ fn main() { println!("{}", n); } - // increment counter + // Increment counter n += 1; } } diff --git a/node_modules/gitbook-plugin-rust-playpen/book/editor.css b/node_modules/gitbook-plugin-rust-playpen/book/editor.css index 2b6e16e5e8..6471ce2dc5 100644 --- a/node_modules/gitbook-plugin-rust-playpen/book/editor.css +++ b/node_modules/gitbook-plugin-rust-playpen/book/editor.css @@ -25,6 +25,7 @@ padding: 10px; display: none; border-radius: 4px; + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; } #reset-code { diff --git a/node_modules/gitbook-plugin-rust-playpen/book/editor.js b/node_modules/gitbook-plugin-rust-playpen/book/editor.js index d62c231521..c1e397d4bb 100644 --- a/node_modules/gitbook-plugin-rust-playpen/book/editor.js +++ b/node_modules/gitbook-plugin-rust-playpen/book/editor.js @@ -132,7 +132,7 @@ function runProgram(program, callback) { var req = new XMLHttpRequest(); var data = JSON.stringify({ version: "master", - optimize: "2", + optimize: "0", code: program }); diff --git a/setup-stage.sh b/setup-stage.sh index ff8be9339b..d6b8f02b66 100755 --- a/setup-stage.sh +++ b/setup-stage.sh @@ -1,3 +1,5 @@ -mkdir -p stage/node_modules +mkdir bin +mkdir stage +mkdir stage/node_modules ln -sf ../book.json stage -ln -sf ../examples/README.md stage/README.md +ln -sf ../examples/README.md stage diff --git a/src/example.rs b/src/example.rs index a7ffc7448b..757a74aa60 100644 --- a/src/example.rs +++ b/src/example.rs @@ -1,22 +1,24 @@ -use file::read; +use file; use markdown::Markdown; use serialize::{Decodable,json}; +use std::iter::AdditiveIterator; #[deriving(Decodable)] pub struct Example { + children: Option>, id: String, title: String, } impl Example { pub fn get_list() -> Vec { - match read(&Path::new("examples/order.json")) { + match file::read(&Path::new("examples/structure.json")) { Err(why) => fail!("{}", why), Ok(string) => match json::from_str(string.as_slice()) { - Err(_) => fail!("order.json is not valid json"), + Err(_) => fail!("structure.json is not valid json"), Ok(json) => { match Decodable::decode(&mut json::Decoder::new(json)) { - Err(_) => fail!("error decoding order.json"), + Err(_) => fail!("error decoding structure.json"), Ok(examples) => examples, } } @@ -24,20 +26,65 @@ impl Example { } } - pub fn copy_id(&self) -> String { - self.id.clone() + pub fn count(&self) -> uint { + match self.children { + None => 1, + Some(ref children) => 1 + children.iter().map(|c| c.count()).sum(), + } } - pub fn process(&self) -> String { - match Markdown::process(self.id.as_slice(), self.title.as_slice()) { + pub fn process(&self, + pos: uint, + tx: Sender<(uint, String)>, + indent: uint, + prefix: String) + { + let id = self.id.as_slice(); + let prefix = prefix.as_slice(); + let title = self.title.as_slice(); + + let entry = match Markdown::process(id, title, prefix) { Ok(_) => { - format!("* [{}]({}.md)", self.title, self.id) + let md = if prefix.as_slice().is_whitespace() { + format!("{}.md", id) + } else { + format!("{}/{}.md", prefix, id) + }; + + format!("{}* [{}]({})", + " ".repeat(indent), + title, + md) }, Err(why) => { - print!("{}: {}\n", self.id, why); - format!("* {}", self.title) + print!("{}: {}\n", id, why); + format!("{}* {}", " ".repeat(indent), title) }, - } + }; + + tx.send((pos, entry)); + + match self.children { + None => {}, + Some(ref children) => { + let path = Path::new(format!("stage/{}/{}", prefix, id)); + file::mkdir(&path); + + for (i, example) in children.iter().enumerate() { + let tx = tx.clone(); + let prefix = if prefix.as_slice().is_whitespace() { + format!("{}", id) + } else { + format!("{}/{}", prefix, id) + }; + + example.process(pos + i + 1, + tx, + indent + 1, + prefix); + } + }, + } } } diff --git a/src/file.rs b/src/file.rs index d850151b17..73fa7eb166 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,8 +1,16 @@ +use std::io::UserRWX; use std::io::fs; use std::io::process::{Command,ProcessOutput}; use std::io::{File,Truncate,Write}; use std::os; +pub fn mkdir(path: &Path) { + match fs::mkdir_recursive(path, UserRWX) { + Err(_) => {}, + Ok(_) => {}, + } +} + pub fn read(path: &Path) -> Result { match File::open(path) { Err(_) => Err(format!("couldn't open {}", path.display())), @@ -13,13 +21,13 @@ pub fn read(path: &Path) -> Result { } } -pub fn run(id: &str, filename: &str) -> Result { +pub fn run(prefix: &str, id: &str, src: &str) -> Result { let cwd = os::getcwd(); - let out_dir = cwd.join(format!("stage/{}", id)); + let out_dir = cwd.join(format!("bin/{}/{}", prefix, id)); let mut cmd = Command::new("rustc"); - cmd.cwd(&Path::new(format!("examples/{}", id))); - cmd.arg(format!("{}.rs", filename)); + cmd.cwd(&Path::new(format!("examples/{}/{}", prefix, id))); + cmd.arg(format!("{}.rs", src)); cmd.arg("--out-dir"); cmd.arg(out_dir); @@ -30,16 +38,11 @@ pub fn run(id: &str, filename: &str) -> Result { }, } - let executable = Path::new(format!("./stage/{}/{}", id, filename)); + let executable = Path::new(format!("./bin/{}/{}/{}", prefix, id, src)); match Command::new(&executable).output() { - Err(_) => Err(format!("couldn't find {}", id)), + Err(_) => Err(format!("couldn't find {}", executable.display())), Ok(ProcessOutput { error: error, output: output, status: status }) => { - match fs::unlink(&executable) { - Err(_) => return Err(format!("couldn't remove {}", id)), - Ok(_) => {}, - } - let mut s = String::from_utf8(output).unwrap(); if !status.success() { s.push_str(String::from_utf8(error).unwrap().as_slice()); diff --git a/src/markdown.rs b/src/markdown.rs index 5699d11182..12a2349d22 100644 --- a/src/markdown.rs +++ b/src/markdown.rs @@ -1,35 +1,42 @@ use file; use playpen; -use std::io::{UserRWX,fs}; -pub struct Markdown<'a> { - id: &'a str, +pub struct Markdown<'a, 'b> { content: String, + id: &'a str, + prefix: &'b str, } -impl<'a> Markdown<'a> { - pub fn process(id: &'a str, title: &str) -> Result, String> { - let mut mkd = try!(Markdown::new(id, title)); +impl<'a, 'b> Markdown<'a, 'b> { + pub fn process(id: &'a str, title: &str, prefix: &'b str) + -> Result<(), String> + { + let mut mkd = try!(Markdown::new(id, title, prefix)); try!(mkd.insert_sources()); try!(mkd.insert_outputs()); try!(mkd.insert_playpen_links()); try!(mkd.save()); - Ok(mkd) + Ok(()) } - fn new(id: &'a str, title: &str) -> Result, String> { - let p = Path::new(format!("examples/{}/input.md", id)); + fn new(id: &'a str, title: &str, prefix: &'b str) + -> Result, String> + { + let p = Path::new(format!("examples/{}/{}/input.md", prefix, id)); let s = try!(file::read(&p)); Ok(Markdown { + content: format!("# {}\n\n{}", title, s), id: id, - content: format!("\\# {}\n\n{}", title, s), + prefix: prefix, }) } fn insert_sources(&mut self) -> Result<(), String> { + let id = self.id; + let prefix = self.prefix; let re = regex!(r"\{(.*\.rs)\}"); let mut table = Vec::new(); @@ -38,8 +45,8 @@ impl<'a> Markdown<'a> { None => {}, Some(captures) => { let src = captures.at(1); - let input = format!("\\{{}\\}", src); - let p = format!("examples/{}/{}", self.id, src); + let input = format!("{{{}}}", src); + let p = format!("examples/{}/{}/{}", prefix, id, src); let output = match file::read(&Path::new(p.as_slice())) { Err(_) => { return Err(format!("{} not found", p)); @@ -64,14 +71,13 @@ impl<'a> Markdown<'a> { } fn insert_outputs(&mut self) -> Result<(), String> { + let id = self.id; + let prefix = self.prefix; let r = regex!(r"\{(.*)\.out\}"); - let dir = Path::new(format!("stage/{}", self.id)); + let dir = Path::new(format!("bin/{}/{}", prefix, id)); - match fs::mkdir(&dir, UserRWX) { - Err(_) => {}, - Ok(_) => {}, - } + file::mkdir(&dir); let mut table = Vec::new(); for line in self.content.as_slice().lines() { @@ -79,8 +85,8 @@ impl<'a> Markdown<'a> { None => {}, Some(captures) => { let src = captures.at(1); - let input = format!("\\{{}.out\\}", src); - let s = try!(file::run(self.id, src)); + let input = format!("{{{}.out}}", src); + let s = try!(file::run(prefix, id, src)); let s = format!("```\n$ rustc {0}.rs && ./{0}\n{1}```", src, s); @@ -94,13 +100,12 @@ impl<'a> Markdown<'a> { output.as_slice()); } - match fs::rmdir(&dir) { - Err(_) => Err(format!("couldn't remove {}", dir.display())), - Ok(_) => Ok(()), - } + Ok(()) } fn insert_playpen_links(&mut self) -> Result<(), String> { + let id = self.id; + let prefix = self.prefix; let re = regex!(r"\{(.*)\.play\}"); let mut once_ = false; @@ -115,9 +120,9 @@ impl<'a> Markdown<'a> { once_ = true; } - let input = format!("\\{{}.play\\}", captures.at(1)); + let input = format!("{{{}.play}}", captures.at(1)); let src = format!("{}.rs", captures.at(1)); - let p = format!("examples/{}/{}", self.id, src); + let p = format!("examples/{}/{}/{}", prefix, id, src); let output = match file::read(&Path::new(p.as_slice())) { Err(_) => { return Err(format!("{} not found", p)); @@ -141,7 +146,7 @@ impl<'a> Markdown<'a> { } fn save(&self) -> Result<(), String> { - let path = Path::new(format!("stage/{}.md", self.id)); + let path = Path::new(format!("stage/{}/{}.md", self.prefix, self.id)); file::write(&path, self.content.as_slice()) } diff --git a/src/playpen.rs b/src/playpen.rs index a3721f3fae..d9f3eb9013 100644 --- a/src/playpen.rs +++ b/src/playpen.rs @@ -15,7 +15,9 @@ fn escape(source: &str) -> String { '*' => s.push_str("*"), '<' => s.push_str("<"), '>' => s.push_str(">"), + '\\' => s.push_str("\"), '_' => s.push_str("_"), + '`' => s.push_str("`"), chr => s.push_char(chr), } } diff --git a/src/update.rs b/src/update.rs index d6bedfbeae..72a6ba5b80 100644 --- a/src/update.rs +++ b/src/update.rs @@ -1,7 +1,7 @@ #![feature(phase)] extern crate regex; -#[phase(syntax)] +#[phase(plugin)] extern crate regex_macros; extern crate serialize; @@ -15,38 +15,29 @@ mod playpen; fn main() { let examples = Example::get_list(); let (tx, rx) = channel(); - let nexamples = examples.len(); - for (i, example) in examples.move_iter().enumerate() { + let mut nexamples = 0; + for example in examples.move_iter() { let tx = tx.clone(); + let count = example.count(); spawn(proc() { - tx.send((i, example.copy_id(), example.process())); - }) + example.process(nexamples, tx, 0, String::new()); + }); + + nexamples += count; } - let mut chapters = range(0, nexamples).map(|_| { + let mut entries = range(0, nexamples).map(|_| { rx.recv() - }).collect::>(); - - chapters.sort_by(|&(i, _, _), &(j, _, _)| i.cmp(&j)); + }).collect::>(); - let mut summary = String::new(); - let mut indent = false; - for (_, id, chapter) in chapters.move_iter() { - let id = id.as_slice(); + entries.sort_by(|&(i, _), &(j, _)| i.cmp(&j)); - if indent && id != "todo" && id != "staging" { - summary.push_str(format!(" {}", chapter).as_slice()); - } else { - summary.push_str(chapter.as_slice()); - } - summary.push_char('\n'); - - if id == "staging" { - indent = true; - } - } + let summary = entries.move_iter() + .map(|(_, s)| s) + .collect::>() + .connect("\n"); match file::write(&Path::new("stage/SUMMARY.md"), summary.as_slice()) { Err(why) => fail!("{}", why),