Skip to content

Instantly share code, notes, and snippets.

@jorendorff
Created November 8, 2018 10:22
Show Gist options
  • Save jorendorff/c04b6a2b56db051e0493de13acb77df0 to your computer and use it in GitHub Desktop.
Save jorendorff/c04b6a2b56db051e0493de13acb77df0 to your computer and use it in GitHub Desktop.
mod sorting {
#[test]
fn sorting_integers() {
// Sorting a vector of integers is easy.
let mut integers = vec![8, 6, 7, 5, 3, 0, 9];
integers.sort();
assert_eq!(integers, vec![0, 3, 5, 6, 7, 8, 9]);
}
#[allow(dead_code)]
struct City {
name: String,
population: i64,
country: String,
lat_long: (f64, f64),
is_fictional: bool,
has_hot_chicken: bool,
monster_attack_risk: f64
}
impl City {
fn new(t: (&'static str, i64, &'static str, (f64, f64), bool, bool, f64)) -> City {
City {
name: t.0.to_string(),
population: t.1,
country: t.2.to_string(),
lat_long: t.3,
is_fictional: t.4,
has_hot_chicken: t.5,
monster_attack_risk: t.6
}
}
}
fn sample_data() -> Vec<City> {
[
("Gainesville", 277163, "USA", (29.6500583, -82.3487493), false, false, 0.0),
("Athens", 203189, "USA", (33.9497366, -83.3733819), false, false, 0.0),
("Lexington", 500535, "USA", (38.0220905, -84.5053408), false, false, 0.0),
("Columbia, MO", 174974, "USA", (38.9359174, -92.3334619), false, false, 0.0),
("Columbia, SC", 810068, "USA", (33.9730840, -81.0187890), false, false, 0.0),
("Knoxville", 861424, "USA", (35.9525345, -83.9246578), false, false, 0.0),
("Nashville", 1830345, "USA", (36.1430984, -86.8085619), false, true, 13.2),
("Tuscaloosa", 239908, "USA", (33.2079134, -87.5496290), true, false, 0.0),
("Fayetteville", 513559, "USA", (36.0677677, -94.1778107), false, false, 0.0),
("Auburn", 156993, "USA", (32.6028163, -85.4901143), false, false, 0.0),
("Baton Rouge", 830480, "USA", (30.4117210, -91.1842500), false, false, 0.0),
("Starkville", 49800, "USA", (33.4563214, -88.7938700), false, false, 117.0),
("Oxford", 53154, "USA", (34.3618972, -89.5336923), false, false, 0.0),
("College Station", 249156, "USA", (30.6098417, -96.3404366), false, false, 0.0)
].iter().map(|&t| City::new(t)).collect()
}
#[test]
fn sort_with_key_fn() {
/// Helper function for sorting cities by population.
fn city_population_descending(city: &City) -> i64 {
-city.population
}
fn sort_cities(cities: &mut Vec<City>) {
cities.sort_by_key(city_population_descending); // ok
}
let mut cities = sample_data();
sort_cities(&mut cities);
assert_eq!(cities[0].name, "Nashville");
}
#[test]
fn sort_with_key_closure() {
fn sort_cities(cities: &mut Vec<City>) {
cities.sort_by_key(|city| -city.population);
}
let mut cities = sample_data();
sort_cities(&mut cities);
assert_eq!(cities[0].name, "Nashville");
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
enum Statistic {
Population,
MonsterAttackRisk
}
impl City {
fn get_statistic(&self, stat: Statistic) -> i64 {
match stat {
Statistic::Population => self.population,
Statistic::MonsterAttackRisk => self.monster_attack_risk as i64
}
}
}
#[test]
fn sort_closure() {
/// Sort by any of several different statistics.
fn sort_by_statistic(cities: &mut Vec<City>, stat: Statistic) {
cities.sort_by_key(|city| -city.get_statistic(stat));
}
let mut cities = sample_data();
sort_by_statistic(&mut cities, Statistic::Population);
assert_eq!(cities[0].name, "Nashville");
}
#[test]
fn sort_on_thread() {
use std::thread;
fn start_sorting_thread(mut cities: Vec<City>, stat: Statistic)
-> thread::JoinHandle<Vec<City>>
{
let key_fn = move |city: &City| -> i64 { -city.get_statistic(stat) };
thread::spawn(move || {
cities.sort_by_key(key_fn);
cities
})
}
let s = start_sorting_thread(sample_data(), Statistic::Population);
let results = s.join().unwrap();
assert_eq!(results[0].name, "Nashville");
}
#[test]
fn test_function_values_in_expr() {
/// Helper function for sorting cities by population.
fn city_population_descending(city: &City) -> i64 {
-city.population
}
fn city_monster_attack_risk_descending(city: &City) -> i64 {
-city.monster_attack_risk as i64
}
struct Prefs { by_population: bool }
struct User { prefs: Prefs }
let user = User { prefs: Prefs { by_population: false } };
let mut cities = sample_data();
let my_key_fn: fn(&City) -> i64 =
if user.prefs.by_population {
city_population_descending
} else {
city_monster_attack_risk_descending
};
cities.sort_by_key(my_key_fn);
assert_eq!(cities[0].name, "Starkville");
}
#[test]
fn count_cities_by_function() {
let my_cities = sample_data();
/// Given a list of cities and a test function,
/// return how many cities pass the test.
fn count_selected_cities(cities: &Vec<City>,
test_fn: fn(&City) -> bool) -> usize
{
let mut count = 0;
for city in cities {
if test_fn(city) {
count += 1;
}
}
count
}
/// An example of a test function. Note that the type of
/// this function is `fn(&City) -> bool`, the same as
/// the `test_fn` argument to `count_selected_cities`.
fn has_monster_attacks(city: &City) -> bool {
city.monster_attack_risk > 0.0
}
// How many cities are at risk for monster attack?
let n = count_selected_cities(&my_cities, has_monster_attacks);
assert_eq!(n, 2);
}
#[test]
fn count_cities_by_closure() {
fn count_selected_cities<F>(cities: &Vec<City>, test_fn: F) -> usize
where F: Fn(&City) -> bool
{
let mut count = 0;
for city in cities {
if test_fn(city) {
count += 1;
}
}
count
}
let my_cities = sample_data();
fn has_monster_attacks(city: &City) -> bool {
city.monster_attack_risk > 0.0
}
let limit = 0.0000001;
count_selected_cities(
&my_cities,
has_monster_attacks); // ok
count_selected_cities(
&my_cities,
|city| city.monster_attack_risk > limit); // also ok
}
#[allow(dead_code)]
type CityFilterType =
fn(&City) -> bool // fn type (functions only)
;
#[allow(dead_code)]
type CityFilterTrait =
Fn(&City) -> bool // Fn trait (both functions and closures)
;
}
mod fnonce_closures {
#[test]
fn you_can_call_a_thing_twice() {
fn f() {}
f();
f();
}
fn call_twice<F>(closure: F) where F: Fn() {
closure();
closure();
}
#[test]
fn test_call_twice() {
fn do_nothing() {}
call_twice(do_nothing);
call_twice(|| {}); // do-nothing closure
}
}
mod fixing_a_fnonce_closure {
use std::collections::HashMap;
fn produce_glossary() -> HashMap<String, String> {
HashMap::new()
}
#[test]
fn test_dumping_dict_twice() {
let dict = produce_glossary();
let debug_dump_dict = || {
for (key, value) in &dict { // does not use up dict
println!("{:?} - {:?}", key, value);
}
};
debug_dump_dict();
debug_dump_dict();
}
}
mod fnmut_closures {
#[allow(dead_code)]
fn can_call_incr_twice_1() {
let mut i = 0;
let incr = || {
i += 1; // incr borrows a mut reference to i
println!("Ding! i is now: {}", i);
};
call_twice(incr);
}
fn call_twice<F>(mut closure: F) where F: FnMut() {
closure();
closure();
}
#[test]
fn can_call_incr_twice_2() {
let mut i = 0;
call_twice(|| i += 1); // ok!
assert_eq!(i, 2);
}
}
#[test]
fn router_supports_closures() {
use router::Router;
use iron::prelude::{Iron, IronResult, Request, Response};
use iron::status;
fn get_form_response() -> Response {
Response::with((status::Ok, "Hello World!"))
}
fn get_numbers(_request: &Request) -> IronResult<Vec<i64>> {
unimplemented!();
}
fn get_gcd_response(_numbers: Vec<i64>) -> Response {
unimplemented!();
}
let mut router = Router::new();
router.get("/", |_: &mut Request| {
Ok(get_form_response())
}, "root");
router.post("/gcd", |request: &mut Request| {
let numbers = get_numbers(request)?;
Ok(get_gcd_response(numbers))
}, "gcd");
let _: Iron<Router> = Iron::new(router);
}
#[allow(dead_code)]
mod basic_router {
use std::collections::HashMap;
struct Request {
method: String,
url: String,
headers: HashMap<String, String>,
body: Vec<u8>
}
struct Response {
code: u32,
headers: HashMap<String, String>,
body: Vec<u8>
}
type BoxedCallback = Box<Fn(&Request) -> Response>;
struct BasicRouter {
routes: HashMap<String, BoxedCallback>
}
impl BasicRouter {
// Create an empty router.
fn new() -> BasicRouter {
BasicRouter { routes: HashMap::new() }
}
// Add a route to the router.
fn add_route<C>(&mut self, url: &str, callback: C)
where C: Fn(&Request) -> Response + 'static
{
self.routes.insert(url.to_string(), Box::new(callback));
}
}
impl BasicRouter {
fn handle_request(&self, request: &Request) -> Response {
match self.routes.get(&request.url) {
None => not_found_response(),
Some(callback) => callback(request)
}
}
}
fn not_found_response() -> Response {
Response {
code: 404,
headers: HashMap::new(),
body: b"<h1>Page not found</h1>".to_vec()
}
}
fn get_form_response() -> Response {
Response {
code: 200,
headers: HashMap::new(),
body: b"<form>".to_vec()
}
}
fn get_gcd_response(_req: &Request) -> Response {
Response {
code: 500,
headers: HashMap::new(),
body: b"<h1>Internal server error</h1>".to_vec()
}
}
fn req(url: &str) -> Request {
Request {
method: "GET".to_string(),
url: url.to_string(),
headers: HashMap::new(),
body: vec![]
}
}
#[test]
fn test_router() {
let mut router = BasicRouter::new();
router.add_route("/", |_| get_form_response());
router.add_route("/gcd", |req| get_gcd_response(req));
assert_eq!(router.handle_request(&req("/piano")).code, 404);
assert_eq!(router.handle_request(&req("/")).code, 200);
assert_eq!(router.handle_request(&req("/gcd")).code, 500);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment