<commit_before>use std::collections::{HashMap, HashSet};

// Documents
type DocId = u64;

// Index
#[derive(Debug)]
struct InvertedIndex {
    // Token --> [ DocId ]
    index: HashMap<String, Vec<DocId>>,

    // DocId --> Body
    docs: HashMap<DocId, String>,

    num_docs: u64,
}

impl InvertedIndex {
    fn new() -> InvertedIndex {
        return InvertedIndex {
            index: HashMap::new(),
            docs: HashMap::new(),
            num_docs: 0,
        };
    }

    fn tokenize(&self, payload: &str) -> Vec<String> {
        let lower = payload.to_lowercase();
        lower.split_whitespace().map(|token| token.to_string()).collect()
    }

    fn index(&mut self, payload: String) -> DocId {
        // Generate document id
        let id: DocId = self.num_docs;
        self.num_docs += 1;

        // Tokenize document
        let tokens = self.tokenize(&payload);

        // Store whole document
        self.docs.insert(id, payload);

        // Index document by tokens
        for token in tokens {
            self.index
                .entry(token)
                .or_insert(Vec::new())
                .push(id);
        }
        id
    }

    fn delete(&mut self, doc_id: DocId) -> () {
        // Remove DocId from each token's posting list
        for (token, mut posting_list) in &mut self.index {
            posting_list.retain(|val| *val != doc_id)
        }

        // Remove document
        self.docs.remove(&doc_id);

        // Decrement num_docs
        self.num_docs -= 1;
    }

    fn search(&self, query: String) -> HashSet<DocId> {
        let mut docs = HashSet::new();
        let tokens = self.tokenize(&query);
        for token in &tokens {
            match self.index.get(token) {
                Some(ids) => {
                    for id in ids {
                        docs.insert(*id);
                    }
                }
                _ => {}
            }
        }
        docs
    }

    fn lookup(&self, doc_id: DocId) -> Option<&String> {
        self.docs.get(&doc_id)
    }
}

fn main() {
    // Create and populate documents
    let mut idx = InvertedIndex::new();
    idx.index("The quick brown fox jumps over the lazy dog".to_string());
    idx.index("life, universe, and everything".to_string());
    idx.index("The world is flat".to_string());

    // Search for a term
    println!("{:?}", idx);
    println!();
    let query = "what the";
    let doc_ids = idx.search(query.to_string());

    // Display found documents
    for doc_id in &doc_ids {
        let doc = idx.lookup(*doc_id);
        println!("Query({}) -> DocId({}) -> Document({:?})",
                 query,
                 doc_id,
                 doc);
    }
    idx.delete(0);
    println!("{:?}", idx);
    println!();

    // Display found documents
    let doc_ids = idx.search(query.to_string());
    for doc_id in &doc_ids {
        let doc = idx.lookup(*doc_id);
        println!("Query({}) -> DocId({}) -> Document({:?})",
                 query,
                 doc_id,
                 doc);
    }
}
<commit_msg>Remove debug println!<commit_after>use std::collections::{HashMap, HashSet};

// Documents
type DocId = u64;

// Index
#[derive(Debug)]
struct InvertedIndex {
    // Token --> [ DocId ]
    index: HashMap<String, Vec<DocId>>,

    // DocId --> Body
    docs: HashMap<DocId, String>,

    num_docs: u64,
}

impl InvertedIndex {
    fn new() -> InvertedIndex {
        return InvertedIndex {
            index: HashMap::new(),
            docs: HashMap::new(),
            num_docs: 0,
        };
    }

    fn tokenize(&self, payload: &str) -> Vec<String> {
        let lower = payload.to_lowercase();
        lower.split_whitespace().map(|token| token.to_string()).collect()
    }

    fn index(&mut self, payload: String) -> DocId {
        // Generate document id
        let id: DocId = self.num_docs;
        self.num_docs += 1;

        // Tokenize document
        let tokens = self.tokenize(&payload);

        // Store whole document
        self.docs.insert(id, payload);

        // Index document by tokens
        for token in tokens {
            self.index
                .entry(token)
                .or_insert(Vec::new())
                .push(id);
        }
        id
    }

    fn delete(&mut self, doc_id: DocId) -> () {
        // Remove DocId from each token's posting list
        for (_, mut posting_list) in &mut self.index {
            posting_list.retain(|val| *val != doc_id)
        }

        // Remove document
        self.docs.remove(&doc_id);

        // Decrement num_docs
        self.num_docs -= 1;
    }

    fn search(&self, query: String) -> HashSet<DocId> {
        let mut docs = HashSet::new();
        let tokens = self.tokenize(&query);
        for token in &tokens {
            match self.index.get(token) {
                Some(ids) => {
                    for id in ids {
                        docs.insert(*id);
                    }
                }
                _ => {}
            }
        }
        docs
    }

    fn lookup(&self, doc_id: DocId) -> Option<&String> {
        self.docs.get(&doc_id)
    }
}

fn main() {
    // Create and populate documents
    let mut idx = InvertedIndex::new();
    idx.index("The quick brown fox jumps over the lazy dog".to_string());
    idx.index("life, universe, and everything".to_string());
    idx.index("The world is flat".to_string());

    // Search for a term
    let query = "what the";
    let doc_ids = idx.search(query.to_string());

    // Display found documents
    for doc_id in &doc_ids {
        let doc = idx.lookup(*doc_id);
        println!("Query({}) -> DocId({}) -> Document({:?})",
                 query,
                 doc_id,
                 doc);
    }
    idx.delete(0);

    // Display found documents
    let doc_ids = idx.search(query.to_string());
    for doc_id in &doc_ids {
        let doc = idx.lookup(*doc_id);
        println!("Query({}) -> DocId({}) -> Document({:?})",
                 query,
                 doc_id,
                 doc);
    }
}
<|endoftext|>


<commit_before>extern crate lxd;

use lxd::list_containers;

fn format_output(headers: &Vec<&str>, items: &Vec<Vec<String>>) -> String{
    let mut widths = Vec::new();
    for header in headers {
        widths.push(header.len());
    }
    for item in items {
        for (n, column) in item.iter().enumerate() {
            if column.len() > widths[n] {
                widths[n] = column.len();
            }
        }
    }
    let mut dividing_line = "+".to_string();
    let mut header_line = "|".to_string();
    for (n, header) in headers.iter().enumerate() {
        dividing_line.push_str(&vec!["-"; widths[n] + 2].concat());
        dividing_line.push_str("+");
        header_line.push_str(&format!("{:^1$}", &header, widths[n] + 2));
        header_line.push_str("|");
    }
    let mut output_string = String::new();
    output_string.push_str(&dividing_line);
    output_string.push_str("\n");
    output_string.push_str(&header_line);
    output_string.push_str("\n");
    output_string.push_str(&dividing_line);
    output_string.push_str("\n");
    for item in items {
        output_string.push_str("|");
        for (n, column_content) in item.iter().enumerate() {
            output_string.push_str(" ");
            output_string.push_str(&format!("{:1$}", &column_content, widths[n] + 1));
            output_string.push_str("|");
        }
        output_string.push_str("\n");
    }
    output_string.push_str(&dividing_line);
    output_string
}

fn main() {
    let containers = list_containers();
    let headers = vec!["NAME", "STATE", "IPV4", "IPV6", "EPHEMERAL", "SNAPSHOTS"];
    let container_items = containers.iter().map(
        |c| {
            let mut ipv4_address = String::new();
            let mut ipv6_address = String::new();
            for ip in &c.status.ips {
                if ip.protocol == "IPV4" && ip.address != "127.0.0.1" {
                    ipv4_address = ip.address.clone();
                }
                if ip.protocol == "IPV6" && ip.address != "::1" {
                    ipv6_address = ip.address.clone();
                }
            }
            let ephemeral = if c.ephemeral { "YES" } else { "NO" };
            vec![c.name.clone(), c.status.status.clone().to_uppercase(), ipv4_address.to_string(), ipv6_address.to_string(), ephemeral.to_string(), c.snapshot_urls.len().to_string()]
        }).collect();
    println!("{}", format_output(&headers, &container_items));
}
<commit_msg>Split up rendering a little.<commit_after>extern crate lxd;

use lxd::Container;
use lxd::list_containers;

fn format_output(headers: &Vec<&str>, items: &Vec<Vec<String>>) -> String{
    let mut widths = Vec::new();
    for header in headers {
        widths.push(header.len());
    }
    for item in items {
        for (n, column) in item.iter().enumerate() {
            if column.len() > widths[n] {
                widths[n] = column.len();
            }
        }
    }
    let mut dividing_line = "+".to_string();
    let mut header_line = "|".to_string();
    for (n, header) in headers.iter().enumerate() {
        dividing_line.push_str(&vec!["-"; widths[n] + 2].concat());
        dividing_line.push_str("+");
        header_line.push_str(&format!("{:^1$}", &header, widths[n] + 2));
        header_line.push_str("|");
    }
    let mut output_string = String::new();
    output_string.push_str(&dividing_line);
    output_string.push_str("\n");
    output_string.push_str(&header_line);
    output_string.push_str("\n");
    output_string.push_str(&dividing_line);
    output_string.push_str("\n");
    for item in items {
        output_string.push_str("|");
        for (n, column_content) in item.iter().enumerate() {
            output_string.push_str(" ");
            output_string.push_str(&format!("{:1$}", &column_content, widths[n] + 1));
            output_string.push_str("|");
        }
        output_string.push_str("\n");
    }
    output_string.push_str(&dividing_line);
    output_string
}

fn prepare_container_line(c: &Container) -> Vec<String> {
    let mut ipv4_address = String::new();
    let mut ipv6_address = String::new();
    for ip in &c.status.ips {
        if ip.protocol == "IPV4" && ip.address != "127.0.0.1" {
            ipv4_address = ip.address.clone();
        }
        if ip.protocol == "IPV6" && ip.address != "::1" {
            ipv6_address = ip.address.clone();
        }
    }
    let ephemeral = if c.ephemeral { "YES" } else { "NO" };
    vec![c.name.clone(), c.status.status.clone().to_uppercase(), ipv4_address.to_string(), ipv6_address.to_string(), ephemeral.to_string(), c.snapshot_urls.len().to_string()]
}

fn main() {
    let headers = vec!["NAME", "STATE", "IPV4", "IPV6", "EPHEMERAL", "SNAPSHOTS"];
    let container_items = list_containers().iter().map(prepare_container_line).collect();
    println!("{}", format_output(&headers, &container_items));
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
use glium::DisplayBuild;
use glium::Surface;

extern crate rand;
use rand::distributions::{IndependentSample, Range};

#[derive(Debug, Default, Copy, Clone)]
struct Vertex {
    position: [f64; 2],
}

#[derive(Debug)]
struct Ball {
    vertex: Vertex,
    radius: f64,
    velocity: [f64; 3],
    tris: u8,
    mass: f64,
}

impl Ball {
    fn new(position: [f64; 2], radius: f64, velocity: [f64; 3]) -> Ball {
        Ball {
            vertex: Vertex { position: position },
            radius: radius,
            velocity: velocity,
            tris: 50,
            mass: 1.0,
        }
    }

    fn update(&mut self) {
        // negate velocity if pos + radius is on the edges
        if (self.vertex.position[0] - self.radius <= 0.0) || (self.vertex.position[0] + self.radius >= WIDTH as f64) {
            self.velocity[0] *= -1.;
        }
        if (self.vertex.position[1] - self.radius <= 0.0) || (self.vertex.position[1] + self.radius >= HEIGHT as f64) {
            self.velocity[1] *= -1.;
        }
        // update position from current velocity
        self.vertex.position[0] += self.velocity[0];
        self.vertex.position[1] += self.velocity[1];
    }

    fn render(&self) -> Vec<Vertex> {
        let mut vertices = vec![];

        vertices.push(self.vertex.clone());
        for n in 0..self.tris + 1 {
            vertices.push(Vertex {
                position: [&self.vertex.position[0] + (&self.radius * (n as f64 * PI2 / self.tris as f64).cos()),
                           &self.vertex.position[1] + (&self.radius * (n as f64 * PI2 / self.tris as f64).sin())],
            });
        }

        vertices
    }

}

fn collision(balls: &mut [Ball]) {
    for j in 0..balls.len() {
        for i in 1..balls.len() {
            // distxji = circleposx(j) - circleposx(i)
            let dist_x = balls[j].vertex.position[0] - balls[i].vertex.position[0];
            // distyji = circleposy(j) - circleposy(i)
            let dist_y = balls[j].vertex.position[1] - balls[i].vertex.position[1];
            // distance = (distxji * distxji) + (distyji * distyji)
            let distance = dist_x.powf(2.0) + dist_y.powf(2.0);

            // if colliding
            if distance <= (balls[i].radius + balls[j].radius).powf(2.0) {
                println!("{:?} vs {:?}", i, j);
                // newvix = (circlevx(i) * distxji + circlevy(i) * distyji) / distance * distxji
                // newviy = (circlevx(i) * distxji + circlevy(i) * distyji) / distance * distyji
                let new_vi_x = (balls[i].velocity[0] * dist_x + balls[i].velocity[1] * dist_y) / distance * dist_x;
                let new_vi_y = (balls[i].velocity[0] * dist_x + balls[i].velocity[1] * dist_y) / distance * dist_y;

                // newvjx = (circlevx(j) * -(distxji) + circlevy(j) * -(distyji)) / distance * -(distxji)
                // newvjy = (circlevx(j) * -(distxji) + circlevy(j) * -(distyji)) / distance * -(distyji)
                let new_vj_x = (balls[j].velocity[0] * -(dist_x) + balls[j].velocity[1] * -(dist_y)) / distance * -(dist_x);
                let new_vj_y = (balls[j].velocity[0] * -(dist_x) + balls[j].velocity[1] * -(dist_y)) / distance * -(dist_y);

                // circlevx(i) = circlevx(i) + ((2 * circlemass(j)) / (circlemass(i) + circlemass(j))) * (newvjx - newvix)
                balls[i].velocity[0] += ((2.0 * balls[j].mass) / (balls[i].mass + balls[j].mass)) * (new_vj_x - new_vi_x);
                // circlevy(i) = circlevy(i) + ((2 * circlemass(j)) / (circlemass(i) + circlemass(j))) * (newvjy - newviy)
                balls[i].velocity[1] += ((2.0 * balls[j].mass) / (balls[i].mass + balls[j].mass)) * (new_vj_y - new_vi_y);
                // circlevx(j) = circlevx(j) + ((2 * circlemass(i)) / (circlemass(j) + circlemass(i))) * (newvix - newvjx)
                balls[j].velocity[0] += ((2.0 * balls[i].mass) / (balls[j].mass + balls[i].mass)) * (new_vi_x - new_vj_x);
                // circlevy(j) = circlevy(j) + ((2 * circlemass(i)) / (circlemass(j) + circlemass(i))) * (newviy - newvjy)
                balls[j].velocity[1] += ((2.0 * balls[i].mass) / (balls[j].mass + balls[i].mass)) * (new_vi_y - new_vj_y);
            }
        }
    }
}

const PI2: f64 = std::f64::consts::PI * 2.;
const WIDTH: u32 = 640;
const HEIGHT: u32 = 480;

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(WIDTH, HEIGHT)
        .with_title(format!("Elma Menu bounce balls deluxe"))
        .build_glium()
        .unwrap();

    implement_vertex!(Vertex, position);

    let rand_range = Range::new(0.028648_f64, 89.848719_f64);
    let mut rng_gen = rand::thread_rng();
    let rand_degree = rand_range.ind_sample(&mut rng_gen) * std::f64::consts::PI / 180.0; // deg to rad
    let mut circles = vec![];

    circles.push(Ball::new([200.0, 120.0], 24.0, [rand_degree.cos() / 10.0, rand_degree.sin() / 10.0, 0.0]));
    circles.push(Ball::new([320.0, 120.0], 30.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([440.0, 120.0], 50.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([200.0, 240.0], 24.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([320.0, 240.0], 30.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([440.0, 240.0], 50.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([200.0, 360.0], 24.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([320.0, 360.0], 30.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([440.0, 360.0], 50.0, [0.0, 0.0, 0.0]));

    let vertex_shader_src = include_str!("shaders/ball.vert");
    let fragment_shader_src = include_str!("shaders/ball.frag");

    let program =
        glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
            .unwrap();

    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TriangleFan);

    println!("{:?}", &circles.len());

    loop {
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 1.0);

        collision(&mut circles);

        for circle in &mut circles {
            circle.update();
            target.draw(&glium::VertexBuffer::new(&display, &circle.render()).unwrap(),
                &indices,
                &program,
                &glium::uniforms::EmptyUniforms,
                &Default::default())
                .unwrap();
        }

        target.finish().unwrap();

        for event in display.poll_events() {
            match event {
                glium::glutin::Event::Closed => return,
                _ => (),
            }
        }
    }
}
<commit_msg>fix: first success<commit_after>#[macro_use]
extern crate glium;
use glium::DisplayBuild;
use glium::Surface;

extern crate rand;
use rand::distributions::{IndependentSample, Range};

#[derive(Debug, Default, Copy, Clone)]
struct Vertex {
    position: [f64; 2],
}

#[derive(Debug)]
struct Ball {
    vertex: Vertex,
    radius: f64,
    velocity: [f64; 3],
    tris: u8,
    mass: f64,
}

impl Ball {
    fn new(position: [f64; 2], radius: f64, velocity: [f64; 3]) -> Ball {
        Ball {
            vertex: Vertex { position: position },
            radius: radius,
            velocity: velocity,
            tris: 50,
            mass: 1.5,
        }
    }

    fn update(&mut self) {
        // negate velocity if pos + radius is on the edges
        if (self.vertex.position[0] - self.radius <= 0.0) || (self.vertex.position[0] + self.radius >= WIDTH as f64) {
            self.velocity[0] *= -1.;
        }
        if (self.vertex.position[1] - self.radius <= 0.0) || (self.vertex.position[1] + self.radius >= HEIGHT as f64) {
            self.velocity[1] *= -1.;
        }
        // update position from current velocity
        self.vertex.position[0] += self.velocity[0];
        self.vertex.position[1] += self.velocity[1];
    }

    fn render(&self) -> Vec<Vertex> {
        let mut vertices = vec![];

        vertices.push(self.vertex.clone());
        for n in 0..self.tris + 1 {
            vertices.push(Vertex {
                position: [&self.vertex.position[0] + (&self.radius * (n as f64 * PI2 / self.tris as f64).cos()),
                           &self.vertex.position[1] + (&self.radius * (n as f64 * PI2 / self.tris as f64).sin())],
            });
        }

        vertices
    }

}

fn collision(balls: &mut [Ball]) {
    for j in 0..balls.len() {
        for i in j+1..balls.len() {
            // distxji = circleposx(j) - circleposx(i)
            let dist_x = balls[j].vertex.position[0] - balls[i].vertex.position[0];
            // distyji = circleposy(j) - circleposy(i)
            let dist_y = balls[j].vertex.position[1] - balls[i].vertex.position[1];
            // distance = (distxji * distxji) + (distyji * distyji)
            let distance = dist_x.powf(2.0) + dist_y.powf(2.0);

            // if colliding
            if distance <= (balls[i].radius + balls[j].radius).powf(2.0) {
                // println!("{:?} vs {:?}", i, j);
                // newvix = (circlevx(i) * distxji + circlevy(i) * distyji) / distance * distxji
                // newviy = (circlevx(i) * distxji + circlevy(i) * distyji) / distance * distyji
                let new_vi_x = (balls[i].velocity[0] * dist_x + balls[i].velocity[1] * dist_y) / distance * dist_x;
                let new_vi_y = (balls[i].velocity[0] * dist_x + balls[i].velocity[1] * dist_y) / distance * dist_y;

                // newvjx = (circlevx(j) * -(distxji) + circlevy(j) * -(distyji)) / distance * -(distxji)
                // newvjy = (circlevx(j) * -(distxji) + circlevy(j) * -(distyji)) / distance * -(distyji)
                let new_vj_x = (balls[j].velocity[0] * -(dist_x) + balls[j].velocity[1] * -(dist_y)) / distance * -(dist_x);
                let new_vj_y = (balls[j].velocity[0] * -(dist_x) + balls[j].velocity[1] * -(dist_y)) / distance * -(dist_y);

                // circlevx(i) = circlevx(i) + ((2 * circlemass(j)) / (circlemass(i) + circlemass(j))) * (newvjx - newvix)
                balls[i].velocity[0] += ((2.0 * balls[j].mass) / (balls[i].mass + balls[j].mass)) * (new_vj_x - new_vi_x);
                // circlevy(i) = circlevy(i) + ((2 * circlemass(j)) / (circlemass(i) + circlemass(j))) * (newvjy - newviy)
                balls[i].velocity[1] += ((2.0 * balls[j].mass) / (balls[i].mass + balls[j].mass)) * (new_vj_y - new_vi_y);
                // circlevx(j) = circlevx(j) + ((2 * circlemass(i)) / (circlemass(j) + circlemass(i))) * (newvix - newvjx)
                balls[j].velocity[0] += ((2.0 * balls[i].mass) / (balls[j].mass + balls[i].mass)) * (new_vi_x - new_vj_x);
                // circlevy(j) = circlevy(j) + ((2 * circlemass(i)) / (circlemass(j) + circlemass(i))) * (newviy - newvjy)
                balls[j].velocity[1] += ((2.0 * balls[i].mass) / (balls[j].mass + balls[i].mass)) * (new_vi_y - new_vj_y);
            }
        }
    }
}

const PI2: f64 = std::f64::consts::PI * 2.;
const WIDTH: u32 = 640;
const HEIGHT: u32 = 480;

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(WIDTH, HEIGHT)
        .with_title(format!("Elma Menu bounce balls deluxe"))
        .build_glium()
        .unwrap();

    implement_vertex!(Vertex, position);

    let rand_range = Range::new(0.028648_f64, 89.848719_f64);
    let mut rng_gen = rand::thread_rng();
    let rand_degree = rand_range.ind_sample(&mut rng_gen) * std::f64::consts::PI / 180.0; // deg to rad
    let mut circles = vec![];

    circles.push(Ball::new([200.0, 120.0], 24.0, [rand_degree.cos() / 10.0, rand_degree.sin() / 10.0, 0.0]));
    circles.push(Ball::new([320.0, 120.0], 30.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([440.0, 120.0], 50.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([200.0, 240.0], 24.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([320.0, 240.0], 30.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([440.0, 240.0], 50.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([200.0, 360.0], 24.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([320.0, 360.0], 30.0, [0.0, 0.0, 0.0]));
    circles.push(Ball::new([440.0, 360.0], 50.0, [0.0, 0.0, 0.0]));

    let vertex_shader_src = include_str!("shaders/ball.vert");
    let fragment_shader_src = include_str!("shaders/ball.frag");

    let program =
        glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
            .unwrap();

    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TriangleFan);

    println!("{:?}", &circles.len());

    loop {
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 1.0);

        collision(&mut circles);

        for circle in &mut circles {
            circle.update();
            target.draw(&glium::VertexBuffer::new(&display, &circle.render()).unwrap(),
                &indices,
                &program,
                &glium::uniforms::EmptyUniforms,
                &Default::default())
                .unwrap();
        }

        target.finish().unwrap();

        for event in display.poll_events() {
            match event {
                glium::glutin::Event::Closed => return,
                _ => (),
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{App, AppSettings, Arg};

#[derive(Debug)]
struct Options {
    no_progress: bool,
    info_only: bool,
    silent: bool,
    debug: bool,
    append: bool,
    json: bool,
    download_url: String,
    filter: Vec<String>,
    byte_range: String,
    output_file: String,
    start_offset: String,
}

fn main() {
    let flags = vec![
        Arg::with_name("output")
            .short("o")
            .long("output")
            .value_name("FILE")
            .help("write output to a file")
            .takes_value(true),
        Arg::with_name("no-progress")
            .long("no-progress")
            .help("write output to a file"),
        Arg::with_name("range")
            .short("r")
            .long("range")
            .value_name("RANGE")
            .help("download a specific range of bytes of the video, [start]-[end]")
            .takes_value(true),
        Arg::with_name("download-url")
            .short("-u")
            .long("download-url")
            .value_name("URL")
            .help("prints download url to stdout")
            .takes_value(true),
        Arg::with_name("json")
            .short("j")
            .long("json")
            .help("print info json to stdout"),
        Arg::with_name("debug")
            .short("d")
            .long("debug")
            .help("output debug log"),
        Arg::with_name("filter")
            .short("f")
            .long("filter")
            .value_name("FILTER")
            .multiple(true)
            .help("filter available formats, syntax: val1 val2 val3")
            .takes_value(true),
        Arg::with_name("append")
            .short("-a")
            .long("--append")
            .help("append to output file instead of overwriting"),
        Arg::with_name("start-offset")
            .long("start-offset")
            .value_name("STARTOFFSET")
            .help("offset the start of the video")
            .takes_value(true),
        Arg::with_name("silent")
            .short("s")
            .long("silent")
            .help("only output error, also diables progressbar"),
        Arg::with_name("info")
            .short("i")
            .long("info")
            .help("only output info")];

    let matches = App::new("ytdl")
        .setting(AppSettings::ArgRequiredElseHelp)
        .version("0.0.1")
        .about("download youtube videos")
        .args(&flags)
        .get_matches();

    let mut filter = vec![];
    if matches.is_present("filter") {
        filter = matches.values_of("filter").unwrap().map(|s| String::from(s)).collect();
    }

    let options = Options {
        no_progress: matches.is_present("no-progress"),
        info_only: matches.is_present("info"),
        silent: matches.is_present("silent"),
        debug: matches.is_present("debug"),
        append: matches.is_present("append"),
        json: matches.is_present("json"),
        filter: filter,
        output_file: matches.value_of("output").unwrap_or("").to_string(),
        byte_range: matches.value_of("range").unwrap_or("").to_string(),
        download_url: matches.value_of("download-url").unwrap_or("").to_string(),
        start_offset: matches.value_of("start-offset").unwrap_or("").to_string(),
    };

    println!("{:?}", options);
}<commit_msg>feat: download-url bool<commit_after>extern crate clap;

use clap::{App, AppSettings, Arg};

#[derive(Debug)]
struct Options {
    no_progress: bool,
    info_only: bool,
    silent: bool,
    debug: bool,
    append: bool,
    json: bool,
    download_url: bool,
    filter: Vec<String>,
    byte_range: String,
    output_file: String,
    start_offset: String,
}

fn main() {
    let flags = vec![
        Arg::with_name("output")
            .short("o")
            .long("output")
            .value_name("FILE")
            .help("write output to a file")
            .takes_value(true),
        Arg::with_name("no-progress")
            .long("no-progress")
            .help("write output to a file"),
        Arg::with_name("range")
            .short("r")
            .long("range")
            .value_name("RANGE")
            .help("download a specific range of bytes of the video, [start]-[end]")
            .takes_value(true),
        Arg::with_name("download-url")
            .short("-u")
            .long("download-url")
            .help("prints download url to stdout"),
        Arg::with_name("json")
            .short("j")
            .long("json")
            .help("print info json to stdout"),
        Arg::with_name("debug")
            .short("d")
            .long("debug")
            .help("output debug log"),
        Arg::with_name("filter")
            .short("f")
            .long("filter")
            .value_name("FILTER")
            .multiple(true)
            .help("filter available formats, syntax: val1 val2 val3")
            .takes_value(true),
        Arg::with_name("append")
            .short("-a")
            .long("--append")
            .help("append to output file instead of overwriting"),
        Arg::with_name("start-offset")
            .long("start-offset")
            .value_name("STARTOFFSET")
            .help("offset the start of the video")
            .takes_value(true),
        Arg::with_name("silent")
            .short("s")
            .long("silent")
            .help("only output error, also diables progressbar"),
        Arg::with_name("info")
            .short("i")
            .long("info")
            .help("only output info")];

    let matches = App::new("ytdl")
        .setting(AppSettings::ArgRequiredElseHelp)
        .version("0.0.1")
        .about("download youtube videos")
        .args(&flags)
        .get_matches();

    let mut filter = vec![];
    if matches.is_present("filter") {
        filter = matches.values_of("filter").unwrap().map(|s| String::from(s)).collect();
    }

    let options = Options {
        no_progress: matches.is_present("no-progress"),
        info_only: matches.is_present("info"),
        silent: matches.is_present("silent"),
        debug: matches.is_present("debug"),
        append: matches.is_present("append"),
        json: matches.is_present("json"),
        download_url: matches.is_present("download-url"),
        filter: filter,
        output_file: matches.value_of("output").unwrap_or("").to_string(),
        byte_range: matches.value_of("range").unwrap_or("").to_string(),
        start_offset: matches.value_of("start-offset").unwrap_or("").to_string(),
    };

    println!("{:?}", options);
}<|endoftext|>


<commit_before>#![recursion_limit = "256"]
#![feature(proc_macro_hygiene, decl_macro)]
#![allow(proc_macro_derive_resolution_fallback)]

#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;

#[cfg(unix)]
use libsystemd::daemon::{self, NotifyState};
#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::io::prelude::*;
#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use crate::errors::*;
use core::ops::Deref;
use error_chain::bail;
use getopts::Options;
use log::{error, info};
use simplelog::{Level, LevelFilter, SimpleLogger, TermLogger, TerminalMode};
use std::path::Path;
use std::sync::Arc;

mod api;
#[cfg(test)]
mod api_tests;
mod config;
mod db;
mod ddns;
mod errors;
mod index;
mod lastfm;
mod metadata;
mod playlist;
mod serve;
mod server;
mod swagger;
#[cfg(test)]
mod test;
mod thumbnails;
mod ui;
mod user;
mod utils;
mod vfs;
mod web;

fn log_config() -> simplelog::Config {
	simplelog::Config {
		time: Some(Level::Error),
		level: Some(Level::Error),
		target: Some(Level::Error),
		location: Some(Level::Error),
		..Default::default()
	}
}

fn main() {
	if let Err(ref e) = run() {
		println!("Error: {}", e);

		for e in e.iter().skip(1) {
			println!("caused by: {}", e);
		}
		if let Some(backtrace) = e.backtrace() {
			println!("backtrace: {:?}", backtrace);
		}
		::std::process::exit(1);
	}
}

#[cfg(unix)]
fn daemonize(options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		return Ok(());
	}
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	let pid = match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(p) => p,
		Err(_) => bail!(ErrorKind::DaemonError),
	};
	let mut pid_path = utils::get_data_root()?;
	pid_path.push("polaris.pid");
	let mut file = File::create(pid_path)?;
	file.write_all(pid.to_string().as_bytes())?;
	Ok(())
}

#[cfg(unix)]
fn init_log(log_level: LevelFilter, options: &getopts::Matches) -> Result<()> {
	let config = log_config();
	if options.opt_present("f") {
		if let Err(e) = TermLogger::init(log_level, config, TerminalMode::Stdout) {
			println!("Error starting terminal logger: {}", e);
		} else {
			return Ok(());
		}
	}

	if let Err(e) = SimpleLogger::init(log_level, config) {
		bail!("Error starting simple logger: {}", e);
	}
	Ok(())
}

#[cfg(windows)]
fn init_log(log_level: LevelFilter, _: &getopts::Matches) -> Result<()> {
	let config = log_config();
	if TermLogger::init(log_level, config, TerminalMode::Stdout).is_err() {
		if let Err(e) = SimpleLogger::init(log_level, config) {
			bail!("Error starting simple logger: {}", e);
		}
	};
	Ok(())
}

#[cfg(unix)]
fn notify_ready() {
	if daemon::booted() {
		if let Err(e) = daemon::notify(true, &[NotifyState::Ready]) {
			error!("Unable to send ready notification: {}", e);
		}
	}
}

#[cfg(windows)]
fn notify_ready() {}

fn run() -> Result<()> {
	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("p", "port", "set polaris to run on a custom port", "PORT");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");
	options.optopt("s", "swagger", "set the path to swagger files", "DIRECTORY");
	options.optopt(
		"l",
		"log",
		"set the log level to a value between 0 (off) and 3 (debug)",
		"LEVEL",
	);

	#[cfg(unix)]
	options.optflag(
		"f",
		"foreground",
		"run polaris in the foreground instead of daemonizing",
	);

	options.optflag("h", "help", "print this help menu");

	let matches = options.parse(&args[1..])?;

	if matches.opt_present("h") {
		let program = args[0].clone();
		let brief = format!("Usage: {} [options]", program);
		print!("{}", options.usage(&brief));
		return Ok(());
	}

	let log_level = match matches.opt_str("l").as_ref().map(String::as_ref) {
		Some("0") => LevelFilter::Off,
		Some("1") => LevelFilter::Error,
		Some("2") => LevelFilter::Info,
		Some("3") => LevelFilter::Debug,
		_ => LevelFilter::Info,
	};

	init_log(log_level, &matches)?;

	#[cfg(unix)]
	daemonize(&matches)?;

	// Init DB
	info!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = Arc::new(db::DB::new(&db_path)?);

	// Parse config
	info!("Parsing configuration");
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		config::overwrite(db.deref(), &config)?;
	}
	let config = config::read(db.deref())?;
	let auth_secret = config::get_auth_secret(db.deref())?;

	// Init index
	info!("Initializing index");
	let command_sender = index::init(db.clone());

	// Trigger auto-indexing
	let db_auto_index = db.clone();
	let command_sender_auto_index = command_sender.clone();
	std::thread::spawn(move || {
		index::self_trigger(db_auto_index.deref(), &command_sender_auto_index);
	});

	// API mount target
	let prefix_url = config.prefix_url.unwrap_or_else(|| "".to_string());
	let api_url = format!("/{}api", &prefix_url);
	info!("Mounting API on {}", api_url);

	// Web client mount target
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);
	info!("Static files location is {}", web_dir_path.display());
	let web_url = format!("/{}", &prefix_url);
	info!("Mounting web client files on {}", web_url);

	// Swagger files mount target
	let swagger_dir_name = matches.opt_str("s");
	let mut default_swagger_dir = utils::get_data_root()?;
	default_swagger_dir.push("swagger");
	let swagger_dir_path = swagger_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_swagger_dir);
	info!("Swagger files location is {}", swagger_dir_path.display());
	let swagger_url = format!("/{}swagger", &prefix_url);
	info!("Mounting swagger files on {}", swagger_url);

	// Start server
	info!("Starting up server");
	let port: u16 = matches
		.opt_str("p")
		.unwrap_or_else(|| "5050".to_owned())
		.parse()
		.or(Err("invalid port number"))?;

	let server = server::get_server(
		port,
		Some(auth_secret.as_slice()),
		&api_url,
		&web_url,
		&web_dir_path,
		&swagger_url,
		&swagger_dir_path,
		db.clone(),
		command_sender,
	)?;
	std::thread::spawn(move || {
		server.launch();
	});

	// Start DDNS updates
	let db_ddns = db.clone();
	std::thread::spawn(move || {
		ddns::run(db_ddns.deref());
	});

	// Send readiness notification
	notify_ready();

	// Run UI
	ui::run();

	info!("Shutting down server");
	Ok(())
}
<commit_msg>Fixed warning when compiling on Windows<commit_after>#![recursion_limit = "256"]
#![feature(proc_macro_hygiene, decl_macro)]
#![allow(proc_macro_derive_resolution_fallback)]

#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;

#[cfg(unix)]
use libsystemd::daemon::{self, NotifyState};
#[cfg(unix)]
use log::error;
#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::io::prelude::*;
#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use crate::errors::*;
use core::ops::Deref;
use error_chain::bail;
use getopts::Options;
use log::info;
use simplelog::{Level, LevelFilter, SimpleLogger, TermLogger, TerminalMode};
use std::path::Path;
use std::sync::Arc;

mod api;
#[cfg(test)]
mod api_tests;
mod config;
mod db;
mod ddns;
mod errors;
mod index;
mod lastfm;
mod metadata;
mod playlist;
mod serve;
mod server;
mod swagger;
#[cfg(test)]
mod test;
mod thumbnails;
mod ui;
mod user;
mod utils;
mod vfs;
mod web;

fn log_config() -> simplelog::Config {
	simplelog::Config {
		time: Some(Level::Error),
		level: Some(Level::Error),
		target: Some(Level::Error),
		location: Some(Level::Error),
		..Default::default()
	}
}

fn main() {
	if let Err(ref e) = run() {
		println!("Error: {}", e);

		for e in e.iter().skip(1) {
			println!("caused by: {}", e);
		}
		if let Some(backtrace) = e.backtrace() {
			println!("backtrace: {:?}", backtrace);
		}
		::std::process::exit(1);
	}
}

#[cfg(unix)]
fn daemonize(options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		return Ok(());
	}
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	let pid = match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(p) => p,
		Err(_) => bail!(ErrorKind::DaemonError),
	};
	let mut pid_path = utils::get_data_root()?;
	pid_path.push("polaris.pid");
	let mut file = File::create(pid_path)?;
	file.write_all(pid.to_string().as_bytes())?;
	Ok(())
}

#[cfg(unix)]
fn init_log(log_level: LevelFilter, options: &getopts::Matches) -> Result<()> {
	let config = log_config();
	if options.opt_present("f") {
		if let Err(e) = TermLogger::init(log_level, config, TerminalMode::Stdout) {
			println!("Error starting terminal logger: {}", e);
		} else {
			return Ok(());
		}
	}

	if let Err(e) = SimpleLogger::init(log_level, config) {
		bail!("Error starting simple logger: {}", e);
	}
	Ok(())
}

#[cfg(windows)]
fn init_log(log_level: LevelFilter, _: &getopts::Matches) -> Result<()> {
	let config = log_config();
	if TermLogger::init(log_level, config, TerminalMode::Stdout).is_err() {
		if let Err(e) = SimpleLogger::init(log_level, config) {
			bail!("Error starting simple logger: {}", e);
		}
	};
	Ok(())
}

#[cfg(unix)]
fn notify_ready() {
	if daemon::booted() {
		if let Err(e) = daemon::notify(true, &[NotifyState::Ready]) {
			error!("Unable to send ready notification: {}", e);
		}
	}
}

#[cfg(windows)]
fn notify_ready() {}

fn run() -> Result<()> {
	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("p", "port", "set polaris to run on a custom port", "PORT");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");
	options.optopt("s", "swagger", "set the path to swagger files", "DIRECTORY");
	options.optopt(
		"l",
		"log",
		"set the log level to a value between 0 (off) and 3 (debug)",
		"LEVEL",
	);

	#[cfg(unix)]
	options.optflag(
		"f",
		"foreground",
		"run polaris in the foreground instead of daemonizing",
	);

	options.optflag("h", "help", "print this help menu");

	let matches = options.parse(&args[1..])?;

	if matches.opt_present("h") {
		let program = args[0].clone();
		let brief = format!("Usage: {} [options]", program);
		print!("{}", options.usage(&brief));
		return Ok(());
	}

	let log_level = match matches.opt_str("l").as_ref().map(String::as_ref) {
		Some("0") => LevelFilter::Off,
		Some("1") => LevelFilter::Error,
		Some("2") => LevelFilter::Info,
		Some("3") => LevelFilter::Debug,
		_ => LevelFilter::Info,
	};

	init_log(log_level, &matches)?;

	#[cfg(unix)]
	daemonize(&matches)?;

	// Init DB
	info!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = Arc::new(db::DB::new(&db_path)?);

	// Parse config
	info!("Parsing configuration");
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		config::overwrite(db.deref(), &config)?;
	}
	let config = config::read(db.deref())?;
	let auth_secret = config::get_auth_secret(db.deref())?;

	// Init index
	info!("Initializing index");
	let command_sender = index::init(db.clone());

	// Trigger auto-indexing
	let db_auto_index = db.clone();
	let command_sender_auto_index = command_sender.clone();
	std::thread::spawn(move || {
		index::self_trigger(db_auto_index.deref(), &command_sender_auto_index);
	});

	// API mount target
	let prefix_url = config.prefix_url.unwrap_or_else(|| "".to_string());
	let api_url = format!("/{}api", &prefix_url);
	info!("Mounting API on {}", api_url);

	// Web client mount target
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);
	info!("Static files location is {}", web_dir_path.display());
	let web_url = format!("/{}", &prefix_url);
	info!("Mounting web client files on {}", web_url);

	// Swagger files mount target
	let swagger_dir_name = matches.opt_str("s");
	let mut default_swagger_dir = utils::get_data_root()?;
	default_swagger_dir.push("swagger");
	let swagger_dir_path = swagger_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_swagger_dir);
	info!("Swagger files location is {}", swagger_dir_path.display());
	let swagger_url = format!("/{}swagger", &prefix_url);
	info!("Mounting swagger files on {}", swagger_url);

	// Start server
	info!("Starting up server");
	let port: u16 = matches
		.opt_str("p")
		.unwrap_or_else(|| "5050".to_owned())
		.parse()
		.or(Err("invalid port number"))?;

	let server = server::get_server(
		port,
		Some(auth_secret.as_slice()),
		&api_url,
		&web_url,
		&web_dir_path,
		&swagger_url,
		&swagger_dir_path,
		db.clone(),
		command_sender,
	)?;
	std::thread::spawn(move || {
		server.launch();
	});

	// Start DDNS updates
	let db_ddns = db.clone();
	std::thread::spawn(move || {
		ddns::run(db_ddns.deref());
	});

	// Send readiness notification
	notify_ready();

	// Run UI
	ui::run();

	info!("Shutting down server");
	Ok(())
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::collections::{HashSet, VecDeque};
use std::sync::{Arc, Mutex};

enum Message {
    Command(String),
    Data(Box<Any + Send>),
}

type ActorRef = Arc<Mutex<Actor>>;

trait Actor {
    fn receive(&mut self, Message);
    fn handle_message(&mut self);
}

struct Printer {
    name: String,
    message_queue: VecDeque<Message>,
}

impl Printer {
    fn new(name: String) -> Printer {
        Printer {
            name: name,
            message_queue: VecDeque::new(),
        }
    }
}

impl Actor for Printer {
    fn receive(&mut self, message: Message) {
        self.message_queue.push_back(message);
    }

    fn handle_message(&mut self) {
        let message = self.message_queue.pop_front().unwrap();

        match message {
            Message::Command(command) => {
                println!("Received Command: ({})", command)
            },
            Message::Data(truc) => {
                match truc.downcast_ref::<String>() {
                    Some(s) => println!("Received data: ({})", s),
                    None => println!("Message is dropped"),
                }
            }
        }
    }
}

struct ActorSystem {
    // TODO(gamazeps): Use an unordered container instead.
    // There is currently an issue with having an ActorRef as a Arc<Mutex<Actor + Eq + Hash>>.
    actors_table: Mutex<Vec<ActorRef>>,
    actors_queue: Arc<Mutex<VecDeque<ActorRef>>>,
}

impl ActorSystem {
    fn new() -> ActorSystem {
        ActorSystem {
            actors_table: Mutex::new(Vec::new()),
            actors_queue: Arc::new(Mutex::new(VecDeque::new())),
        }
    }

    fn spawn_actor(&self, name: String) -> ActorRef {
        let actor_ref = Arc::new(Mutex::new(Printer::new(name)));
        {
            let mut actors_table = self.actors_table.lock().unwrap();
            actors_table.push(actor_ref.clone());
        }
        actor_ref
    }

    fn send_to_actor(&self, actor_ref: ActorRef, message: Message) {
        {
            let mut actor = actor_ref.lock().unwrap();
            actor.receive(message);
        }
        {
            let mut actors_queue = self.actors_queue.lock().unwrap();
            actors_queue.push_back(actor_ref);
        }
    }
}

fn main() {
    let message = "This is a message".to_string();
    let command = "This is a command".to_string();

    let mut actor = Printer::new("actor_1".to_string());

    actor.receive(Message::Command(command));
    actor.receive(Message::Data(Box::new(message)));
    actor.receive(Message::Data(Box::new(3i32)));

    actor.handle_message();
    actor.handle_message();
    actor.handle_message();
}
<commit_msg>WIP - Messages go through the ActorSystem<commit_after>use std::any::Any;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

enum Message {
    Command(String),
    Data(Box<Any + Send>),
}

type ActorRef = Arc<Mutex<Actor>>;

trait Actor {
    fn receive(&mut self, Message);
    fn handle_message(&mut self);
}

struct Printer {
    _name: String,
    message_queue: VecDeque<Message>,
}

impl Printer {
    fn new(name: String) -> Printer {
        Printer {
            _name: name,
            message_queue: VecDeque::new(),
        }
    }
}

impl Actor for Printer {
    fn receive(&mut self, message: Message) {
        self.message_queue.push_back(message);
    }

    fn handle_message(&mut self) {
        let message = self.message_queue.pop_front().unwrap();

        match message {
            Message::Command(command) => {
                println!("Received Command: ({})", command)
            },
            Message::Data(truc) => {
                match truc.downcast_ref::<String>() {
                    Some(s) => println!("Received data: ({})", s),
                    None => println!("Message is dropped"),
                }
            }
        }
    }
}

struct ActorSystem {
    // TODO(gamazeps): Use an unordered container instead.
    // There is currently an issue with having an ActorRef as a Arc<Mutex<Actor + Eq + Hash>>.
    actors_table: Mutex<Vec<ActorRef>>,
    actors_queue: Arc<Mutex<VecDeque<ActorRef>>>,
}

impl ActorSystem {
    fn new() -> ActorSystem {
        ActorSystem {
            actors_table: Mutex::new(Vec::new()),
            actors_queue: Arc::new(Mutex::new(VecDeque::new())),
        }
    }

    fn spawn_actor(&self, name: String) -> ActorRef {
        let actor_ref = Arc::new(Mutex::new(Printer::new(name)));
        {
            let mut actors_table = self.actors_table.lock().unwrap();
            actors_table.push(actor_ref.clone());
        }
        actor_ref
    }

    fn send_to_actor(&self, actor_ref: ActorRef, message: Message) {
        {
            let mut actor = actor_ref.lock().unwrap();
            actor.receive(message);
        }
        {
            let mut actors_queue = self.actors_queue.lock().unwrap();
            actors_queue.push_back(actor_ref);
        }
    }

    fn handle_actor_message(&self) {
        let actor_ref;
        {
            actor_ref = self.actors_queue.lock().unwrap().pop_front();
        }
        if let Some(actor) = actor_ref {
            actor.lock().unwrap().handle_message();
        }
    }
}

fn main() {
    let message = "This is a message".to_string();
    let command = "This is a command".to_string();

    let actor_system = ActorSystem::new();
    let actor_ref = actor_system.spawn_actor("actor_1".to_string());

    actor_system.send_to_actor(actor_ref.clone(), Message::Command(command));
    actor_system.send_to_actor(actor_ref.clone(), Message::Data(Box::new(message)));
    actor_system.send_to_actor(actor_ref.clone(), Message::Data(Box::new(3i32)));

    actor_system.handle_actor_message();
    actor_system.handle_actor_message();
    actor_system.handle_actor_message();
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate notify;
extern crate rustc_serialize;

use actions::Action;
use actions::print::PrintAction;
use actions::command::CommandAction;
use docopt::Docopt;
use files_watcher::FilesWatcher;
use std::path::PathBuf;

pub mod files_watcher;
pub mod actions;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[cfg_attr(rustfmt, rustfmt_skip)]
const USAGE: &'static str = "
Eagle Eye.

Usage:
  eagle [--quiet] [--execute=<cmd>] <path>
  eagle (-h | --help)
  eagle --version

Options:
  path                  Path to a file or directory to watch for changes.
  -e --execute=<cmd>    A command to execute whenever a change happens.
                        If the command contains one or more instances of
                        {:p}, they will be replaced by the path to the changed
                        file or folder.
  -h --help             Show this screen.
  -q --quiet            Do not print file change information.
  --version             Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_path: String,
    flag_execute: String,
    flag_help: bool,
    flag_quiet: bool,
    flag_version: bool,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    let version_option = Some(VERSION.to_string());
    let args: Args = Docopt::new(USAGE)
                         .and_then(|d| {
                             d.help(true)
                              .version(version_option)
                              .decode()
                         })
                         .unwrap_or_else(|e| e.exit());

    let mut actions: Vec<Box<Action + 'static>> = vec![];

    if !args.flag_quiet {
        let print = PrintAction::new();
        actions.push(Box::new(print));
    }

    if !args.flag_execute.is_empty() {
        let command = CommandAction::new(args.flag_execute, args.flag_quiet);
        actions.push(Box::new(command));
    }

    let mut fw = FilesWatcher::new();

    let path_buf = PathBuf::from(args.arg_path);
    fw.add_file(path_buf, actions);

    loop {
        let result = fw.wait_and_execute();

        match result {
            Ok(i) => println!("Executed {} action(s) successfully.", i),
            Err(_) => println!("Error executing some actions."),
        }
    }

    // Uncomment this as soon as we have a way of leaving the loop
    // fw.close();
}
<commit_msg>Add the command-line flag for a config file<commit_after>extern crate docopt;
extern crate notify;
extern crate rustc_serialize;
extern crate toml;

use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::process;

use actions::Action;
use actions::print::PrintAction;
use actions::command::CommandAction;
use docopt::Docopt;
use files_watcher::FilesWatcher;
use toml::Value;

pub mod files_watcher;
pub mod actions;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[cfg_attr(rustfmt, rustfmt_skip)]
const USAGE: &'static str = "
Eagle Eye.

Usage:
  eagle [--quiet] [--config=<cfg_path>] [--execute=<cmd>] [--path=<path>]
  eagle (-h | --help)
  eagle --version

Options:
  -c --config=<cfg_path>  Path to a TOML config file. This option is mutually
                          exclusive to the -p and -e options.
  -e --execute=<cmd>      A command to execute whenever a change happens.
                          If the command contains one or more instances of
                          {:p}, they will be replaced by the path to the
                          changed file or folder. Requires also specifying
                          the -p option.
  -h --help               Show this screen.
  -p --path=<path>        Path to a file or directory to watch for changes.
                          Requires also specifying the -e option.
  -q --quiet              Do not print file change information.
  --version               Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_config: String,
    flag_execute: String,
    flag_help: bool,
    flag_quiet: bool,
    flag_version: bool,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    let version_option = Some(VERSION.to_string());
    let args: Args = Docopt::new(USAGE)
                         .and_then(|d| {
                             d.help(true)
                              .version(version_option)
                              .decode()
                         })
                         .unwrap_or_else(|e| e.exit());

    let mut actions: Vec<Box<Action + 'static>> = vec![];

    if !args.flag_config.is_empty() &&
        (!args.flag_execute.is_empty() || !args.flag_path.is_empty()) {
        println!("Error: you can specify a config file or a command to");
        println!("       execute and a path, but not both.");
        process::exit(1);
    }

    if args.flag_execute.is_empty() && !args.flag_path.is_empty() {
        println!("Error: you have specified a path to watch, but no command");
        println!("       to execute on changes. Use the -e option to specify");
        println!("       a command.");
        process::exit(1);
    }

    if !args.flag_execute.is_empty() && args.flag_path.is_empty() {
        println!("Error: you have specified a command to execute, but no");
        println!("       path to watch. Use the -p option to specify a path.");
        process::exit(1);
    }

    if args.flag_config.is_empty() && args.flag_execute.is_empty() {
        println!("Error: you must specify either a config file or a command");
        println!("       to execute and a path.");
        process::exit(1);
    }

    if !args.flag_quiet {
        let print = PrintAction::new();
        actions.push(Box::new(print));
    }

    if !args.flag_execute.is_empty() {
        let command = CommandAction::new(args.flag_execute, args.flag_quiet);
        actions.push(Box::new(command));
    }

    let mut fw = FilesWatcher::new();

    let path_buf = PathBuf::from(args.flag_path);
    fw.add_file(path_buf, actions);

    loop {
        let result = fw.wait_and_execute();

        match result {
            Ok(i) => println!("Executed {} action(s) successfully.", i),
            Err(_) => println!("Error executing some actions."),
        }
    }

     //Uncomment this as soon as we have a way of leaving the loop
     //fw.close();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate rand;

mod world;
use world::terrain::Terrain;

mod draw;
use draw::shaders::ShaderManager;

mod math3d;

fn main() {
	use glium::{DisplayBuild, Surface};
	// can not do multisampling due to glutin bug with_multisampling(16)
	let display = glium::glutin::WindowBuilder::new().with_vsync().with_depth_buffer(24).build_glium().unwrap();

	// draw parametres
	let params = glium::DrawParameters {
		depth: glium::Depth {
			test:glium::DepthTest::IfLess,
			write:true,
			.. Default::default()
		},
		.. Default::default()
	};

	// build all the shaders
	let mut shader_manager = ShaderManager::new(&display);

	// create terrain
	let terrain = Terrain::new(&display,&mut shader_manager,5);
	let other = Terrain::new(&display,&mut shader_manager,3);

	/*
	// init scene
	// create a triangle
	let vertex1 = Vertex { position: [-0.5,-0.5] };
	let vertex2 = Vertex { position: [0.0,0.5] };
	let vertex3 = Vertex { position: [0.5,-0.25] };
	let shape = vec![vertex1,vertex2,vertex3];
	let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
	let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

	// shader program
	let vertex_shader_src = r#"
		#version 430

		in vec2 position;

		void main(){
			gl_Position = vec4(position, 0.0, 1.0);
		}
	"#;
	let fragment_shader_src = r#"
		#version 430

		out vec4 color;

		void main(){
			color = vec4(1.0, 0.0, 0.0, 1.0);
		}
	"#;
	let program = glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None).unwrap();*/

    // listen for events produced in the window and wait to be received
    loop {
    	// get reference to the frame
    	let mut target = display.draw();

    	// clear the background
    	target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0),1.0);

    	//target.draw(&vertex_buffer,&indices,&program,&glium::uniforms::EmptyUniforms,&params).unwrap();

    	// finish drawing and destroy frame object
    	target.finish().unwrap();

	    for ev in display.poll_events(){
	    	match ev {
	    		glium::glutin::Event::Closed => return,
	    		_ => ()
	    	}
	    }
    }
}<commit_msg>Clean some things up<commit_after>#[macro_use]
extern crate glium;
extern crate rand;

mod world;
use world::terrain::Terrain;

mod draw;
use draw::shaders::ShaderManager;

mod math3d;

fn main() {
	use glium::{DisplayBuild, Surface};
	// can not do multisampling due to glutin bug with_multisampling(16)
	let display = glium::glutin::WindowBuilder::new().with_vsync().with_depth_buffer(24).build_glium().unwrap();

	// draw parametres
	let params = glium::DrawParameters {
		depth: glium::Depth {
			test:glium::DepthTest::IfLess,
			write:true,
			.. Default::default()
		},
		.. Default::default()
	};

	// build all the shaders
	let mut shader_manager = ShaderManager::new(&display);

	// create terrain
	let terrain = Terrain::new(&display,&mut shader_manager,5);

    // listen for events produced in the window and wait to be received
    loop {
    	// get reference to the frame
    	let mut target = display.draw();

    	// clear the background
    	target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0),1.0);

    	// draw the terrain

    	//target.draw(&vertex_buffer,&indices,&program,&glium::uniforms::EmptyUniforms,&params).unwrap();

    	// finish drawing and destroy frame object
    	target.finish().unwrap();

	    for ev in display.poll_events(){
	    	match ev {
	    		glium::glutin::Event::Closed => return,
	    		_ => ()
	    	}
	    }
    }
}<|endoftext|>


<commit_before>#[derive(Eq,PartialEq,Debug,Copy,Clone)]
struct Locale {
    rank: u8,
    file: u8
}

impl Locale {
    pub fn bit_index(&self) -> u32 {
        (8u32 * self.rank as u32) + self.file as u32
    }

    pub fn pinpoint(&self) -> Bitboard {
        Bitboard(2u64.pow(self.bit_index()))
    }
}

#[derive(Eq,PartialEq,Debug)]
struct Bitboard(u64);

impl Bitboard {
    pub fn new() -> Bitboard {
        Bitboard(0)
    }

    pub fn init(starters: &Vec<Locale>) -> Bitboard {
        let mut board = Bitboard::new();
        for &starter in starters.iter() {
            board = board.alight(starter);
        }
        board
    }

    pub fn union(&self, other: Bitboard) -> Bitboard {
        let Bitboard(our_bits) = *self;
        let Bitboard(their_bits) = other;
        Bitboard(our_bits | their_bits)
    }

    pub fn intersection(&self, other: Bitboard) -> Bitboard {
        let Bitboard(our_bits) = *self;
        let Bitboard(their_bits) = other;
        Bitboard(our_bits & their_bits)
    }

    pub fn invert(&self) -> Bitboard {
        let Bitboard(our_bits) = *self;
        Bitboard(our_bits ^ our_bits)
    }

    pub fn alight(&self, station: Locale) -> Bitboard {
        // classic `|= (1 << n)` would probably be more efficient, huh &c.
        self.union(station.pinpoint())
    }

    pub fn quench(&self, station: Locale) -> Bitboard {
        self.intersection(station.pinpoint().invert())
    }

    pub fn query(&self, station: Locale) -> bool {
        let Bitboard(our_bits) = *self;
        let Bitboard(beacon_bits) = station.pinpoint();
        (our_bits & beacon_bits) != 0
    }
}

#[derive(Eq,PartialEq,Debug)]
enum Team { Orange, Blue }

#[derive(Eq,PartialEq,Debug)]
enum JobDescription { Servant, Pony, Scholar, Cop, Princess, Figurehead }

#[derive(Eq,PartialEq,Debug)]
struct Agent {
    team: Team,
    job_description: JobDescription
}

#[derive(Eq,PartialEq,Debug)]
struct GameState {
    orange_servants: Bitboard,
    orange_ponies: Bitboard,
    orange_scholars: Bitboard,
    orange_cops: Bitboard,
    orange_princesses: Bitboard,
    orange_figurehead: Bitboard,

    blue_servants: Bitboard,
    blue_ponies: Bitboard,
    blue_scholars: Bitboard,
    blue_cops: Bitboard,
    blue_princesses: Bitboard,
    blue_figurehead: Bitboard,
}

impl GameState {
    pub fn new() -> GameState {
        let mut orange_servant_locales = Vec::new();
        let mut blue_servant_locales = Vec::new();
        for f in 0..8 {
            orange_servant_locales.push(Locale { rank: 6, file: f });
            blue_servant_locales.push(Locale { rank: 1, file: f });
        }
        GameState {
            orange_servants: Bitboard::init(&orange_servant_locales),
            orange_ponies: Bitboard::init(
                &vec![Locale { rank: 0, file: 1 },
                      Locale { rank: 0, file: 6 }]
            ),
            orange_scholars: Bitboard::init(
                &vec![Locale { rank: 0, file: 2 },
                      Locale { rank: 0, file: 5 }]
            ),
            orange_cops: Bitboard::init(
                &vec![Locale { rank: 0, file: 0 },
                      Locale { rank: 0, file: 7 }]
            ),
            orange_princesses: Bitboard::init(
                &vec![Locale { rank: 0, file: 3 }]),
            orange_figurehead: Bitboard::init(
                &vec![Locale { rank: 0, file: 4 }]),
            blue_servants: Bitboard::init(&blue_servant_locales),
            blue_ponies: Bitboard::init(
                &vec![Locale { rank: 7, file: 1 },
                      Locale { rank: 7, file: 6 }]
            ),
            blue_scholars: Bitboard::init(
                &vec![Locale { rank: 7, file: 2 },
                      Locale { rank: 7, file: 5 }]
            ),
            blue_cops: Bitboard::init(
                &vec![Locale { rank: 7, file: 0 },
                      Locale { rank: 7, file: 7 }]
            ),
            blue_princesses: Bitboard::init(
                &vec![Locale { rank: 7, file: 3 }]),
            blue_figurehead: Bitboard::init(
                &vec![Locale { rank: 7, file: 4 }]),
        }
    }

    pub fn agent_to_bitboard_ref(&self, agent: Agent) ->
        // I'm actually going to return a Bitboard from this function,
        // but am writing something different first as an experiment to see if
        // I understand how `match` works.
        &str {
        match agent {
            Agent{ team: Team::Orange, .. } => "orange!",
            Agent{ team: Team::Blue, .. } => "blue!"
        }
        // TOOD
    }

    pub fn display(&self) {
        for rank in 0..8 {
            for file in 0..8 {
                // TODO
            }
        }

    }

}

#[cfg(test)]
mod test {
    use super::{Locale, Bitboard, Team, JobDescription, Agent, GameState};

    #[test]
    fn test_locale() {
        let a1 = Locale { rank: 0, file: 0 };
        assert_eq!(Bitboard(1u64), a1.pinpoint());

        let c4 = Locale { rank: 2, file: 3 };
        assert_eq!(Bitboard(524288u64), c4.pinpoint());
    }

    #[test]
    fn test_empty_board_is_empty() {
        let empty_board = Bitboard::new();
        for rank in 0..8 {
            for file in 0..8 {
                assert!(!empty_board.query(Locale { rank: rank, file: file }));
            }
        }
    }

    #[test]
    fn test_alight_and_quench() {
        let mut stage = Bitboard(0);
        let b5 = Locale { rank: 1, file: 4 };
        stage = stage.alight(b5);
        assert!(stage.query(b5));
        stage = stage.quench(b5);
        assert!(!stage.query(b5));
    }

    #[test]
    fn test_init_bitboard() {
        let starters = vec![Locale{ rank: 1, file: 2 },
                            Locale{ rank: 3, file: 4 },
                            Locale{ rank: 5, file: 6 }];
        let stage = Bitboard::init(&starters);
        for &starter in starters.iter() {
            assert!(stage.query(starter));
        }
    }

    #[test]
    fn test_agent_to_bitboard_ref_on_new_stage() {
        let stage = GameState::new();
        let agent = Agent { team: Team::Blue,
                            job_description: JobDescription::Princess };
        assert_eq!("blue!", stage.agent_to_bitboard_ref(agent));
    }

}
<commit_msg>"The needle on my record player has been wearing thin"<commit_after>#[derive(Eq,PartialEq,Debug,Copy,Clone)]
struct Locale {
    rank: u8,
    file: u8
}

impl Locale {
    pub fn bit_index(&self) -> u32 {
        (8u32 * self.rank as u32) + self.file as u32
    }

    pub fn pinpoint(&self) -> Bitboard {
        Bitboard(2u64.pow(self.bit_index()))
    }
}

#[derive(Eq,PartialEq,Debug)]
struct Bitboard(u64);

impl Bitboard {
    pub fn new() -> Bitboard {
        Bitboard(0)
    }

    pub fn init(starters: &Vec<Locale>) -> Bitboard {
        let mut board = Bitboard::new();
        for &starter in starters.iter() {
            board = board.alight(starter);
        }
        board
    }

    pub fn union(&self, other: Bitboard) -> Bitboard {
        let Bitboard(our_bits) = *self;
        let Bitboard(their_bits) = other;
        Bitboard(our_bits | their_bits)
    }

    pub fn intersection(&self, other: Bitboard) -> Bitboard {
        let Bitboard(our_bits) = *self;
        let Bitboard(their_bits) = other;
        Bitboard(our_bits & their_bits)
    }

    pub fn invert(&self) -> Bitboard {
        let Bitboard(our_bits) = *self;
        Bitboard(our_bits ^ our_bits)
    }

    pub fn alight(&self, station: Locale) -> Bitboard {
        // classic `|= (1 << n)` would probably be more efficient, huh &c.
        self.union(station.pinpoint())
    }

    pub fn quench(&self, station: Locale) -> Bitboard {
        self.intersection(station.pinpoint().invert())
    }

    pub fn query(&self, station: Locale) -> bool {
        let Bitboard(our_bits) = *self;
        let Bitboard(beacon_bits) = station.pinpoint();
        (our_bits & beacon_bits) != 0
    }
}

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
enum Team { Orange, Blue }

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
enum JobDescription {
    Servant,  // ♂
    Pony,  // ♀
    Scholar,  // ♀
    Cop,  // ♂
    Princess,  // ♀
    Figurehead  // ♂
}

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
struct Agent {
    team: Team,
    job_description: JobDescription
}

impl Agent {
    // I wanted to call it `dramatis_personæ`, but "non-ascii idents
    // are not fully supported" 🙀
    pub fn dramatis_personae() -> Vec<Agent> {
        vec![Agent{ team: Team::Orange,
                    job_description: JobDescription::Servant },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Pony },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Scholar },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Cop },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Princess },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Figurehead },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Servant },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Pony },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Scholar },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Cop },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Princess },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Figurehead }]
    }
}

#[derive(Eq,PartialEq,Debug)]
struct GameState {
    orange_servants: Bitboard,
    orange_ponies: Bitboard,
    orange_scholars: Bitboard,
    orange_cops: Bitboard,
    orange_princesses: Bitboard,
    orange_figurehead: Bitboard,

    blue_servants: Bitboard,
    blue_ponies: Bitboard,
    blue_scholars: Bitboard,
    blue_cops: Bitboard,
    blue_princesses: Bitboard,
    blue_figurehead: Bitboard,
}

impl GameState {
    pub fn new() -> GameState {
        let mut orange_servant_locales = Vec::new();
        let mut blue_servant_locales = Vec::new();
        for f in 0..8 {
            orange_servant_locales.push(Locale { rank: 6, file: f });
            blue_servant_locales.push(Locale { rank: 1, file: f });
        }
        GameState {
            orange_servants: Bitboard::init(&orange_servant_locales),
            orange_ponies: Bitboard::init(
                &vec![Locale { rank: 0, file: 1 },
                      Locale { rank: 0, file: 6 }]
            ),
            orange_scholars: Bitboard::init(
                &vec![Locale { rank: 0, file: 2 },
                      Locale { rank: 0, file: 5 }]
            ),
            orange_cops: Bitboard::init(
                &vec![Locale { rank: 0, file: 0 },
                      Locale { rank: 0, file: 7 }]
            ),
            orange_princesses: Bitboard::init(
                &vec![Locale { rank: 0, file: 3 }]),
            orange_figurehead: Bitboard::init(
                &vec![Locale { rank: 0, file: 4 }]),
            blue_servants: Bitboard::init(&blue_servant_locales),
            blue_ponies: Bitboard::init(
                &vec![Locale { rank: 7, file: 1 },
                      Locale { rank: 7, file: 6 }]
            ),
            blue_scholars: Bitboard::init(
                &vec![Locale { rank: 7, file: 2 },
                      Locale { rank: 7, file: 5 }]
            ),
            blue_cops: Bitboard::init(
                &vec![Locale { rank: 7, file: 0 },
                      Locale { rank: 7, file: 7 }]
            ),
            blue_princesses: Bitboard::init(
                &vec![Locale { rank: 7, file: 3 }]),
            blue_figurehead: Bitboard::init(
                &vec![Locale { rank: 7, file: 4 }]),
        }
    }

    pub fn agent_to_bitboard_ref(&self, agent: Agent) -> &Bitboard {
        match agent {
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Servant } =>
                &self.orange_servants,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Pony } =>
                &self.orange_ponies,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Scholar } =>
                &self.orange_scholars,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Cop } =>
                &self.orange_cops,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Princess } =>
                &self.orange_princesses,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Figurehead } =>
                &self.orange_figurehead,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Servant } =>
                &self.blue_servants,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Pony } =>
                &self.blue_ponies,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Scholar } =>
                &self.blue_scholars,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Cop } =>
                &self.blue_cops,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Princess } =>
                &self.blue_princesses,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Figurehead } =>
                &self.blue_figurehead,
        }
    }

    pub fn display(&self) {
        for rank in 0..8 {
            for file in 0..8 {
                for &figurine in Agent::dramatis_personae().iter() {
                    if self.agent_to_bitboard_ref(figurine).query(
                        Locale { rank: rank, file: file }
                    ) {
                        print!("X");
                    }
                }
            }
            println!("");
        }
    }
}

fn main() {
    let arena = GameState::new();
    arena.display();
}

#[cfg(test)]
mod test {
    use super::{Locale, Bitboard, Team, JobDescription, Agent, GameState};

    #[test]
    fn test_locale() {
        let a1 = Locale { rank: 0, file: 0 };
        assert_eq!(Bitboard(1u64), a1.pinpoint());

        let c4 = Locale { rank: 2, file: 3 };
        assert_eq!(Bitboard(524288u64), c4.pinpoint());
    }

    #[test]
    fn test_empty_board_is_empty() {
        let empty_board = Bitboard::new();
        for rank in 0..8 {
            for file in 0..8 {
                assert!(!empty_board.query(Locale { rank: rank, file: file }));
            }
        }
    }

    #[test]
    fn test_alight_and_quench() {
        let mut stage = Bitboard(0);
        let b5 = Locale { rank: 1, file: 4 };
        stage = stage.alight(b5);
        assert!(stage.query(b5));
        stage = stage.quench(b5);
        assert!(!stage.query(b5));
    }

    #[test]
    fn test_init_bitboard() {
        let starters = vec![Locale{ rank: 1, file: 2 },
                            Locale{ rank: 3, file: 4 },
                            Locale{ rank: 5, file: 6 }];
        let stage = Bitboard::init(&starters);
        for &starter in starters.iter() {
            assert!(stage.query(starter));
        }
    }

    #[test]
    fn test_agent_to_bitboard_ref_on_new_gamestate() {
        let state = GameState::new();
        let agent = Agent { team: Team::Blue,
                            job_description: JobDescription::Princess };
        let blue_princess_realm = state.agent_to_bitboard_ref(agent);
        assert!(blue_princess_realm.query(Locale { rank: 7, file: 3 }));
    }

}
<|endoftext|>