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

use std::rc::Rc;
use std::iter::FromIterator;
use syntax::ast;
use syntax::ptr::P;
use syntax::ast_util::empty_generics;
use syntax::codemap::{DUMMY_SP, dummy_spanned};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::parse::token;

use node;
use super::Builder;
use super::utils;

enum RegOrPadding<'a> {
  /// A register
  Reg(&'a node::Reg),
  /// A given number of bytes of padding
  Pad(u64)
}

/// An iterator which takes a potentially unsorted list of registers,
/// sorts them, and adds padding to make offsets correct
struct PaddedRegsIterator<'a> {
  sorted_regs: &'a Vec<node::Reg>,
  index: usize,
  last_offset: u64,
}

impl<'a> PaddedRegsIterator<'a> {
  fn new(regs: &'a mut Vec<node::Reg>) -> PaddedRegsIterator<'a> {
    regs.sort_by(|r1,r2| r1.offset.cmp(&r2.offset));
    PaddedRegsIterator {
      sorted_regs: regs,
      index: 0,
      last_offset: 0,
    }
  }
}

impl<'a> Iterator for PaddedRegsIterator<'a> {
  type Item = RegOrPadding<'a>;
  fn next(&mut self) -> Option<RegOrPadding<'a>> {
    if self.index >= self.sorted_regs.len() {
      None
    } else {
      let ref reg = self.sorted_regs[self.index];
      if reg.offset > self.last_offset {
        let pad_length = reg.offset - self.last_offset;
        self.last_offset = reg.offset;
        Some(RegOrPadding::Pad(pad_length))
      } else {
        self.index += 1;
        self.last_offset += reg.size();
        Some(RegOrPadding::Reg(reg))
      }
    }
  }
}

/// Build types for `RegUnions`
pub struct BuildUnionTypes<'a> {
  builder: &'a mut Builder,
  cx: &'a ExtCtxt<'a>
}

impl<'a> BuildUnionTypes<'a> {
  pub fn new(builder: &'a mut Builder, cx: &'a ExtCtxt<'a>)
      -> BuildUnionTypes<'a> {
    BuildUnionTypes { builder: builder, cx: cx }
  }
}

fn expr_u64(cx: &ExtCtxt, n: u64) -> P<ast::Expr> {
  cx.expr_lit(DUMMY_SP, ast::LitInt(n as u64, ast::UnsignedIntLit(ast::TyUs(false))))
}

/// Returns the type of the field representing the given register
/// within a `RegGroup` struct
fn reg_struct_type(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg)
                   -> P<ast::Ty> {
  let base_ty_path = cx.path_ident(DUMMY_SP, utils::path_ident(cx, path));
  let base_ty: P<ast::Ty> = cx.ty_path(base_ty_path);
  match reg.count.node {
    1 => base_ty,
    n =>
      cx.ty(DUMMY_SP,
            ast::TyFixedLengthVec(base_ty, expr_u64(cx, n as u64))),
  }
}

impl<'a> node::RegVisitor for BuildUnionTypes<'a> {
  fn visit_union_reg<'b>(&'b mut self, path: &Vec<String>, reg: &'b node::Reg,
                         subregs: Rc<Vec<node::Reg>>) {
    let union_type = self.build_union_type(path, reg, &*subregs);
    let ty_name = union_type.ident.clone();
    self.builder.push_item(union_type);
  }
}

impl<'a> BuildUnionTypes<'a> {
  /// Produce a field for the given register in a `RegUnion` struct
  fn build_reg_union_field(&self, path: &Vec<String>, reg: &node::Reg)
                           -> ast::StructField {
    let attrs = match reg.docstring {
      Some(doc) => vec!(utils::doc_attribute(self.cx, token::get_ident(doc.node))),
      None => Vec::new(),
    };
    let mut field_path = path.clone();
    field_path.push(reg.name.node.clone());
    dummy_spanned(
      ast::StructField_ {
        kind: ast::NamedField(
          self.cx.ident_of(reg.name.node.as_slice()),
          ast::Public),
        id: ast::DUMMY_NODE_ID,
        ty: reg_struct_type(self.cx, &field_path, reg),
        attrs: attrs,
      }
    )
  }

  /// Build field for padding or a register
  fn build_pad_or_reg(&self, path: &Vec<String>, reg_or_pad: RegOrPadding,
                      index: usize) -> ast::StructField {
    match reg_or_pad {
      RegOrPadding::Reg(reg) => self.build_reg_union_field(path, reg),
      RegOrPadding::Pad(length) => {
        let u8_path = self.cx.path_ident(
          DUMMY_SP,
          self.cx.ident_of("u8"));
        let u8_ty: P<ast::Ty> = self.cx.ty_path(u8_path);
        let ty: P<ast::Ty> =
          self.cx.ty(
            DUMMY_SP,
            ast::TyFixedLengthVec(u8_ty, expr_u64(self.cx, length)));
        dummy_spanned(
          ast::StructField_ {
            kind: ast::NamedField(
              self.cx.ident_of(format!("_pad{}", index).as_slice()),
              ast::Inherited),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: Vec::new(),
          },
        )
      },
    }
  }

  /// Build the type associated with a register group
  fn build_union_type(&self, path: &Vec<String>, reg: &node::Reg,
                      regs: &Vec<node::Reg>) -> P<ast::Item> {
    let name = String::from_str(
        token::get_ident(utils::path_ident(self.cx, path)).get());
    // Registers are already sorted by parser
    let mut regs = regs.clone();
    let padded_regs = PaddedRegsIterator::new(&mut regs);
    let fields =
      padded_regs.enumerate().map(|(n,r)| self.build_pad_or_reg(path, r, n));
    let struct_def = ast::StructDef {
      fields: FromIterator::from_iter(fields),
      ctor_id: None,
    };
    let mut attrs: Vec<ast::Attribute> = vec!(
      utils::list_attribute(self.cx, "allow",
                            vec!("non_camel_case_types",
                                 "dead_code",
                                 "missing_docs")),
    );
    match reg.docstring {
      Some(docstring) =>
        attrs.push(
          utils::doc_attribute(self.cx, token::get_ident(docstring.node))),
      None => (),
    }
    P(ast::Item {
      ident: self.cx.ident_of(name.as_slice()),
      attrs: attrs,
      id: ast::DUMMY_NODE_ID,
      node: ast::ItemStruct(P(struct_def), empty_generics()),
      vis: ast::Public,
      span: reg.name.span,
    })
  }
}
<commit_msg>ioreg::builder::union: Give unions Copy impls<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::rc::Rc;
use std::iter::FromIterator;
use syntax::ast;
use syntax::ptr::P;
use syntax::ast_util::empty_generics;
use syntax::codemap::{DUMMY_SP, dummy_spanned};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::parse::token;

use node;
use super::Builder;
use super::utils;

enum RegOrPadding<'a> {
  /// A register
  Reg(&'a node::Reg),
  /// A given number of bytes of padding
  Pad(u64)
}

/// An iterator which takes a potentially unsorted list of registers,
/// sorts them, and adds padding to make offsets correct
struct PaddedRegsIterator<'a> {
  sorted_regs: &'a Vec<node::Reg>,
  index: usize,
  last_offset: u64,
}

impl<'a> PaddedRegsIterator<'a> {
  fn new(regs: &'a mut Vec<node::Reg>) -> PaddedRegsIterator<'a> {
    regs.sort_by(|r1,r2| r1.offset.cmp(&r2.offset));
    PaddedRegsIterator {
      sorted_regs: regs,
      index: 0,
      last_offset: 0,
    }
  }
}

impl<'a> Iterator for PaddedRegsIterator<'a> {
  type Item = RegOrPadding<'a>;
  fn next(&mut self) -> Option<RegOrPadding<'a>> {
    if self.index >= self.sorted_regs.len() {
      None
    } else {
      let ref reg = self.sorted_regs[self.index];
      if reg.offset > self.last_offset {
        let pad_length = reg.offset - self.last_offset;
        self.last_offset = reg.offset;
        Some(RegOrPadding::Pad(pad_length))
      } else {
        self.index += 1;
        self.last_offset += reg.size();
        Some(RegOrPadding::Reg(reg))
      }
    }
  }
}

/// Build types for `RegUnions`
pub struct BuildUnionTypes<'a> {
  builder: &'a mut Builder,
  cx: &'a ExtCtxt<'a>
}

impl<'a> BuildUnionTypes<'a> {
  pub fn new(builder: &'a mut Builder, cx: &'a ExtCtxt<'a>)
      -> BuildUnionTypes<'a> {
    BuildUnionTypes { builder: builder, cx: cx }
  }
}

fn expr_u64(cx: &ExtCtxt, n: u64) -> P<ast::Expr> {
  cx.expr_lit(DUMMY_SP, ast::LitInt(n as u64, ast::UnsignedIntLit(ast::TyUs(false))))
}

/// Returns the type of the field representing the given register
/// within a `RegGroup` struct
fn reg_struct_type(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg)
                   -> P<ast::Ty> {
  let base_ty_path = cx.path_ident(DUMMY_SP, utils::path_ident(cx, path));
  let base_ty: P<ast::Ty> = cx.ty_path(base_ty_path);
  match reg.count.node {
    1 => base_ty,
    n =>
      cx.ty(DUMMY_SP,
            ast::TyFixedLengthVec(base_ty, expr_u64(cx, n as u64))),
  }
}

impl<'a> node::RegVisitor for BuildUnionTypes<'a> {
  fn visit_union_reg<'b>(&'b mut self, path: &Vec<String>, reg: &'b node::Reg,
                         subregs: Rc<Vec<node::Reg>>) {
    let items = self.build_union_type(path, reg, &*subregs);
    for item in items.into_iter() {
      self.builder.push_item(item);
    }
  }
}

impl<'a> BuildUnionTypes<'a> {
  /// Produce a field for the given register in a `RegUnion` struct
  fn build_reg_union_field(&self, path: &Vec<String>, reg: &node::Reg)
                           -> ast::StructField {
    let attrs = match reg.docstring {
      Some(doc) => vec!(utils::doc_attribute(self.cx, token::get_ident(doc.node))),
      None => Vec::new(),
    };
    let mut field_path = path.clone();
    field_path.push(reg.name.node.clone());
    dummy_spanned(
      ast::StructField_ {
        kind: ast::NamedField(
          self.cx.ident_of(reg.name.node.as_slice()),
          ast::Public),
        id: ast::DUMMY_NODE_ID,
        ty: reg_struct_type(self.cx, &field_path, reg),
        attrs: attrs,
      }
    )
  }

  /// Build field for padding or a register
  fn build_pad_or_reg(&self, path: &Vec<String>, reg_or_pad: RegOrPadding,
                      index: usize) -> ast::StructField {
    match reg_or_pad {
      RegOrPadding::Reg(reg) => self.build_reg_union_field(path, reg),
      RegOrPadding::Pad(length) => {
        let u8_path = self.cx.path_ident(
          DUMMY_SP,
          self.cx.ident_of("u8"));
        let u8_ty: P<ast::Ty> = self.cx.ty_path(u8_path);
        let ty: P<ast::Ty> =
          self.cx.ty(
            DUMMY_SP,
            ast::TyFixedLengthVec(u8_ty, expr_u64(self.cx, length)));
        dummy_spanned(
          ast::StructField_ {
            kind: ast::NamedField(
              self.cx.ident_of(format!("_pad{}", index).as_slice()),
              ast::Inherited),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: Vec::new(),
          },
        )
      },
    }
  }

  /// Build the type associated with a register group
  fn build_union_type(&self, path: &Vec<String>, reg: &node::Reg,
                      regs: &Vec<node::Reg>) -> Vec<P<ast::Item>> {
    let name = utils::path_ident(self.cx, path);
    // Registers are already sorted by parser
    let mut regs = regs.clone();
    let padded_regs = PaddedRegsIterator::new(&mut regs);
    let fields =
      padded_regs.enumerate().map(|(n,r)| self.build_pad_or_reg(path, r, n));
    let struct_def = ast::StructDef {
      fields: FromIterator::from_iter(fields),
      ctor_id: None,
    };
    let mut attrs: Vec<ast::Attribute> = vec!(
      utils::list_attribute(self.cx, "allow",
                            vec!("non_camel_case_types",
                                 "dead_code",
                                 "missing_docs")),
    );
    match reg.docstring {
      Some(docstring) =>
        attrs.push(
          utils::doc_attribute(self.cx, token::get_ident(docstring.node))),
      None => (),
    }
    let struct_item = P(ast::Item {
      ident: name,
      attrs: attrs,
      id: ast::DUMMY_NODE_ID,
      node: ast::ItemStruct(P(struct_def), empty_generics()),
      vis: ast::Public,
      span: reg.name.span,
    });
    let copy_impl = quote_item!(self.cx, impl ::core::marker::Copy for $name {}).unwrap();
    vec!(struct_item, copy_impl)
  }
}
<|endoftext|>


<commit_before>use memory::Frame;

pub struct Entry(u64);

impl Entry {
    pub fn unused(&self) -> bool {
        self.0 == 0
    }

    pub fn set_unused(&mut self) {
        self.0 = 0;
    }

    pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    pub fn pointed_frame(&self) -> Option<Frame> {
        if self.flags().contains(PRESENT) {
            Some(Frame::containing_address(self.0 as usize & 0x000fffff_fffff000))
        } else {
            None
        }
    }

    pub fn set(&mut self, frame: Frame, flags: EntryFlags) {
        let frame_addr = (frame.number << 12) & 0x000fffff_fffff000;
        self.0 = (frame_addr as u64) | flags.bits();
    }
}

bitflags! {
    flags 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,
    }
}
<commit_msg>Add `Frame::start_address`<commit_after>use memory::Frame;
use memory::paging::PhysicalAddress;

pub struct Entry(u64);

impl Entry {
    pub fn unused(&self) -> bool {
        self.0 == 0
    }

    pub fn set_unused(&mut self) {
        self.0 = 0;
    }

    pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    pub fn pointed_frame(&self) -> Option<Frame> {
        if self.flags().contains(PRESENT) {
            Some(Frame::containing_address(self.0 as usize & 0x000fffff_fffff000))
        } else {
            None
        }
    }

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

bitflags! {
    flags 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,
    }
}

impl Frame {
    fn start_address(&self) -> PhysicalAddress {
        self.number << 12
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::ops::{Add, Range, Sub};

use take_mut;

#[derive(Debug)]
pub struct ScheduleTree<'a, T: 'a, D: 'a> {
    root: Option<Node<'a, T, D>>,
    scope: Option<Range<T>>,
}

#[derive(Debug, PartialEq)]
enum Node<'a, T: 'a, D: 'a> {
    Leaf { start: T, end: T, data: &'a D },
    Intermediate {
        left: Box<Node<'a, T, D>>,
        right: Box<Node<'a, T, D>>,
        free: Range<T>,
    },
}

impl<'a, T: Copy + Clone + Ord + Debug, D: Debug> ScheduleTree<'a, T, D> {
    pub fn new() -> Self {
        ScheduleTree {
            root: None,
            scope: None,
        }
    }

    pub fn schedule_exact<W>(&mut self, start: T, duration: W, data: &'a D) -> bool
        where T: Add<W, Output = T> + Sub<T, Output = W> + Sub<W, Output = T>,
              W: Add<W, Output = W> + Add<T, Output = T> + Sub<W, Output = W>
    {
        let end = start + duration;
        let new_node = Node::Leaf {
            start: start,
            end: end,
            data: data,
        };

        if self.root.is_none() {
            self.root = Some(new_node);
            self.scope = Some(start..end);
            return true;
        }

        let scope = self.scope.as_ref().cloned().unwrap();
        if end <= scope.start {
            let root = self.root.take().unwrap();
            self.root = Some(Node::Intermediate {
                left: Box::new(new_node),
                right: Box::new(root),
                free: end..scope.start,
            });
            self.scope = Some(start..scope.end);
            return true;
        } else if scope.end <= start {
            let root = self.root.take().unwrap();
            self.root = Some(Node::Intermediate {
                left: Box::new(root),
                right: Box::new(new_node),
                free: scope.end..start,
            });
            self.scope = Some(scope.start..end);
            return true;
        }

        self.root.as_mut().unwrap().insert(start, end, new_node)
    }

    pub fn schedule_after<W>(&self, start: T, duration: W, max_end: Option<T>, data: &'a D) -> bool
        where T: Add<W, Output = T> + Sub<T, Output = W> + Sub<W, Output = T>,
              W: Add<W, Output = W> + Add<T, Output = T> + Sub<W, Output = W> + Copy
    {
        assert!(max_end.map_or(true, |max_end| start + duration <= max_end));
        // TODO schedule
        true
    }
}

impl<'a, T: Copy + Ord + Debug, D> Node<'a, T, D> {
    fn insert(&mut self, start: T, end: T, sub_tree: Node<'a, T, D>) -> bool {
        match *self {
            Node::Intermediate { ref mut left, ref mut right, ref mut free } => {
                if end <= free.start {
                    left.insert(start, end, sub_tree)
                } else if free.end <= start {
                    right.insert(start, end, sub_tree)
                } else if free.start <= start && end <= free.end {
                    // [start, end] completely within self.free
                    take_mut::take(right, |right_value| {
                        Box::new(Node::Intermediate {
                            left: Box::new(sub_tree),
                            right: right_value,
                            free: end..free.end,
                        })
                    });
                    *free = free.start..start;
                    true
                } else {
                    // Overlap between [start, end] and self.free
                    false
                }
            }
            Node::Leaf { .. } => false,
        }
    }
}

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

    const DATA: &i8 = &9;

    #[test]
    fn test_schedule_exact() {
        let mut tree: ScheduleTree<i8, i8> = ScheduleTree::new();

        // 5..10
        let scheduled = tree.schedule_exact(5, 5, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..10));
        assert_matches!(tree.root, Some(Node::Leaf { start: 5, end: 10, .. }));

        //   free:10..13
        //    /        \
        // 5..10      13..18
        let scheduled = tree.schedule_exact(13, 5, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..18));
        assert_matches!(tree.root, Some(Node::Intermediate {
            free: Range { start: 10, end: 13 },
            right: box Node::Leaf { start: 13, end: 18, .. },
        .. }));

        //   free:10..10
        //    /        \
        // 5..10     free:12..13
        //             /     \
        //          10..12  13..18
        let scheduled = tree.schedule_exact(10, 2, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..18));
        assert_matches!(tree.root, Some(Node::Intermediate {
            free: Range { start: 10, end: 10 },
            right: box Node::Intermediate {
                free: Range { start: 12, end: 13 },
                left: box Node::Leaf { start: 10, end: 12, .. },
            .. },
        .. }));
    }
}
<commit_msg>Implemented iterator<commit_after>use std::fmt::Debug;
use std::ops::{Add, Range, Sub};

use take_mut;

#[derive(Debug)]
pub struct ScheduleTree<'a, T, D: 'a> {
    root: Option<Node<'a, T, D>>,
    scope: Option<Range<T>>,
}

#[derive(Debug, PartialEq)]
pub enum Node<'a, T, D: 'a> {
    Leaf { start: T, end: T, data: &'a D },
    Intermediate {
        left: Box<Node<'a, T, D>>,
        right: Box<Node<'a, T, D>>,
        free: Range<T>,
    },
}

impl<'a, T, D> ScheduleTree<'a, T, D>
    where T: Copy + Clone + Ord + Debug,
          D: Debug
{
    pub fn new() -> Self {
        ScheduleTree {
            root: None,
            scope: None,
        }
    }

    pub fn iter(&self) -> Iter<T, D> {
        Iter { path: self.root.iter().collect() }
    }

    pub fn schedule_exact<W>(&mut self, start: T, duration: W, data: &'a D) -> bool
        where T: Add<W, Output = T>
    {
        let end = start + duration;
        let new_node = Node::Leaf {
            start: start,
            end: end,
            data: data,
        };

        if self.root.is_none() {
            self.root = Some(new_node);
            self.scope = Some(start..end);
            return true;
        }

        let scope = self.scope
            .as_ref()
            .cloned()
            .unwrap();
        if end <= scope.start {
            let root = self.root.take().unwrap();
            self.root = Some(Node::Intermediate {
                                 left: Box::new(new_node),
                                 right: Box::new(root),
                                 free: end..scope.start,
                             });
            self.scope = Some(start..scope.end);
            return true;
        } else if scope.end <= start {
            let root = self.root.take().unwrap();
            self.root = Some(Node::Intermediate {
                                 left: Box::new(root),
                                 right: Box::new(new_node),
                                 free: scope.end..start,
                             });
            self.scope = Some(scope.start..end);
            return true;
        }

        self.root
            .as_mut()
            .unwrap()
            .insert(start, end, new_node)
    }

    pub fn schedule_after<W>(&self, start: T, duration: W, max_end: Option<T>, data: &'a D) -> bool
        where T: Add<W, Output = T> + Sub<T, Output = W> + Sub<W, Output = T>,
              W: Add<W, Output = W> + Add<T, Output = T> + Sub<W, Output = W> + Copy
    {
        assert!(max_end.map_or(true, |max_end| start + duration <= max_end));
        // TODO schedule
        true
    }
}

impl<'a, T, D> Node<'a, T, D>
    where T: Copy + Ord + Debug
{
    fn insert(&mut self, start: T, end: T, sub_tree: Node<'a, T, D>) -> bool {
        match *self {
            Node::Intermediate { ref mut left, ref mut right, ref mut free } => {
                if end <= free.start {
                    left.insert(start, end, sub_tree)
                } else if free.end <= start {
                    right.insert(start, end, sub_tree)
                } else if free.start <= start && end <= free.end {
                    // [start, end] completely within self.free
                    take_mut::take(right, |right_value| {
                        Box::new(Node::Intermediate {
                                     left: Box::new(sub_tree),
                                     right: right_value,
                                     free: end..free.end,
                                 })
                    });
                    *free = free.start..start;
                    true
                } else {
                    // Overlap between [start, end] and self.free
                    false
                }
            }
            Node::Leaf { .. } => false,
        }
    }
}

#[derive(Debug)]
pub struct Entry<'a, T, D: 'a> {
    pub start: T,
    pub end: T,
    pub data: &'a D,
}

#[derive(Debug)]
pub struct Iter<'b, 'a: 'b, T: 'b, D: 'a> {
    path: Vec<&'b Node<'a, T, D>>,
}

impl<'b, 'a, T, D> Iterator for Iter<'b, 'a, T, D>
    where T: Copy
{
    type Item = Entry<'a, T, D>;

    fn next(&mut self) -> Option<Self::Item> {
        self.path.pop().and_then(|mut current| {
            while let Node::Intermediate { ref left, ref right, .. } = *current {
                self.path.push(right);
                current = left;
            }
            if let Node::Leaf { start, end, ref data } = *current {
                Some(Entry {
                         start: start,
                         end: end,
                         data: *data,
                     })
            } else {
                None
            }
        })
    }
}

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

    const DATA: &i8 = &9;

    #[test]
    fn test_schedule_exact() {
        let mut tree: ScheduleTree<i8, i8> = ScheduleTree::new();

        // 5..10
        let scheduled = tree.schedule_exact(5, 5, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..10));
        assert_matches!(tree.root, Some(Node::Leaf { start: 5, end: 10, .. }));

        //   free:10..13
        //    /        \
        // 5..10      13..18
        let scheduled = tree.schedule_exact(13, 5, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..18));
        assert_matches!(tree.root, Some(Node::Intermediate {
            free: Range { start: 10, end: 13 },
            right: box Node::Leaf { start: 13, end: 18, .. },
        .. }));

        //   free:10..10
        //    /        \
        // 5..10     free:12..13
        //             /     \
        //          10..12  13..18
        let scheduled = tree.schedule_exact(10, 2, DATA);
        assert!(scheduled);
        assert!(tree.scope == Some(5..18));
        assert_matches!(tree.root, Some(Node::Intermediate {
            free: Range { start: 10, end: 10 },
            right: box Node::Intermediate {
                free: Range { start: 12, end: 13 },
                left: box Node::Leaf { start: 10, end: 12, .. },
            .. },
        .. }));
    }
}
<|endoftext|>


<commit_before>#![cfg(target_os = "linux")]

mod common;

use std::fs;
use std::mem::size_of;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use sled::Config;

const N_TESTS: usize = 100;
const CYCLE: usize = 256;
const BATCH_SIZE: u32 = 8;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (_k, v) = res.unwrap();
        if &v[..4] == &highest_vec[..4] {
            contiguous += 1;
        } else {
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.range(&*low_beginning..) {
        let (k, v): (sled::IVec, _) = res.unwrap();
        assert_eq!(
            slice_to_u32(&*v),
            lowest,
            "expected key {} to have value {}, instead it had value {} in db: {:?}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v),
            tree
        );
    }

    (contiguous, highest)
}

/// Verifies that the keys in the tree are correctly recovered (i.e., equal).
/// Panics if they are incorrect.
fn verify_batches(tree: &sled::Tree) -> u32 {
    let mut iter = tree.iter();
    let first_value = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return 0,
    };
    for key in 0..BATCH_SIZE {
        let res = tree.get(u32_to_vec(key));
        let option = res.unwrap();
        let v = match option {
            Some(v) => v,
            None => panic!(
                "expected key {} to have a value, instead it was missing in db: {:?}",
                key,
                tree
            ),
        };
        let value = slice_to_u32(&*v);
        assert_eq!(
            first_value,
            value,
            "expected key {} to have value {}, instead it had value {} in db: {:?}",
            key,
            first_value,
            value,
            tree
        );
    }

    first_value
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; size_of::<u32>()] = u.to_be_bytes();
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; size_of::<u32>()];
    buf.copy_from_slice(&b[..size_of::<u32>()]);

    u32::from_be_bytes(buf)
}

fn spawn_killah() {
    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });
}

fn run(config: Config) {
    common::setup_logger();

    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = config.open().unwrap();

    if !crash_during_initialization {
        spawn_killah();
    }

    let (key, highest) = verify(&tree);

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let key = u32_to_vec((hu % CYCLE) as u32);

        let mut value = u32_to_vec((hu / CYCLE) as u32);
        let additional_len = rand::thread_rng().gen_range(0, 1000);
        value.append(&mut vec![0u8; additional_len]);

        tree.insert(&key, value).unwrap();
    }
}

fn run_batches(config: Config) {
    fn do_batch(i: u32, tree: &sled::Tree) {
        let mut rng = rand::thread_rng();
        let base_value = u32_to_vec(i);

        let mut batch = sled::Batch::default();
        if rng.gen_bool(0.1) {
            for key in 0..BATCH_SIZE {
                batch.remove(u32_to_vec(key));
            }
        } else {
            for key in 0..BATCH_SIZE {
                let mut value = base_value.clone();
                let additional_len = rng.gen_range(0, 1000);
                value.append(&mut vec![0u8; additional_len]);

                batch.insert(u32_to_vec(key), value);
            }
        }
        tree.apply_batch(batch).unwrap();
    }

    common::setup_logger();
    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = config.open().unwrap();

    let mut i = verify_batches(&tree);
    i += 1;
    do_batch(i, &tree);

    if !crash_during_initialization {
        spawn_killah();
    }

    loop {
        i += 1;
        do_batch(i, &tree);
    }
}

fn run_without_snapshot(dir: &str) {
    let config = Config::new()
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .path(dir.to_string())
        .snapshot_after_ops(1 << 56)
        .segment_size(1024);

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_with_snapshot(dir: &str) {
    let config = Config::new()
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .path(dir.to_string())
        .snapshot_after_ops(5000)
        .segment_size(1024);

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_batches_without_snapshot(dir: &str) {
    let config = Config::new()
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .path(dir.to_string())
        .snapshot_after_ops(1 << 56)
        .segment_size(1024);

    match thread::spawn(|| run_batches(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_batches_with_snapshot(dir: &str) {
    let config = Config::new()
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .path(dir.to_string())
        .snapshot_after_ops(5000)
        .segment_size(1024);

    match thread::spawn(|| run_batches(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

#[test]
fn test_crash_recovery_with_runtime_snapshot() {
    let dir = "test_crashes_with_snapshot";
    cleanup(dir);
    for _ in 0..N_TESTS {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot(dir)
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup(dir);
                panic!("child exited abnormally");
            }
        }
    }
    cleanup(dir);
}

#[test]
fn test_crash_recovery_no_runtime_snapshot() {
    let dir = "test_crashes";
    cleanup(dir);
    for _ in 0..N_TESTS {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot(dir)
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup(dir);
                panic!("child exited abnormally");
            }
        }
    }
    cleanup(dir);
}

#[test]
#[ignore]
fn test_crash_batches_with_runtime_snapshot() {
    let dir = "test_batches_with_snapshot";
    cleanup(dir);
    for _ in 0..N_TESTS {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_batches_with_snapshot(dir)
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup(dir);
                panic!("child exited abnormally");
            }
        }
    }
    cleanup(dir);
}

#[test]
#[ignore]
fn test_crash_batches_no_runtime_snapshot() {
    let dir = "test_batches";
    cleanup(dir);
    for _ in 0..N_TESTS {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_batches_without_snapshot(dir)
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup(dir);
                panic!("child exited abnormally");
            }
        }
    }
    cleanup(dir);
}

fn cleanup(dir: &str) {
    let dir = Path::new(dir);
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}
<commit_msg>woop woop the segment handling refactor seems to fix the crash batch recovery issue :)<commit_after>#![cfg(target_os = "linux")]

mod common;

use std::fs;
use std::mem::size_of;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use sled::Config;

const N_TESTS: usize = 100;
const CYCLE: usize = 256;
const BATCH_SIZE: u32 = 8;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (_k, v) = res.unwrap();
        if &v[..4] == &highest_vec[..4] {
            contiguous += 1;
        } else {
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.range(&*low_beginning..) {
        let (k, v): (sled::IVec, _) = res.unwrap();
        assert_eq!(
            slice_to_u32(&*v),
            lowest,
            "expected key {} to have value {}, instead it had value {} in db: {:?}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v),
            tree
        );
    }

    (contiguous, highest)
}

/// Verifies that the keys in the tree are correctly recovered (i.e., equal).
/// Panics if they are incorrect.
fn verify_batches(tree: &sled::Tree) -> u32 {
    let mut iter = tree.iter();
    let first_value = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return 0,
    };
    for key in 0..BATCH_SIZE {
        let res = tree.get(u32_to_vec(key));
        let option = res.unwrap();
        let v = match option {
            Some(v) => v,
            None => panic!(
                "expected key {} to have a value, instead it was missing in db: {:?}",
                key,
                tree
            ),
        };
        let value = slice_to_u32(&*v);
        assert_eq!(
            first_value,
            value,
            "expected key {} to have value {}, instead it had value {} in db: {:?}",
            key,
            first_value,
            value,
            tree
        );
    }

    first_value
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; size_of::<u32>()] = u.to_be_bytes();
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; size_of::<u32>()];
    buf.copy_from_slice(&b[..size_of::<u32>()]);

    u32::from_be_bytes(buf)
}

fn spawn_killah() {
    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });
}

fn run(config: Config) {
    common::setup_logger();

    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = config.open().unwrap();

    if !crash_during_initialization {
        spawn_killah();
    }

    let (key, highest) = verify(&tree);

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let key = u32_to_vec((hu % CYCLE) as u32);

        let mut value = u32_to_vec((hu / CYCLE) as u32);
        let additional_len = rand::thread_rng().gen_range(0, 1000);
        value.append(&mut vec![0u8; additional_len]);

        tree.insert(&key, value).unwrap();
    }
}

fn run_batches(config: Config) {
    fn do_batch(i: u32, tree: &sled::Tree) {
        let mut rng = rand::thread_rng();
        let base_value = u32_to_vec(i);

        let mut batch = sled::Batch::default();
        if rng.gen_bool(0.1) {
            for key in 0..BATCH_SIZE {
                batch.remove(u32_to_vec(key));
            }
        } else {
            for key in 0..BATCH_SIZE {
                let mut value = base_value.clone();
                let additional_len = rng.gen_range(0, 1000);
                value.append(&mut vec![0u8; additional_len]);

                batch.insert(u32_to_vec(key), value);
            }
        }
        tree.apply_batch(batch).unwrap();
    }

    common::setup_logger();
    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = config.open().unwrap();

    let mut i = verify_batches(&tree);
    i += 1;
    do_batch(i, &tree);

    if !crash_during_initialization {
        spawn_killah();
    }

    loop {
        i += 1;
        do_batch(i, &tree);
    }
}

fn run_without_snapshot(dir: &str) {
    let config = Config::new()
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .path(dir.to_string())
        .snapshot_after_ops(1 << 56)
        .segment_size(1024);

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_with_snapshot(dir: &str) {
    let config = Config::new()
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .path(dir.to_string())
        .snapshot_after_ops(5000)
        .segment_size(1024);

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_batches_without_snapshot(dir: &str) {
    let config = Config::new()
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .path(dir.to_string())
        .snapshot_after_ops(1 << 56)
        .segment_size(1024);

    match thread::spawn(|| run_batches(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_batches_with_snapshot(dir: &str) {
    let config = Config::new()
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .path(dir.to_string())
        .snapshot_after_ops(5000)
        .segment_size(1024);

    match thread::spawn(|| run_batches(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

#[test]
fn test_crash_recovery_with_runtime_snapshot() {
    let dir = "test_crashes_with_snapshot";
    cleanup(dir);
    for _ in 0..N_TESTS {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot(dir)
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup(dir);
                panic!("child exited abnormally");
            }
        }
    }
    cleanup(dir);
}

#[test]
fn test_crash_recovery_no_runtime_snapshot() {
    let dir = "test_crashes";
    cleanup(dir);
    for _ in 0..N_TESTS {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot(dir)
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup(dir);
                panic!("child exited abnormally");
            }
        }
    }
    cleanup(dir);
}

#[test]
fn test_crash_batches_with_runtime_snapshot() {
    let dir = "test_batches_with_snapshot";
    cleanup(dir);
    for _ in 0..N_TESTS {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_batches_with_snapshot(dir)
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup(dir);
                panic!("child exited abnormally");
            }
        }
    }
    cleanup(dir);
}

#[test]
fn test_crash_batches_no_runtime_snapshot() {
    let dir = "test_batches";
    cleanup(dir);
    for _ in 0..N_TESTS {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_batches_without_snapshot(dir)
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup(dir);
                panic!("child exited abnormally");
            }
        }
    }
    cleanup(dir);
}

fn cleanup(dir: &str) {
    let dir = Path::new(dir);
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}
<|endoftext|>


<commit_before>use collections::hashmap::HashMap;
use std::num::FromPrimitive;
use std::ptr;
use std::str;
use std::vec;

use keycode::KeyCode;
use rect::Rect;
use scancode::ScanCode;
use video::Window;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{c_int, c_char, c_uint, int32_t, uint8_t, uint16_t,
                    uint32_t};
    use rect::Rect;
    use video::ll::SDL_Window;

    pub type SDL_bool = c_int;
    pub type SDL_Rect = Rect;
    pub type SDL_Keycode = int32_t;
    pub type SDL_Keymod = c_uint;
    pub type SDL_Scancode = c_uint;

    // SDL_keyboard.h
    pub struct SDL_Keysym {
        pub scancode: SDL_Scancode,
        pub sym: SDL_Keycode,
        pub _mod: uint16_t,
        pub unused: uint32_t,
    }

    extern "C" {
        pub fn SDL_GetKeyboardFocus() -> *SDL_Window;
        pub fn SDL_GetKeyboardState(numkeys: *c_int) -> *uint8_t;
        pub fn SDL_GetModState() -> SDL_Keymod;
        pub fn SDL_SetModState(modstate: SDL_Keymod);
        pub fn SDL_GetKeyFromScancode(scancode: SDL_Scancode) -> SDL_Keycode;
        pub fn SDL_GetScancodeFromKey(key: SDL_Keycode) -> SDL_Scancode;
        pub fn SDL_GetScancodeName(scancode: SDL_Scancode) -> *c_char;
        pub fn SDL_GetScancodeFromName(name: *c_char) -> SDL_Scancode;
        pub fn SDL_GetKeyName(key: SDL_Keycode) -> *c_char;
        pub fn SDL_GetKeyFromName(name: *c_char) -> SDL_Keycode;
        pub fn SDL_StartTextInput();
        pub fn SDL_IsTextInputActive() -> SDL_bool;
        pub fn SDL_StopTextInput();
        pub fn SDL_SetTextInputRect(rect: *SDL_Rect);
        pub fn SDL_HasScreenKeyboardSupport() -> SDL_bool;
        pub fn SDL_IsScreenKeyboardShown(window: *SDL_Window) -> SDL_bool;
    }
}

bitflags!(flags Mod: u32 {
     static NoMod = 0x0000,
     static LShiftMod = 0x0001,
     static RShiftMod = 0x0002,
     static LCtrlMod = 0x0040,
     static RCtrlMod = 0x0080,
     static LAltMod = 0x0100,
     static RAltMod = 0x0200,
     static LGuiMod = 0x0400,
     static RGuiMod = 0x0800,
     static NumMod = 0x1000,
     static CapsMod = 0x2000,
     static ModeMod = 0x4000,
     static ReservedMod = 0x8000
})

pub fn get_keyboard_focus() -> Option<Window> {
    let raw = unsafe { ll::SDL_GetKeyboardFocus() };
    if raw == ptr::null() {
        None
    } else {
        unsafe { Some(Window::from_ll(raw, false)) }
    }
}

pub fn get_keyboard_state() -> HashMap<ScanCode, bool> {
    let mut state: HashMap<ScanCode, bool> = HashMap::new();
    let count = 0;

    let raw = unsafe { vec::raw::from_buf(ll::SDL_GetKeyboardState(&count),
                                          count as uint) };

    let mut current = 0;
    while current < raw.len() {
        state.insert(FromPrimitive::from_int(current as int).unwrap(),
                     *raw.get(current) == 1);
        current += 1;
    }

    return state;
}

pub fn get_mod_state() -> Mod {
    unsafe { Mod::from_bits(ll::SDL_GetModState()).unwrap() }
}

pub fn set_mod_state(flags: Mod) {
    unsafe { ll::SDL_SetModState(flags.bits()); }
}

pub fn get_key_from_scancode(scancode: ScanCode) -> KeyCode {
    unsafe {
        FromPrimitive::from_int(ll::SDL_GetKeyFromScancode(scancode.code()
                                                            as u32) as int).unwrap()
    }
}

pub fn get_scancode_from_key(key: KeyCode) -> ScanCode {
    unsafe {
        FromPrimitive::from_int(ll::SDL_GetScancodeFromKey(key.code())
                                 as int).unwrap()
    }
}

pub fn get_scancode_name(scancode: ScanCode) -> String {
    unsafe {
        str::raw::from_c_str(ll::SDL_GetScancodeName(scancode.code() as u32))
    }
}

pub fn get_scancode_from_name(name: &str) -> ScanCode {
    unsafe {
        name.with_c_str(|name| {
            FromPrimitive::from_int(ll::SDL_GetScancodeFromName(name) as int).unwrap()
        })
    }
}

pub fn get_key_name(key: KeyCode) -> String {
    unsafe {
        str::raw::from_c_str(ll::SDL_GetKeyName(key.code()))
    }
}

pub fn get_key_from_name(name: &str) -> KeyCode {
    unsafe {
        name.with_c_str(|name| {
            FromPrimitive::from_int(ll::SDL_GetKeyFromName(name) as int).unwrap()
        })
    }
}

pub fn start_text_input() {
    unsafe { ll::SDL_StartTextInput(); }
}

pub fn is_text_input_active() -> bool {
    unsafe { ll::SDL_IsTextInputActive() == 1 }
}

pub fn stop_text_input() {
    unsafe { ll::SDL_StopTextInput(); }
}

pub fn set_text_input_rect(rect: &Rect) {
    unsafe { ll::SDL_SetTextInputRect(rect); }
}

pub fn has_screen_keyboard_support() -> bool {
    unsafe { ll::SDL_HasScreenKeyboardSupport() == 1 }
}

pub fn is_screen_keyboard_shown(window: &Window) -> bool {
    unsafe { ll::SDL_IsScreenKeyboardShown(window.raw()) == 1 }
}
<commit_msg>Convert old-style collections import to new std::collections<commit_after>use std::collections::HashMap;
use std::num::FromPrimitive;
use std::ptr;
use std::str;
use std::vec;

use keycode::KeyCode;
use rect::Rect;
use scancode::ScanCode;
use video::Window;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{c_int, c_char, c_uint, int32_t, uint8_t, uint16_t,
                    uint32_t};
    use rect::Rect;
    use video::ll::SDL_Window;

    pub type SDL_bool = c_int;
    pub type SDL_Rect = Rect;
    pub type SDL_Keycode = int32_t;
    pub type SDL_Keymod = c_uint;
    pub type SDL_Scancode = c_uint;

    // SDL_keyboard.h
    pub struct SDL_Keysym {
        pub scancode: SDL_Scancode,
        pub sym: SDL_Keycode,
        pub _mod: uint16_t,
        pub unused: uint32_t,
    }

    extern "C" {
        pub fn SDL_GetKeyboardFocus() -> *SDL_Window;
        pub fn SDL_GetKeyboardState(numkeys: *c_int) -> *uint8_t;
        pub fn SDL_GetModState() -> SDL_Keymod;
        pub fn SDL_SetModState(modstate: SDL_Keymod);
        pub fn SDL_GetKeyFromScancode(scancode: SDL_Scancode) -> SDL_Keycode;
        pub fn SDL_GetScancodeFromKey(key: SDL_Keycode) -> SDL_Scancode;
        pub fn SDL_GetScancodeName(scancode: SDL_Scancode) -> *c_char;
        pub fn SDL_GetScancodeFromName(name: *c_char) -> SDL_Scancode;
        pub fn SDL_GetKeyName(key: SDL_Keycode) -> *c_char;
        pub fn SDL_GetKeyFromName(name: *c_char) -> SDL_Keycode;
        pub fn SDL_StartTextInput();
        pub fn SDL_IsTextInputActive() -> SDL_bool;
        pub fn SDL_StopTextInput();
        pub fn SDL_SetTextInputRect(rect: *SDL_Rect);
        pub fn SDL_HasScreenKeyboardSupport() -> SDL_bool;
        pub fn SDL_IsScreenKeyboardShown(window: *SDL_Window) -> SDL_bool;
    }
}

bitflags!(flags Mod: u32 {
     static NoMod = 0x0000,
     static LShiftMod = 0x0001,
     static RShiftMod = 0x0002,
     static LCtrlMod = 0x0040,
     static RCtrlMod = 0x0080,
     static LAltMod = 0x0100,
     static RAltMod = 0x0200,
     static LGuiMod = 0x0400,
     static RGuiMod = 0x0800,
     static NumMod = 0x1000,
     static CapsMod = 0x2000,
     static ModeMod = 0x4000,
     static ReservedMod = 0x8000
})

pub fn get_keyboard_focus() -> Option<Window> {
    let raw = unsafe { ll::SDL_GetKeyboardFocus() };
    if raw == ptr::null() {
        None
    } else {
        unsafe { Some(Window::from_ll(raw, false)) }
    }
}

pub fn get_keyboard_state() -> HashMap<ScanCode, bool> {
    let mut state: HashMap<ScanCode, bool> = HashMap::new();
    let count = 0;

    let raw = unsafe { vec::raw::from_buf(ll::SDL_GetKeyboardState(&count),
                                          count as uint) };

    let mut current = 0;
    while current < raw.len() {
        state.insert(FromPrimitive::from_int(current as int).unwrap(),
                     *raw.get(current) == 1);
        current += 1;
    }

    return state;
}

pub fn get_mod_state() -> Mod {
    unsafe { Mod::from_bits(ll::SDL_GetModState()).unwrap() }
}

pub fn set_mod_state(flags: Mod) {
    unsafe { ll::SDL_SetModState(flags.bits()); }
}

pub fn get_key_from_scancode(scancode: ScanCode) -> KeyCode {
    unsafe {
        FromPrimitive::from_int(ll::SDL_GetKeyFromScancode(scancode.code()
                                                            as u32) as int).unwrap()
    }
}

pub fn get_scancode_from_key(key: KeyCode) -> ScanCode {
    unsafe {
        FromPrimitive::from_int(ll::SDL_GetScancodeFromKey(key.code())
                                 as int).unwrap()
    }
}

pub fn get_scancode_name(scancode: ScanCode) -> String {
    unsafe {
        str::raw::from_c_str(ll::SDL_GetScancodeName(scancode.code() as u32))
    }
}

pub fn get_scancode_from_name(name: &str) -> ScanCode {
    unsafe {
        name.with_c_str(|name| {
            FromPrimitive::from_int(ll::SDL_GetScancodeFromName(name) as int).unwrap()
        })
    }
}

pub fn get_key_name(key: KeyCode) -> String {
    unsafe {
        str::raw::from_c_str(ll::SDL_GetKeyName(key.code()))
    }
}

pub fn get_key_from_name(name: &str) -> KeyCode {
    unsafe {
        name.with_c_str(|name| {
            FromPrimitive::from_int(ll::SDL_GetKeyFromName(name) as int).unwrap()
        })
    }
}

pub fn start_text_input() {
    unsafe { ll::SDL_StartTextInput(); }
}

pub fn is_text_input_active() -> bool {
    unsafe { ll::SDL_IsTextInputActive() == 1 }
}

pub fn stop_text_input() {
    unsafe { ll::SDL_StopTextInput(); }
}

pub fn set_text_input_rect(rect: &Rect) {
    unsafe { ll::SDL_SetTextInputRect(rect); }
}

pub fn has_screen_keyboard_support() -> bool {
    unsafe { ll::SDL_HasScreenKeyboardSupport() == 1 }
}

pub fn is_screen_keyboard_shown(window: &Window) -> bool {
    unsafe { ll::SDL_IsScreenKeyboardShown(window.raw()) == 1 }
}
<|endoftext|>


<commit_before>/*!

Implements the copy-on-write DOM-sharing model.  This model allows for
a single writer and any number of readers, but the writer must be able
to control and manage the lifetimes of the reader(s).  For simplicity
I will describe the implementation as though there were a single
reader.

The basic idea is that every object in the COW pool has both a reader
view and a writer view.  The writer always sees the writer view, which
contains the most up-to-date values.  The reader uses the reader view,
which contains the values as of the point where the reader was forked.
When the writer joins the reader, the reader view will be synchronized
with the writer view.

Internally, the way this works is using a copy-on-write scheme.  Each
COW node maintains two pointers (`read_ptr` and `write_ptr`).
Assuming that readers are active, when a writer wants to modify a
node, it first copies the reader's data into a new pointer.  Any
writes that occur after that point (but before the reader is joined)
will operate on this same copy.  When the reader is joined, any nodes
which the writer modified will free the stale reader data and update
the reader pointer to be the same as the writer pointer.

# Using the COW APIs as a writer

You must first create a `scope` object.  The scope object manages the
memory and the COW operations.  COW'd objects of some sendable type
`T` are not referenced directly but rather through a `handle<T>`.  To
create a new COW object, you use `scope.handle(t)` where `t` is some
initial value of type `T`.  To write to an COW object, use
`scope.write()` and to read from it use `scope.read()`. Be sure not to
use the various `ReaderMethods`.

Handles can be freely sent between tasks but the COW scope cannot.  It must stay with the writer
task.  You are responsible for correctly invoking `reader_forked()` and `reader_joined()` to keep
the COW scope abreast of when the reader is active.  Failure to do so will lead to race conditions
or worse.

# Using the COW APIs as a reader

Import the `ReaderMethods` impl.  When you receive a handle, you can
invoke `h.read { |v| ... }` and so forth.  There is also a piece of
auxiliary data that can be optionally associated with each handle.

Note: if the type `T` contains mutable fields, then there is nothing
to stop the reader from mutating those fields in the `read()` method.
Do not do this.  It will lead to race conditions.

FIXME: We can enforce that this is not done by ensuring that the type
`T` contains no mutable fields.

# Auxiliary data

Readers can associate a piece of auxiliary data of type `A` along with
main nodes.  This is convenient but dangerous: it is the reader's job
to ensure that this data remains live independent of the COW nodes
themselves.

*/

use core::libc::types::os::arch::c95::size_t;
use ptr::Ptr;
use vec::push;

type ScopeData<T:Send,A> = {
    mut layout_active: bool,
    mut free_list: ~[Handle<T,A>],
    mut first_dirty: Handle<T,A>
};

struct ScopeResource<T:Send,A> {
    d : ScopeData<T,A>,

    drop unsafe {
        error!("dropp!");
        for self.d.free_list.each |h| { free_handle(*h); }
    }
}

fn ScopeResource<T:Send,A>(d : ScopeData<T,A>) -> ScopeResource<T,A> {
    ScopeResource { d: d }
}

pub type Scope<T:Send,A> = @ScopeResource<T,A>;

type HandleData<T:Send,A> = {mut read_ptr: *T,
                             mut write_ptr: *mut T,
                             mut read_aux: *A,
                             mut next_dirty: Handle<T,A>};
pub enum Handle<T:Send,A> {
    _Handle(*HandleData<T,A>)
}

// Private methods
impl<T:Send,A> Handle<T,A> {
    fn read_ptr() -> *T unsafe            { (**self).read_ptr   }
    fn write_ptr() -> *mut T unsafe       { (**self).write_ptr  }
    fn read_aux() -> *A unsafe            { (**self).read_aux   }
    fn next_dirty() -> Handle<T,A> unsafe { (**self).next_dirty }

    fn set_read_ptr(t: *T) unsafe             { (**self).read_ptr = t;   }
    fn set_write_ptr(t: *mut T) unsafe        { (**self).write_ptr = t;  }
    fn set_read_aux(t: *A) unsafe             { (**self).read_aux = t;   }
    fn set_next_dirty(h: Handle<T,A>) unsafe { (**self).next_dirty = h; }

    pure fn is_null() -> bool { (*self).is_null() }
    fn is_not_null() -> bool { (*self).is_not_null() }
}

impl<T:Send,A> Handle<T,A> {
    /// Access the reader's view of the handle's data
    fn read<U>(f: fn(&T) -> U) -> U unsafe {
        f(&*self.read_ptr())
    }

    /// True if auxiliary data is associated with this handle
    fn has_aux() -> bool unsafe {
        self.read_aux().is_not_null()
    }

    /** Set the auxiliary data associated with this handle.

    **Warning:** the reader is responsible for keeping this data live!
    */
    fn set_aux(p: @A) unsafe {
        (**self).read_aux = ptr::to_unsafe_ptr(&*p);
    }

    /// Access the auxiliary data associated with this handle
    fn aux<U>(f: fn(&A) -> U) -> U unsafe {
        assert self.has_aux();
        f(&*self.read_aux())
    }
}

// Private methods
impl<T: Copy Send,A> Scope<T,A> {
    fn clone(v: *T) -> *T unsafe {
        let n: *mut T =
            cast::reinterpret_cast(&libc::calloc(sys::size_of::<T>() as size_t, 1u as size_t));

        // n.b.: this assignment will run the drop glue for <T,A>. *Hopefully* the fact that
        // everything is initialized to NULL by calloc will make this ok.  We may have to make the
        // take glue be tolerant of this.
        *n = unsafe{*v};

        return cast::reinterpret_cast(&n);
    }
}

unsafe fn free<T:Send>(t: *T) {
    let _x <- *cast::reinterpret_cast::<*T,*mut T>(&t);
    libc::free(cast::reinterpret_cast(&t));
}

unsafe fn free_handle<T:Send,A>(h: Handle<T,A>) {
    free(h.read_ptr());
    if h.write_ptr() != cast::reinterpret_cast(&h.read_ptr()) {
        free(cast::reinterpret_cast::<*mut T,*T>(&h.write_ptr()));
    }
}

fn null_handle<T:Send,A>() -> Handle<T,A> {
    _Handle(ptr::null())
}

pub fn Scope<T:Send,A>() -> Scope<T,A> {
    @ScopeResource({mut layout_active: false,
                    mut free_list: ~[],
                    mut first_dirty: null_handle()})
}

// Writer methods
impl<T:Copy Send,A> Scope<T,A> {
    fn is_reader_forked() -> bool {
        self.d.layout_active
    }

    fn reader_forked() {
        assert !self.d.layout_active;
        assert self.d.first_dirty.is_null();
        self.d.layout_active = true;
    }

    fn reader_joined() unsafe {
        assert self.d.layout_active;

        if self.d.first_dirty.is_not_null() {
            let mut handle = self.d.first_dirty;
            while (*handle).is_not_null() {
                free(handle.read_ptr());

                handle.set_read_ptr(cast::reinterpret_cast(&handle.write_ptr()));
                let next_handle = handle.next_dirty();
                handle.set_next_dirty(null_handle());
                handle = next_handle;
            }
            self.d.first_dirty = null_handle();
        }

        assert self.d.first_dirty.is_null();
        self.d.layout_active = false;
    }

    fn read<U>(h: &Handle<T,A>, f: fn(&T) -> U) -> U unsafe {
        // Use the write_ptr, which may be more up to date than the read_ptr or may not
        f(&*h.write_ptr())
    }

    fn write<U>(h: &Handle<T,A>, f: fn(&T) -> U) -> U unsafe {
        let const_read_ptr = ptr::const_offset(h.read_ptr(), 0);
        let const_write_ptr = ptr::const_offset(h.write_ptr(), 0);
        if self.d.layout_active && const_read_ptr == const_write_ptr {
            #debug["marking handle %? as dirty", h];
            h.set_write_ptr(cast::reinterpret_cast(&self.clone(h.read_ptr())));
            h.set_next_dirty(self.d.first_dirty);
            self.d.first_dirty = *h;
        }
        f(&*h.write_ptr())
    }

    // FIXME: This could avoid a deep copy by taking ownership of `v`
    #[allow(non_implicitly_copyable_typarams)]
    fn handle(v: &T) -> Handle<T,A> unsafe {
        debug!("vv: %?", *v);
        let d: *HandleData<T,A> =
            cast::reinterpret_cast(
                &libc::malloc(sys::size_of::<HandleData<T,A>>() as size_t));
        (*d).read_ptr = self.clone(ptr::to_unsafe_ptr(v));
        (*d).write_ptr = cast::reinterpret_cast(&(*d).read_ptr);
        (*d).read_aux = ptr::null();
        (*d).next_dirty = null_handle();
        let h = _Handle(d);
        push(&mut self.d.free_list, h);
        do self.read(&h) |v| {
            debug!("vv: %?", *v);
        }
        return h;
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod test {
    type animal = {name: ~str, species: species};
    enum species {
        chicken(~chicken),
        bull(~bull)
    }
    type chicken = {mut eggs_per_day:uint};
    type bull = {mut horns:uint};

    type processed = {flag: bool};

    type animal_scope = Scope<animal, processed>;

    #[test]
    fn handles_get_freed() {
        let s: animal_scope = Scope();
        s.handle(&{name:~"henrietta", species:chicken(~{mut eggs_per_day:22u})});
        s.handle(&{name:~"ferdinand", species:bull(~{mut horns:3u})});
    }

    fn mutate(a: &animal) {
        match a.species {
          chicken(c) => c.eggs_per_day += 1u,
          bull(c) => c.horns += 1u
        }
    }

    fn read_characteristic(a: &animal) -> uint {
        match a.species {
          chicken(c) => c.eggs_per_day,
          bull(c) => c.horns
        }
    }

    #[test]
    fn interspersed_execution() {
        let s: animal_scope = Scope();
        let henrietta =
            s.handle(&{name:~"henrietta",
                      species:chicken(~{mut eggs_per_day:0u})});
        let ferdinand =
            s.handle(&{name:~"ferdinand",
                      species:bull(~{mut horns:0u})});

        let iter1 = 3u;
        let iter2 = 22u;
        let read_port = comm::Port();
        let read_chan = comm::Chan(read_port);

        // fire up a reader task
        for uint::range(0u, iter1) |i| {
            s.reader_forked();
            let wait_chan = task::spawn_listener(|wait_port| {
                for uint::range(0u, iter2) |_i| {
                    comm::send(read_chan, henrietta.read(read_characteristic));
                    comm::send(read_chan, ferdinand.read(read_characteristic));
                    comm::recv(wait_port);
                }
            });

            let hrc = henrietta.read(read_characteristic);
            assert hrc == (i * iter2);

            let frc = ferdinand.read(read_characteristic);
            assert frc == i * iter2;

            for uint::range(0u, iter2) |_i| {
                assert hrc == comm::recv(read_port);
                s.write(&henrietta, mutate);
                assert frc == comm::recv(read_port);
                s.write(&ferdinand, mutate);
                comm::send(wait_chan, ());
            }
            s.reader_joined();
        }

        assert henrietta.read(read_characteristic) == iter1 * iter2;
        assert ferdinand.read(read_characteristic) == iter1 * iter2;
    }
}
<commit_msg>Fix build error<commit_after>/*!

Implements the copy-on-write DOM-sharing model.  This model allows for
a single writer and any number of readers, but the writer must be able
to control and manage the lifetimes of the reader(s).  For simplicity
I will describe the implementation as though there were a single
reader.

The basic idea is that every object in the COW pool has both a reader
view and a writer view.  The writer always sees the writer view, which
contains the most up-to-date values.  The reader uses the reader view,
which contains the values as of the point where the reader was forked.
When the writer joins the reader, the reader view will be synchronized
with the writer view.

Internally, the way this works is using a copy-on-write scheme.  Each
COW node maintains two pointers (`read_ptr` and `write_ptr`).
Assuming that readers are active, when a writer wants to modify a
node, it first copies the reader's data into a new pointer.  Any
writes that occur after that point (but before the reader is joined)
will operate on this same copy.  When the reader is joined, any nodes
which the writer modified will free the stale reader data and update
the reader pointer to be the same as the writer pointer.

# Using the COW APIs as a writer

You must first create a `scope` object.  The scope object manages the
memory and the COW operations.  COW'd objects of some sendable type
`T` are not referenced directly but rather through a `handle<T>`.  To
create a new COW object, you use `scope.handle(t)` where `t` is some
initial value of type `T`.  To write to an COW object, use
`scope.write()` and to read from it use `scope.read()`. Be sure not to
use the various `ReaderMethods`.

Handles can be freely sent between tasks but the COW scope cannot.  It must stay with the writer
task.  You are responsible for correctly invoking `reader_forked()` and `reader_joined()` to keep
the COW scope abreast of when the reader is active.  Failure to do so will lead to race conditions
or worse.

# Using the COW APIs as a reader

Import the `ReaderMethods` impl.  When you receive a handle, you can
invoke `h.read { |v| ... }` and so forth.  There is also a piece of
auxiliary data that can be optionally associated with each handle.

Note: if the type `T` contains mutable fields, then there is nothing
to stop the reader from mutating those fields in the `read()` method.
Do not do this.  It will lead to race conditions.

FIXME: We can enforce that this is not done by ensuring that the type
`T` contains no mutable fields.

# Auxiliary data

Readers can associate a piece of auxiliary data of type `A` along with
main nodes.  This is convenient but dangerous: it is the reader's job
to ensure that this data remains live independent of the COW nodes
themselves.

*/

use core::libc::types::os::arch::c95::size_t;
use ptr::Ptr;
use vec::push;

type ScopeData<T:Send,A> = {
    mut layout_active: bool,
    mut free_list: ~[Handle<T,A>],
    mut first_dirty: Handle<T,A>
};

struct ScopeResource<T:Send,A> {
    d : ScopeData<T,A>,

    drop unsafe {
        error!("dropp!");
        for self.d.free_list.each |h| { free_handle(*h); }
    }
}

fn ScopeResource<T:Send,A>(d : ScopeData<T,A>) -> ScopeResource<T,A> {
    ScopeResource { d: d }
}

pub type Scope<T:Send,A> = @ScopeResource<T,A>;

type HandleData<T:Send,A> = {mut read_ptr: *T,
                             mut write_ptr: *mut T,
                             mut read_aux: *A,
                             mut next_dirty: Handle<T,A>};
pub enum Handle<T:Send,A> {
    _Handle(*HandleData<T,A>)
}

// Private methods
impl<T:Send,A> Handle<T,A> {
    fn read_ptr() -> *T unsafe            { (**self).read_ptr   }
    fn write_ptr() -> *mut T unsafe       { (**self).write_ptr  }
    fn read_aux() -> *A unsafe            { (**self).read_aux   }
    fn next_dirty() -> Handle<T,A> unsafe { (**self).next_dirty }

    fn set_read_ptr(t: *T) unsafe             { (**self).read_ptr = t;   }
    fn set_write_ptr(t: *mut T) unsafe        { (**self).write_ptr = t;  }
    fn set_read_aux(t: *A) unsafe             { (**self).read_aux = t;   }
    fn set_next_dirty(h: Handle<T,A>) unsafe { (**self).next_dirty = h; }

    pure fn is_null() -> bool { (*self).is_null() }
    fn is_not_null() -> bool { (*self).is_not_null() }
}

impl<T:Send,A> Handle<T,A> {
    /// Access the reader's view of the handle's data
    fn read<U>(f: fn(&T) -> U) -> U unsafe {
        f(&*self.read_ptr())
    }

    /// True if auxiliary data is associated with this handle
    fn has_aux() -> bool unsafe {
        self.read_aux().is_not_null()
    }

    /** Set the auxiliary data associated with this handle.

    **Warning:** the reader is responsible for keeping this data live!
    */
    fn set_aux(p: @A) unsafe {
        (**self).read_aux = ptr::to_unsafe_ptr(&*p);
    }

    /// Access the auxiliary data associated with this handle
    fn aux<U>(f: fn(&A) -> U) -> U unsafe {
        assert self.has_aux();
        f(&*self.read_aux())
    }
}

// Private methods
impl<T: Copy Send,A> Scope<T,A> {
    fn clone(v: *T) -> *T unsafe {
        let n: *mut T =
            cast::reinterpret_cast(&libc::calloc(sys::size_of::<T>() as size_t, 1u as size_t));

        // n.b.: this assignment will run the drop glue for <T,A>. *Hopefully* the fact that
        // everything is initialized to NULL by calloc will make this ok.  We may have to make the
        // take glue be tolerant of this.
        *n = unsafe{*v};

        return cast::reinterpret_cast(&n);
    }
}

unsafe fn free<T:Send>(t: *T) {
    let _x <- *cast::reinterpret_cast::<*T,*mut T>(&t);
    libc::free(cast::reinterpret_cast(&t));
}

unsafe fn free_handle<T:Send,A>(h: Handle<T,A>) {
    free(h.read_ptr());
    if h.write_ptr() != cast::reinterpret_cast(&h.read_ptr()) {
        free(cast::reinterpret_cast::<*mut T,*T>(&h.write_ptr()));
    }
}

fn null_handle<T:Send,A>() -> Handle<T,A> {
    _Handle(ptr::null())
}

pub fn Scope<T:Send,A>() -> Scope<T,A> {
    @ScopeResource({mut layout_active: false,
                    mut free_list: ~[],
                    mut first_dirty: null_handle()})
}

// Writer methods
impl<T:Copy Send,A> Scope<T,A> {
    fn is_reader_forked() -> bool {
        self.d.layout_active
    }

    fn reader_forked() {
        assert !self.d.layout_active;
        assert self.d.first_dirty.is_null();
        self.d.layout_active = true;
    }

    fn reader_joined() unsafe {
        assert self.d.layout_active;

        if self.d.first_dirty.is_not_null() {
            let mut handle = self.d.first_dirty;
            while (*handle).is_not_null() {
                free(handle.read_ptr());

                handle.set_read_ptr(cast::reinterpret_cast(&handle.write_ptr()));
                let next_handle = handle.next_dirty();
                handle.set_next_dirty(null_handle());
                handle = next_handle;
            }
            self.d.first_dirty = null_handle();
        }

        assert self.d.first_dirty.is_null();
        self.d.layout_active = false;
    }

    fn read<U>(h: &Handle<T,A>, f: fn(&T) -> U) -> U unsafe {
        // Use the write_ptr, which may be more up to date than the read_ptr or may not
        f(&*h.write_ptr())
    }

    fn write<U>(h: &Handle<T,A>, f: fn(&T) -> U) -> U unsafe {
        let const_read_ptr = ptr::const_offset(h.read_ptr(), 0);
        let const_write_ptr = ptr::const_offset(h.write_ptr(), 0);
        if self.d.layout_active && const_read_ptr == const_write_ptr {
            #debug["marking handle %? as dirty", h];
            h.set_write_ptr(cast::reinterpret_cast(&self.clone(h.read_ptr())));
            h.set_next_dirty(self.d.first_dirty);
            self.d.first_dirty = *h;
        }
        f(&*h.write_ptr())
    }

    // FIXME: This could avoid a deep copy by taking ownership of `v`
    #[allow(non_implicitly_copyable_typarams)]
    fn handle(v: &T) -> Handle<T,A> unsafe {
        debug!("vv: %?", *v);
        let d: *HandleData<T,A> =
            cast::reinterpret_cast(
                &libc::malloc(sys::size_of::<HandleData<T,A>>() as size_t));
        (*d).read_ptr = self.clone(ptr::to_unsafe_ptr(v));
        (*d).write_ptr = cast::reinterpret_cast(&(*d).read_ptr);
        (*d).read_aux = ptr::null();
        (*d).next_dirty = null_handle();
        let h = _Handle(d);
        push(&mut self.d.free_list, h);
        do self.read(&h) |v| {
            debug!("vv: %?", *v);
        }
        return h;
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod test {
    type animal = {name: ~str, species: species};
    enum species {
        chicken(~chicken),
        bull(~bull)
    }
    type chicken = {mut eggs_per_day:uint};
    type bull = {mut horns:uint};

    type processed = {flag: bool};

    type animal_scope = Scope<animal, processed>;

    #[test]
    fn handles_get_freed() {
        let s: animal_scope = Scope();
        s.handle(&{name:~"henrietta", species:chicken(~{mut eggs_per_day:22u})});
        s.handle(&{name:~"ferdinand", species:bull(~{mut horns:3u})});
    }

    fn mutate(a: &animal) {
        match a.species {
          chicken(c) => c.eggs_per_day += 1u,
          bull(c) => c.horns += 1u
        }
    }

    fn read_characteristic(a: &animal) -> uint {
        match a.species {
          chicken(c) => c.eggs_per_day,
          bull(c) => c.horns
        }
    }

    #[test]
    fn interspersed_execution() {
        let s: animal_scope = Scope();
        let henrietta =
            s.handle(&{name:~"henrietta",
                      species:chicken(~{mut eggs_per_day:0u})});
        let ferdinand =
            s.handle(&{name:~"ferdinand",
                      species:bull(~{mut horns:0u})});

        let iter1 = 3u;
        let iter2 = 22u;
        let read_port = comm::Port();
        let read_chan = comm::Chan(&read_port);

        // fire up a reader task
        for uint::range(0u, iter1) |i| {
            s.reader_forked();
            let wait_chan = task::spawn_listener(|wait_port| {
                for uint::range(0u, iter2) |_i| {
                    comm::send(read_chan, henrietta.read(read_characteristic));
                    comm::send(read_chan, ferdinand.read(read_characteristic));
                    comm::recv(wait_port);
                }
            });

            let hrc = henrietta.read(read_characteristic);
            assert hrc == (i * iter2);

            let frc = ferdinand.read(read_characteristic);
            assert frc == i * iter2;

            for uint::range(0u, iter2) |_i| {
                assert hrc == comm::recv(read_port);
                s.write(&henrietta, mutate);
                assert frc == comm::recv(read_port);
                s.write(&ferdinand, mutate);
                comm::send(wait_chan, ());
            }
            s.reader_joined();
        }

        assert henrietta.read(read_characteristic) == iter1 * iter2;
        assert ferdinand.read(read_characteristic) == iter1 * iter2;
    }
}
<|endoftext|>


<commit_before>extern crate rs6502;

use std::io::{self, BufRead, Write};
use std::sync::mpsc::{channel, Receiver};
use std::thread;

use rs6502::{Cpu, Disassembler};

#[derive(Debug)]
pub struct MemoryMonitor {
    pub enabled: bool,
    start_addr: usize,
    end_addr: usize,
}

pub struct VirtualMachine {
    pub cpu: Cpu,
    pub monitor: MemoryMonitor,
    code_offset: u16,
    clock_rate: Option<u32>,
    receiver: Receiver<String>,
    last_command: String,
    breakpoints: [u8; 64 * 1024],
    broken: bool,
    step: bool,
}

impl VirtualMachine {
    pub fn new<CR>(cpu: Cpu, code_offset: u16, clock_rate: CR) -> VirtualMachine
        where CR: Into<Option<u32>>
    {
        let (tx, rx) = channel();

        thread::spawn(move || {
            std::io::stdout().write(b"hakka> ").unwrap();
            std::io::stdout().flush().unwrap();

            loop {
                let mut line = String::new();
                let stdin = io::stdin();
                stdin.lock().read_line(&mut line).expect("Could not read line");
                tx.send(line).unwrap();
            }
        });

        VirtualMachine {
            cpu: cpu,
            code_offset: code_offset,
            clock_rate: clock_rate.into(),
            receiver: rx,
            monitor: MemoryMonitor {
                enabled: false,
                start_addr: 0,
                end_addr: 0,
            },
            last_command: "".into(),
            breakpoints: [0; 64 * 1024],
            broken: false,
            step: false,
        }
    }

    pub fn cycle(&mut self) {
        if let Some(clock_rate) = self.clock_rate {
            let mut n = 0;
            while (n < clock_rate && !self.broken) || self.step {
                n += self.cpu.step().expect("SEGFAULT") as u32;
                if self.breakpoints[self.cpu.registers.PC as usize] > 0 {
                    self.broken = true;
                    println!("");
                    println!("BREAKPOINT hit at {:04X}", self.cpu.registers.PC);
                }
                self.step = false;
            }
        } else {
            self.cpu.step().expect("SEGFAULT");
            self.step = false;
            if self.breakpoints[self.cpu.registers.PC as usize] > 0 {
                self.broken = true;
                println!("");
                println!("BREAKPOINT hit at {:04X}", self.cpu.registers.PC);
            }
        }
    }

    pub fn try_execute_command(&mut self) {
        if let Ok(input) = self.receiver.try_recv() {
            let mut input: String = input.trim().into();

            if input.len() == 0 {
                if self.monitor.enabled {
                    self.monitor.enabled = false;
                } else {
                    input = self.last_command.clone();
                }
            }

            if input == "source" {
                self.dump_disassembly();
            }

            if input == "list" {
                self.dump_local_disassembly();
            }

            if input.starts_with("monitor") {
                if self.monitor.enabled {
                    self.monitor.enabled = false;
                } else {
                    self.enable_memory_monitor(&input);
                }
            }

            if input.starts_with("memset") {
                let parts: Vec<&str> = input.split(" ").collect();
                if parts.len() < 3 {
                    println!("ERR: Requires 2 arguments. Example: memset 0x00 0x01 to store 0x01 \
                              in 0x00.");
                } else if parts.len() == 3 {
                    if let Ok(dst) = u16::from_str_radix(&parts[1].replace("0x", "")[..], 16) {
                        if let Ok(src) = u8::from_str_radix(&parts[2].replace("0x", "")[..], 16) {
                            self.cpu.memory[dst as usize] = src;
                        } else {
                            println!("ERR: Unable to parse source byte value");
                        }
                    } else {
                        println!("ERR: Unable to parse destination byte value");
                    }
                } else {
                    if let Ok(mut dst) = usize::from_str_radix(&parts[1].replace("0x", "")[..],
                                                               16) {
                        for p in &parts[2..] {
                            if let Ok(byte) = u8::from_str_radix(&p.replace("0x", "")[..], 16) {
                                self.cpu.memory[dst] = byte;
                                dst += 0x01;
                            } else {
                                println!("ERR: Unable to parse source byte value");
                            }
                        }
                    } else {
                        println!("ERR: Unable to parse destination byte value");
                    }
                }
            }

            if input.starts_with("memdmp") {
                // 1 argument assumes 1 memory "page"
                let parts: Vec<&str> = input.split(" ").collect();
                if parts.len() == 2 {
                    let page_number: usize =
                        parts[1].parse().expect("Unable to parse memory page number");

                    self.dump_memory_page(page_number);
                }
            }

            if input.starts_with("break") {
                // 1 argument assumes 1 memory "page"
                let parts: Vec<&str> = input.split(" ").collect();
                if parts.len() == 2 {
                    if let Ok(addr) = usize::from_str_radix(&parts[1][..], 16) {
                        if self.breakpoints[addr] > 0 {
                            self.breakpoints[addr] = 0;
                        } else {
                            self.breakpoints[addr] = 1;
                        }
                    } else {
                        println!("Err: Unable to parse breakpoint address");
                    }
                } else {
                    println!("ERR: Requires 1 argument");
                }
            }

            if input == "continue" {
                self.broken = false;
                println!("Execution resumed");
            }

            if input == "step" {
                self.step = true;
                self.dump_local_disassembly();
            }

            std::io::stdout().write(b"hakka> ").unwrap();
            std::io::stdout().flush().unwrap();

            // Don't assign a blank command as a last command
            if input.len() > 0 {
                self.last_command = input.clone();
            }
        }

    }

    fn enable_memory_monitor(&mut self, input: &str) {
        let parts: Vec<&str> = input.split(" ").collect();
        if parts.len() < 3 {
            println!("ERR: Requires 2 arguments. Example: monitor 0x00 0xFF");
        } else {
            let start = usize::from_str_radix(&parts[1].replace("0x", "")[..], 16).unwrap();
            let end = usize::from_str_radix(&parts[2].replace("0x", "")[..], 16).unwrap();

            self.monitor.start_addr = start;
            self.monitor.end_addr = end;
            self.monitor.enabled = true;

            println!("{:?}", self.monitor);
        }
    }

    fn dump_disassembly(&self) {
        println!("");
        println!("-- Disassembly --");

        let disassembler = Disassembler::with_offset(self.code_offset);
        let pairs = disassembler.disassemble_with_addresses(self.cpu.get_code());
        let result = self.highlight_lines(self.cpu.registers.PC as usize, pairs, false).join("");
        print!("{}", result);
    }

    fn dump_local_disassembly(&self) {
        println!("");
        println!("-- Disassembly --");

        let disassembler = Disassembler::with_offset(self.code_offset);
        let pc = self.cpu.registers.PC as usize;
        let code = self.cpu.get_code();
        let pairs = disassembler.disassemble_with_addresses(code);
        let result = self.highlight_lines(pc, pairs, true).join("");
        print!("{}", result);
    }

    pub fn dump_memory_page(&self, page: usize) {
        let mut addr = page * 0x100;
        println!("-- Memory dump --");
        for chunk in self.cpu.memory[page * 0x100..(page * 0x100) + 0x100].chunks(8) {
            print!("{:04X}: ", addr);
            for b in chunk {
                print!("{:02X} ", *b);
            }
            addr += 0x08;
            println!("");
        }
    }

    pub fn dump_memory(&self) {
        println!("-- Memory dump --");
        for chunk in self.cpu.memory[self.monitor.start_addr..self.monitor.end_addr + 0x01]
            .chunks(8) {
            for b in chunk {
                print!("{:02X} ", *b);
            }
            println!("");
        }
    }

    fn highlight_lines(&self,
                       pc: usize,
                       pairs: Vec<(String, u16)>,
                       limit_results: bool)
                       -> Vec<String> {
        let mut result = Vec::new();

        let base = pc - self.code_offset as usize;

        for pair in pairs {
            if limit_results {
                let start = if base > 0x0A { base - 0x0A } else { 0 };
                if (pair.1 as usize) < start || (pair.1 as usize) > base + 0x0A {
                    continue;
                }
            }
            let current_line = pc as u16 == self.code_offset + pair.1;
            let breakpoint = self.breakpoints[self.code_offset as usize + pair.1 as usize] > 0x00;

            if breakpoint && current_line {
                result.push(format!("> * {}", pair.0));
            } else if breakpoint && !current_line {
                result.push(format!("  * {}", pair.0));
            } else if !breakpoint && current_line {
                result.push(format!(">   {}", pair.0));
            } else {
                result.push(format!("    {}", pair.0));
            }
        }

        result
    }
}<commit_msg>Add 'registers' command and step disassembly after each step<commit_after>extern crate rs6502;

use std::io::{self, BufRead, Write};
use std::sync::mpsc::{channel, Receiver};
use std::thread;

use rs6502::{Cpu, Disassembler};

#[derive(Debug)]
pub struct MemoryMonitor {
    pub enabled: bool,
    start_addr: usize,
    end_addr: usize,
}

pub struct VirtualMachine {
    pub cpu: Cpu,
    pub monitor: MemoryMonitor,
    code_offset: u16,
    clock_rate: Option<u32>,
    receiver: Receiver<String>,
    last_command: String,
    breakpoints: [u8; 64 * 1024],
    broken: bool,
    step: bool,
}

impl VirtualMachine {
    pub fn new<CR>(cpu: Cpu, code_offset: u16, clock_rate: CR) -> VirtualMachine
        where CR: Into<Option<u32>>
    {
        let (tx, rx) = channel();

        thread::spawn(move || {
            std::io::stdout().write(b"hakka> ").unwrap();
            std::io::stdout().flush().unwrap();

            loop {
                let mut line = String::new();
                let stdin = io::stdin();
                stdin.lock().read_line(&mut line).expect("Could not read line");
                tx.send(line).unwrap();
            }
        });

        VirtualMachine {
            cpu: cpu,
            code_offset: code_offset,
            clock_rate: clock_rate.into(),
            receiver: rx,
            monitor: MemoryMonitor {
                enabled: false,
                start_addr: 0,
                end_addr: 0,
            },
            last_command: "".into(),
            breakpoints: [0; 64 * 1024],
            broken: false,
            step: false,
        }
    }

    pub fn cycle(&mut self) {
        if let Some(clock_rate) = self.clock_rate {
            let mut n = 0;
            while (n < clock_rate && !self.broken) || self.step {
                n += self.cpu.step().expect("SEGFAULT") as u32;
                if self.breakpoints[self.cpu.registers.PC as usize] > 0 {
                    self.broken = true;
                    println!("");
                    println!("BREAKPOINT hit at {:04X}", self.cpu.registers.PC);
                }
                if self.step {
                    self.dump_local_disassembly();
                }
                self.step = false;
            }
        } else {
            self.cpu.step().expect("SEGFAULT");
            if self.step {
                self.dump_local_disassembly();
            }
            self.step = false;
            if self.breakpoints[self.cpu.registers.PC as usize] > 0 {
                self.broken = true;
                println!("");
                println!("BREAKPOINT hit at {:04X}", self.cpu.registers.PC);
            }
        }
    }

    pub fn try_execute_command(&mut self) {
        if let Ok(input) = self.receiver.try_recv() {
            let mut input: String = input.trim().into();

            if input.len() == 0 {
                if self.monitor.enabled {
                    self.monitor.enabled = false;
                } else {
                    input = self.last_command.clone();
                }
            }

            if input == "source" {
                self.dump_disassembly();
            }

            if input == "list" {
                self.dump_local_disassembly();
            }

            if input.starts_with("monitor") {
                if self.monitor.enabled {
                    self.monitor.enabled = false;
                } else {
                    self.enable_memory_monitor(&input);
                }
            }

            if input.starts_with("memset") {
                let parts: Vec<&str> = input.split(" ").collect();
                if parts.len() < 3 {
                    println!("ERR: Requires 2 arguments. Example: memset 0x00 0x01 to store 0x01 \
                              in 0x00.");
                } else if parts.len() == 3 {
                    if let Ok(dst) = u16::from_str_radix(&parts[1].replace("0x", "")[..], 16) {
                        if let Ok(src) = u8::from_str_radix(&parts[2].replace("0x", "")[..], 16) {
                            self.cpu.memory[dst as usize] = src;
                        } else {
                            println!("ERR: Unable to parse source byte value");
                        }
                    } else {
                        println!("ERR: Unable to parse destination byte value");
                    }
                } else {
                    if let Ok(mut dst) = usize::from_str_radix(&parts[1].replace("0x", "")[..],
                                                               16) {
                        for p in &parts[2..] {
                            if let Ok(byte) = u8::from_str_radix(&p.replace("0x", "")[..], 16) {
                                self.cpu.memory[dst] = byte;
                                dst += 0x01;
                            } else {
                                println!("ERR: Unable to parse source byte value");
                            }
                        }
                    } else {
                        println!("ERR: Unable to parse destination byte value");
                    }
                }
            }

            if input.starts_with("memdmp") {
                // 1 argument assumes 1 memory "page"
                let parts: Vec<&str> = input.split(" ").collect();
                if parts.len() == 2 {
                    let page_number: usize =
                        parts[1].parse().expect("Unable to parse memory page number");

                    self.dump_memory_page(page_number);
                }
            }

            if input == "registers" {
                self.dump_registers();
            }

            if input.starts_with("break") {
                // 1 argument assumes 1 memory "page"
                let parts: Vec<&str> = input.split(" ").collect();
                if parts.len() == 2 {
                    if let Ok(addr) = usize::from_str_radix(&parts[1][..], 16) {
                        if self.breakpoints[addr] > 0 {
                            self.breakpoints[addr] = 0;
                        } else {
                            self.breakpoints[addr] = 1;
                        }
                    } else {
                        println!("Err: Unable to parse breakpoint address");
                    }
                } else {
                    println!("ERR: Requires 1 argument");
                }
            }

            if input == "continue" {
                self.broken = false;
                println!("Execution resumed");
            }

            if input == "step" {
                self.step = true;
            }

            std::io::stdout().write(b"hakka> ").unwrap();
            std::io::stdout().flush().unwrap();

            // Don't assign a blank command as a last command
            if input.len() > 0 {
                self.last_command = input.clone();
            }
        }

    }

    fn enable_memory_monitor(&mut self, input: &str) {
        let parts: Vec<&str> = input.split(" ").collect();
        if parts.len() < 3 {
            println!("ERR: Requires 2 arguments. Example: monitor 0x00 0xFF");
        } else {
            let start = usize::from_str_radix(&parts[1].replace("0x", "")[..], 16).unwrap();
            let end = usize::from_str_radix(&parts[2].replace("0x", "")[..], 16).unwrap();

            self.monitor.start_addr = start;
            self.monitor.end_addr = end;
            self.monitor.enabled = true;

            println!("{:?}", self.monitor);
        }
    }

    fn dump_disassembly(&self) {
        println!("");
        println!("-- Disassembly --");

        let disassembler = Disassembler::with_offset(self.code_offset);
        let pairs = disassembler.disassemble_with_addresses(self.cpu.get_code());
        let result = self.highlight_lines(self.cpu.registers.PC as usize, pairs, false).join("");
        print!("{}", result);
    }

    fn dump_local_disassembly(&self) {
        println!("");
        println!("-- Disassembly --");

        let disassembler = Disassembler::with_offset(self.code_offset);
        let pc = self.cpu.registers.PC as usize;
        let code = self.cpu.get_code();
        let pairs = disassembler.disassemble_with_addresses(code);
        let result = self.highlight_lines(pc, pairs, true).join("");
        print!("{}", result);
    }

    pub fn dump_memory_page(&self, page: usize) {
        let mut addr = page * 0x100;
        println!("-- Memory dump --");
        for chunk in self.cpu.memory[page * 0x100..(page * 0x100) + 0x100].chunks(8) {
            print!("{:04X}: ", addr);
            for b in chunk {
                print!("{:02X} ", *b);
            }
            addr += 0x08;
            println!("");
        }
    }

    pub fn dump_memory(&self) {
        println!("-- Memory dump --");
        for chunk in self.cpu.memory[self.monitor.start_addr..self.monitor.end_addr + 0x01]
            .chunks(8) {
            for b in chunk {
                print!("{:02X} ", *b);
            }
            println!("");
        }
    }

    fn dump_registers(&self) {
        println!("-- Registers --");
        println!("A: {} ({:04X})", self.cpu.registers.A, self.cpu.registers.A);
        println!("X: {} ({:04X})", self.cpu.registers.X, self.cpu.registers.X);
        println!("Y: {} ({:04X})", self.cpu.registers.Y, self.cpu.registers.Y);
        println!("PC: {} ({:04X})",
                 self.cpu.registers.PC,
                 self.cpu.registers.PC);
        println!("S: {} ({:04X})",
                 self.cpu.stack.pointer,
                 self.cpu.stack.pointer);
    }

    fn highlight_lines(&self,
                       pc: usize,
                       pairs: Vec<(String, u16)>,
                       limit_results: bool)
                       -> Vec<String> {
        let mut result = Vec::new();

        let base = pc - self.code_offset as usize;

        for pair in pairs {
            if limit_results {
                let start = if base > 0x0A { base - 0x0A } else { 0 };
                if (pair.1 as usize) < start || (pair.1 as usize) > base + 0x0A {
                    continue;
                }
            }
            let current_line = pc as u16 == self.code_offset + pair.1;
            let breakpoint = self.breakpoints[self.code_offset as usize + pair.1 as usize] > 0x00;

            if breakpoint && current_line {
                result.push(format!("> * {}", pair.0));
            } else if breakpoint && !current_line {
                result.push(format!("  * {}", pair.0));
            } else if !breakpoint && current_line {
                result.push(format!(">   {}", pair.0));
            } else {
                result.push(format!("    {}", pair.0));
            }
        }

        result
    }
}<|endoftext|>