<commit_before>use super::{Index, Range};
use small;
use std::{cmp::Ordering, u8};

fn numeric_range<'a>(
    start: isize,
    end: isize,
    step: isize,
    inclusive: bool,
    nb_digits: usize,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };

    if step == 0 || (start < end && step < 0) || (start > end && step > 0) {
        None
    } else {
        let (x, y, ordering) = if start < end {
            (start, end, Ordering::Greater)
        } else {
            (end, start, Ordering::Less)
        };

        let iter = (x..y).scan(start, move |index, _| {
            if end.cmp(index) == ordering {
                let index_holder = *index;
                *index += step; // This step adds
                Some(format!("{:0width$}", index_holder, width = nb_digits).into())
            } else {
                None
            }
        });

        Some(Box::new(iter))
    }
}

fn char_range<'a>(
    start: u8,
    mut end: u8,
    step: isize,
    inclusive: bool,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    if !start.is_ascii_alphabetic()
        || !end.is_ascii_alphabetic()
        || step == 0
        || step.checked_abs()? > u8::MAX as isize
    {
        return None;
    }

    if (start < end && inclusive) || (start > end && !inclusive) {
        end += 1;
    }

    if start < end {
        Some(Box::new((start..end).step_by(step as usize).map(|x| (x as char).to_string().into())))
    } else {
        Some(Box::new(
            (end..=start).rev().step_by(step as usize).map(|x| (x as char).to_string().into()),
        ))
    }
}

fn count_minimum_digits(a: &str) -> usize {
    match a.bytes().find(|&c| c != b'-') {
        Some(b'0') => a.len(),
        Some(b'1'...b'9') => 0,
        Some(_) => panic!("count_minimum_digits should only be called for a valid number."),
        None => 0,
    }
}

fn finish(
    inclusive: bool,
    start_str: &str,
    end_str: &str,
    step: isize,
) -> Option<Box<Iterator<Item = small::String>>> {
    if let (Ok(start), Ok(end)) = (start_str.parse::<isize>(), end_str.parse::<isize>()) {
        let step = if step == 1 && start >= end { -step } else { step };
        let nb_digits = usize::max(count_minimum_digits(start_str), count_minimum_digits(end_str));
        numeric_range(start, end, step, inclusive, nb_digits)
    } else if start_str.len() != 1 || end_str.len() != 1 {
        None
    } else {
        char_range(start_str.as_bytes()[0], end_str.as_bytes()[0], step, inclusive)
    }
}

// TODO: Make this an iterator structure.
// In a range we allow the following syntax:
//      Exclusive nonstepped: {start..end}
//      Inclusive nonstepped: {start...end}
//      Exclusive stepped: {start..step..end}
//      Inclusive stepped: {start..step...end}
pub fn parse_range(input: &str) -> Option<Box<Iterator<Item = small::String>>> {
    let mut parts = input.split("..").collect::<Vec<_>>();
    let len = parts.len();

    // if the last separator contains three dots, this can only be an inclusive range
    let inclusive = parts.last()?.starts_with(|c| c == '.' || c == '=');
    if inclusive {
        parts[len - 1] = parts[len - 1].trim_start_matches(|c| c == '.' || c == '=');
    }

    match len {
        // two parts means unstepped range
        2 => finish(inclusive, parts[0], parts[1], 1),
        // middle string contains the step size
        3 => finish(inclusive, parts[0], parts[2], parts[1].parse::<isize>().ok()?),
        // not a valid byte for ranges
        _ => None,
    }
}

pub fn parse_index_range(input: &str) -> Option<Range> {
    let mut parts = input.splitn(2, "..");
    let first = parts.next()?;
    let mut end = parts.next()?;

    if first.is_empty() && !end.is_empty() {
        end.parse::<isize>().map(|end| Range::to(Index::new(end))).ok()
    } else if !end.is_empty() {
        let inclusive = end.starts_with('.') || end.starts_with('=');
        if inclusive {
            end = &end[1..];
        }

        let start = first.parse::<isize>().ok()?;
        let end = end.parse::<isize>().ok()?;
        if inclusive {
            Some(Range::inclusive(Index::new(start), Index::new(end)))
        } else {
            Some(Range::exclusive(Index::new(start), Index::new(end)))
        }
    } else {
        first.parse::<isize>().map(|start| Range::from(Index::new(start))).ok()
    }
}
<commit_msg>Use positive step values<commit_after>use super::{Index, Range};
use small;
use std::{cmp::Ordering, u8};

fn numeric_range<'a>(
    start: isize,
    end: isize,
    step: isize,
    inclusive: bool,
    nb_digits: usize,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };

    if step == 0 || (start < end && step < 0) || (start > end && step > 0) {
        None
    } else {
        let (x, y, ordering) = if start < end {
            (start, end, Ordering::Greater)
        } else {
            (end, start, Ordering::Less)
        };

        let iter = (x..y).scan(start, move |index, _| {
            if end.cmp(index) == ordering {
                let index_holder = *index;
                *index += step; // This step adds
                Some(format!("{:0width$}", index_holder, width = nb_digits).into())
            } else {
                None
            }
        });

        Some(Box::new(iter))
    }
}

fn char_range<'a>(
    start: u8,
    mut end: u8,
    step: isize,
    inclusive: bool,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    if !start.is_ascii_alphabetic() || !end.is_ascii_alphabetic() || step == 0 {
        return None;
    }

    if (start < end && inclusive) || (start > end && !inclusive) {
        end += 1;
    }

    let char_step = step.checked_abs()? as usize;
    if start < end {
        Some(Box::new((start..end).step_by(char_step).map(|x| (x as char).to_string().into())))
    } else {
        Some(Box::new(
            (end..=start).rev().step_by(char_step).map(|x| (x as char).to_string().into()),
        ))
    }
}

fn count_minimum_digits(a: &str) -> usize {
    match a.bytes().find(|&c| c != b'-') {
        Some(b'0') => a.len(),
        Some(b'1'...b'9') => 0,
        Some(_) => panic!("count_minimum_digits should only be called for a valid number."),
        None => 0,
    }
}

fn finish(
    inclusive: bool,
    start_str: &str,
    end_str: &str,
    step: isize,
) -> Option<Box<Iterator<Item = small::String>>> {
    if let (Ok(start), Ok(end)) = (start_str.parse::<isize>(), end_str.parse::<isize>()) {
        let step = if step == 1 && start >= end { -step } else { step };
        let nb_digits = usize::max(count_minimum_digits(start_str), count_minimum_digits(end_str));
        numeric_range(start, end, step, inclusive, nb_digits)
    } else if start_str.len() != 1 || end_str.len() != 1 {
        None
    } else {
        char_range(start_str.as_bytes()[0], end_str.as_bytes()[0], step, inclusive)
    }
}

// TODO: Make this an iterator structure.
// In a range we allow the following syntax:
//      Exclusive nonstepped: {start..end}
//      Inclusive nonstepped: {start...end}
//      Exclusive stepped: {start..step..end}
//      Inclusive stepped: {start..step...end}
pub fn parse_range(input: &str) -> Option<Box<Iterator<Item = small::String>>> {
    let mut parts = input.split("..").collect::<Vec<_>>();
    let len = parts.len();

    // if the last separator contains three dots, this can only be an inclusive range
    let inclusive = parts.last()?.starts_with(|c| c == '.' || c == '=');
    if inclusive {
        parts[len - 1] = parts[len - 1].trim_start_matches(|c| c == '.' || c == '=');
    }

    match len {
        // two parts means unstepped range
        2 => finish(inclusive, parts[0], parts[1], 1),
        // middle string contains the step size
        3 => finish(inclusive, parts[0], parts[2], parts[1].parse::<isize>().ok()?),
        // not a valid byte for ranges
        _ => None,
    }
}

pub fn parse_index_range(input: &str) -> Option<Range> {
    let mut parts = input.splitn(2, "..");
    let first = parts.next()?;
    let mut end = parts.next()?;

    if first.is_empty() && !end.is_empty() {
        end.parse::<isize>().map(|end| Range::to(Index::new(end))).ok()
    } else if !end.is_empty() {
        let inclusive = end.starts_with('.') || end.starts_with('=');
        if inclusive {
            end = &end[1..];
        }

        let start = first.parse::<isize>().ok()?;
        let end = end.parse::<isize>().ok()?;
        if inclusive {
            Some(Range::inclusive(Index::new(start), Index::new(end)))
        } else {
            Some(Range::exclusive(Index::new(start), Index::new(end)))
        }
    } else {
        first.parse::<isize>().map(|start| Range::from(Index::new(start))).ok()
    }
}
<|endoftext|>


<commit_before>/*!
 * # Expected behaviour:
 * Same as the box_vee3d demo.
 *
 * It seems to behave as expected if the excentricity is not too big (tested with 10 and 100).
 *
 * # Symptoms:
 * Some object just fall through the ground, missing any collison. Then, after a while they seem
 * to notice that they are deep into the plane, and "jump" due to penetration resolution.
 * Thus, some collision are missed.
 * Identically, some boxes just dont collide to each other some times.
 *
 * # Cause:
 * Not sure, but this seems to be an accuracy limitation of the contact manifold generators
 * (OneShotContactManifoldGenerator and IncrementalContactManifoldGenerator). The repetitive
 * transformations of the saved contact might invalidate them.
 *
 * However, this might be a real bug for some other non-accuracy-related reasons. For example, when
 * a box is deep on the plane without contact why does the one-shot contact manifold generator
 * fails? Something wrong with the perturbation?
 *
 * This might be (but it is very unlikely) a problem with the DBVT that might become invalid.
 * Though this seems very unlikely as the AABBs seem to be fine and the plane has an infinite aabb
 * anyway. Thurthermore, the ray-cast (which uses the dbvt…) works fine, even for "jumpy" objects.
 *
 *
 * # Solution:
 *
 *
 * # Limitations of the solution:
 *
 */

extern crate nalgebra as na;
extern crate ncollide;
extern crate nphysics3d;
extern crate nphysics_testbed3d;

use na::{Point3, Vector3, Translation3};
use ncollide::shape::{Plane, ConvexHull};
use ncollide::procedural;
use nphysics3d::world::World;
use nphysics3d::object::RigidBody;
use nphysics_testbed3d::Testbed;

fn main() {
    /*
     * World
     */
    let mut world = World::new();
    world.set_gravity(Vector3::new(0.0, -9.81, 0.0));

    /*
     * Plane
     */
    let geom = Plane::new(Vector3::new(0.0, 1.0, 0.0));

    world.add_rigid_body(RigidBody::new_static(geom, 0.3, 0.6));

    /*
     * Create the convex geometries.
     */
    let num     = 8;
    let shift   = 2.0;
    let centerx = shift * (num as f32) / 2.0;
    let centery = shift / 2.0;
    let centerz = shift * (num as f32) / 2.0;

    for i in 0usize .. num {
        for j in 0usize .. num {
            for k in 0usize .. num {
                let excentricity = 5000.0;
                let x = i as f32 * shift - centerx - excentricity;
                let y = j as f32 * shift + centery - excentricity;
                let z = k as f32 * shift - centerz - excentricity;

                let mut shape = procedural::cuboid(&Vector3::new(2.0 - 0.08, 2.0 - 0.08, 2.0 - 0.08));

                for c in shape.coords.iter_mut() {
                    *c = *c + Vector3::new(excentricity, excentricity, excentricity);
                }

                let geom = ConvexHull::new(shape.coords);
                let mut rb = RigidBody::new_dynamic(geom, 1.0, 0.3, 0.5);
                rb.set_deactivation_threshold(None);

                rb.append_translation(&Translation3::new(x, y, z));

                world.add_rigid_body(rb);
            }
        }
    }

    /*
     * Set up the testbed.
     */
    let mut testbed = Testbed::new(world);

    testbed.look_at(Point3::new(-30.0, 30.0, -30.0), Point3::new(0.0, 0.0, 0.0));
    testbed.run();
}
<commit_msg>Make bugged example compile again.<commit_after>/*!
 * # Expected behaviour:
 * Same as the box_vee3d demo.
 *
 * It seems to behave as expected if the excentricity is not too big (tested with 10 and 100).
 *
 * # Symptoms:
 * Some object just fall through the ground, missing any collison. Then, after a while they seem
 * to notice that they are deep into the plane, and "jump" due to penetration resolution.
 * Thus, some collision are missed.
 * Identically, some boxes just dont collide to each other some times.
 *
 * # Cause:
 * Not sure, but this seems to be an accuracy limitation of the contact manifold generators
 * (OneShotContactManifoldGenerator and IncrementalContactManifoldGenerator). The repetitive
 * transformations of the saved contact might invalidate them.
 *
 * However, this might be a real bug for some other non-accuracy-related reasons. For example, when
 * a box is deep on the plane without contact why does the one-shot contact manifold generator
 * fails? Something wrong with the perturbation?
 *
 * This might be (but it is very unlikely) a problem with the DBVT that might become invalid.
 * Though this seems very unlikely as the AABBs seem to be fine and the plane has an infinite aabb
 * anyway. Thurthermore, the ray-cast (which uses the dbvt…) works fine, even for "jumpy" objects.
 *
 *
 * # Solution:
 *
 *
 * # Limitations of the solution:
 *
 */

extern crate nalgebra as na;
extern crate ncollide;
extern crate nphysics3d;
extern crate nphysics_testbed3d;

use na::{Isometry3, Point3, Vector3};
use ncollide::shape::{ConvexHull, Cuboid, Plane, ShapeHandle};
use ncollide::procedural;
use nphysics3d::world::World;
use nphysics3d::object::{BodyHandle, Material};
use nphysics3d::volumetric::Volumetric;
use nphysics_testbed3d::Testbed;

const COLLIDER_MARGIN: f32 = 0.01;

fn main() {
    /*
     * World
     */
    let mut world = World::new();
    world.set_gravity(Vector3::new(0.0, -9.81, 0.0));

    /*
     * Ground
     */
    let ground_size = 50.0;
    let ground_shape =
        ShapeHandle::new(Cuboid::new(Vector3::repeat(ground_size - COLLIDER_MARGIN)));
    let ground_pos = Isometry3::new(Vector3::y() * -ground_size, na::zero());

    world.add_collider(
        COLLIDER_MARGIN,
        ground_shape,
        BodyHandle::ground(),
        ground_pos,
        Material::default(),
    );

    /*
     * Create the convex geometries.
     */
    let num = 8;
    let shift = 2.0;
    let excentricity = 5000.0f32;
    let centerx = shift * (num as f32) / 2.0;
    let centery = shift / 2.0;
    let centerz = shift * (num as f32) / 2.0;

    let mut cuboid_mesh = procedural::cuboid(&Vector3::new(2.0 - 0.08, 2.0 - 0.08, 2.0 - 0.08));

    for c in cuboid_mesh.coords.iter_mut() {
        *c = *c + Vector3::new(excentricity, excentricity, excentricity);
    }

    let indices: Vec<usize> = cuboid_mesh.flat_indices()
        .into_iter()
        .map(|i| i as usize)
        .collect();
    let vertices = cuboid_mesh.coords;

    for v in &vertices {
        println!("Vertex: {}", *v)
    }

    for i in indices.chunks(3) {
        println!("Index: {}, {}, {}", i[0], i[1], i[2])
    }
    println!("Original indices: {:?}", cuboid_mesh.indices);

    let geom = ShapeHandle::new(ConvexHull::try_new(vertices, &indices).unwrap());
    let inertia = geom.inertia(1.0);
    let center_of_mass = geom.center_of_mass();

    for i in 0usize..num {
        for j in 0usize..num {
            for k in 0usize..num {
                let x = i as f32 * shift - centerx - excentricity;
                let y = j as f32 * shift + centery - excentricity;
                let z = k as f32 * shift - centerz - excentricity;

                /*
                 * Create the rigid body.
                 */
                let pos = Isometry3::new(Vector3::new(x, y, z), na::zero());
                let handle = world.add_rigid_body(pos, inertia, center_of_mass);

                /*
                 * Create the collider.
                 */
                world.add_collider(
                    COLLIDER_MARGIN,
                    geom.clone(),
                    handle,
                    Isometry3::identity(),
                    Material::default(),
                );
            }
        }
    }

    /*
     * Set up the testbed.
     */
    let mut testbed = Testbed::new(world);

    testbed.look_at(Point3::new(-30.0, 30.0, -30.0), Point3::new(0.0, 0.0, 0.0));
    testbed.run();
}
<|endoftext|>


<commit_before>//! # Page table entry
//! Some code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html)

use memory::Frame;

use super::PhysicalAddress;

/// A page table entry
pub struct Entry(u64);

bitflags! {
    pub struct EntryFlags: u64 {
        const PRESENT =         1 << 0;
        const WRITABLE =        1 << 1;
        const USER_ACCESSIBLE = 1 << 2;
        const WRITE_THROUGH =   1 << 3;
        const NO_CACHE =        1 << 4;
        const ACCESSED =        1 << 5;
        const DIRTY =           1 << 6;
        const HUGE_PAGE =       1 << 7;
        const GLOBAL =          1 << 8;
        const NO_EXECUTE =      1 << 63;
    }
}

pub const ADDRESS_MASK: usize = 0x000f_ffff_ffff_f000;
pub const COUNTER_MASK: u64 = 0x3ff00000_00000000;

impl Entry {
    /// Zero entry
    pub fn set_zero(&mut self) {
        self.0 = 0;
    }

    /// Is the entry unused?
    pub fn is_unused(&self) -> bool {
        self.0 == (self.0 & COUNTER_MASK)
    }

    /// Make the entry unused
    pub fn set_unused(&mut self) {
        self.0 = self.0 & COUNTER_MASK;
    }

    /// Get the address this page references
    pub fn address(&self) -> PhysicalAddress {
        PhysicalAddress::new(self.0 as usize & ADDRESS_MASK)
    }

    /// Get the current entry flags
    pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    /// Get the associated frame, if available
    pub fn pointed_frame(&self) -> Option<Frame> {
        if self.flags().contains(EntryFlags::PRESENT) {
            Some(Frame::containing_address(self.address()))
        } else {
            None
        }
    }

    pub fn set(&mut self, frame: Frame, flags: EntryFlags) {
        debug_assert!(frame.start_address().get() & !ADDRESS_MASK == 0);
        self.0 = (frame.start_address().get() as u64) | flags.bits() | (self.0 & COUNTER_MASK);
    }

    /// Get bits 52-61 in entry, used as counter for page table
    pub fn counter_bits(&self) -> u64 {
        (self.0 & COUNTER_MASK) >> 52
    }

    /// Set bits 52-61 in entry, used as counter for page table
    pub fn set_counter_bits(&mut self, count: u64) {
        self.0 = (self.0 & !COUNTER_MASK) | (count << 52);
    }
}
<commit_msg>Better comment and mask representation<commit_after>//! # Page table entry
//! Some code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html)

use memory::Frame;

use super::PhysicalAddress;

/// A page table entry
pub struct Entry(u64);

bitflags! {
    pub struct EntryFlags: u64 {
        const PRESENT =         1 << 0;
        const WRITABLE =        1 << 1;
        const USER_ACCESSIBLE = 1 << 2;
        const WRITE_THROUGH =   1 << 3;
        const NO_CACHE =        1 << 4;
        const ACCESSED =        1 << 5;
        const DIRTY =           1 << 6;
        const HUGE_PAGE =       1 << 7;
        const GLOBAL =          1 << 8;
        const NO_EXECUTE =      1 << 63;
    }
}

pub const ADDRESS_MASK: usize = 0x000f_ffff_ffff_f000;
pub const COUNTER_MASK: u64 = 0x3ff0_0000_0000_0000;

impl Entry {
    /// Clear entry
    pub fn set_zero(&mut self) {
        self.0 = 0;
    }

    /// Is the entry unused?
    pub fn is_unused(&self) -> bool {
        self.0 == (self.0 & COUNTER_MASK)
    }

    /// Make the entry unused
    pub fn set_unused(&mut self) {
        self.0 = self.0 & COUNTER_MASK;
    }

    /// Get the address this page references
    pub fn address(&self) -> PhysicalAddress {
        PhysicalAddress::new(self.0 as usize & ADDRESS_MASK)
    }

    /// Get the current entry flags
    pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    /// Get the associated frame, if available
    pub fn pointed_frame(&self) -> Option<Frame> {
        if self.flags().contains(EntryFlags::PRESENT) {
            Some(Frame::containing_address(self.address()))
        } else {
            None
        }
    }

    pub fn set(&mut self, frame: Frame, flags: EntryFlags) {
        debug_assert!(frame.start_address().get() & !ADDRESS_MASK == 0);
        self.0 = (frame.start_address().get() as u64) | flags.bits() | (self.0 & COUNTER_MASK);
    }

    /// Get bits 52-61 in entry, used as counter for page table
    pub fn counter_bits(&self) -> u64 {
        (self.0 & COUNTER_MASK) >> 52
    }

    /// Set bits 52-61 in entry, used as counter for page table
    pub fn set_counter_bits(&mut self, count: u64) {
        self.0 = (self.0 & !COUNTER_MASK) | (count << 52);
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul,Add};
use num::traits::{Zero,One,Float};

#[derive(PartialEq,Debug)]
pub struct Vec3<T> where T: Mul<T, Output = T> + Add<T, Output = T> + Zero + Copy + Clone {
    x: T,
    y: T,
    z: T,
}

impl <T> Vec3<T> where T : Mul<T, Output = T> + Add<T, Output = T> + Zero + Copy + Clone {
    pub fn new(xx: T, yy: T, zz: T) -> Vec3<T> {
        Vec3 { x: xx, y: yy, z: zz }
    }

    pub fn zero() -> Vec3<T> {
        Vec3::new(T::zero(), T::zero(), T::zero())
    }

    pub fn diagonal(xx: T) -> Vec3<T> {
        Vec3::new(xx, xx, xx)
    }

    pub fn dot(self, rhs: Vec3<T>) -> T {
         return self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
    }
}

impl <T> Vec3<T> where T: Mul<T, Output=T> + One + Zero + Float + Clone + Copy {
    pub fn length(& self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
    }

    pub fn normalize(&mut self) {
        let length: T = self.length();
        if length > T::zero() {
            let inverse_length = T::one() / length;

            self.x = self.x * inverse_length;
            self.y = self.y * inverse_length;
            self.z = self.z * inverse_length;
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Vec3;

    #[test]
    fn should_be_created_with_constructor() {
        let v: Vec3<f64> = Vec3::new(0.0, 1.0, 2.0);

        assert_eq!(v, Vec3 { x: 0.0, y: 1.0, z: 2.0 });
    }

    #[test]
    fn should_initialize_to_zero_vector() {
        let v: Vec3<f64> = Vec3::zero();

        assert_eq!(v, Vec3::<f64>{ x: 0.0, y: 0.0, z: 0.0 });
    }

    #[test]
    fn should_initialize_to_diagonal_vector() {
        let v: Vec3<f64> = Vec3::diagonal(1.0);

        assert_eq!(v, Vec3::<f64>{ x: 1.0, y: 1.0, z: 1.0 });
    }

    #[test]
    fn should_know_dot_product() {
        let u: Vec3<f64> = Vec3::diagonal(1.0);
        let v: Vec3<f64> = Vec3::new(0.0, 1.0, 2.0);

        let dot_product: f64 = u.dot(v);

        assert_eq!(dot_product, 3.0);
    }

    #[test]
    fn should_know_its_length() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.length(), 0.0);
    }

    #[test]
    fn should_be_able_to_normalize() {
        let mut v: Vec3<f64> = Vec3::new(3.0, 0.0, 0.0);
        v.normalize();

        assert_eq!(v, Vec3 { x: 1.0, y: 0.0, z: 0.0 });
    }
}
<commit_msg>Create a cross product<commit_after>use std::ops::{Mul,Add,Sub};
use num::traits::{Zero,One,Float};

#[derive(PartialEq,Debug)]
pub struct Vec3<T> where T: Mul<T, Output = T> + Add<T, Output = T> + Sub<T, Output = T> + Zero + Copy + Clone {
    x: T,
    y: T,
    z: T,
}

impl <T> Vec3<T> where T : Mul<T, Output = T> + Add<T, Output = T> + Sub<T, Output = T> + Zero + Copy + Clone {
    pub fn new(xx: T, yy: T, zz: T) -> Vec3<T> {
        Vec3 { x: xx, y: yy, z: zz }
    }

    pub fn zero() -> Vec3<T> {
        Vec3::new(T::zero(), T::zero(), T::zero())
    }

    pub fn diagonal(xx: T) -> Vec3<T> {
        Vec3::new(xx, xx, xx)
    }

    pub fn dot(self, rhs: Vec3<T>) -> T {
         self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
    }

    pub fn cross(self, rhs: Vec3<T>) -> Vec3<T> {
        Vec3::new(
            self.y * rhs.z - self.z * rhs.y,
            self.z * rhs.x - self.x * rhs.z,
            self.x * rhs.y - self.y * rhs.x,
            )
    }
}

impl <T> Vec3<T> where T: Mul<T, Output=T> + One + Zero + Float + Clone + Copy {
    pub fn length(& self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
    }

    pub fn normalize(&mut self) {
        let length: T = self.length();
        if length > T::zero() {
            let inverse_length = T::one() / length;

            self.x = self.x * inverse_length;
            self.y = self.y * inverse_length;
            self.z = self.z * inverse_length;
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Vec3;

    #[test]
    fn should_be_created_with_constructor() {
        let v: Vec3<f64> = Vec3::new(0.0, 1.0, 2.0);

        assert_eq!(v, Vec3 { x: 0.0, y: 1.0, z: 2.0 });
    }

    #[test]
    fn should_initialize_to_zero_vector() {
        let v: Vec3<f64> = Vec3::zero();

        assert_eq!(v, Vec3::<f64>{ x: 0.0, y: 0.0, z: 0.0 });
    }

    #[test]
    fn should_initialize_to_diagonal_vector() {
        let v: Vec3<f64> = Vec3::diagonal(1.0);

        assert_eq!(v, Vec3::<f64>{ x: 1.0, y: 1.0, z: 1.0 });
    }

    #[test]
    fn should_know_dot_product() {
        let u: Vec3<f64> = Vec3::diagonal(1.0);
        let v: Vec3<f64> = Vec3::new(0.0, 1.0, 2.0);

        let dot_product: f64 = u.dot(v);

        assert_eq!(dot_product, 3.0);
    }

    #[test]
    fn should_know_its_length() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.length(), 0.0);
    }

    #[test]
    fn should_be_able_to_normalize() {
        let mut v: Vec3<f64> = Vec3::new(3.0, 0.0, 0.0);
        v.normalize();

        assert_eq!(v, Vec3 { x: 1.0, y: 0.0, z: 0.0 });
    }

    #[test]
    fn should_know_cross_product() {
        let v: Vec3<f64> = Vec3::new(1.0, 0.0, 0.0);
        let w: Vec3<f64> = Vec3::new(0.0, 1.0, 0.0);

        let product = v.cross(w);

        assert_eq!(product, Vec3 { x: 0.0, y: 0.0, z: 1.0 });
    }
}
<|endoftext|>


<commit_before>use libimagrt::runtime::Runtime;

pub fn delete(rt: &Runtime) {
}

<commit_msg>Implement Store::delete() interface<commit_after>use std::path::PathBuf;

use libimagrt::runtime::Runtime;

use util::build_entry_path;

pub fn delete(rt: &Runtime) {
    use std::process::exit;

    rt.cli()
        .subcommand_matches("delete")
        .map(|sub| {
            sub.value_of("id")
                .map(|id| {
                    debug!("Deleting file at {:?}", id);
                    rt.store()
                        .delete(build_entry_path(rt, id))
                        .map_err(|e| {
                           warn!("Error: {:?}", e);
                           exit(1);
                        })
                })
                .or_else(|| {
                    warn!("No ID passed. Will exit now");
                    exit(1);
                })
        })
        .or_else(|| {
            warn!("No subcommand 'delete'. Will exit now");
            exit(1);
        });
}

<|endoftext|>


<commit_before>use std::net::{SocketAddr, TcpListener, TcpStream};
use std::sync::mpsc;

enum InternalMessage {
    NewClient(SocketAddr, mpsc::SyncSender<Vec<u8>>),
    ClientDisconnected(SocketAddr),
    NewMessage(Vec<u8>),
}

fn handle_client_read(mut stream: TcpStream, sender: mpsc::Sender<InternalMessage>) -> ::std::io::Result<()> {
    use std::io::Read;
    loop {
        let mut buf = [0];
        try!(stream.read_exact(&mut buf[..]));
        let mut buf_body = vec![0; buf[0] as usize];
        try!(stream.read_exact(&mut buf_body[..]));
        sender.send(InternalMessage::NewMessage(buf_body));
    }
}

fn handle_client_write(mut stream: TcpStream, rx: mpsc::Receiver<Vec<u8>>) -> ::std::io::Result<()> {
    use std::io::Write;
    loop {
        match rx.recv() {
            Ok(m) => {
                try!(stream.write_all(&[m.len() as u8]));
                try!(stream.write_all(&m[..]));
            }
            Err(_) => {
                // assume disconnected
                break
            }
        }
    }
    Ok(())
}

fn run() -> Result<(), ::std::io::Error> {

    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 2 {
        println!("usage: {} HOST:PORT", args[0]);
        return Ok(());
    }

    let addr_str = &args[1];
    let addr = addr_str.parse::<::std::net::SocketAddr>().unwrap();
    let listener = try!(TcpListener::bind(addr));

    let (tx, rx) = mpsc::channel();
    // start "global state" thread.
    ::std::thread::spawn(move || {
        let mut clients =
            ::std::collections::HashMap::<SocketAddr, mpsc::SyncSender<Vec<u8>>>::new();
        loop {
            match rx.recv().expect("receive error") {
                InternalMessage::NewClient(addr, s) => {
                    clients.insert(addr, s);
                }
                InternalMessage::ClientDisconnected(addr) => {
                    clients.remove(&addr);
                }
                InternalMessage::NewMessage(v) => {
                    for (_, tx) in &clients {
                        // Try to send without blocking.
                        let _ = tx.try_send(v.clone());
                    }
                }
            }
        }
    });

    println!("listening on {}", addr_str);
    // accept connections and process them, spawning a new thread for each one
    for stream in listener.incoming() {
        let tx = tx.clone();
        match stream {
            Ok(stream) => {
                let (message_tx, message_rx) = mpsc::sync_channel(5);

                let peer_addr = try!(stream.peer_addr());
                tx.send(InternalMessage::NewClient(peer_addr, message_tx));

                let read_stream = try!(stream.try_clone());

                // start write thread
                ::std::thread::spawn(move|| {
                    handle_client_write(stream, message_rx)
                });

                // start read thread
                ::std::thread::spawn(move|| {
                    handle_client_read(read_stream, tx);
                });

            }
            Err(e) => { /* connection failed */ }
        }
    }

    Ok(())
}

pub fn main() {
    run().expect("top level error")
}
<commit_msg>clean up on disconnect<commit_after>use std::net::{SocketAddr, TcpListener, TcpStream};
use std::sync::mpsc;

enum InternalMessage {
    NewClient(SocketAddr, mpsc::SyncSender<Vec<u8>>),
    ClientDisconnected(SocketAddr),
    NewMessage(Vec<u8>),
}

struct DisconnectNotifier {
    peer_addr: SocketAddr,
    tx: mpsc::Sender<InternalMessage>,
}

impl Drop for DisconnectNotifier {
    fn drop(&mut self) {
        let _ = self.tx.send(InternalMessage::ClientDisconnected(self.peer_addr));
    }
}

fn handle_client_read(mut stream: TcpStream,
                      sender: mpsc::Sender<InternalMessage>,
                      peer_addr: SocketAddr)
                      -> ::std::io::Result<()>
{
    use std::io::Read;

    let _notifer = DisconnectNotifier { peer_addr: peer_addr, tx: sender.clone() };
    loop {
        let mut buf = [0];
        try!(stream.read_exact(&mut buf[..]));
        let mut buf_body = vec![0; buf[0] as usize];
        try!(stream.read_exact(&mut buf_body[..]));
        let _ = sender.send(InternalMessage::NewMessage(buf_body));
    }
}

fn handle_client_write(mut stream: TcpStream, rx: mpsc::Receiver<Vec<u8>>) -> ::std::io::Result<()> {
    use std::io::Write;
    loop {
        match rx.recv() {
            Ok(m) => {
                try!(stream.write_all(&[m.len() as u8]));
                try!(stream.write_all(&m[..]));
            }
            Err(_) => {
                // assume disconnected
                break
            }
        }
    }
    Ok(())
}

fn run() -> Result<(), ::std::io::Error> {

    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 2 {
        println!("usage: {} HOST:PORT", args[0]);
        return Ok(());
    }

    let addr_str = &args[1];
    let addr = addr_str.parse::<::std::net::SocketAddr>().unwrap();
    let listener = try!(TcpListener::bind(addr));

    let (tx, rx) = mpsc::channel();
    // start "global state" thread.
    ::std::thread::spawn(move || {
        let mut clients =
            ::std::collections::HashMap::<SocketAddr, mpsc::SyncSender<Vec<u8>>>::new();
        loop {
            match rx.recv() {
                Ok(InternalMessage::NewClient(addr, s)) => {
                    clients.insert(addr, s);
                }
                Ok(InternalMessage::ClientDisconnected(addr)) => {
                    clients.remove(&addr);
                }
                Ok(InternalMessage::NewMessage(v)) => {
                    for (_, tx) in &clients {
                        // Try to send without blocking.
                        let _ = tx.try_send(v.clone());
                    }
                }
                Err(_) => {
                    // No senders left, so no more work to do.
                    break;
                }
            }
        }
    });

    println!("listening on {}", addr_str);
    // accept connections and process them, spawning a new thread for each one
    for stream in listener.incoming() {
        let tx = tx.clone();
        match stream {
            Ok(stream) => {
                let (message_tx, message_rx) = mpsc::sync_channel(5);

                let peer_addr = try!(stream.peer_addr());
                let _ = tx.send(InternalMessage::NewClient(peer_addr, message_tx));

                let read_stream = try!(stream.try_clone());

                // start write thread
                ::std::thread::spawn(move|| {
                    let _ = handle_client_write(stream, message_rx);
                });

                // start read thread
                ::std::thread::spawn(move|| {
                    let _ = handle_client_read(read_stream, tx, peer_addr);
                });

            }
            Err(_e) => { /* connection failed */ }
        }
    }

    Ok(())
}

pub fn main() {
    run().expect("top level error")
}
<|endoftext|>


<commit_before>
extern crate debug;
extern crate lab;

use lab::units::Per;
use lab::units::Comp;

pub enum L1Cache {}
#[deriving(PartialEq)]
pub enum F32 {}
#[deriving(PartialEq)]
pub enum Byte {}
pub enum XY<T> {}
pub enum XYZ<T> {}
pub enum RGB<T> {}
pub enum RGBA<T> {}
pub enum Triangle<T> {}
pub enum Quad<T> {}

impl Comp<Byte> for L1Cache {
    fn comp() -> Per<Byte, L1Cache> {
        Per::kibi(32.0)
    }
}

impl<T> Comp<XY<T>> for Triangle<XY<T>> {
    fn comp() -> Per<XY<T>, Triangle<XY<T>>> {
        Per::new(3.0)
    }
}

impl<T> Comp<XYZ<T>> for Triangle<XYZ<T>> {
    fn comp() -> Per<XYZ<T>, Triangle<XYZ<T>>> {
        Per::new(3.0)
    }
}

impl<T> Comp<Triangle<T>> for Quad<Triangle<T>> {
    fn comp() -> Per<Triangle<T>, Quad<Triangle<T>>> {
        Per::new(2.0)
    }
}

impl Comp<Byte> for F32 {
    fn comp() -> Per<Byte, F32> {
        Per::new(4.0)
    }
}

impl<T> Comp<T> for XY<T> {
    fn comp() -> Per<T, XY<T>> {
        Per::new(2.0)
    }
}

impl<T> Comp<T> for XYZ<T> {
    fn comp() -> Per<T, XYZ<T>> {
        Per::new(3.0)
    }
}

impl<T> Comp<T> for RGB<T> {
    fn comp() -> Per<T, RGB<T>> {
        Per::new(3.0)
    }
}

impl<T> Comp<T> for RGBA<T> {
    fn comp() -> Per<T, RGBA<T>> {
        Per::new(4.0)
    }
}

fn per<T: Comp<U>, U, V: Comp<T>>() -> Per<U, V> {
    let u_per_t: Per<U, T> = Comp::comp();
    let t_per_v: Per<T, V> = Comp::comp();
    u_per_t * t_per_v
}

fn main() {
    let bytes_per_xy: Per<Byte, XY<F32>> = per();
    println!("{:?}", bytes_per_xy);

    let bytes_per_xyz: Per<Byte, XYZ<F32>> = per();
    println!("{:?}", bytes_per_xyz);

    let bytes_per_triangle: Per<Byte, Triangle<XY<F32>>>
        = bytes_per_xy * Comp::comp();
    println!("{:?}", bytes_per_triangle);
}

<commit_msg>Triangles per L1 cache<commit_after>
extern crate debug;
extern crate lab;

use lab::units::Per;
use lab::units::Comp;

pub enum L1Cache {}
#[deriving(PartialEq)]
pub enum F32 {}
#[deriving(PartialEq)]
pub enum Byte {}
pub enum XY<T> {}
pub enum XYZ<T> {}
pub enum RGB<T> {}
pub enum RGBA<T> {}
pub enum Triangle<T> {}
pub enum Quad<T> {}

impl Comp<Byte> for L1Cache {
    fn comp() -> Per<Byte, L1Cache> {
        Per::kibi(32.0)
    }
}

impl<T> Comp<XY<T>> for Triangle<XY<T>> {
    fn comp() -> Per<XY<T>, Triangle<XY<T>>> {
        Per::new(3.0)
    }
}

impl<T> Comp<XYZ<T>> for Triangle<XYZ<T>> {
    fn comp() -> Per<XYZ<T>, Triangle<XYZ<T>>> {
        Per::new(3.0)
    }
}

impl<T> Comp<Triangle<T>> for Quad<Triangle<T>> {
    fn comp() -> Per<Triangle<T>, Quad<Triangle<T>>> {
        Per::new(2.0)
    }
}

impl Comp<Byte> for F32 {
    fn comp() -> Per<Byte, F32> {
        Per::new(4.0)
    }
}

impl<T> Comp<T> for XY<T> {
    fn comp() -> Per<T, XY<T>> {
        Per::new(2.0)
    }
}

impl<T> Comp<T> for XYZ<T> {
    fn comp() -> Per<T, XYZ<T>> {
        Per::new(3.0)
    }
}

impl<T> Comp<T> for RGB<T> {
    fn comp() -> Per<T, RGB<T>> {
        Per::new(3.0)
    }
}

impl<T> Comp<T> for RGBA<T> {
    fn comp() -> Per<T, RGBA<T>> {
        Per::new(4.0)
    }
}

fn per<T: Comp<U>, U, V: Comp<T>>() -> Per<U, V> {
    let u_per_t: Per<U, T> = Comp::comp();
    let t_per_v: Per<T, V> = Comp::comp();
    u_per_t * t_per_v
}

fn main() {
    let bytes_per_xy: Per<Byte, XY<F32>> = per();
    println!("{:?}", bytes_per_xy);

    let bytes_per_xyz: Per<Byte, XYZ<F32>> = per();
    println!("{:?}", bytes_per_xyz);

    let bytes_per_triangle: Per<Byte, Triangle<XY<F32>>>
        = bytes_per_xy * Comp::comp();
    println!("{:?}", bytes_per_triangle);

    let bytes_per_l1cache: Per<Byte, L1Cache> = Comp::comp();
    println!("{:?}", bytes_per_l1cache);

    let triangles_per_l1cache = bytes_per_l1cache / bytes_per_triangle;
    println!("{:?}", triangles_per_l1cache);
}

<|endoftext|>


<commit_before>//! Extension trait and implementation for observing and action on streamed data.

use Data;
use dataflow::channels::pact::Pipeline;
use dataflow::{Stream, Scope};
use dataflow::operators::unary::Unary;

/// Methods to inspect records and batches of records on a stream.
pub trait Inspect<G: Scope, D: Data> {
    /// Creates a dataflow operator that calls the supplied function on each record.
    fn inspect<F: FnMut(&D)+'static>(&self, func: F) -> Self;
    /// Creates a dataflow operator that calls the supplied function on each timestamp and batch of records.
    fn inspect_batch<F: FnMut(&G::Timestamp, &[D])+'static>(&self, mut func: F) -> Self;
}

impl<G: Scope, D: Data> Inspect<G, D> for Stream<G, D> {
    fn inspect<F: FnMut(&D)+'static>(&self, mut func: F) -> Stream<G, D> {
        self.unary_stream(Pipeline, "Inspect", move |input, output| {
            input.for_each(|time, data| {
                for datum in data.iter() { func(datum); }
                output.session(&time).give_content(data);
            });
        })
    }

    fn inspect_batch<F: FnMut(&G::Timestamp, &[D])+'static>(&self, mut func: F) -> Stream<G, D> {
        self.unary_stream(Pipeline, "InspectBatch", move |input, output| {
            while let Some((time, data)) = input.next() {
                func(&time, &data[..]);
                output.session(&time).give_content(data);
            }
        })
    }
}
<commit_msg>added examples/doctests for inspect/inspect_batch<commit_after>//! Extension trait and implementation for observing and action on streamed data.

use Data;
use dataflow::channels::pact::Pipeline;
use dataflow::{Stream, Scope};
use dataflow::operators::unary::Unary;

/// Methods to inspect records and batches of records on a stream.
pub trait Inspect<G: Scope, D: Data> {
    /// Runs a supplied closure on each observed data element.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Map, Inspect};
    ///
    /// timely::example(|scope| {
    ///     (0..10).to_stream(scope)
    ///            .inspect(|x| println!("seen: {:?}", x));
    /// });
    /// ```
    fn inspect<F: FnMut(&D)+'static>(&self, func: F) -> Self;
    /// Runs a supplied closure on each observed data batch (time and data slice).
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Map, Inspect};
    ///
    /// timely::example(|scope| {
    ///     (0..10).to_stream(scope)
    ///            .inspect_batch(|t,xs| println!("seen at: {:?}\t{:?} records", t, xs.len()));
    /// });
    /// ```
    fn inspect_batch<F: FnMut(&G::Timestamp, &[D])+'static>(&self, mut func: F) -> Self;
}

impl<G: Scope, D: Data> Inspect<G, D> for Stream<G, D> {

    fn inspect<F: FnMut(&D)+'static>(&self, mut func: F) -> Stream<G, D> {
        self.unary_stream(Pipeline, "Inspect", move |input, output| {
            input.for_each(|time, data| {
                for datum in data.iter() { func(datum); }
                output.session(&time).give_content(data);
            });
        })
    }

    fn inspect_batch<F: FnMut(&G::Timestamp, &[D])+'static>(&self, mut func: F) -> Stream<G, D> {
        self.unary_stream(Pipeline, "InspectBatch", move |input, output| {
            while let Some((time, data)) = input.next() {
                func(&time, &data[..]);
                output.session(&time).give_content(data);
            }
        })
    }
}
<|endoftext|>


<commit_before>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

use acpi::Acpi;

use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::event::{self, EVENT_KEY, EventOption};
use common::memory;
use common::paging::Page;
use common::time::Duration;

use drivers::pci;
use drivers::pio::*;
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

pub use externs::*;

use graphics::display;

use programs::executor::execute;
use programs::scheme::*;

use scheduler::{Context, Regs, TSS};
use scheduler::context::context_switch;

use schemes::Url;
use schemes::arp::*;
use schemes::context::*;
use schemes::debug::*;
use schemes::ethernet::*;
use schemes::icmp::*;
use schemes::interrupt::*;
use schemes::ip::*;
use schemes::memory::*;
// use schemes::display::*;

use syscall::handle::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
/// ACPI
pub mod acpi;
/// Allocation
pub mod alloc_system;
/// Audio
pub mod audio;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Externs
pub mod externs;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Network
pub mod network;
/// Panic
pub mod panic;
/// Programs
pub mod programs;
/// Schemes
pub mod schemes;
/// Scheduling
pub mod scheduler;
/// Sync primatives
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 2250286,
};

/// Idle loop (active while idle)
unsafe fn idle_loop() {
    loop {
        asm!("cli" : : : : "intel", "volatile");

        let mut halt = true;

        for i in env().contexts.lock().iter() {
            if i.interrupted {
                halt = false;
                break;
            }
        }

        asm!("sti" : : : : "intel", "volatile");

        if halt {
            asm!("hlt" : : : : "intel", "volatile");
        }

        context_switch(false);
    }
}

/// Event poll loop
fn poll_loop() {
    loop {
        env().on_poll();

        unsafe { context_switch(false) };
    }
}

/// Event loop
fn event_loop() {
    {
        let mut console = env().console.lock();
        console.instant = false;
    }

    let mut cmd = String::new();
    loop {
        loop {
            let mut console = env().console.lock();
            match env().events.lock().pop_front() {
                Some(event) => {
                    if console.draw {
                        match event.to_option() {
                            EventOption::Key(key_event) => {
                                if key_event.pressed {
                                    match key_event.scancode {
                                        event::K_F2 => {
                                            console.draw = false;
                                        }
                                        event::K_BKSP => if !cmd.is_empty() {
                                            console.write(&[8]);
                                            cmd.pop();
                                        },
                                        _ => match key_event.character {
                                            '\0' => (),
                                            '\n' => {
                                                console.command = Some(cmd.clone());

                                                cmd.clear();
                                                console.write(&[10]);
                                            }
                                            _ => {
                                                cmd.push(key_event.character);
                                                console.write(&[key_event.character as u8]);
                                            }
                                        },
                                    }
                                }
                            }
                            _ => (),
                        }
                    } else {
                        if event.code == EVENT_KEY && event.b as u8 == event::K_F1 && event.c > 0 {
                            console.draw = true;
                            console.redraw = true;
                        } else {
                            // TODO: Magical orbital hack
                            unsafe {
                                for scheme in env().schemes.iter() {
                                    if (*scheme.get()).scheme() == "orbital" {
                                        (*scheme.get()).event(&event);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                None => break,
            }
        }

        {
            let mut console = env().console.lock();
            console.instant = false;
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(font_data: usize, tss_data: usize) {
    // Zero BSS, this initializes statics that are set to 0
    {
        extern {
            static mut __bss_start: u8;
            static mut __bss_end: u8;
        }

        let start_ptr = &mut __bss_start;
        let end_ptr = &mut __bss_end;

        if start_ptr as *const _ as usize <= end_ptr as *const _ as usize {
            let size = end_ptr as *const _ as usize - start_ptr as *const _ as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

    display::fonts = font_data;
    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());
            env.console.lock().draw = true;

            debug!("Redox {} bits\n", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.push(UnsafeCell::new(acpi));
            }

            *(env.clock_realtime.lock()) = Rtc::new().time();

            env.schemes.push(UnsafeCell::new(Ps2::new()));
            env.schemes.push(UnsafeCell::new(Serial::new(0x3F8, 0x4)));

            pci::pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box InterruptScheme));
            env.schemes.push(UnsafeCell::new(box MemoryScheme));
            // session.items.push(box RandomScheme);
            // session.items.push(box TimeScheme);

            env.schemes.push(UnsafeCell::new(box EthernetScheme));
            env.schemes.push(UnsafeCell::new(box ArpScheme));
            env.schemes.push(UnsafeCell::new(box IcmpScheme));
            env.schemes.push(UnsafeCell::new(box IpScheme { arp: Vec::new() }));
            // session.items.push(box DisplayScheme);

            Context::spawn("kpoll".to_string(),
            box move || {
                poll_loop();
            });

            Context::spawn("kevent".to_string(),
            box move || {
                event_loop();
            });

            Context::spawn("karp".to_string(),
            box move || {
                ArpScheme::reply_loop();
            });

            Context::spawn("kicmp".to_string(),
            box move || {
                IcmpScheme::reply_loop();
            });

            env.contexts.lock().enabled = true;

            if let Ok(mut resource) = Url::from_str("file:/schemes/").open() {
                let mut vec: Vec<u8> = Vec::new();
                let _ = resource.read_to_end(&mut vec);

                for folder in String::from_utf8_unchecked(vec).lines() {
                    if folder.ends_with('/') {
                        let scheme_item = SchemeItem::from_url(&Url::from_string("file:/schemes/"
                                                                                .to_string() +
                                                                                &folder));

                        env.schemes.push(UnsafeCell::new(scheme_item));
                    }
                }
            }

            Context::spawn("kinit".to_string(),
            box move || {
                {
                    let wd_c = "file:/\0";
                    do_sys_chdir(wd_c.as_ptr());

                    let stdio_c = "debug:\0";
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                }

                execute(Url::from_str("file:/apps/login/main.bin"), Vec::new());
                debug!("INIT: Failed to execute\n");

                loop {
                    context_switch(false);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Some(context) = contexts.current() {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                debug!("    {:>3}:", y * 8 * 4);
                for x in 0..8 {
                    debug!(" {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            unsafe { Pio8::new(0xA0).write(0x20) };
        }

        unsafe { Pio8::new(0x20).write(0x20) };
    }

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            let switch = {
                let mut contexts = ::env().contexts.lock();
                if let Some(mut context) = contexts.current_mut() {
                    context.slices -= 1;
                    context.slice_total += 1;
                    context.slices == 0
                } else {
                    false
                }
            };

            if switch {
                unsafe { context_switch(true) };
            }
        }
        i @ 0x21 ... 0x2F => env().on_irq(i as u8 - 0x20),
        0x80 => if ! syscall_handle(regs) {
            exception!("Unknown Syscall");
        },
        0xFF => {
            unsafe {
                init(regs.ax, regs.bx);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }
}
<commit_msg>Add CSO exception (for compatibility with older machines)<commit_after>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

use acpi::Acpi;

use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::event::{self, EVENT_KEY, EventOption};
use common::memory;
use common::paging::Page;
use common::time::Duration;

use drivers::pci;
use drivers::pio::*;
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

pub use externs::*;

use graphics::display;

use programs::executor::execute;
use programs::scheme::*;

use scheduler::{Context, Regs, TSS};
use scheduler::context::context_switch;

use schemes::Url;
use schemes::arp::*;
use schemes::context::*;
use schemes::debug::*;
use schemes::ethernet::*;
use schemes::icmp::*;
use schemes::interrupt::*;
use schemes::ip::*;
use schemes::memory::*;
// use schemes::display::*;

use syscall::handle::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
/// ACPI
pub mod acpi;
/// Allocation
pub mod alloc_system;
/// Audio
pub mod audio;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Externs
pub mod externs;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Network
pub mod network;
/// Panic
pub mod panic;
/// Programs
pub mod programs;
/// Schemes
pub mod schemes;
/// Scheduling
pub mod scheduler;
/// Sync primatives
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 2250286,
};

/// Idle loop (active while idle)
unsafe fn idle_loop() {
    loop {
        asm!("cli" : : : : "intel", "volatile");

        let mut halt = true;

        for i in env().contexts.lock().iter() {
            if i.interrupted {
                halt = false;
                break;
            }
        }

        asm!("sti" : : : : "intel", "volatile");

        if halt {
            asm!("hlt" : : : : "intel", "volatile");
        }

        context_switch(false);
    }
}

/// Event poll loop
fn poll_loop() {
    loop {
        env().on_poll();

        unsafe { context_switch(false) };
    }
}

/// Event loop
fn event_loop() {
    {
        let mut console = env().console.lock();
        console.instant = false;
    }

    let mut cmd = String::new();
    loop {
        loop {
            let mut console = env().console.lock();
            match env().events.lock().pop_front() {
                Some(event) => {
                    if console.draw {
                        match event.to_option() {
                            EventOption::Key(key_event) => {
                                if key_event.pressed {
                                    match key_event.scancode {
                                        event::K_F2 => {
                                            console.draw = false;
                                        }
                                        event::K_BKSP => if !cmd.is_empty() {
                                            console.write(&[8]);
                                            cmd.pop();
                                        },
                                        _ => match key_event.character {
                                            '\0' => (),
                                            '\n' => {
                                                console.command = Some(cmd.clone());

                                                cmd.clear();
                                                console.write(&[10]);
                                            }
                                            _ => {
                                                cmd.push(key_event.character);
                                                console.write(&[key_event.character as u8]);
                                            }
                                        },
                                    }
                                }
                            }
                            _ => (),
                        }
                    } else {
                        if event.code == EVENT_KEY && event.b as u8 == event::K_F1 && event.c > 0 {
                            console.draw = true;
                            console.redraw = true;
                        } else {
                            // TODO: Magical orbital hack
                            unsafe {
                                for scheme in env().schemes.iter() {
                                    if (*scheme.get()).scheme() == "orbital" {
                                        (*scheme.get()).event(&event);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                None => break,
            }
        }

        {
            let mut console = env().console.lock();
            console.instant = false;
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(font_data: usize, tss_data: usize) {
    // Zero BSS, this initializes statics that are set to 0
    {
        extern {
            static mut __bss_start: u8;
            static mut __bss_end: u8;
        }

        let start_ptr = &mut __bss_start;
        let end_ptr = &mut __bss_end;

        if start_ptr as *const _ as usize <= end_ptr as *const _ as usize {
            let size = end_ptr as *const _ as usize - start_ptr as *const _ as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

    display::fonts = font_data;
    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());
            env.console.lock().draw = true;

            debug!("Redox {} bits\n", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.push(UnsafeCell::new(acpi));
            }

            *(env.clock_realtime.lock()) = Rtc::new().time();

            env.schemes.push(UnsafeCell::new(Ps2::new()));
            env.schemes.push(UnsafeCell::new(Serial::new(0x3F8, 0x4)));

            pci::pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box InterruptScheme));
            env.schemes.push(UnsafeCell::new(box MemoryScheme));
            // session.items.push(box RandomScheme);
            // session.items.push(box TimeScheme);

            env.schemes.push(UnsafeCell::new(box EthernetScheme));
            env.schemes.push(UnsafeCell::new(box ArpScheme));
            env.schemes.push(UnsafeCell::new(box IcmpScheme));
            env.schemes.push(UnsafeCell::new(box IpScheme { arp: Vec::new() }));
            // session.items.push(box DisplayScheme);

            Context::spawn("kpoll".to_string(),
            box move || {
                poll_loop();
            });

            Context::spawn("kevent".to_string(),
            box move || {
                event_loop();
            });

            Context::spawn("karp".to_string(),
            box move || {
                ArpScheme::reply_loop();
            });

            Context::spawn("kicmp".to_string(),
            box move || {
                IcmpScheme::reply_loop();
            });

            env.contexts.lock().enabled = true;

            if let Ok(mut resource) = Url::from_str("file:/schemes/").open() {
                let mut vec: Vec<u8> = Vec::new();
                let _ = resource.read_to_end(&mut vec);

                for folder in String::from_utf8_unchecked(vec).lines() {
                    if folder.ends_with('/') {
                        let scheme_item = SchemeItem::from_url(&Url::from_string("file:/schemes/"
                                                                                .to_string() +
                                                                                &folder));

                        env.schemes.push(UnsafeCell::new(scheme_item));
                    }
                }
            }

            Context::spawn("kinit".to_string(),
            box move || {
                {
                    let wd_c = "file:/\0";
                    do_sys_chdir(wd_c.as_ptr());

                    let stdio_c = "debug:\0";
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                }

                execute(Url::from_str("file:/apps/login/main.bin"), Vec::new());
                debug!("INIT: Failed to execute\n");

                loop {
                    context_switch(false);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Some(context) = contexts.current() {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                debug!("    {:>3}:", y * 8 * 4);
                for x in 0..8 {
                    debug!(" {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            unsafe { Pio8::new(0xA0).write(0x20) };
        }

        unsafe { Pio8::new(0x20).write(0x20) };
    }

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            let switch = {
                let mut contexts = ::env().contexts.lock();
                if let Some(mut context) = contexts.current_mut() {
                    context.slices -= 1;
                    context.slice_total += 1;
                    context.slices == 0
                } else {
                    false
                }
            };

            if switch {
                unsafe { context_switch(true) };
            }
        }
        i @ 0x21 ... 0x2F => env().on_irq(i as u8 - 0x20),
        0x80 => if !syscall_handle(regs) {
            exception!("Unknown Syscall");
        },
        0xFF => {
            unsafe {
                init(regs.ax, regs.bx);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }
}
<|endoftext|>


<commit_before>use std::io::{FileAccess, FileMode, Open, Read, Truncate};
use std::io::{ReadWrite};
use std::io::{SeekEnd, SeekSet};
use std::io::fs::File;
use std::mem::size_of;
use std::io::Decorator;

static version: u8 = 1;

// some definitions from kissdb.h

struct Kissdb {
    hash_table_size : u64,
    key_size : u64,
    value_size : u64,
    num_hash_tables : u64,
    hash_tables : ~[u64],
    f : std::io::fs::File
}

enum OpenMode {
  ReadOnly,
  RW,
  RWCreate,
  RWReplace
}

fn kissdb_hash(b : &~[u8]) -> u64
{
    let mut hash : u64 = 5381;
    for &bx in b.iter() {
        hash = ((hash << 5) + hash) + (bx as u64);
    }
    return hash
}

fn kissdb_open(
    path : &Path,
    orig_mode : OpenMode,
    mut hash_table_size : u64,
    mut key_size : u64,
    mut value_size : u64
    ) -> Option<~ Kissdb>
{
    let (mode, access) : (FileMode, FileAccess) =
        match orig_mode {
            ReadOnly =>  (Open, Read), // rb
            RW => (Open, ReadWrite), // r+b
            RWCreate =>  (Open, ReadWrite), // r+b
            RWReplace => (Truncate, ReadWrite) // w+b
        };
    let mut f_ : Option<File>
        = std::io::fs::File::open_mode(path, mode, access);

    if f_.is_none() {
        match (orig_mode) {
            RWCreate =>
            f_ = std::io::fs::File::open_mode(path, Truncate, ReadWrite), // w+b
            _ => f_ = f_
        }
    };

    let mut f =
        match f_ {
            None => return None,
            Some (f) => f
        };
    let kissdb_header_size : u64 = ((size_of::<u64>() * 3) + 4) as u64;

    f.seek(0, SeekEnd);
    if (f.tell() < kissdb_header_size) {
        if hash_table_size > 0 && key_size > 0
            && value_size >0
        {
            f.seek(0, SeekSet);
            let tmp2 : [u8, ..4] = ['K' as u8, 'd' as u8, 'R' as u8, version];
            f.write(tmp2);
            f.write_le_u64(hash_table_size);
            f.write_le_u64(key_size);
            f.write_le_u64(value_size);
            f.flush();
        }
        else {
            fail!()
        }
    }
    else {
        f.seek(0, SeekSet);
        let mut tmp2 : [u8, ..4] = [0,0,0,0];
        if f.read(tmp2) != Some(4) { fail! (); }
        if tmp2 != ['K' as u8, 'd' as u8, 'R' as u8, version] {fail! ();}
        hash_table_size = f.read_le_u64();
        key_size = f.read_le_u64();
        value_size = f.read_le_u64();
    }

    let mut num_hash_tables = 0;

    let mut hash_tables : ~[u64] = std::vec::from_elem(0, 0 as u64);
    let mut h : Option<~[u64]>;

    // do we do realloc in rust? with append, apparently.
    while({h = f.read_one_hash_table(hash_table_size); h.is_some()})
    {
        let httmp = h.unwrap();
        hash_tables = std::vec::append(hash_tables, httmp);
        num_hash_tables = num_hash_tables + 1;
        if (httmp[hash_table_size] > 0) {
            f.seek(httmp[hash_table_size] as i64, SeekSet)
        }
        else {
            break;
        }
    }

    debug!("key_size = {:s}", key_size.to_str());

    return Some(~Kissdb {hash_table_size : hash_table_size,
                         key_size : key_size,
                         value_size : value_size,
                         num_hash_tables : num_hash_tables,
                         hash_tables : hash_tables,
                         f : f})
}

trait File2 {
    fn read_one_hash_table(&mut self, u64) -> Option<~[u64]>;
    fn write_one_hash_table(&mut self, &[u64]);
}

impl File2 for File {
    fn read_one_hash_table(&mut self,
                           hash_table_size : u64) -> Option<~[u64]> {
        let bs = (hash_table_size + 1) as uint * size_of::<u64>();
        let mut buf = std::vec::from_elem(bs, 0 as u8);
        let mut result = std::vec::from_elem((hash_table_size + 1) as uint, 0 as u64);
        match self.read(buf) {
            None => None,
            Some(buf_size) if buf_size == bs => {
                let mut br = std::io::mem::BufReader::new(buf);
                for i in range(0, hash_table_size + 1) {
                    result[i] = br.read_le_u64();
                }
                Some((result))
            },
            _ => None
        }
    }
    fn write_one_hash_table(&mut self,
                            ht : &[u64]) {
        for &x in ht.iter() {
            self.write_le_u64(x);
        }
    }
}

fn kissdb_close(~db : ~Kissdb) {
    //throwing away
}

trait Kdb {
    fn kissdb_get(&mut self, &~[u8]) -> Option<~[u8]>;
    fn kissdb_put(&mut self, key : &~[u8], value : &[u8]) -> bool;
}

impl Kdb for Kissdb {
    fn kissdb_get(&mut self, key : &~[u8]) -> Option<~[u8]> {
        if key.len() != self.key_size as uint { return None }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let hash_tables = &self.hash_tables;
        for i in range(0, self.num_hash_tables) {
            let offset : i64 = hash_tables[i * (self.hash_table_size + 1) + hash] as i64;
            if (offset == 0) { return None }; // yeah, 0 is being special. never used normally.
            self.f.seek(offset as i64, SeekSet);

            let klen = self.key_size as uint;
            // isn't compare available?? read_bytes available
            let tmp = self.f.read_bytes(klen);

            if std::vec::bytes::memcmp(key, &tmp) == 0 {
                return Some(self.f.read_bytes(self.value_size as uint))
            }
        }
        return None
    }

    fn kissdb_put(&mut self, key : &~[u8], value : &[u8]) -> bool
    {
        if key.len() != self.key_size as uint { fail!() }
        if value.len() != self.value_size as uint { fail!() }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let mut lasthtoffset : u64 = ((size_of::<u64>() * 3) + 4) as u64;
        let mut htoffset = lasthtoffset;

        for i in range(0, self.num_hash_tables) {
            let offset : i64 = self.hash_tables[(self.hash_table_size + 1) * i + hash] as i64;
		    if (offset != 0) { // yes, 0 is treated special. 0 will never used normally
			    /* rewrite if already exists */
                self.f.seek(offset, SeekSet);

			    let klen = self.key_size as uint;
                let tmp = self.f.read_bytes(klen);
                if std::vec::bytes::memcmp(key, &tmp) == 0 {
                    self.f.write(value);
				    self.f.flush();
				    return true; /* success */
                }
                // put_no_match_next_hash_table:
        	    lasthtoffset = htoffset;
		        htoffset = self.hash_tables[(self.hash_table_size + 1) * i + self.hash_table_size];
                //cmp != , should be put_no_match_next_hash_table
		    } else {
			    /* add if an empty hash table slot is discovered */
                self.f.seek(0, SeekEnd);
	            let endoffset : u64 = self.f.tell();

                // debug!("endoffset = {:s}",endoffset.to_str());
                self.f.write(*key);
                self.f.write(value);

                self.f.seek(htoffset as i64 + (size_of::<u64>() as i64 * hash as i64), SeekSet);
                self.f.write_le_u64(endoffset);
			    self.hash_tables[(self.hash_table_size + 1) * i + hash] = endoffset;

			    self.f.flush();

			    return true; /* success */
		    }
	    }

	    /* if no existing slots, add a new page of hash table entries */
        debug!("add new page");
        self.f.seek(0, SeekEnd);
	    let endoffset = self.f.tell();

        let mut new_table : ~[u64] = std::vec::from_elem(self.hash_table_size as uint + 1, 0 as u64);
        let hash_table_size_bytes : u64 = size_of::<u64>() as u64 * (self.hash_table_size + 1);
        new_table[hash] = endoffset + hash_table_size_bytes; // where key, value are to be written
        self.f.write_one_hash_table(new_table);
        let longer = std::vec::append(self.hash_tables.clone(), new_table); // slow!!
        self.hash_tables = longer;

        debug!("writing at {:s}",self.f.tell().to_str());
        self.f.write(*key);
        self.f.write(value);

	    if (self.num_hash_tables > 0) {
            self.f.seek(lasthtoffset as i64 + (size_of::<u64>() as i64 * self.hash_table_size as i64), SeekSet);
            self.f.write_le_u64(endoffset);
            // mimick rereading
            self.hash_tables[((self.hash_table_size + 1) * (self.num_hash_tables - 1)) + self.hash_table_size] = endoffset;
	    }

        self.num_hash_tables = self.num_hash_tables + 1;
        self.f.flush();
	    return true; /* success */
    }

}

fn main()
{
    println("Opening new empty database test.db...");
    let mut db = kissdb_open(&Path::new("test.db"), RWReplace, 1024, 8, size_of::<u64>() as u64).unwrap();

    println("Adding and then re-getting 10000 64-byte values...");

    let mut v : [u8, .. 8] = [0,0,0,0,0,0,0,0];

    for i in range(0, 10000) {
        for j in range(0, 8) {
            v[j] = i as u8;
        }
        let mut key = std::io::mem::MemWriter::new();
        key.write_le_u64(i as u64);
        db.kissdb_put(key.inner_ref(), v);
        let gotten = db.kissdb_get(key.inner_ref()).unwrap();
        for j in range(0, 8) {
            if gotten[j] != i as u8 { fail!() }
        }
    }

    println("Getting 10000 64-byte values...");

    for i in range(0, 10000) {
        let mut key = std::io::mem::MemWriter::new();
        key.write_le_u64(i as u64);
        let gotten = db.kissdb_get(key.inner_ref()).unwrap();
        for j in range(0,8) {
            if gotten[j] != i as u8 { fail!() }
        }
    }

    println("closing and re-opening database in read-only mode...");

    kissdb_close(db);

    let mut db = kissdb_open(&Path::new("test.db"), ReadOnly, 1024, 8, size_of::<u64>() as u64).unwrap();

    println("Getting 10000 64-byte values...");

    for i in range(0, 10000) {
        let mut key = std::io::mem::MemWriter::new();
        key.write_le_u64(i as u64);
        let gotten = db.kissdb_get(key.inner_ref()).unwrap();
        for j in range(0,8) {
            if gotten[j] != i as u8 { fail!() }
        }
    }

	println("Iterator not implemented ...");

    kissdb_close(db);

    println("All tests OK!");
}
<commit_msg>remove close<commit_after>use std::io::{FileAccess, FileMode, Open, Read, Truncate};
use std::io::{ReadWrite};
use std::io::{SeekEnd, SeekSet};
use std::io::fs::File;
use std::mem::size_of;
use std::io::Decorator;

static version: u8 = 1;

// some definitions from kissdb.h

struct Kissdb {
    hash_table_size : u64,
    key_size : u64,
    value_size : u64,
    num_hash_tables : u64,
    hash_tables : ~[u64],
    f : std::io::fs::File
}

enum OpenMode {
  ReadOnly,
  RW,
  RWCreate,
  RWReplace
}

fn kissdb_hash(b : &~[u8]) -> u64
{
    let mut hash : u64 = 5381;
    for &bx in b.iter() {
        hash = ((hash << 5) + hash) + (bx as u64);
    }
    return hash
}

fn kissdb_open(
    path : &Path,
    orig_mode : OpenMode,
    mut hash_table_size : u64,
    mut key_size : u64,
    mut value_size : u64
    ) -> Option<~ Kissdb>
{
    let (mode, access) : (FileMode, FileAccess) =
        match orig_mode {
            ReadOnly =>  (Open, Read), // rb
            RW => (Open, ReadWrite), // r+b
            RWCreate =>  (Open, ReadWrite), // r+b
            RWReplace => (Truncate, ReadWrite) // w+b
        };
    let mut f_ : Option<File>
        = std::io::fs::File::open_mode(path, mode, access);

    if f_.is_none() {
        match (orig_mode) {
            RWCreate =>
            f_ = std::io::fs::File::open_mode(path, Truncate, ReadWrite), // w+b
            _ => f_ = f_
        }
    };

    let mut f =
        match f_ {
            None => return None,
            Some (f) => f
        };
    let kissdb_header_size : u64 = ((size_of::<u64>() * 3) + 4) as u64;

    f.seek(0, SeekEnd);
    if (f.tell() < kissdb_header_size) {
        if hash_table_size > 0 && key_size > 0
            && value_size >0
        {
            f.seek(0, SeekSet);
            let tmp2 : [u8, ..4] = ['K' as u8, 'd' as u8, 'R' as u8, version];
            f.write(tmp2);
            f.write_le_u64(hash_table_size);
            f.write_le_u64(key_size);
            f.write_le_u64(value_size);
            f.flush();
        }
        else {
            fail!()
        }
    }
    else {
        f.seek(0, SeekSet);
        let mut tmp2 : [u8, ..4] = [0,0,0,0];
        if f.read(tmp2) != Some(4) { fail! (); }
        if tmp2 != ['K' as u8, 'd' as u8, 'R' as u8, version] {fail! ();}
        hash_table_size = f.read_le_u64();
        key_size = f.read_le_u64();
        value_size = f.read_le_u64();
    }

    let mut num_hash_tables = 0;

    let mut hash_tables : ~[u64] = std::vec::from_elem(0, 0 as u64);
    let mut h : Option<~[u64]>;

    // do we do realloc in rust? with append, apparently.
    while({h = f.read_one_hash_table(hash_table_size); h.is_some()})
    {
        let httmp = h.unwrap();
        hash_tables = std::vec::append(hash_tables, httmp);
        num_hash_tables = num_hash_tables + 1;
        if (httmp[hash_table_size] > 0) {
            f.seek(httmp[hash_table_size] as i64, SeekSet)
        }
        else {
            break;
        }
    }

    debug!("key_size = {:s}", key_size.to_str());

    return Some(~Kissdb {hash_table_size : hash_table_size,
                         key_size : key_size,
                         value_size : value_size,
                         num_hash_tables : num_hash_tables,
                         hash_tables : hash_tables,
                         f : f})
}

trait File2 {
    fn read_one_hash_table(&mut self, u64) -> Option<~[u64]>;
    fn write_one_hash_table(&mut self, &[u64]);
}

impl File2 for File {
    fn read_one_hash_table(&mut self,
                           hash_table_size : u64) -> Option<~[u64]> {
        let bs = (hash_table_size + 1) as uint * size_of::<u64>();
        let mut buf = std::vec::from_elem(bs, 0 as u8);
        let mut result = std::vec::from_elem((hash_table_size + 1) as uint, 0 as u64);
        match self.read(buf) {
            None => None,
            Some(buf_size) if buf_size == bs => {
                let mut br = std::io::mem::BufReader::new(buf);
                for i in range(0, hash_table_size + 1) {
                    result[i] = br.read_le_u64();
                }
                Some((result))
            },
            _ => None
        }
    }
    fn write_one_hash_table(&mut self,
                            ht : &[u64]) {
        for &x in ht.iter() {
            self.write_le_u64(x);
        }
    }
}

trait Kdb {
    fn kissdb_get(&mut self, &~[u8]) -> Option<~[u8]>;
    fn kissdb_put(&mut self, key : &~[u8], value : &[u8]) -> bool;
}

impl Kdb for Kissdb {
    fn kissdb_get(&mut self, key : &~[u8]) -> Option<~[u8]> {
        if key.len() != self.key_size as uint { return None }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let hash_tables = &self.hash_tables;
        for i in range(0, self.num_hash_tables) {
            let offset : i64 = hash_tables[i * (self.hash_table_size + 1) + hash] as i64;
            if (offset == 0) { return None }; // yeah, 0 is being special. never used normally.
            self.f.seek(offset as i64, SeekSet);

            let klen = self.key_size as uint;
            // isn't compare available?? read_bytes available
            let tmp = self.f.read_bytes(klen);

            if std::vec::bytes::memcmp(key, &tmp) == 0 {
                return Some(self.f.read_bytes(self.value_size as uint))
            }
        }
        return None
    }

    fn kissdb_put(&mut self, key : &~[u8], value : &[u8]) -> bool
    {
        if key.len() != self.key_size as uint { fail!() }
        if value.len() != self.value_size as uint { fail!() }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let mut lasthtoffset : u64 = ((size_of::<u64>() * 3) + 4) as u64;
        let mut htoffset = lasthtoffset;

        for i in range(0, self.num_hash_tables) {
            let offset : i64 = self.hash_tables[(self.hash_table_size + 1) * i + hash] as i64;
		    if (offset != 0) { // yes, 0 is treated special. 0 will never used normally
			    /* rewrite if already exists */
                self.f.seek(offset, SeekSet);

			    let klen = self.key_size as uint;
                let tmp = self.f.read_bytes(klen);
                if std::vec::bytes::memcmp(key, &tmp) == 0 {
                    self.f.write(value);
				    self.f.flush();
				    return true; /* success */
                }
                // put_no_match_next_hash_table:
        	    lasthtoffset = htoffset;
		        htoffset = self.hash_tables[(self.hash_table_size + 1) * i + self.hash_table_size];
                //cmp != , should be put_no_match_next_hash_table
		    } else {
			    /* add if an empty hash table slot is discovered */
                self.f.seek(0, SeekEnd);
	            let endoffset : u64 = self.f.tell();

                // debug!("endoffset = {:s}",endoffset.to_str());
                self.f.write(*key);
                self.f.write(value);

                self.f.seek(htoffset as i64 + (size_of::<u64>() as i64 * hash as i64), SeekSet);
                self.f.write_le_u64(endoffset);
			    self.hash_tables[(self.hash_table_size + 1) * i + hash] = endoffset;

			    self.f.flush();

			    return true; /* success */
		    }
	    }

	    /* if no existing slots, add a new page of hash table entries */
        debug!("add new page");
        self.f.seek(0, SeekEnd);
	    let endoffset = self.f.tell();

        let mut new_table : ~[u64] = std::vec::from_elem(self.hash_table_size as uint + 1, 0 as u64);
        let hash_table_size_bytes : u64 = size_of::<u64>() as u64 * (self.hash_table_size + 1);
        new_table[hash] = endoffset + hash_table_size_bytes; // where key, value are to be written
        self.f.write_one_hash_table(new_table);
        let longer = std::vec::append(self.hash_tables.clone(), new_table); // slow!!
        self.hash_tables = longer;

        debug!("writing at {:s}",self.f.tell().to_str());
        self.f.write(*key);
        self.f.write(value);

	    if (self.num_hash_tables > 0) {
            self.f.seek(lasthtoffset as i64 + (size_of::<u64>() as i64 * self.hash_table_size as i64), SeekSet);
            self.f.write_le_u64(endoffset);
            // mimick rereading
            self.hash_tables[((self.hash_table_size + 1) * (self.num_hash_tables - 1)) + self.hash_table_size] = endoffset;
	    }

        self.num_hash_tables = self.num_hash_tables + 1;
        self.f.flush();
	    return true; /* success */
    }

}

fn main()
{
    println("Opening new empty database test.db...");
    {
        let mut db = kissdb_open(&Path::new("test.db"), RWReplace, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Adding and then re-getting 10000 64-byte values...");

        let mut v : [u8, .. 8] = [0,0,0,0,0,0,0,0];

        for i in range(0, 10000) {
            for j in range(0, 8) {
                v[j] = i as u8;
            }
            let mut key = std::io::mem::MemWriter::new();
            key.write_le_u64(i as u64);
            db.kissdb_put(key.inner_ref(), v);
            let gotten = db.kissdb_get(key.inner_ref()).unwrap();
            for j in range(0, 8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = std::io::mem::MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner_ref()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }

        println("closing and re-opening database in read-only mode...");
    }

    {
        let mut db = kissdb_open(&Path::new("test.db"), ReadOnly, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = std::io::mem::MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner_ref()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
    }

	println("Iterator not implemented ...");

    println("All tests OK!");
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;

fn part1() -> i32 {
    let f = File::open("input.txt").unwrap();
    let file = BufReader::new(&f);
    let mut floor:i32 = 0;
    for line in file.lines() {
        for c in line.unwrap().chars() {
            match c.to_string().as_ref() {
                "(" => floor += 1,
                ")" => floor -= 1,
                _ => panic!()
            }
        }
    }
    floor
}

fn part2() {}

pub fn main() {
    println!("part 1: {}", part1());
}<commit_msg>day 1 part 2 rust solution<commit_after>use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;

fn part1() -> i32 {
    let file = BufReader::new(File::open("input.txt").unwrap());
    let mut floor:i32 = 0;
    for line in file.lines() {
        for c in line.unwrap().chars() {
            match c.to_string().as_ref() {
                "(" => floor += 1,
                ")" => floor -= 1,
                _ => panic!()
            }
        }
    }
    floor
}

fn part2() -> Option<i32> {
    let file = BufReader::new(File::open("input.txt").unwrap());
    let mut floor :i32 = 0;
    let mut n :i32 = 1;
    for line in file.lines() {
        for c in line.unwrap().chars() {
            match c.to_string().as_ref() {
                "(" => floor += 1,
                ")" => floor -= 1,
                _ => panic!()
            }
            if floor == -1 {
                return Some(n);
            }
            n += 1;
        }
    }
    None
}

pub fn main() {
    println!("part 1: {}", part1());
    println!("part 2: {}", part2().unwrap());
}<|endoftext|>