Skip to content

Commit 8a78dd5

Browse files
committed
---
yaml --- r: 124275 b: refs/heads/try c: 2eadfe4 h: refs/heads/master i: 124273: 7069f35 124271: 32c32ba v: v3
1 parent c36060d commit 8a78dd5

File tree

6 files changed

+145
-8
lines changed

6 files changed

+145
-8
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
refs/heads/master: 6c35d513cea468b30759b4f78becf28f11a123c0
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: afbcbbc77ffc6b10053bc543daf7d2e05d68cc01
5-
refs/heads/try: a008fc84aaf429a1966c422297302cf809df796d
5+
refs/heads/try: 2eadfe42e58de0263286195e7560cb85337a3847
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: 147ecfdd8221e4a4d4e090486829a06da1e0ca3c

branches/try/src/doc/guide.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,102 @@ do that with `match`.
12641264

12651265
## Match
12661266

1267+
Often, a simple `if`/`else` isn't enough, because you have more than two
1268+
possible options. And `else` conditions can get incredibly complicated. So
1269+
what's the solution?
1270+
1271+
Rust has a keyword, `match`, that allows you to replace complicated `if`/`else`
1272+
groupings with something more powerful. Check it out:
1273+
1274+
```rust
1275+
let x = 5i;
1276+
1277+
match x {
1278+
1 => println!("one"),
1279+
2 => println!("two"),
1280+
3 => println!("three"),
1281+
4 => println!("four"),
1282+
5 => println!("five"),
1283+
_ => println!("something else"),
1284+
}
1285+
```
1286+
1287+
`match` takes an expression, and then branches based on its value. Each 'arm' of
1288+
the branch is of the form `val => expression`. When the value matches, that arm's
1289+
expression will be evaluated. It's called `match` because of the term 'pattern
1290+
matching,' which `match` is an implementation of.
1291+
1292+
So what's the big advantage here? Well, there are a few. First of all, `match`
1293+
does 'exhaustiveness checking.' Do you see that last arm, the one with the
1294+
underscore (`_`)? If we remove that arm, Rust will give us an error:
1295+
1296+
```{ignore,notrust}
1297+
error: non-exhaustive patterns: `_` not covered
1298+
```
1299+
1300+
In other words, Rust is trying to tell us we forgot a value. Because `x` is an
1301+
integer, Rust knows that it can have a number of different values. For example,
1302+
`6i`. But without the `_`, there is no arm that could match, and so Rust refuses
1303+
to compile. `_` is sort of like a catch-all arm. If none of the other arms match,
1304+
the arm with `_` will. And since we have this catch-all arm, we now have an arm
1305+
for every possible value of `x`, and so our program will now compile.
1306+
1307+
`match` statements also destructure enums, as well. Remember this code from the
1308+
section on enums?
1309+
1310+
```{rust}
1311+
let x = 5i;
1312+
let y = 10i;
1313+
1314+
let ordering = x.cmp(&y);
1315+
1316+
if ordering == Less {
1317+
println!("less");
1318+
} else if ordering == Greater {
1319+
println!("greater");
1320+
} else if ordering == Equal {
1321+
println!("equal");
1322+
}
1323+
```
1324+
1325+
We can re-write this as a `match`:
1326+
1327+
```{rust}
1328+
let x = 5i;
1329+
let y = 10i;
1330+
1331+
match x.cmp(&y) {
1332+
Less => println!("less"),
1333+
Greater => println!("greater"),
1334+
Equal => println!("equal"),
1335+
}
1336+
```
1337+
1338+
This version has way less noise, and it also checks exhaustively to make sure
1339+
that we have covered all possible variants of `Ordering`. With our `if`/`else`
1340+
version, if we had forgotten the `Greater` case, for example, our program would
1341+
have happily compiled. If we forget in the `match`, it will not. Rust helps us
1342+
make sure to cover all of our bases.
1343+
1344+
`match` is also an expression, which means we can use it on the right hand side
1345+
of a `let` binding. We could also implement the previous line like this:
1346+
1347+
```
1348+
let x = 5i;
1349+
let y = 10i;
1350+
1351+
let result = match x.cmp(&y) {
1352+
Less => "less",
1353+
Greater => "greater",
1354+
Equal => "equal",
1355+
};
1356+
1357+
println!("{}", result);
1358+
```
1359+
1360+
In this case, it doesn't make a lot of sense, as we are just making a temporary
1361+
string where we don't need to, but sometimes, it's a nice pattern.
1362+
12671363
## Looping
12681364

12691365
for

branches/try/src/doc/tutorial.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ let mut b = Foo { x: 5, y: box 10 };
979979
b.x = 10;
980980
~~~~
981981

982-
If an object doesn't contain any non-Send types, it consists of a single
982+
If an object doesn't contain any non-`Send` types, it consists of a single
983983
ownership tree and is itself given the `Send` trait which allows it to be sent
984984
between tasks. Custom destructors can only be implemented directly on types
985985
that are `Send`, but non-`Send` types can still *contain* types with custom

branches/try/src/librustuv/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
420420
uvll::EADDRNOTAVAIL => libc::WSAEADDRNOTAVAIL,
421421
uvll::ECANCELED => libc::ERROR_OPERATION_ABORTED,
422422
uvll::EADDRINUSE => libc::WSAEADDRINUSE,
423+
uvll::EPERM => libc::ERROR_ACCESS_DENIED,
423424
err => {
424425
uvdebug!("uverr.code {}", err as int);
425426
// FIXME: Need to map remaining uv error types

branches/try/src/librustuv/uvll.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use libc::uintptr_t;
3939

4040
pub use self::errors::{EACCES, ECONNREFUSED, ECONNRESET, EPIPE, ECONNABORTED,
4141
ECANCELED, EBADF, ENOTCONN, ENOENT, EADDRNOTAVAIL,
42-
EADDRINUSE};
42+
EADDRINUSE, EPERM};
4343

4444
pub static OK: c_int = 0;
4545
pub static EOF: c_int = -4095;
@@ -63,6 +63,7 @@ pub mod errors {
6363
pub static EBADF: c_int = -4083;
6464
pub static EADDRNOTAVAIL: c_int = -4090;
6565
pub static EADDRINUSE: c_int = -4091;
66+
pub static EPERM: c_int = -4048;
6667
}
6768
#[cfg(not(windows))]
6869
pub mod errors {
@@ -80,6 +81,7 @@ pub mod errors {
8081
pub static EBADF : c_int = -libc::EBADF;
8182
pub static EADDRNOTAVAIL : c_int = -libc::EADDRNOTAVAIL;
8283
pub static EADDRINUSE : c_int = -libc::EADDRINUSE;
84+
pub static EPERM: c_int = -libc::EPERM;
8385
}
8486

8587
pub static PROCESS_SETUID: c_int = 1 << 0;

branches/try/src/libstd/io/fs.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,41 @@ impl File {
275275
/// user lacks permissions to remove the file, or if some other filesystem-level
276276
/// error occurs.
277277
pub fn unlink(path: &Path) -> IoResult<()> {
278-
let err = LocalIo::maybe_raise(|io| {
279-
io.fs_unlink(&path.to_c_str())
280-
}).map_err(IoError::from_rtio_error);
281-
err.update_err("couldn't unlink path",
282-
|e| format!("{}; path={}", e, path.display()))
278+
return match do_unlink(path) {
279+
Ok(()) => Ok(()),
280+
Err(e) => {
281+
// On unix, a readonly file can be successfully removed. On windows,
282+
// however, it cannot. To keep the two platforms in line with
283+
// respect to their behavior, catch this case on windows, attempt to
284+
// change it to read-write, and then remove the file.
285+
if cfg!(windows) && e.kind == io::PermissionDenied {
286+
let stat = match stat(path) {
287+
Ok(stat) => stat,
288+
Err(..) => return Err(e),
289+
};
290+
if stat.perm.intersects(io::UserWrite) { return Err(e) }
291+
292+
match chmod(path, stat.perm | io::UserWrite) {
293+
Ok(()) => do_unlink(path),
294+
Err(..) => {
295+
// Try to put it back as we found it
296+
let _ = chmod(path, stat.perm);
297+
Err(e)
298+
}
299+
}
300+
} else {
301+
Err(e)
302+
}
303+
}
304+
};
305+
306+
fn do_unlink(path: &Path) -> IoResult<()> {
307+
let err = LocalIo::maybe_raise(|io| {
308+
io.fs_unlink(&path.to_c_str())
309+
}).map_err(IoError::from_rtio_error);
310+
err.update_err("couldn't unlink path",
311+
|e| format!("{}; path={}", e, path.display()))
312+
}
283313
}
284314

285315
/// Given a path, query the file system to get information about a file,
@@ -1591,4 +1621,12 @@ mod test {
15911621
let actual = check!(File::open(&tmpdir.join("test")).read_to_end());
15921622
assert!(actual.as_slice() == bytes);
15931623
})
1624+
1625+
iotest!(fn unlink_readonly() {
1626+
let tmpdir = tmpdir();
1627+
let path = tmpdir.join("file");
1628+
check!(File::create(&path));
1629+
check!(chmod(&path, io::UserRead));
1630+
check!(unlink(&path));
1631+
})
15941632
}

0 commit comments

Comments
 (0)