Skip to content

Commit 17eceff

Browse files
committed
add PorgramingRust
1 parent ded8883 commit 17eceff

96 files changed

Lines changed: 3811 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎ProgrammingRust/LICENSE-MIT‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Permission is hereby granted, free of charge, to any
2+
person obtaining a copy of this software and associated
3+
documentation files (the "Software"), to deal in the
4+
Software without restriction, including without
5+
limitation the rights to use, copy, modify, merge,
6+
publish, distribute, sublicense, and/or sell copies of
7+
the Software, and to permit persons to whom the Software
8+
is furnished to do so, subject to the following
9+
conditions:
10+
11+
The above copyright notice and this permission notice
12+
shall be included in all copies or substantial portions
13+
of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
16+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
17+
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
18+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
19+
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
22+
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+
DEALINGS IN THE SOFTWARE.

‎ProgrammingRust/README.md‎

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Code Examples for _Programming Rust_
2+
3+
This repository contains complete code for the larger example programs
4+
from the book “Programming Rust”, by Jim Blandy and Jason Orendorff.
5+
6+
Each subdirectory is a distinct Rust project, with its own Cargo.toml file. You
7+
should be able to enter each directory and use `cargo build` and `cargo test`.
8+
For those projects that define programs, `cargo run` should run them.
9+
10+
The example code in this directory and its subdirectories is licensed under the
11+
terms of the MIT license. See [LICENSE-MIT](LICENSE-MIT) for details.
12+
13+
## Chapter 2: A Tour of Rust
14+
15+
- The `gcd` directory holds the command-line program for computing the greatest
16+
common denominator of a list of numbers.
17+
18+
- The `iron-gcd` directory holds the code for the simple web service,
19+
implemented using the [`iron`] framework, that computes greatest common
20+
denominators.
21+
22+
- The Mandelbrot plotting program has its own repository, at
23+
`https://github.com/ProgrammingRust/mandelbrot`. This repository contains
24+
several branches, each showing a different implementation strategy. The
25+
`single-threaded` branch holds the code for the single-threaded version, and
26+
the `bands` branch holds the multi-threaded version. Chapter 19,
27+
“Concurrency”, shows several other approaches, which appear on other branches;
28+
see the repository's [README.md][mandel-readme] file for details.
29+
30+
[`iron`]: https://crates.io/crates/iron
31+
32+
## Chapter 8: Crates and Modules
33+
34+
- We did not actually write a fern simulator. Please accept our sincere apology
35+
for this feckless deception. But the skeleton of modules and definitions we
36+
show in the book is in the `fern_sim` subdirectory.
37+
38+
## Chapter 9: Structs
39+
40+
- The `queue` directory holds a library that defines the `Queue` type,
41+
representing a queue of `char` values.
42+
43+
- The `generic-queue` directory holds code for generic `Queue` type.
44+
45+
## Chapter 10: Enums and Patterns
46+
47+
- The `binary-tree` directory holds the source code for the `BinaryTree` type
48+
that appears in the “Generic Enums” and “Populating a Binary Tree” sections.
49+
50+
## Chapter 12: Operator Overloading
51+
52+
- The `complex` directory holds the `Complex` type used as a running example
53+
throughout the chapter.
54+
55+
- The `interval` directory holds the `Interval` type for which the book
56+
implements the `std::cmp::PartialOrd` trait.
57+
58+
## Chapter 14: Closures
59+
60+
- The 'basic-router' directory holds the `BasicRouter` type used as an example
61+
in the “Callbacks” section.
62+
63+
## Chapter 15: Iterators
64+
65+
- The `binary-tree` directory holds the implementation of the `Iterator` trait
66+
for the `BinaryTree` type originally defined in the “Enums and Patterns”
67+
chapter.
68+
69+
## Chapter 17: Strings and Text
70+
71+
- The `complex` directory includes the implementation of the `std::fmt::Display`
72+
formatting trait for a complex number type, shown in the section “Formatting
73+
Your Own Types”.
74+
75+
## Chapter 18: Input and Output
76+
77+
- The `grep` directory holds the simple grep-like program shown in the section
78+
“Reading Lines”.
79+
80+
- The `copy` directory holds the program for copying directory trees from the
81+
section “Reading Directories”, including the additions shown in the next
82+
section, “Platform-Specific Features”.
83+
84+
- The `echo-server` directory holds the simple network service shown in the
85+
“Networking” section.
86+
87+
- The `http-get` directory holds the command-line program that uses the
88+
`reqwest` crate to carry out an HTTP request.
89+
90+
## Chapter 19: Concurrency
91+
92+
- The search engine used as a running example throughout the book has its own
93+
repository, at `https://github.com/ProgrammingRust/fingertips`.
94+
95+
- The Mandelbrot set plotter discussed in the section “Revisiting the Mandelbrot
96+
Set” also has its own repository, at `https://github.com/ProgrammingRust/mandelbrot`.
97+
The repository includes several branches exploring different implementations;
98+
see the repository's [README.md][mandel-readme] file for details.
99+
100+
[mandel-readme]: https://github.com/ProgrammingRust/mandelbrot/blob/master/README.md
101+
102+
## Chapter 20: Macros
103+
104+
- The `json-macro` directory holds the definition of the `json!` macro built in
105+
the section “The json! Macro”.
106+
107+
## Chapter 21: Unsafe Code
108+
109+
- The `ascii` directory holds the `Ascii` type used as an example in the
110+
sections “Unsafe Blocks” and “Unsafe Functions”.
111+
112+
- The `ref-with-flag` directory holds the `RefWithFlag` type from the “Raw
113+
Pointers” section.
114+
115+
- The `gap-buffer` directory holds the `GapBuffer` type, used in the “Raw
116+
Pointers” section to illustrate pointer arithmetic and `std::ptr::read` and
117+
`std::ptr::write`.
118+
119+
- The `libgit2-rs` and `libgit2-rs-safe` directories contain the two versions of
120+
the program that uses Rust's foreign function interface to call functions from
121+
the `libgit2` C library. The version in `libgit2-rs` is written as a single
122+
giant block of unsafe code, whereas the version in `libgit2-rs-safe`
123+
implements a safe Rust interface to the same functionality, using Rust's type
124+
system to enforce libgit2's rules for proper use of the library.
125+
126+
Note that both of these require you to have a copy of `libgit2` present on
127+
your system. The chapter provides detailed instructions for building the
128+
correct version, for Linux, macOS, and Microsoft Windows.

‎ProgrammingRust/ascii/.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target

‎ProgrammingRust/ascii/Cargo.lock‎

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎ProgrammingRust/ascii/Cargo.toml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "ascii"
3+
version = "0.1.0"
4+
authors = ["You <you@example.com>"]
5+
6+
[dependencies]

‎ProgrammingRust/ascii/src/lib.rs‎

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
mod my_ascii {
2+
use std::ascii::AsciiExt; // for u8::is_ascii
3+
4+
/// An ASCII-encoded string.
5+
#[derive(Debug, Eq, PartialEq)]
6+
pub struct Ascii(
7+
// This must hold only well-formed ASCII text:
8+
// bytes from `0` to `0x7f`.
9+
Vec<u8>
10+
);
11+
12+
impl Ascii {
13+
/// Create an `Ascii` from the ASCII text in `bytes`. Return a
14+
/// `NotAsciiError` error if `bytes` contains any non-ASCII
15+
/// characters.
16+
pub fn from_bytes(bytes: Vec<u8>) -> Result<Ascii, NotAsciiError> {
17+
if bytes.iter().any(|&byte| !byte.is_ascii()) {
18+
return Err(NotAsciiError(bytes));
19+
}
20+
Ok(Ascii(bytes))
21+
}
22+
}
23+
24+
// When conversion fails, we give back the vector we couldn't convert.
25+
// This should implement `std::error::Error`; omitted for brevity.
26+
#[derive(Debug, Eq, PartialEq)]
27+
pub struct NotAsciiError(pub Vec<u8>);
28+
29+
// Safe, efficient conversion, implemented using unsafe code.
30+
impl From<Ascii> for String {
31+
fn from(ascii: Ascii) -> String {
32+
// If this module has no bugs, this is safe, because
33+
// well-formed ASCII text is also well-formed UTF-8.
34+
unsafe {
35+
String::from_utf8_unchecked(ascii.0)
36+
}
37+
}
38+
}
39+
40+
impl From<Ascii> for Vec<u8> {
41+
fn from(ascii: Ascii) -> Vec<u8> { ascii.0 }
42+
}
43+
44+
// This must be placed inside the `my_ascii` module.
45+
impl Ascii {
46+
/// Construct an `Ascii` value from `bytes`, without checking
47+
/// whether `bytes` actually contains well-formed ASCII.
48+
///
49+
/// This constructor is infallible, and returns an `Ascii` directly,
50+
/// rather than a `Result<Ascii, NotAsciiError>` as the `from_bytes`
51+
/// constructor does.
52+
///
53+
/// # Safety
54+
///
55+
/// The caller must ensure that `bytes` contains only ASCII
56+
/// characters: bytes no greater than 0x7f. Otherwise, the effect is
57+
/// undefined.
58+
pub unsafe fn from_bytes_unchecked(bytes: Vec<u8>) -> Ascii {
59+
Ascii(bytes)
60+
}
61+
}
62+
}
63+
64+
65+
#[test]
66+
fn good_ascii() {
67+
use self::my_ascii::Ascii;
68+
69+
let bytes: Vec<u8> = b"ASCII and ye shall receive".to_vec();
70+
71+
// This call entails no allocation or text copies, just a scan.
72+
let ascii: Ascii = Ascii::from_bytes(bytes)
73+
.unwrap(); // We know these chosen bytes are legit.
74+
75+
// This call is zero-cost: no allocation, copies, or scans.
76+
let string = String::from(ascii);
77+
78+
assert_eq!(string, "ASCII and ye shall receive");
79+
}
80+
81+
82+
#[test]
83+
fn bad_ascii() {
84+
use self::my_ascii::Ascii;
85+
86+
// Imagine that this vector is the result of some complicated process
87+
// that we expected to produce ASCII. Something went wrong!
88+
let bytes = vec![0xf7, 0xbf, 0xbf, 0xbf];
89+
90+
let ascii = unsafe {
91+
// This unsafe function's contract is violated
92+
// when `bytes` holds non-ASCII bytes.
93+
Ascii::from_bytes_unchecked(bytes)
94+
};
95+
96+
let bogus: String = ascii.into();
97+
98+
// `bogus` now holds ill-formed UTF-8. Parsing its first character
99+
// produces a `char` that is not a valid Unicode code point.
100+
assert_eq!(bogus.chars().next().unwrap() as u32, 0x1fffff);
101+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target

‎ProgrammingRust/basic-router/Cargo.lock‎

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "basic-router"
3+
version = "0.1.0"
4+
authors = ["You <you@example.com>"]
5+
6+
[dependencies]
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#![allow(dead_code)]
2+
3+
use std::collections::HashMap;
4+
5+
struct Request {
6+
method: String,
7+
url: String,
8+
headers: HashMap<String, String>,
9+
body: Vec<u8>
10+
}
11+
12+
struct Response {
13+
code: u32,
14+
headers: HashMap<String, String>,
15+
body: Vec<u8>
16+
}
17+
18+
type BoxedCallback = Box<Fn(&Request) -> Response>;
19+
20+
struct BasicRouter {
21+
routes: HashMap<String, BoxedCallback>
22+
}
23+
24+
impl BasicRouter {
25+
// Create an empty router.
26+
fn new() -> BasicRouter {
27+
BasicRouter { routes: HashMap::new() }
28+
}
29+
30+
// Add a route to the router.
31+
fn add_route<C>(&mut self, url: &str, callback: C)
32+
where C: Fn(&Request) -> Response + 'static
33+
{
34+
self.routes.insert(url.to_string(), Box::new(callback));
35+
}
36+
}
37+
38+
impl BasicRouter {
39+
fn handle_request(&self, request: &Request) -> Response {
40+
match self.routes.get(&request.url) {
41+
None => not_found_response(),
42+
Some(callback) => callback(request)
43+
}
44+
}
45+
}
46+
47+
fn not_found_response() -> Response {
48+
Response {
49+
code: 404,
50+
headers: HashMap::new(),
51+
body: b"<h1>Page not found</h1>".to_vec()
52+
}
53+
}
54+
55+
fn get_form_response() -> Response {
56+
Response {
57+
code: 200,
58+
headers: HashMap::new(),
59+
body: b"<form>".to_vec()
60+
}
61+
}
62+
63+
fn get_gcd_response(_req: &Request) -> Response {
64+
Response {
65+
code: 500,
66+
headers: HashMap::new(),
67+
body: b"<h1>Internal server error</h1>".to_vec()
68+
}
69+
}
70+
71+
fn req(url: &str) -> Request {
72+
Request {
73+
method: "GET".to_string(),
74+
url: url.to_string(),
75+
headers: HashMap::new(),
76+
body: vec![]
77+
}
78+
}
79+
80+
#[test]
81+
fn test_router() {
82+
let mut router = BasicRouter::new();
83+
router.add_route("/", |_| get_form_response());
84+
router.add_route("/gcd", |req| get_gcd_response(req));
85+
86+
assert_eq!(router.handle_request(&req("/piano")).code, 404);
87+
assert_eq!(router.handle_request(&req("/")).code, 200);
88+
assert_eq!(router.handle_request(&req("/gcd")).code, 500);
89+
}

0 commit comments

Comments
 (0)