programming rust: finish chapter 2.

This commit is contained in:
Kyle Isom 2018-09-03 18:50:37 -07:00
parent 1f90323879
commit c1d6c41510
7 changed files with 364 additions and 0 deletions

6
lr/ch2/gcd/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "gcd"
version = "0.1.0"
authors = ["Kyle Isom <kyle@imap.cc>"]
[dependencies]

43
lr/ch2/gcd/src/main.rs Normal file
View File

@ -0,0 +1,43 @@
use std::io::Write;
use std::str::FromStr;
fn gcd(mut n: u64, mut m: u64) -> u64 {
assert!(n != 0 && m != 0);
while m != 0 {
if m < n {
let t = m;
m = n;
n = t;
}
m = m % n;
}
n
}
#[test]
fn test_gcd() {
assert_eq!(gcd(14, 15), 1);
assert_eq!(gcd(2 * 3 * 5 * 11 * 17,
3 * 7 * 11 * 13 * 19),
3 * 11);
}
fn main() {
let mut numbers = Vec::new();
for arg in std::env::args().skip(1) {
numbers.push(u64::from_str(&arg).expect("error parsing argument as u64"));
}
if numbers.len() == 0 {
writeln!(std::io::stderr(), "Usage: gcd NUMBER...").unwrap();
std::process::exit(1);
}
let mut d = numbers[0];
for m in &numbers[1..] {
d = gcd(d, *m);
}
println!("The greatest common divisor of {:?} is {}", numbers, d);
}

View File

@ -0,0 +1,10 @@
[package]
name = "iron-gcd"
version = "0.1.0"
authors = ["Kyle Isom <kyle@imap.cc>"]
[dependencies]
iron = "0.5.1"
mime = "0.2.3"
router = "0.5.1"
urlencoded = "0.5.0"

View File

@ -0,0 +1,96 @@
extern crate iron;
extern crate router;
extern crate urlencoded;
#[macro_use] extern crate mime;
use std::str::FromStr;
use urlencoded::UrlEncodedBody;
use iron::prelude::*;
use iron::status;
use router::Router;
fn gcd(mut n: u64, mut m: u64) -> u64 {
assert!(n != 0 && m != 0);
while m != 0 {
if m < n {
let t = m;
m = n;
n = t;
}
m = m % n;
}
n
}
fn main() {
let mut router = Router::new();
router.get("/", get_form, "root");
router.post("/gcd", post_gcd, "gcd");
println!("Serving on http://localhost:3000...");
Iron::new(router).http("localhost:3000").unwrap();
}
fn get_form(_request: &mut Request) -> IronResult<Response> {
let mut response = Response::new();
response.set_mut(status::Ok);
response.set_mut(mime!(Text/Html; Charset=Utf8));
response.set_mut(r#"
<title>GCD calculator</title>
<form action="/gcd" method="post">
<input type="text" name="n" />
<input type="text" name="n" />
<button type="submit">Compute GCD</button>
</form>
"#);
Ok(response)
}
fn post_gcd(request: &mut Request) -> IronResult<Response> {
let mut response = Response::new();
let form_data = match request.get_ref::<UrlEncodedBody>() {
Err(e) => {
response.set_mut(status::BadRequest);
response.set_mut(format!("Error parsing form data: {:?}\n", e));
return Ok(response);
}
Ok(map) => map
};
let unparsed_numbers = match form_data.get("n") {
None => {
response.set_mut(status::BadRequest);
response.set_mut(format!("Form has no 'n' parameters!\n"));
return Ok(response);
}
Some(nums) => nums
};
let mut numbers = Vec::new();
for unparsed in unparsed_numbers {
match u64::from_str(&unparsed) {
Err(_) => {
response.set_mut(status::BadRequest);
response.set_mut(format!("Value for 'n' parameter isn't a number {:?}\n", unparsed));
return Ok(response);
}
Ok(n) => { numbers.push(n); }
}
}
let mut d = numbers[0];
for m in &numbers[1..] {
d = gcd(d, *m);
}
response.set_mut(status::Ok);
response.set_mut(mime!(Text/Html; Charset=Utf8));
response.set_mut(format!("The GCD of {:?} is {}.\n", numbers, d));
Ok(response)
}

View File

@ -0,0 +1,9 @@
[package]
name = "mandelbrot"
version = "0.1.0"
authors = ["Kyle Isom <kyle@imap.cc>"]
[dependencies]
crossbeam = "0.2.8"
image = "0.13.0"
num = "0.1.27"

View File

@ -0,0 +1,165 @@
extern crate crossbeam;
extern crate image;
extern crate num;
use image::png::PNGEncoder;
use image::ColorType;
use num::Complex;
use std::fs::File;
use std::io::Write;
use std::str::FromStr;
#[allow(dead_code)]
fn parse_pair<T: FromStr>(s: &str, separator: char) -> Option<(T, T)> {
match s.find(separator) {
None => None,
Some(index) => match (T::from_str(&s[..index]), T::from_str(&s[index + 1..])) {
(Ok(l), Ok(r)) => Some((l, r)),
_ => None,
},
}
}
fn parse_complex(s: &str) -> Option<Complex<f64>> {
match parse_pair(s, ',') {
Some((re, im)) => Some(Complex { re, im }),
None => None,
}
}
#[test]
fn test_parse_complex() {
assert_eq!(
parse_complex("1.25,-0.0625"),
Some(Complex {
re: 1.25,
im: -0.0625
})
);
assert_eq!(parse_complex(",-0.0625", None))
}
fn escape_time(c: Complex<f64>, limit: u32) -> Option<u32> {
let mut z = Complex { re: 0.0, im: 0.0 };
for i in 0..limit {
z = z * z + c;
if z.norm_sqr() > 4.0 {
return Some(i);
}
}
None
}
fn pixel_to_point(
bounds: (usize, usize),
pixel: (usize, usize),
upper_left: Complex<f64>,
lower_right: Complex<f64>,
) -> Complex<f64> {
let (width, height) = (
lower_right.re - upper_left.re,
upper_left.im - lower_right.im,
);
Complex {
re: upper_left.re + pixel.0 as f64 * width / bounds.0 as f64,
// Subtraction because pixel.1 increases downward, but the imaginary
// component increases upward.
im: upper_left.im - pixel.1 as f64 * height / bounds.1 as f64,
}
}
#[test]
fn test_pixel_to_point() {
assert_eq!(
pixel_to_point(
(100, 100),
(25, 75),
Complex { re: -1.0, im: 1.0 },
Complex { re: 1.0, im: -1.0 }
),
Complex { re: -0.5, im: -0.5 }
);
}
fn render(
pixels: &mut [u8],
bounds: (usize, usize),
upper_left: Complex<f64>,
lower_right: Complex<f64>,
) {
assert!(pixels.len() == bounds.0 * bounds.1);
for row in 0..bounds.1 {
for column in 0..bounds.1 {
let point = pixel_to_point(bounds, (column, row), upper_left, lower_right);
pixels[row * bounds.0 + column] = match escape_time(point, 255) {
None => 0,
Some(count) => 255 - count as u8,
};
}
}
}
fn write_image(
filename: &str,
pixels: &[u8],
bounds: (usize, usize),
) -> Result<(), std::io::Error> {
let output = File::create(filename)?;
let encoder = PNGEncoder::new(output);
encoder.encode(
&pixels,
bounds.0 as u32,
bounds.1 as u32,
ColorType::Gray(8),
)?;
Ok(())
}
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() != 5 {
writeln!(
std::io::stderr(),
"Usage: mandelbrot FILE PIXELS UPPERLEFT LOWERRIGHT"
).unwrap();
writeln!(
std::io::stderr(),
"Example: {} mandel.png 1000x750 -1.20,0.35 -1,0.20",
args[0]
).unwrap();
std::process::exit(1);
}
let bounds: (usize, usize) = parse_pair(&args[2], 'x').expect("error parsing image dimensions");
let upper_left = parse_complex(&args[3]).expect("error parsing upper left corner point");
let lower_right = parse_complex(&args[4]).expect("error parsing lower right corner point");
let mut pixels = vec![0; bounds.0 * bounds.1];
let threads = 8;
let rows_per_band = bounds.1 / threads + 1;
{
let bands: Vec<&mut [u8]> = pixels.chunks_mut(rows_per_band * bounds.0).collect();
crossbeam::scope(|spawner| {
for (i, band) in bands.into_iter().enumerate() {
let top = rows_per_band * i;
let height = band.len() / bounds.0;
let band_bounds = (bounds.0, height);
let band_upper_left = pixel_to_point(bounds, (0, top), upper_left, lower_right);
let band_lower_right =
pixel_to_point(bounds, (bounds.0, top + height), upper_left, lower_right);
spawner.spawn(move || {
println!("spawned: {}", i);
render(band, band_bounds, band_upper_left, band_lower_right);
});
}
});
}
write_image(&args[1], &pixels, bounds).expect("error writing PNG file");
}

35
ostep/hw5.txt Normal file
View File

@ -0,0 +1,35 @@
Homework for chapter 5: Interlude: Process API
1. Write a program that calls fork(). Before calling fork(), have the main
program access a variable and set its value to something. What value is the
variable in the child process? What happens to the variable when both the child
and the parent change the value of x?
2. Write a program that opens a new file with open() and then calls fork() to
create a new process. Can both the child and the parent access the file
descriptor returned by open()? What happens when they are writing to the file
concurrently?
3. Write another program using fork(). The child process should print "hello",
the parent process should print "goodbye". You should try to ensure that the
child process always prints first; can you do this without calling wait() in
the parent?
4. Write a program that calls fork() and then calls some form of exec() to run
/bin/ls. See if you can try all the variants of exec(), including execl(),
execle(), execlp(), execv(), execvp(), and execevP(). Why do you think there
are so many variants of the same basic call?
5. Now write a program that uses wait() to wait for the child process to finish
in the parent. What does wait() return? What happens if you use wait() in the
child()?
6. Write a slight modification of the previous program, this time using
waitpid() instead of wait(). When would waitpid() be useful?
7. Write a program that creates a child process, and then in the child close
standard output. What happens if the child calls printf() to print some output
after closing the descriptor?
8. Write a program that creates two children, and connects the standard output
of one to the standard input of the other using the pipe() system call.