<commit_before>extern crate cleaver;
use cleaver::front;
use cleaver::diagnostics as diag;

extern crate clap;
use clap::{App, Arg};

extern crate time;
use time::PreciseTime;

use std::path::Path;

fn main() {
    // commandline arguments
    let arguments = App::new("Cleaver")
        .about("Cleaver is a toy / research compiler, it takes .gib files as input.")
        .version("0.1")
        .author("Alex Hirsch <W4RH4WK@bluephoenix.at>")
        .arg(Arg::with_name("diagnostics")
            .short("d")
            .help("create various diagnostic outputs during compilation"))
        .arg(Arg::with_name("timings")
            .short("t")
            .help("print timings after each phase"))
        .arg(Arg::with_name("input")
            .required(true)
            .multiple(true))
        .get_matches();

    // initiate diagnostics config
    let config = if arguments.is_present("diagnostics") {
        Some(diag::Config::default())
    } else {
        None
    };

    // list of input files
    let inputs: Vec<_> = arguments.values_of("input").unwrap().map(Path::new).collect();

    // run frontend
    let start = PreciseTime::now();
    let functions = front::process_with_diag(&inputs, &config).expect("Frontend");
    let end = PreciseTime::now();
    if arguments.is_present("timings") {
        println!("Frontend time: {}", start.to(end));
    }
}
<commit_msg>Driver: Exit on FrontendError<commit_after>extern crate cleaver;
use cleaver::front;
use cleaver::diagnostics as diag;

extern crate clap;
use clap::{App, Arg};

extern crate time;
use time::PreciseTime;

use std::path::Path;
use std::process::exit;

fn main() {
    // commandline arguments
    let arguments = App::new("Cleaver")
        .about("Cleaver is a toy / research compiler, it takes .gib files as input.")
        .version("0.1")
        .author("Alex Hirsch <W4RH4WK@bluephoenix.at>")
        .arg(Arg::with_name("diagnostics")
            .short("d")
            .help("create various diagnostic outputs during compilation"))
        .arg(Arg::with_name("timings")
            .short("t")
            .help("print timings after each phase"))
        .arg(Arg::with_name("input")
            .required(true)
            .multiple(true))
        .get_matches();

    // initiate diagnostics config
    let config = if arguments.is_present("diagnostics") {
        Some(diag::Config::default())
    } else {
        None
    };

    // list of input files
    let inputs: Vec<_> = arguments.values_of("input").unwrap().map(Path::new).collect();

    // run frontend
    let start = PreciseTime::now();
    let functions = front::process_with_diag(&inputs, &config);
    let end = PreciseTime::now();
    if arguments.is_present("timings") {
        println!("Frontend time: {}", start.to(end));
    }

    let functions = functions.unwrap_or_else(|err| {
        println!("{}", err);
        exit(-1);
    });
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::on_chain_config::OnChainConfig;
use anyhow::{format_err, Result};
use diem_crypto::HashValue;
use serde::{Deserialize, Serialize};

/// Defines and holds the publishing policies for the VM. There are three possible configurations:
/// 1. No module publishing, only allowlisted scripts are allowed.
/// 2. No module publishing, custom scripts are allowed.
/// 3. Both module publishing and custom scripts are allowed.
/// We represent these as an enum instead of a struct since allowlisting and module/script
/// publishing are mutually exclusive options.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct VMPublishingOption {
    pub script_allow_list: Vec<HashValue>,
    pub is_open_module: bool,
}

impl VMPublishingOption {
    pub fn locked(allowlist: Vec<HashValue>) -> Self {
        Self {
            script_allow_list: allowlist,
            is_open_module: false,
        }
    }

    pub fn custom_scripts() -> Self {
        Self {
            script_allow_list: vec![],
            is_open_module: false,
        }
    }

    pub fn open() -> Self {
        Self {
            script_allow_list: vec![],
            is_open_module: true,
        }
    }

    pub fn is_open_module(&self) -> bool {
        self.is_open_module
    }

    pub fn is_open_script(&self) -> bool {
        self.script_allow_list.is_empty()
    }
}

impl OnChainConfig for VMPublishingOption {
    const IDENTIFIER: &'static str = "DiemTransactionPublishingOption";

    fn deserialize_into_config(bytes: &[u8]) -> Result<Self> {
        bcs::from_bytes(bytes).map_err(|e| {
            format_err!(
                "Failed first round of deserialization for VMPublishingOptionInner: {}",
                e
            )
        })
    }
}
<commit_msg>[on-chain config] cleanup the customized deserialization<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::on_chain_config::OnChainConfig;
use diem_crypto::HashValue;
use serde::{Deserialize, Serialize};

/// Defines and holds the publishing policies for the VM. There are three possible configurations:
/// 1. No module publishing, only allowlisted scripts are allowed.
/// 2. No module publishing, custom scripts are allowed.
/// 3. Both module publishing and custom scripts are allowed.
/// We represent these as an enum instead of a struct since allowlisting and module/script
/// publishing are mutually exclusive options.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct VMPublishingOption {
    pub script_allow_list: Vec<HashValue>,
    pub is_open_module: bool,
}

impl VMPublishingOption {
    pub fn locked(allowlist: Vec<HashValue>) -> Self {
        Self {
            script_allow_list: allowlist,
            is_open_module: false,
        }
    }

    pub fn custom_scripts() -> Self {
        Self {
            script_allow_list: vec![],
            is_open_module: false,
        }
    }

    pub fn open() -> Self {
        Self {
            script_allow_list: vec![],
            is_open_module: true,
        }
    }

    pub fn is_open_module(&self) -> bool {
        self.is_open_module
    }

    pub fn is_open_script(&self) -> bool {
        self.script_allow_list.is_empty()
    }
}

impl OnChainConfig for VMPublishingOption {
    const IDENTIFIER: &'static str = "DiemTransactionPublishingOption";
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]

use std::thread::Thread;

use super::piece::King;
use super::moves::Move;
use super::pos::Position;
use super::gen;
use super::make_move::make_move_mut;

pub fn receive_legal(p: Position) -> Receiver<Move> {
    let (tx,rx) = sync_channel(0);
    Thread::spawn(move || gen_legal(&p, tx)).detach();
    rx
}

pub fn gen_legal(p: &Position, out: SyncSender<Move>) {
    let (tx, rx) = sync_channel::<Move>(1);
    let temp = (*p).clone();
    Thread::spawn(move || gen::gen_psudo_legal(&temp, tx)).detach();
    filter_legal(p, out, rx);
}

fn filter_legal(p: &Position, out: SyncSender<Move>, rx: Receiver<Move>) {
    for curr_move in rx.iter() {
        if is_legal(p.clone(), &curr_move) {
            if out.send_opt(curr_move).is_err() {
                return;
            }
        }
    }
}

pub fn is_legal(mut p: Position, curr_move: &Move) -> bool {
    make_move_mut(&mut p, curr_move);
    for m in gen::receive_psudo_legal(p.clone()).iter() {
        let dest = p.at(m.to());
        if dest.is_some() && dest.unwrap().piece_type() == King {
            return false;
        }
    }
    true
}
<commit_msg>Add "can_take_king()"<commit_after>#![allow(unused_variables)]

use std::thread::Thread;

use super::piece::King;
use super::moves::Move;
use super::pos::Position;
use super::gen;
use super::make_move::make_move_mut;

pub fn receive_legal(p: Position) -> Receiver<Move> {
    let (tx,rx) = sync_channel(0);
    Thread::spawn(move || gen_legal(&p, tx)).detach();
    rx
}

pub fn gen_legal(p: &Position, out: SyncSender<Move>) {
    let (tx, rx) = sync_channel::<Move>(1);
    let temp = (*p).clone();
    Thread::spawn(move || gen::gen_psudo_legal(&temp, tx)).detach();
    filter_legal(p, out, rx);
}

fn filter_legal(p: &Position, out: SyncSender<Move>, rx: Receiver<Move>) {
    for curr_move in rx.iter() {
        if is_legal(p.clone(), &curr_move) {
            if out.send_opt(curr_move).is_err() {
                return;
            }
        }
    }
}

pub fn is_legal(mut p: Position, curr_move: &Move) -> bool {
    make_move_mut(&mut p, curr_move);
    !can_take_king(&p)
}

pub fn can_take_king(p: &Position) -> bool {
    for m in gen::receive_psudo_legal(p.clone()).iter() {
        let dest = p.at(m.to());
        if dest.is_some() && dest.unwrap().piece_type() == King {
            return true;
        }
    }
    false
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::fmt;

use log::trace;

use rustc_span::DUMMY_SP;

use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(Option<String>),
    UnsupportedInIsolation(String),
    ExperimentalUb { msg: String, url: String },
    Deadlock,
}

impl fmt::Debug for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) =>
                write!(f, "the evaluated program completed with exit code {}", code),
            Abort(None) =>
                write!(f, "the evaluated program aborted execution"),
            Abort(Some(msg)) =>
                write!(f, "the evaluated program aborted execution: {}", msg),
            UnsupportedInIsolation(msg) =>
                write!(f, "{}", msg),
            ExperimentalUb { msg, .. } =>
                write!(f, "{}", msg),
            Deadlock =>
                write!(f, "the evaluated program deadlocked"),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    PoppedTrackedPointerTag(Item),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    mut e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) =>
                    "abnormal termination",
                UnsupportedInIsolation(_) =>
                    "unsupported operation",
                ExperimentalUb { .. } =>
                    "Undefined Behavior",
                Deadlock => "deadlock",
            };
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")],
                ExperimentalUb { url, .. } =>
                    vec![
                        format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"),
                        format!("see {} for further information", url),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            let title = match e.kind {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                _ =>
                    bug!("This error should be impossible in Miri: {}", e),
            };
            let helps = match e.kind {
                Unsupported(UnsupportedOpInfo::NoMirFor(..)) =>
                    vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")],
                Unsupported(UnsupportedOpInfo::ReadBytesAsPointer) =>
                    panic!("`ReadBytesAsPointer` cannot be raised by Miri"),
                Unsupported(_) =>
                    vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) =>
                    vec![
                        format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
                        format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"),
                        format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs")
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
                        format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
    };

    e.print_backtrace();
    if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind {
        ecx.memory.dump_alloc(ptr.alloc_id);
    }
    let msg = e.to_string();
    report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true)
}

/// Report an error or note (depending on the `error` argument) at the current frame's current statement.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    title: &str,
    span_msg: String,
    mut helps: Vec<String>,
    error: bool,
) -> Option<i64> {
    let span = if let Some(frame) = ecx.machine.stack.last() {
        frame.current_source_info().unwrap().span
    } else {
        DUMMY_SP
    };
    let mut err = if error {
        ecx.tcx.sess.struct_span_err(span, title)
    } else {
        ecx.tcx.sess.diagnostic().span_note_diag(span, title)
    };
    err.span_label(span, span_msg);
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().push_str("\n");
        for help in helps {
            err.help(&help);
        }
    }
    // Add backtrace
    let frames = ecx.generate_stacktrace();
    for (idx, frame_info) in frames.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();

    for (i, frame) in ecx.machine.stack.iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }
    // Let the reported error determine the return code.
    return None;
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            for e in diagnostics.borrow_mut().drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    PoppedTrackedPointerTag(item) =>
                        format!("popped tracked tag for item {:?}", item),
                    CreatedAlloc(AllocId(id)) =>
                        format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) =>
                        format!("freed allocation with id {}", id),
                };
                report_msg(this, "tracking was triggered", msg, vec![], false);
            }
        });
    }
}
<commit_msg>Reorder output<commit_after>use std::cell::RefCell;
use std::fmt;

use log::trace;

use rustc_span::DUMMY_SP;

use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(Option<String>),
    UnsupportedInIsolation(String),
    ExperimentalUb { msg: String, url: String },
    Deadlock,
}

impl fmt::Debug for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) =>
                write!(f, "the evaluated program completed with exit code {}", code),
            Abort(None) =>
                write!(f, "the evaluated program aborted execution"),
            Abort(Some(msg)) =>
                write!(f, "the evaluated program aborted execution: {}", msg),
            UnsupportedInIsolation(msg) =>
                write!(f, "{}", msg),
            ExperimentalUb { msg, .. } =>
                write!(f, "{}", msg),
            Deadlock =>
                write!(f, "the evaluated program deadlocked"),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    PoppedTrackedPointerTag(Item),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    mut e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) =>
                    "abnormal termination",
                UnsupportedInIsolation(_) =>
                    "unsupported operation",
                ExperimentalUb { .. } =>
                    "Undefined Behavior",
                Deadlock => "deadlock",
            };
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")],
                ExperimentalUb { url, .. } =>
                    vec![
                        format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"),
                        format!("see {} for further information", url),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            let title = match e.kind {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                _ =>
                    bug!("This error should be impossible in Miri: {}", e),
            };
            let helps = match e.kind {
                Unsupported(UnsupportedOpInfo::NoMirFor(..)) =>
                    vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")],
                Unsupported(UnsupportedOpInfo::ReadBytesAsPointer) =>
                    panic!("`ReadBytesAsPointer` cannot be raised by Miri"),
                Unsupported(_) =>
                    vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) =>
                    vec![
                        format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
                        format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"),
                        format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs")
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
                        format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
                    ],
                _ => vec![],
            };
            (title, helps)
        }
    };

    e.print_backtrace();
    let msg = e.to_string();
    let result = report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true);

    if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind {
        ecx.memory.dump_alloc(ptr.alloc_id);
    }

    result
}

/// Report an error or note (depending on the `error` argument) at the current frame's current statement.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    title: &str,
    span_msg: String,
    mut helps: Vec<String>,
    error: bool,
) -> Option<i64> {
    let span = if let Some(frame) = ecx.machine.stack.last() {
        frame.current_source_info().unwrap().span
    } else {
        DUMMY_SP
    };
    let mut err = if error {
        ecx.tcx.sess.struct_span_err(span, title)
    } else {
        ecx.tcx.sess.diagnostic().span_note_diag(span, title)
    };
    err.span_label(span, span_msg);
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().push_str("\n");
        for help in helps {
            err.help(&help);
        }
    }
    // Add backtrace
    let frames = ecx.generate_stacktrace();
    for (idx, frame_info) in frames.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();

    for (i, frame) in ecx.machine.stack.iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }
    // Let the reported error determine the return code.
    return None;
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            for e in diagnostics.borrow_mut().drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    PoppedTrackedPointerTag(item) =>
                        format!("popped tracked tag for item {:?}", item),
                    CreatedAlloc(AllocId(id)) =>
                        format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) =>
                        format!("freed allocation with id {}", id),
                };
                report_msg(this, "tracking was triggered", msg, vec![], false);
            }
        });
    }
}
<|endoftext|>


<commit_before>use std::boxed::Box;
use std::fmt;
use std::fmt::Debug;

struct Heap<T> {
    inner_vec: Vec<T>,
    cap: usize,
    insert_p: usize,

    /// cmp func used in shift_up of insert
    /// and shift_down of delete
    cmp_func: Box<dyn Fn(&T, &T) -> bool>,
}

impl<T> Debug for Heap<T>
where
    T: Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Heap")
            .field("inner_vec", &self.inner_vec)
            .field("cap", &self.cap)
            .field("insert_p", &self.insert_p)
            .finish()
    }
}

impl<T> Heap<T>
where
    T: Clone + Default,
{
    fn new(f: Box<dyn Fn(&T, &T) -> bool>) -> Self {
        Self {
            inner_vec: vec![Default::default(); 2], // first one take index 0
            cap: 2,
            insert_p: 1, // next insert index
            cmp_func: f,
        }
    }

    fn insert(&mut self, ele: &T) {
        if self.insert_p == self.cap {
            self.double_cap();
        }
        self.inner_vec[self.insert_p] = ele.clone();

        self.shift_up(self.insert_p);

        self.insert_p += 1;
    }

    fn delete(&mut self) -> Option<T> {
        if self.insert_p == 1 {
            return None;
        }

        let result = Some(self.inner_vec[1].clone());
        self.insert_p -= 1;
        self.inner_vec[1] = self.inner_vec[self.insert_p].clone();
        self.inner_vec[self.insert_p] = Default::default();

        self.shift_down(1);

        result
    }

    /*
    util functions below
     */

    fn double_cap(&mut self) {
        self.inner_vec
            .append(&mut vec![Default::default(); self.cap - 1]);
        self.cap *= 2;
        self.cap -= 1;
    }

    fn shift_up(&mut self, ind: usize) {
        let root = (ind as i32 / 2) as usize;
        if root != 0 && !self.cmp_root_child(root, ind) {
            self.swop(root, ind);
            self.shift_up(root)
        }
    }

    fn shift_down(&mut self, ind: usize) {
        let (left, right) = (ind * 2, ind * 2 + 1);

        // last branch
        if right >= self.insert_p {
            self.swop(ind, left);
            return;
        }

        let next_ind = if self.cmp_root_child(left, right) {
            self.swop(ind, left);
            left
        } else {
            self.swop(ind, right);
            right
        };

        self.shift_down(next_ind);
    }

    fn swop(&mut self, a: usize, b: usize) {
        let aa = self.inner_vec[a].clone();
        self.inner_vec[a] = self.inner_vec[b].clone();
        self.inner_vec[b] = aa
    }

    /// id1 and id2 have to exsit
    fn cmp_root_child(&self, id1: usize, id2: usize) -> bool {
        self.cmp_func.as_ref()(&self.inner_vec[id1], &self.inner_vec[id2])
    }
}

fn main() {
    let mut heap = Heap::new(Box::new(|a: &i32, b: &i32| a <= b));
    for i in vec![10, 99, 14, 25, 33, 81, 82] {
        heap.insert(&i);
    }

    dbg!(&heap);
    dbg!(heap.delete());
    dbg!(&heap);

    heap.insert(&79);
    dbg!(&heap);
}
<commit_msg>a bit<commit_after>use std::fmt;
use std::fmt::Debug;

#[derive(Clone)]
struct Heap<'a, T> {
    inner_vec: Vec<T>,
    cap: usize,
    insert_p: usize, // next position of insert element

    /// cmp func used in shift_up of insert
    /// and shift_down of delete
    //cmp_func: Box<dyn Fn(&T, &T) -> bool>,
    cmp_func: &'a dyn Fn(&T, &T) -> bool,
}

impl<'a, T> Debug for Heap<'a, T>
where
    T: Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Heap")
            .field("inner_vec", &self.inner_vec)
            .field("cap", &self.cap)
            .field("insert_p", &self.insert_p)
            .finish()
    }
}

impl<'a, T> Heap<'a, T>
where
    T: Clone + Default + Debug,
{
    // fn new(f: Box<dyn Fn(&T, &T) -> bool>) -> Self {
    //     Self {
    //         inner_vec: vec![Default::default(); 2], // first one take index 0
    //         cap: 2,
    //         insert_p: 1, // next insert index
    //         cmp_func: f,
    //     }
    // }

    fn new(f: &'a dyn Fn(&T, &T) -> bool) -> Self {
        Self {
            inner_vec: vec![Default::default(); 2], // first one take index 0
            cap: 2,
            insert_p: 1, // next insert index
            cmp_func: f,
        }
    }

    // insert new element
    fn insert(&mut self, ele: &T) {
        // if inner_vec is full, double it
        if self.insert_p == self.cap {
            self.double_cap();
        }
        self.inner_vec[self.insert_p] = ele.clone();

        // adjust heap
        self.shift_up(self.insert_p);

        // give new index
        self.insert_p += 1;
    }

    // delete top element of heap
    fn delete(&mut self) -> Option<T> {
        if self.insert_p == 1 {
            return None;
        }

        let result = Some(self.inner_vec[1].clone());
        self.insert_p -= 1;
        // move last element to the first
        self.inner_vec[1] = self.inner_vec[self.insert_p].clone();
        self.inner_vec[self.insert_p] = Default::default();
        self.shift_down(1); // shift down from top

        result
    }

    fn len(&self) -> usize {
        self.insert_p - 1
    }

    /*
    util functions below
     */

    fn double_cap(&mut self) {
        self.inner_vec
            .append(&mut vec![Default::default(); self.cap - 1]);
        self.cap *= 2;
        self.cap -= 1;
    }

    fn shift_up(&mut self, ind: usize) {
        let root = (ind as i32 / 2) as usize;
        if root != 0 && !self.cmp_root_child(root, ind) {
            self.swop(root, ind);
            self.shift_up(root)
        }
    }

    fn shift_down(&mut self, ind: usize) {
        let (left, right) = (ind * 2, ind * 2 + 1);

        // last branch
        if right >= self.insert_p && left < self.insert_p {
            if !self.cmp_root_child(ind, left) {
                self.swop(ind, left);
            }
            return;
        }

        if left >= self.insert_p {
            return;
        }

        let next_ind = if self.cmp_root_child(left, right) {
            self.swop(ind, left);
            left
        } else {
            self.swop(ind, right);
            right
        };

        self.shift_down(next_ind);
    }

    // switch two index elements
    fn swop(&mut self, a: usize, b: usize) {
        let aa = self.inner_vec[a].clone();
        self.inner_vec[a] = self.inner_vec[b].clone();
        self.inner_vec[b] = aa
    }

    /// id1 and id2 have to exsit
    fn cmp_root_child(&self, id1: usize, id2: usize) -> bool {
        //self.cmp_func.as_ref()(&self.inner_vec[id1], &self.inner_vec[id2])
        (self.cmp_func)(&self.inner_vec[id1], &self.inner_vec[id2])
    }
}

fn main() {
    let mut heap = Heap::new(&|a: &i32, b: &i32| a <= b);
    for i in vec![10, 99, 14, 25, 33, 81, 82] {
        heap.insert(&i);
    }

    dbg!(&heap);

    heap.delete().unwrap();

    dbg!(&heap);

    heap.insert(&79);

    dbg!(&heap);
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//

use memory::PAddr;

use core::mem;
use core::fmt;

// Distinguished section indices.
pub const SHN_UNDEF: u16        = 0;
pub const SHN_LORESERVE: u16    = 0xff00;
pub const SHN_LOPROC: u16       = 0xff00;
pub const SHN_HIPROC: u16       = 0xff1f;
pub const SHN_LOOS: u16         = 0xff20;
pub const SHN_HIOS: u16         = 0xff3f;
pub const SHN_ABS: u16          = 0xfff1;
pub const SHN_COMMON: u16       = 0xfff2;
pub const SHN_XINDEX: u16       = 0xffff;
pub const SHN_HIRESERVE: u16    = 0xffff;

pub const SHT_LOOS: u32   = 0x60000000;
pub const SHT_HIOS: u32   = 0x6fffffff;
pub const SHT_LOPROC: u32 = 0x70000000;
pub const SHT_HIPROC: u32 = 0x7fffffff;
pub const SHT_LOUSER: u32 = 0x80000000;
pub const SHT_HIUSER: u32 = 0xffffffff;

/// Represents an ELF section header
///
/// Refer to the [ELF standard](http://www.sco.com/developers/gabi/latest/ch4.sheader.html)
/// for more information.
#[derive(Clone, Copy, Debug)]
pub enum Header<'a> {
    Header32(&'a HeaderRepr<u32>)
  , Header64(&'a HeaderRepr<u64>)
}

#[derive(Debug)]
#[repr(C)]
pub struct HeaderRepr<Word> {
    /// This member specifies the name of the section.
    ///
    /// Its value is an index into the section header string table section,
    /// giving the location of a null-terminated string.
    name_offset: u32
  , /// This member categorizes the section's contents and semantics.
    ty: TypeRepr
  , flags: Flags
  , address: Word
  , offset: Word
  , length: Word
  , link: u32
  , info: u32
  , address_align: u32
  , entry_length: Word
}

trait AsHeader {
    fn as_header<'a>(&'a self) -> Header<'a>;
}

impl AsHeader for HeaderRepr<u32> {
    #[inline] fn as_header<'a>(&'a self) -> Header<'a> {
        Header::Header32(self)
    }
}

impl AsHeader for HeaderRepr<u64> {
    #[inline] fn as_header<'a>(&'a self) -> Header<'a> {
        Header::Header64(self)
    }
}

bitflags! {
    flags Flags: usize {
        // Flags (SectionHeader::flags)
        const SHF_WRITE            =        0x1
      , const SHF_ALLOC            =        0x2
      , const SHF_EXECINSTR        =        0x4
      , const SHF_MERGE            =       0x10
      , const SHF_STRINGS          =       0x20
      , const SHF_INFO_LINK        =       0x40
      , const SHF_LINK_ORDER       =       0x80
      , const SHF_OS_NONCONFORMING =      0x100
      , const SHF_GROUP            =      0x200
      , const SHF_TLS              =      0x400
      , const SHF_COMPRESSED       =      0x800
      , const SHF_MASKOS           = 0x0ff00000
      , const SHF_MASKPROC         = 0xf0000000
    }
}

impl fmt::LowerHex for Flags {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.bits.fmt(f)
    }
}

bitflags! {
    flags GroupFlags: u32 {
        const GRP_COMDAT	=        0x1
      , const GRP_MASKOS	= 0x0ff00000
      , const GRP_MASKPROC	= 0xf0000000
    }
}

macro_rules! get {
    ($s: expr, $name: ident) => {
        match *$s {
            Header::Header32(x) => x.$name
          , Header::Header64(x) => x.$name
        }
    }
}

macro_rules! impl_getters {
    ( $($name: ident: $ty: ident),+ ) => {
        $(#[inline] pub fn $name(&self) -> $ty {
            match *self {
                Header::Header32(x) => x.$name as $ty
              , Header::Header64(x) => x.$name as $ty
            }
        })+
    }
}

impl<'a> Header<'a> {
    impl_getters! { address: u64
                  , offset: u64
                  , length: u64
                  , link: u32
                  , info: u32
                  , address_align: u32
                  , entry_length: u64
                  }

    /// Access the type of this section
    #[inline] pub fn flags(&self) -> u64 { get!(self, flags).bits as u64}

    /// Access the type of this section
    #[inline] pub fn get_type(&self) -> Type { get!(self, ty).as_type() }

    /// Returns true if this section is writable.
    #[inline] pub fn is_writable(&self) -> bool {
        get!(self, flags).contains(SHF_WRITE)
    }

    /// Returns true if this section occupies memory during program execution.
    #[inline] pub fn is_allocated(&self) -> bool {
        get!(self, flags).contains(SHF_ALLOC)
    }

    /// Returns true if this section contains executable instructions.
    #[inline] pub fn is_executable(&self) -> bool {
        get!(self, flags).contains(SHF_EXECINSTR)
    }

    /// Returns true if this section can be merged.
    #[inline] pub fn is_mergeable(&self) -> bool {
        get!(self, flags).contains(SHF_MERGE)
    }

    /// Returns true if this section contains data that is of a uniform size.
    #[inline] pub fn is_uniform(&self) -> bool {
        get!(self, flags).contains(SHF_MERGE) &&
        !get!(self, flags).contains(SHF_STRINGS)
    }
}

pub enum Contents<'a> {
    Empty
  , Undefined(&'a [u8])
  , Group { flags: &'a u32, indicies: &'a[u32] }
}

#[derive(Debug, Copy, Clone)]
struct TypeRepr(u32);

impl TypeRepr {
    #[inline] fn as_type(&self) -> Type {
        match self.0 {
            0 => Type::Null
          , 1 => Type::ProgramBits
          , 2 => Type::SymbolTable
          , 3 => Type::StringTable
          , 4 => Type::Rela
          , 5 => Type::HashTable
          , 6 => Type::Dynamic
          , 7 => Type::Notes
          , 8 => Type::NoBits
          , 9 => Type::Rel
          , 10 => Type::Shlib
          , 11 => Type::DynSymTable
          , 14 => Type::InitArray
          , 15 => Type::FiniArray
          , 16 => Type::PreInitArray
          , x @ SHT_LOOS ... SHT_HIOS => Type::OSSpecific(x)
          , x @ SHT_LOPROC ... SHT_HIPROC => Type::ProcessorSpecific(x)
          , x @ SHT_LOUSER ... SHT_HIUSER => Type::User(x)
          , _ => panic!("Invalid section type!")
        }
    }
}

/// Enum representing an ELF file section type.
///
/// Refer to Figure 1-10: "Section Types, sh_type" in Section 1 of the
/// [ELF standard](http://www.sco.com/developers/gabi/latest/ch4.sheader.html)
/// for more information.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Type {
    /// Section type 0: `SHT_NULL`
    ///
    /// This value marks the section header as inactive; it does not have an
    /// associated section. Other members of the section header have
    /// undefined values.
    Null
  , /// Section type 1: `SHT_PROGBITS`
    ///
    /// The section holds information defined by the program, whose format and
    /// meaning are determined solely by the program.
    ProgramBits
  , /// Section type 2: `SHT_SYMTAB`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    SymbolTable
  , /// Section type 3: `SHT_STRTAB`
    ///
    /// The section holds a string table. An object file may have multiple
    /// string table sections.
    StringTable
  , /// Section type 4: `SHT_RELA`
    ///
    /// The section holds relocation entries with explicit addends, such as
    /// type `Elf32_Rela` for the 32-bit class of object files. An object file
    /// may have multiple relocation sections.
    Rela
  , /// Section type 5: `SHT_HASH`
    ///
    /// The section holds a symbol hash table. All objects participating in
    /// dynamic linking must contain a symbol hash table. Currently, an object
    /// file may have only one hash table, but this restriction may be relaxed
    /// in the future.
    HashTable
  , /// Section type 6: `SHT_DYNAMIC`
    ///
    /// The section holds information for dynamic linking. Currently, an object
    /// file may have only one dynamic section, but this restriction may be
    ///  relaxed in the future.
    Dynamic
  , /// Section type 7: `SHT_NOTE`
    ///
    /// The section holds information that marks the file in some way.
    Notes
  , /// Section type 8: `SHT_NOBITS`
    ///
    /// A section of this type occupies no space in the file but otherwise
    /// resembles `SHT_PROGBITS`. Although this section contains no bytes, the
    /// `sh_offset` member contains the conceptual file offset.
    NoBits
  , /// Section type 9: `SHT_REL`
    ///
    /// The section holds relocation entries without explicit addends, such as
    /// type `Elf32_Rel` for the 32-bit class of object files. An object file
    /// may have multiple reloca- tion sections.
    Rel
  , /// Section type 10: `SHT_SHLIB`
    ///
    /// This section type is reserved but has unspecified semantics. Programs
    /// that contain a section of this type do not conform to the ABI.
    Shlib
  , /// Section type 11: `SHT_DYNSYM`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    DynSymTable
  , InitArray
  , FiniArray
  , PreInitArray
  , Group
  , SymbolTableShIndex
  , OSSpecific(u32)
  , ProcessorSpecific(u32)
  , User(u32)
}

/// Iterator over ELF64 sections
#[derive(Clone,Debug)]
pub struct Sections<'a, W: 'a> { curr: &'a HeaderRepr<W>
                               , remaining: u32
                               , size: u32
                               }

impl<'a, W: 'a> Sections<'a, W> {
    pub fn new(curr: &'a HeaderRepr<W>, remaining: u32, size: u32)
               -> Sections<'a, W>
    {
        Sections { curr: curr, remaining: remaining, size: size }

    }
}

impl<'a, W> Iterator for Sections<'a, W>
where HeaderRepr<W>: AsHeader {
    type Item = Header<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.remaining == 0 {
            None
        } else {
            let current = self.curr.as_header();
            self.curr = unsafe {
                &*(((self.curr as *const HeaderRepr<W>) as u32 + self.size)
                    as *const HeaderRepr<W>)
            };
            self.remaining -= 1;
            if current.get_type() == Type::Null {
                self.next()
            } else {
                Some(current)
            }
        }
    }
}

//
// #[derive(Debug)]
// #[repr(u32)]
// pub enum Flags { Writable    = 0x1
//                , Allocated   = 0x2
//                , Executable  = 0x4
//                }
<commit_msg>[elf] Unused unused imports<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//

use core::fmt;

// Distinguished section indices.
pub const SHN_UNDEF: u16        = 0;
pub const SHN_LORESERVE: u16    = 0xff00;
pub const SHN_LOPROC: u16       = 0xff00;
pub const SHN_HIPROC: u16       = 0xff1f;
pub const SHN_LOOS: u16         = 0xff20;
pub const SHN_HIOS: u16         = 0xff3f;
pub const SHN_ABS: u16          = 0xfff1;
pub const SHN_COMMON: u16       = 0xfff2;
pub const SHN_XINDEX: u16       = 0xffff;
pub const SHN_HIRESERVE: u16    = 0xffff;

pub const SHT_LOOS: u32   = 0x60000000;
pub const SHT_HIOS: u32   = 0x6fffffff;
pub const SHT_LOPROC: u32 = 0x70000000;
pub const SHT_HIPROC: u32 = 0x7fffffff;
pub const SHT_LOUSER: u32 = 0x80000000;
pub const SHT_HIUSER: u32 = 0xffffffff;

/// Represents an ELF section header
///
/// Refer to the [ELF standard](http://www.sco.com/developers/gabi/latest/ch4.sheader.html)
/// for more information.
#[derive(Clone, Copy, Debug)]
pub enum Header<'a> {
    Header32(&'a HeaderRepr<u32>)
  , Header64(&'a HeaderRepr<u64>)
}

#[derive(Debug)]
#[repr(C)]
pub struct HeaderRepr<Word> {
    /// This member specifies the name of the section.
    ///
    /// Its value is an index into the section header string table section,
    /// giving the location of a null-terminated string.
    name_offset: u32
  , /// This member categorizes the section's contents and semantics.
    ty: TypeRepr
  , flags: Flags
  , address: Word
  , offset: Word
  , length: Word
  , link: u32
  , info: u32
  , address_align: u32
  , entry_length: Word
}

trait AsHeader {
    fn as_header<'a>(&'a self) -> Header<'a>;
}

impl AsHeader for HeaderRepr<u32> {
    #[inline] fn as_header<'a>(&'a self) -> Header<'a> {
        Header::Header32(self)
    }
}

impl AsHeader for HeaderRepr<u64> {
    #[inline] fn as_header<'a>(&'a self) -> Header<'a> {
        Header::Header64(self)
    }
}

bitflags! {
    flags Flags: usize {
        // Flags (SectionHeader::flags)
        const SHF_WRITE            =        0x1
      , const SHF_ALLOC            =        0x2
      , const SHF_EXECINSTR        =        0x4
      , const SHF_MERGE            =       0x10
      , const SHF_STRINGS          =       0x20
      , const SHF_INFO_LINK        =       0x40
      , const SHF_LINK_ORDER       =       0x80
      , const SHF_OS_NONCONFORMING =      0x100
      , const SHF_GROUP            =      0x200
      , const SHF_TLS              =      0x400
      , const SHF_COMPRESSED       =      0x800
      , const SHF_MASKOS           = 0x0ff00000
      , const SHF_MASKPROC         = 0xf0000000
    }
}

impl fmt::LowerHex for Flags {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.bits.fmt(f)
    }
}

bitflags! {
    flags GroupFlags: u32 {
        const GRP_COMDAT	=        0x1
      , const GRP_MASKOS	= 0x0ff00000
      , const GRP_MASKPROC	= 0xf0000000
    }
}

macro_rules! get {
    ($s: expr, $name: ident) => {
        match *$s {
            Header::Header32(x) => x.$name
          , Header::Header64(x) => x.$name
        }
    }
}

macro_rules! impl_getters {
    ( $($name: ident: $ty: ident),+ ) => {
        $(#[inline] pub fn $name(&self) -> $ty {
            match *self {
                Header::Header32(x) => x.$name as $ty
              , Header::Header64(x) => x.$name as $ty
            }
        })+
    }
}

impl<'a> Header<'a> {
    impl_getters! { address: u64
                  , offset: u64
                  , length: u64
                  , link: u32
                  , info: u32
                  , address_align: u32
                  , entry_length: u64
                  }

    /// Access the type of this section
    #[inline] pub fn flags(&self) -> u64 { get!(self, flags).bits as u64}

    /// Access the type of this section
    #[inline] pub fn get_type(&self) -> Type { get!(self, ty).as_type() }

    /// Returns true if this section is writable.
    #[inline] pub fn is_writable(&self) -> bool {
        get!(self, flags).contains(SHF_WRITE)
    }

    /// Returns true if this section occupies memory during program execution.
    #[inline] pub fn is_allocated(&self) -> bool {
        get!(self, flags).contains(SHF_ALLOC)
    }

    /// Returns true if this section contains executable instructions.
    #[inline] pub fn is_executable(&self) -> bool {
        get!(self, flags).contains(SHF_EXECINSTR)
    }

    /// Returns true if this section can be merged.
    #[inline] pub fn is_mergeable(&self) -> bool {
        get!(self, flags).contains(SHF_MERGE)
    }

    /// Returns true if this section contains data that is of a uniform size.
    #[inline] pub fn is_uniform(&self) -> bool {
        get!(self, flags).contains(SHF_MERGE) &&
        !get!(self, flags).contains(SHF_STRINGS)
    }
}

pub enum Contents<'a> {
    Empty
  , Undefined(&'a [u8])
  , Group { flags: &'a u32, indicies: &'a[u32] }
}

#[derive(Debug, Copy, Clone)]
struct TypeRepr(u32);

impl TypeRepr {
    #[inline] fn as_type(&self) -> Type {
        match self.0 {
            0 => Type::Null
          , 1 => Type::ProgramBits
          , 2 => Type::SymbolTable
          , 3 => Type::StringTable
          , 4 => Type::Rela
          , 5 => Type::HashTable
          , 6 => Type::Dynamic
          , 7 => Type::Notes
          , 8 => Type::NoBits
          , 9 => Type::Rel
          , 10 => Type::Shlib
          , 11 => Type::DynSymTable
          , 14 => Type::InitArray
          , 15 => Type::FiniArray
          , 16 => Type::PreInitArray
          , x @ SHT_LOOS ... SHT_HIOS => Type::OSSpecific(x)
          , x @ SHT_LOPROC ... SHT_HIPROC => Type::ProcessorSpecific(x)
          , x @ SHT_LOUSER ... SHT_HIUSER => Type::User(x)
          , _ => panic!("Invalid section type!")
        }
    }
}

/// Enum representing an ELF file section type.
///
/// Refer to Figure 1-10: "Section Types, sh_type" in Section 1 of the
/// [ELF standard](http://www.sco.com/developers/gabi/latest/ch4.sheader.html)
/// for more information.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Type {
    /// Section type 0: `SHT_NULL`
    ///
    /// This value marks the section header as inactive; it does not have an
    /// associated section. Other members of the section header have
    /// undefined values.
    Null
  , /// Section type 1: `SHT_PROGBITS`
    ///
    /// The section holds information defined by the program, whose format and
    /// meaning are determined solely by the program.
    ProgramBits
  , /// Section type 2: `SHT_SYMTAB`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    SymbolTable
  , /// Section type 3: `SHT_STRTAB`
    ///
    /// The section holds a string table. An object file may have multiple
    /// string table sections.
    StringTable
  , /// Section type 4: `SHT_RELA`
    ///
    /// The section holds relocation entries with explicit addends, such as
    /// type `Elf32_Rela` for the 32-bit class of object files. An object file
    /// may have multiple relocation sections.
    Rela
  , /// Section type 5: `SHT_HASH`
    ///
    /// The section holds a symbol hash table. All objects participating in
    /// dynamic linking must contain a symbol hash table. Currently, an object
    /// file may have only one hash table, but this restriction may be relaxed
    /// in the future.
    HashTable
  , /// Section type 6: `SHT_DYNAMIC`
    ///
    /// The section holds information for dynamic linking. Currently, an object
    /// file may have only one dynamic section, but this restriction may be
    ///  relaxed in the future.
    Dynamic
  , /// Section type 7: `SHT_NOTE`
    ///
    /// The section holds information that marks the file in some way.
    Notes
  , /// Section type 8: `SHT_NOBITS`
    ///
    /// A section of this type occupies no space in the file but otherwise
    /// resembles `SHT_PROGBITS`. Although this section contains no bytes, the
    /// `sh_offset` member contains the conceptual file offset.
    NoBits
  , /// Section type 9: `SHT_REL`
    ///
    /// The section holds relocation entries without explicit addends, such as
    /// type `Elf32_Rel` for the 32-bit class of object files. An object file
    /// may have multiple reloca- tion sections.
    Rel
  , /// Section type 10: `SHT_SHLIB`
    ///
    /// This section type is reserved but has unspecified semantics. Programs
    /// that contain a section of this type do not conform to the ABI.
    Shlib
  , /// Section type 11: `SHT_DYNSYM`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    DynSymTable
  , InitArray
  , FiniArray
  , PreInitArray
  , Group
  , SymbolTableShIndex
  , OSSpecific(u32)
  , ProcessorSpecific(u32)
  , User(u32)
}

/// Iterator over ELF64 sections
#[derive(Clone,Debug)]
pub struct Sections<'a, W: 'a> { curr: &'a HeaderRepr<W>
                               , remaining: u32
                               , size: u32
                               }

impl<'a, W: 'a> Sections<'a, W> {
    pub fn new(curr: &'a HeaderRepr<W>, remaining: u32, size: u32)
               -> Sections<'a, W>
    {
        Sections { curr: curr, remaining: remaining, size: size }

    }
}

impl<'a, W> Iterator for Sections<'a, W>
where HeaderRepr<W>: AsHeader {
    type Item = Header<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.remaining == 0 {
            None
        } else {
            let current = self.curr.as_header();
            self.curr = unsafe {
                &*(((self.curr as *const HeaderRepr<W>) as u32 + self.size)
                    as *const HeaderRepr<W>)
            };
            self.remaining -= 1;
            if current.get_type() == Type::Null {
                self.next()
            } else {
                Some(current)
            }
        }
    }
}

//
// #[derive(Debug)]
// #[repr(u32)]
// pub enum Flags { Writable    = 0x1
//                , Allocated   = 0x2
//                , Executable  = 0x4
//                }
<|endoftext|>


<commit_before>use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::frame::{Color, Frame};

const VRAM_SIZE: usize = 0x4000;
const SPRITE_DATA_SIZE: usize = 0xA0;

pub struct GpuStat {
    pub coincidence_interrupt_enabled: bool,
    pub OAM_interrupt_enabled: bool,
    pub VBlank_interrupt_enabled: bool,
    pub HBlank_interrupt_enabled: bool,
}

impl GpuStat {
    pub fn new() -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: false,
            OAM_interrupt_enabled: false,
            VBlank_interrupt_enabled: false,
            HBlank_interrupt_enabled: false,
        }
    }

    pub fn from_u8(b: u8) -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: b & 0x40 == 0x40,
            OAM_interrupt_enabled: b & 0x20 == 0x20,
            VBlank_interrupt_enabled: b & 0x10 == 0x10,
            HBlank_interrupt_enabled: b & 0x08 == 0x08,
        }
    }

    pub fn to_u8(&self, gpu: &Gpu) -> u8 {
        (if self.coincidence_interrupt_enabled {
             0x40
         } else {
             0
         }) | (if self.OAM_interrupt_enabled { 0x20 } else { 0 }) |
            (if self.VBlank_interrupt_enabled {
                 0x10
             } else {
                 0
             }) |
            (if self.HBlank_interrupt_enabled {
                 0x08
             } else {
                 0
             }) | (if gpu.ly == gpu.lyc { 0x04 } else { 0 }) | gpu.mode.to_u8()
    }
}

pub enum GpuMode {
    HBlank,
    VBlank,
    SearchingRam,
    TransferringData,
}

impl GpuMode {
    fn cycles(&self, scroll_x: u8) -> isize {
        let scroll_adjust = match scroll_x % 0x08 {
            5...7 => 2,
            1...4 => 1,
            _ => 0,
        };
        match *self {
            GpuMode::SearchingRam => 21,
            GpuMode::TransferringData => 43 + scroll_adjust,
            GpuMode::HBlank => 50 - scroll_adjust,
            GpuMode::VBlank => 114,
        }
    }

    fn to_u8(&self) -> u8 {
        match *self {
            GpuMode::HBlank => 0x00,
            GpuMode::VBlank => 0x01,
            GpuMode::SearchingRam => 0x02,
            GpuMode::TransferringData => 0x03,
        }
    }
}

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,
    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    ly: u8,
    lyc: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: isize,

    pub frame: Frame,
    mode: GpuMode,

    counter: u8,
    tile_base: usize,
    background_base: usize,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(VRAM_SIZE),
            sprite_data: Memory::new(SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
            tile_base: 0x00,
            background_base: 0xC00,
        }
    }

    pub fn reset(&mut self) {
        *self = Gpu::new();
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        let cycles = cycles as isize;

        if !self.enabled {
            return Ok(());
        }

        self.cycles += cycles;
        // self.cycles = 0x1C8; // it takes 456 CPU clock cycles to draw 1 LCD scanline
        match self.mode {
            GpuMode::HBlank => {
                if self.cycles >= 0xCC {
                    self.cycles = 0x00;
                    self.ly = self.ly + 0x01;
                    if self.ly >= 0x90 {
                        self.switch_mode(GpuMode::VBlank, irq);
                    } else {
                        self.switch_mode(GpuMode::SearchingRam, irq);
                    }
                    self.check_coincidence(irq);
                }
            }
            GpuMode::TransferringData => {
                if self.cycles >= 0xAC {
                    self.render_scanline();

                    self.cycles = 0x00;
                    self.switch_mode(GpuMode::HBlank, irq);
                }
            }
            GpuMode::SearchingRam => {
                if self.cycles >= 0x50 {
                    self.cycles = 0x00;
                    self.switch_mode(GpuMode::TransferringData, irq);
                }
            }
            GpuMode::VBlank => {
                irq.request(Interrupt::Vblank);
                if self.cycles >= 0x1C8 {
                    self.cycles = 0x00;
                    self.ly += 0x01;
                    if self.ly >= 0x99 {
                        self.ly = 0;
                        self.switch_mode(GpuMode::SearchingRam, irq);
                    }
                    self.check_coincidence(irq);
                }
            }
        }

        Ok(())
    }

    fn render_scanline(&mut self) {
        self.clear_scanline();
        self.render_background();
    }

    fn clear_scanline(&mut self) {
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        for i in 0..160 {
            self.frame.pixels[line * 160 + i] = Color::new(0, 0xFF, 0xFF, 0xFF);
        }
    }

    fn render_background(&mut self) {
        let background_map_base_address = self.background_base;
        let tile_base_address = self.tile_base;
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        let bg_map_row = (line / 0x08) as usize;
        for i in 0..160 {
            let x = (i as u8).wrapping_add(self.scroll_x);
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number =
                self.ram[background_map_base_address + (bg_map_row * 0x20 + bg_map_col)];
            let t = if tile_base_address == 0x00 {
                raw_tile_number as usize
            } else {
                128 + ((raw_tile_number as i8 as i16) + 128) as usize
            };

            let line_offset = (line % 0x08) << 0x01;
            let tile_data_start = tile_base_address + (t * 0x10) + line_offset;
            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.frame.pixels[line as usize * 160 + i as usize] = c;
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => {
                self.control_register = val;
                self.enabled = self.control_register & 0x80 == 0x80;
                self.tile_base = if self.control_register & 0x10 == 0x10 {
                    0x00
                } else {
                    0x800
                };
                self.background_base = if self.control_register & 0x08 == 0x08 {
                    0x1C00
                } else {
                    0x1800
                };
            }
            0x41 => self.stat = GpuStat::from_u8(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => {
                self.ly = val;
                println!("WRITING TO LY");
            }
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }

    fn switch_mode(&mut self, mode: GpuMode, irq: &mut Irq) {
        self.cycles += mode.cycles(self.scroll_x);
        match mode {
            GpuMode::SearchingRam => {
                if self.stat.OAM_interrupt_enabled {
                    irq.request(Interrupt::OAM);
                }
            }
            _ => (),
        }
        self.mode = mode;
    }
}
<commit_msg>Add 'render_sprites' method that is a copypasta of 'render_background' (before making it work)<commit_after>use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::frame::{Color, Frame};

const VRAM_SIZE: usize = 0x4000;
const SPRITE_DATA_SIZE: usize = 0xA0;

pub struct GpuStat {
    pub coincidence_interrupt_enabled: bool,
    pub OAM_interrupt_enabled: bool,
    pub VBlank_interrupt_enabled: bool,
    pub HBlank_interrupt_enabled: bool,
}

impl GpuStat {
    pub fn new() -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: false,
            OAM_interrupt_enabled: false,
            VBlank_interrupt_enabled: false,
            HBlank_interrupt_enabled: false,
        }
    }

    pub fn from_u8(b: u8) -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: b & 0x40 == 0x40,
            OAM_interrupt_enabled: b & 0x20 == 0x20,
            VBlank_interrupt_enabled: b & 0x10 == 0x10,
            HBlank_interrupt_enabled: b & 0x08 == 0x08,
        }
    }

    pub fn to_u8(&self, gpu: &Gpu) -> u8 {
        (if self.coincidence_interrupt_enabled {
             0x40
         } else {
             0
         }) | (if self.OAM_interrupt_enabled { 0x20 } else { 0 }) |
            (if self.VBlank_interrupt_enabled {
                 0x10
             } else {
                 0
             }) |
            (if self.HBlank_interrupt_enabled {
                 0x08
             } else {
                 0
             }) | (if gpu.ly == gpu.lyc { 0x04 } else { 0 }) | gpu.mode.to_u8()
    }
}

pub enum GpuMode {
    HBlank,
    VBlank,
    SearchingRam,
    TransferringData,
}

impl GpuMode {
    fn cycles(&self, scroll_x: u8) -> isize {
        let scroll_adjust = match scroll_x % 0x08 {
            5...7 => 2,
            1...4 => 1,
            _ => 0,
        };
        match *self {
            GpuMode::SearchingRam => 21,
            GpuMode::TransferringData => 43 + scroll_adjust,
            GpuMode::HBlank => 50 - scroll_adjust,
            GpuMode::VBlank => 114,
        }
    }

    fn to_u8(&self) -> u8 {
        match *self {
            GpuMode::HBlank => 0x00,
            GpuMode::VBlank => 0x01,
            GpuMode::SearchingRam => 0x02,
            GpuMode::TransferringData => 0x03,
        }
    }
}

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,
    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    ly: u8,
    lyc: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: isize,

    pub frame: Frame,
    mode: GpuMode,

    counter: u8,
    tile_base: usize,
    background_base: usize,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(VRAM_SIZE),
            sprite_data: Memory::new(SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
            tile_base: 0x00,
            background_base: 0xC00,
        }
    }

    pub fn reset(&mut self) {
        *self = Gpu::new();
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        let cycles = cycles as isize;

        if !self.enabled {
            return Ok(());
        }

        self.cycles += cycles;
        // self.cycles = 0x1C8; // it takes 456 CPU clock cycles to draw 1 LCD scanline
        match self.mode {
            GpuMode::HBlank => {
                if self.cycles >= 0xCC {
                    self.cycles = 0x00;
                    self.ly = self.ly + 0x01;
                    if self.ly >= 0x90 {
                        self.switch_mode(GpuMode::VBlank, irq);
                    } else {
                        self.switch_mode(GpuMode::SearchingRam, irq);
                    }
                    self.check_coincidence(irq);
                }
            }
            GpuMode::TransferringData => {
                if self.cycles >= 0xAC {
                    self.render_scanline();

                    self.cycles = 0x00;
                    self.switch_mode(GpuMode::HBlank, irq);
                }
            }
            GpuMode::SearchingRam => {
                if self.cycles >= 0x50 {
                    self.cycles = 0x00;
                    self.switch_mode(GpuMode::TransferringData, irq);
                }
            }
            GpuMode::VBlank => {
                irq.request(Interrupt::Vblank);
                if self.cycles >= 0x1C8 {
                    self.cycles = 0x00;
                    self.ly += 0x01;
                    if self.ly >= 0x99 {
                        self.ly = 0;
                        self.switch_mode(GpuMode::SearchingRam, irq);
                    }
                    self.check_coincidence(irq);
                }
            }
        }

        Ok(())
    }

    fn render_scanline(&mut self) {
        self.clear_scanline();
        self.render_background();
        self.render_sprites();
    }

    fn clear_scanline(&mut self) {
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        for i in 0..160 {
            self.frame.pixels[line * 160 + i] = Color::new(0, 0xFF, 0xFF, 0xFF);
        }
    }

    fn render_background(&mut self) {
        let background_map_base_address = self.background_base;
        let tile_base_address = self.tile_base;
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        let bg_map_row = (line / 0x08) as usize;
        for i in 0..160 {
            let x = (i as u8).wrapping_add(self.scroll_x);
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number =
                self.ram[background_map_base_address + (bg_map_row * 0x20 + bg_map_col)];
            let t = if tile_base_address == 0x00 {
                raw_tile_number as usize
            } else {
                128 + ((raw_tile_number as i8 as i16) + 128) as usize
            };

            let line_offset = (line % 0x08) << 0x01;
            let tile_data_start = tile_base_address + (t * 0x10) + line_offset;
            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.frame.pixels[line as usize * 160 + i as usize] = c;
        }
    }

    fn render_sprites(&mut self) {
        let background_map_base_address = self.background_base;
        let tile_base_address = self.tile_base;
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        let bg_map_row = (line / 0x08) as usize;
        for i in 0..160 {
            let x = (i as u8).wrapping_add(self.scroll_x);
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number =
                self.ram[background_map_base_address + (bg_map_row * 0x20 + bg_map_col)];
            let t = if tile_base_address == 0x00 {
                raw_tile_number as usize
            } else {
                128 + ((raw_tile_number as i8 as i16) + 128) as usize
            };

            let line_offset = (line % 0x08) << 0x01;
            let tile_data_start = tile_base_address + (t * 0x10) + line_offset;
            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.frame.pixels[line as usize * 160 + i as usize] = c;
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => {
                self.control_register = val;
                self.enabled = self.control_register & 0x80 == 0x80;
                self.tile_base = if self.control_register & 0x10 == 0x10 {
                    0x00
                } else {
                    0x800
                };
                self.background_base = if self.control_register & 0x08 == 0x08 {
                    0x1C00
                } else {
                    0x1800
                };
            }
            0x41 => self.stat = GpuStat::from_u8(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => {
                self.ly = val;
                println!("WRITING TO LY");
            }
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }

    fn switch_mode(&mut self, mode: GpuMode, irq: &mut Irq) {
        self.cycles += mode.cycles(self.scroll_x);
        match mode {
            GpuMode::SearchingRam => {
                if self.stat.OAM_interrupt_enabled {
                    irq.request(Interrupt::OAM);
                }
            }
            _ => (),
        }
        self.mode = mode;
    }
}
<|endoftext|>


<commit_before>use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::frame::{Color, Frame};

const VRAM_SIZE: usize = 0x4000;
const SPRITE_DATA_SIZE: usize = 0xA0;

pub struct GpuStat {
    pub coincidence_interrupt_enabled: bool,
    pub OAM_interrupt_enabled: bool,
    pub VBlank_interrupt_enabled: bool,
    pub HBlank_interrupt_enabled: bool,
}

impl GpuStat {
    pub fn new() -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: false,
            OAM_interrupt_enabled: false,
            VBlank_interrupt_enabled: false,
            HBlank_interrupt_enabled: false,
        }
    }

    pub fn from_u8(b: u8) -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: b & 0x40 == 0x40,
            OAM_interrupt_enabled: b & 0x20 == 0x20,
            VBlank_interrupt_enabled: b & 0x10 == 0x10,
            HBlank_interrupt_enabled: b & 0x08 == 0x08,
        }
    }

    pub fn to_u8(&self, gpu: &Gpu) -> u8 {
        (if self.coincidence_interrupt_enabled {
            0x40
        } else {
            0
        }) | (if self.OAM_interrupt_enabled { 0x20 } else { 0 }) |
        (if self.VBlank_interrupt_enabled {
            0x10
        } else {
            0
        }) |
        (if self.HBlank_interrupt_enabled {
            0x08
        } else {
            0
        }) | (if gpu.ly == gpu.lyc { 0x04 } else { 0 }) | gpu.mode.to_u8()
    }
}

pub enum GpuMode {
    HBlank,
    VBlank,
    SearchingRam,
    TransferringData,
}

impl GpuMode {
    fn cycles(&self, scroll_x: u8) -> isize {
        let scroll_adjust = match scroll_x % 0x08 {
            5...7 => 2,
            1...4 => 1,
            _ => 0,
        };
        match *self {
            GpuMode::SearchingRam => 21,
            GpuMode::TransferringData => 43 + scroll_adjust,
            GpuMode::HBlank => 50 - scroll_adjust,
            GpuMode::VBlank => 114,
        }
    }

    fn to_u8(&self) -> u8 {
        match *self {
            GpuMode::HBlank => 0x00,
            GpuMode::VBlank => 0x01,
            GpuMode::SearchingRam => 0x02,
            GpuMode::TransferringData => 0x03,
        }
    }
}

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,
    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    ly: u8,
    lyc: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: isize,

    pub frame: Frame,
    mode: GpuMode,

    counter: u8,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(VRAM_SIZE),
            sprite_data: Memory::new(SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
        }
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        let cycles = cycles as isize;
        self.enabled = self.control_register & 0x80 == 0x80;

        if !self.enabled {
            return Ok(());
        }

        self.cycles -= cycles;
        if self.cycles < 0 {
            self.cycles = 0x1C8; // it takes 456 CPU clock cycles to draw 1 LCD scanline
            match self.mode {
                GpuMode::HBlank => {
                    self.ly = (self.ly + 0x01) % 0x1C8;
                    if self.ly >= 0x90 {
                        self.switch_mode(GpuMode::VBlank, irq);
                    } else {
                        self.switch_mode(GpuMode::SearchingRam, irq);
                    }
                    self.check_coincidence(irq);
                }
                GpuMode::TransferringData => {
                    self.render_scanline();
                    self.switch_mode(GpuMode::HBlank, irq);
                }
                GpuMode::SearchingRam => {
                    self.switch_mode(GpuMode::TransferringData, irq);
                }
                GpuMode::VBlank => {
                    self.ly += 0x01;
                    if self.ly >= 0x99 {
                        self.ly = 0;
                        self.switch_mode(GpuMode::SearchingRam, irq);
                    }
                    self.check_coincidence(irq);
                }
            }
        }

        Ok(())
    }

    fn render_scanline(&mut self) {
        self.clear_scanline();
        self.render_background();
    }

    fn clear_scanline(&mut self) {
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        for i in 0..160 {
            self.frame.pixels[line * 160 + i] = Color::new(0, 0xFF, 0xFF, 0xFF);
        }
    }

    fn render_background(&mut self) {
        let background_map_base_address = self.get_base_background_map_address() as usize;
        let tile_base_address = 0x00; //self.get_base_tile_address() as usize;
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        let bg_map_row = (line / 0x08) as usize;
        for i in 0..160 {
            let x = (i as u8).wrapping_add(self.scroll_x);
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number = self.ram[background_map_base_address +
                                           (bg_map_row * 0x20 + bg_map_col)];
            let t = if tile_base_address == 0x0000 {
                raw_tile_number as usize
            } else {
                128 + ((raw_tile_number as i8 as i16) + 128) as usize
            };

            let line_offset = (line % 0x08) << 0x01;
            let tile_data_start = tile_base_address + (t * 0x10) + line_offset;

            if t == 0x9E {
                panic!("Raw tile number: {}, tile_data_start: {:04X}",
                       t,
                       tile_data_start);
            }
            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.frame.pixels[self.ly as usize * 160 + i as usize] = c;
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    fn get_base_tile_address(&self) -> u16 {
        if self.control_register & 0x10 == 0x10 {
            0x0000
        } else {
            0x0800
        }
    }

    fn get_base_background_map_address(&self) -> u16 {
        if self.control_register & 0x08 == 0x08 {
            0x1C00
        } else {
            0x1800
        }
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => self.control_register = val,
            0x41 => self.stat = GpuStat::from_u8(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => {
                self.ly = val;
                println!("WRITING TO LY");
            }
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }

    fn switch_mode(&mut self, mode: GpuMode, irq: &mut Irq) {
        self.cycles += mode.cycles(self.scroll_x);
        match mode {
            GpuMode::VBlank => {
                irq.request(Interrupt::Vblank);
            }
            GpuMode::SearchingRam => {
                irq.request(Interrupt::Lcd);
            }
            _ => (),
        }
        self.mode = mode;
    }
}
<commit_msg>Remove debug println calls<commit_after>use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::frame::{Color, Frame};

const VRAM_SIZE: usize = 0x4000;
const SPRITE_DATA_SIZE: usize = 0xA0;

pub struct GpuStat {
    pub coincidence_interrupt_enabled: bool,
    pub OAM_interrupt_enabled: bool,
    pub VBlank_interrupt_enabled: bool,
    pub HBlank_interrupt_enabled: bool,
}

impl GpuStat {
    pub fn new() -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: false,
            OAM_interrupt_enabled: false,
            VBlank_interrupt_enabled: false,
            HBlank_interrupt_enabled: false,
        }
    }

    pub fn from_u8(b: u8) -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: b & 0x40 == 0x40,
            OAM_interrupt_enabled: b & 0x20 == 0x20,
            VBlank_interrupt_enabled: b & 0x10 == 0x10,
            HBlank_interrupt_enabled: b & 0x08 == 0x08,
        }
    }

    pub fn to_u8(&self, gpu: &Gpu) -> u8 {
        (if self.coincidence_interrupt_enabled {
            0x40
        } else {
            0
        }) | (if self.OAM_interrupt_enabled { 0x20 } else { 0 }) |
        (if self.VBlank_interrupt_enabled {
            0x10
        } else {
            0
        }) |
        (if self.HBlank_interrupt_enabled {
            0x08
        } else {
            0
        }) | (if gpu.ly == gpu.lyc { 0x04 } else { 0 }) | gpu.mode.to_u8()
    }
}

pub enum GpuMode {
    HBlank,
    VBlank,
    SearchingRam,
    TransferringData,
}

impl GpuMode {
    fn cycles(&self, scroll_x: u8) -> isize {
        let scroll_adjust = match scroll_x % 0x08 {
            5...7 => 2,
            1...4 => 1,
            _ => 0,
        };
        match *self {
            GpuMode::SearchingRam => 21,
            GpuMode::TransferringData => 43 + scroll_adjust,
            GpuMode::HBlank => 50 - scroll_adjust,
            GpuMode::VBlank => 114,
        }
    }

    fn to_u8(&self) -> u8 {
        match *self {
            GpuMode::HBlank => 0x00,
            GpuMode::VBlank => 0x01,
            GpuMode::SearchingRam => 0x02,
            GpuMode::TransferringData => 0x03,
        }
    }
}

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,
    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    ly: u8,
    lyc: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: isize,

    pub frame: Frame,
    mode: GpuMode,

    counter: u8,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(VRAM_SIZE),
            sprite_data: Memory::new(SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
        }
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        let cycles = cycles as isize;
        self.enabled = self.control_register & 0x80 == 0x80;

        if !self.enabled {
            return Ok(());
        }

        self.cycles -= cycles;
        if self.cycles < 0 {
            self.cycles = 0x1C8; // it takes 456 CPU clock cycles to draw 1 LCD scanline
            match self.mode {
                GpuMode::HBlank => {
                    self.ly = (self.ly + 0x01) % 0x1C8;
                    if self.ly >= 0x90 {
                        self.switch_mode(GpuMode::VBlank, irq);
                    } else {
                        self.switch_mode(GpuMode::SearchingRam, irq);
                    }
                    self.check_coincidence(irq);
                }
                GpuMode::TransferringData => {
                    self.render_scanline();
                    self.switch_mode(GpuMode::HBlank, irq);
                }
                GpuMode::SearchingRam => {
                    self.switch_mode(GpuMode::TransferringData, irq);
                }
                GpuMode::VBlank => {
                    self.ly += 0x01;
                    if self.ly >= 0x99 {
                        self.ly = 0;
                        self.switch_mode(GpuMode::SearchingRam, irq);
                    }
                    self.check_coincidence(irq);
                }
            }
        }

        Ok(())
    }

    fn render_scanline(&mut self) {
        self.clear_scanline();
        self.render_background();
    }

    fn clear_scanline(&mut self) {
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        for i in 0..160 {
            self.frame.pixels[line * 160 + i] = Color::new(0, 0xFF, 0xFF, 0xFF);
        }
    }

    fn render_background(&mut self) {
        let background_map_base_address = self.get_base_background_map_address() as usize;
        let tile_base_address = 0x00; //self.get_base_tile_address() as usize;
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        let bg_map_row = (line / 0x08) as usize;
        for i in 0..160 {
            let x = (i as u8).wrapping_add(self.scroll_x);
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number = self.ram[background_map_base_address +
                                           (bg_map_row * 0x20 + bg_map_col)];
            let t = if tile_base_address == 0x0000 {
                raw_tile_number as usize
            } else {
                128 + ((raw_tile_number as i8 as i16) + 128) as usize
            };

            let line_offset = (line % 0x08) << 0x01;
            let tile_data_start = tile_base_address + (t * 0x10) + line_offset;
            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.frame.pixels[self.ly as usize * 160 + i as usize] = c;
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    fn get_base_tile_address(&self) -> u16 {
        if self.control_register & 0x10 == 0x10 {
            0x0000
        } else {
            0x0800
        }
    }

    fn get_base_background_map_address(&self) -> u16 {
        if self.control_register & 0x08 == 0x08 {
            0x1C00
        } else {
            0x1800
        }
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => self.control_register = val,
            0x41 => self.stat = GpuStat::from_u8(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => {
                self.ly = val;
                println!("WRITING TO LY");
            }
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }

    fn switch_mode(&mut self, mode: GpuMode, irq: &mut Irq) {
        self.cycles += mode.cycles(self.scroll_x);
        match mode {
            GpuMode::VBlank => {
                irq.request(Interrupt::Vblank);
            }
            GpuMode::SearchingRam => {
                irq.request(Interrupt::Lcd);
            }
            _ => (),
        }
        self.mode = mode;
    }
}
<|endoftext|>