<commit_before>//! Defines hir-level representation of structs, enums and unions

use std::sync::Arc;

use either::Either;
use hir_expand::{
    name::{AsName, Name},
    InFile,
};
use ra_arena::{map::ArenaMap, Arena};
use ra_prof::profile;
use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner};

use crate::{
    body::{CfgExpander, LowerCtx},
    db::DefDatabase,
    item_tree::{Field, Fields, ItemTree},
    src::HasChildSource,
    src::HasSource,
    trace::Trace,
    type_ref::TypeRef,
    visibility::RawVisibility,
    EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId,
    VariantId,
};
use ra_cfg::CfgOptions;

/// Note that we use `StructData` for unions as well!
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructData {
    pub name: Name,
    pub variant_data: Arc<VariantData>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumData {
    pub name: Name,
    pub variants: Arena<EnumVariantData>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumVariantData {
    pub name: Name,
    pub variant_data: Arc<VariantData>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VariantData {
    Record(Arena<FieldData>),
    Tuple(Arena<FieldData>),
    Unit,
}

/// A single field of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldData {
    pub name: Name,
    pub type_ref: TypeRef,
    pub visibility: RawVisibility,
}

impl StructData {
    pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
        let loc = id.lookup(db);
        let item_tree = db.item_tree(loc.id.file_id);
        let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();

        let strukt = &item_tree[loc.id.value];
        let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields);

        Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) })
    }
    pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
        let loc = id.lookup(db);
        let item_tree = db.item_tree(loc.id.file_id);
        let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();

        let union = &item_tree[loc.id.value];
        let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields);

        Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) })
    }
}

impl EnumData {
    pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
        let _p = profile("enum_data_query");
        let src = e.lookup(db).source(db);
        let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
        let mut trace = Trace::new_for_arena();
        lower_enum(db, &mut trace, &src, e.lookup(db).container.module(db));
        Arc::new(EnumData { name, variants: trace.into_arena() })
    }

    pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
        let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
        Some(id)
    }
}

impl HasChildSource for EnumId {
    type ChildId = LocalEnumVariantId;
    type Value = ast::EnumVariant;
    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
        let src = self.lookup(db).source(db);
        let mut trace = Trace::new_for_map();
        lower_enum(db, &mut trace, &src, self.lookup(db).container.module(db));
        src.with_value(trace.into_map())
    }
}

fn lower_enum(
    db: &dyn DefDatabase,
    trace: &mut Trace<EnumVariantData, ast::EnumVariant>,
    ast: &InFile<ast::EnumDef>,
    module_id: ModuleId,
) {
    let expander = CfgExpander::new(db, ast.file_id, module_id.krate);
    let variants = ast
        .value
        .variant_list()
        .into_iter()
        .flat_map(|it| it.variants())
        .filter(|var| expander.is_cfg_enabled(var));
    for var in variants {
        trace.alloc(
            || var.clone(),
            || EnumVariantData {
                name: var.name().map_or_else(Name::missing, |it| it.as_name()),
                variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)),
            },
        );
    }
}

impl VariantData {
    fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self {
        let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate);
        let mut trace = Trace::new_for_arena();
        match lower_struct(db, &mut expander, &mut trace, &flavor) {
            StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
            StructKind::Record => VariantData::Record(trace.into_arena()),
            StructKind::Unit => VariantData::Unit,
        }
    }

    pub fn fields(&self) -> &Arena<FieldData> {
        const EMPTY: &Arena<FieldData> = &Arena::new();
        match &self {
            VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
            _ => EMPTY,
        }
    }

    pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
        self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
    }

    pub fn kind(&self) -> StructKind {
        match self {
            VariantData::Record(_) => StructKind::Record,
            VariantData::Tuple(_) => StructKind::Tuple,
            VariantData::Unit => StructKind::Unit,
        }
    }
}

impl HasChildSource for VariantId {
    type ChildId = LocalFieldId;
    type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>;

    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
        let (src, module_id) = match self {
            VariantId::EnumVariantId(it) => {
                // I don't really like the fact that we call into parent source
                // here, this might add to more queries then necessary.
                let src = it.parent.child_source(db);
                (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container.module(db))
            }
            VariantId::StructId(it) => {
                (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container.module(db))
            }
            VariantId::UnionId(it) => (
                it.lookup(db).source(db).map(|it| {
                    it.record_field_def_list()
                        .map(ast::StructKind::Record)
                        .unwrap_or(ast::StructKind::Unit)
                }),
                it.lookup(db).container.module(db),
            ),
        };
        let mut expander = CfgExpander::new(db, src.file_id, module_id.krate);
        let mut trace = Trace::new_for_map();
        lower_struct(db, &mut expander, &mut trace, &src);
        src.with_value(trace.into_map())
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum StructKind {
    Tuple,
    Record,
    Unit,
}

fn lower_struct(
    db: &dyn DefDatabase,
    expander: &mut CfgExpander,
    trace: &mut Trace<FieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
    ast: &InFile<ast::StructKind>,
) -> StructKind {
    let ctx = LowerCtx::new(db, ast.file_id);

    match &ast.value {
        ast::StructKind::Tuple(fl) => {
            for (i, fd) in fl.fields().enumerate() {
                if !expander.is_cfg_enabled(&fd) {
                    continue;
                }

                trace.alloc(
                    || Either::Left(fd.clone()),
                    || FieldData {
                        name: Name::new_tuple_field(i),
                        type_ref: TypeRef::from_ast_opt(&ctx, fd.type_ref()),
                        visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
                    },
                );
            }
            StructKind::Tuple
        }
        ast::StructKind::Record(fl) => {
            for fd in fl.fields() {
                if !expander.is_cfg_enabled(&fd) {
                    continue;
                }

                trace.alloc(
                    || Either::Right(fd.clone()),
                    || FieldData {
                        name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
                        type_ref: TypeRef::from_ast_opt(&ctx, fd.ascribed_type()),
                        visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
                    },
                );
            }
            StructKind::Record
        }
        ast::StructKind::Unit => StructKind::Unit,
    }
}

fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) -> VariantData {
    match fields {
        Fields::Record(flds) => {
            let mut arena = Arena::new();
            for field_id in flds.clone() {
                if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
                    arena.alloc(lower_field(item_tree, &item_tree[field_id]));
                }
            }
            VariantData::Record(arena)
        }
        Fields::Tuple(flds) => {
            let mut arena = Arena::new();
            for field_id in flds.clone() {
                if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
                    arena.alloc(lower_field(item_tree, &item_tree[field_id]));
                }
            }
            VariantData::Tuple(arena)
        }
        Fields::Unit => VariantData::Unit,
    }
}

fn lower_field(item_tree: &ItemTree, field: &Field) -> FieldData {
    FieldData {
        name: field.name.clone(),
        type_ref: field.type_ref.clone(),
        visibility: item_tree[field.visibility].clone(),
    }
}
<commit_msg>Use ItemTree to answer enum_data query<commit_after>//! Defines hir-level representation of structs, enums and unions

use std::sync::Arc;

use either::Either;
use hir_expand::{
    name::{AsName, Name},
    InFile,
};
use ra_arena::{map::ArenaMap, Arena};
use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner};

use crate::{
    body::{CfgExpander, LowerCtx},
    db::DefDatabase,
    item_tree::{Field, Fields, ItemTree},
    src::HasChildSource,
    src::HasSource,
    trace::Trace,
    type_ref::TypeRef,
    visibility::RawVisibility,
    EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId,
    VariantId,
};
use ra_cfg::CfgOptions;

/// Note that we use `StructData` for unions as well!
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructData {
    pub name: Name,
    pub variant_data: Arc<VariantData>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumData {
    pub name: Name,
    pub variants: Arena<EnumVariantData>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumVariantData {
    pub name: Name,
    pub variant_data: Arc<VariantData>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VariantData {
    Record(Arena<FieldData>),
    Tuple(Arena<FieldData>),
    Unit,
}

/// A single field of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldData {
    pub name: Name,
    pub type_ref: TypeRef,
    pub visibility: RawVisibility,
}

impl StructData {
    pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
        let loc = id.lookup(db);
        let item_tree = db.item_tree(loc.id.file_id);
        let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();

        let strukt = &item_tree[loc.id.value];
        let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields);

        Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) })
    }
    pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
        let loc = id.lookup(db);
        let item_tree = db.item_tree(loc.id.file_id);
        let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();

        let union = &item_tree[loc.id.value];
        let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields);

        Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) })
    }
}

impl EnumData {
    pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
        let loc = e.lookup(db);
        let item_tree = db.item_tree(loc.id.file_id);
        let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();

        let enum_ = &item_tree[loc.id.value];
        let mut variants = Arena::new();
        for var_id in enum_.variants.clone() {
            if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) {
                let var = &item_tree[var_id];
                let var_data = lower_fields(&item_tree, &cfg_options, &var.fields);

                variants.alloc(EnumVariantData {
                    name: var.name.clone(),
                    variant_data: Arc::new(var_data),
                });
            }
        }

        Arc::new(EnumData { name: enum_.name.clone(), variants })
    }

    pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
        let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
        Some(id)
    }
}

impl HasChildSource for EnumId {
    type ChildId = LocalEnumVariantId;
    type Value = ast::EnumVariant;
    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
        let src = self.lookup(db).source(db);
        let mut trace = Trace::new_for_map();
        lower_enum(db, &mut trace, &src, self.lookup(db).container.module(db));
        src.with_value(trace.into_map())
    }
}

fn lower_enum(
    db: &dyn DefDatabase,
    trace: &mut Trace<EnumVariantData, ast::EnumVariant>,
    ast: &InFile<ast::EnumDef>,
    module_id: ModuleId,
) {
    let expander = CfgExpander::new(db, ast.file_id, module_id.krate);
    let variants = ast
        .value
        .variant_list()
        .into_iter()
        .flat_map(|it| it.variants())
        .filter(|var| expander.is_cfg_enabled(var));
    for var in variants {
        trace.alloc(
            || var.clone(),
            || EnumVariantData {
                name: var.name().map_or_else(Name::missing, |it| it.as_name()),
                variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)),
            },
        );
    }
}

impl VariantData {
    fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self {
        let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate);
        let mut trace = Trace::new_for_arena();
        match lower_struct(db, &mut expander, &mut trace, &flavor) {
            StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
            StructKind::Record => VariantData::Record(trace.into_arena()),
            StructKind::Unit => VariantData::Unit,
        }
    }

    pub fn fields(&self) -> &Arena<FieldData> {
        const EMPTY: &Arena<FieldData> = &Arena::new();
        match &self {
            VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
            _ => EMPTY,
        }
    }

    pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
        self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
    }

    pub fn kind(&self) -> StructKind {
        match self {
            VariantData::Record(_) => StructKind::Record,
            VariantData::Tuple(_) => StructKind::Tuple,
            VariantData::Unit => StructKind::Unit,
        }
    }
}

impl HasChildSource for VariantId {
    type ChildId = LocalFieldId;
    type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>;

    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
        let (src, module_id) = match self {
            VariantId::EnumVariantId(it) => {
                // I don't really like the fact that we call into parent source
                // here, this might add to more queries then necessary.
                let src = it.parent.child_source(db);
                (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container.module(db))
            }
            VariantId::StructId(it) => {
                (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container.module(db))
            }
            VariantId::UnionId(it) => (
                it.lookup(db).source(db).map(|it| {
                    it.record_field_def_list()
                        .map(ast::StructKind::Record)
                        .unwrap_or(ast::StructKind::Unit)
                }),
                it.lookup(db).container.module(db),
            ),
        };
        let mut expander = CfgExpander::new(db, src.file_id, module_id.krate);
        let mut trace = Trace::new_for_map();
        lower_struct(db, &mut expander, &mut trace, &src);
        src.with_value(trace.into_map())
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum StructKind {
    Tuple,
    Record,
    Unit,
}

fn lower_struct(
    db: &dyn DefDatabase,
    expander: &mut CfgExpander,
    trace: &mut Trace<FieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
    ast: &InFile<ast::StructKind>,
) -> StructKind {
    let ctx = LowerCtx::new(db, ast.file_id);

    match &ast.value {
        ast::StructKind::Tuple(fl) => {
            for (i, fd) in fl.fields().enumerate() {
                if !expander.is_cfg_enabled(&fd) {
                    continue;
                }

                trace.alloc(
                    || Either::Left(fd.clone()),
                    || FieldData {
                        name: Name::new_tuple_field(i),
                        type_ref: TypeRef::from_ast_opt(&ctx, fd.type_ref()),
                        visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
                    },
                );
            }
            StructKind::Tuple
        }
        ast::StructKind::Record(fl) => {
            for fd in fl.fields() {
                if !expander.is_cfg_enabled(&fd) {
                    continue;
                }

                trace.alloc(
                    || Either::Right(fd.clone()),
                    || FieldData {
                        name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
                        type_ref: TypeRef::from_ast_opt(&ctx, fd.ascribed_type()),
                        visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
                    },
                );
            }
            StructKind::Record
        }
        ast::StructKind::Unit => StructKind::Unit,
    }
}

fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) -> VariantData {
    match fields {
        Fields::Record(flds) => {
            let mut arena = Arena::new();
            for field_id in flds.clone() {
                if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
                    arena.alloc(lower_field(item_tree, &item_tree[field_id]));
                }
            }
            VariantData::Record(arena)
        }
        Fields::Tuple(flds) => {
            let mut arena = Arena::new();
            for field_id in flds.clone() {
                if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
                    arena.alloc(lower_field(item_tree, &item_tree[field_id]));
                }
            }
            VariantData::Tuple(arena)
        }
        Fields::Unit => VariantData::Unit,
    }
}

fn lower_field(item_tree: &ItemTree, field: &Field) -> FieldData {
    FieldData {
        name: field.name.clone(),
        type_ref: field.type_ref.clone(),
        visibility: item_tree[field.visibility].clone(),
    }
}
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {

	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        let new_cpu_state = self.execute(cpu_state,mem);
        // Perform logging, recording here...
        *cpu_state = new_cpu_state
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);
        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState, mut mem:&Memory) -> CpuState {

    	// The state of the CPU after executing the current instruction.
    	let mut new_cpu_state = cpu_state.clone();

    	// Figure out which opcode is being executed.
    	let ref decode_register = cpu_state.decode_register;

    	match decode_register.info.opcode_class {

    		// ASL (Arithmetic Shift Left)
    		OpcodeClass::ASL => {

				// Shift accumulator to the left.
				new_cpu_state.a = cpu_state.a << 1;
				// Carry flag gets set to the most significant bit.
				new_cpu_state.C = (128 & cpu_state.a) > 0;
				// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// LDA (Load Accumulator)
    		OpcodeClass::LDA => {
    			new_cpu_state.a = decode_register.value_final.unwrap()
    		},

    		// LDX (Load X)
    		OpcodeClass::LDX => {
    			new_cpu_state.x = decode_register.value_final.unwrap()
    		},

    		// LDY (Load Y)
    		OpcodeClass::LDY => {
    			new_cpu_state.y = decode_register.value_final.unwrap()
    		},

    		// LSR (Logical Shift Right)
    		OpcodeClass::LSR => {

    			// Shift accumulator to the right.
    			new_cpu_state.a = cpu_state.a >> 1;
    			// Carry flag gets set to the least significant bit.
    			new_cpu_state.C = 1 & cpu_state.a > 0;
    			// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// NOP (No Operation)
    		OpcodeClass::NOP => {},

    		// Default: not sure what this opcode is.
			_ => panic!("Unrecognised opcode class: {:?}", decode_register.info.opcode_class)

    	}

    	// Expression returned is the updated cpu_state.
    	new_cpu_state
    }

}

<commit_msg>fetch was incrementing the pc incorrectly<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {

	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        let new_cpu_state = self.execute(cpu_state,mem);
        // Perform logging, recording here...
        *cpu_state = new_cpu_state
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);
        //cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
        cpu_state.pc = cpu_state.pc+1;
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState, mut mem:&Memory) -> CpuState {

    	// The state of the CPU after executing the current instruction.
    	let mut new_cpu_state = cpu_state.clone();

    	// Figure out which opcode is being executed.
    	let ref decode_register = cpu_state.decode_register;

    	match decode_register.info.opcode_class {

    		// ASL (Arithmetic Shift Left)
    		OpcodeClass::ASL => {

				// Shift accumulator to the left.
				new_cpu_state.a = cpu_state.a << 1;
				// Carry flag gets set to the most significant bit.
				new_cpu_state.C = (128 & cpu_state.a) > 0;
				// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// LDA (Load Accumulator)
    		OpcodeClass::LDA => {
    			new_cpu_state.a = decode_register.value_final.unwrap()
    		},

    		// LDX (Load X)
    		OpcodeClass::LDX => {
    			new_cpu_state.x = decode_register.value_final.unwrap()
    		},

    		// LDY (Load Y)
    		OpcodeClass::LDY => {
    			new_cpu_state.y = decode_register.value_final.unwrap()
    		},

    		// LSR (Logical Shift Right)
    		OpcodeClass::LSR => {

    			// Shift accumulator to the right.
    			new_cpu_state.a = cpu_state.a >> 1;
    			// Carry flag gets set to the least significant bit.
    			new_cpu_state.C = 1 & cpu_state.a > 0;
    			// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// NOP (No Operation)
    		OpcodeClass::NOP => {},

    		// Default: not sure what this opcode is.
			_ => panic!("Unrecognised opcode class: {:?}", decode_register.info.opcode_class)

    	}

    	// Expression returned is the updated cpu_state.
    	new_cpu_state
    }

}

<|endoftext|>


<commit_before>extern crate futures;
#[macro_use]
extern crate iron;
extern crate persistent;
extern crate staticfile;
extern crate mount;
extern crate gluon;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::fs::{File, read_dir};
use std::io::{self, Read};
use std::time::Instant;

use futures::Async;

use iron::mime::Mime;
use iron::prelude::*;
use iron::status;
use iron::typemap::Key;

use serde_json::Value;

use staticfile::Static;

use mount::Mount;

use gluon::vm::thread::{RootedThread, Thread, ThreadInternal};
use gluon::vm::Error;
use gluon::vm::api::{Hole, OpaqueValue};
use gluon::Compiler;
use gluon::import::{DefaultImporter, Import};

pub struct VMKey;

impl Key for VMKey {
    type Value = RootedThread;
}

fn eval(req: &mut Request) -> IronResult<Response> {
    eval_(req).map(|s| {
        let mime: Mime = "text/plain".parse().unwrap();

        Response::with((status::Ok, mime, serde_json::to_string(&s).unwrap()))
    })
}

fn eval_(req: &mut Request) -> IronResult<String> {
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Eval: `{}`", body);

    let global_vm = req.get::<persistent::Read<VMKey>>().unwrap();
    let vm = match global_vm.new_thread() {
        Ok(vm) => vm,
        Err(err) => return Ok(format!("{}", err)),
    };

    // Prevent a single thread from allocating to much memory
    vm.set_memory_limit(2_000_000);

    {
        let mut context = vm.context();

        // Prevent the stack from consuming to much memory
        context.set_max_stack_size(10000);

        // Prevent infinite loops from running forever
        let start = Instant::now();
        context.set_hook(Some(Box::new(move |_, _| if start.elapsed().as_secs() < 10 {
            Ok(Async::Ready(()))
        } else {
            Err(Error::Message("Thread has exceeded the allowed exection time".into()))
        })));
    }

    let (value, typ) = match Compiler::new()
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "<top>", &body) {
        Ok(value) => value,
        Err(err) => return Ok(format!("{}", err)),
    };

    Ok(format!("{:?} : {}", value, typ))
}

pub struct Examples;

impl Key for Examples {
    type Value = String;
}

fn examples(req: &mut Request) -> IronResult<Response> {
    let s = req.get::<persistent::Read<Examples>>().unwrap();
    Ok(Response::with((status::Ok, (*s).clone())))
}

/// Load all examples into a JSON array `[{ name: .., value: .. }, ..]`
fn load_examples() -> Value {
    let vec = read_dir("public/examples")
        .unwrap()
        .map(|entry| {
            let path = try!(entry).path();
            let name = String::from(path.file_stem().unwrap().to_str().unwrap());
            let mut file = try!(File::open(path));
            let mut contents = String::new();

            try!(file.read_to_string(&mut contents));

            let value = vec![("name".into(), Value::String(name)),
                             ("value".into(), Value::String(contents))];

            Ok(Value::Object(value.into_iter().collect()))
        })
        .collect::<io::Result<_>>()
        .unwrap();

    Value::Array(vec)
}

fn make_eval_vm() -> RootedThread {
    let vm = RootedThread::new();

    // Ensure the import macro cannot be abused to to open files
    {
        // Ensure the lock to `paths` are released
        let import = Import::new(DefaultImporter);
        import.paths.write().unwrap().clear();
        vm.get_macros()
            .insert(String::from("import"), import);
    }

    // Initialize the basic types such as `Bool` and `Option` so they are available when loading
    // other modules
    Compiler::new()
        .implicit_prelude(false)
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "", r#" import "std/types.glu" "#)
        .unwrap();

    gluon::vm::primitives::load(&vm).expect("Loaded primitives library");
    // Load the io library so the prelude can be loaded (`IO` actions won't actually execute however)
    gluon::io::load(&vm).expect("Loaded IO library");

    vm
}

fn main() {
    env_logger::init().unwrap();
    let mut mount = Mount::new();

    mount.mount("/", Static::new("dist"));

    {
        let mut middleware = Chain::new(eval);

        let vm = make_eval_vm();
        middleware.link(persistent::Read::<VMKey>::both(vm));

        mount.mount("/eval", middleware);
    }

    {
        let mut middleware = Chain::new(examples);
        let examples_string = serde_json::to_string(&load_examples()).unwrap();

        middleware.link(persistent::Read::<Examples>::both(examples_string));
        mount.mount("/examples", middleware);
    }

    let address = "0.0.0.0:8080";

    // Dropping `server` causes it to block so keep it alive until the end of scope
    let _server = Iron::new(mount).http(address).unwrap();

    println!("Server started at `{}`", address);
}
<commit_msg>feat: Print values using the new value printer<commit_after>extern crate futures;
#[macro_use]
extern crate iron;
extern crate persistent;
extern crate staticfile;
extern crate mount;
extern crate gluon;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::fs::{File, read_dir};
use std::io::{self, Read};
use std::time::Instant;

use futures::Async;

use iron::mime::Mime;
use iron::prelude::*;
use iron::status;
use iron::typemap::Key;

use serde_json::Value;

use staticfile::Static;

use mount::Mount;

use gluon::base::symbol::{Symbol, SymbolRef};
use gluon::base::kind::{ArcKind, KindEnv};
use gluon::base::types::{Alias, ArcType, TypeEnv};
use gluon::vm::thread::{RootedThread, Thread, ThreadInternal};
use gluon::vm::Error;
use gluon::vm::internal::ValuePrinter;
use gluon::vm::api::{Hole, OpaqueValue};
use gluon::Compiler;
use gluon::import::{DefaultImporter, Import};

pub struct EmptyEnv;

impl KindEnv for EmptyEnv {
    fn find_kind(&self, _type_name: &SymbolRef) -> Option<ArcKind> {
        None
    }
}

impl TypeEnv for EmptyEnv {
    fn find_type(&self, _id: &SymbolRef) -> Option<&ArcType> {
        None
    }
    fn find_type_info(&self, _id: &SymbolRef) -> Option<&Alias<Symbol, ArcType>> {
        None
    }
    fn find_record(&self, _fields: &[Symbol]) -> Option<(ArcType, ArcType)> {
        None
    }
}

pub struct VMKey;

impl Key for VMKey {
    type Value = RootedThread;
}

fn eval(req: &mut Request) -> IronResult<Response> {
    eval_(req).map(|s| {
        let mime: Mime = "text/plain".parse().unwrap();

        Response::with((status::Ok, mime, serde_json::to_string(&s).unwrap()))
    })
}

fn eval_(req: &mut Request) -> IronResult<String> {
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Eval: `{}`", body);

    let global_vm = req.get::<persistent::Read<VMKey>>().unwrap();
    let vm = match global_vm.new_thread() {
        Ok(vm) => vm,
        Err(err) => return Ok(format!("{}", err)),
    };

    // Prevent a single thread from allocating to much memory
    vm.set_memory_limit(2_000_000);

    {
        let mut context = vm.context();

        // Prevent the stack from consuming to much memory
        context.set_max_stack_size(10000);

        // Prevent infinite loops from running forever
        let start = Instant::now();
        context.set_hook(Some(Box::new(move |_, _| if start.elapsed().as_secs() < 10 {
            Ok(Async::Ready(()))
        } else {
            Err(Error::Message("Thread has exceeded the allowed exection time".into()))
        })));
    }

    let (value, typ) = match Compiler::new()
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "<top>", &body) {
        Ok(value) => value,
        Err(err) => return Ok(format!("{}", err)),
    };

    unsafe {
        Ok(format!("{} : {}",
                   ValuePrinter::new(&EmptyEnv, &typ, value.get_value()).max_level(6),
                   typ))
    }
}

pub struct Examples;

impl Key for Examples {
    type Value = String;
}

fn examples(req: &mut Request) -> IronResult<Response> {
    let s = req.get::<persistent::Read<Examples>>().unwrap();
    Ok(Response::with((status::Ok, (*s).clone())))
}

/// Load all examples into a JSON array `[{ name: .., value: .. }, ..]`
fn load_examples() -> Value {
    let vec = read_dir("public/examples")
        .unwrap()
        .map(|entry| {
            let path = try!(entry).path();
            let name = String::from(path.file_stem().unwrap().to_str().unwrap());
            let mut file = try!(File::open(path));
            let mut contents = String::new();

            try!(file.read_to_string(&mut contents));

            let value = vec![("name".into(), Value::String(name)),
                             ("value".into(), Value::String(contents))];

            Ok(Value::Object(value.into_iter().collect()))
        })
        .collect::<io::Result<_>>()
        .unwrap();

    Value::Array(vec)
}

fn make_eval_vm() -> RootedThread {
    let vm = RootedThread::new();

    // Ensure the import macro cannot be abused to to open files
    {
        // Ensure the lock to `paths` are released
        let import = Import::new(DefaultImporter);
        import.paths.write().unwrap().clear();
        vm.get_macros()
            .insert(String::from("import"), import);
    }

    // Initialize the basic types such as `Bool` and `Option` so they are available when loading
    // other modules
    Compiler::new()
        .implicit_prelude(false)
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "", r#" import "std/types.glu" "#)
        .unwrap();

    gluon::vm::primitives::load(&vm).expect("Loaded primitives library");
    // Load the io library so the prelude can be loaded (`IO` actions won't actually execute however)
    gluon::io::load(&vm).expect("Loaded IO library");

    vm
}

fn main() {
    env_logger::init().unwrap();
    let mut mount = Mount::new();

    mount.mount("/", Static::new("dist"));

    {
        let mut middleware = Chain::new(eval);

        let vm = make_eval_vm();
        middleware.link(persistent::Read::<VMKey>::both(vm));

        mount.mount("/eval", middleware);
    }

    {
        let mut middleware = Chain::new(examples);
        let examples_string = serde_json::to_string(&load_examples()).unwrap();

        middleware.link(persistent::Read::<Examples>::both(examples_string));
        mount.mount("/examples", middleware);
    }

    let address = "0.0.0.0:8080";

    // Dropping `server` causes it to block so keep it alive until the end of scope
    let _server = Iron::new(mount).http(address).unwrap();

    println!("Server started at `{}`", address);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Robert Collins. Licensed under the Apache-2.0 license.
use std::collections::BTreeMap;
use std::net::Ipv4Addr;
#[cfg(test)]
use std::str::FromStr;
use std::time::{Duration, SystemTime};

use pnet::util::MacAddr;

pub struct CacheEntry {
    pub mac: MacAddr,
    pub expires: SystemTime,
}

pub struct Cache {
    pub entries: BTreeMap<Ipv4Addr, CacheEntry>,
}

impl Cache {

    pub fn new() -> Cache {
        Cache {entries: BTreeMap::new()}
    }

    pub fn lookup<'a>(&'a mut self, addr: &Ipv4Addr) -> Option<&'a MacAddr> {
        self.entries.get(addr).map(|e| &e.mac)
    }

    pub fn add(& mut self, ip: &Ipv4Addr, mac: &MacAddr) {
        self.entries.insert(*ip, CacheEntry {mac: *mac, expires:SystemTime::now()+Duration::new(30,0)});
    }

    pub fn expire(& mut self) {
        let now = SystemTime::now();
        let mut expired: Vec<Ipv4Addr> = Vec::new();
        for (ip, entry) in self.entries.iter_mut() {
            if entry.expires < now {
                println!("expiring");
                expired.push(*ip);
            }
        }
        for ip in expired {
            self.entries.remove(&ip);
        }
    }
}

#[test]
fn add_and_lookup_expire() {
    let mut c = Cache::new();
    let target_mac = MacAddr::from_str("aa:aa:aa:aa:aa:aa").unwrap();
    let some_ip = Ipv4Addr::from_str("127.0.0.1").unwrap();
    let past = SystemTime::now() - Duration::new(1,0);
    c.add(&some_ip, &target_mac);
    c.lookup(&some_ip).unwrap();
    c.expire();
    c.lookup(&some_ip).unwrap();
    c.entries.insert(some_ip, CacheEntry {mac: target_mac, expires: past});
    c.expire();
    let maybe_ip = c.lookup(&some_ip);
    if let Some(_) = maybe_ip {
        panic!("Failed to expire cached entry.");
    }
}
<commit_msg>rustfmt<commit_after>// Copyright (c) 2016 Robert Collins. Licensed under the Apache-2.0 license.
use std::collections::BTreeMap;
use std::net::Ipv4Addr;
#[cfg(test)]
use std::str::FromStr;
use std::time::{Duration, SystemTime};

use pnet::util::MacAddr;

pub struct CacheEntry {
    pub mac: MacAddr,
    pub expires: SystemTime,
}

pub struct Cache {
    pub entries: BTreeMap<Ipv4Addr, CacheEntry>,
}

impl Cache {
    pub fn new() -> Cache {
        Cache { entries: BTreeMap::new() }
    }

    pub fn lookup<'a>(&'a mut self, addr: &Ipv4Addr) -> Option<&'a MacAddr> {
        self.entries.get(addr).map(|e| &e.mac)
    }

    pub fn add(&mut self, ip: &Ipv4Addr, mac: &MacAddr) {
        self.entries.insert(*ip,
                            CacheEntry {
                                mac: *mac,
                                expires: SystemTime::now() + Duration::new(30, 0),
                            });
    }

    pub fn expire(&mut self) {
        let now = SystemTime::now();
        let mut expired: Vec<Ipv4Addr> = Vec::new();
        for (ip, entry) in self.entries.iter_mut() {
            if entry.expires < now {
                println!("expiring");
                expired.push(*ip);
            }
        }
        for ip in expired {
            self.entries.remove(&ip);
        }
    }
}

#[test]
fn add_and_lookup_expire() {
    let mut c = Cache::new();
    let target_mac = MacAddr::from_str("aa:aa:aa:aa:aa:aa").unwrap();
    let some_ip = Ipv4Addr::from_str("127.0.0.1").unwrap();
    let past = SystemTime::now() - Duration::new(1, 0);
    c.add(&some_ip, &target_mac);
    c.lookup(&some_ip).unwrap();
    c.expire();
    c.lookup(&some_ip).unwrap();
    c.entries.insert(some_ip,
                     CacheEntry {
                         mac: target_mac,
                         expires: past,
                     });
    c.expire();
    let maybe_ip = c.lookup(&some_ip);
    if let Some(_) = maybe_ip {
        panic!("Failed to expire cached entry.");
    }
}
<|endoftext|>


<commit_before>use graphics::{ self, DrawState, Graphics, Viewport };
use graphics::color::gamma_srgb_to_linear;
use glium::{
    Frame, Surface, Program, VertexBuffer,
};
use glium::index::{ NoIndices, PrimitiveType };
use glium::backend::Facade;
use shader_version::{ Shaders, OpenGL };
use shader_version::glsl::GLSL;
use Texture;

use draw_state;

#[derive(Copy, Clone)]
struct PlainVertex {
    pos: [f32; 2],
}

implement_vertex!(PlainVertex, pos);

#[derive(Copy, Clone)]
struct TexturedVertex {
    pos: [f32; 2],
    uv: [f32; 2],
}

implement_vertex!(TexturedVertex, pos, uv);

/// The resources needed for rendering 2D.
pub struct Glium2d {
    plain_buffer: VertexBuffer<PlainVertex>,
    textured_buffer: VertexBuffer<TexturedVertex>,
    shader_texture: Program,
    shader_color: Program,
}

impl Glium2d {
    /// Creates a new `Glium2d`.
    pub fn new<W>(opengl: OpenGL, window: &W) -> Glium2d where W: Facade {
        use shaders::{ colored, textured };

        let src = |bytes| { unsafe { ::std::str::from_utf8_unchecked(bytes) } };
        let glsl = opengl.to_glsl();

        Glium2d {
            plain_buffer: VertexBuffer::empty_dynamic(window, graphics::BACK_END_MAX_VERTEX_COUNT).unwrap(),
            textured_buffer: VertexBuffer::empty_dynamic(window, graphics::BACK_END_MAX_VERTEX_COUNT).unwrap(),
            shader_texture:
                Program::from_source(window,
                                     Shaders::new().set(GLSL::V1_20, src(textured::VERTEX_GLSL_120))
                                                   .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE))
                                                   .get(glsl).unwrap(),
                                     Shaders::new().set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120))
                                                   .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE))
                                                   .get(glsl).unwrap(),
                                     None).ok().expect("failed to initialize textured shader"),
            shader_color:
                Program::from_source(window,
                                     Shaders::new().set(GLSL::V1_20, src(colored::VERTEX_GLSL_120))
                                                   .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE))
                                                   .get(glsl).unwrap(),
                                     Shaders::new().set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120))
                                                   .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE))
                                                   .get(glsl).unwrap(),
                                     None).ok().expect("failed to initialize colored shader"),
        }
    }

    /// Renders 2D graphics.
    pub fn draw<F>(&mut self, target: &mut Frame, viewport: Viewport, f: F) where
        F: FnOnce(graphics::Context, &mut GliumGraphics<Frame>)
    {
        use graphics::Context;

        let ref mut g = GliumGraphics::new(self, target);
        let c = Context::new_viewport(viewport);
        f(c, g);
    }
}

/// Graphics back-end.
pub struct GliumGraphics<'d, 's, S: 's> {
    system: &'d mut Glium2d,
    surface: &'s mut S,
}

impl<'d, 's, S> GliumGraphics<'d, 's, S> {
    /// Creates a new graphics object.
    pub fn new(system: &'d mut Glium2d, surface: &'s mut S)
               -> GliumGraphics<'d, 's, S> {
        GliumGraphics {
            system: system,
            surface: surface,
        }
    }
}

/// Implemented by all graphics back-ends.
impl<'d, 's, S: Surface> Graphics for GliumGraphics<'d, 's, S> {
    type Texture = Texture;

    /// Clears background with a color.
    fn clear_color(&mut self, color: [f32; 4]) {
        let color = gamma_srgb_to_linear(color);
        let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
        self.surface.clear_color(r, g, b, a);
    }

    fn clear_stencil(&mut self, value: u8) {
        self.surface.clear_stencil(value as i32);
    }

    /// Renders list of 2d triangles.
    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        f(&mut |vertices: &[f32]| {
            self.system.plain_buffer.invalidate();
            let slice = self.system.plain_buffer.slice(0..vertices.len() / 2).unwrap();

            slice.write({
                &(0 .. vertices.len() / 2)
                    .map(|i| PlainVertex {
                        pos: [vertices[2 * i], vertices[2 * i + 1]]
                    })
                    .collect::<Vec<_>>()
            });

            self.surface.draw(
                slice,
                &NoIndices(PrimitiveType::TrianglesList),
                &self.system.shader_color,
                &uniform! { color: color },
                &draw_state::convert_draw_state(draw_state),
            )
            .ok()
            .expect("failed to draw triangle list");
        })
    }

    /// Renders list of 2d triangles.
    ///
    /// A texture coordinate is assigned per vertex.
    /// The texture coordinates refers to the current texture.
    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        use std::cmp::min;

        let color = gamma_srgb_to_linear(*color);
        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let len = min(vertices.len(), texture_coords.len()) / 2;

            self.system.textured_buffer.invalidate();
            let slice = self.system.textured_buffer.slice(0..len).unwrap();

            slice.write({
                &(0 .. len)
                    .map(|i| TexturedVertex {
                        pos: [vertices[2 * i], vertices[2 * i + 1]],
                        // FIXME: The `1.0 - ...` is because of a wrong convention
                        uv: [texture_coords[2 * i], 1.0 - texture_coords[2 * i + 1]]
                    })
                    .collect::<Vec<_>>()
            });

            let ref texture = texture.0;
            self.surface.draw(
                slice,
                &NoIndices(PrimitiveType::TrianglesList),
                &self.system.shader_texture,
                &uniform! {
                    color: color,
                    s_texture: texture
                },
                &draw_state::convert_draw_state(draw_state),
            )
            .ok()
            .expect("failed to draw triangle list");
        })
    }
}
<commit_msg>Made `Glium2d::draw` return generic type<commit_after>use graphics::{ self, DrawState, Graphics, Viewport };
use graphics::color::gamma_srgb_to_linear;
use glium::{
    Frame, Surface, Program, VertexBuffer,
};
use glium::index::{ NoIndices, PrimitiveType };
use glium::backend::Facade;
use shader_version::{ Shaders, OpenGL };
use shader_version::glsl::GLSL;
use Texture;

use draw_state;

#[derive(Copy, Clone)]
struct PlainVertex {
    pos: [f32; 2],
}

implement_vertex!(PlainVertex, pos);

#[derive(Copy, Clone)]
struct TexturedVertex {
    pos: [f32; 2],
    uv: [f32; 2],
}

implement_vertex!(TexturedVertex, pos, uv);

/// The resources needed for rendering 2D.
pub struct Glium2d {
    plain_buffer: VertexBuffer<PlainVertex>,
    textured_buffer: VertexBuffer<TexturedVertex>,
    shader_texture: Program,
    shader_color: Program,
}

impl Glium2d {
    /// Creates a new `Glium2d`.
    pub fn new<W>(opengl: OpenGL, window: &W) -> Glium2d where W: Facade {
        use shaders::{ colored, textured };

        let src = |bytes| { unsafe { ::std::str::from_utf8_unchecked(bytes) } };
        let glsl = opengl.to_glsl();

        Glium2d {
            plain_buffer: VertexBuffer::empty_dynamic(window, graphics::BACK_END_MAX_VERTEX_COUNT).unwrap(),
            textured_buffer: VertexBuffer::empty_dynamic(window, graphics::BACK_END_MAX_VERTEX_COUNT).unwrap(),
            shader_texture:
                Program::from_source(window,
                                     Shaders::new().set(GLSL::V1_20, src(textured::VERTEX_GLSL_120))
                                                   .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE))
                                                   .get(glsl).unwrap(),
                                     Shaders::new().set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120))
                                                   .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE))
                                                   .get(glsl).unwrap(),
                                     None).ok().expect("failed to initialize textured shader"),
            shader_color:
                Program::from_source(window,
                                     Shaders::new().set(GLSL::V1_20, src(colored::VERTEX_GLSL_120))
                                                   .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE))
                                                   .get(glsl).unwrap(),
                                     Shaders::new().set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120))
                                                   .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE))
                                                   .get(glsl).unwrap(),
                                     None).ok().expect("failed to initialize colored shader"),
        }
    }

    /// Renders 2D graphics.
    pub fn draw<F, U>(&mut self, target: &mut Frame, viewport: Viewport, f: F) -> U where
        F: FnOnce(graphics::Context, &mut GliumGraphics<Frame>) -> U
    {
        use graphics::Context;

        let ref mut g = GliumGraphics::new(self, target);
        let c = Context::new_viewport(viewport);
        f(c, g)
    }
}

/// Graphics back-end.
pub struct GliumGraphics<'d, 's, S: 's> {
    system: &'d mut Glium2d,
    surface: &'s mut S,
}

impl<'d, 's, S> GliumGraphics<'d, 's, S> {
    /// Creates a new graphics object.
    pub fn new(system: &'d mut Glium2d, surface: &'s mut S)
               -> GliumGraphics<'d, 's, S> {
        GliumGraphics {
            system: system,
            surface: surface,
        }
    }
}

/// Implemented by all graphics back-ends.
impl<'d, 's, S: Surface> Graphics for GliumGraphics<'d, 's, S> {
    type Texture = Texture;

    /// Clears background with a color.
    fn clear_color(&mut self, color: [f32; 4]) {
        let color = gamma_srgb_to_linear(color);
        let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
        self.surface.clear_color(r, g, b, a);
    }

    fn clear_stencil(&mut self, value: u8) {
        self.surface.clear_stencil(value as i32);
    }

    /// Renders list of 2d triangles.
    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        f(&mut |vertices: &[f32]| {
            self.system.plain_buffer.invalidate();
            let slice = self.system.plain_buffer.slice(0..vertices.len() / 2).unwrap();

            slice.write({
                &(0 .. vertices.len() / 2)
                    .map(|i| PlainVertex {
                        pos: [vertices[2 * i], vertices[2 * i + 1]]
                    })
                    .collect::<Vec<_>>()
            });

            self.surface.draw(
                slice,
                &NoIndices(PrimitiveType::TrianglesList),
                &self.system.shader_color,
                &uniform! { color: color },
                &draw_state::convert_draw_state(draw_state),
            )
            .ok()
            .expect("failed to draw triangle list");
        })
    }

    /// Renders list of 2d triangles.
    ///
    /// A texture coordinate is assigned per vertex.
    /// The texture coordinates refers to the current texture.
    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        use std::cmp::min;

        let color = gamma_srgb_to_linear(*color);
        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let len = min(vertices.len(), texture_coords.len()) / 2;

            self.system.textured_buffer.invalidate();
            let slice = self.system.textured_buffer.slice(0..len).unwrap();

            slice.write({
                &(0 .. len)
                    .map(|i| TexturedVertex {
                        pos: [vertices[2 * i], vertices[2 * i + 1]],
                        // FIXME: The `1.0 - ...` is because of a wrong convention
                        uv: [texture_coords[2 * i], 1.0 - texture_coords[2 * i + 1]]
                    })
                    .collect::<Vec<_>>()
            });

            let ref texture = texture.0;
            self.surface.draw(
                slice,
                &NoIndices(PrimitiveType::TrianglesList),
                &self.system.shader_texture,
                &uniform! {
                    color: color,
                    s_texture: texture
                },
                &draw_state::convert_draw_state(draw_state),
            )
            .ok()
            .expect("failed to draw triangle list");
        })
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix break_statement to get complete break statements without label at end of input<commit_after><|endoftext|>


<commit_before><commit_msg>Made interpret_expr take &self rather than &mut self.<commit_after><|endoftext|>


<commit_before>mod beacon_chain;
mod checkpoint;
mod errors;
pub mod initialise;
pub mod test_utils;

pub use self::beacon_chain::{
    AttestationValidationError, BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock,
};
pub use self::checkpoint::CheckPoint;
pub use self::errors::{BeaconChainError, BlockProductionError};
pub use db;
pub use fork_choice;
pub use parking_lot;
pub use slot_clock;
pub use state_processing::per_block_processing::errors::{
    AttestationValidationError, AttesterSlashingValidationError, DepositValidationError,
    ExitValidationError, ProposerSlashingValidationError, TransferValidationError,
};
pub use types;
<commit_msg>Correct compile error<commit_after>mod beacon_chain;
mod checkpoint;
mod errors;
pub mod initialise;
pub mod test_utils;

pub use self::beacon_chain::{BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock};
pub use self::checkpoint::CheckPoint;
pub use self::errors::{BeaconChainError, BlockProductionError};
pub use db;
pub use fork_choice;
pub use parking_lot;
pub use slot_clock;
pub use state_processing::per_block_processing::errors::{
    AttestationValidationError, AttesterSlashingValidationError, DepositValidationError,
    ExitValidationError, ProposerSlashingValidationError, TransferValidationError,
};
pub use types;
<|endoftext|>


<commit_before>use std::env;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::Error;
use std::io::prelude::*;

extern crate rustbox;

use rustbox::{Color, RustBox};
use rustbox::Key;

static BANKOCOLS: usize = 9;
static BANKOROWS: usize = 3;

#[derive(Clone, Copy)]
enum Mode {
	Normal,
	Moving,
}

struct Video {
	rustbox: RustBox,
	mode: Mode,
}

impl Video {
	fn init() -> Video {
		let rustbox = match RustBox::init(Default::default()) {
			Ok(val) => val,
			Err(e) => panic!("{}", e),
		};

		let v = Video {
			rustbox: rustbox,
			mode: Mode::Normal,
		};

		v.draw_top();

		v
	}

	fn draw_top(&self) {
		let text = "L: Luk  G: Gem  F: Flyttetilstand";
		let x = self.rustbox.width()/2 - text.len()/2;

		self.rustbox.print(x, 2, rustbox::RB_BOLD, Color::Default, Color::Default, "L");
		self.rustbox.print(x+1, 2, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Luk");
		self.rustbox.print(x+8, 2, rustbox::RB_BOLD, Color::Default, Color::Default, "G");
		self.rustbox.print(x+9, 2, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Gem");
		self.rustbox.print(x+16, 2, rustbox::RB_BOLD, Color::Default, Color::Default, "F");
		self.rustbox.print(x+17, 2, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Flyttetilstand");

		let text2 = "Venstre/Højre: Flyt";
		let x2 = self.rustbox.width()/2 - text2.len()/2;

		self.rustbox.print(x2, 3, rustbox::RB_BOLD, Color::Default, Color::Default, "Venstre");
		self.rustbox.print(x2+7, 3, rustbox::RB_NORMAL, Color::Default, Color::Default, "/");
		self.rustbox.print(x2+8, 3, rustbox::RB_BOLD, Color::Default, Color::Default, "Højre");
		match self.mode {
			Mode::Normal => self.rustbox.print(x2+13, 3, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Skift"),
			Mode::Moving => self.rustbox.print(x2+13, 3, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Flyt "),
		}
		self.rustbox.present();
	}

	fn display_status(&self, text: &str) {
		self.rustbox.print(2, 0, rustbox::RB_BOLD, Color::Default, Color::Default, text);

		self.rustbox.present();
	}

	fn clear_status(&self) {
		self.rustbox.print(0, 0, rustbox::RB_NORMAL, Color::Default, Color::Default, &(0..self.rustbox.width()).map(|_| " ").collect::<String>());

		self.rustbox.present();
	}

	fn draw_plade(&self, n: usize, total: usize,
			      plade: [[u16; 9]; 3]) {
		let toptext = if n == 0 {
			format!("  {}/{} >", n+1, total)
		} else if n == total - 1 {
			format!("< {}/{}  ", n+1, total)
		} else {
			format!("< {}/{} >", n+1, total)
		};
		let x = self.rustbox.width()/2 - toptext.len()/2;
		self.rustbox.print(1, 1, rustbox::RB_NORMAL, Color::Default, Color::Default, &(0..self.rustbox.width()).map(|_| " ").collect::<String>());
		self.rustbox.print(x, 1, rustbox::RB_NORMAL, Color::Default, Color::Default, &toptext);

		let line = "+----+----+----+----+----+----+----+----+----+";
		let space = "|    |    |    |    |    |    |    |    |    |";
		let nonumber = "|    ";

		let x = self.rustbox.width()/2 - line.len()/2;
		let y = 6;

		self.rustbox.print(x, y, rustbox::RB_NORMAL, Color::Default, Color::Default, line);
		for row in 0..plade.len() {
		self.rustbox.print(x, y + row*4 + 1, rustbox::RB_NORMAL, Color::Default, Color::Default, space);
			for col in 0..plade[row].len() {
				let ff = plade[row][col];
				let text = if ff == 0 {
					nonumber.to_string()
				} else if ff < 10 {
					format!("|  {} ", ff)
				} else {
					format!("| {}", ff)
				};
				self.rustbox.print(x + nonumber.len()*col, y + row*4 + 2, rustbox::RB_NORMAL, Color::Default, Color::Default, &text);
			}
			self.rustbox.print(x + nonumber.len()*plade[row].len(), y + row*4 + 2, rustbox::RB_NORMAL, Color::Default, Color::Default, "|");
			self.rustbox.print(x, y + row*4 + 3, rustbox::RB_NORMAL, Color::Default, Color::Default, space);
			self.rustbox.print(x, y + row*4 + 4, rustbox::RB_NORMAL, Color::Default, Color::Default, line);
		}

		self.rustbox.present();
	}

	fn set_mode(&mut self, mode: Mode) {
		self.mode = mode;
		self.draw_top();
	}
}

fn save_plader(filename: &str, plader: &Vec<[[u16; 9]; 3]>) -> Result<usize, io::Error> {
	let mut f = try!(OpenOptions::new().write(true).open(filename));

	for plade in plader {
		for row in 0..BANKOROWS {
			for col in 0..BANKOCOLS {
				if col + 1 == BANKOCOLS {
					try!(write!(f, "{:02}", plade[row][col]));
				} else {
					try!(write!(f, "{:02} ", plade[row][col]));
				}
			}
			try!(f.write(b"\n"));
		}
		try!(f.write(b"\n"));
	}

	try!(f.flush());

	Ok(plader.len() as usize)
}

fn parse_bankopladeformat(filename: &str) -> Vec<[[u16; 9]; 3]> {
	let mut f = match File::open(&filename) {
		Ok(val) => val,
		Err(_) => panic!("Den fil kan jeg altså ikke åbne, Preben."),
	};

	let mut buffer = String::new();

	match f.read_to_string(&mut buffer) {
		Ok(_) => {},
		Err(_) => panic!("Det er sgu' da ikke til at læse..."),
	}

	let mut plader: Vec<[[u16; 9]; 3]> = Vec::new();

	let mut plade: [[u16; 9]; 3] = [[0, 0, 0, 0, 0, 0, 0, 0, 0],
	                                [0, 0, 0, 0, 0, 0, 0, 0, 0],
	                                [0, 0, 0, 0, 0, 0, 0, 0, 0]];
	let mut row = 0;
	let mut col = 0;
	let mut current_field: i16 = -1;

	for c in buffer.chars() {
		if col >= BANKOCOLS {
			panic!("Slet format: For mange felter! ({})", c);
		}
		if row > BANKOROWS {
			panic!("Slet format: For mange rækker! ({})", c);
		}
		if c == '\n' {
			if current_field >= 0 {
				plade[row][col] = current_field as u16;
				current_field = -1;
				col = 0;
				row += 1;
			} else {
				plader.push(plade);
				plade = [[0, 0, 0, 0, 0, 0, 0, 0, 0],
				         [0, 0, 0, 0, 0, 0, 0, 0, 0],
				         [0, 0, 0, 0, 0, 0, 0, 0, 0]];
				row = 0;
			}
		} else if c == ' ' {
			plade[row][col] = current_field as u16;
			current_field = -1;
			col += 1;
		} else {
			if current_field == -1 {
				current_field = match c.to_digit(10) {
					Some(val) => val as i16 * 10,
					None      => 0,
				};
			} else {
				current_field += match c.to_digit(10) {
					Some(val) => val as i16,
					None      => 0,
				};
			}
		}
	}

	plader
}

fn main() {
	let filename = match env::args().nth(1) {
		Some(val) => val,
		None      => panic!("Du glemte vist at angive en fil, dit kvaj!"),
	};

	let mut plader = parse_bankopladeformat(&filename);

	let mut v = Video::init();

	let mut current: usize = 0;
	let mut mode = Mode::Normal;
	let mut till_clear = 0;

	'main: loop {
		v.draw_plade(current, plader.len(), plader[current]);
		if till_clear > 0 {
			till_clear -= 1;
		} else {
			v.clear_status();
		}

		match v.rustbox.poll_event(false) {
			Ok(rustbox::Event::KeyEvent(key)) => {
				match key {
					Some(Key::Char('q')) => { break 'main; },
					Some(Key::Char('l')) => { break 'main; },
					Some(Key::Char('g')) => {
						v.clear_status();
						till_clear = 5;
						match save_plader(&filename, &plader) {
							Ok(_) => {
								v.display_status("Gemt!");
							},
							Err(e) => {
								v.display_status(&format!("En fejl! {}", e));
							},
						}
					},
					Some(Key::Char('f')) => {
						mode = match mode {
							Mode::Normal => Mode::Moving,
							Mode::Moving => Mode::Normal,
						};
						v.set_mode(mode);
					},
					Some(Key::Right) => {
						match mode {
							Mode::Moving => {
								if current + 1 < plader.len() {
									plader.swap(current, current+1);
								}
							},
							_ => {},
						}
						current = if current + 1 < plader.len() { current + 1 } else { current };
					},
					Some(Key::Left) => {
						match mode {
							Mode::Moving => {
								if current > 0 {
									plader.swap(current-1, current);
								}
							},
							_ => {},
						}
						current = if current > 0 { current - 1 } else { current };
					},
					_ => {},
				}
			},
			Err(e) => panic!("{}", e),
			_ => {}
		}
	}
}
<commit_msg>Nu med forhåndsvisning af forrige og næste plade i flyttetilstand.<commit_after>use std::env;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::Error;
use std::io::prelude::*;

extern crate rustbox;

use rustbox::{Color, RustBox};
use rustbox::Key;

static BANKOCOLS: usize = 9;
static BANKOROWS: usize = 3;

#[derive(Clone, Copy, PartialEq)]
enum Mode {
	Normal,
	Moving,
}

struct Video {
	rustbox: RustBox,
	mode: Mode,
}

impl Video {
	fn init() -> Video {
		let rustbox = match RustBox::init(Default::default()) {
			Ok(val) => val,
			Err(e) => panic!("{}", e),
		};

		let v = Video {
			rustbox: rustbox,
			mode: Mode::Normal,
		};

		v.draw_top();

		v
	}

	fn draw_top(&self) {
		let text = "L: Luk  G: Gem  F: Flyttetilstand";
		let x = self.rustbox.width()/2 - text.len()/2;

		self.rustbox.print(x, 2, rustbox::RB_BOLD, Color::Default, Color::Default, "L");
		self.rustbox.print(x+1, 2, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Luk");
		self.rustbox.print(x+8, 2, rustbox::RB_BOLD, Color::Default, Color::Default, "G");
		self.rustbox.print(x+9, 2, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Gem");
		self.rustbox.print(x+16, 2, rustbox::RB_BOLD, Color::Default, Color::Default, "F");
		self.rustbox.print(x+17, 2, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Flyttetilstand");

		let text2 = "Venstre/Højre: Flyt";
		let x2 = self.rustbox.width()/2 - text2.len()/2;

		self.rustbox.print(x2, 3, rustbox::RB_BOLD, Color::Default, Color::Default, "Venstre");
		self.rustbox.print(x2+7, 3, rustbox::RB_NORMAL, Color::Default, Color::Default, "/");
		self.rustbox.print(x2+8, 3, rustbox::RB_BOLD, Color::Default, Color::Default, "Højre");
		match self.mode {
			Mode::Normal => self.rustbox.print(x2+13, 3, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Skift"),
			Mode::Moving => self.rustbox.print(x2+13, 3, rustbox::RB_NORMAL, Color::Default, Color::Default, ": Flyt "),
		}
		self.rustbox.present();
	}

	fn display_status(&self, text: &str) {
		self.rustbox.print(2, 0, rustbox::RB_BOLD, Color::Default, Color::Default, text);

		self.rustbox.present();
	}

	fn clear_status(&self) {
		self.rustbox.print(0, 0, rustbox::RB_NORMAL, Color::Default, Color::Default, &(0..self.rustbox.width()).map(|_| " ").collect::<String>());

		self.rustbox.present();
	}

	fn draw_previous_plade(&self, plade: [[u16; 9]; 3]) {
		let line = "+----+----+----+----+----+----+----+----+----+";

		let endx = self.rustbox.width()/2 - line.len()/2 - 5;
		let y = 6;

		let mut col = BANKOCOLS - 1;

		for rcol in 0..BANKOCOLS-1 {
			if endx < rcol*5 {
				break;
			}
			let colx = endx - rcol*5;
			for row in 0..plade.len() {
				let ff = plade[row][col];
				let text = if ff == 0 {
					"|    ".to_string()
				} else if ff < 10 {
					format!("|  {} ", ff)
				} else {
					format!("| {}", ff)
				};
				self.rustbox.print(colx, y + row*4, rustbox::RB_NORMAL, Color::White, Color::Default, "+----");
				self.rustbox.print(colx, y + row*4 + 1, rustbox::RB_NORMAL, Color::White, Color::Default, "|    ");
				self.rustbox.print(colx, y + row*4 + 2, rustbox::RB_NORMAL, Color::White, Color::Default, &text);
				self.rustbox.print(colx, y + row*4 + 3, rustbox::RB_NORMAL, Color::White, Color::Default, "|    ");
			}
			self.rustbox.print(colx, y + (plade.len()-1)*4 + 4, rustbox::RB_NORMAL, Color::White, Color::Default, "+----");
			col -= 1;
		}

		self.rustbox.present();
	}

	fn draw_next_plade(&self, plade: [[u16; 9]; 3]) {
		let line = "+----+----+----+----+----+----+----+----+----+";

		let x = self.rustbox.width()/2 + line.len()/2;
		let y = 6;

		for col in 0..BANKOCOLS-1 {
			if x + col*5 > self.rustbox.width() {
				break;
			}
			let colx = x + col*5;
			for row in 0..plade.len() {
				let ff = plade[row][col];
				let text = if ff == 0 {
					"    |".to_string()
				} else if ff < 10 {
					format!("  {} |", ff)
				} else {
					format!(" {} |", ff)
				};
				self.rustbox.print(colx, y + row*4, rustbox::RB_NORMAL, Color::White, Color::Default, "----+");
				self.rustbox.print(colx, y + row*4 + 1, rustbox::RB_NORMAL, Color::White, Color::Default, "    |");
				self.rustbox.print(colx, y + row*4 + 2, rustbox::RB_NORMAL, Color::White, Color::Default, &text);
				self.rustbox.print(colx, y + row*4 + 3, rustbox::RB_NORMAL, Color::White, Color::Default, "    |");
			}
			self.rustbox.print(colx, y + (plade.len()-1)*4 + 4, rustbox::RB_NORMAL, Color::White, Color::Default, "----+");
		}

		self.rustbox.present();
	}

	fn draw_plade(&self, n: usize, total: usize,
			      plade: [[u16; 9]; 3]) {
		// clean up!
		for y in 0..BANKOROWS*4 + 1 {
			self.rustbox.print(1, 6+y, rustbox::RB_NORMAL, Color::Default, Color::Default, &(0..self.rustbox.width()).map(|_| " ").collect::<String>());
		}
		let toptext = if n == 0 {
			format!("  {}/{} >", n+1, total)
		} else if n == total - 1 {
			format!("< {}/{}  ", n+1, total)
		} else {
			format!("< {}/{} >", n+1, total)
		};
		let x = self.rustbox.width()/2 - toptext.len()/2;
		self.rustbox.print(1, 1, rustbox::RB_NORMAL, Color::Default, Color::Default, &(0..self.rustbox.width()).map(|_| " ").collect::<String>());
		self.rustbox.print(x, 1, rustbox::RB_NORMAL, Color::Default, Color::Default, &toptext);

		let line = "+----+----+----+----+----+----+----+----+----+";
		let space = "|    |    |    |    |    |    |    |    |    |";
		let nonumber = "|    ";

		let x = self.rustbox.width()/2 - line.len()/2;
		let y = 6;

		self.rustbox.print(x, y, rustbox::RB_NORMAL, Color::Default, Color::Default, line);
		for row in 0..plade.len() {
		self.rustbox.print(x, y + row*4 + 1, rustbox::RB_NORMAL, Color::Default, Color::Default, space);
			for col in 0..plade[row].len() {
				let ff = plade[row][col];
				let text = if ff == 0 {
					nonumber.to_string()
				} else if ff < 10 {
					format!("|  {} ", ff)
				} else {
					format!("| {}", ff)
				};
				self.rustbox.print(x + nonumber.len()*col, y + row*4 + 2, rustbox::RB_NORMAL, Color::Default, Color::Default, &text);
			}
			self.rustbox.print(x + nonumber.len()*plade[row].len(), y + row*4 + 2, rustbox::RB_NORMAL, Color::Default, Color::Default, "|");
			self.rustbox.print(x, y + row*4 + 3, rustbox::RB_NORMAL, Color::Default, Color::Default, space);
			self.rustbox.print(x, y + row*4 + 4, rustbox::RB_NORMAL, Color::Default, Color::Default, line);
		}

		self.rustbox.present();
	}

	fn set_mode(&mut self, mode: Mode) {
		self.mode = mode;
		self.draw_top();
	}
}

fn save_plader(filename: &str, plader: &Vec<[[u16; 9]; 3]>) -> Result<usize, io::Error> {
	let mut f = try!(OpenOptions::new().write(true).open(filename));

	for plade in plader {
		for row in 0..BANKOROWS {
			for col in 0..BANKOCOLS {
				if col + 1 == BANKOCOLS {
					try!(write!(f, "{:02}", plade[row][col]));
				} else {
					try!(write!(f, "{:02} ", plade[row][col]));
				}
			}
			try!(f.write(b"\n"));
		}
		try!(f.write(b"\n"));
	}

	try!(f.flush());

	Ok(plader.len() as usize)
}

fn parse_bankopladeformat(filename: &str) -> Vec<[[u16; 9]; 3]> {
	let mut f = match File::open(&filename) {
		Ok(val) => val,
		Err(_) => panic!("Den fil kan jeg altså ikke åbne, Preben."),
	};

	let mut buffer = String::new();

	match f.read_to_string(&mut buffer) {
		Ok(_) => {},
		Err(_) => panic!("Det er sgu' da ikke til at læse..."),
	}

	let mut plader: Vec<[[u16; 9]; 3]> = Vec::new();

	let mut plade: [[u16; 9]; 3] = [[0, 0, 0, 0, 0, 0, 0, 0, 0],
	                                [0, 0, 0, 0, 0, 0, 0, 0, 0],
	                                [0, 0, 0, 0, 0, 0, 0, 0, 0]];
	let mut row = 0;
	let mut col = 0;
	let mut current_field: i16 = -1;

	for c in buffer.chars() {
		if col >= BANKOCOLS {
			panic!("Slet format: For mange felter! ({})", c);
		}
		if row > BANKOROWS {
			panic!("Slet format: For mange rækker! ({})", c);
		}
		if c == '\n' {
			if current_field >= 0 {
				plade[row][col] = current_field as u16;
				current_field = -1;
				col = 0;
				row += 1;
			} else {
				plader.push(plade);
				plade = [[0, 0, 0, 0, 0, 0, 0, 0, 0],
				         [0, 0, 0, 0, 0, 0, 0, 0, 0],
				         [0, 0, 0, 0, 0, 0, 0, 0, 0]];
				row = 0;
			}
		} else if c == ' ' {
			plade[row][col] = current_field as u16;
			current_field = -1;
			col += 1;
		} else {
			if current_field == -1 {
				current_field = match c.to_digit(10) {
					Some(val) => val as i16 * 10,
					None      => 0,
				};
			} else {
				current_field += match c.to_digit(10) {
					Some(val) => val as i16,
					None      => 0,
				};
			}
		}
	}

	plader
}

fn main() {
	let filename = match env::args().nth(1) {
		Some(val) => val,
		None      => panic!("Du glemte vist at angive en fil, dit kvaj!"),
	};

	let mut plader = parse_bankopladeformat(&filename);

	let mut v = Video::init();

	let mut current: usize = 0;
	let mut mode = Mode::Normal;
	let mut till_clear = 0;

	'main: loop {
		v.draw_plade(current, plader.len(), plader[current]);
		if current > 0 && mode == Mode::Moving {
			v.draw_previous_plade(plader[current-1]);
		}
		if current + 1 < plader.len() && mode == Mode::Moving {
			v.draw_next_plade(plader[current+1]);
		}
		if till_clear > 1 {
			till_clear -= 1;
		} else if till_clear == 1 {
			v.clear_status();
			till_clear -= 1;
		}

		match v.rustbox.poll_event(false) {
			Ok(rustbox::Event::KeyEvent(key)) => {
				match key {
					Some(Key::Char('q')) => { break 'main; },
					Some(Key::Char('l')) => { break 'main; },
					Some(Key::Char('g')) => {
						v.clear_status();
						till_clear = 5;
						match save_plader(&filename, &plader) {
							Ok(_) => {
								v.display_status("Gemt!");
							},
							Err(e) => {
								v.display_status(&format!("En fejl! {}", e));
							},
						}
					},
					Some(Key::Char('f')) => {
						mode = match mode {
							Mode::Normal => Mode::Moving,
							Mode::Moving => Mode::Normal,
						};
						v.set_mode(mode);
					},
					Some(Key::Right) => {
						match mode {
							Mode::Moving => {
								if current + 1 < plader.len() {
									plader.swap(current, current+1);
								}
							},
							_ => {},
						}
						current = if current + 1 < plader.len() { current + 1 } else { current };
					},
					Some(Key::Left) => {
						match mode {
							Mode::Moving => {
								if current > 0 {
									plader.swap(current-1, current);
								}
							},
							_ => {},
						}
						current = if current > 0 { current - 1 } else { current };
					},
					_ => {},
				}
			},
			Err(e) => panic!("{}", e),
			_ => {}
		}
	}
}
<|endoftext|>


<commit_before>use core::pin::Pin;
use futures_core::future::{Future, FusedFuture};
use futures_core::task::{Context, Poll};
use crate::future::{Either, FutureExt};

/// Future for the [`select()`] function.
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[derive(Debug)]
pub struct Select<A, B> {
    inner: Option<(A, B)>,
}

impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {}

/// Waits for either one of two differently-typed futures to complete.
///
/// This function will return a new future which awaits for either one of both
/// futures to complete. The returned future will finish with both the value
/// resolved and a future representing the completion of the other work.
///
/// Note that this function consumes the receiving futures and returns a
/// wrapped version of them.
///
/// Also note that if both this and the second future have the same
/// output type you can use the `Either::factor_first` method to
/// conveniently extract out the value at the end.
///
/// # Examples
///
/// ```
/// use futures::future::{self, Either, Future, FutureExt};
///
/// // A poor-man's join implemented on top of select
///
/// fn join<A, B, E>(a: A, b: B) -> impl Future<Output=(A::Output, B::Output)>
///     where A: Future + Unpin,
///           B: Future + Unpin,
/// {
///     future::select(a, b).then(|either| {
///         match either {
///             Either::Left((x, b)) => b.map(move |y| (x, y)).left_future(),
///             Either::Right((y, a)) => a.map(move |x| (x, y)).right_future(),
///         }
///     })
/// }
/// ```
pub fn select<A, B>(future1: A, future2: B) -> Select<A, B>
    where A: Future + Unpin, B: Future + Unpin
{
    Select { inner: Some((future1, future2)) }
}

impl<A, B> Future for Select<A, B>
where
    A: Future + Unpin,
    B: Future + Unpin,
{
    type Output = Either<(A::Output, B), (B::Output, A)>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let (mut a, mut b) = self.inner.take().expect("cannot poll Select twice");
        match a.poll_unpin(cx) {
            Poll::Ready(x) => Poll::Ready(Either::Left((x, b))),
            Poll::Pending => match b.poll_unpin(cx) {
                Poll::Ready(x) => Poll::Ready(Either::Right((x, a))),
                Poll::Pending => {
                    self.inner = Some((a, b));
                    Poll::Pending
                }
            }
        }
    }
}

impl<A, B> FusedFuture for Select<A, B>
where
    A: Future + Unpin,
    B: Future + Unpin,
{
    fn is_terminated(&self) -> bool {
        self.inner.is_none()
    }
}
<commit_msg>Remove unused type parameter<commit_after>use core::pin::Pin;
use futures_core::future::{Future, FusedFuture};
use futures_core::task::{Context, Poll};
use crate::future::{Either, FutureExt};

/// Future for the [`select()`] function.
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[derive(Debug)]
pub struct Select<A, B> {
    inner: Option<(A, B)>,
}

impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {}

/// Waits for either one of two differently-typed futures to complete.
///
/// This function will return a new future which awaits for either one of both
/// futures to complete. The returned future will finish with both the value
/// resolved and a future representing the completion of the other work.
///
/// Note that this function consumes the receiving futures and returns a
/// wrapped version of them.
///
/// Also note that if both this and the second future have the same
/// output type you can use the `Either::factor_first` method to
/// conveniently extract out the value at the end.
///
/// # Examples
///
/// ```
/// use futures::future::{self, Either, Future, FutureExt};
///
/// // A poor-man's join implemented on top of select
///
/// fn join<A, B>(a: A, b: B) -> impl Future<Output=(A::Output, B::Output)>
///     where A: Future + Unpin,
///           B: Future + Unpin,
/// {
///     future::select(a, b).then(|either| {
///         match either {
///             Either::Left((x, b)) => b.map(move |y| (x, y)).left_future(),
///             Either::Right((y, a)) => a.map(move |x| (x, y)).right_future(),
///         }
///     })
/// }
/// ```
pub fn select<A, B>(future1: A, future2: B) -> Select<A, B>
    where A: Future + Unpin, B: Future + Unpin
{
    Select { inner: Some((future1, future2)) }
}

impl<A, B> Future for Select<A, B>
where
    A: Future + Unpin,
    B: Future + Unpin,
{
    type Output = Either<(A::Output, B), (B::Output, A)>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let (mut a, mut b) = self.inner.take().expect("cannot poll Select twice");
        match a.poll_unpin(cx) {
            Poll::Ready(x) => Poll::Ready(Either::Left((x, b))),
            Poll::Pending => match b.poll_unpin(cx) {
                Poll::Ready(x) => Poll::Ready(Either::Right((x, a))),
                Poll::Pending => {
                    self.inner = Some((a, b));
                    Poll::Pending
                }
            }
        }
    }
}

impl<A, B> FusedFuture for Select<A, B>
where
    A: Future + Unpin,
    B: Future + Unpin,
{
    fn is_terminated(&self) -> bool {
        self.inner.is_none()
    }
}
<|endoftext|>


<commit_before>use crate::stream::{StreamExt, Fuse};
use core::pin::Pin;
use futures_core::future::Future;
use futures_core::stream::Stream;
use futures_core::task::{Context, Poll};
use futures_sink::Sink;

/// Future for the [`send_all`](super::SinkExt::send_all) method.
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct SendAll<'a, Si, St>
where
    Si: Sink<St::Item> + Unpin + ?Sized,
    St: Stream + Unpin + ?Sized,
{
    sink: &'a mut Si,
    stream: Fuse<&'a mut St>,
    buffered: Option<St::Item>,
}

// Pinning is never projected to any fields
impl<Si, St> Unpin for SendAll<'_, Si, St>
where
    Si: Sink<St::Item> + Unpin + ?Sized,
    St: Stream + Unpin + ?Sized,
{}

impl<'a, Si, St> SendAll<'a, Si, St>
where
    Si: Sink<St::Item> + Unpin + ?Sized,
    St: Stream + Unpin + ?Sized,
{
    pub(super) fn new(
        sink: &'a mut Si,
        stream: &'a mut St,
    ) -> SendAll<'a, Si, St> {
        SendAll {
            sink,
            stream: stream.fuse(),
            buffered: None,
        }
    }

    fn try_start_send(
        &mut self,
        cx: &mut Context<'_>,
        item: St::Item,
    ) -> Poll<Result<(), Si::Error>> {
        debug_assert!(self.buffered.is_none());
        match Pin::new(&mut self.sink).poll_ready(cx)? {
            Poll::Ready(()) => {
                Poll::Ready(Pin::new(&mut self.sink).start_send(item))
            }
            Poll::Pending => {
                self.buffered = Some(item);
                Poll::Pending
            }
        }
    }
}

impl<Si, St> Future for SendAll<'_, Si, St>
where
    Si: Sink<St::Item> + Unpin + ?Sized,
    St: Stream + Unpin + ?Sized,
{
    type Output = Result<(), Si::Error>;

    fn poll(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Self::Output> {
        let this = &mut *self;
        // If we've got an item buffered already, we need to write it to the
        // sink before we can do anything else
        if let Some(item) = this.buffered.take() {
            ready!(this.try_start_send(cx, item))?
        }

        loop {
            match this.stream.poll_next_unpin(cx) {
                Poll::Ready(Some(item)) => {
                    ready!(this.try_start_send(cx, item))?
                }
                Poll::Ready(None) => {
                    ready!(Pin::new(&mut this.sink).poll_flush(cx))?;
                    return Poll::Ready(Ok(()))
                }
                Poll::Pending => {
                    ready!(Pin::new(&mut this.sink).poll_flush(cx))?;
                    return Poll::Pending
                }
            }
        }
    }
}
<commit_msg>Don't require a full flush before pushing next item in SendAll<commit_after>use crate::stream::{StreamExt, Fuse};
use core::pin::Pin;
use futures_core::future::Future;
use futures_core::stream::Stream;
use futures_core::task::{Context, Poll};
use futures_sink::Sink;

/// Future for the [`send_all`](super::SinkExt::send_all) method.
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct SendAll<'a, Si, St>
where
    Si: Sink<St::Item> + Unpin + ?Sized,
    St: Stream + Unpin + ?Sized,
{
    sink: &'a mut Si,
    stream: Fuse<&'a mut St>,
    buffered: Option<St::Item>,
}

// Pinning is never projected to any fields
impl<Si, St> Unpin for SendAll<'_, Si, St>
where
    Si: Sink<St::Item> + Unpin + ?Sized,
    St: Stream + Unpin + ?Sized,
{}

impl<'a, Si, St> SendAll<'a, Si, St>
where
    Si: Sink<St::Item> + Unpin + ?Sized,
    St: Stream + Unpin + ?Sized,
{
    pub(super) fn new(
        sink: &'a mut Si,
        stream: &'a mut St,
    ) -> SendAll<'a, Si, St> {
        SendAll {
            sink,
            stream: stream.fuse(),
            buffered: None,
        }
    }

    fn try_start_send(
        &mut self,
        cx: &mut Context<'_>,
        item: St::Item,
    ) -> Poll<Result<(), Si::Error>> {
        debug_assert!(self.buffered.is_none());
        match Pin::new(&mut self.sink).poll_ready(cx)? {
            Poll::Ready(()) => {
                Poll::Ready(Pin::new(&mut self.sink).start_send(item))
            }
            Poll::Pending => {
                self.buffered = Some(item);
                Poll::Pending
            }
        }
    }
}

impl<Si, St> Future for SendAll<'_, Si, St>
where
    Si: Sink<St::Item> + Unpin + ?Sized,
    St: Stream + Unpin + ?Sized,
{
    type Output = Result<(), Si::Error>;

    fn poll(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Self::Output> {
        let this = &mut *self;
        // If we've got an item buffered already, we need to write it to the
        // sink before we can do anything else
        if let Some(item) = this.buffered.take() {
            ready!(this.try_start_send(cx, item))?
        }

        loop {
            match this.stream.poll_next_unpin(cx) {
                Poll::Ready(Some(item)) => {
                    ready!(this.try_start_send(cx, item))?
                }
                Poll::Ready(None) => {
                    ready!(Pin::new(&mut this.sink).poll_flush(cx))?;
                    return Poll::Ready(Ok(()))
                }
                Poll::Pending => {
                    ready!(Pin::new(&mut this.sink).poll_ready(cx))?;
                    return Poll::Pending
                }
            }
        }
    }
}
<|endoftext|>