<commit_before>extern crate time;

use std::rand::{Rng, task_rng, SeedableRng, StdRng};
use std::rand::distributions::{IndependentSample, Range};
use std::collections::HashMap;
use time::precise_time_ns;
use std::io::{File, BufferedReader, IoResult};
use std::iter::Repeat;
use std::fmt;

pub type Node = uint;

#[deriving(Show)]
pub struct NodePt {
    id: Node,
    x: f64,
    y: f64
}

impl NodePt {
	fn new(nodeId: Node, x: f64, y: f64) -> NodePt {
		NodePt {
			id: nodeId,
			x: x,
			y: y
		}
	}

	fn distance_to(self, other: NodePt) -> f64 {
		let xx = (self.x - other.x) * (self.x - other.x);
		let yy = (self.y - other.y) * (self.y - other.y);

		(xx+yy).sqrt()
	}
}

impl PartialEq for NodePt {
	fn eq(&self, other: &NodePt) -> bool {
		self.id == other.id
	}

	fn ne(&self, other: &NodePt) -> bool {
		self.id != other.id
	}
}

#[deriving(Show, Clone)]
pub struct Edge {
	from: Node,
	to: Node,
	weight: f64
}

impl Edge {
	fn new(a: NodePt, b: NodePt) -> Edge {
		Edge {
			from: a.id,
			to: b.id,
			weight: a.distance_to(b)
		}
	}
}

#[deriving(Show, Clone)]
pub struct Tour {
    nodes: Vec<Node>,
    total_weight: f64
}

impl PartialEq for Tour {
	fn eq(&self, other: &Tour) -> bool {
		self.nodes == other.nodes
	}

	fn ne(&self, other: &Tour) -> bool {
		self.nodes != other.nodes
	}
}

impl PartialOrd for Tour {
	fn lt(&self, other: &Tour) -> bool {
		self.total_weight < other.total_weight
	}
}

impl Tour {
	fn new(nodes: Vec<Node>, weight: f64) -> Tour {
		Tour {
			nodes: nodes,
			total_weight: weight
		}
	}

	fn calc_tour_weight(tour: &Vec<Node>, graph: &Graph) -> f64 {
		let mut tour_weight = 0.0;
		let mut last_node = tour.get(0u);
		for node in tour.iter() {
			tour_weight += graph.get(*last_node, *node);
			last_node = node;
		}

		tour_weight
	}

	fn random_tour<R: Rng>(rng: &mut R, graph: &Graph) -> Tour {
		let node_count = graph.size();
		let mut tour_nodes = graph.nodes();
		rng.shuffle(tour_nodes.as_mut_slice());
		let last: Node = *tour_nodes.last().unwrap();
		tour_nodes.insert(0, last);
		let tour_weight = Tour::calc_tour_weight(&tour_nodes, graph);
		Tour::new(tour_nodes, tour_weight)
	}

	fn mutate<R: Rng>(&self, rng: &mut R, graph: &Graph, mutation_rate: f64) -> Tour {
		let size = self.nodes.len() as f64;
		let mut mutated: Vec<Node> = self.nodes.clone();

		for i in range(0, self.nodes.len()) {
			let t = rng.gen::<f64>();
			if t < mutation_rate {
				let j = (rng.gen::<f64>() * size) as uint;
				mutated.as_mut_slice().swap(i, j);
			}
		}
		let weight = Tour::calc_tour_weight(&mutated, graph);
		Tour {
			nodes: mutated,
			total_weight: weight
		}
	}

	fn crossover<R: Rng>(&self, other: Tour, graph: &Graph, rng: &mut R) -> Tour {
		let size = self.nodes.len();
		let start = (rng.gen::<f64>() * (size as f64)) as uint;
		let end = (rng.gen::<f64>() * (size as f64)) as uint;

		let mut new_tour: Vec<Node> = Vec::new();
		new_tour.grow_set(size - 1, &(std::uint::MAX), std::uint::MAX);

		for i in range(0, size) {
			if start < end && i > start && i < end {
				//new_tour[i] = self.nodes.get(i);
				new_tour.grow_set(i, &(std::uint::MAX), *self.nodes.get(i));
			}
			else if start > end {
				if !(i < start && i > end) {
					*new_tour.get_mut(i) = *self.nodes.get(i);
				}
			}
		}

		for i in range(0, size) {
			if !new_tour.contains(other.nodes.get(i)) {
				for j in range(0, new_tour.len()) {
					if *new_tour.get(j) == std::uint::MAX {
						*new_tour.get_mut(i) = *other.nodes.get(i);
						break;
					}
				}
			}
		}

		let tour_weight = Tour::calc_tour_weight(&new_tour, graph);

		Tour::new(new_tour, tour_weight)
	}
}

#[deriving(Show)]
pub struct Graph {
	adj_list: HashMap<Node, Vec<Edge>>
}

impl Graph {
	fn new(adj_list: HashMap<Node, Vec<Edge>>) -> Graph {
		Graph {
			adj_list: adj_list
		}
	}

	fn from_nodes(nodes: Vec<NodePt>) -> Graph {
		let mut map: HashMap<Node, Vec<Edge>> = HashMap::new();
		for i in range(0, nodes.len()) {
			let mut adj_edges: Vec<Edge> = Vec::new();

			for j in range(0, nodes.len()) {
				let a = nodes.get(i);
				let b = nodes.get(j);
				if i != j {
					adj_edges.push(Edge::new(*a, *b));
				}
			}

			map.insert(i, adj_edges);
		}

		Graph::new(map)
	}

	fn random_graph<R: Rng>(rng: &mut R, num_nodes: uint, x_max: f64, y_max: f64) -> Graph {
		let points = rng.gen_iter::<(f64, f64)>()
			.enumerate()
			.map(|(idx, (x, y))| NodePt::new(idx, x * x_max, y * y_max))
			.take(num_nodes)
			.collect();

		Graph::from_nodes(points)
	}

	fn get(&self, n: Node, m: Node) -> f64 {
		if n == m {
			0.0
		}
		else {
			let edges = self.adj_list.get(&n);
			let result = edges.iter().filter(|edge| edge.to == m).nth(0);
			match result {
				Some(edge) => edge.weight,
				None => 0.0
			}
		}
	}

	fn size(&self) -> uint {
		self.adj_list.len()
	}

	fn nodes(&self) -> Vec<Node> {
		range(0, self.size()).collect()
	}

	fn from_file(file_path: &str) -> Graph {
		let path = Path::new(file_path);
		let mut file = BufferedReader::new(File::open(&path));
		let mut nodes: Vec<NodePt> = Vec::new();
		let mut i = 0u;

		for line in file.lines() {
			let mut numbers: Vec<f64> = Vec::new();
			// This could be a lot nicer
			match line {
				Ok(val) => {
					for token in val.as_slice().split(' ') {
						if token == "\n" {
							continue
						}

						let n = match from_str::<f64>(token) {
							Some(num) => num,
							None => continue
						};
						numbers.push(n);
					}
				},
				Err(_) => fail!("Failed reading file.")
			}
			if numbers.len() == 2 {
				let point = NodePt::new(i, *numbers.get(0), *numbers.get(1));
				nodes.push(point);
			}
			i += 1;
		}

		Graph::from_nodes(nodes)
	}
}

struct Population {
	rng: StdRng,
	graph: Box<Graph>,
	population: Vec<Tour>,
	mutation_rate: f64,
	tournament_size: uint
}

impl Population {
	fn new(population_count: uint, graph: Box<Graph>, mutation_rate: f64, tournament_size: uint) -> Population {
		let mut rng: StdRng = SeedableRng::from_seed(&[12, 13, 14, 15]);
		let population = Vec::from_fn(population_count, |_| Tour::random_tour(&mut rng, graph));

		Population {
			rng: rng,
			graph: graph,
			population: population,
			mutation_rate: mutation_rate,
			tournament_size: tournament_size
		}
	}

	fn fittest(&self) -> Tour {
		self.population.iter().fold(self.population.get(0), |min, next| if next < min { next } else { min }).clone()
	}

	fn tournament_selection(&mut self) -> Tour {
		// let mut sample = self.population.clone();
		// self.rng.shuffle(sample.as_mut_slice());
		// let tournament: Vec<Tour> = sample.iter().take(self.tournament_size).collect();
		// tournament.iter().fold(tournament.get(0), |min, next| if next < min {next} else {min}).clone()
		let size = self.population.len();
		let mut buffer: Vec<&Tour> = Vec::new();
		for i in range(0, self.tournament_size) {
			let t = (self.rng.gen::<f64>() * (size as f64)) as uint;
			buffer.push(self.population.get(t));
		}

		buffer.iter().fold(buffer.get(0), |min, next| if next < min {next} else {min})
	}

	fn evolve(&mut self) {

	}
}

impl fmt::Show for Population {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "Population: {}", self.population)
	}
}

fn main() {
	let mut rng: StdRng = SeedableRng::from_seed(&[12, 13, 14, 15]);
	let graph = Graph::random_graph(&mut rng, 5, 200.0, 200.0);
	let pop = Population::new(5, box graph, 0.015, 5);
	println!("{}", pop);
	println!("{}", pop.fittest())
}<commit_msg>GA should be working now<commit_after>//extern crate time;

use std::rand::{Rng, SeedableRng, StdRng};
use std::collections::HashMap;
//use time::precise_time_ns;
use std::io::{File, BufferedReader};
use std::fmt;

pub type Node = uint;

#[deriving(Show)]
pub struct NodePt {
    id: Node,
    x: f64,
    y: f64
}

impl NodePt {
    fn new(nodeId: Node, x: f64, y: f64) -> NodePt {
        NodePt {
            id: nodeId,
            x: x,
            y: y
        }
    }

    fn distance_to(self, other: NodePt) -> f64 {
        let xx = (self.x - other.x) * (self.x - other.x);
        let yy = (self.y - other.y) * (self.y - other.y);

        (xx+yy).sqrt()
    }
}

impl PartialEq for NodePt {
    fn eq(&self, other: &NodePt) -> bool {
        self.id == other.id
    }

    fn ne(&self, other: &NodePt) -> bool {
        self.id != other.id
    }
}

#[deriving(Show, Clone)]
pub struct Edge {
    from: Node,
    to: Node,
    weight: f64
}

impl Edge {
    fn new(a: NodePt, b: NodePt) -> Edge {
        Edge {
            from: a.id,
            to: b.id,
            weight: a.distance_to(b)
        }
    }
}

#[deriving(Show, Clone)]
pub struct Tour {
    nodes: Vec<Node>,
    total_weight: f64
}

impl PartialEq for Tour {
    fn eq(&self, other: &Tour) -> bool {
        self.nodes == other.nodes
    }

    fn ne(&self, other: &Tour) -> bool {
        self.nodes != other.nodes
    }
}

impl PartialOrd for Tour {
    fn lt(&self, other: &Tour) -> bool {
        self.total_weight < other.total_weight
    }
}

impl Tour {
    fn new(nodes: Vec<Node>, weight: f64) -> Tour {
        Tour {
            nodes: nodes,
            total_weight: weight
        }
    }

    fn calc_tour_weight(tour: &Vec<Node>, graph: &Graph) -> f64 {
        let mut tour_weight = 0.0;
        let mut last_node = tour.get(0u);

        for node in tour.iter() {
            tour_weight += graph.get(*last_node, *node);
            last_node = node;
        }

        tour_weight
    }

    fn random_tour<R: Rng>(rng: &mut R, graph: &Graph) -> Tour {
        let mut tour_nodes = graph.nodes();
        rng.shuffle(tour_nodes.as_mut_slice());
        let last: Node = *tour_nodes.last().unwrap();
        tour_nodes.insert(0, last);
        let tour_weight = Tour::calc_tour_weight(&tour_nodes, graph);
        Tour::new(tour_nodes, tour_weight)
    }

    fn mutate<R: Rng>(&self, rng: &mut R, graph: &Graph, mutation_rate: f64) -> Tour {
        let size = self.nodes.len() as f64;
        let mut mutated: Vec<Node> = self.nodes.clone();

        for i in range(0, self.nodes.len()) {
            let t = rng.gen::<f64>();
            if t < mutation_rate {
                let j = (rng.gen::<f64>() * size) as uint;
                mutated.as_mut_slice().swap(i, j);
            }
        }
        let weight = Tour::calc_tour_weight(&mutated, graph);
        Tour {
            nodes: mutated,
            total_weight: weight
        }
    }

    // fn crossover<R: Rng>(&self, other: Tour, graph: &Graph, rng: &mut R) -> Tour {
    //     let size = self.nodes.len();
    //     let start = (rng.gen::<f64>() * (size as f64)) as uint;
    //     let end = (rng.gen::<f64>() * (size as f64)) as uint;

    //     assert!(self.nodes.len() == other.nodes.len());
    //     println!("start = {}, end = {}", start, end)

    //     let mut new_tour: Vec<Node> = Vec::new();
    //     new_tour.grow_set(size - 1, &(std::uint::MAX), std::uint::MAX);

    //     for i in range(0, size) {
    //         if start < end && i > start && i < end {
    //             //new_tour.grow_set(i, &(std::uint::MAX), *self.nodes.get(i));
    //             *new_tour.get_mut(i) = *self.nodes.get(i);
    //         }
    //         else if start > end {
    //             if !(i < start && i > end) {
    //                 *new_tour.get_mut(i) = *self.nodes.get(i);
    //             }
    //         }
    //     }

    //     for i in range(0, size) {
    //         if !new_tour.contains(other.nodes.get(i)) {
    //             for j in range(0, new_tour.len()) {
    //                 if *new_tour.get(j) == std::uint::MAX {
    //                     *new_tour.get_mut(i) = *other.nodes.get(i);
    //                     break;
    //                 }
    //             }
    //         }
    //     }
    //     println!("new_tour = {}", new_tour)
    //     let tour_weight = Tour::calc_tour_weight(&new_tour, graph);
    //     Tour::new(new_tour, tour_weight)
    // }

    fn crossover<R: Rng>(&self, other: Tour, graph: &Graph, rng: &mut R) -> Tour {
        let size = self.nodes.len();
        let mut start = (rng.gen::<f64>() * (size as f64)) as uint;
        let mut end = (rng.gen::<f64>() * (size as f64)) as uint;
        if start == end {
            return self.clone()
        }

        if end > start {
            std::mem::swap(&mut start, &mut end);
        }

        let new_tour = Vec::from_fn(size, |i| {
            if i >= start && i <= end {
                *self.nodes.get(i)
            } else {
                *other.nodes.get(i)
            }
        });

        let tour_weight = Tour::calc_tour_weight(&new_tour, graph);
        Tour::new(new_tour, tour_weight)
    }
}

#[deriving(Show, Clone)]
pub struct Graph {
    adj_list: HashMap<Node, Vec<Edge>>
}

impl Graph {
    fn new(adj_list: HashMap<Node, Vec<Edge>>) -> Graph {
        Graph {
            adj_list: adj_list
        }
    }

    fn from_nodes(nodes: Vec<NodePt>) -> Graph {
        let mut map: HashMap<Node, Vec<Edge>> = HashMap::new();
        for i in range(0, nodes.len()) {
            let mut adj_edges: Vec<Edge> = Vec::new();

            for j in range(0, nodes.len()) {
                let a = nodes.get(i);
                let b = nodes.get(j);
                if i != j {
                    adj_edges.push(Edge::new(*a, *b));
                }
            }

            map.insert(i, adj_edges);
        }

        Graph::new(map)
    }

    fn random_graph<R: Rng>(rng: &mut R, num_nodes: uint, x_max: f64, y_max: f64) -> Graph {
        let points = rng.gen_iter::<(f64, f64)>()
            .enumerate()
            .map(|(idx, (x, y))| NodePt::new(idx, x * x_max, y * y_max))
            .take(num_nodes)
            .collect();

        Graph::from_nodes(points)
    }

    fn get(&self, n: Node, m: Node) -> f64 {
        if n == m {
            0.0
        }
        else {
            let edges = self.adj_list.get(&n);
            let result = edges.iter().filter(|edge| edge.to == m).nth(0);
            match result {
                Some(edge) => edge.weight,
                None => fail!("No edge found!")
            }
        }
    }

    fn size(&self) -> uint {
        self.adj_list.len()
    }

    fn nodes(&self) -> Vec<Node> {
        range(0, self.size()).collect()
    }

    #[allow(dead_code)]
    fn from_file(file_path: &str) -> Graph {
        let path = Path::new(file_path);
        let mut file = BufferedReader::new(File::open(&path));
        let mut nodes: Vec<NodePt> = Vec::new();
        let mut i = 0u;

        for line in file.lines() {
            let mut numbers: Vec<f64> = Vec::new();
            // This could be a lot nicer
            match line {
                Ok(val) => {
                    for token in val.as_slice().split(' ') {
                        if token == "\n" {
                            continue
                        }

                        let n = match from_str::<f64>(token) {
                            Some(num) => num,
                            None => continue
                        };
                        numbers.push(n);
                    }
                },
                Err(_) => fail!("Failed reading file.")
            }

            if numbers.len() == 2 {
                let point = NodePt::new(i, *numbers.get(0), *numbers.get(1));
                nodes.push(point);
            }

            i += 1;
        }

        Graph::from_nodes(nodes)
    }
}

struct Population {
    rng: StdRng,
    graph: Box<Graph>,
    population: Vec<Tour>,
    mutation_rate: f64,
    tournament_size: uint
}

impl Population {
    fn new(population_count: uint, graph: Box<Graph>, mutation_rate: f64, tournament_size: uint) -> Population {
        let mut rng: StdRng = SeedableRng::from_seed(&[12, 13, 14, 15]);
        let population = Vec::from_fn(population_count, |_| Tour::random_tour(&mut rng, graph));

        Population {
            rng: rng,
            graph: graph,
            population: population,
            mutation_rate: mutation_rate,
            tournament_size: tournament_size
        }
    }

    fn fittest(&self) -> Tour {
        self.population.iter().fold(self.population.get(0), |min, next| if next < min { next } else { min }).clone()
    }

    fn tournament_selection(&mut self) -> Tour {
        let size = self.population.len();
        let mut buffer: Vec<Tour> = Vec::new();
        for _ in range(0, self.tournament_size) {
            let t = (self.rng.gen::<f64>() * (size as f64)) as uint;
            buffer.push(self.population.get(t).clone());
        }

        buffer.iter().fold(buffer.get(0), |min, next| if next < min {next} else {min}).clone()
    }

    fn evolve(&mut self) -> Population {
        let mut new_population: Vec<Tour> = Vec::new();

        for _ in range(0, self.population.len()) {
            let parent1 = self.tournament_selection();
            let parent2 = self.tournament_selection();
            let child: Tour = parent1.crossover(parent2, self.graph, &mut self.rng);
            new_population.push(child);
        }

        let mutated = new_population.iter().map(|tour| tour.mutate(&mut self.rng, self.graph, self.mutation_rate)).collect();

        Population {
            rng: self.rng,
            graph: self.graph.clone(),
            population: mutated,
            mutation_rate: self.mutation_rate,
            tournament_size: self.tournament_size
        }
    }
}

impl fmt::Show for Population {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Population: {}", self.population)
    }
}

fn main() {
    let mut rng: StdRng = match StdRng::new() {
        Ok(r) => r,
        Err(why) => fail!("failed to acquire RNG")
    };
    let graph = Graph::random_graph(&mut rng, 25, 200.0, 200.0);
    let mut pop = Population::new(10000, box graph, 0.015, 5);
    println!("Fittest at start: {}", pop.fittest())

    for _ in range(0, 100) {
        pop = pop.evolve();
    }

    println!("Fittest at end: {}", pop.fittest())
}<|endoftext|>


<commit_before>//extern crate time;

use std::rand::{Rng, SeedableRng, StdRng};
use std::collections::HashMap;
//use time::precise_time_ns;
use std::io::{File, BufferedReader};
use std::fmt;

pub type Node = uint;

#[deriving(Show)]
pub struct NodePt {
    id: Node,
    x: f64,
    y: f64
}

impl NodePt {
    fn new(nodeId: Node, x: f64, y: f64) -> NodePt {
        NodePt {
            id: nodeId,
            x: x,
            y: y
        }
    }

    fn distance_to(self, other: NodePt) -> f64 {
        let xx = (self.x - other.x) * (self.x - other.x);
        let yy = (self.y - other.y) * (self.y - other.y);

        (xx+yy).sqrt()
    }
}

impl PartialEq for NodePt {
    fn eq(&self, other: &NodePt) -> bool {
        self.id == other.id
    }

    fn ne(&self, other: &NodePt) -> bool {
        self.id != other.id
    }
}

#[deriving(Show, Clone)]
pub struct Edge {
    from: Node,
    to: Node,
    weight: f64
}

impl Edge {
    fn new(a: NodePt, b: NodePt) -> Edge {
        Edge {
            from: a.id,
            to: b.id,
            weight: a.distance_to(b)
        }
    }
}

#[deriving(Show, Clone)]
pub struct Tour {
    nodes: Vec<Node>,
    total_weight: f64
}

impl PartialEq for Tour {
    fn eq(&self, other: &Tour) -> bool {
        self.nodes == other.nodes
    }

    fn ne(&self, other: &Tour) -> bool {
        self.nodes != other.nodes
    }
}

impl PartialOrd for Tour {
    fn lt(&self, other: &Tour) -> bool {
        self.total_weight < other.total_weight
    }
}

impl Tour {
    fn new(nodes: Vec<Node>, weight: f64) -> Tour {
        Tour {
            nodes: nodes,
            total_weight: weight
        }
    }

    fn calc_tour_weight(tour: &Vec<Node>, graph: &Graph) -> f64 {
        let mut tour_weight = 0.0;
        let mut last_node = tour.get(0u);

        for node in tour.iter() {
            tour_weight += graph.get(*last_node, *node);
            last_node = node;
        }

        tour_weight
    }

    fn random_tour<R: Rng>(rng: &mut R, graph: &Graph) -> Tour {
        let mut tour_nodes = graph.nodes();
        rng.shuffle(tour_nodes.as_mut_slice());
        let last: Node = *tour_nodes.last().unwrap();
        tour_nodes.insert(0, last);
        let tour_weight = Tour::calc_tour_weight(&tour_nodes, graph);
        Tour::new(tour_nodes, tour_weight)
    }

    fn mutate<R: Rng>(&self, rng: &mut R, graph: &Graph, mutation_rate: f64) -> Tour {
        let size = self.nodes.len() as f64;
        let mut mutated: Vec<Node> = self.nodes.clone();

        for i in range(0, self.nodes.len()) {
            let t = rng.gen::<f64>();
            if t < mutation_rate {
                let j = (rng.gen::<f64>() * size) as uint;
                mutated.as_mut_slice().swap(i, j);
            }
        }
        let weight = Tour::calc_tour_weight(&mutated, graph);
        Tour {
            nodes: mutated,
            total_weight: weight
        }
    }

    // fn crossover<R: Rng>(&self, other: Tour, graph: &Graph, rng: &mut R) -> Tour {
    //     let size = self.nodes.len();
    //     let start = (rng.gen::<f64>() * (size as f64)) as uint;
    //     let end = (rng.gen::<f64>() * (size as f64)) as uint;

    //     assert!(self.nodes.len() == other.nodes.len());
    //     println!("start = {}, end = {}", start, end)

    //     let mut new_tour: Vec<Node> = Vec::new();
    //     new_tour.grow_set(size - 1, &(std::uint::MAX), std::uint::MAX);

    //     for i in range(0, size) {
    //         if start < end && i > start && i < end {
    //             //new_tour.grow_set(i, &(std::uint::MAX), *self.nodes.get(i));
    //             *new_tour.get_mut(i) = *self.nodes.get(i);
    //         }
    //         else if start > end {
    //             if !(i < start && i > end) {
    //                 *new_tour.get_mut(i) = *self.nodes.get(i);
    //             }
    //         }
    //     }

    //     for i in range(0, size) {
    //         if !new_tour.contains(other.nodes.get(i)) {
    //             for j in range(0, new_tour.len()) {
    //                 if *new_tour.get(j) == std::uint::MAX {
    //                     *new_tour.get_mut(i) = *other.nodes.get(i);
    //                     break;
    //                 }
    //             }
    //         }
    //     }
    //     println!("new_tour = {}", new_tour)
    //     let tour_weight = Tour::calc_tour_weight(&new_tour, graph);
    //     Tour::new(new_tour, tour_weight)
    // }

    fn crossover<R: Rng>(&self, other: Tour, graph: &Graph, rng: &mut R) -> Tour {
        let size = self.nodes.len();
        let mut start = (rng.gen::<f64>() * (size as f64)) as uint;
        let mut end = (rng.gen::<f64>() * (size as f64)) as uint;
        if start == end {
            return self.clone()
        }

        if end > start {
            std::mem::swap(&mut start, &mut end);
        }

        let new_tour = Vec::from_fn(size, |i| {
            if i >= start && i <= end {
                *self.nodes.get(i)
            } else {
                *other.nodes.get(i)
            }
        });

        let tour_weight = Tour::calc_tour_weight(&new_tour, graph);
        Tour::new(new_tour, tour_weight)
    }
}

#[deriving(Show, Clone)]
pub struct Graph {
    adj_list: HashMap<Node, Vec<Edge>>
}

impl Graph {
    fn new(adj_list: HashMap<Node, Vec<Edge>>) -> Graph {
        Graph {
            adj_list: adj_list
        }
    }

    fn from_nodes(nodes: Vec<NodePt>) -> Graph {
        let mut map: HashMap<Node, Vec<Edge>> = HashMap::new();
        for i in range(0, nodes.len()) {
            let mut adj_edges: Vec<Edge> = Vec::new();

            for j in range(0, nodes.len()) {
                let a = nodes.get(i);
                let b = nodes.get(j);
                if i != j {
                    adj_edges.push(Edge::new(*a, *b));
                }
            }

            map.insert(i, adj_edges);
        }

        Graph::new(map)
    }

    fn random_graph<R: Rng>(rng: &mut R, num_nodes: uint, x_max: f64, y_max: f64) -> Graph {
        let points = rng.gen_iter::<(f64, f64)>()
            .enumerate()
            .map(|(idx, (x, y))| NodePt::new(idx, x * x_max, y * y_max))
            .take(num_nodes)
            .collect();

        Graph::from_nodes(points)
    }

    fn get(&self, n: Node, m: Node) -> f64 {
        if n == m {
            0.0
        }
        else {
            let edges = self.adj_list.get(&n);
            let result = edges.iter().filter(|edge| edge.to == m).nth(0);
            match result {
                Some(edge) => edge.weight,
                None => fail!("No edge found!")
            }
        }
    }

    fn size(&self) -> uint {
        self.adj_list.len()
    }

    fn nodes(&self) -> Vec<Node> {
        range(0, self.size()).collect()
    }

    #[allow(dead_code)]
    fn from_file(file_path: &str) -> Graph {
        let path = Path::new(file_path);
        let mut file = BufferedReader::new(File::open(&path));
        let mut nodes: Vec<NodePt> = Vec::new();
        let mut i = 0u;

        for line in file.lines() {
            let mut numbers: Vec<f64> = Vec::new();
            // This could be a lot nicer
            match line {
                Ok(val) => {
                    for token in val.as_slice().split(' ') {
                        if token == "\n" {
                            continue
                        }

                        let n = match from_str::<f64>(token) {
                            Some(num) => num,
                            None => continue
                        };
                        numbers.push(n);
                    }
                },
                Err(_) => fail!("Failed reading file.")
            }

            if numbers.len() == 2 {
                let point = NodePt::new(i, *numbers.get(0), *numbers.get(1));
                nodes.push(point);
            }

            i += 1;
        }

        Graph::from_nodes(nodes)
    }
}

struct Population {
    rng: StdRng,
    graph: Box<Graph>,
    population: Vec<Tour>,
    mutation_rate: f64,
    tournament_size: uint
}

impl Population {
    fn new(population_count: uint, graph: Box<Graph>, mutation_rate: f64, tournament_size: uint) -> Population {
        let mut rng: StdRng = SeedableRng::from_seed(&[12, 13, 14, 15]);
        let population = Vec::from_fn(population_count, |_| Tour::random_tour(&mut rng, graph));

        Population {
            rng: rng,
            graph: graph,
            population: population,
            mutation_rate: mutation_rate,
            tournament_size: tournament_size
        }
    }

    fn fittest(&self) -> Tour {
        self.population.iter().fold(self.population.get(0), |min, next| if next < min { next } else { min }).clone()
    }

    fn tournament_selection(&mut self) -> Tour {
        let size = self.population.len();
        let mut buffer: Vec<Tour> = Vec::new();
        for _ in range(0, self.tournament_size) {
            let t = (self.rng.gen::<f64>() * (size as f64)) as uint;
            buffer.push(self.population.get(t).clone());
        }

        buffer.iter().fold(buffer.get(0), |min, next| if next < min {next} else {min}).clone()
    }

    fn evolve(&mut self) -> Population {
        let mut new_population: Vec<Tour> = Vec::new();

        for _ in range(0, self.population.len()) {
            let parent1 = self.tournament_selection();
            let parent2 = self.tournament_selection();
            let child: Tour = parent1.crossover(parent2, self.graph, &mut self.rng);
            new_population.push(child);
        }

        let mutated = new_population.iter().map(|tour| tour.mutate(&mut self.rng, self.graph, self.mutation_rate)).collect();

        Population {
            rng: self.rng,
            graph: self.graph.clone(),
            population: mutated,
            mutation_rate: self.mutation_rate,
            tournament_size: self.tournament_size
        }
    }
}

impl fmt::Show for Population {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Population: {}", self.population)
    }
}

fn main() {
    let mut rng: StdRng = match StdRng::new() {
        Ok(r) => r,
        Err(why) => fail!("failed to acquire RNG")
    };
    let graph = Graph::random_graph(&mut rng, 25, 200.0, 200.0);
    let mut pop = Population::new(10000, box graph, 0.015, 5);
    println!("Fittest at start: {}", pop.fittest())

    for _ in range(0, 100) {
        pop = pop.evolve();
    }

    println!("Fittest at end: {}", pop.fittest())
}<commit_msg>added time measurement, find_min function<commit_after>extern crate time;

use std::rand::{Rng, SeedableRng, StdRng};
use std::collections::HashMap;
use time::precise_time_ns;
use std::io::{File, BufferedReader};
use std::fmt;

pub type Node = uint;

#[deriving(Show)]
pub struct NodePt {
    id: Node,
    x: f64,
    y: f64
}

impl NodePt {
    fn new(nodeId: Node, x: f64, y: f64) -> NodePt {
        NodePt {
            id: nodeId,
            x: x,
            y: y
        }
    }

    fn distance_to(self, other: NodePt) -> f64 {
        let xx = (self.x - other.x) * (self.x - other.x);
        let yy = (self.y - other.y) * (self.y - other.y);

        (xx+yy).sqrt()
    }
}

impl PartialEq for NodePt {
    fn eq(&self, other: &NodePt) -> bool {
        self.id == other.id
    }

    fn ne(&self, other: &NodePt) -> bool {
        self.id != other.id
    }
}

#[deriving(Show, Clone)]
pub struct Edge {
    from: Node,
    to: Node,
    weight: f64
}

impl Edge {
    fn new(a: NodePt, b: NodePt) -> Edge {
        Edge {
            from: a.id,
            to: b.id,
            weight: a.distance_to(b)
        }
    }
}

#[deriving(Show, Clone)]
pub struct Tour {
    nodes: Vec<Node>,
    total_weight: f64
}

impl PartialEq for Tour {
    fn eq(&self, other: &Tour) -> bool {
        self.nodes == other.nodes
    }

    fn ne(&self, other: &Tour) -> bool {
        self.nodes != other.nodes
    }
}

impl PartialOrd for Tour {
    fn lt(&self, other: &Tour) -> bool {
        self.total_weight < other.total_weight
    }
}

impl Tour {
    fn new(nodes: Vec<Node>, weight: f64) -> Tour {
        Tour {
            nodes: nodes,
            total_weight: weight
        }
    }

    fn calc_tour_weight(tour: &Vec<Node>, graph: &Graph) -> f64 {
        let mut tour_weight = 0.0;
        let mut last_node = tour.get(0u);

        for node in tour.iter() {
            tour_weight += graph.get(*last_node, *node);
            last_node = node;
        }

        tour_weight
    }

    fn random_tour<R: Rng>(rng: &mut R, graph: &Graph) -> Tour {
        let mut tour_nodes = graph.nodes();
        rng.shuffle(tour_nodes.as_mut_slice());
        let last: Node = *tour_nodes.last().unwrap();
        tour_nodes.insert(0, last);
        let tour_weight = Tour::calc_tour_weight(&tour_nodes, graph);
        Tour::new(tour_nodes, tour_weight)
    }

    fn mutate<R: Rng>(&self, rng: &mut R, graph: &Graph, mutation_rate: f64) -> Tour {
        let size = self.nodes.len() as f64;
        let mut mutated: Vec<Node> = self.nodes.clone();

        for i in range(0, self.nodes.len()) {
            let t = rng.gen::<f64>();
            if t < mutation_rate {
                let j = (rng.gen::<f64>() * size) as uint;
                mutated.as_mut_slice().swap(i, j);
            }
        }
        let weight = Tour::calc_tour_weight(&mutated, graph);
        Tour {
            nodes: mutated,
            total_weight: weight
        }
    }

    fn crossover<R: Rng>(&self, other: Tour, graph: &Graph, rng: &mut R) -> Tour {
        let size = self.nodes.len();
        let mut start = (rng.gen::<f64>() * (size as f64)) as uint;
        let mut end = (rng.gen::<f64>() * (size as f64)) as uint;
        if start == end {
            return self.clone()
        }

        if end > start {
            std::mem::swap(&mut start, &mut end);
        }

        let new_tour = Vec::from_fn(size, |i| {
            if i >= start && i <= end {
                *self.nodes.get(i)
            } else {
                *other.nodes.get(i)
            }
        });

        let tour_weight = Tour::calc_tour_weight(&new_tour, graph);
        Tour::new(new_tour, tour_weight)
    }
}

#[deriving(Show, Clone)]
pub struct Graph {
    adj_list: HashMap<Node, Vec<Edge>>
}

impl Graph {
    fn new(adj_list: HashMap<Node, Vec<Edge>>) -> Graph {
        Graph {
            adj_list: adj_list
        }
    }

    fn from_nodes(nodes: Vec<NodePt>) -> Graph {
        let mut map: HashMap<Node, Vec<Edge>> = HashMap::new();
        for i in range(0, nodes.len()) {
            let mut adj_edges: Vec<Edge> = Vec::new();

            for j in range(0, nodes.len()) {
                let a = nodes.get(i);
                let b = nodes.get(j);
                if i != j {
                    adj_edges.push(Edge::new(*a, *b));
                }
            }

            map.insert(i, adj_edges);
        }

        Graph::new(map)
    }

    fn random_graph<R: Rng>(rng: &mut R, num_nodes: uint, x_max: f64, y_max: f64) -> Graph {
        let points = rng.gen_iter::<(f64, f64)>()
            .enumerate()
            .map(|(idx, (x, y))| NodePt::new(idx, x * x_max, y * y_max))
            .take(num_nodes)
            .collect();

        Graph::from_nodes(points)
    }

    fn get(&self, n: Node, m: Node) -> f64 {
        if n == m {
            0.0
        } else {
            let edges = self.adj_list.get(&n);
            let result = edges.iter().filter(|edge| edge.to == m).nth(0);
            match result {
                Some(edge) => edge.weight,
                None => fail!("No edge found!")
            }
        }
    }

    fn size(&self) -> uint {
        self.adj_list.len()
    }

    fn nodes(&self) -> Vec<Node> {
        range(0, self.size()).collect()
    }

    #[allow(dead_code)]
    fn from_file(file_path: &str) -> Graph {
        let path = Path::new(file_path);
        let mut file = BufferedReader::new(File::open(&path));
        let mut nodes: Vec<NodePt> = Vec::new();
        let mut i = 0u;

        for line in file.lines() {
            let mut numbers: Vec<f64> = Vec::new();
            // This could be a lot nicer
            match line {
                Ok(val) => {
                    for token in val.as_slice().split(' ') {
                        if token == "\n" {
                            continue
                        }

                        let n = match from_str::<f64>(token) {
                            Some(num) => num,
                            None => continue
                        };
                        numbers.push(n);
                    }
                },
                Err(_) => fail!("Failed reading file.")
            }

            if numbers.len() == 2 {
                let point = NodePt::new(i, *numbers.get(0), *numbers.get(1));
                nodes.push(point);
            }

            i += 1;
        }

        Graph::from_nodes(nodes)
    }
}

struct Population {
    rng: StdRng,
    graph: Box<Graph>,
    population: Vec<Tour>,
    mutation_rate: f64,
    tournament_size: uint
}

impl Population {
    fn new(population_count: uint, graph: Box<Graph>, mutation_rate: f64, tournament_size: uint, mut rng: StdRng) -> Population {
        let population = Vec::from_fn(population_count, |_| Tour::random_tour(&mut rng, graph));

        Population {
            rng: rng,
            graph: graph,
            population: population,
            mutation_rate: mutation_rate,
            tournament_size: tournament_size
        }
    }

    fn fittest(&self) -> Tour {
        find_min(&self.population)
    }

    fn tournament_selection(&mut self) -> Tour {
        let size = self.population.len();
        let mut buffer: Vec<Tour> = Vec::new();
        for _ in range(0, self.tournament_size) {
            let t = (self.rng.gen::<f64>() * (size as f64)) as uint;
            buffer.push(self.population.get(t).clone());
        }
        find_min(&buffer)
    }

    fn evolve(&mut self) -> Population {
        let mut new_population: Vec<Tour> = Vec::new();

        for _ in range(0, self.population.len()) {
            let parent1 = self.tournament_selection();
            let parent2 = self.tournament_selection();
            let child: Tour = parent1.crossover(parent2, self.graph, &mut self.rng);
            new_population.push(child);
        }

        let mutated = new_population.iter().map(|tour| tour.mutate(&mut self.rng, self.graph, self.mutation_rate)).collect();

        Population {
            rng: self.rng,
            graph: self.graph.clone(),
            population: mutated,
            mutation_rate: self.mutation_rate,
            tournament_size: self.tournament_size
        }
    }
}

impl fmt::Show for Population {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Population: {}", self.population)
    }
}

fn find_min<E: PartialOrd+Clone>(xs: &Vec<E>) -> E {
    let ref min = *xs.iter().fold(xs.get(0), |min, next| if next < min {next} else {min});
    min.clone()
}

fn main() {
    // let mut rng: StdRng = match StdRng::new() {
    //     Ok(r) => r,
    //     Err(why) => fail!("failed to acquire RNG")
    // };
    let mut rng: StdRng = SeedableRng::from_seed(&[12, 13, 14, 15]);
    let graph = Graph::random_graph(&mut rng, 25, 200.0, 200.0);
    let mut pop = Population::new(5000, box graph, 0.03, 5, rng);
    println!("Fittest at start: {}", pop.fittest())

    let t0 = precise_time_ns();
    for _ in range(0, 100) {
        pop = pop.evolve();
    }
    let t1 = precise_time_ns();

    println!("Fittest at end: {}", pop.fittest())
    let dt = ((t1-t0) as f64) / 1e6;
    println!("t_avg = {} ms", dt / 100.0);
}<|endoftext|>


<commit_before>use std::cmp;
use std::io;
use std::io::BufRead;
use std::error::Error;

fn main() {
    let stdin = io::stdin();
    let mut ns: Vec<f64> = match read_floats(&mut stdin.lock()) {
        Ok(ns) => ns,
        Err(e) => panic!("failed to read numbers: {}", e),
    };

    ns.sort_by(|a, b| a.partial_cmp(b).unwrap_or(cmp::Ordering::Equal));

    let count = ns.len();

    let sum = ns.iter().fold(0.0, |a, &b| a + b);

    println!("count: {}", count);
    println!("sum:   {}", sum);

    if ns.is_empty() {
        println!("(empty set of numbers, remaining stats not available)");
    } else {
        println!("avg:   {}", sum / count as f64);
        println!("max:   {}", ns[count - 1]);
        println!("p999:  {}", ns[ns.len() * 999 / 1000]);
        println!("p99:   {}", ns[ns.len() * 99 / 100]);
        println!("p90:   {}", ns[ns.len() * 90 / 100]);
        println!("p50:   {}", ns[ns.len() * 50 / 100]);
        println!("min:   {}", ns[0]);
    }
}

fn read_floats(input: &mut io::BufRead) -> Result<Vec<f64>, Box<Error>> {
    let ns: Result<Vec<f64>, Box<Error>> = input
        .lines()
        .map(|line| -> Result<f64, Box<Error>> {
            Ok(line?.parse::<f64>()?)
        })
        .collect();

    ns
}
<commit_msg>Deal with NaN more cleanly.<commit_after>use std::cmp;
use std::io;
use std::io::BufRead;
use std::error::Error;

fn main() {
    let stdin = io::stdin();
    let mut ns: Vec<f64> = match read_floats(&mut stdin.lock()) {
        Ok(ns) => ns,
        Err(e) => panic!("failed to read numbers: {}", e),
    };

    ns.sort_by(|a, b| {
        match a.partial_cmp(b) {
            Some(o) => o,
            None => panic!("cannot compare {} and {}, thus cannort sort them", a, b),
        }
    });

    let count = ns.len();

    let sum = ns.iter().fold(0.0, |a, &b| a + b);

    println!("count: {}", count);
    println!("sum:   {}", sum);

    if ns.is_empty() {
        println!("(empty set of numbers, remaining stats not available)");
    } else {
        println!("avg:   {}", sum / count as f64);
        println!("max:   {}", ns[count - 1]);
        println!("p999:  {}", ns[ns.len() * 999 / 1000]);
        println!("p99:   {}", ns[ns.len() * 99 / 100]);
        println!("p90:   {}", ns[ns.len() * 90 / 100]);
        println!("p50:   {}", ns[ns.len() * 50 / 100]);
        println!("min:   {}", ns[0]);
    }
}

fn read_floats(input: &mut io::BufRead) -> Result<Vec<f64>, Box<Error>> {
    let ns: Result<Vec<f64>, Box<Error>> = input
        .lines()
        .map(|line| -> Result<f64, Box<Error>> {
            Ok(line?.parse::<f64>()?)
        })
        .collect();

    ns
}
<|endoftext|>


<commit_before>//! Module for implementing convert's FromTable

use hlua::any::AnyLuaValue;
use hlua::any::AnyLuaValue::*;

use std::hash::Hash;
use std::cmp::Eq;
use std::collections::HashMap;

/// Represents types which can be serialized from a Lua table (AnyLuaValue).
///
/// For convenience, this method takes in a `LuaDecoder` (obtained from
/// `LuaDecoder::new(AnyLuaValue)`). See methods on `LuaDecoder`.
pub trait FromTable {
    /// Attempt to parse this value from the decoder.
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Self>
        where Self: Sized;

    fn from_lua_table(table: AnyLuaValue) -> ConvertResult<Self>
        where Self: Sized {
        Self::from_table(LuaDecoder::new(table))
    }
}

/// Errors a converter can run into
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum ConverterError {
    /// The type of value present did not match the one expected
    UnexpectedType(String),
    /// The table index expected did not exist
    MissingTableIndex(String),
    /// The table index present was not valid
    InvalidTableIndex(String)
}

impl ConverterError {
    pub fn into_message(self) -> String {
        match self {
            ConverterError::UnexpectedType(m) => m,
            ConverterError::MissingTableIndex(m) => m,
            ConverterError::InvalidTableIndex(m) => m
        }
    }
}

/// Results for conversion operations
pub type ConvertResult<T> = Result<T, ConverterError>;

/// Can decode values with a FromTable
#[derive(Debug, PartialEq, Clone)]
pub struct LuaDecoder {
    val: AnyLuaValue
}

impl LuaDecoder {
    pub fn new(val: AnyLuaValue) -> LuaDecoder {
        LuaDecoder { val: val }
    }

    pub fn get_bool(self) -> ConvertResult<bool> {
        match self.val {
            LuaBoolean(val) => Ok(val),
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected bool, got {:?}", self.val)))
        }
    }

    pub fn get_string(self) -> ConvertResult<String> {
        match self.val {
            LuaString(text) => Ok(text),
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected String, got {:?}", self.val)))
        }
    }

    pub fn get_option<T: FromTable>(self) -> ConvertResult<Option<T>> {
        match self.val {
            LuaNil => Ok(None),
            val => T::from_table(LuaDecoder::new(val)).map(|val| Some(val))
        }
    }

    #[allow(dead_code)]
    pub fn read_field<T>(self, name: String) -> ConvertResult<(Self, T)>
        where T: FromTable {
        match self.val {
            LuaArray(mut arr) => {
                let maybe_pos = arr.iter().position(|ref val_pair| {
                    match val_pair.0 {
                        LuaString(ref key) => {
                            *key == name
                        },
                        _ => false
                    }
                });
                if let Some(pos) = maybe_pos {
                    let (_, val) = arr.remove(pos);
                    let val_parser = LuaDecoder::new(val);
                    T::from_table(val_parser).map(|parse|
                                    (LuaDecoder::new(LuaArray(arr)), parse))
                }
                else {
                    Err(ConverterError::MissingTableIndex(name))
                }
            }
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected table, got {:?}", self.val)))
        }
    }

    pub fn get_unordered_array<T: FromTable>(self) -> ConvertResult<Vec<T>> {
        match self.val {
            LuaArray(mut arr) => {
                let mut turn = Vec::with_capacity(arr.len());
                // Completely ignore the keys, push values of type T
                for (_, lua_val) in arr.into_iter() {
                    match T::from_lua_table(lua_val) {
                        Ok(val) => turn.push(val),
                        Err(err) => {
                            return Err(ConverterError::InvalidTableIndex(
                                format!("Attempted to parse value in a Vec, \
                                got error: {}", err.into_message())));
                        }
                    }
                }
                return Ok(turn);
            }
            _ => Err(ConverterError::UnexpectedType(
                 format!("Expected table for Vec, got {:?}", self.val)))
        }
    }

    pub fn get_hash_map<K, V>(self) -> ConvertResult<HashMap<K, V>>
        where K: Eq + Hash + FromTable, V: FromTable {
        match self.val {
            LuaArray(arr) => {
                let mut map = HashMap::with_capacity(arr.len());
                for (lua_key, lua_value) in arr.into_iter() {
                    match K::from_lua_table(lua_key) {
                        Ok(key) => match V::from_lua_table(lua_value) {
                            Ok(value) => { map.insert(key, value); },
                            Err(e) =>
                                return Err(ConverterError::InvalidTableIndex(
                                    format!("Attempted to parse value in a Hash\
                                             Map, got error: {}",
                                            e.into_message())))
                        },
                        Err(e) => return Err(ConverterError::InvalidTableIndex(
                        format!("Attempted to parse key in a HashMap, got error\
                                 : {}", e.into_message())))
                    }
                }
                return Ok(map);
            },
            _ => Err(ConverterError::UnexpectedType(
            format!("Expected table for HashMap, got {:?}", self.val)))
        }
    }
}

macro_rules! primitive_decode {
    ( $($ptype:ty, $fun:ident;) +) => {
        $(impl LuaDecoder {
            pub fn $fun(self) -> ConvertResult<$ptype> {
                match self.val {
                    AnyLuaValue::LuaNumber(num) => Ok(num as $ptype),
                    other => Err(ConverterError::UnexpectedType(
                        format!("Expected {}, got {:?}",
                                stringify!($ptype), other)))
                }
            }
        }

        impl FromTable for $ptype {
            fn from_table(decoder: LuaDecoder) -> ConvertResult<$ptype> {
                LuaDecoder::$fun(decoder)
            }
        })+
    }
}

macro_rules! type_fn_decode {
    ( $( $ptype:ty => $fun:ident), + ) => {
        $(impl FromTable for $ptype {
            fn from_table(decoder: LuaDecoder) -> ConvertResult<$ptype> {
                LuaDecoder::$fun(decoder)
            }
        })+
    }
}

primitive_decode! {
    i8,  get_i8;
    i16, get_i16;
    i32, get_i32;

    u8,  get_u8;
    u16, get_u16;
    u32, get_u32;

    f32, get_f32;
    f64, get_f64;
}

type_fn_decode! {
    String => get_string,
    bool => get_bool
}

impl<T: FromTable> FromTable for Vec<T> {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Vec<T>> {
        decoder.get_unordered_array()
    }
}

impl<T: FromTable> FromTable for Option<T> {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Option<T>> {
        decoder.get_option()
    }
}

impl<K, V> FromTable for HashMap<K, V> where K: Hash + Eq + FromTable, V: FromTable {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<HashMap<K,V>> {
        decoder.get_hash_map()
    }
}
<commit_msg>Removed unneccessary mut<commit_after>//! Module for implementing convert's FromTable

use hlua::any::AnyLuaValue;
use hlua::any::AnyLuaValue::*;

use std::hash::Hash;
use std::cmp::Eq;
use std::collections::HashMap;

/// Represents types which can be serialized from a Lua table (AnyLuaValue).
///
/// For convenience, this method takes in a `LuaDecoder` (obtained from
/// `LuaDecoder::new(AnyLuaValue)`). See methods on `LuaDecoder`.
pub trait FromTable {
    /// Attempt to parse this value from the decoder.
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Self>
        where Self: Sized;

    fn from_lua_table(table: AnyLuaValue) -> ConvertResult<Self>
        where Self: Sized {
        Self::from_table(LuaDecoder::new(table))
    }
}

/// Errors a converter can run into
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum ConverterError {
    /// The type of value present did not match the one expected
    UnexpectedType(String),
    /// The table index expected did not exist
    MissingTableIndex(String),
    /// The table index present was not valid
    InvalidTableIndex(String)
}

impl ConverterError {
    pub fn into_message(self) -> String {
        match self {
            ConverterError::UnexpectedType(m) => m,
            ConverterError::MissingTableIndex(m) => m,
            ConverterError::InvalidTableIndex(m) => m
        }
    }
}

/// Results for conversion operations
pub type ConvertResult<T> = Result<T, ConverterError>;

/// Can decode values with a FromTable
#[derive(Debug, PartialEq, Clone)]
pub struct LuaDecoder {
    val: AnyLuaValue
}

impl LuaDecoder {
    pub fn new(val: AnyLuaValue) -> LuaDecoder {
        LuaDecoder { val: val }
    }

    pub fn get_bool(self) -> ConvertResult<bool> {
        match self.val {
            LuaBoolean(val) => Ok(val),
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected bool, got {:?}", self.val)))
        }
    }

    pub fn get_string(self) -> ConvertResult<String> {
        match self.val {
            LuaString(text) => Ok(text),
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected String, got {:?}", self.val)))
        }
    }

    pub fn get_option<T: FromTable>(self) -> ConvertResult<Option<T>> {
        match self.val {
            LuaNil => Ok(None),
            val => T::from_table(LuaDecoder::new(val)).map(|val| Some(val))
        }
    }

    #[allow(dead_code)]
    pub fn read_field<T>(self, name: String) -> ConvertResult<(Self, T)>
        where T: FromTable {
        match self.val {
            LuaArray(mut arr) => {
                let maybe_pos = arr.iter().position(|ref val_pair| {
                    match val_pair.0 {
                        LuaString(ref key) => {
                            *key == name
                        },
                        _ => false
                    }
                });
                if let Some(pos) = maybe_pos {
                    let (_, val) = arr.remove(pos);
                    let val_parser = LuaDecoder::new(val);
                    T::from_table(val_parser).map(|parse|
                                    (LuaDecoder::new(LuaArray(arr)), parse))
                }
                else {
                    Err(ConverterError::MissingTableIndex(name))
                }
            }
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected table, got {:?}", self.val)))
        }
    }

    pub fn get_unordered_array<T: FromTable>(self) -> ConvertResult<Vec<T>> {
        match self.val {
            LuaArray(arr) => {
                let mut turn = Vec::with_capacity(arr.len());
                // Completely ignore the keys, push values of type T
                for (_, lua_val) in arr.into_iter() {
                    match T::from_lua_table(lua_val) {
                        Ok(val) => turn.push(val),
                        Err(err) => {
                            return Err(ConverterError::InvalidTableIndex(
                                format!("Attempted to parse value in a Vec, \
                                got error: {}", err.into_message())));
                        }
                    }
                }
                return Ok(turn);
            }
            _ => Err(ConverterError::UnexpectedType(
                 format!("Expected table for Vec, got {:?}", self.val)))
        }
    }

    pub fn get_hash_map<K, V>(self) -> ConvertResult<HashMap<K, V>>
        where K: Eq + Hash + FromTable, V: FromTable {
        match self.val {
            LuaArray(arr) => {
                let mut map = HashMap::with_capacity(arr.len());
                for (lua_key, lua_value) in arr.into_iter() {
                    match K::from_lua_table(lua_key) {
                        Ok(key) => match V::from_lua_table(lua_value) {
                            Ok(value) => { map.insert(key, value); },
                            Err(e) =>
                                return Err(ConverterError::InvalidTableIndex(
                                    format!("Attempted to parse value in a Hash\
                                             Map, got error: {}",
                                            e.into_message())))
                        },
                        Err(e) => return Err(ConverterError::InvalidTableIndex(
                        format!("Attempted to parse key in a HashMap, got error\
                                 : {}", e.into_message())))
                    }
                }
                return Ok(map);
            },
            _ => Err(ConverterError::UnexpectedType(
            format!("Expected table for HashMap, got {:?}", self.val)))
        }
    }
}

macro_rules! primitive_decode {
    ( $($ptype:ty, $fun:ident;) +) => {
        $(impl LuaDecoder {
            pub fn $fun(self) -> ConvertResult<$ptype> {
                match self.val {
                    AnyLuaValue::LuaNumber(num) => Ok(num as $ptype),
                    other => Err(ConverterError::UnexpectedType(
                        format!("Expected {}, got {:?}",
                                stringify!($ptype), other)))
                }
            }
        }

        impl FromTable for $ptype {
            fn from_table(decoder: LuaDecoder) -> ConvertResult<$ptype> {
                LuaDecoder::$fun(decoder)
            }
        })+
    }
}

macro_rules! type_fn_decode {
    ( $( $ptype:ty => $fun:ident), + ) => {
        $(impl FromTable for $ptype {
            fn from_table(decoder: LuaDecoder) -> ConvertResult<$ptype> {
                LuaDecoder::$fun(decoder)
            }
        })+
    }
}

primitive_decode! {
    i8,  get_i8;
    i16, get_i16;
    i32, get_i32;

    u8,  get_u8;
    u16, get_u16;
    u32, get_u32;

    f32, get_f32;
    f64, get_f64;
}

type_fn_decode! {
    String => get_string,
    bool => get_bool
}

impl<T: FromTable> FromTable for Vec<T> {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Vec<T>> {
        decoder.get_unordered_array()
    }
}

impl<T: FromTable> FromTable for Option<T> {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Option<T>> {
        decoder.get_option()
    }
}

impl<K, V> FromTable for HashMap<K, V> where K: Hash + Eq + FromTable, V: FromTable {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<HashMap<K,V>> {
        decoder.get_hash_map()
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use serde::Serialize;
use slog::{Drain, Key, OwnedKVList, Record, KV};
use std::{
    collections::HashMap,
    fmt::{self, Write},
    io,
    sync::RwLock,
};

#[derive(Debug, Default)]
pub struct MemDrain {
    records: RwLock<Vec<LogRecord>>,
    logging: bool,
}

#[derive(Debug, Serialize)]
struct LogRecord {
    level: String,
    message: String,
    time: String,
    data: HashMap<String, String>,
}

impl MemDrain {
    pub fn start_logging(&mut self) {
        self.records.write().unwrap().clear();
        self.logging = true;
    }

    pub fn stop_logging(&mut self) {
        self.logging = false;
    }
}

impl Serialize for MemDrain {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        use serde::ser::SerializeStruct;

        let mut state = serializer.serialize_struct("Log", 1)?;
        state.serialize_field("entries", &self.records)?;
        state.end()
    }
}

impl ToString for MemDrain {
    fn to_string(&self) -> String {
        let records = self.records.read().unwrap();

        let mut ret = String::new();
        for record in records.iter() {
            let mut msg = record.message.clone();
            for (k, v) in &record.data {
                msg = msg.replace(k, v);
            }

            writeln!(&mut ret, "{} {} {}", record.time, record.level, msg).unwrap();
        }
        ret
    }
}

impl Drain for MemDrain {
    type Err = io::Error;
    type Ok = ();

    fn log(&self, record: &Record, kvs: &OwnedKVList) -> io::Result<()> {
        if self.logging {
            let mut kv = KVSerializer::default();
            record.kv().serialize(record, &mut kv)?;
            kvs.serialize(record, &mut kv)?;

            let l = LogRecord {
                level: record.level().as_str().to_lowercase(),
                message: fmt::format(*record.msg()),
                time: chrono::Local::now().format("%b %d %H:%M:%S%.3f").to_string(),
                data: kv.0,
            };

            self.records.write().unwrap().push(l);
        }

        Ok(())
    }
}

#[derive(Default)]
struct KVSerializer(HashMap<String, String>);

impl slog::ser::Serializer for KVSerializer {
    fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments) -> slog::Result {
        let val = &format!("{:?}", val);
        self.0.insert(key.to_string(), val.to_string());
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use slog::{o, slog_debug, slog_error, slog_info, Logger};
    use std::sync::{Arc, Mutex};

    fn eq_without_time(s1: &str, s2: &str) -> bool {
        let s1 = s1.split('\n');
        let s2 = s2.split('\n');
        for (i, (x, y)) in s1.zip(s2).enumerate() {
            if x.contains("time") {
                continue;
            }
            if x != y {
                println!("Difference on string's line: {}\n{} != {}", i, x, y);
                return false;
            }
        }
        true
    }

    #[test]
    fn drain_storage_log() {
        let s1 = "Multiple log messages should";
        let s2 = "all be find inside log string";
        let drain = Arc::new(Mutex::new(MemDrain::default()));
        let r_vec = drain.clone();
        drain.lock().unwrap().start_logging();
        let log = Logger::root(drain.fuse(), o!());
        slog_info!(log, "{}", s1);
        slog_info!(log, "{}", s2);
        let result = r_vec.lock().unwrap().to_string();
        println!("{}", result);
        assert!(result.contains(s1));
        assert!(result.contains(s2));
    }

    #[test]
    fn drain_format() {
        let s1 = "Log should contain message type";
        let s2 = "Type strings are shorten";
        let drain = Arc::new(Mutex::new(MemDrain::default()));
        let r_vec = drain.clone();
        drain.lock().unwrap().start_logging();
        let log = Logger::root(drain.fuse(), o!());
        slog_info!(log, "{}", s1);
        slog_debug!(log, "{}", s2);
        let result = r_vec.lock().unwrap().to_string();
        println!("{}", result);
        assert!(result.contains("info"));
        assert!(result.contains("debug"));
    }

    #[test]
    fn drain_key_values() {
        let txt = "Key values should be swapped, LOGGER and RECORD";
        let logger_value = "when defined on logger";
        let macro_value = "when defined on record";
        let drain = Arc::new(Mutex::new(MemDrain::default()));
        let r_vec = drain.clone();
        drain.lock().unwrap().start_logging();
        let log = Logger::root(drain.fuse(), o!("LOGGER" => logger_value));
        slog_info!(log, "{}", txt; "RECORD" => macro_value);
        let result = r_vec.lock().unwrap().to_string();
        println!("{}", result);
        assert!(result.contains(logger_value));
        assert!(result.contains(macro_value));
    }

    #[test]
    fn drain_serialized() {
        let expected = r#"{
  "entries": [
    {
      "level": "info",
      "message": "info 1",
      "time": "Aug 27 16:09:48.740",
      "data": {}
    },
    {
      "level": "info",
      "message": "info 2",
      "time": "Aug 27 16:09:48.740",
      "data": {
        "field1": "value1"
      }
    },
    {
      "level": "error",
      "message": "error n",
      "time": "Aug 27 16:09:48.740",
      "data": {}
    }
  ]
}"#;

        let drain = Arc::new(Mutex::new(MemDrain::default()));
        let r_vec = drain.clone();
        drain.lock().unwrap().start_logging();
        let log = Logger::root(drain.fuse(), o!());
        slog_info!(log, "{}", "info 1");
        slog_info!(log, "{}", "info 2"; "field1" => "value1");
        slog_error!(log, "{}", "error n");
        let result = serde_json::to_string_pretty(&r_vec).unwrap();
        assert!(
            eq_without_time(expected, &result),
            "Expected:\n{}\n\nResult:\n{}",
            expected,
            result
        );
    }
}
<commit_msg>updatehub: mem_drain: avoid using temporary vars in the for<commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use serde::Serialize;
use slog::{Drain, Key, OwnedKVList, Record, KV};
use std::{
    collections::HashMap,
    fmt::{self, Write},
    io,
    sync::RwLock,
};

#[derive(Debug, Default)]
pub struct MemDrain {
    records: RwLock<Vec<LogRecord>>,
    logging: bool,
}

#[derive(Debug, Serialize)]
struct LogRecord {
    level: String,
    message: String,
    time: String,
    data: HashMap<String, String>,
}

impl MemDrain {
    pub fn start_logging(&mut self) {
        self.records.write().unwrap().clear();
        self.logging = true;
    }

    pub fn stop_logging(&mut self) {
        self.logging = false;
    }
}

impl Serialize for MemDrain {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        use serde::ser::SerializeStruct;

        let mut state = serializer.serialize_struct("Log", 1)?;
        state.serialize_field("entries", &self.records)?;
        state.end()
    }
}

impl ToString for MemDrain {
    fn to_string(&self) -> String {
        let records = self.records.read().unwrap();

        let mut ret = String::new();
        let records = records.iter();
        for record in records {
            let mut msg = record.message.clone();
            for (k, v) in &record.data {
                msg = msg.replace(k, v);
            }

            writeln!(&mut ret, "{} {} {}", record.time, record.level, msg).unwrap();
        }
        ret
    }
}

impl Drain for MemDrain {
    type Err = io::Error;
    type Ok = ();

    fn log(&self, record: &Record, kvs: &OwnedKVList) -> io::Result<()> {
        if self.logging {
            let mut kv = KVSerializer::default();
            record.kv().serialize(record, &mut kv)?;
            kvs.serialize(record, &mut kv)?;

            let l = LogRecord {
                level: record.level().as_str().to_lowercase(),
                message: fmt::format(*record.msg()),
                time: chrono::Local::now().format("%b %d %H:%M:%S%.3f").to_string(),
                data: kv.0,
            };

            self.records.write().unwrap().push(l);
        }

        Ok(())
    }
}

#[derive(Default)]
struct KVSerializer(HashMap<String, String>);

impl slog::ser::Serializer for KVSerializer {
    fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments) -> slog::Result {
        let val = &format!("{:?}", val);
        self.0.insert(key.to_string(), val.to_string());
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use slog::{o, slog_debug, slog_error, slog_info, Logger};
    use std::sync::{Arc, Mutex};

    fn eq_without_time(s1: &str, s2: &str) -> bool {
        let s1 = s1.split('\n');
        let s2 = s2.split('\n');
        for (i, (x, y)) in s1.zip(s2).enumerate() {
            if x.contains("time") {
                continue;
            }
            if x != y {
                println!("Difference on string's line: {}\n{} != {}", i, x, y);
                return false;
            }
        }
        true
    }

    #[test]
    fn drain_storage_log() {
        let s1 = "Multiple log messages should";
        let s2 = "all be find inside log string";
        let drain = Arc::new(Mutex::new(MemDrain::default()));
        let r_vec = drain.clone();
        drain.lock().unwrap().start_logging();
        let log = Logger::root(drain.fuse(), o!());
        slog_info!(log, "{}", s1);
        slog_info!(log, "{}", s2);
        let result = r_vec.lock().unwrap().to_string();
        println!("{}", result);
        assert!(result.contains(s1));
        assert!(result.contains(s2));
    }

    #[test]
    fn drain_format() {
        let s1 = "Log should contain message type";
        let s2 = "Type strings are shorten";
        let drain = Arc::new(Mutex::new(MemDrain::default()));
        let r_vec = drain.clone();
        drain.lock().unwrap().start_logging();
        let log = Logger::root(drain.fuse(), o!());
        slog_info!(log, "{}", s1);
        slog_debug!(log, "{}", s2);
        let result = r_vec.lock().unwrap().to_string();
        println!("{}", result);
        assert!(result.contains("info"));
        assert!(result.contains("debug"));
    }

    #[test]
    fn drain_key_values() {
        let txt = "Key values should be swapped, LOGGER and RECORD";
        let logger_value = "when defined on logger";
        let macro_value = "when defined on record";
        let drain = Arc::new(Mutex::new(MemDrain::default()));
        let r_vec = drain.clone();
        drain.lock().unwrap().start_logging();
        let log = Logger::root(drain.fuse(), o!("LOGGER" => logger_value));
        slog_info!(log, "{}", txt; "RECORD" => macro_value);
        let result = r_vec.lock().unwrap().to_string();
        println!("{}", result);
        assert!(result.contains(logger_value));
        assert!(result.contains(macro_value));
    }

    #[test]
    fn drain_serialized() {
        let expected = r#"{
  "entries": [
    {
      "level": "info",
      "message": "info 1",
      "time": "Aug 27 16:09:48.740",
      "data": {}
    },
    {
      "level": "info",
      "message": "info 2",
      "time": "Aug 27 16:09:48.740",
      "data": {
        "field1": "value1"
      }
    },
    {
      "level": "error",
      "message": "error n",
      "time": "Aug 27 16:09:48.740",
      "data": {}
    }
  ]
}"#;

        let drain = Arc::new(Mutex::new(MemDrain::default()));
        let r_vec = drain.clone();
        drain.lock().unwrap().start_logging();
        let log = Logger::root(drain.fuse(), o!());
        slog_info!(log, "{}", "info 1");
        slog_info!(log, "{}", "info 2"; "field1" => "value1");
        slog_error!(log, "{}", "error n");
        let result = serde_json::to_string_pretty(&r_vec).unwrap();
        assert!(
            eq_without_time(expected, &result),
            "Expected:\n{}\n\nResult:\n{}",
            expected,
            result
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::{
    conversion::ConvertError,
    types::{make_ident, TypeName},
};
use indoc::indoc;
use lazy_static::lazy_static;
use std::collections::HashMap;
use syn::{parse_quote, GenericArgument, PathArguments, Type, TypePath, TypePtr};

/// Whether this type should be included in the 'prelude'
/// passed to bindgen, and if so, how.
#[derive(Debug)]
enum PreludePolicy {
    Exclude,
    IncludeNormal,
    IncludeTemplated,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    /// Whether this can be safely represented by value.
    by_value_safe: bool,
    /// Whether and how to include this in the prelude given to bindgen.
    prelude_policy: PreludePolicy,
    /// Whether this is a & on the Rust side but a value on the C++
    /// side. Only applies to &str.
    de_referencicate: bool,
    /// Is a C type whose size is not fixed (e.g. int, short)
    is_ctype: bool,
    /// Whether this is a container type cxx allows. Otherwise,
    /// if we encounter such a type as a generic, we'll replace it with
    /// a concrete instantiation.
    is_cxx_container: bool,
    /// Any extra non-canonical names
    extra_non_canonical_name: Option<String>,
}

impl TypeDetails {
    fn new(
        rs_name: String,
        cpp_name: String,
        by_value_safe: bool,
        prelude_policy: PreludePolicy,
        de_referencicate: bool,
        is_ctype: bool,
        is_cxx_container: bool,
        extra_non_canonical_name: Option<String>,
    ) -> Self {
        TypeDetails {
            rs_name,
            cpp_name,
            by_value_safe,
            prelude_policy,
            de_referencicate,
            is_ctype,
            is_cxx_container,
            extra_non_canonical_name,
        }
    }

    fn get_prelude_entry(&self) -> Option<String> {
        match self.prelude_policy {
            PreludePolicy::Exclude => None,
            PreludePolicy::IncludeNormal | PreludePolicy::IncludeTemplated => {
                let tn = TypeName::new_from_user_input(&self.rs_name);
                let cxx_name = tn.get_final_ident();
                let (templating, payload) = match self.prelude_policy {
                    PreludePolicy::IncludeNormal => ("", "char* ptr"),
                    PreludePolicy::IncludeTemplated => ("template<typename T> ", "T* ptr"),
                    _ => unreachable!(),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};

                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
        }
    }

    fn to_type_path(&self) -> TypePath {
        let segs = self.rs_name.split("::").map(make_ident);
        parse_quote! {
            #(#segs)::*
        }
    }
}

/// Database of known types.
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<TypeName, TypeDetails>,
    canonical_names: HashMap<TypeName, TypeName>,
}

lazy_static! {
    /// Database of known types.
    pub(crate) static ref KNOWN_TYPES: TypeDatabase = create_type_database();
}

impl TypeDatabase {
    fn get(&self, ty: &TypeName) -> Option<&TypeDetails> {
        // The following line is important. It says that
        // when we encounter something like 'std::unique_ptr'
        // in the bindgen-generated bindings, we'll immediately
        // start to refer to that as 'UniquePtr' henceforth.
        let canonical_name = self.canonical_names.get(ty).unwrap_or(ty);
        self.by_rs_name.get(canonical_name)
    }

    /// Prelude of C++ for squirting into bindgen. This configures
    /// bindgen to output simpler types to replace some STL types
    /// that bindgen just can't cope with. Although we then replace
    /// those types with cxx types (e.g. UniquePtr), this intermediate
    /// step is still necessary because bindgen can't otherwise
    /// give us the templated types (e.g. when faced with the STL
    /// unique_ptr, bindgen would normally give us std_unique_ptr
    /// as opposed to std_unique_ptr<T>.)
    pub(crate) fn get_prelude(&self) -> String {
        itertools::join(
            self.by_rs_name
                .values()
                .filter_map(|t| t.get_prelude_entry()),
            "\n",
        )
    }

    /// Types which are known to be safe (or unsafe) to hold and pass by
    /// value in Rust.
    pub(crate) fn get_pod_safe_types<'a>(
        &'a self,
    ) -> impl Iterator<Item = (&'a TypeName, bool)> + 'a {
        self.by_rs_name
            .iter()
            .map(|(tn, td)| (tn, td.by_value_safe))
    }

    /// Whether this TypePath should be treated as a value in C++
    /// but a reference in Rust. This only applies to rust::Str
    /// (C++ name) which is &str in Rust.
    pub(crate) fn should_dereference_in_cpp(&self, typ: &TypePath) -> bool {
        let tn = TypeName::from_type_path(typ);
        let td = self.get(&tn);
        if let Some(td) = td {
            td.de_referencicate
        } else {
            false
        }
    }

    /// Here we substitute any names which we know are Special from
    /// our type database, e.g. std::unique_ptr -> UniquePtr.
    /// We strip off and ignore
    /// any PathArguments within this TypePath - callers should
    /// put them back again if needs be.
    pub(crate) fn known_type_substitute_path(&self, typ: &TypePath) -> Option<TypePath> {
        let tn = TypeName::from_type_path(typ);
        self.get(&tn).map(|td| td.to_type_path())
    }

    pub(crate) fn special_cpp_name(&self, rs: &TypeName) -> Option<String> {
        self.get(rs).map(|x| x.cpp_name.to_string())
    }

    pub(crate) fn is_known_type(&self, ty: &TypeName) -> bool {
        self.get(ty).is_some()
    }

    pub(crate) fn known_type_type_path(&self, ty: &TypeName) -> Option<TypePath> {
        self.get(ty).map(|td| td.to_type_path())
    }

    pub(crate) fn is_ctype(&self, ty: &TypeName) -> bool {
        self.get(ty).map(|td| td.is_ctype).unwrap_or(false)
    }

    pub(crate) fn is_cxx_acceptable_generic(&self, ty: &TypeName) -> bool {
        self.get(ty).map(|x| x.is_cxx_container).unwrap_or(false)
    }
}

fn create_type_database() -> TypeDatabase {
    let mut by_rs_name = HashMap::new();

    let mut do_insert =
        |td: TypeDetails| by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    do_insert(TypeDetails::new(
        "cxx::UniquePtr".into(),
        "std::unique_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
        None,
    ));
    do_insert(TypeDetails::new(
        "cxx::CxxVector".into(),
        "std::vector".into(),
        false,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
        None,
    ));
    do_insert(TypeDetails::new(
        "cxx::SharedPtr".into(),
        "std::shared_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
        None,
    ));
    do_insert(TypeDetails::new(
        "cxx::CxxString".into(),
        "std::string".into(),
        false,
        PreludePolicy::IncludeNormal,
        false,
        false,
        false,
        None,
    ));
    do_insert(TypeDetails::new(
        "str".into(),
        "rust::Str".into(),
        true,
        PreludePolicy::IncludeNormal,
        true,
        false,
        false,
        None,
    ));
    do_insert(TypeDetails::new(
        "String".into(),
        "rust::String".into(),
        true,
        PreludePolicy::IncludeNormal,
        false,
        false,
        false,
        None,
    ));
    for (cpp_type, rust_type) in (3..7)
        .map(|x| 2i32.pow(x))
        .map(|x| {
            vec![
                (format!("uint{}_t", x), format!("u{}", x)),
                (format!("int{}_t", x), format!("i{}", x)),
            ]
        })
        .flatten()
    {
        do_insert(TypeDetails::new(
            rust_type,
            cpp_type,
            true,
            PreludePolicy::Exclude,
            false,
            false,
            false,
            None,
        ));
    }
    do_insert(TypeDetails::new(
        "bool".into(),
        "bool".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    ));

    do_insert(TypeDetails::new(
        "std::pin::Pin".into(),
        "Pin".into(),
        true, // because this is actually Pin<&something>
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    ));

    let mut insert_ctype = |cname: &str| {
        let td = TypeDetails::new(
            format!("autocxx::c_{}", cname),
            cname.into(),
            true,
            PreludePolicy::Exclude,
            false,
            true,
            false,
            Some(format!("std::os::raw::c_{}", cname)),
        );
        by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
        let td = TypeDetails::new(
            format!("autocxx::c_u{}", cname),
            format!("unsigned {}", cname),
            true,
            PreludePolicy::Exclude,
            false,
            true,
            false,
            Some(format!("std::os::raw::c_u{}", cname)),
        );
        by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
    };

    insert_ctype("long");
    insert_ctype("int");
    insert_ctype("short");

    let td = TypeDetails::new(
        "f32".into(),
        "float".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    );
    by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    let td = TypeDetails::new(
        "f64".into(),
        "double".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    );
    by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    let td = TypeDetails::new(
        "std::os::raw::c_char".into(),
        "char".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    );
    by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    let mut by_cppname = HashMap::new();
    for td in by_rs_name.values() {
        let rs_name = TypeName::new_from_user_input(&td.rs_name);
        if let Some(extra_non_canonical_name) = &td.extra_non_canonical_name {
            by_cppname.insert(
                TypeName::new_from_user_input(extra_non_canonical_name),
                rs_name.clone(),
            );
        }
        by_cppname.insert(TypeName::new_from_user_input(&td.cpp_name), rs_name);
    }

    TypeDatabase {
        by_rs_name,
        canonical_names: by_cppname,
    }
}

/// This is worked out basically using trial and error.
/// Excluding std* and rust* is obvious, but the other items...
/// in theory bindgen ought to be smart enough to work out that
/// they're not used and therefore not generate code for them.
/// But it doesm unless we blocklist them. This is obviously
/// a bit sensitive to the particular STL in use so one day
/// it would be good to dig into bindgen's behavior here - TODO.
const BINDGEN_BLOCKLIST: &[&str] = &["std.*", "__gnu.*", ".*mbstate_t.*", "rust.*"];

/// Get the list of types to give to bindgen to ask it _not_ to
/// generate code for.
pub(crate) fn get_initial_blocklist() -> Vec<String> {
    BINDGEN_BLOCKLIST.iter().map(|s| s.to_string()).collect()
}

/// If a given type lacks a copy constructor, we should always use
/// std::move in wrapper functions.
pub(crate) fn type_lacks_copy_constructor(ty: &Type) -> bool {
    // In future we may wish to look this up in KNOWN_TYPES.
    match ty {
        Type::Path(typ) => {
            let tn = TypeName::from_type_path(typ);
            tn.to_cpp_name().starts_with("std::unique_ptr")
        }
        _ => false,
    }
}

pub(crate) fn confirm_inner_type_is_acceptable_generic_payload(
    path_args: &PathArguments,
    desc: &TypeName,
) -> Result<(), ConvertError> {
    // For now, all supported generics accept the same payloads. This
    // may change in future in which case we'll need to accept more arguments here.
    match path_args {
        PathArguments::None => Ok(()),
        PathArguments::Parenthesized(_) => Err(ConvertError::TemplatedTypeContainingNonPathArg(
            desc.clone(),
        )),
        PathArguments::AngleBracketed(ab) => {
            for inner in &ab.args {
                match inner {
                    GenericArgument::Type(Type::Path(typ)) => {
                        if let Some(more_generics) = typ.path.segments.last() {
                            confirm_inner_type_is_acceptable_generic_payload(
                                &more_generics.arguments,
                                desc,
                            )?;
                        }
                    }
                    _ => {
                        return Err(ConvertError::TemplatedTypeContainingNonPathArg(
                            desc.clone(),
                        ))
                    }
                }
            }
            Ok(())
        }
    }
}

pub(crate) fn ensure_pointee_is_valid(ptr: &TypePtr) -> Result<(), ConvertError> {
    match *ptr.elem {
        Type::Path(..) => Ok(()),
        _ => Err(ConvertError::InvalidPointee),
    }
}
<commit_msg>Further clippies.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::{
    conversion::ConvertError,
    types::{make_ident, TypeName},
};
use indoc::indoc;
use lazy_static::lazy_static;
use std::collections::HashMap;
use syn::{parse_quote, GenericArgument, PathArguments, Type, TypePath, TypePtr};

/// Whether this type should be included in the 'prelude'
/// passed to bindgen, and if so, how.
#[derive(Debug)]
enum PreludePolicy {
    Exclude,
    IncludeNormal,
    IncludeTemplated,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    /// Whether this can be safely represented by value.
    by_value_safe: bool,
    /// Whether and how to include this in the prelude given to bindgen.
    prelude_policy: PreludePolicy,
    /// Whether this is a & on the Rust side but a value on the C++
    /// side. Only applies to &str.
    de_referencicate: bool,
    /// Is a C type whose size is not fixed (e.g. int, short)
    is_ctype: bool,
    /// Whether this is a container type cxx allows. Otherwise,
    /// if we encounter such a type as a generic, we'll replace it with
    /// a concrete instantiation.
    is_cxx_container: bool,
    /// Any extra non-canonical names
    extra_non_canonical_name: Option<String>,
}

impl TypeDetails {
    #[allow(clippy::too_many_arguments)]
    fn new(
        rs_name: String,
        cpp_name: String,
        by_value_safe: bool,
        prelude_policy: PreludePolicy,
        de_referencicate: bool,
        is_ctype: bool,
        is_cxx_container: bool,
        extra_non_canonical_name: Option<String>,
    ) -> Self {
        TypeDetails {
            rs_name,
            cpp_name,
            by_value_safe,
            prelude_policy,
            de_referencicate,
            is_ctype,
            is_cxx_container,
            extra_non_canonical_name,
        }
    }

    fn get_prelude_entry(&self) -> Option<String> {
        match self.prelude_policy {
            PreludePolicy::Exclude => None,
            PreludePolicy::IncludeNormal | PreludePolicy::IncludeTemplated => {
                let tn = TypeName::new_from_user_input(&self.rs_name);
                let cxx_name = tn.get_final_ident();
                let (templating, payload) = match self.prelude_policy {
                    PreludePolicy::IncludeNormal => ("", "char* ptr"),
                    PreludePolicy::IncludeTemplated => ("template<typename T> ", "T* ptr"),
                    _ => unreachable!(),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};

                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
        }
    }

    fn to_type_path(&self) -> TypePath {
        let segs = self.rs_name.split("::").map(make_ident);
        parse_quote! {
            #(#segs)::*
        }
    }
}

/// Database of known types.
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<TypeName, TypeDetails>,
    canonical_names: HashMap<TypeName, TypeName>,
}

lazy_static! {
    /// Database of known types.
    pub(crate) static ref KNOWN_TYPES: TypeDatabase = create_type_database();
}

impl TypeDatabase {
    fn get(&self, ty: &TypeName) -> Option<&TypeDetails> {
        // The following line is important. It says that
        // when we encounter something like 'std::unique_ptr'
        // in the bindgen-generated bindings, we'll immediately
        // start to refer to that as 'UniquePtr' henceforth.
        let canonical_name = self.canonical_names.get(ty).unwrap_or(ty);
        self.by_rs_name.get(canonical_name)
    }

    /// Prelude of C++ for squirting into bindgen. This configures
    /// bindgen to output simpler types to replace some STL types
    /// that bindgen just can't cope with. Although we then replace
    /// those types with cxx types (e.g. UniquePtr), this intermediate
    /// step is still necessary because bindgen can't otherwise
    /// give us the templated types (e.g. when faced with the STL
    /// unique_ptr, bindgen would normally give us std_unique_ptr
    /// as opposed to std_unique_ptr<T>.)
    pub(crate) fn get_prelude(&self) -> String {
        itertools::join(
            self.by_rs_name
                .values()
                .filter_map(|t| t.get_prelude_entry()),
            "\n",
        )
    }

    /// Types which are known to be safe (or unsafe) to hold and pass by
    /// value in Rust.
    pub(crate) fn get_pod_safe_types(&self) -> impl Iterator<Item = (&TypeName, bool)> {
        self.by_rs_name
            .iter()
            .map(|(tn, td)| (tn, td.by_value_safe))
    }

    /// Whether this TypePath should be treated as a value in C++
    /// but a reference in Rust. This only applies to rust::Str
    /// (C++ name) which is &str in Rust.
    pub(crate) fn should_dereference_in_cpp(&self, typ: &TypePath) -> bool {
        let tn = TypeName::from_type_path(typ);
        let td = self.get(&tn);
        if let Some(td) = td {
            td.de_referencicate
        } else {
            false
        }
    }

    /// Here we substitute any names which we know are Special from
    /// our type database, e.g. std::unique_ptr -> UniquePtr.
    /// We strip off and ignore
    /// any PathArguments within this TypePath - callers should
    /// put them back again if needs be.
    pub(crate) fn known_type_substitute_path(&self, typ: &TypePath) -> Option<TypePath> {
        let tn = TypeName::from_type_path(typ);
        self.get(&tn).map(|td| td.to_type_path())
    }

    pub(crate) fn special_cpp_name(&self, rs: &TypeName) -> Option<String> {
        self.get(rs).map(|x| x.cpp_name.to_string())
    }

    pub(crate) fn is_known_type(&self, ty: &TypeName) -> bool {
        self.get(ty).is_some()
    }

    pub(crate) fn known_type_type_path(&self, ty: &TypeName) -> Option<TypePath> {
        self.get(ty).map(|td| td.to_type_path())
    }

    pub(crate) fn is_ctype(&self, ty: &TypeName) -> bool {
        self.get(ty).map(|td| td.is_ctype).unwrap_or(false)
    }

    pub(crate) fn is_cxx_acceptable_generic(&self, ty: &TypeName) -> bool {
        self.get(ty).map(|x| x.is_cxx_container).unwrap_or(false)
    }
}

fn create_type_database() -> TypeDatabase {
    let mut by_rs_name = HashMap::new();

    let mut do_insert =
        |td: TypeDetails| by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    do_insert(TypeDetails::new(
        "cxx::UniquePtr".into(),
        "std::unique_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
        None,
    ));
    do_insert(TypeDetails::new(
        "cxx::CxxVector".into(),
        "std::vector".into(),
        false,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
        None,
    ));
    do_insert(TypeDetails::new(
        "cxx::SharedPtr".into(),
        "std::shared_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
        None,
    ));
    do_insert(TypeDetails::new(
        "cxx::CxxString".into(),
        "std::string".into(),
        false,
        PreludePolicy::IncludeNormal,
        false,
        false,
        false,
        None,
    ));
    do_insert(TypeDetails::new(
        "str".into(),
        "rust::Str".into(),
        true,
        PreludePolicy::IncludeNormal,
        true,
        false,
        false,
        None,
    ));
    do_insert(TypeDetails::new(
        "String".into(),
        "rust::String".into(),
        true,
        PreludePolicy::IncludeNormal,
        false,
        false,
        false,
        None,
    ));
    for (cpp_type, rust_type) in (3..7)
        .map(|x| 2i32.pow(x))
        .map(|x| {
            vec![
                (format!("uint{}_t", x), format!("u{}", x)),
                (format!("int{}_t", x), format!("i{}", x)),
            ]
        })
        .flatten()
    {
        do_insert(TypeDetails::new(
            rust_type,
            cpp_type,
            true,
            PreludePolicy::Exclude,
            false,
            false,
            false,
            None,
        ));
    }
    do_insert(TypeDetails::new(
        "bool".into(),
        "bool".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    ));

    do_insert(TypeDetails::new(
        "std::pin::Pin".into(),
        "Pin".into(),
        true, // because this is actually Pin<&something>
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    ));

    let mut insert_ctype = |cname: &str| {
        let td = TypeDetails::new(
            format!("autocxx::c_{}", cname),
            cname.into(),
            true,
            PreludePolicy::Exclude,
            false,
            true,
            false,
            Some(format!("std::os::raw::c_{}", cname)),
        );
        by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
        let td = TypeDetails::new(
            format!("autocxx::c_u{}", cname),
            format!("unsigned {}", cname),
            true,
            PreludePolicy::Exclude,
            false,
            true,
            false,
            Some(format!("std::os::raw::c_u{}", cname)),
        );
        by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
    };

    insert_ctype("long");
    insert_ctype("int");
    insert_ctype("short");

    let td = TypeDetails::new(
        "f32".into(),
        "float".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    );
    by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    let td = TypeDetails::new(
        "f64".into(),
        "double".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    );
    by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    let td = TypeDetails::new(
        "std::os::raw::c_char".into(),
        "char".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
        None,
    );
    by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    let mut by_cppname = HashMap::new();
    for td in by_rs_name.values() {
        let rs_name = TypeName::new_from_user_input(&td.rs_name);
        if let Some(extra_non_canonical_name) = &td.extra_non_canonical_name {
            by_cppname.insert(
                TypeName::new_from_user_input(extra_non_canonical_name),
                rs_name.clone(),
            );
        }
        by_cppname.insert(TypeName::new_from_user_input(&td.cpp_name), rs_name);
    }

    TypeDatabase {
        by_rs_name,
        canonical_names: by_cppname,
    }
}

/// This is worked out basically using trial and error.
/// Excluding std* and rust* is obvious, but the other items...
/// in theory bindgen ought to be smart enough to work out that
/// they're not used and therefore not generate code for them.
/// But it doesm unless we blocklist them. This is obviously
/// a bit sensitive to the particular STL in use so one day
/// it would be good to dig into bindgen's behavior here - TODO.
const BINDGEN_BLOCKLIST: &[&str] = &["std.*", "__gnu.*", ".*mbstate_t.*", "rust.*"];

/// Get the list of types to give to bindgen to ask it _not_ to
/// generate code for.
pub(crate) fn get_initial_blocklist() -> Vec<String> {
    BINDGEN_BLOCKLIST.iter().map(|s| s.to_string()).collect()
}

/// If a given type lacks a copy constructor, we should always use
/// std::move in wrapper functions.
pub(crate) fn type_lacks_copy_constructor(ty: &Type) -> bool {
    // In future we may wish to look this up in KNOWN_TYPES.
    match ty {
        Type::Path(typ) => {
            let tn = TypeName::from_type_path(typ);
            tn.to_cpp_name().starts_with("std::unique_ptr")
        }
        _ => false,
    }
}

pub(crate) fn confirm_inner_type_is_acceptable_generic_payload(
    path_args: &PathArguments,
    desc: &TypeName,
) -> Result<(), ConvertError> {
    // For now, all supported generics accept the same payloads. This
    // may change in future in which case we'll need to accept more arguments here.
    match path_args {
        PathArguments::None => Ok(()),
        PathArguments::Parenthesized(_) => Err(ConvertError::TemplatedTypeContainingNonPathArg(
            desc.clone(),
        )),
        PathArguments::AngleBracketed(ab) => {
            for inner in &ab.args {
                match inner {
                    GenericArgument::Type(Type::Path(typ)) => {
                        if let Some(more_generics) = typ.path.segments.last() {
                            confirm_inner_type_is_acceptable_generic_payload(
                                &more_generics.arguments,
                                desc,
                            )?;
                        }
                    }
                    _ => {
                        return Err(ConvertError::TemplatedTypeContainingNonPathArg(
                            desc.clone(),
                        ))
                    }
                }
            }
            Ok(())
        }
    }
}

pub(crate) fn ensure_pointee_is_valid(ptr: &TypePtr) -> Result<(), ConvertError> {
    match *ptr.elem {
        Type::Path(..) => Ok(()),
        _ => Err(ConvertError::InvalidPointee),
    }
}
<|endoftext|>