<commit_before>extern crate dbus;

use std;
use std::env;
use general::*;
use device::DeviceType;
use manager::NetworkManager;

/// Get a list of Network Manager connections sorted by path.
///
/// # Examples
///
/// ```no_run
/// use network_manager::connection;
/// use network_manager::manager::NetworkManager;
/// let manager = NetworkManager::new();
/// let connections = connection::list(&manager).unwrap();
/// println!("{:?}", connections);
/// ```
pub fn list(manager: &NetworkManager) -> Result<Vec<Connection>, String> {
    let paths = try!(manager.list_connections());

    let mut connections = Vec::new();

    for path in &paths {
        connections.push(try!(get_connection(&manager, path)))
    }

    connections.sort();

    Ok(connections)
}

#[test]
fn test_list_function() {
    let manager = NetworkManager::new();

    let connections = list(&manager).unwrap();
    assert!(connections.len() > 0);

    for (index, val) in connections.iter().enumerate() {
        assert_ne!(Connection { ..Default::default() }, val.clone());
        assert_eq!(index as i32, i32::from(val));
    }
}

/// Creates a Network Manager connection.
///
/// # Examples
///
/// ```
/// let connection = network_manager::connection::create(
///     "resin_io",
///     network_manager::device::DeviceType::WiFi,
///     network_manager::general::Security::WPA2,
///     "super_secret_passphase"
///     ).unwrap();
/// println!("{:?}", connection);
/// ```
pub fn create(s: &str, dt: DeviceType, sc: Security, p: &str) -> Result<Connection, String> {
    // Create a connection
    // Get the connection
    // Return the connection

    let settings = ConnectionSettings {
        id: "resin_io".to_string(),
        uuid: "3c8e6e8b-b895-4b07-97a5-bbc192c3b436".to_string(),
        ssid: "resin_io".to_string(),
    };

    let connection1 = Connection {
        path: "/org/freedesktop/NetworkManager/ActiveConnection/187".to_string(),
        active_path: "test".to_string(),
        settings: settings,
        state: ConnectionState::Deactivated, /* device: "wlp4s0".to_string(),
                                              * interface: DeviceType::WiFi,
                                              * security: Security::WPA2,
                                              * state: ConnectionState::Activated, */
    };

    Ok(connection1)
}

/// Deletes a Network Manager connection.
///
/// # Examples
///
/// ```
/// use network_manager::connection;
/// use network_manager::manager::NetworkManager;
/// let manager = NetworkManager::new();
/// let mut connections = connection::list(&manager).unwrap();
/// connection::delete(connections.pop().unwrap()).unwrap();
/// ```
pub fn delete(connection: Connection) -> Result<(), String> {
    let message = dbus_message!(NM_SERVICE_MANAGER,
                                connection.path,
                                NM_CONNECTION_INTERFACE,
                                "Delete");
    dbus_connect!(message);

    Ok(())
}

/// Enables a Network Manager connection.
///
/// # Examples
///
/// ```no_run
/// use network_manager::connection;
/// use network_manager::manager::NetworkManager;
/// let manager = NetworkManager::new();
/// let connections = connection::list(&manager).unwrap();
/// let mut connection = connections[0].clone();
/// connection::enable(&manager, &mut connection, 10).unwrap();
/// println!("{:?}", connection.state);
/// ```
pub fn enable(manager: &NetworkManager,
              connection: &mut Connection,
              time_out: i32)
              -> Result<(), String> {
    match connection.state {
        ConnectionState::Activated => Ok(()),
        ConnectionState::Activating => {
            wait(manager, connection, time_out, ConnectionState::Activated)
        }
        ConnectionState::Unknown => Err("Unable to get connection state".to_string()),
        _ => {
            let mut message = dbus_message!(NM_SERVICE_MANAGER,
                                            NM_SERVICE_PATH,
                                            NM_SERVICE_INTERFACE,
                                            "ActivateConnection");
            message.append_items(&[dbus::MessageItem::ObjectPath(connection
                                                                     .path
                                                                     .to_string()
                                                                     .into()),
                                   dbus::MessageItem::ObjectPath("/".into()),
                                   dbus::MessageItem::ObjectPath("/".into())]);
            dbus_connect!(message);

            wait(manager, connection, time_out, ConnectionState::Activated)
        }
    }
}

/// Disables a Network Manager connection.
///
/// # Examples
///
/// ```no_run
/// use network_manager::connection;
/// use network_manager::manager::NetworkManager;
/// let manager = NetworkManager::new();
/// let connections = connection::list(&manager).unwrap();
/// let mut connection = connections[0].clone();
/// connection::disable(&manager, &mut connection, 10).unwrap();
/// println!("{:?}", connection.state);
/// ```
pub fn disable(manager: &NetworkManager,
               connection: &mut Connection,
               time_out: i32)
               -> Result<(), String> {
    match connection.state {
        ConnectionState::Deactivated => Ok(()),
        ConnectionState::Deactivating => {
            wait(manager, connection, time_out, ConnectionState::Deactivated)
        }
        ConnectionState::Unknown => Err("Unable to get connection state".to_string()),
        _ => {
            let mut message = dbus_message!(NM_SERVICE_MANAGER,
                                            NM_SERVICE_PATH,
                                            NM_SERVICE_INTERFACE,
                                            "DeactivateConnection");
            message.append_items(&[dbus::MessageItem::ObjectPath(connection
                                                                     .active_path
                                                                     .to_string()
                                                                     .into())]);
            dbus_connect!(message);

            wait(manager, connection, time_out, ConnectionState::Deactivated)
        }
    }
}

#[test]
fn test_enable_disable_functions() {
    let manager = NetworkManager::new();

    let connections = list(&manager).unwrap();
    let mut connection;

    // set enviorment variable $TEST_WIFI_SSID with the wifi's SSID that you want to test
    // e.g.  export TEST_WIFI_SSID="Resin.io Wifi"
    let wifiEnvVar = "TEST_WIFI_SSID";
    match env::var(wifiEnvVar) {
        Ok(ssid) => {
            connection = connections
                .iter()
                .filter(|c| c.settings.ssid == ssid)
                .nth(0)
                .unwrap()
                .clone()
        }
        Err(e) => {
            panic!("couldn't retrieve enviorment variable {}: {}",
                   wifiEnvVar,
                   e)
        }
    };

    if connection.state == ConnectionState::Activated {
        disable(&manager, &mut connection, 10).unwrap();
        assert_eq!(ConnectionState::Deactivated, connection.state);

        enable(&manager, &mut connection, 10).unwrap();
        assert_eq!(ConnectionState::Activated, connection.state);
    } else {
        enable(&manager, &mut connection, 10).unwrap();
        assert_eq!(ConnectionState::Activated, connection.state);

        disable(&manager, &mut connection, 10).unwrap();
        assert_eq!(ConnectionState::Deactivated, connection.state);
    }
}

fn get_connection(manager: &NetworkManager, path: &String) -> Result<Connection, String> {
    let mut connection = Connection::default();

    connection.path = path.clone();

    connection.settings = try!(manager.get_connection_settings(path));

    try!(update_state(manager, &mut connection));

    Ok(connection)
}

fn update_state(manager: &NetworkManager, connection: &mut Connection) -> Result<(), String> {
    let active_paths = try!(manager.get_active_connections());

    let mut settings_paths = Vec::new();

    for active_path in &active_paths {
        if let Some(settings_path) = manager.get_active_connection_path(&active_path) {
            settings_paths.push(settings_path)
        }
    }

    // TODO: Consider using Option<String> instead for deactivated connections
    connection.active_path = "".to_string();
    connection.state = ConnectionState::Deactivated;

    for (active_path, settings_path) in active_paths.iter().zip(settings_paths.iter()) {
        if connection.path == *settings_path {

            connection.active_path = active_path.clone();
            connection.state = try!(manager.get_connection_state(&active_path));

            break;
        }
    }

    Ok(())
}

fn wait(manager: &NetworkManager,
        connection: &mut Connection,
        time_out: i32,
        target_state: ConnectionState)
        -> Result<(), String> {
    if time_out == 0 {
        return Ok(());
    }

    let mut total_time = 0;

    while total_time < time_out {
        try!(update_state(manager, connection));

        if connection.state == target_state {
            return Ok(());
        }

        std::thread::sleep(std::time::Duration::from_secs(1));

        total_time += 1;
    }

    Err("service timed out".to_string())
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Connection {
    pub path: String,
    pub active_path: String,
    pub settings: ConnectionSettings,
    pub state: ConnectionState, /* device: String,
                                 * device_type: DeviceType,
                                 * security: Security, */
}

impl Default for Connection {
    fn default() -> Connection {
        Connection {
            path: "".to_string(),
            active_path: "".to_string(),
            settings: ConnectionSettings::default(),
            state: ConnectionState::Unknown,
        }
    }
}

impl Ord for Connection {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        i32::from(self).cmp(&i32::from(other))
    }
}

impl PartialOrd for Connection {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a> From<&'a Connection> for i32 {
    fn from(val: &Connection) -> i32 {
        val.clone()
            .path
            .rsplit('/')
            .nth(0)
            .unwrap()
            .parse::<i32>()
            .unwrap()
    }
}

#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct ConnectionSettings {
    pub id: String,
    pub uuid: String,
    pub ssid: String,
}
<commit_msg>Removing failing assert in connection::list on deleted connection<commit_after>extern crate dbus;

use std;
use std::env;
use general::*;
use device::DeviceType;
use manager::NetworkManager;

/// Get a list of Network Manager connections sorted by path.
///
/// # Examples
///
/// ```no_run
/// use network_manager::connection;
/// use network_manager::manager::NetworkManager;
/// let manager = NetworkManager::new();
/// let connections = connection::list(&manager).unwrap();
/// println!("{:?}", connections);
/// ```
pub fn list(manager: &NetworkManager) -> Result<Vec<Connection>, String> {
    let paths = try!(manager.list_connections());

    let mut connections = Vec::new();

    for path in &paths {
        connections.push(try!(get_connection(&manager, path)))
    }

    connections.sort();

    Ok(connections)
}

#[test]
fn test_list_function() {
    let manager = NetworkManager::new();

    let connections = list(&manager).unwrap();
    assert!(connections.len() > 0);

    for (index, val) in connections.iter().enumerate() {
        assert_ne!(Connection { ..Default::default() }, val.clone());
    }
}

/// Creates a Network Manager connection.
///
/// # Examples
///
/// ```
/// let connection = network_manager::connection::create(
///     "resin_io",
///     network_manager::device::DeviceType::WiFi,
///     network_manager::general::Security::WPA2,
///     "super_secret_passphase"
///     ).unwrap();
/// println!("{:?}", connection);
/// ```
pub fn create(s: &str, dt: DeviceType, sc: Security, p: &str) -> Result<Connection, String> {
    // Create a connection
    // Get the connection
    // Return the connection

    let settings = ConnectionSettings {
        id: "resin_io".to_string(),
        uuid: "3c8e6e8b-b895-4b07-97a5-bbc192c3b436".to_string(),
        ssid: "resin_io".to_string(),
    };

    let connection1 = Connection {
        path: "/org/freedesktop/NetworkManager/ActiveConnection/187".to_string(),
        active_path: "test".to_string(),
        settings: settings,
        state: ConnectionState::Deactivated, /* device: "wlp4s0".to_string(),
                                              * interface: DeviceType::WiFi,
                                              * security: Security::WPA2,
                                              * state: ConnectionState::Activated, */
    };

    Ok(connection1)
}

/// Deletes a Network Manager connection.
///
/// # Examples
///
/// ```
/// use network_manager::connection;
/// use network_manager::manager::NetworkManager;
/// let manager = NetworkManager::new();
/// let mut connections = connection::list(&manager).unwrap();
/// connection::delete(connections.pop().unwrap()).unwrap();
/// ```
pub fn delete(connection: Connection) -> Result<(), String> {
    let message = dbus_message!(NM_SERVICE_MANAGER,
                                connection.path,
                                NM_CONNECTION_INTERFACE,
                                "Delete");
    dbus_connect!(message);

    Ok(())
}

/// Enables a Network Manager connection.
///
/// # Examples
///
/// ```no_run
/// use network_manager::connection;
/// use network_manager::manager::NetworkManager;
/// let manager = NetworkManager::new();
/// let connections = connection::list(&manager).unwrap();
/// let mut connection = connections[0].clone();
/// connection::enable(&manager, &mut connection, 10).unwrap();
/// println!("{:?}", connection.state);
/// ```
pub fn enable(manager: &NetworkManager,
              connection: &mut Connection,
              time_out: i32)
              -> Result<(), String> {
    match connection.state {
        ConnectionState::Activated => Ok(()),
        ConnectionState::Activating => {
            wait(manager, connection, time_out, ConnectionState::Activated)
        }
        ConnectionState::Unknown => Err("Unable to get connection state".to_string()),
        _ => {
            let mut message = dbus_message!(NM_SERVICE_MANAGER,
                                            NM_SERVICE_PATH,
                                            NM_SERVICE_INTERFACE,
                                            "ActivateConnection");
            message.append_items(&[dbus::MessageItem::ObjectPath(connection
                                                                     .path
                                                                     .to_string()
                                                                     .into()),
                                   dbus::MessageItem::ObjectPath("/".into()),
                                   dbus::MessageItem::ObjectPath("/".into())]);
            dbus_connect!(message);

            wait(manager, connection, time_out, ConnectionState::Activated)
        }
    }
}

/// Disables a Network Manager connection.
///
/// # Examples
///
/// ```no_run
/// use network_manager::connection;
/// use network_manager::manager::NetworkManager;
/// let manager = NetworkManager::new();
/// let connections = connection::list(&manager).unwrap();
/// let mut connection = connections[0].clone();
/// connection::disable(&manager, &mut connection, 10).unwrap();
/// println!("{:?}", connection.state);
/// ```
pub fn disable(manager: &NetworkManager,
               connection: &mut Connection,
               time_out: i32)
               -> Result<(), String> {
    match connection.state {
        ConnectionState::Deactivated => Ok(()),
        ConnectionState::Deactivating => {
            wait(manager, connection, time_out, ConnectionState::Deactivated)
        }
        ConnectionState::Unknown => Err("Unable to get connection state".to_string()),
        _ => {
            let mut message = dbus_message!(NM_SERVICE_MANAGER,
                                            NM_SERVICE_PATH,
                                            NM_SERVICE_INTERFACE,
                                            "DeactivateConnection");
            message.append_items(&[dbus::MessageItem::ObjectPath(connection
                                                                     .active_path
                                                                     .to_string()
                                                                     .into())]);
            dbus_connect!(message);

            wait(manager, connection, time_out, ConnectionState::Deactivated)
        }
    }
}

#[test]
fn test_enable_disable_functions() {
    let manager = NetworkManager::new();

    let connections = list(&manager).unwrap();
    let mut connection;

    // set enviorment variable $TEST_WIFI_SSID with the wifi's SSID that you want to test
    // e.g.  export TEST_WIFI_SSID="Resin.io Wifi"
    let wifiEnvVar = "TEST_WIFI_SSID";
    match env::var(wifiEnvVar) {
        Ok(ssid) => {
            connection = connections
                .iter()
                .filter(|c| c.settings.ssid == ssid)
                .nth(0)
                .unwrap()
                .clone()
        }
        Err(e) => {
            panic!("couldn't retrieve enviorment variable {}: {}",
                   wifiEnvVar,
                   e)
        }
    };

    if connection.state == ConnectionState::Activated {
        disable(&manager, &mut connection, 10).unwrap();
        assert_eq!(ConnectionState::Deactivated, connection.state);

        enable(&manager, &mut connection, 10).unwrap();
        assert_eq!(ConnectionState::Activated, connection.state);
    } else {
        enable(&manager, &mut connection, 10).unwrap();
        assert_eq!(ConnectionState::Activated, connection.state);

        disable(&manager, &mut connection, 10).unwrap();
        assert_eq!(ConnectionState::Deactivated, connection.state);
    }
}

fn get_connection(manager: &NetworkManager, path: &String) -> Result<Connection, String> {
    let mut connection = Connection::default();

    connection.path = path.clone();

    connection.settings = try!(manager.get_connection_settings(path));

    try!(update_state(manager, &mut connection));

    Ok(connection)
}

fn update_state(manager: &NetworkManager, connection: &mut Connection) -> Result<(), String> {
    let active_paths = try!(manager.get_active_connections());

    let mut settings_paths = Vec::new();

    for active_path in &active_paths {
        if let Some(settings_path) = manager.get_active_connection_path(&active_path) {
            settings_paths.push(settings_path)
        }
    }

    // TODO: Consider using Option<String> instead for deactivated connections
    connection.active_path = "".to_string();
    connection.state = ConnectionState::Deactivated;

    for (active_path, settings_path) in active_paths.iter().zip(settings_paths.iter()) {
        if connection.path == *settings_path {

            connection.active_path = active_path.clone();
            connection.state = try!(manager.get_connection_state(&active_path));

            break;
        }
    }

    Ok(())
}

fn wait(manager: &NetworkManager,
        connection: &mut Connection,
        time_out: i32,
        target_state: ConnectionState)
        -> Result<(), String> {
    if time_out == 0 {
        return Ok(());
    }

    let mut total_time = 0;

    while total_time < time_out {
        try!(update_state(manager, connection));

        if connection.state == target_state {
            return Ok(());
        }

        std::thread::sleep(std::time::Duration::from_secs(1));

        total_time += 1;
    }

    Err("service timed out".to_string())
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Connection {
    pub path: String,
    pub active_path: String,
    pub settings: ConnectionSettings,
    pub state: ConnectionState, /* device: String,
                                 * device_type: DeviceType,
                                 * security: Security, */
}

impl Default for Connection {
    fn default() -> Connection {
        Connection {
            path: "".to_string(),
            active_path: "".to_string(),
            settings: ConnectionSettings::default(),
            state: ConnectionState::Unknown,
        }
    }
}

impl Ord for Connection {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        i32::from(self).cmp(&i32::from(other))
    }
}

impl PartialOrd for Connection {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a> From<&'a Connection> for i32 {
    fn from(val: &Connection) -> i32 {
        val.clone()
            .path
            .rsplit('/')
            .nth(0)
            .unwrap()
            .parse::<i32>()
            .unwrap()
    }
}

#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct ConnectionSettings {
    pub id: String,
    pub uuid: String,
    pub ssid: String,
}
<|endoftext|>


<commit_before>extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::hashmap::HashMap;
use std;

use gl::types::*;

use cgmath::vector::Vector;
use cgmath::vector::Vec3;
use cgmath::vector::Vec4;

use noise::Perlin;

use CHUNK_SIZE;
use WORLD_SIZE;
use GraphicsResources;

static MAX_CHUNKS : uint = 32;

pub struct ChunkLoader<'a> {
    seed : u32,
    graphics_resources : &'a GraphicsResources,
    cache : HashMap<(i64, i64), ~Chunk>
}

impl<'a> ChunkLoader<'a> {
    pub fn new<'a>(seed : u32, graphics_resources : &'a GraphicsResources) -> ChunkLoader<'a> {
        ChunkLoader {
            seed: seed,
            graphics_resources : graphics_resources,
            cache: HashMap::new(),
        }
    }

    pub fn load(&mut self, cx : i64, cz: i64) {
        println!("loading chunk ({}, {})", cx, cz);
        let chunk = chunk_gen(self.graphics_resources, self.seed, cx, cz);
        self.cache.insert((cx, cz), chunk);

        while self.cache.len() > MAX_CHUNKS {
            let (&k, _) = self.cache.iter().min_by(|&(_, chunk)| chunk.used_time).unwrap();
            self.cache.remove(&k);
        }
    }
}

pub struct Chunk {
    x: i64,
    z: i64,
    map: ~Map,
    vao: GLuint,
    vertex_buffer: GLuint,
    normal_buffer: GLuint,
    element_buffer: GLuint,
    num_elements: uint,
    used_time: u64,
}

impl Chunk {
    pub fn touch(&mut self) {
        self.used_time = extra::time::precise_time_ns();
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        unsafe {
            println!("unloading chunk ({}, {})", self.x, self.z);
            gl::DeleteBuffers(1, &self.vertex_buffer);
            gl::DeleteBuffers(1, &self.normal_buffer);
            gl::DeleteBuffers(1, &self.element_buffer);
            gl::DeleteVertexArrays(1, &self.vao);
        }
    }
}

struct Block {
    visible: bool,
}

struct Map {
    blocks: [[[Block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
}

struct Face {
    normal: Vec3<f32>,
    vertices: [Vec3<f32>, ..4],
}

pub fn chunk_gen(res: &GraphicsResources, seed: u32, chunk_x: i64, chunk_z: i64) -> ~Chunk {
    let def_block = Block { visible: false };
    let mut map = ~Map {
        blocks: [[[def_block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
    };

    let block_exists = |x: int, y: int, z: int| -> bool {
        if x < 0 || x >= CHUNK_SIZE as int || y < 0 || y >= CHUNK_SIZE as int || z < 0 || z >= CHUNK_SIZE as int {
            return false;
        }

        map.blocks[x][y][z].visible
    };

    let start_time = extra::time::precise_time_ns();

    let perlin = Perlin::from_seed([seed as uint]);

    for block_x in range(0, CHUNK_SIZE) {
        for block_z in range(0, CHUNK_SIZE) {
            let noise = perlin.gen([
                (chunk_x + block_x as i64) as f64 * 0.1,
                (chunk_z + block_z as i64) as f64 * 0.1
            ]);
            let height = ((noise + 1.0) * (CHUNK_SIZE as f64 / 8.0)) as uint;
            for y in range(0, height) {
                map.blocks[block_x][y][block_z] = Block { visible: true };
            }
        }
    }

    let after_noise_time = extra::time::precise_time_ns();

    let mut vertices : ~[Vec3<f32>] = ~[];
    let mut normals : ~[Vec3<f32>] = ~[];
    let mut elements : ~[GLuint] = ~[];

    let mut idx = 0;

    for x in range(0, CHUNK_SIZE) {
        for y in range(0, CHUNK_SIZE) {
            for z in range(0, CHUNK_SIZE) {
                let block = &map.blocks[x][y][z];

                if (!block.visible) {
                    continue;
                }

                let block_position = Vec3 { x: x as f32, y: y as f32, z: z as f32 };

                for face in faces.iter() {
                    let neighbor_position = block_position.add_v(&face.normal);
                    if block_exists(neighbor_position.x as int, neighbor_position.y as int, neighbor_position.z as int) {
                        continue;
                    }

                    for v in face.vertices.iter() {
                        vertices.push(v.add_v(&block_position));
                        normals.push(face.normal);
                    }

                    for e in face_elements.iter() {
                        elements.push((idx * face.vertices.len()) as GLuint + *e);
                    }

                    idx += 1;
                }
            }
        }
    }

    let after_mesh_time = extra::time::precise_time_ns();

    let mut vao = 0;
    let mut vertex_buffer = 0;
    let mut normal_buffer = 0;
    let mut element_buffer = 0;

    unsafe {
        // Create Vertex Array Object
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vertex_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (vertices.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&vertices[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the normal data to it
        gl::GenBuffers(1, &mut normal_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (normals.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&normals[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the element data to it
        gl::GenBuffers(1, &mut element_buffer);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, element_buffer);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                        (elements.len() * std::mem::size_of::<GLuint>()) as GLsizeiptr,
                        cast::transmute(&elements[0]),
                        gl::STATIC_DRAW);

        // Specify the layout of the vertex data
        let vert_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
        assert!(vert_attr as u32 != gl::INVALID_VALUE);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::EnableVertexAttribArray(vert_attr as GLuint);
        gl::VertexAttribPointer(vert_attr as GLuint, 3, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());

        let normal_attr = "normal".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
        assert!(normal_attr as u32 != gl::INVALID_VALUE);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::EnableVertexAttribArray(normal_attr as GLuint);
        gl::VertexAttribPointer(normal_attr as GLuint, 3, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());
    }

    gl::BindVertexArray(0);

    let after_buffer_time = extra::time::precise_time_ns();

    println!("chunk loading profile (us): noise={} mesh={} buffer={}",
             (after_noise_time - start_time)/1000,
             (after_mesh_time - after_noise_time)/1000,
             (after_buffer_time - after_mesh_time)/1000)

    return ~Chunk {
        x: chunk_x,
        z: chunk_z,
        map: map,
        vao: vao,
        vertex_buffer: vertex_buffer,
        normal_buffer: normal_buffer,
        element_buffer: element_buffer,
        num_elements: elements.len(),
        used_time: extra::time::precise_time_ns(),
    };
}

static face_elements : [GLuint, ..6] = [
    0, 1, 2, 3, 2, 1,
];

static faces : [Face, ..6] = [
    /* front */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 },  /* bottom right */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 },  /* top right */
        ],
    },

    /* back */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom right */
            Vec3 { x: 0.0, y: 0.0, z: 0.0 },  /* bottom left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 },  /* top left */
        ],
    },

    /* right */
    Face {
        normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* top front */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top back */
        ],
    },

    /* left */
    Face {
        normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* top back */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top front */
        ],
    },

    /* top */
    Face {
        normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* front right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* back right */
        ],
    },

    /* bottom */
    Face {
        normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* back right */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* front right */
        ],
    },
];
<commit_msg>reserve large vectors for meshing<commit_after>extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::hashmap::HashMap;
use std;

use gl::types::*;

use cgmath::vector::Vector;
use cgmath::vector::Vec3;
use cgmath::vector::Vec4;

use noise::Perlin;

use CHUNK_SIZE;
use WORLD_SIZE;
use GraphicsResources;

static MAX_CHUNKS : uint = 32;

pub struct ChunkLoader<'a> {
    seed : u32,
    graphics_resources : &'a GraphicsResources,
    cache : HashMap<(i64, i64), ~Chunk>
}

impl<'a> ChunkLoader<'a> {
    pub fn new<'a>(seed : u32, graphics_resources : &'a GraphicsResources) -> ChunkLoader<'a> {
        ChunkLoader {
            seed: seed,
            graphics_resources : graphics_resources,
            cache: HashMap::new(),
        }
    }

    pub fn load(&mut self, cx : i64, cz: i64) {
        println!("loading chunk ({}, {})", cx, cz);
        let chunk = chunk_gen(self.graphics_resources, self.seed, cx, cz);
        self.cache.insert((cx, cz), chunk);

        while self.cache.len() > MAX_CHUNKS {
            let (&k, _) = self.cache.iter().min_by(|&(_, chunk)| chunk.used_time).unwrap();
            self.cache.remove(&k);
        }
    }
}

pub struct Chunk {
    x: i64,
    z: i64,
    map: ~Map,
    vao: GLuint,
    vertex_buffer: GLuint,
    normal_buffer: GLuint,
    element_buffer: GLuint,
    num_elements: uint,
    used_time: u64,
}

impl Chunk {
    pub fn touch(&mut self) {
        self.used_time = extra::time::precise_time_ns();
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        unsafe {
            println!("unloading chunk ({}, {})", self.x, self.z);
            gl::DeleteBuffers(1, &self.vertex_buffer);
            gl::DeleteBuffers(1, &self.normal_buffer);
            gl::DeleteBuffers(1, &self.element_buffer);
            gl::DeleteVertexArrays(1, &self.vao);
        }
    }
}

struct Block {
    visible: bool,
}

struct Map {
    blocks: [[[Block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
}

struct Face {
    normal: Vec3<f32>,
    vertices: [Vec3<f32>, ..4],
}

pub fn chunk_gen(res: &GraphicsResources, seed: u32, chunk_x: i64, chunk_z: i64) -> ~Chunk {
    let def_block = Block { visible: false };
    let mut map = ~Map {
        blocks: [[[def_block, ..CHUNK_SIZE], ..CHUNK_SIZE], ..CHUNK_SIZE],
    };

    let block_exists = |x: int, y: int, z: int| -> bool {
        if x < 0 || x >= CHUNK_SIZE as int || y < 0 || y >= CHUNK_SIZE as int || z < 0 || z >= CHUNK_SIZE as int {
            return false;
        }

        map.blocks[x][y][z].visible
    };

    let start_time = extra::time::precise_time_ns();

    let perlin = Perlin::from_seed([seed as uint]);

    for block_x in range(0, CHUNK_SIZE) {
        for block_z in range(0, CHUNK_SIZE) {
            let noise = perlin.gen([
                (chunk_x + block_x as i64) as f64 * 0.1,
                (chunk_z + block_z as i64) as f64 * 0.1
            ]);
            let height = ((noise + 1.0) * (CHUNK_SIZE as f64 / 8.0)) as uint;
            for y in range(0, height) {
                map.blocks[block_x][y][block_z] = Block { visible: true };
            }
        }
    }

    let after_noise_time = extra::time::precise_time_ns();

    let mut vertices : ~[Vec3<f32>] = ~[];
    let mut normals : ~[Vec3<f32>] = ~[];
    let mut elements : ~[GLuint] = ~[];

    static expected_vertices : uint = 70000;
    static expected_elements : uint = expected_vertices * 3 / 2;
    vertices.reserve(expected_vertices);
    normals.reserve(expected_vertices);
    elements.reserve(expected_elements);

    let mut idx = 0;

    for x in range(0, CHUNK_SIZE) {
        for y in range(0, CHUNK_SIZE) {
            for z in range(0, CHUNK_SIZE) {
                let block = &map.blocks[x][y][z];

                if (!block.visible) {
                    continue;
                }

                let block_position = Vec3 { x: x as f32, y: y as f32, z: z as f32 };

                for face in faces.iter() {
                    let neighbor_position = block_position.add_v(&face.normal);
                    if block_exists(neighbor_position.x as int, neighbor_position.y as int, neighbor_position.z as int) {
                        continue;
                    }

                    for v in face.vertices.iter() {
                        vertices.push(v.add_v(&block_position));
                        normals.push(face.normal);
                    }

                    for e in face_elements.iter() {
                        elements.push((idx * face.vertices.len()) as GLuint + *e);
                    }

                    idx += 1;
                }
            }
        }
    }

    let after_mesh_time = extra::time::precise_time_ns();

    let mut vao = 0;
    let mut vertex_buffer = 0;
    let mut normal_buffer = 0;
    let mut element_buffer = 0;

    unsafe {
        // Create Vertex Array Object
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vertex_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (vertices.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&vertices[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the normal data to it
        gl::GenBuffers(1, &mut normal_buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::BufferData(gl::ARRAY_BUFFER,
                        (normals.len() * std::mem::size_of::<Vec3<f32>>()) as GLsizeiptr,
                        cast::transmute(&normals[0]),
                        gl::STATIC_DRAW);

        // Create a Vertex Buffer Object and copy the element data to it
        gl::GenBuffers(1, &mut element_buffer);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, element_buffer);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                        (elements.len() * std::mem::size_of::<GLuint>()) as GLsizeiptr,
                        cast::transmute(&elements[0]),
                        gl::STATIC_DRAW);

        // Specify the layout of the vertex data
        let vert_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
        assert!(vert_attr as u32 != gl::INVALID_VALUE);
        gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
        gl::EnableVertexAttribArray(vert_attr as GLuint);
        gl::VertexAttribPointer(vert_attr as GLuint, 3, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());

        let normal_attr = "normal".with_c_str(|ptr| gl::GetAttribLocation(res.program, ptr));
        assert!(normal_attr as u32 != gl::INVALID_VALUE);
        gl::BindBuffer(gl::ARRAY_BUFFER, normal_buffer);
        gl::EnableVertexAttribArray(normal_attr as GLuint);
        gl::VertexAttribPointer(normal_attr as GLuint, 3, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());
    }

    gl::BindVertexArray(0);

    let after_buffer_time = extra::time::precise_time_ns();

    println!("chunk load: noise={}us mesh={}us buffer={}us num_vertices={} num_elements={}",
             (after_noise_time - start_time)/1000,
             (after_mesh_time - after_noise_time)/1000,
             (after_buffer_time - after_mesh_time)/1000,
             vertices.len(), elements.len())

    return ~Chunk {
        x: chunk_x,
        z: chunk_z,
        map: map,
        vao: vao,
        vertex_buffer: vertex_buffer,
        normal_buffer: normal_buffer,
        element_buffer: element_buffer,
        num_elements: elements.len(),
        used_time: extra::time::precise_time_ns(),
    };
}

static face_elements : [GLuint, ..6] = [
    0, 1, 2, 3, 2, 1,
];

static faces : [Face, ..6] = [
    /* front */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: 1.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 },  /* bottom right */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 },  /* top right */
        ],
    },

    /* back */
    Face {
        normal: Vec3 { x: 0.0, y: 0.0, z: -1.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom right */
            Vec3 { x: 0.0, y: 0.0, z: 0.0 },  /* bottom left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 },  /* top left */
        ],
    },

    /* right */
    Face {
        normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* top front */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* top back */
        ],
    },

    /* left */
    Face {
        normal: Vec3 { x: -1.0, y: 0.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* bottom back */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* bottom front */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* top back */
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* top front */
        ],
    },

    /* top */
    Face {
        normal: Vec3 { x: 0.0, y: 1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 1.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 1.0, z: 1.0 }, /* front right */
            Vec3 { x: 0.0, y: 1.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 1.0, z: 0.0 }, /* back right */
        ],
    },

    /* bottom */
    Face {
        normal: Vec3 { x: 0.0, y: -1.0, z: 0.0 },
        vertices: [
            Vec3 { x: 0.0, y: 0.0, z: 0.0 }, /* back left */
            Vec3 { x: 1.0, y: 0.0, z: 0.0 }, /* back right */
            Vec3 { x: 0.0, y: 0.0, z: 1.0 }, /* front left */
            Vec3 { x: 1.0, y: 0.0, z: 1.0 }, /* front right */
        ],
    },
];
<|endoftext|>


<commit_before>mod scan;
mod util;

use alloc::vec::Vec;
use spin::Mutex;

const CONFIG_ADDR: usize = 0xCF8;
const CONFIG_DATA: usize = 0xCFC;

struct CapabilityHeader {}

/// Bus, device, function
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DeviceLocation(pub u8, pub u8, pub u8);

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DeviceClass(pub u8, pub u8, pub u8);

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Device {
    pub id: u16,
    pub vendor: u16,
    pub location: DeviceLocation,
    pub class: DeviceClass,
}
impl Device {
    fn new(id: u16, vendor: u16, location: DeviceLocation, class: DeviceClass) -> Device {
        Device {
            id,
            vendor,
            location,
            class,
        }
    }

    pub unsafe fn read(&self, offset: u8) -> u32 {
        util::pci_read_device(self.location, offset)
    }

    pub unsafe fn write(&self, offset: u8, value: u32) {
        util::pci_write_device(self.location, offset, value)
    }

    pub unsafe fn read_u16(&self, offset: u8) -> u16 {
        assert!(offset & 1 == 0, "Must align at u16 boundary");
        let data = util::pci_read_device(self.location, offset & !0b11);
        ((data >> (offset as u32 & 0b1)) & 0xffff) as u16
    }

    pub unsafe fn read_u8(&self, offset: u8) -> u8 {
        let data = util::pci_read_device(self.location, offset & !0b11);
        ((data >> (8 * (offset as u32 & 0b11))) & 0xff) as u8
    }

    pub fn status(&self) -> u16 {
        (unsafe { self.read(0x04) } >> 16) as u16
    }

    /// Read the linked list of capabilities, filter by type
    /// http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-740004
    pub fn read_capabilities<T>(&self, cap_type: u8, f: &dyn Fn(&Self, u8) -> T) -> Vec<T> {
        assert!((self.status() & (1 << 4)) != 0, "Capabilities not availble");
        let mut cap_addr = (unsafe { self.read(0x34) } & 0b1111_1100) as u8;

        let mut result = Vec::new();
        while cap_addr != 0 {
            unsafe {
                let item_type = self.read_u8(cap_addr);
                let item_size = self.read_u8(cap_addr + 2);

                if item_type == cap_type {
                    result.push(f(&self, cap_addr));
                }

                cap_addr = self.read_u8(cap_addr + 1);
            }
        }
        result
    }

    pub fn subsystem_id(&self) -> u16 {
        (unsafe { self.read(0x2c) } >> 16) as u16
    }

    pub fn get_bar(&self, i: u8) -> u32 {
        assert!(i < 6);
        unsafe { self.read(0x10 + 4 * i) }
    }

    // http://wiki.osdev.org/RTL8139#PCI_Bus_Mastering
    pub unsafe fn enable_bus_mastering(&self) {
        self.write(0x04, self.read(0x04) | (1 << 2));
    }
}

pub struct PCIController {
    devices: Option<Vec<Device>>,
}
impl PCIController {
    const fn new() -> PCIController {
        PCIController { devices: None }
    }

    fn init(&mut self) {
        self.devices = Some(scan::check_all_busses());
    }

    fn print(&self) {
        assert!(self.devices.is_some(), "PCI is not initialized");
        for dev in self.devices.clone().unwrap() {
            rprintln!("/ {:x}:{:x}", dev.vendor, dev.id);
            rprintln!("\\ {:x} {:x} {:x}", dev.class.0, dev.class.1, dev.class.2);
        }
    }

    pub fn find<P>(&self, pred: P) -> Option<Device>
    where P: Fn(Device) -> bool {
        for dev in self.devices.clone().unwrap() {
            if pred(dev) {
                return Some(dev);
            }
        }
        None
    }
}

pub static PCI: Mutex<PCIController> = Mutex::new(PCIController::new());

pub fn init() {
    PCI.lock().init();
    // PCI.lock().print();
    rprintln!("PCI: enabled");
}
<commit_msg>Add pci::Device::get_interrupt_line function<commit_after>mod scan;
mod util;

use alloc::vec::Vec;
use spin::Mutex;

const CONFIG_ADDR: usize = 0xCF8;
const CONFIG_DATA: usize = 0xCFC;

struct CapabilityHeader {}

/// Bus, device, function
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DeviceLocation(pub u8, pub u8, pub u8);

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DeviceClass(pub u8, pub u8, pub u8);

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Device {
    pub id: u16,
    pub vendor: u16,
    pub location: DeviceLocation,
    pub class: DeviceClass,
}
impl Device {
    fn new(id: u16, vendor: u16, location: DeviceLocation, class: DeviceClass) -> Device {
        Device {
            id,
            vendor,
            location,
            class,
        }
    }

    pub unsafe fn read(&self, offset: u8) -> u32 {
        util::pci_read_device(self.location, offset)
    }

    pub unsafe fn write(&self, offset: u8, value: u32) {
        util::pci_write_device(self.location, offset, value)
    }

    pub unsafe fn read_u16(&self, offset: u8) -> u16 {
        assert!(offset & 1 == 0, "Must align at u16 boundary");
        let data = util::pci_read_device(self.location, offset & !0b11);
        ((data >> (offset as u32 & 0b1)) & 0xffff) as u16
    }

    pub unsafe fn read_u8(&self, offset: u8) -> u8 {
        let data = util::pci_read_device(self.location, offset & !0b11);
        ((data >> (8 * (offset as u32 & 0b11))) & 0xff) as u8
    }

    pub fn status(&self) -> u16 {
        (unsafe { self.read(0x04) } >> 16) as u16
    }

    /// Read the linked list of capabilities, filter by type
    /// http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-740004
    pub fn read_capabilities<T>(&self, cap_type: u8, f: &dyn Fn(&Self, u8) -> T) -> Vec<T> {
        assert!((self.status() & (1 << 4)) != 0, "Capabilities not availble");
        let mut cap_addr = (unsafe { self.read(0x34) } & 0b1111_1100) as u8;

        let mut result = Vec::new();
        while cap_addr != 0 {
            unsafe {
                let item_type = self.read_u8(cap_addr);
                let item_size = self.read_u8(cap_addr + 2);

                if item_type == cap_type {
                    result.push(f(&self, cap_addr));
                }

                cap_addr = self.read_u8(cap_addr + 1);
            }
        }
        result
    }

    pub fn subsystem_id(&self) -> u16 {
        (unsafe { self.read(0x2c) } >> 16) as u16
    }

    pub fn get_bar(&self, i: u8) -> u32 {
        assert!(i < 6);
        unsafe { self.read(0x10 + 4 * i) }
    }

    // https://wiki.osdev.org/PCI#PCI_Device_Structure
    // Under "Interrupt Line"
    pub fn get_interrupt_line(&self) -> Option<u8> {
        let line = unsafe { self.read_u8(0x3c) };
        if line == 0xff {
            // No connection
            None
        } else {
            Some(line)
        }
    }

    // http://wiki.osdev.org/RTL8139#PCI_Bus_Mastering
    pub unsafe fn enable_bus_mastering(&self) {
        self.write(0x04, self.read(0x04) | (1 << 2));
    }
}

pub struct PCIController {
    devices: Option<Vec<Device>>,
}
impl PCIController {
    const fn new() -> PCIController {
        PCIController { devices: None }
    }

    fn init(&mut self) {
        self.devices = Some(scan::check_all_busses());
    }

    fn print(&self) {
        assert!(self.devices.is_some(), "PCI is not initialized");
        for dev in self.devices.clone().unwrap() {
            rprintln!("/ {:x}:{:x}", dev.vendor, dev.id);
            rprintln!("\\ {:x} {:x} {:x}", dev.class.0, dev.class.1, dev.class.2);
        }
    }

    pub fn find<P>(&self, pred: P) -> Option<Device>
    where P: Fn(Device) -> bool {
        for dev in self.devices.clone().unwrap() {
            if pred(dev) {
                return Some(dev);
            }
        }
        None
    }
}

pub static PCI: Mutex<PCIController> = Mutex::new(PCIController::new());

pub fn init() {
    PCI.lock().init();
    // PCI.lock().print();
    rprintln!("PCI: enabled");
}
<|endoftext|>


<commit_before>use core::prelude::*;
use hil::{Driver,Callback};
use hil::i2c::I2C;
use hil::timer::*;

#[allow(dead_code)]
enum Registers {
    SensorVoltage = 0x00,
    LocalTemperature = 0x01,
    Configuration = 0x02,
    ManufacturerID = 0xFE,
    DeviceID = 0xFF
}

pub struct TMP006<I: I2C + 'static> {
    i2c: &'static mut I,
    timer: TimerMux,
    timer_request: Option<&'static mut TimerRequest>,
    callback: Option<Callback>
}

impl<I: I2C> TMP006<I> {
    pub fn new(i2c: &'static mut I, timer: TimerMux,
               timer_request: &'static mut TimerRequest)
            -> TMP006<I> {
        TMP006{i2c: i2c, timer: timer, timer_request: Some(timer_request), callback: None}
    }

    pub fn foo(&mut self) {
    }
}

impl<I: I2C> TimerCB for TMP006<I> {
    fn fired(&mut self, _: &'static mut TimerRequest, _: u32) {
        let mut buf: [u8; 3] = [0; 3];
        let mut config: u16;

        // Start by enabling the sensor
        config = 0x7 << 12;
        buf[0] = Registers::Configuration as u8;
        buf[1] = ((config & 0xFF00) >> 8) as u8;
        buf[2] = (config & 0x00FF) as u8;
        self.i2c.write_sync(0x40, &buf);

        // Wait for ready bit in control register
        loop {
            self.i2c.read_sync(0x40, &mut buf[0..2]);
            if buf[1] & 0x80 == 0x80 {
                break;
            }
        }

        // Now set the correct register pointer value so we can issue a read
        // to the sensor voltage register
        buf[0] = Registers::SensorVoltage as u8;
        self.i2c.write_sync(0x40, &buf[0..1]);

        // Now read the sensor reading
        self.i2c.read_sync(0x40, &mut buf[0..2]);
        //let sensor_voltage = (((buf[0] as u16) << 8) | buf[1] as u16) as i16;

        // Now move the register pointer to the die temp register
        buf[0] = Registers::LocalTemperature as u8;
        self.i2c.write_sync(0x40, &buf[0..1]);

        // Now read the 14bit die temp
        self.i2c.read_sync(0x40, &mut buf[0..2]);
        let die_temp = (((buf[0] as u16) << 8) | buf[1] as u16) as i16;

        // Shift to the right to make it 14 bits (this should be a signed shift)
        // The die temp is is in 1/32 degrees C.
        self.callback.as_mut().map(|cb| {
            cb.schedule((die_temp >> 2) as usize, 0, 0);
        });
    }
}

impl<I: I2C> Driver for TMP006<I> {
    fn subscribe(&'static mut self, subscribe_num: usize, mut callback: Callback) -> isize {
        match subscribe_num {
            0 /* read temperature  */ => {
                let mut buf: [u8; 3] = [0; 3];
                let mut config: u16;

                self.i2c.enable();
                self.callback = Some(callback);
                self.timer.repeat(32768, self.timer_request.take().unwrap());
                0
            },
            _ => -1
        }
    }

    fn command(&mut self, cmd_num: usize, _: usize) -> isize {
        match cmd_num {
            0 /* Enable sensor  */ => {
                let mut buf: [u8; 3] = [0; 3];
                let mut config: u16;

                self.i2c.enable();

                // Start by enabling the sensor
                config = 0x7 << 12;
                buf[0] = Registers::Configuration as u8;
                buf[1] = ((config & 0xFF00) >> 8) as u8;
                buf[2] = (config & 0x00FF) as u8;
                self.i2c.write_sync(0x40, &buf);

                0
            },
            _ => -1
        }
    }
}

<commit_msg>Psych, the request doesn't need to be in an Option<commit_after>use core::prelude::*;
use hil::{Driver,Callback};
use hil::i2c::I2C;
use hil::timer::*;

#[allow(dead_code)]
enum Registers {
    SensorVoltage = 0x00,
    LocalTemperature = 0x01,
    Configuration = 0x02,
    ManufacturerID = 0xFE,
    DeviceID = 0xFF
}

pub struct TMP006<I: I2C + 'static> {
    i2c: &'static mut I,
    timer: TimerMux,
    timer_request: &'static mut TimerRequest,
    callback: Option<Callback>
}

impl<I: I2C> TMP006<I> {
    pub fn new(i2c: &'static mut I, timer: TimerMux,
               timer_request: &'static mut TimerRequest)
            -> TMP006<I> {
        TMP006{i2c: i2c, timer: timer, timer_request: timer_request, callback: None}
    }

    pub fn foo(&mut self) {
    }
}

impl<I: I2C> TimerCB for TMP006<I> {
    fn fired(&mut self, _: &'static mut TimerRequest, _: u32) {
        let mut buf: [u8; 3] = [0; 3];
        let mut config: u16;

        // Start by enabling the sensor
        config = 0x7 << 12;
        buf[0] = Registers::Configuration as u8;
        buf[1] = ((config & 0xFF00) >> 8) as u8;
        buf[2] = (config & 0x00FF) as u8;
        self.i2c.write_sync(0x40, &buf);

        // Wait for ready bit in control register
        loop {
            self.i2c.read_sync(0x40, &mut buf[0..2]);
            if buf[1] & 0x80 == 0x80 {
                break;
            }
        }

        // Now set the correct register pointer value so we can issue a read
        // to the sensor voltage register
        buf[0] = Registers::SensorVoltage as u8;
        self.i2c.write_sync(0x40, &buf[0..1]);

        // Now read the sensor reading
        self.i2c.read_sync(0x40, &mut buf[0..2]);
        //let sensor_voltage = (((buf[0] as u16) << 8) | buf[1] as u16) as i16;

        // Now move the register pointer to the die temp register
        buf[0] = Registers::LocalTemperature as u8;
        self.i2c.write_sync(0x40, &buf[0..1]);

        // Now read the 14bit die temp
        self.i2c.read_sync(0x40, &mut buf[0..2]);
        let die_temp = (((buf[0] as u16) << 8) | buf[1] as u16) as i16;

        // Shift to the right to make it 14 bits (this should be a signed shift)
        // The die temp is is in 1/32 degrees C.
        self.callback.as_mut().map(|cb| {
            cb.schedule((die_temp >> 2) as usize, 0, 0);
        });
    }
}

impl<I: I2C> Driver for TMP006<I> {
    fn subscribe(&'static mut self, subscribe_num: usize, mut callback: Callback) -> isize {
        match subscribe_num {
            0 /* read temperature  */ => {
                let mut buf: [u8; 3] = [0; 3];
                let mut config: u16;

                self.i2c.enable();
                self.callback = Some(callback);
                self.timer.repeat(32768, self.timer_request);
                0
            },
            _ => -1
        }
    }

    fn command(&mut self, cmd_num: usize, _: usize) -> isize {
        match cmd_num {
            0 /* Enable sensor  */ => {
                let mut buf: [u8; 3] = [0; 3];
                let mut config: u16;

                self.i2c.enable();

                // Start by enabling the sensor
                config = 0x7 << 12;
                buf[0] = Registers::Configuration as u8;
                buf[1] = ((config & 0xFF00) >> 8) as u8;
                buf[2] = (config & 0x00FF) as u8;
                self.i2c.write_sync(0x40, &buf);

                0
            },
            _ => -1
        }
    }
}

<|endoftext|>


<commit_before>use std::fmt::{Show,Formatter};
use std::fmt;
use std::hash::Hasher;
use std::hash::sip::SipHasher;
use std::str;

use core::source::{Source, SourceId, GitKind, Location, Remote, Local};
use core::{Package,PackageId,Summary};
use util::{CargoResult, Config, to_hex};
use sources::PathSource;
use sources::git::utils::{GitReference,GitRemote,Master,Other};

/* TODO: Refactor GitSource to delegate to a PathSource
 */
pub struct GitSource<'a, 'b> {
    remote: GitRemote,
    reference: GitReference,
    db_path: Path,
    checkout_path: Path,
    path_source: PathSource,
    config: &'a mut Config<'b>
}

impl<'a, 'b> GitSource<'a, 'b> {
    pub fn new<'a, 'b>(source_id: &SourceId, config: &'a mut Config<'b>) -> GitSource<'a, 'b> {
        assert!(source_id.is_git(), "id is not git, id={}", source_id);

        let reference = match source_id.kind {
            GitKind(ref reference) => reference,
            _ => fail!("Not a git source; id={}", source_id)
        };

        let remote = GitRemote::new(source_id.get_location());
        let ident = ident(source_id.get_location());

        let db_path = config.git_db_path()
            .join(ident.as_slice());

        let checkout_path = config.git_checkout_path()
            .join(ident.as_slice()).join(reference.as_slice());

        let path_source = PathSource::new(&checkout_path, source_id);

        GitSource {
            remote: remote,
            reference: GitReference::for_str(reference.as_slice()),
            db_path: db_path,
            checkout_path: checkout_path,
            path_source: path_source,
            config: config
        }
    }

    pub fn get_namespace<'a>(&'a self) -> &'a Location {
        self.remote.get_location()
    }
}

fn ident(location: &Location) -> String {
    let hasher = SipHasher::new_with_keys(0,0);

    // FIXME: this really should be able to not use to_str() everywhere, but the
    //        compiler seems to currently ask for static lifetimes spuriously.
    //        Perhaps related to rust-lang/rust#15144
    let ident = match *location {
        Local(ref path) => {
            let last = path.components().last().unwrap();
            str::from_utf8(last).unwrap().to_str()
        }
        Remote(ref url) => url.path.as_slice().split('/').last().unwrap().to_str()
    };

    let ident = if ident.as_slice() == "" {
        "_empty".to_string()
    } else {
        ident
    };

    format!("{}-{}", ident, to_hex(hasher.hash(&location.to_str())))
}

impl<'a, 'b> Show for GitSource<'a, 'b> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "git repo at {}", self.remote.get_location()));

        match self.reference {
            Master => Ok(()),
            Other(ref reference) => write!(f, " ({})", reference)
        }
    }
}

impl<'a, 'b> Source for GitSource<'a, 'b> {
    fn update(&mut self) -> CargoResult<()> {
        let should_update = self.config.update_remotes() || {
            !self.remote.has_ref(&self.db_path, self.reference.as_slice()).is_ok()
        };

        let repo = if should_update {
            try!(self.config.shell().status("Updating",
                format!("git repository `{}`", self.remote.get_location())));

            log!(5, "updating git source `{}`", self.remote);
            try!(self.remote.checkout(&self.db_path))
        } else {
            self.remote.db_at(&self.db_path)
        };

        try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path));

        self.path_source.update()
    }

    fn list(&self) -> CargoResult<Vec<Summary>> {
        self.path_source.list()
    }

    fn download(&self, _: &[PackageId]) -> CargoResult<()> {
        // TODO: assert! that the PackageId is contained by the source
        Ok(())
    }

    fn get(&self, ids: &[PackageId]) -> CargoResult<Vec<Package>> {
        log!(5, "getting packages for package ids `{}` from `{}`", ids, self.remote);
        self.path_source.get(ids)
    }

    fn fingerprint(&self, _pkg: &Package) -> CargoResult<String> {
        let db = self.remote.db_at(&self.db_path);
        db.rev_for(self.reference.as_slice())
    }
}

#[cfg(test)]
mod test {
    use url;
    use url::Url;
    use core::source::Remote;
    use super::ident;

    #[test]
    pub fn test_url_to_path_ident_with_path() {
        let ident = ident(&Remote(url("https://github.com/carlhuda/cargo")));
        assert_eq!(ident.as_slice(), "cargo-0eed735c8ffd7c88");
    }

    #[test]
    pub fn test_url_to_path_ident_without_path() {
        let ident = ident(&Remote(url("https://github.com")));
        assert_eq!(ident.as_slice(), "_empty-fc065c9b6b16fc00");
    }

    fn url(s: &str) -> Url {
        url::from_str(s).unwrap()
    }
}
<commit_msg>Revert "Merge pull request #89 from rust-lang/revert-88-fix"<commit_after>use std::fmt::{Show,Formatter};
use std::fmt;
use std::hash::Hasher;
use std::hash::sip::SipHasher;
use std::str;

use core::source::{Source, SourceId, GitKind, Location, Remote, Local};
use core::{Package,PackageId,Summary};
use util::{CargoResult, Config, to_hex};
use sources::PathSource;
use sources::git::utils::{GitReference,GitRemote,Master,Other};

/* TODO: Refactor GitSource to delegate to a PathSource
 */
pub struct GitSource<'a, 'b> {
    remote: GitRemote,
    reference: GitReference,
    db_path: Path,
    checkout_path: Path,
    path_source: PathSource,
    config: &'a mut Config<'b>
}

impl<'a, 'b> GitSource<'a, 'b> {
    pub fn new<'a, 'b>(source_id: &SourceId, config: &'a mut Config<'b>) -> GitSource<'a, 'b> {
        assert!(source_id.is_git(), "id is not git, id={}", source_id);

        let reference = match source_id.kind {
            GitKind(ref reference) => reference,
            _ => fail!("Not a git source; id={}", source_id)
        };

        let remote = GitRemote::new(source_id.get_location());
        let ident = ident(source_id.get_location());

        let db_path = config.git_db_path()
            .join(ident.as_slice());

        let checkout_path = config.git_checkout_path()
            .join(ident.as_slice()).join(reference.as_slice());

        let path_source = PathSource::new(&checkout_path, source_id);

        GitSource {
            remote: remote,
            reference: GitReference::for_str(reference.as_slice()),
            db_path: db_path,
            checkout_path: checkout_path,
            path_source: path_source,
            config: config
        }
    }

    pub fn get_namespace<'a>(&'a self) -> &'a Location {
        self.remote.get_location()
    }
}

fn ident(location: &Location) -> String {
    let hasher = SipHasher::new_with_keys(0,0);

    // FIXME: this really should be able to not use to_str() everywhere, but the
    //        compiler seems to currently ask for static lifetimes spuriously.
    //        Perhaps related to rust-lang/rust#15144
    let ident = match *location {
        Local(ref path) => {
            let last = path.components().last().unwrap();
            str::from_utf8(last).unwrap().to_str()
        }
        Remote(ref url) => {
            let path = canonicalize_url(url.path.as_slice());
            path.as_slice().split('/').last().unwrap().to_str()
        }
    };

    let ident = if ident.as_slice() == "" {
        "_empty".to_string()
    } else {
        ident
    };

    let location = canonicalize_url(location.to_str().as_slice());

    format!("{}-{}", ident, to_hex(hasher.hash(&location.as_slice())))
}

fn strip_trailing_slash<'a>(path: &'a str) -> &'a str {
    // Remove the trailing '/' so that 'split' doesn't give us
    // an empty string, making '../foo/' and '../foo' both
    // result in the name 'foo' (#84)
    if path.as_bytes().last() != Some(&('/' as u8)) {
        path.clone()
    } else {
        path.slice(0, path.len() - 1)
    }
}

// Some hacks and heuristics for making equivalent URLs hash the same
fn canonicalize_url(url: &str) -> String {
    let url = strip_trailing_slash(url);

    // HACKHACK: For github URL's specifically just lowercase
    // everything.  GitHub traits both the same, but they hash
    // differently, and we're gonna be hashing them. This wants a more
    // general solution, and also we're almost certainly not using the
    // same case conversion rules that GitHub does. (#84)

    let lower_url = url.chars().map(|c|c.to_lowercase()).collect::<String>();
    let url = if lower_url.as_slice().contains("github.com") {
        lower_url
    } else {
        url.to_string()
    };

    // Repos generally can be accessed with or w/o '.git'
    let url = if !url.as_slice().ends_with(".git") {
        url
    } else {
        url.as_slice().slice(0, url.len() - 4).to_string()
    };

    return url;
}

impl<'a, 'b> Show for GitSource<'a, 'b> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "git repo at {}", self.remote.get_location()));

        match self.reference {
            Master => Ok(()),
            Other(ref reference) => write!(f, " ({})", reference)
        }
    }
}

impl<'a, 'b> Source for GitSource<'a, 'b> {
    fn update(&mut self) -> CargoResult<()> {
        let should_update = self.config.update_remotes() || {
            !self.remote.has_ref(&self.db_path, self.reference.as_slice()).is_ok()
        };

        let repo = if should_update {
            try!(self.config.shell().status("Updating",
                format!("git repository `{}`", self.remote.get_location())));

            log!(5, "updating git source `{}`", self.remote);
            try!(self.remote.checkout(&self.db_path))
        } else {
            self.remote.db_at(&self.db_path)
        };

        try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path));

        self.path_source.update()
    }

    fn list(&self) -> CargoResult<Vec<Summary>> {
        self.path_source.list()
    }

    fn download(&self, _: &[PackageId]) -> CargoResult<()> {
        // TODO: assert! that the PackageId is contained by the source
        Ok(())
    }

    fn get(&self, ids: &[PackageId]) -> CargoResult<Vec<Package>> {
        log!(5, "getting packages for package ids `{}` from `{}`", ids, self.remote);
        self.path_source.get(ids)
    }

    fn fingerprint(&self, _pkg: &Package) -> CargoResult<String> {
        let db = self.remote.db_at(&self.db_path);
        db.rev_for(self.reference.as_slice())
    }
}

#[cfg(test)]
mod test {
    use url;
    use url::Url;
    use core::source::Remote;
    use super::ident;

    #[test]
    pub fn test_url_to_path_ident_with_path() {
        let ident = ident(&Remote(url("https://github.com/carlhuda/cargo")));
        assert_eq!(ident.as_slice(), "cargo-0eed735c8ffd7c88");
    }

    #[test]
    pub fn test_url_to_path_ident_without_path() {
        let ident = ident(&Remote(url("https://github.com")));
        assert_eq!(ident.as_slice(), "_empty-fc065c9b6b16fc00");
    }

    #[test]
    fn test_canonicalize_idents_by_stripping_trailing_url_slash() {
        let ident1 = ident(&Remote(url("https://github.com/PistonDevelopers/piston/")));
        let ident2 = ident(&Remote(url("https://github.com/PistonDevelopers/piston")));
        assert_eq!(ident1, ident2);
    }

    #[test]
    fn test_canonicalize_idents_by_lowercasing_github_urls() {
        let ident1 = ident(&Remote(url("https://github.com/PistonDevelopers/piston")));
        let ident2 = ident(&Remote(url("https://github.com/pistondevelopers/piston")));
        assert_eq!(ident1, ident2);
    }

    #[test]
    fn test_canonicalize_idents_by_stripping_dot_git() {
        let ident1 = ident(&Remote(url("https://github.com/PistonDevelopers/piston")));
        let ident2 = ident(&Remote(url("https://github.com/PistonDevelopers/piston.git")));
        assert_eq!(ident1, ident2);
    }

    fn url(s: &str) -> Url {
        url::from_str(s).unwrap()
    }
}
<|endoftext|>


<commit_before>extern crate csv;
extern crate rustc_serialize;

#[macro_use]
extern crate text_io;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

struct IndexedDB(HashMap<String, HashMap<String, f32>>, HashMap<String, HashMap<String, f32>>);

fn load_db(path: &str) -> IndexedDB {
    let mut rdr = csv::Reader::from_file(path).unwrap().has_headers(false);
    let mut ratings: HashMap<String, HashMap<String, f32>> = HashMap::new();
    let mut features: HashMap<String, HashMap<String, f32>> = HashMap::new();

    for record in rdr.decode() {
        let (user_id, feat_id, rating): (String, String, f32) = record.unwrap();
        let (user_id2, feat_id2, rating2) = (user_id.clone(), feat_id.clone(), rating);

        match ratings.entry(user_id) {
            Vacant(entry) => {
                let mut user_ratings = HashMap::new();
                user_ratings.insert(feat_id, rating);
                entry.insert(user_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(feat_id, rating);
            }
        }

        match features.entry(feat_id2) {
            Vacant(entry) => {
                let mut movie_ratings = HashMap::new();
                movie_ratings.insert(user_id2, rating2);
                entry.insert(movie_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(user_id2, rating2);
            }
        }
    }

    IndexedDB(ratings, features)
}

fn deviation(db: &IndexedDB, feat_1: &str, feat_2: &str) -> (f32, usize) {
    let mut vec_a: Vec<f32> = Vec::new();
    let mut vec_b: Vec<f32> = Vec::new();

    if let Some(ref ratings_f1) = db.1.get(&String::from(feat_1)) {
        for (user_id, &rating_f1) in ratings_f1.iter() {
            if let Some(ratings_f2) = db.1.get(&String::from(feat_2)) {
                if let Some(&rating_f2) = ratings_f2.get(user_id) {
                    vec_a.push(rating_f1);
                    vec_b.push(rating_f2);
                }
            } else {
                panic!("feat_2 is not found!");
            }
        }
    } else {
        panic!("feat_1 is not found!");
    }

    let length = vec_a.len();
    let mut deviation = 0.0;
    for i in 0..length {
        deviation += (vec_a[i] - vec_b[i]) / length as f32;
    }

    (deviation, length)
}

fn weighted_slope_one(db: &IndexedDB, user: &str, feat: &str) -> f32 {
    let mut num = 0.0;
    let mut den = 0.0;
    if let Some(ref ratings) = db.0.get(&String::from(user)) {
        for (feat_id, &rating) in ratings.iter() {
            let (dev, card) = deviation(&db, feat, feat_id);
            num += (dev + rating) * card as f32;
            den += card as f32;
        }
    } else {
        panic!("user is not found!");
    }

    num / den
}

fn adjusted_cosine(vec_feat_1: &Vec<f32>, vec_feat_2: &Vec<f32>, vec_avg: &Vec<f32>) -> f32 {
    if vec_feat_1.len() != vec_feat_2.len() || vec_feat_1.len() != vec_avg.len() {
        panic!("Should compare vectors of same size");
    }

    let n_users = vec_feat_1.len();

    let mut usr_pref = 0.0;
    let mut feat_1_sqr = 0.0;
    let mut feat_2_sqr = 0.0;

    for i in 0..n_users {
        if vec_feat_1[i] > 0.0 && vec_feat_2[i] > 0.0 {
            let feat_1_inf = vec_feat_1[i] - vec_avg[i];
            let feat_2_inf = vec_feat_2[i] - vec_avg[i];
            usr_pref += feat_1_inf * feat_2_inf;
            feat_1_sqr += feat_1_inf.powf(2.0);
            feat_2_sqr += feat_2_inf.powf(2.0);
        }
    }

    usr_pref / (feat_1_sqr.sqrt() * feat_2_sqr.sqrt())
}

fn computer_user_avg(db: &IndexedDB, user: &str) -> f32 {
    let mut avg: f32 = 0.0;
    if let Some(ref ratings) = db.0.get(&String::from(user)) {
        for (_, &rating) in ratings.iter() {
            avg += rating;
        }
        avg /= ratings.len() as f32
    }
    avg
}

fn adjusted_cosine_features(db: &IndexedDB, feat_1: &str, feat_2: &str) -> f32 {
    let mut vec_a: Vec<f32> = Vec::new();
    let mut vec_b: Vec<f32> = Vec::new();
    let mut vec_avg: Vec<f32> = Vec::new();

    if let Some(ref ratings_f1) = db.1.get(&String::from(feat_1)) {
        for (user_id, &rating_f1) in ratings_f1.iter() {
            vec_avg.push(computer_user_avg(&db, user_id));
            if let Some(ratings_f2) = db.1.get(&String::from(feat_2)) {
                if let Some(&rating_f2) = ratings_f2.get(user_id) {
                    vec_a.push(rating_f1);
                    vec_b.push(rating_f2);
                } else {
                    vec_a.push(rating_f1);
                    vec_b.push(0.0);
                }
            } else {
                panic!("1: feat_2 is not found!");
            }
        }
    } else {
        panic!("1: feat_1 is not found!");
    }

    if let Some(ref ratings_f2) = db.1.get(&String::from(feat_2)) {
        for (user_id, &rating_f2) in ratings_f2.iter() {
            if let Some(ratings_f1) = db.1.get(&String::from(feat_1)) {
                if let Some(_) = ratings_f1.get(user_id) {
                } else {
                    vec_a.push(0.0);
                    vec_b.push(rating_f2);
                    vec_avg.push(computer_user_avg(&db, user_id));
                }
            } else {
                panic!("2: feat_1 is not found!");
            }
        }
    } else {
        panic!("2: feat_2 is not found!");
    }

    adjusted_cosine(&vec_a, &vec_b, &vec_avg)
}

fn prediction(sim_vec: Vec<f32>, normd_vec: Vec<f32>) -> f32 {
    let mut num = 0.0;
    let mut den = 0.0;
    let inv_i = sim_vec.len();
    for i in 0..inv_i {
        num += sim_vec[i] * normd_vec[i];
        den += sim_vec[i].abs();
    }

    num / den
}

fn normalize(vect: &Vec<f32>) -> (Vec<f32>, f32, f32) {
    let mut normd_vec = Vec::with_capacity(vect.len());

    let mut max = vect[0];
    let mut min = vect[0];

    for rating in vect.iter() {
        if *rating > max {
            max = *rating;
        }
        if *rating != 0.0 && *rating < min || min == 0.0 {
            min = *rating;
        }
    }

    for rating in vect.iter() {
        if *rating > 0.0 {
            let norm = (2.0 * (rating - min) - (max - min)) / (max - min);
            normd_vec.push(norm);
        }
    }

    (normd_vec, max, min)
}

fn unnormalize(norm_val: f32, max: f32, min: f32) -> f32 {
    0.5 * (norm_val + 1.0) * (max - min) + min
}

fn adjusted_cosine_prediction(db: &IndexedDB, user: &str, feature: &str) -> f32 {
    let mut sim_vec: Vec<f32> = Vec::new();
    let mut usr_vec: Vec<f32> = Vec::new();

    match db.0.get(&String::from(user)) {
        Some(a_ratings) => {
            for (movie_id, &rating) in a_ratings.iter() {
                sim_vec.push(adjusted_cosine_features(db, &feature, movie_id));
                usr_vec.push(rating);
            }
        }
        None => {}
    }

    let normd_usr_vec = normalize(&usr_vec);
    let normd_pred = prediction(sim_vec, normd_usr_vec.0);
    println!("Normalized prediction: {}", normd_pred);
    unnormalize(normd_pred, normd_usr_vec.1, normd_usr_vec.2)
}

// fn item_based_prediction_input(db: &mut IndexedDB,
//                                sim_fun: fn(&IndexedDB, String, String) -> f32)
//                                -> f32 {
//     let user_id: String;
//     let movie_id: String;
//     println!("Enter user_id y movie_id:");
//     scan!("{} {}", user_id, movie_id);

//     match db.0.entry(user_id) {
//         Vacant(entry) => {
//             let mut ratings: HashMap<u32, f32> = HashMap::new();
//             let mut movie: u32;
//             let mut rating: f32;
//             for i in 0..10 {
//                 println!("Enter movie_id:");
//                 scan!("{}", movie);
//                 println!("Enter rating:");
//                 scan!("{}", rating);
//                 ratings.insert(movie, rating);
//                 match db.1.entry(user_id) {
//                     Vacant(usr_map) => {
//                         let mut user_rtngs: HashMap<u32, f32> = HashMap::new();
//                         user_rtngs.insert(user_id, rating);
//                         usr_map.insert(user_rtngs);
//                     }
//                     Occupied(usr_map) => {
//                         usr_map.into_mut().insert(user_id, rating);
//                     }
//                 }
//             }
//             entry.insert(ratings);
//         }
//         Occupied(_) => {}
//     }

//     sim_fun(&db, user_id, movie_id)
// }

fn main() {
    println!("Loading database, please wait...");
    let mut db = load_db("./data/db2.csv");
    // let mut db = load_db("../report01/data/BX-Dump/BX-Book-Ratings.csv");
    println!("Database ready!\n---------------------------------------------");

    let mut ender: u32;
    loop {
        println!("Press 1 to make a query with Slope One.\n\
                  Press 2 to make a query with Adjusted Cosine.\n\
                  Press 0 to exit: ");
        scan!("{}", ender);
        match ender {
            1 => {
                println!("S1p: {}", weighted_slope_one(&db, "Ben", "Whitney Houston"));
            }
            2 => {
                println!("ACp: {}",
                         adjusted_cosine_prediction(&db, "Ben", "Whitney Houston"));
            }
            0 => {
                break;
            }
            _ => {
                println!("Try again");
            }
        }
        println!("\n______________________________________________________");
    }
    println!("\nBye bytes...");
}
<commit_msg>It's working<commit_after>extern crate csv;
extern crate rustc_serialize;

#[macro_use]
extern crate text_io;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

struct IndexedDB(HashMap<String, HashMap<String, f32>>, HashMap<String, HashMap<String, f32>>);

fn load_db(path: &str) -> IndexedDB {
    let mut rdr = csv::Reader::from_file(path).unwrap().has_headers(false);
    let mut ratings: HashMap<String, HashMap<String, f32>> = HashMap::new();
    let mut features: HashMap<String, HashMap<String, f32>> = HashMap::new();

    for record in rdr.decode() {
        let (user_id, feat_id, rating): (String, String, f32) = record.unwrap();
        let (user_id2, feat_id2, rating2) = (user_id.clone(), feat_id.clone(), rating);

        match ratings.entry(user_id) {
            Vacant(entry) => {
                let mut user_ratings = HashMap::new();
                user_ratings.insert(feat_id, rating);
                entry.insert(user_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(feat_id, rating);
            }
        }

        match features.entry(feat_id2) {
            Vacant(entry) => {
                let mut movie_ratings = HashMap::new();
                movie_ratings.insert(user_id2, rating2);
                entry.insert(movie_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(user_id2, rating2);
            }
        }
    }

    IndexedDB(ratings, features)
}

fn deviation(db: &IndexedDB, feat_1: &str, feat_2: &str) -> (f32, usize) {
    let mut vec_a: Vec<f32> = Vec::new();
    let mut vec_b: Vec<f32> = Vec::new();

    if let Some(ref ratings_f1) = db.1.get(&String::from(feat_1)) {
        for (user_id, &rating_f1) in ratings_f1.iter() {
            if let Some(ratings_f2) = db.1.get(&String::from(feat_2)) {
                if let Some(&rating_f2) = ratings_f2.get(user_id) {
                    vec_a.push(rating_f1);
                    vec_b.push(rating_f2);
                }
            } else {
                panic!("feat_2 is not found!");
            }
        }
    } else {
        panic!("feat_1 is not found!");
    }

    let length = vec_a.len();
    let mut deviation = 0.0;
    for i in 0..length {
        deviation += (vec_a[i] - vec_b[i]) / length as f32;
    }

    (deviation, length)
}

fn weighted_slope_one(db: &IndexedDB, user: &str, feat: &str) -> f32 {
    let mut num = 0.0;
    let mut den = 0.0;
    if let Some(ref ratings) = db.0.get(&String::from(user)) {
        for (feat_id, &rating) in ratings.iter() {
            let (dev, card) = deviation(&db, feat, feat_id);
            num += (dev + rating) * card as f32;
            den += card as f32;
        }
    } else {
        panic!("user is not found!");
    }

    num / den
}

fn adjusted_cosine(vec_feat_1: &Vec<f32>, vec_feat_2: &Vec<f32>, vec_avg: &Vec<f32>) -> f32 {
    if vec_feat_1.len() != vec_feat_2.len() || vec_feat_1.len() != vec_avg.len() {
        panic!("Should compare vectors of same size");
    }

    let n_users = vec_feat_1.len();

    let mut usr_pref = 0.0;
    let mut feat_1_sqr = 0.0;
    let mut feat_2_sqr = 0.0;

    for i in 0..n_users {
        if vec_feat_1[i] > 0.0 && vec_feat_2[i] > 0.0 {
            let feat_1_inf = vec_feat_1[i] - vec_avg[i];
            let feat_2_inf = vec_feat_2[i] - vec_avg[i];
            usr_pref += feat_1_inf * feat_2_inf;
            feat_1_sqr += feat_1_inf.powf(2.0);
            feat_2_sqr += feat_2_inf.powf(2.0);
        }
    }

    usr_pref / (feat_1_sqr.sqrt() * feat_2_sqr.sqrt())
}

fn computer_user_avg(db: &IndexedDB, user: &str) -> f32 {
    let mut avg: f32 = 0.0;
    if let Some(ref ratings) = db.0.get(&String::from(user)) {
        for (_, &rating) in ratings.iter() {
            avg += rating;
        }
        avg /= ratings.len() as f32
    }
    avg
}

fn adjusted_cosine_features(db: &IndexedDB, feat_1: &str, feat_2: &str) -> f32 {
    let mut vec_a: Vec<f32> = Vec::new();
    let mut vec_b: Vec<f32> = Vec::new();
    let mut vec_avg: Vec<f32> = Vec::new();

    if let Some(ref ratings_f1) = db.1.get(&String::from(feat_1)) {
        for (user_id, &rating_f1) in ratings_f1.iter() {
            vec_avg.push(computer_user_avg(&db, user_id));
            if let Some(ratings_f2) = db.1.get(&String::from(feat_2)) {
                if let Some(&rating_f2) = ratings_f2.get(user_id) {
                    vec_a.push(rating_f1);
                    vec_b.push(rating_f2);
                } else {
                    vec_a.push(rating_f1);
                    vec_b.push(0.0);
                }
            } else {
                panic!("1: feat_2 is not found!");
            }
        }
    } else {
        panic!("1: feat_1 is not found!");
    }

    if let Some(ref ratings_f2) = db.1.get(&String::from(feat_2)) {
        for (user_id, &rating_f2) in ratings_f2.iter() {
            if let Some(ratings_f1) = db.1.get(&String::from(feat_1)) {
                if let Some(_) = ratings_f1.get(user_id) {
                } else {
                    vec_a.push(0.0);
                    vec_b.push(rating_f2);
                    vec_avg.push(computer_user_avg(&db, user_id));
                }
            } else {
                panic!("2: feat_1 is not found!");
            }
        }
    } else {
        panic!("2: feat_2 is not found!");
    }

    adjusted_cosine(&vec_a, &vec_b, &vec_avg)
}

fn prediction(sim_vec: Vec<f32>, normd_vec: Vec<f32>) -> f32 {
    let mut num = 0.0;
    let mut den = 0.0;
    let inv_i = sim_vec.len();
    for i in 0..inv_i {
        num += sim_vec[i] * normd_vec[i];
        den += sim_vec[i].abs();
    }

    num / den
}

fn normalize(vect: &Vec<f32>) -> (Vec<f32>, f32, f32) {
    let mut normd_vec = Vec::with_capacity(vect.len());

    let mut max = vect[0];
    let mut min = vect[0];

    for rating in vect.iter() {
        if *rating > max {
            max = *rating;
        }
        if *rating != 0.0 && *rating < min || min == 0.0 {
            min = *rating;
        }
    }

    for rating in vect.iter() {
        if *rating > 0.0 {
            let norm = (2.0 * (rating - min) - (max - min)) / (max - min);
            normd_vec.push(norm);
        }
    }

    (normd_vec, max, min)
}

fn unnormalize(norm_val: f32, max: f32, min: f32) -> f32 {
    0.5 * (norm_val + 1.0) * (max - min) + min
}

fn adjusted_cosine_prediction(db: &IndexedDB, user: &str, feature: &str) -> f32 {
    let mut sim_vec: Vec<f32> = Vec::new();
    let mut usr_vec: Vec<f32> = Vec::new();

    match db.0.get(&String::from(user)) {
        Some(a_ratings) => {
            for (movie_id, &rating) in a_ratings.iter() {
                sim_vec.push(adjusted_cosine_features(db, &feature, movie_id));
                usr_vec.push(rating);
            }
        }
        None => {}
    }

    let normd_usr_vec = normalize(&usr_vec);
    let normd_pred = prediction(sim_vec, normd_usr_vec.0);
    println!("Normalized prediction: {}", normd_pred);
    unnormalize(normd_pred, normd_usr_vec.1, normd_usr_vec.2)
}

fn prediction_input(db: &mut IndexedDB, sim_fun: fn(&IndexedDB, &str, &str) -> f32) -> f32 {
    let user_id: String;
    let feat_id: String;
    println!("Enter {{user}} y {{feature}}:");
    scan!("{} {}", user_id, feat_id);

    if let Some(_) = db.0.get(&user_id) {
    } else {
        println!("\nUser not found, you'll be requested to enter 10 ratings...");

        let mut ratings: HashMap<String, f32> = HashMap::new();
        let mut feat: String;
        let mut rating: f32;

        for i in 0..10 {
            println!("{}. Enter feature and rating:", i);
            scan!("{} {}", feat, rating);

            let ins_feat = feat.clone();

            match db.1.entry(feat) {
                Vacant(entry) => {
                    let mut feat_ratings = HashMap::new();
                    feat_ratings.insert(user_id.clone(), rating);
                    entry.insert(feat_ratings);
                }
                Occupied(entry) => {
                    entry.into_mut().insert(user_id.clone(), rating);
                }
            }

            ratings.insert(ins_feat, rating);
        }
    }

    // match db.0.entry(&user_id) {
    //     Vacant(usr_map) => {
    //         println!("User not found, you'll be requested to enter 10 ratings...");

    //         let mut ratings: HashMap<String, f32> = HashMap::new();
    //         let mut feat: String;
    //         let mut rating: f32;

    //         for i in 0..10 {
    //             println!("{}. Enter feature:", i);
    //             scan!("{}", feat);
    //             println!("Enter rating:");
    //             scan!("{}", rating);

    //             match db.1.entry(feat) {
    //                 Vacant(entry) => {
    //                     let mut feat_ratings = HashMap::new();
    //                     feat_ratings.insert(user_id.clone(), rating);
    //                     entry.insert(feat_ratings);
    //                 }
    //                 Occupied(entry) => {
    //                     entry.into_mut().insert(user_id.clone(), rating);
    //                 }
    //             }

    //             ratings.insert(feat, rating);
    //         }
    //     }
    //     Occupied(usr_map) => {}
    // }

    sim_fun(&db, user_id.as_str(), feat_id.as_str())
}

fn main() {
    println!("Loading database, please wait...");
    let mut db = load_db("./data/db2.csv");
    // let mut db = load_db("../report01/data/BX-Dump/BX-Book-Ratings.csv");
    println!("Database ready!\n---------------------------------------------");

    let mut ender: u32;
    loop {
        println!("Press 1 to make a query with Slope One.\n\
                  Press 2 to make a query with Adjusted Cosine.\n\
                  Press 0 to exit: ");
        scan!("{}", ender);
        match ender {
            1 => {
                // println!("S1p: {}", weighted_slope_one(&db, "Ben", "Whitney Houston"));
                println!("S1p: {}", prediction_input(&mut db, weighted_slope_one));
            }
            2 => {
                // println!("ACp: {}", adjusted_cosine_prediction(&db, "Ben", "Whitney Houston"));
                println!("ACp: {}",
                         prediction_input(&mut db, adjusted_cosine_prediction));
            }
            0 => {
                break;
            }
            _ => {
                println!("Try again");
            }
        }
        println!("\n______________________________________________________");
    }
    println!("\nBye bytes...");
}
<|endoftext|>


<commit_before>extern crate libc;

extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::sync::{Arc, Mutex};

use std::ffi::CStr;
use libc::{c_void, c_char};

use emu::audio_driver::AudioDriver;
use emu::core_audio_driver::CoreAudioDriver;

use spc::spc::{Spc, RAM_LEN};
use snes_apu::apu::Apu;
use snes_apu::dsp::dsp::{SAMPLE_RATE, BUFFER_LEN};

struct ContextState {
    apu: Box<Apu>,
    spc: Option<Spc>
}

struct Context {
    state: Arc<Mutex<ContextState>>,
    _driver: CoreAudioDriver
}

impl Context {
    fn new() -> Context {
        let state = Arc::new(Mutex::new(ContextState {
            apu: Apu::new(),
            spc: None
        }));

        let mut driver = CoreAudioDriver::new();
        driver.set_sample_rate(SAMPLE_RATE as i32);
        let render_callback_state = state.clone();
        let mut left = [0; BUFFER_LEN];
        let mut right = [0; BUFFER_LEN];
        driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
            render_callback_state.lock().unwrap().apu.render(&mut left, &mut right, num_frames as i32);
            for i in 0..num_frames {
                let j = i * 2;
                buffer[j + 0] = left[i] as f32 / 32768.0;
                buffer[j + 1] = right[i] as f32 / 32768.0;
            }
        })));

        Context {
            state: state,
            _driver: driver
        }
    }

    fn set_song(&mut self, spc: Option<Spc>) {
        let state = &mut self.state.lock().unwrap();
        state.apu.reset();
        if let Some(ref spc) = spc {
            state.apu.set_state(&spc);
            state.apu.clear_echo_buffer();
        }
        state.spc = spc;
    }

    fn get_ram_snapshot(&mut self) -> Box<[u8; RAM_LEN]> {
        self.state.lock().unwrap().apu.get_ram_snapshot()
    }
}

#[no_mangle]
pub extern fn create_context() -> *mut c_void {
    Box::into_raw(Box::new(Context::new())) as *mut c_void
}

#[no_mangle]
pub extern fn free_context(context: *mut c_void) {
    unsafe { Box::from_raw(context as *mut Context) };
}

#[no_mangle]
pub extern fn set_song(context: *mut c_void, filename: *const c_char) {
    let context = unsafe { &mut *(context as *mut Context) };
    let spc = if filename.is_null() {
        None
    } else {
        let filename = unsafe { CStr::from_ptr(filename) }.to_str().unwrap();
        Some(Spc::load(filename).unwrap())
    };
    context.set_song(spc);
}

#[no_mangle]
pub extern fn get_ram_snapshot(context: *mut c_void) -> *mut u8 {
    let context = unsafe { &mut *(context as *mut Context) };
    let snapshot = context.get_ram_snapshot();
    Box::into_raw(snapshot) as *mut u8
}

#[no_mangle]
pub extern fn free_ram_snapshot(snapshot: *mut c_void) {
    unsafe { Box::from_raw(snapshot as *mut [u8; RAM_LEN]) };
}
<commit_msg>Moved RAM snapshot code here from snes-apu<commit_after>extern crate libc;

extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::sync::{Arc, Mutex};

use std::ffi::CStr;
use libc::{c_void, c_char};

use emu::audio_driver::AudioDriver;
use emu::core_audio_driver::CoreAudioDriver;

use spc::spc::{Spc, RAM_LEN};
use snes_apu::apu::Apu;
use snes_apu::dsp::dsp::{SAMPLE_RATE, BUFFER_LEN};

struct ContextState {
    apu: Box<Apu>,
    spc: Option<Spc>
}

struct Context {
    state: Arc<Mutex<ContextState>>,
    _driver: CoreAudioDriver
}

impl Context {
    fn new() -> Context {
        let state = Arc::new(Mutex::new(ContextState {
            apu: Apu::new(),
            spc: None
        }));

        let mut driver = CoreAudioDriver::new();
        driver.set_sample_rate(SAMPLE_RATE as i32);
        let render_callback_state = state.clone();
        let mut left = [0; BUFFER_LEN];
        let mut right = [0; BUFFER_LEN];
        driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
            render_callback_state.lock().unwrap().apu.render(&mut left, &mut right, num_frames as i32);
            for i in 0..num_frames {
                let j = i * 2;
                buffer[j + 0] = left[i] as f32 / 32768.0;
                buffer[j + 1] = right[i] as f32 / 32768.0;
            }
        })));

        Context {
            state: state,
            _driver: driver
        }
    }

    fn set_song(&mut self, spc: Option<Spc>) {
        let state = &mut self.state.lock().unwrap();
        state.apu.reset();
        if let Some(ref spc) = spc {
            state.apu.set_state(&spc);
            state.apu.clear_echo_buffer();
        }
        state.spc = spc;
    }

    fn get_ram_snapshot(&mut self) -> Box<[u8; RAM_LEN]> {
        let state = &mut self.state.lock().unwrap();
        let mut ret = Box::new([0; RAM_LEN]);
        for i in 0..RAM_LEN {
            ret[i] = state.apu.read_u8(i as u32);
        }
        ret
    }
}

#[no_mangle]
pub extern fn create_context() -> *mut c_void {
    Box::into_raw(Box::new(Context::new())) as *mut c_void
}

#[no_mangle]
pub extern fn free_context(context: *mut c_void) {
    unsafe { Box::from_raw(context as *mut Context) };
}

#[no_mangle]
pub extern fn set_song(context: *mut c_void, filename: *const c_char) {
    let context = unsafe { &mut *(context as *mut Context) };
    let spc = if filename.is_null() {
        None
    } else {
        let filename = unsafe { CStr::from_ptr(filename) }.to_str().unwrap();
        Some(Spc::load(filename).unwrap())
    };
    context.set_song(spc);
}

#[no_mangle]
pub extern fn get_ram_snapshot(context: *mut c_void) -> *mut u8 {
    let context = unsafe { &mut *(context as *mut Context) };
    let snapshot = context.get_ram_snapshot();
    Box::into_raw(snapshot) as *mut u8
}

#[no_mangle]
pub extern fn free_ram_snapshot(snapshot: *mut c_void) {
    unsafe { Box::from_raw(snapshot as *mut [u8; RAM_LEN]) };
}
<|endoftext|>