<commit_before>use neat::*;

#[derive(Debug, Clone)]
pub struct Organism {
    pub genome: Genome,
    pub fitness: f64,
    pub neurons: Vec<Option<Neuron>>
}

const ACTIVATION_CYCLES: usize = 10;

impl Organism {
    pub fn new(genome: Genome) -> Organism {
        Organism { genome: genome, fitness: 0f64, neurons: vec![] }
    }

    pub fn mutate(&self) -> Organism {
        let mut new_genome = self.genome.clone();
        new_genome.mutate();
        Organism::new(new_genome)
    }

    pub fn mate(&self, other: &Organism) -> Organism {
        Organism::new(self.genome.mate(&other.genome, self.fitness < other.fitness))
    }

    pub fn activate(&mut self, sensors: &Vec<f64>, outputs: &mut Vec<f64>){
       if self.neurons.len() == 0 {
           self.generate_phenome();
       };

       for _n in 0..ACTIVATION_CYCLES {
           for neuron_id in 0..sensors.len() {
               if neuron_id < self.neurons.len() {
                   self.neurons[neuron_id].as_mut().unwrap().stimulate(sensors[neuron_id]);
               }
           }

           self.activate_neurons();
           self.propagate_signals();
       }

       //Take outputs from next neurons after sensors
       let sensors_len = sensors.len();
       for neuron_id in sensors_len..(sensors_len + outputs.len()){
           if neuron_id < self.neurons.len() {
               outputs[neuron_id - sensors_len] = self.neurons[neuron_id].as_ref().map_or(0f64, |neuron| neuron.potential());
           } else {
               outputs[neuron_id - sensors_len] = 0f64;
           }
       }

       for neuron in &mut self.neurons {
           if neuron.is_some() {
               neuron.as_mut().unwrap().relax();
           }
       }
    }

    fn activate_neurons(&mut self){
        for neuron_id in 0..self.neurons.len() {
            self.neurons[neuron_id].as_mut().unwrap().shot();
        }
    }

    fn propagate_signals(&mut self){
        for neuron_option in self.neurons.clone() {
            let neuron = neuron_option.unwrap();
            for connection in &neuron.connections {
               self.neurons[connection.0].as_mut().unwrap().stimulate(neuron.potential() * connection.1);
            }
        }
    }

    fn generate_phenome(&mut self){
        let neurons_to_generate = self.genome.len();

        self.neurons = vec![Some(Neuron::new()); neurons_to_generate as usize];

        for gene in self.genome.get_genes() {
            let mut neuron = self.neurons[gene.in_neuron_id].as_mut().unwrap();
            neuron.connections.push(Connection(gene.out_neuron_id, gene.weight));
        }
    }
}

#[cfg(test)]
mod tests {
    use neat::*;

    #[test]
    fn should_be_able_to_generate_his_phenome(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 0, 0.1f64);
        organism.genome.inject_gene(0, 1, 0.2f64);
        organism.genome.inject_gene(1, 0, 0.3f64);
        organism.genome.inject_gene(1, 1, 0.4f64);
        organism.generate_phenome();
        assert!(organism.neurons.len() == 2);
        let neuron0 = &organism.neurons[0].as_ref().unwrap();
        let connection00 = &neuron0.connections[0];
        assert!(connection00.0 == 0usize);
        assert!(connection00.1 == 0.1f64);
        let connection01 = &neuron0.connections[1];
        assert!(connection01.0 == 1usize);
        assert!(connection01.1 == 0.2f64);
        let neuron1 = &organism.neurons[1].as_ref().unwrap();
        let connection10 = &neuron1.connections[0];
        assert!(connection10.0 == 0usize);
        assert!(connection10.1 == 0.3f64);
        let connection11 = &neuron1.connections[1];
        assert!(connection11.0 == 1usize);
        assert!(connection11.1 == 0.4f64);
    }

    #[test]
    fn should_propagate_signal_without_hidden_layers(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, 1f64);
        let sensors = vec![1f64];
        let mut output = vec![0f64];
        organism.activate(&sensors, &mut output);
        assert!(output[0] > 0.9f64, format!("{:?} is not bigger than 0.9", output[0]));

        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, -1f64);
        let sensors = vec![1f64];
        let mut output = vec![0f64];
        organism.activate(&sensors, &mut output);
        assert!(output[0] < 0.1f64, format!("{:?} is not smaller than 0.1", output[0]));
    }

    #[test]
    fn should_propagate_signal_over_hidden_layers(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, 0f64); //disable connection
        organism.genome.inject_gene(0, 2, 1f64);
        organism.genome.inject_gene(2, 1, 1f64);
        let sensors = vec![0f64];
        let mut output = vec![0f64];
        organism.activate(&sensors, &mut output);
        assert!(output[0] > 0.9f64, format!("{:?} is not bigger than 0.9", output[0]));
    }

    #[test]
    fn should_work_with_cyclic_networks(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, 1f64);
        organism.genome.inject_gene(1, 2, 1f64);
        organism.genome.inject_gene(2, 1, 1f64);
        let mut output = vec![0f64];
        organism.activate(&vec![1f64], &mut output);
        assert!(output[0] > 0.9, format!("{:?} is not bigger than 0.9", output[0]));

        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, -1f64);
        organism.genome.inject_gene(1, 2, -1f64);
        organism.genome.inject_gene(2, 1, -1f64);
        let mut output = vec![0f64];
        organism.activate(&vec![1f64], &mut output);
        assert!(output[0] < 0.1, format!("{:?} is not smaller than 0.1", output[0]));
    }

    #[test]
    fn activate_organims_sensor_without_enough_neurons_should_ignore_it(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, 1f64);
        let sensors = vec![0f64,0f64,0f64];
        let mut output = vec![0f64];
        organism.activate(&sensors, &mut output);
    }
}
<commit_msg>Generate strength connections matrix<commit_after>use neat::*;

#[derive(Debug, Clone)]
pub struct Organism {
    pub genome: Genome,
    pub fitness: f64,
    pub neurons: Vec<Option<Neuron>>
}

const ACTIVATION_CYCLES: usize = 10;

impl Organism {
    pub fn new(genome: Genome) -> Organism {
        Organism { genome: genome, fitness: 0f64, neurons: vec![] }
    }

    pub fn mutate(&self) -> Organism {
        let mut new_genome = self.genome.clone();
        new_genome.mutate();
        Organism::new(new_genome)
    }

    pub fn mate(&self, other: &Organism) -> Organism {
        Organism::new(self.genome.mate(&other.genome, self.fitness < other.fitness))
    }

    pub fn activate(&mut self, sensors: &Vec<f64>, outputs: &mut Vec<f64>){
       if self.neurons.len() == 0 {
           self.generate_phenome();
       };

       for _n in 0..ACTIVATION_CYCLES {
           for neuron_id in 0..sensors.len() {
               if neuron_id < self.neurons.len() {
                   self.neurons[neuron_id].as_mut().unwrap().stimulate(sensors[neuron_id]);
               }
           }

           self.activate_neurons();
           self.propagate_signals();
       }

       //Take outputs from next neurons after sensors
       let sensors_len = sensors.len();
       for neuron_id in sensors_len..(sensors_len + outputs.len()){
           if neuron_id < self.neurons.len() {
               outputs[neuron_id - sensors_len] = self.neurons[neuron_id].as_ref().map_or(0f64, |neuron| neuron.potential());
           } else {
               outputs[neuron_id - sensors_len] = 0f64;
           }
       }

       for neuron in &mut self.neurons {
           if neuron.is_some() {
               neuron.as_mut().unwrap().relax();
           }
       }
    }

    fn activate_neurons(&mut self){
        for neuron_id in 0..self.neurons.len() {
            self.neurons[neuron_id].as_mut().unwrap().shot();
        }
    }

    fn propagate_signals(&mut self){
        for neuron_option in self.neurons.clone() {
            let neuron = neuron_option.unwrap();
            for connection in &neuron.connections {
               self.neurons[connection.0].as_mut().unwrap().stimulate(neuron.potential() * connection.1);
            }
        }
    }

    fn generate_phenome(&mut self){
        let neurons_to_generate = self.genome.len();

        self.neurons = vec![Some(Neuron::new()); neurons_to_generate as usize];

        for gene in self.genome.get_genes() {
            let mut neuron = self.neurons[gene.in_neuron_id].as_mut().unwrap();
            neuron.connections.push(Connection(gene.out_neuron_id, gene.weight));
        }
    }

    fn get_weights_matrix(&self) -> Vec<Vec<f64>>{
        let neurons_len = self.genome.len();
        let mut matrix = vec![vec![0.0; neurons_len]; neurons_len];
        for gene in self.genome.get_genes() {
            if gene.enabled {
                matrix[gene.in_neuron_id][gene.out_neuron_id] = gene.weight
            }
        }
        matrix
    }
}

#[cfg(test)]
mod tests {
    use neat::*;

    #[test]
    fn should_be_able_to_generate_his_phenome(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 0, 0.1f64);
        organism.genome.inject_gene(0, 1, 0.2f64);
        organism.genome.inject_gene(1, 0, 0.3f64);
        organism.genome.inject_gene(1, 1, 0.4f64);
        organism.generate_phenome();
        assert!(organism.neurons.len() == 2);
        let neuron0 = &organism.neurons[0].as_ref().unwrap();
        let connection00 = &neuron0.connections[0];
        assert!(connection00.0 == 0usize);
        assert!(connection00.1 == 0.1f64);
        let connection01 = &neuron0.connections[1];
        assert!(connection01.0 == 1usize);
        assert!(connection01.1 == 0.2f64);
        let neuron1 = &organism.neurons[1].as_ref().unwrap();
        let connection10 = &neuron1.connections[0];
        assert!(connection10.0 == 0usize);
        assert!(connection10.1 == 0.3f64);
        let connection11 = &neuron1.connections[1];
        assert!(connection11.0 == 1usize);
        assert!(connection11.1 == 0.4f64);
    }

    #[test]
    fn should_propagate_signal_without_hidden_layers(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, 1f64);
        let sensors = vec![1f64];
        let mut output = vec![0f64];
        organism.activate(&sensors, &mut output);
        assert!(output[0] > 0.9f64, format!("{:?} is not bigger than 0.9", output[0]));

        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, -1f64);
        let sensors = vec![1f64];
        let mut output = vec![0f64];
        organism.activate(&sensors, &mut output);
        assert!(output[0] < 0.1f64, format!("{:?} is not smaller than 0.1", output[0]));
    }

    #[test]
    fn should_propagate_signal_over_hidden_layers(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, 0f64); //disable connection
        organism.genome.inject_gene(0, 2, 1f64);
        organism.genome.inject_gene(2, 1, 1f64);
        let sensors = vec![0f64];
        let mut output = vec![0f64];
        organism.activate(&sensors, &mut output);
        assert!(output[0] > 0.9f64, format!("{:?} is not bigger than 0.9", output[0]));
    }

    #[test]
    fn should_work_with_cyclic_networks(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, 1f64);
        organism.genome.inject_gene(1, 2, 1f64);
        organism.genome.inject_gene(2, 1, 1f64);
        let mut output = vec![0f64];
        organism.activate(&vec![1f64], &mut output);
        assert!(output[0] > 0.9, format!("{:?} is not bigger than 0.9", output[0]));

        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, -1f64);
        organism.genome.inject_gene(1, 2, -1f64);
        organism.genome.inject_gene(2, 1, -1f64);
        let mut output = vec![0f64];
        organism.activate(&vec![1f64], &mut output);
        assert!(output[0] < 0.1, format!("{:?} is not smaller than 0.1", output[0]));
    }

    #[test]
    fn activate_organims_sensor_without_enough_neurons_should_ignore_it(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, 1f64);
        let sensors = vec![0f64,0f64,0f64];
        let mut output = vec![0f64];
        organism.activate(&sensors, &mut output);
    }

    #[test]
    fn should_be_able_to_get_matrix_representation_of_the_neuron_connections(){
        let mut organism = Organism::new(Genome::new());
        organism.genome.inject_gene(0, 1, 1f64);
        organism.genome.inject_gene(1, 2, 0.5f64);
        organism.genome.inject_gene(2, 1, 0.5f64);
        organism.genome.inject_gene(2, 2, 0.75f64);
        organism.genome.inject_gene(1, 0, 1f64);
        assert_eq!(
            organism.get_weights_matrix(),
            [
                [0.0, 1.0, 0.0],
                [1.0, 0.0, 0.5],
                [0.0, 0.5, 0.75]
            ]
        );
    }
}
<|endoftext|>


<commit_before>mod utils;

use wasm_bindgen::prelude::*;
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

use vt::VT;

#[wasm_bindgen]
pub struct VtWrapper {
    vt: VT
}

#[wasm_bindgen]
pub fn create(w: usize, h: usize) -> VtWrapper {
    VtWrapper { vt: VT::new(w, h) }
}

#[wasm_bindgen]
impl VtWrapper {
    pub fn feed(&mut self, s: &str) -> Vec<usize> {
        self.vt.feed_str(s)
    }

    pub fn inspect(&self) -> String {
        format!("{:?}", self.vt)
    }

    pub fn get_line(&self, l: usize) -> JsValue {
        let line = self.vt.get_line(l);
        serde_wasm_bindgen::to_value(&line).unwrap()
    }
}<commit_msg>js/wasm proxy for get_cursor<commit_after>mod utils;

use wasm_bindgen::prelude::*;
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

use vt::VT;

#[wasm_bindgen]
pub struct VtWrapper {
    vt: VT
}

#[wasm_bindgen]
pub fn create(w: usize, h: usize) -> VtWrapper {
    VtWrapper { vt: VT::new(w, h) }
}

#[wasm_bindgen]
impl VtWrapper {
    pub fn feed(&mut self, s: &str) -> Vec<usize> {
        self.vt.feed_str(s)
    }

    pub fn inspect(&self) -> String {
        format!("{:?}", self.vt)
    }

    pub fn get_line(&self, l: usize) -> JsValue {
        let line = self.vt.get_line(l);
        serde_wasm_bindgen::to_value(&line).unwrap()
    }

    pub fn get_cursor(&self) -> JsValue {
        let cursor = self.vt.get_cursor();
        serde_wasm_bindgen::to_value(&cursor).unwrap()
    }
}<|endoftext|>


<commit_before>use criterion::{BenchmarkId, Criterion, Throughput};
use criterion::{criterion_group, criterion_main};

use std::io::{Cursor, Read, Write};

use rand::Rng;
use zip::{CompressionMethod, ZipArchive, ZipWriter};

fn generate_random_archive(size: usize, method: Option<CompressionMethod>) -> Vec<u8> {
    let data = Vec::new();
    let mut writer = ZipWriter::new(Cursor::new(data));
    let options = zip::write::FileOptions::default()
        .compression_method(method.unwrap_or(CompressionMethod::Stored));

    writer.start_file("random.dat", options).unwrap();

    // Generate some random data.
    let mut bytes = vec![0u8; size];
    rand::thread_rng().fill(bytes.as_mut_slice());

    writer.write_all(&bytes).unwrap();

    writer.finish().unwrap().into_inner()
}

fn read_entry(bench: &mut Criterion) {
    let size = 1024 * 1024;
    let bytes = generate_random_archive(size, None);

    //
    let mut group = bench.benchmark_group("read_entry");

    //
    for method in CompressionMethod::supported_methods().iter() {
        group.bench_with_input(BenchmarkId::from_parameter(method), method, |b, method| {
            b.iter(|| {
                let mut archive = ZipArchive::new(Cursor::new(bytes.as_slice())).unwrap();
                let mut file = archive.by_name("random.dat").unwrap();
                let mut buf = [0u8; 1024];

                let mut total_bytes = 0;

                loop {
                    let n = file.read(&mut buf).unwrap();
                    total_bytes += n;
                    if n == 0 {
                        return total_bytes
                    }
                }
            });
        });
    }
}

fn write_random_archive(bench: &mut Criterion) {
    let size = 1024 * 1024;

    //
    let mut group = bench.benchmark_group("write_random_archive");

    //
    for method in CompressionMethod::supported_methods().iter() {
        group.bench_with_input(BenchmarkId::from_parameter(method), method, |b, method| {
            b.iter(|| {
                generate_random_archive(size, Some(method.clone()));
            })
        });
    }

    group.finish();
}

criterion_group!(benches, read_entry, write_random_archive);
criterion_main!(benches);
<commit_msg>Apply linter fixes<commit_after>use criterion::{criterion_group, criterion_main};
use criterion::{BenchmarkId, Criterion, Throughput};

use std::io::{Cursor, Read, Write};

use rand::Rng;
use zip::{CompressionMethod, ZipArchive, ZipWriter};

fn generate_random_archive(size: usize, method: Option<CompressionMethod>) -> Vec<u8> {
    let data = Vec::new();
    let mut writer = ZipWriter::new(Cursor::new(data));
    let options = zip::write::FileOptions::default()
        .compression_method(method.unwrap_or(CompressionMethod::Stored));

    writer.start_file("random.dat", options).unwrap();

    // Generate some random data.
    let mut bytes = vec![0u8; size];
    rand::thread_rng().fill(bytes.as_mut_slice());

    writer.write_all(&bytes).unwrap();

    writer.finish().unwrap().into_inner()
}

fn read_entry(bench: &mut Criterion) {
    let size = 1024 * 1024;
    let bytes = generate_random_archive(size, None);

    //
    let mut group = bench.benchmark_group("read_entry");

    //
    for method in CompressionMethod::supported_methods().iter() {
        group.bench_with_input(BenchmarkId::from_parameter(method), method, |b, method| {
            b.iter(|| {
                let mut archive = ZipArchive::new(Cursor::new(bytes.as_slice())).unwrap();
                let mut file = archive.by_name("random.dat").unwrap();
                let mut buf = [0u8; 1024];

                let mut total_bytes = 0;

                loop {
                    let n = file.read(&mut buf).unwrap();
                    total_bytes += n;
                    if n == 0 {
                        return total_bytes;
                    }
                }
            });
        });
    }
}

fn write_random_archive(bench: &mut Criterion) {
    let size = 1024 * 1024;

    //
    let mut group = bench.benchmark_group("write_random_archive");

    //
    for method in CompressionMethod::supported_methods().iter() {
        group.bench_with_input(BenchmarkId::from_parameter(method), method, |b, method| {
            b.iter(|| {
                generate_random_archive(size, Some(method.clone()));
            })
        });
    }

    group.finish();
}

criterion_group!(benches, read_entry, write_random_archive);
criterion_main!(benches);
<|endoftext|>


<commit_before>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::{Ipv4Addr, Ipv6Addr};

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    sequence: u32be,
    acknowledgement: u32be,
    data_offset_reserved: u8, // data offset field & reserved field
    control_bits: u8, // the first 5 bits are used; the rest is reserved
    window: u16be,
    checksum: u16be,
    urgent_pointer: u16be,
    // 16+16+32+32+8+8+16+16+16 == 20
    #[payload]
    payload: Vec<u8>
}

#[test]
fn tcp_header_ipv4_test() {
    use pnet::packet::ip::IpNextHeaderProtocols;
    use pnet::packet::ipv4::MutableIpv4Packet;

    const IPV4_HEADER_LEN: usize = 20;
    const TCP_HEADER_LEN: usize = 20;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV4_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let ipv4_source = Ipv4Addr::new(192, 168, 0, 1);
    let ipv4_destination = Ipv4Addr::new(192, 168, 0, 199);
    let next_level_protocol = IpNextHeaderProtocols::Tcp;
    {
        let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_level_protocol(next_level_protocol);
        ip_header.set_source(ipv4_source);
        ip_header.set_destination(ipv4_destination);
    }

    // Set data
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[20..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);

        tcp_header.set_data_offset_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_reserved(), 0x80);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77,
                      0x80,        // header length + reserved
                      0x00,        // control bits
                      0x00, 0x00,  // window
                      0x00, 0x00,  // checksum
                      0x00, 0x00  // urgent pointer
                      ];
                      //0x01, 0x01,  // simple no tcp header options
                      //0x01, 0x00];

    //[48, 57, 212, 49, 0, 0, 13, 128, 0, 0, 30, 119, 128, 0, 0, 0, 0, 0, 0, 0]`, right: `
    //[48, 57, 212, 49, 0, 0, 13, 128, 0, 0, 30, 119, 128, 0, 0, 0, 0, 0, 0, 0, 0]

    assert_eq!(&ref_packet[..], &packet[IPV4_HEADER_LEN .. IPV4_HEADER_LEN + TCP_HEADER_LEN]);
}

#[test]
fn tcp_header_ipv6_test() {
    use packet::ip::{IpNextHeaderProtocols};
    use packet::ipv6::{MutableIpv6Packet};

    const IPV6_HEADER_LEN: usize = 40;
    const TCP_HEADER_LEN: usize = 20;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV6_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let next_header = IpNextHeaderProtocols::Tcp;
    let ipv6_source = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    let ipv6_destination = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    {
        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_header(next_header);
        ip_header.set_source(ipv6_source);
        ip_header.set_destination(ipv6_destination);
    }

    // Set data
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[IPV6_HEADER_LEN..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);

        tcp_header.set_data_offset_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_reserved(), 0x80);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77,
                      0x80,        // header length + reserved
                      0x00,        // control bits
                      0x00, 0x00,  // window
                      0x00, 0x00,  // checksum
                      0x00, 0x00  // urgent pointer
                      ];
                      //0x01, 0x01,  // simple no tcp header options
                      //0x01, 0x00];

    assert_eq!(&ref_packet[..], &packet[IPV6_HEADER_LEN .. IPV6_HEADER_LEN + TCP_HEADER_LEN]);
}
<commit_msg>Add unit tests for various TCP header fields<commit_after>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::{Ipv4Addr, Ipv6Addr};

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    sequence: u32be,
    acknowledgement: u32be,
    data_offset_reserved: u8, // data offset field & reserved field
    control_bits: u8, // the first 5 bits are used; the rest is reserved
    window: u16be,
    checksum: u16be,
    urgent_pointer: u16be,
    // 16+16+32+32+8+8+16+16+16 == 20
    #[payload]
    payload: Vec<u8>
}

#[test]
fn tcp_header_ipv4_test() {
    use pnet::packet::ip::IpNextHeaderProtocols;
    use pnet::packet::ipv4::MutableIpv4Packet;

    const IPV4_HEADER_LEN: usize = 20;
    const TCP_HEADER_LEN: usize = 20;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV4_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let ipv4_source = Ipv4Addr::new(192, 168, 0, 1);
    let ipv4_destination = Ipv4Addr::new(192, 168, 0, 199);
    let next_level_protocol = IpNextHeaderProtocols::Tcp;
    {
        let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_level_protocol(next_level_protocol);
        ip_header.set_source(ipv4_source);
        ip_header.set_destination(ipv4_destination);
    }

    // Set data
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[20..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);

        tcp_header.set_data_offset_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_reserved(), 0x80);

        tcp_header.set_control_bits(0x03);
        assert_eq!(tcp_header.get_control_bits(), 0x03);

        tcp_header.set_window(0x4566);
        assert_eq!(tcp_header.get_window(), 0x4566);

        tcp_header.set_checksum(0x6699);
        assert_eq!(tcp_header.get_checksum(), 0x6699);

        tcp_header.set_urgent_pointer(0x1122);
        assert_eq!(tcp_header.get_urgent_pointer(), 0x1122);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77,
                      0x80,        // header length + reserved
                      0x03,        // control bits
                      0x45, 0x66,  // window
                      0x66, 0x99,  // checksum
                      0x11, 0x22   // urgent pointer
                      ];
    assert_eq!(&ref_packet[..], &packet[IPV4_HEADER_LEN .. IPV4_HEADER_LEN + TCP_HEADER_LEN]);
}

#[test]
fn tcp_header_ipv6_test() {
    use packet::ip::{IpNextHeaderProtocols};
    use packet::ipv6::{MutableIpv6Packet};

    const IPV6_HEADER_LEN: usize = 40;
    const TCP_HEADER_LEN: usize = 20;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV6_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let next_header = IpNextHeaderProtocols::Tcp;
    let ipv6_source = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    let ipv6_destination = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    {
        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_header(next_header);
        ip_header.set_source(ipv6_source);
        ip_header.set_destination(ipv6_destination);
    }

    // Set data
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[IPV6_HEADER_LEN..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);

        tcp_header.set_data_offset_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_reserved(), 0x80);

        tcp_header.set_control_bits(0x03);
        assert_eq!(tcp_header.get_control_bits(), 0x03);

        tcp_header.set_window(0x4566);
        assert_eq!(tcp_header.get_window(), 0x4566);

        tcp_header.set_checksum(0x6699);
        assert_eq!(tcp_header.get_checksum(), 0x6699);

        tcp_header.set_urgent_pointer(0x1122);
        assert_eq!(tcp_header.get_urgent_pointer(), 0x1122);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77,
                      0x80,        // header length + reserved
                      0x03,        // control bits
                      0x45, 0x66,  // window
                      0x66, 0x99,  // checksum
                      0x11, 0x22  // urgent pointer
                      ];
    assert_eq!(&ref_packet[..], &packet[IPV6_HEADER_LEN .. IPV6_HEADER_LEN + TCP_HEADER_LEN]);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A windowing implementation using GLFW.

use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use windowing::{Forward, Back};

use alert::{Alert, AlertMethods};
use std::libc::c_int;
use std::local_data;
use geom::point::Point2D;
use geom::size::Size2D;
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
use servo_msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState};

use glfw;

static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];

/// A structure responsible for setting up and tearing down the entire windowing system.
pub struct Application;

impl ApplicationMethods for Application {
    fn new() -> Application {
        // Per GLFW docs it's safe to set the error callback before calling
        // glfwInit(), and this way we notice errors from init too.
        do glfw::set_error_callback |_error_code, description| {
            error!("GLFW error: %s", description);
        };
        glfw::init();
        Application
    }
}

impl Drop for Application {
    fn drop(&self) {
        glfw::terminate();
        drop_local_window();
    }
}

/// The type of a window.
pub struct Window {
    glfw_window: glfw::Window,

    event_queue: @mut ~[WindowEvent],

    drag_origin: Point2D<c_int>,

    mouse_down_button: @mut c_int,
    mouse_down_point: @mut Point2D<c_int>,

    ready_state: ReadyState,
    render_state: RenderState,
    throbber_frame: u8,
}

impl WindowMethods<Application> for Window {
    /// Creates a new window.
    fn new(_: &Application) -> @mut Window {
        // Create the GLFW window.
        let glfw_window = glfw::Window::create(800, 600, "Servo", glfw::Windowed)
            .expect("Failed to create GLFW window");
        glfw_window.make_context_current();

        // Create our window object.
        let window = @mut Window {
            glfw_window: glfw_window,

            event_queue: @mut ~[],

            drag_origin: Point2D(0 as c_int, 0),

            mouse_down_button: @mut 0,
            mouse_down_point: @mut Point2D(0 as c_int, 0),

            ready_state: Blank,
            render_state: IdleRenderState,
            throbber_frame: 0,
        };

        install_local_window(window);

        // Register event handlers.
        do window.glfw_window.set_framebuffer_size_callback |_win, width, height| {
            local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint))
        }
        do window.glfw_window.set_key_callback |_win, key, _scancode, action, mods| {
            if action == glfw::PRESS {
                local_window().handle_key(key, mods)
            }
        }
        do window.glfw_window.set_mouse_button_callback |win, button, action, _mods| {
            let (x, y) = win.get_cursor_pos();
            //handle hidpi displays, since GLFW returns non-hi-def coordinates.
            let (backing_size, _) = win.get_framebuffer_size();
            let (window_size, _) = win.get_size();
            let hidpi = (backing_size as f32) / (window_size as f32);
            let x = x as f32 * hidpi;
            let y = y as f32 * hidpi;
            if button < 3 {
                local_window().handle_mouse(button, action, x as i32, y as i32);
            }
        }
        do window.glfw_window.set_scroll_callback |win, x_offset, y_offset| {
            let dx = (x_offset as f32) * 30.0;
            let dy = (y_offset as f32) * 30.0;

            let (x, y) = win.get_cursor_pos();
            //handle hidpi displays, since GLFW returns non-hi-def coordinates.
            let (backing_size, _) = win.get_framebuffer_size();
            let (window_size, _) = win.get_size();
            let hidpi = (backing_size as f32) / (window_size as f32);
            let x = x as f32 * hidpi;
            let y = y as f32 * hidpi;

            local_window().event_queue.push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32)));
        }

        window
    }

    /// Returns the size of the window.
    fn size(&self) -> Size2D<f32> {
        let (width, height) = self.glfw_window.get_framebuffer_size();
        Size2D(width as f32, height as f32)
    }

    /// Presents the window to the screen (perhaps by page flipping).
    fn present(&mut self) {
        self.glfw_window.swap_buffers();
    }

    fn recv(@mut self) -> WindowEvent {
        if !self.event_queue.is_empty() {
            return self.event_queue.shift()
        }
        glfw::poll_events();
        self.throbber_frame = (self.throbber_frame + 1) % (THROBBER.len() as u8);
        self.update_window_title(false);
        if self.glfw_window.should_close() {
            QuitWindowEvent
        } else if !self.event_queue.is_empty() {
            self.event_queue.shift()
        } else {
            IdleWindowEvent
        }
    }

    /// Sets the ready state.
    fn set_ready_state(@mut self, ready_state: ReadyState) {
        self.ready_state = ready_state;
        self.update_window_title(true)
    }

    /// Sets the render state.
    fn set_render_state(@mut self, render_state: RenderState) {
        if self.ready_state == FinishedLoading &&
            self.render_state == RenderingRenderState &&
            render_state == IdleRenderState {
            // page loaded
            self.event_queue.push(FinishedWindowEvent);
        }

        self.render_state = render_state;
        self.update_window_title(true)
    }

    fn hidpi_factor(@mut self) -> f32 {
        let (backing_size, _) = self.glfw_window.get_framebuffer_size();
        let (window_size, _) = self.glfw_window.get_size();
        (backing_size as f32) / (window_size as f32)
    }
}

impl Window {
    /// Helper function to set the window title in accordance with the ready state.
    fn update_window_title(&self, state_change: bool) {
        let throbber = THROBBER[self.throbber_frame];
        match self.ready_state {
            Blank => {
                if state_change { self.glfw_window.set_title(fmt!("blank — Servo")) }
            }
            Loading => {
                self.glfw_window.set_title(fmt!("%c Loading — Servo", throbber))
            }
            PerformingLayout => {
                self.glfw_window.set_title(fmt!("%c Performing Layout — Servo", throbber))
            }
            FinishedLoading => {
                match self.render_state {
                    RenderingRenderState => {
                        self.glfw_window.set_title(fmt!("%c Rendering — Servo", throbber))
                    }
                    IdleRenderState => {
                        if state_change { self.glfw_window.set_title("Servo") }
                    }
                }
            }
        }
    }

    /// Helper function to handle keyboard events.
    fn handle_key(&self, key: c_int, mods: glfw::KeyMods) {
        let mods = *mods;
        match key {
            glfw::KEY_ESCAPE => self.glfw_window.set_should_close(true),
            glfw::KEY_L if mods & glfw::MOD_CONTROL != 0 => self.load_url(), // Ctrl+L
            glfw::KEY_EQUAL if mods & glfw::MOD_CONTROL != 0 => { // Ctrl-+
                self.event_queue.push(ZoomWindowEvent(1.1));
            }
            glfw::KEY_MINUS if mods & glfw::MOD_CONTROL != 0 => { // Ctrl--
                self.event_queue.push(ZoomWindowEvent(0.90909090909));
            }
            glfw::KEY_BACKSPACE if mods & glfw::MOD_SHIFT != 0 => { // Shift-Backspace
                self.event_queue.push(NavigationWindowEvent(Forward));
            }
            glfw::KEY_BACKSPACE => { // Backspace
                self.event_queue.push(NavigationWindowEvent(Back));
            }
            _ => {}
        }
    }

    /// Helper function to handle a click
    fn handle_mouse(&self, button: c_int, action: c_int, x: c_int, y: c_int) {
        // FIXME(tkuehn): max pixel dist should be based on pixel density
        let max_pixel_dist = 10f;
        let event = match action {
            glfw::PRESS => {
                *self.mouse_down_point = Point2D(x, y);
                *self.mouse_down_button = button;
                MouseWindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32))
            }
            glfw::RELEASE => {
                if *self.mouse_down_button == button {
                    let pixel_dist = *self.mouse_down_point - Point2D(x, y);
                    let pixel_dist = ((pixel_dist.x * pixel_dist.x +
                                       pixel_dist.y * pixel_dist.y) as float).sqrt();
                    if pixel_dist < max_pixel_dist {
                        let click_event = MouseWindowClickEvent(button as uint,
                                                           Point2D(x as f32, y as f32));
                        self.event_queue.push(MouseWindowEventClass(click_event));
                    }
                }
                MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32))
            }
            _ => fail!("I cannot recognize the type of mouse action that occured. :-(")
        };
        self.event_queue.push(MouseWindowEventClass(event));
    }

    /// Helper function to pop up an alert box prompting the user to load a URL.
    fn load_url(&self) {
        let mut alert: Alert = AlertMethods::new("Navigate to:");
        alert.add_prompt();
        alert.run();
        let value = alert.prompt_value();
        if "" == value {    // To avoid crashing on Linux.
            self.event_queue.push(LoadUrlWindowEvent(~"http://purple.com/"))
        } else {
            self.event_queue.push(LoadUrlWindowEvent(value))
        }
    }
}

static TLS_KEY: local_data::Key<@mut Window> = &local_data::Key;

fn install_local_window(window: @mut Window) {
    local_data::set(TLS_KEY, window);
}

fn drop_local_window() {
    local_data::pop(TLS_KEY);
}

fn local_window() -> @mut Window {
    local_data::get(TLS_KEY, |v| *v.unwrap())
}
<commit_msg>We were removing the Window from TLS and thus destroying it after terminating the windowing system, which caused an error due to calling a glfw function when it was not inititalized.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A windowing implementation using GLFW.

use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use windowing::{Forward, Back};

use alert::{Alert, AlertMethods};
use std::libc::c_int;
use std::local_data;
use geom::point::Point2D;
use geom::size::Size2D;
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
use servo_msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState};

use glfw;

static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];

/// A structure responsible for setting up and tearing down the entire windowing system.
pub struct Application;

impl ApplicationMethods for Application {
    fn new() -> Application {
        // Per GLFW docs it's safe to set the error callback before calling
        // glfwInit(), and this way we notice errors from init too.
        do glfw::set_error_callback |_error_code, description| {
            error!("GLFW error: %s", description);
        };
        glfw::init();
        Application
    }
}

impl Drop for Application {
    fn drop(&self) {
        drop_local_window();
        glfw::terminate();
    }
}

/// The type of a window.
pub struct Window {
    glfw_window: glfw::Window,

    event_queue: @mut ~[WindowEvent],

    drag_origin: Point2D<c_int>,

    mouse_down_button: @mut c_int,
    mouse_down_point: @mut Point2D<c_int>,

    ready_state: ReadyState,
    render_state: RenderState,
    throbber_frame: u8,
}

impl WindowMethods<Application> for Window {
    /// Creates a new window.
    fn new(_: &Application) -> @mut Window {
        // Create the GLFW window.
        let glfw_window = glfw::Window::create(800, 600, "Servo", glfw::Windowed)
            .expect("Failed to create GLFW window");
        glfw_window.make_context_current();

        // Create our window object.
        let window = @mut Window {
            glfw_window: glfw_window,

            event_queue: @mut ~[],

            drag_origin: Point2D(0 as c_int, 0),

            mouse_down_button: @mut 0,
            mouse_down_point: @mut Point2D(0 as c_int, 0),

            ready_state: Blank,
            render_state: IdleRenderState,
            throbber_frame: 0,
        };

        install_local_window(window);

        // Register event handlers.
        do window.glfw_window.set_framebuffer_size_callback |_win, width, height| {
            local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint))
        }
        do window.glfw_window.set_key_callback |_win, key, _scancode, action, mods| {
            if action == glfw::PRESS {
                local_window().handle_key(key, mods)
            }
        }
        do window.glfw_window.set_mouse_button_callback |win, button, action, _mods| {
            let (x, y) = win.get_cursor_pos();
            //handle hidpi displays, since GLFW returns non-hi-def coordinates.
            let (backing_size, _) = win.get_framebuffer_size();
            let (window_size, _) = win.get_size();
            let hidpi = (backing_size as f32) / (window_size as f32);
            let x = x as f32 * hidpi;
            let y = y as f32 * hidpi;
            if button < 3 {
                local_window().handle_mouse(button, action, x as i32, y as i32);
            }
        }
        do window.glfw_window.set_scroll_callback |win, x_offset, y_offset| {
            let dx = (x_offset as f32) * 30.0;
            let dy = (y_offset as f32) * 30.0;

            let (x, y) = win.get_cursor_pos();
            //handle hidpi displays, since GLFW returns non-hi-def coordinates.
            let (backing_size, _) = win.get_framebuffer_size();
            let (window_size, _) = win.get_size();
            let hidpi = (backing_size as f32) / (window_size as f32);
            let x = x as f32 * hidpi;
            let y = y as f32 * hidpi;

            local_window().event_queue.push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32)));
        }

        window
    }

    /// Returns the size of the window.
    fn size(&self) -> Size2D<f32> {
        let (width, height) = self.glfw_window.get_framebuffer_size();
        Size2D(width as f32, height as f32)
    }

    /// Presents the window to the screen (perhaps by page flipping).
    fn present(&mut self) {
        self.glfw_window.swap_buffers();
    }

    fn recv(@mut self) -> WindowEvent {
        if !self.event_queue.is_empty() {
            return self.event_queue.shift()
        }
        glfw::poll_events();
        self.throbber_frame = (self.throbber_frame + 1) % (THROBBER.len() as u8);
        self.update_window_title(false);
        if self.glfw_window.should_close() {
            QuitWindowEvent
        } else if !self.event_queue.is_empty() {
            self.event_queue.shift()
        } else {
            IdleWindowEvent
        }
    }

    /// Sets the ready state.
    fn set_ready_state(@mut self, ready_state: ReadyState) {
        self.ready_state = ready_state;
        self.update_window_title(true)
    }

    /// Sets the render state.
    fn set_render_state(@mut self, render_state: RenderState) {
        if self.ready_state == FinishedLoading &&
            self.render_state == RenderingRenderState &&
            render_state == IdleRenderState {
            // page loaded
            self.event_queue.push(FinishedWindowEvent);
        }

        self.render_state = render_state;
        self.update_window_title(true)
    }

    fn hidpi_factor(@mut self) -> f32 {
        let (backing_size, _) = self.glfw_window.get_framebuffer_size();
        let (window_size, _) = self.glfw_window.get_size();
        (backing_size as f32) / (window_size as f32)
    }
}

impl Window {
    /// Helper function to set the window title in accordance with the ready state.
    fn update_window_title(&self, state_change: bool) {
        let throbber = THROBBER[self.throbber_frame];
        match self.ready_state {
            Blank => {
                if state_change { self.glfw_window.set_title(fmt!("blank — Servo")) }
            }
            Loading => {
                self.glfw_window.set_title(fmt!("%c Loading — Servo", throbber))
            }
            PerformingLayout => {
                self.glfw_window.set_title(fmt!("%c Performing Layout — Servo", throbber))
            }
            FinishedLoading => {
                match self.render_state {
                    RenderingRenderState => {
                        self.glfw_window.set_title(fmt!("%c Rendering — Servo", throbber))
                    }
                    IdleRenderState => {
                        if state_change { self.glfw_window.set_title("Servo") }
                    }
                }
            }
        }
    }

    /// Helper function to handle keyboard events.
    fn handle_key(&self, key: c_int, mods: glfw::KeyMods) {
        let mods = *mods;
        match key {
            glfw::KEY_ESCAPE => self.glfw_window.set_should_close(true),
            glfw::KEY_L if mods & glfw::MOD_CONTROL != 0 => self.load_url(), // Ctrl+L
            glfw::KEY_EQUAL if mods & glfw::MOD_CONTROL != 0 => { // Ctrl-+
                self.event_queue.push(ZoomWindowEvent(1.1));
            }
            glfw::KEY_MINUS if mods & glfw::MOD_CONTROL != 0 => { // Ctrl--
                self.event_queue.push(ZoomWindowEvent(0.90909090909));
            }
            glfw::KEY_BACKSPACE if mods & glfw::MOD_SHIFT != 0 => { // Shift-Backspace
                self.event_queue.push(NavigationWindowEvent(Forward));
            }
            glfw::KEY_BACKSPACE => { // Backspace
                self.event_queue.push(NavigationWindowEvent(Back));
            }
            _ => {}
        }
    }

    /// Helper function to handle a click
    fn handle_mouse(&self, button: c_int, action: c_int, x: c_int, y: c_int) {
        // FIXME(tkuehn): max pixel dist should be based on pixel density
        let max_pixel_dist = 10f;
        let event = match action {
            glfw::PRESS => {
                *self.mouse_down_point = Point2D(x, y);
                *self.mouse_down_button = button;
                MouseWindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32))
            }
            glfw::RELEASE => {
                if *self.mouse_down_button == button {
                    let pixel_dist = *self.mouse_down_point - Point2D(x, y);
                    let pixel_dist = ((pixel_dist.x * pixel_dist.x +
                                       pixel_dist.y * pixel_dist.y) as float).sqrt();
                    if pixel_dist < max_pixel_dist {
                        let click_event = MouseWindowClickEvent(button as uint,
                                                           Point2D(x as f32, y as f32));
                        self.event_queue.push(MouseWindowEventClass(click_event));
                    }
                }
                MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32))
            }
            _ => fail!("I cannot recognize the type of mouse action that occured. :-(")
        };
        self.event_queue.push(MouseWindowEventClass(event));
    }

    /// Helper function to pop up an alert box prompting the user to load a URL.
    fn load_url(&self) {
        let mut alert: Alert = AlertMethods::new("Navigate to:");
        alert.add_prompt();
        alert.run();
        let value = alert.prompt_value();
        if "" == value {    // To avoid crashing on Linux.
            self.event_queue.push(LoadUrlWindowEvent(~"http://purple.com/"))
        } else {
            self.event_queue.push(LoadUrlWindowEvent(value))
        }
    }
}

static TLS_KEY: local_data::Key<@mut Window> = &local_data::Key;

fn install_local_window(window: @mut Window) {
    local_data::set(TLS_KEY, window);
}

fn drop_local_window() {
    local_data::pop(TLS_KEY);
}

fn local_window() -> @mut Window {
    local_data::get(TLS_KEY, |v| *v.unwrap())
}
<|endoftext|>


<commit_before>use egui::{ComboBox, Grid, Ui};
use gba::memory::io;
use std::collections::HashMap;

use crate::GbaData;

#[derive(Default)]
pub struct IoRegistersPane {
    register: IoRegisters,
    value: Option<u32>,
    track_value: bool,
    ioreg_display: HashMap<IoRegisters, String>,
}

impl IoRegistersPane {
    pub(crate) fn render(&mut self, ui: &mut Ui, data: &mut GbaData) {
        if let Some(value) = data.ioreg.take() {
            self.value = Some(value);
        }

        ComboBox::from_label("IO Register")
            .selected_text(&self.ioreg_display[&self.register])
            .show_ui(ui, |ui| {
                for &register in IoRegisters::ALL {
                    ui.selectable_value(
                        &mut self.register,
                        register,
                        &self.ioreg_display[&register],
                    );
                }
            });

        if let Some(value) = self.value {
            let render_reg = self.register.render_function();
            (render_reg)(value, ui);

            if self.track_value {
                data.requests.ioreg = Some(self.register.address());
            }
        } else {
            ui.label("Waiting for value...");
            data.requests.ioreg = Some(self.register.address());
        }
    }

    pub(crate) fn init(&mut self) {
        self.track_value = true;
        self.ioreg_display
            .extend(IoRegisters::ALL.iter().map(|&reg| {
                let addr = reg.address();
                let short_name = reg.short_name();
                let long_name = reg.long_name();
                let text = format!("[0x{addr:08X}] {short_name} - {long_name}",);
                (reg, text)
            }));
    }
}

macro_rules! io_registers {
    (
        $( [$Address:expr, $Width:expr, $EnumName:ident, $ShortName:expr, $LongName:expr, $RenderFn:expr] ),+ $(,)?
    ) => {
        #[derive(Copy, Clone, Hash, PartialEq, Eq)]
        pub enum IoRegisters {
            $($EnumName),+
        }

        impl IoRegisters {
            const ALL: &'static [IoRegisters] = &[
                $(Self::$EnumName),+
            ];

            fn long_name(&self) -> &'static str {
                match self {
                    $( Self::$EnumName => $LongName ),+
                }
            }

            fn short_name(&self) -> &'static str {
                match self {
                    $( Self::$EnumName => $ShortName ),+
                }
            }

            fn address(&self) -> u32 {
                match self {
                    $( Self::$EnumName => $Address ),+
                }
            }

            fn render_function(&self) -> fn(u32, &mut Ui) {
                match self {
                    $( Self::$EnumName => $RenderFn ),+
                }
            }
        }
    };
}

io_registers! {
    [io::DISPCNT, 2, Dispcnt, "DISPCNT", "LCD Control", render_dispcnt],
    [io::DISPSTAT, 2, Dispstat, "DISPSTAT", "LCD Status", render_dispstat],
}

impl Default for IoRegisters {
    fn default() -> Self {
        IoRegisters::Dispcnt
    }
}

#[allow(dead_code)]
fn render_u16(value: u32, ui: &mut Ui) {
    ui.horizontal(|ui| {
        let value = value as u16;
        ui.label("Value");
        ui.label(format!("{value:04X}"));
    });
}

#[allow(dead_code)]
fn render_u32(value: u32, ui: &mut Ui) {
    ui.horizontal(|ui| {
        let lo = value as u16;
        let hi = (value >> 16) as u16;

        ui.label("Value");
        ui.label(format!("{hi:04X} {lo:04X}"));
    });
}

fn render_dispcnt(value: u32, ui: &mut Ui) {
    use io::{LCDControl, ObjCharVramMapping};

    let value = value as u16;
    let dispcnt = LCDControl::new(value);

    Grid::new("DISPCNT values").show(ui, |ui| {
        ui.label("Value");
        ui.label(format!("{value:04X}"));
        ui.end_row();

        ui.label("Mode");
        ui.label(dispcnt.bg_mode().to_string());
        ui.end_row();

        ui.label("CGB Mode");
        ui.label(dispcnt.cgb_mode().to_string());
        ui.end_row();

        ui.label("Frame Select");
        ui.label(dispcnt.frame().to_string());
        ui.end_row();

        ui.label("H-Blank Interval Free");
        ui.label(dispcnt.hblank_interval_free().to_string());
        ui.end_row();

        ui.label("OBJ Character VRAM Mapping");
        ui.label(
            if dispcnt.obj_char_vram_mapping() == ObjCharVramMapping::OneDimensional {
                "One Dimensional"
            } else {
                "Two Dimensional"
            },
        );
        ui.end_row();

        ui.label("Forced Blank");
        ui.label(dispcnt.forced_blank().to_string());
        ui.end_row();

        for bg in 0..3 {
            ui.label(format!("Display BG{bg}"));
            ui.label(dispcnt.display_bg(bg).to_string());
            ui.end_row();
        }

        ui.label("Display OBJ");
        ui.label(dispcnt.display_obj().to_string());
        ui.end_row();

        ui.label("Window 0 Display");
        ui.label(dispcnt.win0_display().to_string());
        ui.end_row();

        ui.label("Window 1 Display");
        ui.label(dispcnt.win1_display().to_string());
        ui.end_row();

        ui.label("OBJ Window Display");
        ui.label(dispcnt.obj_window_display().to_string());
        ui.end_row();
    });
}

fn render_dispstat(value: u32, ui: &mut Ui) {
    use gba::memory::io::LCDStatus;

    let value = value as u16;
    let dispstat = LCDStatus::new(value);

    Grid::new("DISPSTAT values").show(ui, |ui| {
        ui.label("Value");
        ui.label(format!("{value:04X}"));
        ui.end_row();

        ui.label("V-Blank Flag");
        ui.label(dispstat.vblank().to_string());
        ui.end_row();

        ui.label("H-Blank Flag");
        ui.label(dispstat.hblank().to_string());
        ui.end_row();

        ui.label("V-Counter Flag");
        ui.label(dispstat.vcounter_match().to_string());
        ui.end_row();

        ui.label("H-Blank IRQ");
        ui.label(enabled(dispstat.hblank_irq_enable()));
        ui.end_row();

        ui.label("V-Blank IRQ");
        ui.label(enabled(dispstat.vblank_irq_enable()));
        ui.end_row();

        ui.label("V-Counter IRQ");
        ui.label(enabled(dispstat.vcounter_irq_enable()));
        ui.end_row();

        ui.label("V-Counter Setting");
        ui.label(dispstat.vcount_setting().to_string());
        ui.end_row();
    });
}

fn enabled(b: bool) -> &'static str {
    if b {
        "Enabled"
    } else {
        "Disabled"
    }
}
<commit_msg>Add BGCNT to debugger IO register view.<commit_after>use egui::{ComboBox, Grid, Ui};
use gba::memory::io;
use std::collections::HashMap;

use crate::GbaData;

#[derive(Default)]
pub struct IoRegistersPane {
    register: IoRegisters,
    value: Option<u32>,
    track_value: bool,
    ioreg_display: HashMap<IoRegisters, String>,
}

impl IoRegistersPane {
    pub(crate) fn render(&mut self, ui: &mut Ui, data: &mut GbaData) {
        if let Some(value) = data.ioreg.take() {
            self.value = Some(value);
        }

        let mut request_new_reg = false;
        ComboBox::from_label("IO Register")
            .selected_text(&self.ioreg_display[&self.register])
            .show_ui(ui, |ui| {
                for &register in IoRegisters::ALL {
                    let response = ui.selectable_value(
                        &mut self.register,
                        register,
                        &self.ioreg_display[&register],
                    );
                    request_new_reg |= response.changed();
                }
            });

        if request_new_reg {
            self.value = None;
        }

        if let Some(value) = self.value {
            let render_reg = self.register.render_function();
            (render_reg)(value, ui);

            if self.track_value {
                data.requests.ioreg = Some(self.register.address());
            }
        } else {
            ui.label("Waiting for value...");
            data.requests.ioreg = Some(self.register.address());
        }
    }

    pub(crate) fn init(&mut self) {
        self.track_value = true;
        self.ioreg_display
            .extend(IoRegisters::ALL.iter().map(|&reg| {
                let addr = reg.address();
                let short_name = reg.short_name();
                let long_name = reg.long_name();
                let text = format!("[0x{addr:08X}] {short_name} - {long_name}",);
                (reg, text)
            }));
    }
}

macro_rules! io_registers {
    (
        $( [$Address:expr, $Width:expr, $EnumName:ident, $ShortName:expr, $LongName:expr, $RenderFn:expr] ),+ $(,)?
    ) => {
        #[derive(Copy, Clone, Hash, PartialEq, Eq)]
        pub enum IoRegisters {
            $($EnumName),+
        }

        impl IoRegisters {
            const ALL: &'static [IoRegisters] = &[
                $(Self::$EnumName),+
            ];

            fn long_name(&self) -> &'static str {
                match self {
                    $( Self::$EnumName => $LongName ),+
                }
            }

            fn short_name(&self) -> &'static str {
                match self {
                    $( Self::$EnumName => $ShortName ),+
                }
            }

            fn address(&self) -> u32 {
                match self {
                    $( Self::$EnumName => $Address ),+
                }
            }

            fn render_function(&self) -> fn(u32, &mut Ui) {
                match self {
                    $( Self::$EnumName => $RenderFn ),+
                }
            }
        }
    };
}

io_registers! {
    [io::DISPCNT, 2, Dispcnt, "DISPCNT", "LCD Control", render_dispcnt],
    [io::DISPSTAT, 2, Dispstat, "DISPSTAT", "LCD Status", render_dispstat],
    [io::VCOUNT, 2, Vcount, "VCOUNT", "Vertical Counter", render_u16],
    [io::BG0CNT, 2, Bg0cnt, "BG0CNT", "BG0 Control", render_bgcnt],
    [io::BG1CNT, 2, Bg1cnt, "BG1CNT", "BG1 Control", render_bgcnt],
    [io::BG2CNT, 2, Bg2cnt, "BG2CNT", "BG2 Control", render_bgcnt],
    [io::BG3CNT, 2, Bg3cnt, "BG3CNT", "BG3 Control", render_bgcnt],
}

impl Default for IoRegisters {
    fn default() -> Self {
        IoRegisters::Dispcnt
    }
}

#[allow(dead_code)]
fn render_u16(value: u32, ui: &mut Ui) {
    ui.horizontal(|ui| {
        let value = value as u16;
        ui.label("Value");
        ui.label(format!("{value:04X}"));
    });
}

#[allow(dead_code)]
fn render_u32(value: u32, ui: &mut Ui) {
    ui.horizontal(|ui| {
        let lo = value as u16;
        let hi = (value >> 16) as u16;

        ui.label("Value");
        ui.label(format!("{hi:04X} {lo:04X}"));
    });
}

fn render_dispcnt(value: u32, ui: &mut Ui) {
    use io::{LCDControl, ObjCharVramMapping};

    let value = value as u16;
    let dispcnt = LCDControl::new(value);

    Grid::new("DISPCNT values").show(ui, |ui| {
        ui.label("Value");
        ui.label(format!("{value:04X}"));
        ui.end_row();

        ui.label("Mode");
        ui.label(dispcnt.bg_mode().to_string());
        ui.end_row();

        ui.label("CGB Mode");
        ui.label(dispcnt.cgb_mode().to_string());
        ui.end_row();

        ui.label("Frame Select");
        ui.label(dispcnt.frame().to_string());
        ui.end_row();

        ui.label("H-Blank Interval Free");
        ui.label(dispcnt.hblank_interval_free().to_string());
        ui.end_row();

        ui.label("OBJ Character VRAM Mapping");
        ui.label(
            if dispcnt.obj_char_vram_mapping() == ObjCharVramMapping::OneDimensional {
                "One Dimensional"
            } else {
                "Two Dimensional"
            },
        );
        ui.end_row();

        ui.label("Forced Blank");
        ui.label(dispcnt.forced_blank().to_string());
        ui.end_row();

        for bg in 0..3 {
            ui.label(format!("Display BG{bg}"));
            ui.label(dispcnt.display_bg(bg).to_string());
            ui.end_row();
        }

        ui.label("Display OBJ");
        ui.label(dispcnt.display_obj().to_string());
        ui.end_row();

        ui.label("Window 0 Display");
        ui.label(dispcnt.win0_display().to_string());
        ui.end_row();

        ui.label("Window 1 Display");
        ui.label(dispcnt.win1_display().to_string());
        ui.end_row();

        ui.label("OBJ Window Display");
        ui.label(dispcnt.obj_window_display().to_string());
        ui.end_row();
    });
}

fn render_dispstat(value: u32, ui: &mut Ui) {
    use gba::memory::io::LCDStatus;

    let value = value as u16;
    let dispstat = LCDStatus::new(value);

    Grid::new("DISPSTAT values").show(ui, |ui| {
        ui.label("Value");
        ui.label(format!("{value:04X}"));
        ui.end_row();

        ui.label("V-Blank Flag");
        ui.label(dispstat.vblank().to_string());
        ui.end_row();

        ui.label("H-Blank Flag");
        ui.label(dispstat.hblank().to_string());
        ui.end_row();

        ui.label("V-Counter Flag");
        ui.label(dispstat.vcounter_match().to_string());
        ui.end_row();

        ui.label("H-Blank IRQ");
        ui.label(enabled(dispstat.hblank_irq_enable()));
        ui.end_row();

        ui.label("V-Blank IRQ");
        ui.label(enabled(dispstat.vblank_irq_enable()));
        ui.end_row();

        ui.label("V-Counter IRQ");
        ui.label(enabled(dispstat.vcounter_irq_enable()));
        ui.end_row();

        ui.label("V-Counter Setting");
        ui.label(dispstat.vcount_setting().to_string());
        ui.end_row();
    });
}

fn render_bgcnt(value: u32, ui: &mut Ui) {
    use gba::memory::io::BgControl;

    let value = value as u16;
    let bgcnt = BgControl::new(value);

    Grid::new("BGCNT values").show(ui, |ui| {
        ui.label("Value");
        ui.label(format!("{value:04X}"));
        ui.end_row();

        ui.label("Priority");
        ui.label(bgcnt.priority().to_string());
        ui.end_row();

        ui.label("Character Base");
        ui.label(format!("+0x{:04X}", bgcnt.character_base()));
        ui.end_row();

        ui.label("Mosaic");
        ui.label(enabled(bgcnt.mosaic()));
        ui.end_row();

        ui.label("Palettes");
        ui.label(if bgcnt.palette_256() {
            "256/1"
        } else {
            "16/16"
        });
        ui.end_row();

        ui.label("Screen Base");
        ui.label(format!("+0x{:04X}", bgcnt.screen_base()));
        ui.end_row();

        let size = bgcnt.screen_size();
        ui.label("Screen Size");
        ui.label(format!(
            "{}x{} / {}x{} (rotscale)",
            size.width(false),
            size.height(false),
            size.width(true),
            size.height(false)
        ));
        ui.end_row();
    });
}

fn enabled(b: bool) -> &'static str {
    if b {
        "Enabled"
    } else {
        "Disabled"
    }
}
<|endoftext|>


<commit_before>use super::super::error::Result;
use lazy_static::lazy_static;
use regex::Regex;
use std::fs;
use tree_sitter::Point;

// TODO: It would be cooler to do this with a comments query rather than with a regex
// directly.
lazy_static! {
    static ref METADATA_PAIR_REGEX: Regex = Regex::new(r#"(\w+): ([^\s,]+)"#).unwrap();
    static ref NUMBER_REGEX: Regex = Regex::new(r#"\d+"#).unwrap();
}

pub struct CaptureInfo {
    pub name: String,
}

#[derive(Debug, Eq, PartialEq)]
struct Assertion {
    position: Point,
    line_numbers: Vec<usize>,
    capture_type: String,
}

pub fn assert_expected_captures(_captures: Vec<CaptureInfo>, path: String) -> Result<()> {
    let contents = fs::read_to_string(path)?;
    for m in METADATA_PAIR_REGEX.captures_iter(&contents) {
        println!("pair: {:?}", m);
    }
    Ok(())
}
<commit_msg>parse assertions from regex capture<commit_after>use super::super::error::Result;
use lazy_static::lazy_static;
use regex::Regex;
use std::fs;
use tree_sitter::Point;

// TODO: It would be cooler to do this with a comments query rather than with a regex
// directly.
lazy_static! {
    static ref METADATA_REGEX: Regex = Regex::new(r#"(\w+): ([^\s,]+), (\d+), (\d+)"#).unwrap();
}

pub struct CaptureInfo {
    pub name: String,
}

#[derive(Debug, Eq, PartialEq)]
struct Assertion {
    position: Point,
    capture_class: String,
    capture_type: String,
}

impl From<regex::Captures<'_>> for Assertion {
    fn from(re: regex::Captures) -> Assertion {
        Assertion {
            capture_class: re.get(1).unwrap().as_str().to_string(),
            capture_type: re.get(2).unwrap().as_str().to_string(),
            position: Point {
                row: re
                    .get(3)
                    .iter()
                    .flat_map(|m| m.as_str().parse::<usize>())
                    .next()
                    .unwrap(),
                column: re
                    .get(4)
                    .iter()
                    .flat_map(|m| m.as_str().parse::<usize>())
                    .next()
                    .unwrap(),
            },
        }
    }
}

pub fn assert_expected_captures(_captures: Vec<CaptureInfo>, path: String) -> Result<()> {
    let contents = fs::read_to_string(path)?;

    let assertions: Vec<Assertion> = METADATA_REGEX
        .captures_iter(&contents)
        .map(|c| Assertion::from(c))
        .collect();

    for a in assertions {
        println!("a: {:?}", a);
    }

    Ok(())
}
<|endoftext|>