<commit_before>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

pub mod Ports;

use std::fmt::{Debug,Formatter,Error};

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by running `Program`s on it or executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: usize,
    program: Program,
}

/// A `Program` is a sequence of `Instruction`s
pub struct Program(pub Vec<Instruction>);

impl PartialEq for Program {
    fn eq(&self, other: &Program) -> bool {
        let Program(ref self_instructions) = *self;
        let Program(ref other_instructions) = *other;
        if self_instructions.len() == other_instructions.len() {
            for index in 0..(self_instructions.len()) {
                let ref self_instruction = self_instructions[index];
                let ref other_instruction = other_instructions[index];
                if self_instruction != other_instruction {
                    return false
                }
            }
            true
        } else {
            false
        }
    }
}

impl Eq for Program {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let Program(ref instructions) = *self;
        write!(f, "[{}:", instructions.len()).unwrap();
        for instruction in instructions {
            write!(f, " {:?}", instruction).unwrap();
        }
        write!(f, "]")
    }
}

impl Clone for Program {
    fn clone(&self) -> Program {
        let mut clone_instructions: Vec<Instruction> = vec![];
        let Program(ref self_instructions) = *self;
        for ref mut instruction in self_instructions {
            clone_instructions.push(instruction.clone());
        }
        Program(clone_instructions)
    }
}

/// `Instruction`s are executed by a `Node`
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Destination {
    /// A register
    Register(Register),
}

/// The `Status` a `Program` run on a certain `Node`.
pub enum Status {
    /// a successful run of the program
    Successful(Node),
    /// an unsuccessful run of the program, because of a deadlock.
    Deadlock(Node),
}

impl Node {
    /// Create a `Node` with defaults for accumulator, backup registers, program counter and program
    pub fn new() -> Node {
        Node { acc: 0, bac: 0, pc: 0, program: Program(vec![]) }
    }

    /// Loads a program in this `Node`
    pub fn load(&self, program: Program) -> Node {
        Node { program: program.clone(), .. *self }
    }

    /// Run the loaded program, returning an calculation state
    pub fn run(&self) -> Status {
        let mut node = Node { program: self.program.clone(), .. *self };

        loop {
            match node.fetch_instruction() {
                Some(instruction) => {
                    node = node.execute(instruction);
                }
                None => {
                    break
                }
            }
        }

        Status::Successful(Node { program: node.program.clone(), .. node })
    }

    fn fetch_instruction(&self) -> Option<Instruction> {
        let Program(ref instructions) = self.program;
        if self.pc < instructions.len() {
            Some(instructions[self.pc].clone())
        } else {
            None
        }
    }

    /// Create a `Node` from self with the program counter incremented
    fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    fn set_pc(&self, pc: usize) -> Node {
        Node { pc: pc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, program: self.program.clone(), .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: usize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn programs_should_differ_when_different_size() {
        assert_eq!(false, Program(vec![]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_differ_when_different_instructions() {
        assert_eq!(false, Program(vec![Instruction::SWP]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_equal_with_same_instructions() {
        assert_eq!(Program(vec![Instruction::SAV]), Program(vec![Instruction::SAV]));
    }

    #[test]
    fn node_should_execute_program_correctly() {
        let program: Program = Program(vec![// calculate 4 * source - 1
            Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::SUB(Source::Literal(1))
        ]);
        let node: Node = Node::new().load(program);

        match node.run() {
            Status::Successful(_) => assert!(true),
            Status::Deadlock(_) => assert!(false),
        }
    }
}

<commit_msg>Assign ports to node<commit_after>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

pub mod Ports;

use std::fmt::{Debug,Formatter,Error};
use self::Ports::Port;

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by running `Program`s on it or executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: usize,
    program: Program,
    /// The up `Port` used for reading
    up: Port,
    /// The down `Port` used for writing
    down: Port
}

/// A `Program` is a sequence of `Instruction`s
pub struct Program(pub Vec<Instruction>);

impl PartialEq for Program {
    fn eq(&self, other: &Program) -> bool {
        let Program(ref self_instructions) = *self;
        let Program(ref other_instructions) = *other;
        if self_instructions.len() == other_instructions.len() {
            for index in 0..(self_instructions.len()) {
                let ref self_instruction = self_instructions[index];
                let ref other_instruction = other_instructions[index];
                if self_instruction != other_instruction {
                    return false
                }
            }
            true
        } else {
            false
        }
    }
}

impl Eq for Program {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let Program(ref instructions) = *self;
        write!(f, "[{}:", instructions.len()).unwrap();
        for instruction in instructions {
            write!(f, " {:?}", instruction).unwrap();
        }
        write!(f, "]")
    }
}

impl Clone for Program {
    fn clone(&self) -> Program {
        let mut clone_instructions: Vec<Instruction> = vec![];
        let Program(ref self_instructions) = *self;
        for ref mut instruction in self_instructions {
            clone_instructions.push(instruction.clone());
        }
        Program(clone_instructions)
    }
}

/// `Instruction`s are executed by a `Node`
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Destination {
    /// A register
    Register(Register),
}

/// The `Status` a `Program` run on a certain `Node`.
pub enum Status {
    /// a successful run of the program
    Successful(Node),
    /// an unsuccessful run of the program, because of a deadlock.
    Deadlock(Node),
}

impl Node {
    /// Create a `Node` with defaults for accumulator, backup registers, program counter and program
    pub fn new() -> Node {
        Node {
            acc: 0,
            bac: 0,
            pc: 0,
            program: Program(vec![]),
            up: Port::new(vec![]),
            down: Port::new(vec![]),
        }
    }

    /// Loads a program in this `Node`
    pub fn load(&self, program: Program) -> Node {
        Node { program: program.clone(), up: self.up.clone(), down: self.down.clone(), .. *self }
    }

    /// Run the loaded program, returning an calculation state
    pub fn run(&self) -> Status {
        let mut node = Node { program: self.program.clone(), up: self.up.clone(), down: self.down.clone(), .. *self };

        loop {
            match node.fetch_instruction() {
                Some(instruction) => {
                    node = node.execute(instruction);
                }
                None => {
                    break
                }
            }
        }

        Status::Successful(Node { program: node.program.clone(), .. node })
    }

    fn fetch_instruction(&self) -> Option<Instruction> {
        let Program(ref instructions) = self.program;
        if self.pc < instructions.len() {
            Some(instructions[self.pc].clone())
        } else {
            None
        }
    }

    /// Create a `Node` from self with the program counter incremented
    fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, program: self.program.clone(), up: self.up.clone(), down: self.down.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    fn set_pc(&self, pc: usize) -> Node {
        Node { pc: pc, program: self.program.clone(), up: self.up.clone(), down: self.down.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, program: self.program.clone(), up: self.up.clone(), down: self.down.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, program: self.program.clone(), up: self.up.clone(), down: self.down.clone(), .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: usize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn programs_should_differ_when_different_size() {
        assert_eq!(false, Program(vec![]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_differ_when_different_instructions() {
        assert_eq!(false, Program(vec![Instruction::SWP]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_equal_with_same_instructions() {
        assert_eq!(Program(vec![Instruction::SAV]), Program(vec![Instruction::SAV]));
    }

    #[test]
    fn node_should_execute_program_correctly() {
        let program: Program = Program(vec![// calculate 4 * source - 1
            Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::SUB(Source::Literal(1))
        ]);
        let node: Node = Node::new().load(program);

        match node.run() {
            Status::Successful(_) => assert!(true),
            Status::Deadlock(_) => assert!(false),
        }
    }
}

<|endoftext|>


<commit_before>// vim: tw=80
use super::*;

/// An item that's ready to be mocked.
///
/// It should be functionally identical or near-identical to the original item,
/// but with minor alterations that make it suitable for mocking, such as
/// altered lifetimes.
pub(crate) enum MockableItem {
    Module(MockableModule),
    Struct(MockableStruct)
}

impl From<(Attrs, Item)> for MockableItem {
    fn from((attrs, item): (Attrs, Item)) -> MockableItem {
        match item {
            Item::Impl(item_impl) =>
                MockableItem::Struct(MockableStruct::from(item_impl)),
            Item::ForeignMod(item_foreign_mod) =>
                MockableItem::Module(
                    MockableModule::from((attrs, item_foreign_mod))
                ),
            Item::Mod(item_mod) =>
                MockableItem::Module(MockableModule::from(item_mod)),
            Item::Trait(trait_) =>
                MockableItem::Struct(MockableStruct::from((attrs, trait_))),
            _ => panic!("automock does not support this item type")
        }
    }
}

impl From<MockableStruct> for MockableItem {
    fn from(mock: MockableStruct) -> MockableItem {
        // TODO: stuff like deselfify
        MockableItem::Struct(mock)
    }
}

pub(crate) struct MockableModule {
    pub vis: Visibility,
    pub mock_ident: Ident,
    pub mod_token: token::Mod,
    /// Ident of the original module, if any
    pub orig_ident: Option<Ident>,
    pub content: Vec<Item>
}

impl From<(Attrs, ItemForeignMod)> for MockableModule {
    fn from((attrs, foreign): (Attrs, ItemForeignMod)) -> MockableModule {
        let orig_ident = None;
        let mock_ident = attrs.modname.expect(concat!(
            "module name is required when mocking foreign functions,",
            " like `#[automock(mod mock_ffi)]`"
        ));
        let mod_token = <Token![mod]>::default();
        let vis = Visibility::Public(VisPublic{
            pub_token: <Token![pub]>::default()
        });
        let mut content = vec![
            // When mocking extern blocks, we pretend that they're modules, so
            // we need a "use super::*;" to ensure that types can resolve
            Item::Use(ItemUse {
                attrs: Vec::new(),
                vis: Visibility::Inherited,
                use_token: token::Use::default(),
                leading_colon: None,
                tree: UseTree::Path(UsePath {
                    ident: Ident::new("super", Span::call_site()),
                    colon2_token: token::Colon2::default(),
                    tree: Box::new(UseTree::Glob(UseGlob {
                        star_token: token::Star::default()
                    }))
                }),
                semi_token: token::Semi::default()
            })
        ];
        content.extend(foreign.items.into_iter()
            .map(|foreign_item| {
                match foreign_item {
                    ForeignItem::Fn(f) => {
                        let span = f.sig.span();
                        let mut sig = f.sig;

                        // When mocking extern blocks, we pretend that they're
                        // modules.  So we must supersuperfy everything by one
                        // level.
                        let vis = expectation_visibility(&f.vis, 1);

                        for arg in sig.inputs.iter_mut() {
                            if let FnArg::Typed(pt) = arg {
                                *pt.ty = supersuperfy(&*pt.ty, 1);
                            }
                        }
                        if let ReturnType::Type(_, ty) = &mut sig.output {
                            **ty = supersuperfy(&*ty, 1);
                        }

                        // Foreign functions are always unsafe.  Mock foreign
                        // functions should be unsafe too, to prevent "warning:
                        // unused unsafe" messages.
                        sig.unsafety = Some(Token![unsafe](span));
                        let block = Box::new(Block {
                            brace_token: token::Brace::default(),
                            stmts: Vec::new()
                        });

                        Item::Fn(
                            ItemFn {
                                attrs: f.attrs,
                                vis,
                                sig,
                                block
                            }
                        )
                    },
                    _ => {
                        compile_error(foreign_item.span(),
                            "Unsupported foreign item type"
                        );
                        Item::Verbatim(TokenStream::default())
                    }
                }
            }));
        MockableModule { vis, mock_ident, mod_token, orig_ident, content }
    }
}

impl From<ItemMod> for MockableModule {
    fn from(mod_: ItemMod) -> MockableModule {
        let span = mod_.span();
        // TODO: in the future, consider mocking non-public modules
        let vis = Visibility::Public(VisPublic{
            pub_token: Token![pub](mod_.vis.span())
        });
        let mock_ident = format_ident!("mock_{}", mod_.ident);
        let orig_ident = Some(mod_.ident);
        let mod_token = mod_.mod_token;
        let content = if let Some((_, content)) = mod_.content {
            content
        } else {
            compile_error(span,
            "automock can only mock inline modules, not modules from another file");
            Vec::new()
        };
        // TODO: demutify funcs
        // TODO: deimplify funcs
        MockableModule { vis, mock_ident, mod_token, orig_ident, content }
    }
}
<commit_msg>When mocking foreign functions with no return, explicitly return ()<commit_after>// vim: tw=80
use super::*;

/// An item that's ready to be mocked.
///
/// It should be functionally identical or near-identical to the original item,
/// but with minor alterations that make it suitable for mocking, such as
/// altered lifetimes.
pub(crate) enum MockableItem {
    Module(MockableModule),
    Struct(MockableStruct)
}

impl From<(Attrs, Item)> for MockableItem {
    fn from((attrs, item): (Attrs, Item)) -> MockableItem {
        match item {
            Item::Impl(item_impl) =>
                MockableItem::Struct(MockableStruct::from(item_impl)),
            Item::ForeignMod(item_foreign_mod) =>
                MockableItem::Module(
                    MockableModule::from((attrs, item_foreign_mod))
                ),
            Item::Mod(item_mod) =>
                MockableItem::Module(MockableModule::from(item_mod)),
            Item::Trait(trait_) =>
                MockableItem::Struct(MockableStruct::from((attrs, trait_))),
            _ => panic!("automock does not support this item type")
        }
    }
}

impl From<MockableStruct> for MockableItem {
    fn from(mock: MockableStruct) -> MockableItem {
        // TODO: stuff like deselfify
        MockableItem::Struct(mock)
    }
}

pub(crate) struct MockableModule {
    pub vis: Visibility,
    pub mock_ident: Ident,
    pub mod_token: token::Mod,
    /// Ident of the original module, if any
    pub orig_ident: Option<Ident>,
    pub content: Vec<Item>
}

impl From<(Attrs, ItemForeignMod)> for MockableModule {
    fn from((attrs, foreign): (Attrs, ItemForeignMod)) -> MockableModule {
        let orig_ident = None;
        let mock_ident = attrs.modname.expect(concat!(
            "module name is required when mocking foreign functions,",
            " like `#[automock(mod mock_ffi)]`"
        ));
        let mod_token = <Token![mod]>::default();
        let vis = Visibility::Public(VisPublic{
            pub_token: <Token![pub]>::default()
        });
        let mut content = vec![
            // When mocking extern blocks, we pretend that they're modules, so
            // we need a "use super::*;" to ensure that types can resolve
            Item::Use(ItemUse {
                attrs: Vec::new(),
                vis: Visibility::Inherited,
                use_token: token::Use::default(),
                leading_colon: None,
                tree: UseTree::Path(UsePath {
                    ident: Ident::new("super", Span::call_site()),
                    colon2_token: token::Colon2::default(),
                    tree: Box::new(UseTree::Glob(UseGlob {
                        star_token: token::Star::default()
                    }))
                }),
                semi_token: token::Semi::default()
            })
        ];
        content.extend(foreign.items.into_iter()
            .map(|foreign_item| {
                match foreign_item {
                    ForeignItem::Fn(f) => {
                        let span = f.sig.span();
                        let mut sig = f.sig;

                        // When mocking extern blocks, we pretend that they're
                        // modules.  So we must supersuperfy everything by one
                        // level.
                        let vis = expectation_visibility(&f.vis, 1);

                        for arg in sig.inputs.iter_mut() {
                            if let FnArg::Typed(pt) = arg {
                                *pt.ty = supersuperfy(&*pt.ty, 1);
                            }
                        }
                        match &mut sig.output {
                            ReturnType::Type(_, ty) =>
                                **ty = supersuperfy(&*ty, 1),
                            ReturnType::Default => {
                                // Add an explicit "-> ()" for perfect
                                // compatibility with 0.7.0.  TODO: remove this
                                // after merging the 2020_refactor branch
                                let rarrow = Token![->](sig.output.span());
                                let unit = Type::Tuple(TypeTuple{
                                    paren_token: token::Paren::default(),
                                    elems: Punctuated::new()
                                });
                                sig.output = ReturnType::Type(rarrow,
                                                              Box::new(unit));
                            }
                        }

                        // Foreign functions are always unsafe.  Mock foreign
                        // functions should be unsafe too, to prevent "warning:
                        // unused unsafe" messages.
                        sig.unsafety = Some(Token![unsafe](span));
                        let block = Box::new(Block {
                            brace_token: token::Brace::default(),
                            stmts: Vec::new()
                        });

                        Item::Fn(
                            ItemFn {
                                attrs: f.attrs,
                                vis,
                                sig,
                                block
                            }
                        )
                    },
                    _ => {
                        compile_error(foreign_item.span(),
                            "Unsupported foreign item type"
                        );
                        Item::Verbatim(TokenStream::default())
                    }
                }
            }));
        MockableModule { vis, mock_ident, mod_token, orig_ident, content }
    }
}

impl From<ItemMod> for MockableModule {
    fn from(mod_: ItemMod) -> MockableModule {
        let span = mod_.span();
        // TODO: in the future, consider mocking non-public modules
        let vis = Visibility::Public(VisPublic{
            pub_token: Token![pub](mod_.vis.span())
        });
        let mock_ident = format_ident!("mock_{}", mod_.ident);
        let orig_ident = Some(mod_.ident);
        let mod_token = mod_.mod_token;
        let content = if let Some((_, content)) = mod_.content {
            content
        } else {
            compile_error(span,
            "automock can only mock inline modules, not modules from another file");
            Vec::new()
        };
        // TODO: demutify funcs
        // TODO: deimplify funcs
        MockableModule { vis, mock_ident, mod_token, orig_ident, content }
    }
}
<|endoftext|>


<commit_before>// vim: tw=80
use super::*;

/// Performs transformations on a function to make it mockable
fn mockable_fn(mut item_fn: ItemFn) -> ItemFn {
    demutify(&mut item_fn.sig.inputs);
    deimplify(&mut item_fn.sig.output);
    item_fn
}

/// Performs transformations on an Item to make it mockable
fn mockable_item(item: Item) -> Item {
    match item {
        Item::Fn(item_fn) => Item::Fn(mockable_fn(item_fn)),
        x => x
    }
}

/// An item that's ready to be mocked.
///
/// It should be functionally identical or near-identical to the original item,
/// but with minor alterations that make it suitable for mocking, such as
/// altered lifetimes.
pub(crate) enum MockableItem {
    Module(MockableModule),
    Struct(MockableStruct)
}

impl From<(Attrs, Item)> for MockableItem {
    fn from((attrs, item): (Attrs, Item)) -> MockableItem {
        match item {
            Item::Impl(item_impl) =>
                MockableItem::Struct(MockableStruct::from(item_impl)),
            Item::ForeignMod(item_foreign_mod) =>
                MockableItem::Module(
                    MockableModule::from((attrs, item_foreign_mod))
                ),
            Item::Mod(item_mod) =>
                MockableItem::Module(MockableModule::from(item_mod)),
            Item::Trait(trait_) =>
                MockableItem::Struct(MockableStruct::from((attrs, trait_))),
            _ => panic!("automock does not support this item type")
        }
    }
}

impl From<MockableStruct> for MockableItem {
    fn from(mock: MockableStruct) -> MockableItem {
        MockableItem::Struct(mock)
    }
}

pub(crate) struct MockableModule {
    pub attrs: TokenStream,
    pub vis: Visibility,
    pub mock_ident: Ident,
    pub mod_token: token::Mod,
    /// Ident of the original module, if any
    pub orig_ident: Option<Ident>,
    pub content: Vec<Item>
}

impl From<(Attrs, ItemForeignMod)> for MockableModule {
    fn from((attrs, foreign): (Attrs, ItemForeignMod)) -> MockableModule {
        let orig_ident = None;
        let mock_ident = attrs.modname.expect(concat!(
            "module name is required when mocking foreign functions,",
            " like `#[automock(mod mock_ffi)]`"
        ));
        let mod_token = <Token![mod]>::default();
        let vis = Visibility::Public(VisPublic{
            pub_token: <Token![pub]>::default()
        });
        let attrs = quote!(
            #[deprecated(since = "0.9.0", note = "Using automock directly on an extern block is deprecated.  Instead, wrap the extern block in a module, and automock that, like #[automoock] mod ffi { extern \"C\" { fn foo ... } }")]
        );
        let mut content = vec![
            // When mocking extern blocks, we pretend that they're modules, so
            // we need a "use super::*;" to ensure that types can resolve
            Item::Use(ItemUse {
                attrs: Vec::new(),
                vis: Visibility::Inherited,
                use_token: token::Use::default(),
                leading_colon: None,
                tree: UseTree::Path(UsePath {
                    ident: Ident::new("super", Span::call_site()),
                    colon2_token: token::Colon2::default(),
                    tree: Box::new(UseTree::Glob(UseGlob {
                        star_token: token::Star::default()
                    }))
                }),
                semi_token: token::Semi::default()
            })
        ];
        content.extend(foreign.items.into_iter()
            .map(|foreign_item| {
                match foreign_item {
                    ForeignItem::Fn(f) => {
                        let span = f.sig.span();
                        let mut sig = f.sig;

                        // When mocking extern blocks, we pretend that they're
                        // modules.  So we must supersuperfy everything by one
                        // level.
                        let vis = expectation_visibility(&f.vis, 1);

                        for arg in sig.inputs.iter_mut() {
                            if let FnArg::Typed(pt) = arg {
                                *pt.ty = supersuperfy(&*pt.ty, 1);
                            }
                        }
                        if let ReturnType::Type(_, ty) = &mut sig.output {
                                **ty = supersuperfy(&*ty, 1);
                        }

                        // Foreign functions are always unsafe.  Mock foreign
                        // functions should be unsafe too, to prevent "warning:
                        // unused unsafe" messages.
                        sig.unsafety = Some(Token![unsafe](span));
                        let block = Box::new(Block {
                            brace_token: token::Brace::default(),
                            stmts: Vec::new()
                        });

                        Item::Fn(
                            ItemFn {
                                attrs: f.attrs,
                                vis,
                                sig,
                                block
                            }
                        )
                    },
                    _ => {
                        compile_error(foreign_item.span(),
                            "Unsupported foreign item type"
                        );
                        Item::Verbatim(TokenStream::default())
                    }
                }
            }));
        MockableModule {
            attrs,
            vis,
            mock_ident,
            mod_token,
            orig_ident,
            content
        }
    }
}

impl From<ItemMod> for MockableModule {
    fn from(mod_: ItemMod) -> MockableModule {
        let span = mod_.span();
        let vis = mod_.vis;
        let mock_ident = format_ident!("mock_{}", mod_.ident);
        let orig_ident = Some(mod_.ident);
        let mod_token = mod_.mod_token;
        let content = if let Some((_, content)) = mod_.content {
            content.into_iter()
            .map(mockable_item)
            .collect()
        } else {
            compile_error(span,
            "automock can only mock inline modules, not modules from another file");
            Vec::new()
        };
        MockableModule {
            attrs: TokenStream::new(),
            vis,
            mock_ident,
            mod_token,
            orig_ident,
            content
        }
    }
}
<commit_msg>Delete dead code<commit_after>// vim: tw=80
use super::*;

/// Performs transformations on a function to make it mockable
fn mockable_fn(mut item_fn: ItemFn) -> ItemFn {
    demutify(&mut item_fn.sig.inputs);
    deimplify(&mut item_fn.sig.output);
    item_fn
}

/// Performs transformations on an Item to make it mockable
fn mockable_item(item: Item) -> Item {
    match item {
        Item::Fn(item_fn) => Item::Fn(mockable_fn(item_fn)),
        x => x
    }
}

/// An item that's ready to be mocked.
///
/// It should be functionally identical or near-identical to the original item,
/// but with minor alterations that make it suitable for mocking, such as
/// altered lifetimes.
pub(crate) enum MockableItem {
    Module(MockableModule),
    Struct(MockableStruct)
}

impl From<(Attrs, Item)> for MockableItem {
    fn from((attrs, item): (Attrs, Item)) -> MockableItem {
        match item {
            Item::Impl(item_impl) =>
                MockableItem::Struct(MockableStruct::from(item_impl)),
            Item::ForeignMod(item_foreign_mod) =>
                MockableItem::Module(
                    MockableModule::from((attrs, item_foreign_mod))
                ),
            Item::Mod(item_mod) =>
                MockableItem::Module(MockableModule::from(item_mod)),
            Item::Trait(trait_) =>
                MockableItem::Struct(MockableStruct::from((attrs, trait_))),
            _ => panic!("automock does not support this item type")
        }
    }
}

impl From<MockableStruct> for MockableItem {
    fn from(mock: MockableStruct) -> MockableItem {
        MockableItem::Struct(mock)
    }
}

pub(crate) struct MockableModule {
    pub attrs: TokenStream,
    pub vis: Visibility,
    pub mock_ident: Ident,
    /// Ident of the original module, if any
    pub orig_ident: Option<Ident>,
    pub content: Vec<Item>
}

impl From<(Attrs, ItemForeignMod)> for MockableModule {
    fn from((attrs, foreign): (Attrs, ItemForeignMod)) -> MockableModule {
        let orig_ident = None;
        let mock_ident = attrs.modname.expect(concat!(
            "module name is required when mocking foreign functions,",
            " like `#[automock(mod mock_ffi)]`"
        ));
        let vis = Visibility::Public(VisPublic{
            pub_token: <Token![pub]>::default()
        });
        let attrs = quote!(
            #[deprecated(since = "0.9.0", note = "Using automock directly on an extern block is deprecated.  Instead, wrap the extern block in a module, and automock that, like #[automoock] mod ffi { extern \"C\" { fn foo ... } }")]
        );
        let mut content = vec![
            // When mocking extern blocks, we pretend that they're modules, so
            // we need a "use super::*;" to ensure that types can resolve
            Item::Use(ItemUse {
                attrs: Vec::new(),
                vis: Visibility::Inherited,
                use_token: token::Use::default(),
                leading_colon: None,
                tree: UseTree::Path(UsePath {
                    ident: Ident::new("super", Span::call_site()),
                    colon2_token: token::Colon2::default(),
                    tree: Box::new(UseTree::Glob(UseGlob {
                        star_token: token::Star::default()
                    }))
                }),
                semi_token: token::Semi::default()
            })
        ];
        content.extend(foreign.items.into_iter()
            .map(|foreign_item| {
                match foreign_item {
                    ForeignItem::Fn(f) => {
                        let span = f.sig.span();
                        let mut sig = f.sig;

                        // When mocking extern blocks, we pretend that they're
                        // modules.  So we must supersuperfy everything by one
                        // level.
                        let vis = expectation_visibility(&f.vis, 1);

                        for arg in sig.inputs.iter_mut() {
                            if let FnArg::Typed(pt) = arg {
                                *pt.ty = supersuperfy(&*pt.ty, 1);
                            }
                        }
                        if let ReturnType::Type(_, ty) = &mut sig.output {
                                **ty = supersuperfy(&*ty, 1);
                        }

                        // Foreign functions are always unsafe.  Mock foreign
                        // functions should be unsafe too, to prevent "warning:
                        // unused unsafe" messages.
                        sig.unsafety = Some(Token![unsafe](span));
                        let block = Box::new(Block {
                            brace_token: token::Brace::default(),
                            stmts: Vec::new()
                        });

                        Item::Fn(
                            ItemFn {
                                attrs: f.attrs,
                                vis,
                                sig,
                                block
                            }
                        )
                    },
                    _ => {
                        compile_error(foreign_item.span(),
                            "Unsupported foreign item type"
                        );
                        Item::Verbatim(TokenStream::default())
                    }
                }
            }));
        MockableModule {
            attrs,
            vis,
            mock_ident,
            orig_ident,
            content
        }
    }
}

impl From<ItemMod> for MockableModule {
    fn from(mod_: ItemMod) -> MockableModule {
        let span = mod_.span();
        let vis = mod_.vis;
        let mock_ident = format_ident!("mock_{}", mod_.ident);
        let orig_ident = Some(mod_.ident);
        let content = if let Some((_, content)) = mod_.content {
            content.into_iter()
            .map(mockable_item)
            .collect()
        } else {
            compile_error(span,
            "automock can only mock inline modules, not modules from another file");
            Vec::new()
        };
        MockableModule {
            attrs: TokenStream::new(),
            vis,
            mock_ident,
            orig_ident,
            content
        }
    }
}
<|endoftext|>


<commit_before>//! byt - io
//!
//! Implements a piece table to abstract over accessing and
//! modifying a file on disk.

// EXTERNS

// LIBRARY INCLUDES
use std::fmt;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Empty;
use std::io::BufReader;
use std::io::Read;
use std::io;

// SUBMODULES

// LOCAL INCLUDES

#[derive(Debug, Copy, Clone, PartialEq)]
enum SourceFile {
    /// The original file on disk.
    Original,
    /// The append file, held in memory.
    Append
}

/// A Piece stores some information about a part of the
/// modified file.
struct Piece {
    /// The file this piece refers to.
    file : SourceFile,
    /// The offset (in bytes) of the text in this Piece.
    offset : u32,
    /// The length of the text in this Piece.
    length : u32
}

impl fmt::Display for Piece {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({:?}, {}, {})", self.file, self.offset, self.length)
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Operation {
    Insert,
    Delete
}

/// Records a particular modification of the text.
struct Action {
    op     : Operation,
    offset : u32,
    length : u32
}

/// Implements logical operations on a file that are not written
/// until asked to.
pub struct PieceFile {
    /// Stores all mutation operations of the file so that we can
    /// undo.
    actions : Vec<Action>,
    /// The in-memory append string. All edits will refer to bytes
    /// stored here.
    append_file : String,
    /// The total size (in bytes) of the PieceFile.
    length : u32,
    /// The path of the file this PieceFile refers to.
    path : String,
    /// Stores all current Pieces.
    piece_table : Vec<Piece>,
    /// The seekable file reader.
    reader : Option<BufReader<File>>,
}

impl PieceFile {
    // #################################
    // P R I V A T E  F U N C T I O N S
    // #################################
    /// Get a Piece at a particular offset.
    fn get_at_offset(&self, offset : u32) -> Option<usize> {
        let mut logical_length = 0;

        for index in 0..self.piece_table.len() {
            let piece = &self.piece_table[index];
            logical_length += piece.length;

            if offset > logical_length {
                continue;
            }

            return Some(index);
        }
        None
    }

    // ###############################
    // P U B L I C  F U N C T I O N S
    // ###############################
    /// Open a new PieceFile. If the file doesn't exist, it is created.
    pub fn open(path : String) -> io::Result<PieceFile> {
        let file = OpenOptions::new()
            .read(true)
            .open(path.clone()).unwrap();

        // Get the length of the file to initialize the first Piece
        let size = file.metadata().unwrap().len() as u32;

        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : size,
            path,
            piece_table : Vec::new(),
            reader      : Some(BufReader::new(file)),
        };

        piece_file.piece_table.push(Piece {
            file : SourceFile::Original,
            offset : 0,
            length : size as u32,
        });

        Ok(piece_file)
    }

    /// Create a new empty PieceFile.
    pub fn empty() -> io::Result<PieceFile> {
        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : 0,
            path        : String::from(""),
            piece_table : Vec::new(),
            reader      : None,
        };

        Ok(piece_file)
    }

    /// Insert some text.
    pub fn insert(&mut self, text : &str, offset : u32) {
        let length = text.len() as u32;
        let append_offset = self.append_file.len() as u32;

        self.append_file += text;
        self.length      += length;

        let piece = Piece {
            file   : SourceFile::Append,
            offset : append_offset,
            length,
        };

        let action = Action {
            op : Operation::Insert,
            offset,
            length,
        };

        self.actions.push(action);

        // There are edge cases if you do an insert
        // at the beginning or end of the file.
        if offset == 0 {
            self.piece_table.insert(0, piece);
            return;
        }
        else if offset + length == self.length {
            self.piece_table.push(piece);
            return;
        }

        // The insertion may create as many as three pieces. It can
        // split a piece that already exists into two parts and then
        // goes in between them.
        let split_index = match self.get_at_offset(offset) {
            Some(v) => v,
            None => return
        };
        let split_piece = self.piece_table.remove(split_index);

        let lower_size  = offset - split_piece.offset;
        let upper_size  = (split_piece.offset + split_piece.length) - offset;

        if upper_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file   : split_piece.file,
                offset : split_piece.offset + lower_size,
                length : upper_size,
            });
        }

        self.piece_table.insert(split_index, piece);

        if lower_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file   : split_piece.file,
                offset : split_piece.offset,
                length : lower_size,
            });
        }
    }
}

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

    #[test]
    fn it_inserts() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("foo", 0);
        file.insert("bar", 0);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);

        let first_element  = &piece_table[0];
        let second_element = &piece_table[1];

        assert_eq!(first_element.offset, 3);
        assert_eq!(first_element.length, 3);

        assert_eq!(second_element.offset, 0);
        assert_eq!(second_element.length, 3);

        let action = &file.actions[0];
        assert_eq!(action.op, Operation::Insert);
    }
}
<commit_msg>feat(PieceFile): add basic code for text deletion<commit_after>//! byt - io
//!
//! Implements a piece table to abstract over accessing and
//! modifying a file on disk.

// EXTERNS

// LIBRARY INCLUDES
use std::fmt;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Empty;
use std::io::BufReader;
use std::io::Read;
use std::io;

// SUBMODULES

// LOCAL INCLUDES

#[derive(Debug, Copy, Clone, PartialEq)]
enum SourceFile {
    /// The original file on disk.
    Original,
    /// The append file, held in memory.
    Append
}

/// A Piece stores some information about a part of the
/// modified file.
#[derive(Clone)]
struct Piece {
    /// The file this piece refers to.
    file : SourceFile,
    /// The offset (in bytes) of the text in this Piece in its file.
    file_offset : u32,
    /// The length of the text in this Piece.
    length : u32,
    /// The logical offset of the Piece.
    logical_offset : u32,
}

impl fmt::Display for Piece {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}:{} ({}){})", self.file, self.file_offset, self.logical_offset, self.length)
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Operation {
    Insert,
    Delete
}

/// Records a particular modification of the text.
struct Action {
    op     : Operation,
    offset : u32,
    pieces : Vec<Piece>,
    length : u32
}

/// Implements logical operations on a file that are not written
/// until asked to.
pub struct PieceFile {
    /// Stores all mutation operations of the file so that we can
    /// undo.
    actions : Vec<Action>,
    /// The in-memory append string. All edits will refer to bytes
    /// stored here.
    append_file : String,
    /// The total size (in bytes) of the PieceFile.
    length : u32,
    /// The path of the file this PieceFile refers to.
    path : String,
    /// Stores all current Pieces.
    piece_table : Vec<Piece>,
    /// The seekable file reader.
    reader : Option<BufReader<File>>,
}

impl PieceFile {
    // #################################
    // P R I V A T E  F U N C T I O N S
    // #################################
    /// Get a Piece at a particular offset.
    fn get_at_offset(&self, offset : u32) -> Option<usize> {
        let mut logical_length = 0;

        // This has to be O(N) for the time being unless we want
        // to update all logical offsets when the table changes.
        // On modern hardware this will hardly be a bottleneck,
        // but we'll see.
        for index in 0..self.piece_table.len() {
            let piece = &self.piece_table[index];
            logical_length += piece.length;

            if offset > logical_length {
                continue;
            }

            return Some(index);
        }

        None
    }

    // ###############################
    // P U B L I C  F U N C T I O N S
    // ###############################
    /// Open a new PieceFile. If the file doesn't exist, it is created.
    pub fn open(path : String) -> io::Result<PieceFile> {
        let file = OpenOptions::new()
            .read(true)
            .open(path.clone()).unwrap();

        // Get the length of the file to initialize the first Piece
        let size = file.metadata().unwrap().len() as u32;

        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : size,
            path,
            piece_table : Vec::new(),
            reader      : Some(BufReader::new(file)),
        };

        piece_file.piece_table.push(Piece {
            file : SourceFile::Original,
            file_offset : 0,
            length : size as u32,
            logical_offset : 0,
        });

        Ok(piece_file)
    }

    /// Create a new empty PieceFile.
    pub fn empty() -> io::Result<PieceFile> {
        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : 0,
            path        : String::from(""),
            piece_table : Vec::new(),
            reader      : None,
        };

        piece_file.piece_table.push(Piece {
            file : SourceFile::Append,
            file_offset : 0,
            length : 0,
            logical_offset : 0,
        });

        Ok(piece_file)
    }

    /// Insert some text.
    pub fn insert(&mut self, text : &str, offset : u32) {
        let length = text.len() as u32;
        let append_offset = self.append_file.len() as u32;

        self.append_file += text;
        self.length      += length;

        let mut piece = Piece {
            file   : SourceFile::Append,
            file_offset : append_offset,
            logical_offset : 0, // Unknown right now
            length,
        };

        let action = Action {
            op     : Operation::Insert,
            pieces : Vec::new(),
            offset,
            length,
        };

        self.actions.push(action);

        // There are edge cases if you do an insert
        // at the beginning or end of the file.
        if offset == 0 {
            self.piece_table.insert(0, piece);
            return;
        }
        else if offset + length == self.length {
            piece.logical_offset = self.length - length;
            self.piece_table.push(piece);
            return;
        }

        // The insertion may create as many as three pieces. It can
        // split a piece that already exists into two parts and then
        // goes in between them.
        let split_index = match self.get_at_offset(offset) {
            Some(v) => v,
            None => return // TODO: Handle this better
        };
        let split_piece = self.piece_table.remove(split_index);

        let lower_size  = offset - split_piece.logical_offset;
        let upper_size  = (split_piece.logical_offset + split_piece.length) - offset;

        if upper_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset + lower_size,
                length         : upper_size,
                logical_offset : split_piece.logical_offset + lower_size + length,
            });
        }

        self.piece_table.insert(split_index, piece);

        if lower_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset,
                length         : lower_size,
                logical_offset : split_piece.logical_offset,
            });
        }
    }

    /// Delete some text.
    pub fn delete(&mut self, offset : u32, length : u32) {
        let start_offset = offset;
        let end_offset   = offset + length;
        let start_index  = self.get_at_offset(start_offset).unwrap();
        let end_index    = self.get_at_offset(end_offset).unwrap();
        let delete_size  = end_index - start_index;
        let num_pieces   = (end_index - start_index) + 1;

        let mut action = Action {
            length,
            offset,
            op     : Operation::Delete,
            pieces : Vec::new()
        };

        // Deletes can affect multiple pieces if the user wants to delete
        // across piece boundaries. We have to start at the bottom index
        // and move up.
        for index in start_index..end_index {
            let mut piece          = &self.piece_table[index];
            let piece_start_offset = piece.logical_offset;
            let piece_end_offset   = piece.logical_offset + piece.length;

            // Edge case : delete is embedded WITHIN a single piece
            if start_offset > piece_start_offset && end_offset < piece_end_offset {
                self.piece_table.remove(index);
                let upper_size = piece_end_offset - end_offset;
                let lower_size = start_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + (start_offset - piece.logical_offset),
                    length         : delete_size,
                    logical_offset : start_offset,
                });

                // We insert the upper part first
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size + delete_size,
                    length         : upper_size,
                    logical_offset : start_offset,
                });
                // Then the lower part
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset,
                    length         : lower_size,
                    logical_offset : piece.logical_offset,
                });

                return
            }
        }
    }
}

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

    #[test]
    fn it_inserts() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 1);

        file.insert("foo", 0);
        file.insert("bar", 0);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);

        let first_element  = &piece_table[0];
        let second_element = &piece_table[1];

        assert_eq!(first_element.file_offset, 3);
        assert_eq!(first_element.length, 3);

        assert_eq!(second_element.file_offset, 0);
        assert_eq!(second_element.length, 3);

        let action = &file.actions[0];
        assert_eq!(action.op, Operation::Insert);

        // TODO: when read() is implemented check that this says "barfoo"
    }
}
<|endoftext|>


<commit_before>extern crate time;

use memory::Memory;
use memory_bus::*;
use cpu::Cpu;
use ppu::Ppu;
use rom::read_rom;

use std::rc::Rc;
use std::cell::RefCell;

#[derive(Debug)]
pub struct Console{
    cpu: Cpu,
    memory: Rc<RefCell<Box<Memory>>>,
    ppu: Rc<RefCell<Ppu>>,
}

impl Console {
    pub fn new (rom_path: &str) -> Console {
        let rom = Box::new(read_rom(rom_path));
        let tv_system = rom.header.tv_system.clone();
        let ppu = Rc::new(RefCell::new(Ppu::new(&tv_system)));

        let mem = Rc::new(RefCell::new(Box::new(MemoryBus::new(rom, ppu.clone())) as Box<Memory>));
        Console {
            memory: mem.clone(),
            cpu: Cpu::new(&tv_system, mem.clone()),
            ppu: ppu.clone(),
        }
    }

    pub fn execute(&mut self) {
        let cpu_cycle_time_in_nanoseconds = (1.0/(self.cpu.frequency.cpu_clock_frequency/1000.0)) as u64;
        println!("CPU frequency: {}", self.cpu.frequency.cpu_clock_frequency);
        println!("Cycle time in nanoseconds: {}", cpu_cycle_time_in_nanoseconds);

        // execute cpu_cycles_per_tick cycles every cpu_cycles_per_tick * tick_time nanoseconds.
        // the 6502 frequency is around ~2 MHZ whics means that a cycle needs to be
        // executed every ~500ns. This however is not really possible even with high precision
        // timers. At least on my computer, best precision I got from timer was 700ns which means
        // there would be ~40% error. Thus, instead of executing one cpu cycle every ~500ns
        // it is better to execute n cycles every n*500ns as this reduces timer errors.

        let cpu_cycles_per_tick = 10;
        // PAL PPU executes exactly 3.2 cycles for each CPU cycle (vs exactly 3 cycles NTSC).
        // this means we need extra cycle every now an then when emulating PAL to maintaing timing
        //let mut ppu_fractional_cycles = 0.0;
        self.cpu.reset();

        println!("\nPC: {}\n", self.cpu.program_counter);

        let mut time = time::precise_time_ns();
        loop {
            let current_time = time::precise_time_ns();
            let time_taken = current_time - time;

            if time_taken > cpu_cycle_time_in_nanoseconds * cpu_cycles_per_tick {
                for _ in 0..cpu_cycles_per_tick {
                    self.run_emulation_tick();
                }
                time = current_time;
            }

        }
    }

    fn run_emulation_tick(&mut self) {
        // ensure instruction timing
        if self.cpu.wait_counter > 0 {
            self.cpu.wait_counter -= 1;
        } else {

            // check for nmi from ppu
            if self.ppu.borrow_mut().nmi_occured() {
                self.cpu.handle_nmi();
                return;
            } else {
                self.cpu.execute_instruction();
            }
        }
        // emulate PPU cycles. Executes 3 cycles (NTSC) or average 3.2 cycles (PAL) per cpu cycle.
        // PAL executes 3 cycles with an additional cycle every few cpu cycles to remain in sync
        self.ppu.borrow_mut().execute_cycles();
    }

}
<commit_msg>Fixed a bug where ppu was borrowed for too long and writes to ppu registers caused a runtime panic<commit_after>extern crate time;

use memory::Memory;
use memory_bus::*;
use cpu::Cpu;
use ppu::Ppu;
use rom::read_rom;

use std::rc::Rc;
use std::cell::RefCell;

#[derive(Debug)]
pub struct Console{
    cpu: Cpu,
    memory: Rc<RefCell<Box<Memory>>>,
    ppu: Rc<RefCell<Ppu>>,
}

impl Console {
    pub fn new (rom_path: &str) -> Console {
        let rom = Box::new(read_rom(rom_path));
        let tv_system = rom.header.tv_system.clone();
        let ppu = Rc::new(RefCell::new(Ppu::new(&tv_system)));

        let mem = Rc::new(RefCell::new(Box::new(MemoryBus::new(rom, ppu.clone())) as Box<Memory>));
        Console {
            memory: mem.clone(),
            cpu: Cpu::new(&tv_system, mem.clone()),
            ppu: ppu.clone(),
        }
    }

    pub fn execute(&mut self) {
        let cpu_cycle_time_in_nanoseconds = (1.0/(self.cpu.frequency.cpu_clock_frequency/1000.0)) as u64;
        println!("CPU frequency: {}", self.cpu.frequency.cpu_clock_frequency);
        println!("Cycle time in nanoseconds: {}", cpu_cycle_time_in_nanoseconds);

        // execute cpu_cycles_per_tick cycles every cpu_cycles_per_tick * tick_time nanoseconds.
        // the 6502 frequency is around ~2 MHZ whics means that a cycle needs to be
        // executed every ~500ns. This however is not really possible even with high precision
        // timers. At least on my computer, best precision I got from timer was 700ns which means
        // there would be ~40% error. Thus, instead of executing one cpu cycle every ~500ns
        // it is better to execute n cycles every n*500ns as this reduces timer errors.

        let cpu_cycles_per_tick = 10;
        // PAL PPU executes exactly 3.2 cycles for each CPU cycle (vs exactly 3 cycles NTSC).
        // this means we need extra cycle every now an then when emulating PAL to maintaing timing
        //let mut ppu_fractional_cycles = 0.0;
        self.cpu.reset();

        let mut time = time::precise_time_ns();
        loop {
            let current_time = time::precise_time_ns();
            let time_taken = current_time - time;

            if time_taken > cpu_cycle_time_in_nanoseconds * cpu_cycles_per_tick {
                for _ in 0..cpu_cycles_per_tick {
                    self.run_emulation_tick();
                }
                time = current_time;
            }

        }
    }

    fn run_emulation_tick(&mut self) {
        // ensure instruction timing
        if self.cpu.wait_counter > 0 {
            self.cpu.wait_counter -= 1;
        } else {
            // check for nmi from ppu
            let nmi_occured = self.ppu.borrow_mut().nmi_occured();
            if nmi_occured {
                self.cpu.handle_nmi();
                return;
            } else {
                self.cpu.execute_instruction();
            }
        }
        // emulate PPU cycles. Executes 3 cycles (NTSC) or average 3.2 cycles (PAL) per cpu cycle.
        // PAL executes 3 cycles with an additional cycle every few cpu cycles to remain in sync
        self.ppu.borrow_mut().execute_cycles();
    }

}
<|endoftext|>


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

use std::collections::BTreeMap;
use std::cmp::Ordering;
use std::f64;
use std::hash::{Hash, Hasher};
use core::HitboxId;
use util::{TightSet, n64, N64, OneOrTwo};

#[derive(Copy, Clone)]
pub struct EventKey {
    time: N64,
    index: u64
}

impl EventKey {
    fn time(&self) -> f64 {
        self.time.into()
    }
}

impl PartialEq for EventKey {
    fn eq(&self, rhs: &EventKey) -> bool {
        self.index == rhs.index
    }
}

impl Eq for EventKey { }

impl Hash for EventKey {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.index.hash(state)
    }
}

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

impl Ord for EventKey {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.time == other.time {
            self.index.cmp(&other.index)
        } else {
            self.time.cmp(&other.time)
        }
    }
}

pub trait EventKeysMap {
    fn event_keys_mut(&mut self, id: HitboxId) -> &mut TightSet<EventKey>;
}

#[derive(Copy, Clone)]
pub enum InternalEvent {
    PanicSmallHitbox(HitboxId),
    PanicDurationPassed(HitboxId),
    Reiterate(HitboxId),
    Collide(HitboxId, HitboxId),
    Separate(HitboxId, HitboxId)
}

impl InternalEvent {
    fn other_id(self, id: HitboxId) -> Option<HitboxId> {
        self.involved_hitbox_ids().other_id(id)
    }

    fn involved_hitbox_ids(self) -> OneOrTwo<HitboxId> {
        match self {
            InternalEvent::PanicSmallHitbox(id) | InternalEvent::PanicDurationPassed(id)
                | InternalEvent::Reiterate(id) => OneOrTwo::One(id),
            InternalEvent::Collide(a, b) | InternalEvent::Separate(a, b) => OneOrTwo::Two(a, b)
        }
    }
}

pub struct EventManager {
    events: BTreeMap<EventKey, InternalEvent>,
    next_event_index: u64
}

impl EventManager {
    pub fn new() -> EventManager {
        EventManager { events : BTreeMap::new(), next_event_index : 0 }
    }

    pub fn add_solitaire_event(&mut self, time: f64, event: InternalEvent, key_set: &mut TightSet<EventKey>) {
        if let Some(key) = self.new_event_key(time) {
            assert!(self.events.insert(key, event).is_none(), "illegal state");
            assert!(key_set.insert(key), "illegal state");
        }
    }

    pub fn add_pair_event(&mut self, time: f64, event: InternalEvent, first_key_set: &mut TightSet<EventKey>,
        second_key_set: &mut TightSet<EventKey>)
    {
        if let Some(key) = self.new_event_key(time) {
            assert!(self.events.insert(key, event).is_none(), "illegal state");
            assert!(first_key_set.insert(key), "illegal state");
            assert!(second_key_set.insert(key), "illegal state");
        }
    }

    pub fn clear_related_events<M: EventKeysMap>(&mut self, id: HitboxId, key_set: &mut TightSet<EventKey>, map: &mut M) {
        for key in key_set.iter() {
            let event = self.events.remove(key).unwrap();
            if let Some(other_id) = event.other_id(id) {
                assert!(map.event_keys_mut(other_id).remove(key), "illegal state");
            }
        }
        key_set.clear();
    }

    fn new_event_key(&mut self, time: f64) -> Option<EventKey> {
        if time == f64::INFINITY {
            None
        } else {
            let result = EventKey { time: n64(time), index: self.next_event_index };
            self.next_event_index += 1;
            Some(result)
        }
    }

    pub fn peek_time(&self) -> f64 {
        self.peek_key().map(|key| key.time()).unwrap_or(f64::INFINITY)
    }

    pub fn next<M: EventKeysMap>(&mut self, time: f64, map: &mut M) -> Option<InternalEvent> {
        if let Some(key) = self.peek_key() {
            if key.time() == time {
                let event = self.events.remove(&key).unwrap();
                for id in event.involved_hitbox_ids().iter() {
                    assert!(map.event_keys_mut(id).remove(&key), "illegal state");
                }
                Some(event)
            } else {
                None
            }
        } else {
            None
        }
    }

    fn peek_key(&self) -> Option<EventKey> {
        self.events.keys().next().map(|&key| key)
    }
}
<commit_msg>made panic events higher priority<commit_after>// Copyright 2016 Matthew D. Michelotti
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::BTreeMap;
use std::cmp::Ordering;
use std::f64;
use std::hash::{Hash, Hasher};
use core::HitboxId;
use util::{TightSet, n64, N64, OneOrTwo};

const PAIR_BASE: u64 = 0x8000_0000_0000_0000;

#[derive(Copy, Clone)]
pub struct EventKey {
    time: N64,
    index: u64
}

impl EventKey {
    fn time(&self) -> f64 {
        self.time.into()
    }
}

impl PartialEq for EventKey {
    fn eq(&self, rhs: &EventKey) -> bool {
        self.index == rhs.index
    }
}

impl Eq for EventKey { }

impl Hash for EventKey {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.index.hash(state)
    }
}

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

impl Ord for EventKey {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.time == other.time {
            self.index.cmp(&other.index)
        } else {
            self.time.cmp(&other.time)
        }
    }
}

pub trait EventKeysMap {
    fn event_keys_mut(&mut self, id: HitboxId) -> &mut TightSet<EventKey>;
}

#[derive(Copy, Clone)]
pub enum InternalEvent {
    PanicSmallHitbox(HitboxId),
    PanicDurationPassed(HitboxId),
    Reiterate(HitboxId),
    Collide(HitboxId, HitboxId),
    Separate(HitboxId, HitboxId)
}

impl InternalEvent {
    fn other_id(self, id: HitboxId) -> Option<HitboxId> {
        self.involved_hitbox_ids().other_id(id)
    }

    fn involved_hitbox_ids(self) -> OneOrTwo<HitboxId> {
        match self {
            InternalEvent::PanicSmallHitbox(id) | InternalEvent::PanicDurationPassed(id)
                | InternalEvent::Reiterate(id) => OneOrTwo::One(id),
            InternalEvent::Collide(a, b) | InternalEvent::Separate(a, b) => OneOrTwo::Two(a, b)
        }
    }
}

pub struct EventManager {
    events: BTreeMap<EventKey, InternalEvent>,
    next_event_index: u64
}

impl EventManager {
    pub fn new() -> EventManager {
        EventManager { events : BTreeMap::new(), next_event_index : 0 }
    }

    pub fn add_solitaire_event(&mut self, time: f64, event: InternalEvent, key_set: &mut TightSet<EventKey>) {
        if let Some(key) = self.new_event_key(time, false) {
            assert!(self.events.insert(key, event).is_none(), "illegal state");
            assert!(key_set.insert(key), "illegal state");
        }
    }

    pub fn add_pair_event(&mut self, time: f64, event: InternalEvent, first_key_set: &mut TightSet<EventKey>,
        second_key_set: &mut TightSet<EventKey>)
    {
        if let Some(key) = self.new_event_key(time, true) {
            assert!(self.events.insert(key, event).is_none(), "illegal state");
            assert!(first_key_set.insert(key), "illegal state");
            assert!(second_key_set.insert(key), "illegal state");
        }
    }

    pub fn clear_related_events<M: EventKeysMap>(&mut self, id: HitboxId, key_set: &mut TightSet<EventKey>, map: &mut M) {
        for key in key_set.iter() {
            let event = self.events.remove(key).unwrap();
            if let Some(other_id) = event.other_id(id) {
                assert!(map.event_keys_mut(other_id).remove(key), "illegal state");
            }
        }
        key_set.clear();
    }

    fn new_event_key(&mut self, time: f64, for_pair: bool) -> Option<EventKey> {
        if time == f64::INFINITY {
            None
        } else {
            let mut index = self.next_event_index;
            self.next_event_index += 1;
            assert!(index < PAIR_BASE, "illegal state");
            if for_pair { index += PAIR_BASE; }
            let result = EventKey { time: n64(time), index: index };
            Some(result)
        }
    }

    pub fn peek_time(&self) -> f64 {
        self.peek_key().map(|key| key.time()).unwrap_or(f64::INFINITY)
    }

    pub fn next<M: EventKeysMap>(&mut self, time: f64, map: &mut M) -> Option<InternalEvent> {
        if let Some(key) = self.peek_key() {
            if key.time() == time {
                let event = self.events.remove(&key).unwrap();
                for id in event.involved_hitbox_ids().iter() {
                    assert!(map.event_keys_mut(id).remove(&key), "illegal state");
                }
                Some(event)
            } else {
                None
            }
        } else {
            None
        }
    }

    fn peek_key(&self) -> Option<EventKey> {
        self.events.keys().next().map(|&key| key)
    }
}
<|endoftext|>


<commit_before>//! Extensions to the parsing API with niche applicability.

use super::*;

/// Extensions to the `ParseStream` API to support speculative parsing.
pub trait Speculative {
    /// Advance this parse stream to the position of a forked parse stream.
    ///
    /// This is the opposite operation to [`ParseStream::fork`].
    /// You can fork a parse stream, perform some speculative parsing, then join
    /// the original stream to the fork to "commit" the parsing from the fork to
    /// the main stream.
    ///
    /// If you can avoid doing this, you should, as it limits the ability to
    /// generate useful errors. That said, it is often the only way to parse
    /// syntax of the form `A* B*` for arbitrary syntax `A` and `B`. The problem
    /// is that when the fork fails to parse an `A`, it's impossible to tell
    /// whether that was because of a syntax error and the user meant to provide
    /// an `A`, or that the `A`s are finished and its time to start parsing `B`s.
    /// Use with care.
    ///
    /// Also note that if `A` is a subset of `B`, `A* B*` can be parsed by parsing
    /// `B*` and removing the leading members of `A` from the repetition, bypassing
    /// the need to involve the downsides associated with speculative parsing.
    ///
    /// [`ParseStream::fork`]: ../struct.ParseBuffer.html#method.fork
    ///
    /// # Example
    ///
    /// There has been chatter about the possibility of making the colons in the
    /// turbofish syntax like `path::to::<T>` no longer required by accepting
    /// `path::to<T>` in expression position. Specifically, according to [RFC#2544],
    /// [`PathSegment`] parsing should always try to consume a following `<` token
    /// as the start of generic arguments, and reset to the `<` if that fails
    /// (e.g. the token is acting as a less-than operator).
    ///
    /// This is the exact kind of parsing behavior which requires the "fork, try,
    /// commit" behavior that [`ParseStream::fork`] discourages. With `advance_to`,
    /// we can avoid having to parse the speculatively parsed content a second time.
    ///
    /// This change in behavior can be implemented in syn by replacing just the
    /// `Parse` implementation for `PathSegment`:
    ///
    /// ```edition2018
    /// # use syn::ext::IdentExt;
    /// use syn::parse::discouraged::Speculative;
    /// # use syn::parse::{Parse, ParseStream};
    /// # use syn::{Ident, PathArguments, Result, Token};
    ///
    /// pub struct PathSegment {
    ///     pub ident: Ident,
    ///     pub arguments: PathArguments,
    /// }
    ///
    /// # impl<T> From<T> for PathSegment
    /// # where
    /// #     T: Into<Ident>,
    /// # {
    /// #     fn from(ident: T) -> Self {
    /// #         PathSegment {
    /// #             ident: ident.into(),
    /// #             arguments: PathArguments::None,
    /// #         }
    /// #     }
    /// # }
    ///
    ///
    /// impl Parse for PathSegment {
    ///     fn parse(input: ParseStream) -> Result<Self> {
    ///         if input.peek(Token![super])
    ///             || input.peek(Token![self])
    ///             || input.peek(Token![Self])
    ///             || input.peek(Token![crate])
    ///             || input.peek(Token![extern])
    ///         {
    ///             let ident = input.call(Ident::parse_any)?;
    ///             return Ok(PathSegment::from(ident));
    ///         }
    ///
    ///         let ident = input.parse()?;
    ///         if input.peek(Token![::]) && input.peek3(Token![<]) {
    ///             return Ok(PathSegment {
    ///                 ident: ident,
    ///                 arguments: PathArguments::AngleBracketed(input.parse()?),
    ///             });
    ///         }
    ///         if input.peek(Token![<]) && !input.peek(Token![<=]) {
    ///             let fork = input.fork();
    ///             if let Ok(arguments) = fork.parse() {
    ///                 input.advance_to(&fork);
    ///                 return Ok(PathSegment {
    ///                     ident: ident,
    ///                     arguments: PathArguments::AngleBracketed(arguments),
    ///                 });
    ///             }
    ///         }
    ///         Ok(PathSegment::from(ident))
    ///     }
    /// }
    ///
    /// # syn::parse_str::<PathSegment>("a<b,c>").unwrap();
    /// ```
    ///
    /// [RFC#2544]: https://github.com/rust-lang/rfcs/pull/2544
    /// [`PathSegment`]: ../../struct.PathSegment.html
    ///
    /// # Panics
    ///
    /// The forked stream that this joins with must be derived by forking this parse stream.
    fn advance_to(&self, fork: &Self);
}

impl<'a> Speculative for ParseBuffer<'a> {
    fn advance_to(&self, fork: &Self) {
        // See comment on `scope` in the struct definition.
        assert_eq!(
            // Rc::ptr_eq for rustc < 1.17.0
            &*self.scope as *const _, &*fork.scope as *const _,
            "Fork was not derived from the advancing parse stream"
        );
        // See comment on `cell` in the struct definition.
        self.cell.set(unsafe { mem::transmute::<Cursor, Cursor<'static>>(fork.cursor()) })
    }
}
<commit_msg>Add drawbacks section to advance_to doc<commit_after>//! Extensions to the parsing API with niche applicability.

use super::*;

/// Extensions to the `ParseStream` API to support speculative parsing.
pub trait Speculative {
    /// Advance this parse stream to the position of a forked parse stream.
    ///
    /// This is the opposite operation to [`ParseStream::fork`].
    /// You can fork a parse stream, perform some speculative parsing, then join
    /// the original stream to the fork to "commit" the parsing from the fork to
    /// the main stream.
    ///
    /// If you can avoid doing this, you should, as it limits the ability to
    /// generate useful errors. That said, it is often the only way to parse
    /// syntax of the form `A* B*` for arbitrary syntax `A` and `B`. The problem
    /// is that when the fork fails to parse an `A`, it's impossible to tell
    /// whether that was because of a syntax error and the user meant to provide
    /// an `A`, or that the `A`s are finished and its time to start parsing `B`s.
    /// Use with care.
    ///
    /// Also note that if `A` is a subset of `B`, `A* B*` can be parsed by parsing
    /// `B*` and removing the leading members of `A` from the repetition, bypassing
    /// the need to involve the downsides associated with speculative parsing.
    ///
    /// [`ParseStream::fork`]: ../struct.ParseBuffer.html#method.fork
    ///
    /// # Example
    ///
    /// There has been chatter about the possibility of making the colons in the
    /// turbofish syntax like `path::to::<T>` no longer required by accepting
    /// `path::to<T>` in expression position. Specifically, according to [RFC#2544],
    /// [`PathSegment`] parsing should always try to consume a following `<` token
    /// as the start of generic arguments, and reset to the `<` if that fails
    /// (e.g. the token is acting as a less-than operator).
    ///
    /// This is the exact kind of parsing behavior which requires the "fork, try,
    /// commit" behavior that [`ParseStream::fork`] discourages. With `advance_to`,
    /// we can avoid having to parse the speculatively parsed content a second time.
    ///
    /// This change in behavior can be implemented in syn by replacing just the
    /// `Parse` implementation for `PathSegment`:
    ///
    /// ```edition2018
    /// # use syn::ext::IdentExt;
    /// use syn::parse::discouraged::Speculative;
    /// # use syn::parse::{Parse, ParseStream};
    /// # use syn::{Ident, PathArguments, Result, Token};
    ///
    /// pub struct PathSegment {
    ///     pub ident: Ident,
    ///     pub arguments: PathArguments,
    /// }
    ///
    /// # impl<T> From<T> for PathSegment
    /// # where
    /// #     T: Into<Ident>,
    /// # {
    /// #     fn from(ident: T) -> Self {
    /// #         PathSegment {
    /// #             ident: ident.into(),
    /// #             arguments: PathArguments::None,
    /// #         }
    /// #     }
    /// # }
    ///
    ///
    /// impl Parse for PathSegment {
    ///     fn parse(input: ParseStream) -> Result<Self> {
    ///         if input.peek(Token![super])
    ///             || input.peek(Token![self])
    ///             || input.peek(Token![Self])
    ///             || input.peek(Token![crate])
    ///             || input.peek(Token![extern])
    ///         {
    ///             let ident = input.call(Ident::parse_any)?;
    ///             return Ok(PathSegment::from(ident));
    ///         }
    ///
    ///         let ident = input.parse()?;
    ///         if input.peek(Token![::]) && input.peek3(Token![<]) {
    ///             return Ok(PathSegment {
    ///                 ident: ident,
    ///                 arguments: PathArguments::AngleBracketed(input.parse()?),
    ///             });
    ///         }
    ///         if input.peek(Token![<]) && !input.peek(Token![<=]) {
    ///             let fork = input.fork();
    ///             if let Ok(arguments) = fork.parse() {
    ///                 input.advance_to(&fork);
    ///                 return Ok(PathSegment {
    ///                     ident: ident,
    ///                     arguments: PathArguments::AngleBracketed(arguments),
    ///                 });
    ///             }
    ///         }
    ///         Ok(PathSegment::from(ident))
    ///     }
    /// }
    ///
    /// # syn::parse_str::<PathSegment>("a<b,c>").unwrap();
    /// ```
    ///
    /// # Drawbacks
    ///
    /// The main drawback of this style of speculative parsing is in error
    /// presentation. Even if the lookahead is the "correct" parse, the error
    /// that is shown is that of the "fallback" parse. To use the same example
    /// as the turbofish above, take the following unfinished "turbofish":
    ///
    /// ```text
    /// let _ = f<&'a fn(), for<'a> serde::>();
    /// ```
    ///
    /// If this is parsed as generic arguments, we can provide the error message
    ///
    /// ```text
    /// error: expected identifier
    ///  --> src.rs:L:C
    ///   |
    /// L | let _ = f<&'a fn(), for<'a> serde::>();
    ///   |                                    ^
    /// ```
    ///
    /// but if parsed using the above speculative parsing, it falls back to
    /// assuming that the `<` is a less-than when it fails to parse the
    /// generic arguments, and tries to interpret the `&'a` as the start of a
    /// labelled loop, resulting in the much less helpful error
    ///
    /// ```text
    /// error: expected `:`
    ///  --> src.rs:L:C
    ///   |
    /// L | let _ = f<&'a fn(), for<'a> serde::>();
    ///   |               ^^
    /// ```
    ///
    /// This can be mitigated with various heuristics (two examples: show both
    /// forks' parse errors, or show the one that consumed more tokens), but
    /// when you can control the grammar, sticking to something that can be
    /// parsed LL(3) and without the LL(*) speculative parsing this makes
    /// possible, displaying reasonable errors becomes much more simple.
    ///
    /// [RFC#2544]: https://github.com/rust-lang/rfcs/pull/2544
    /// [`PathSegment`]: ../../struct.PathSegment.html
    ///
    /// # Panics
    ///
    /// The forked stream that this joins with must be derived by forking this parse stream.
    fn advance_to(&self, fork: &Self);
}

impl<'a> Speculative for ParseBuffer<'a> {
    fn advance_to(&self, fork: &Self) {
        // See comment on `scope` in the struct definition.
        assert_eq!(
            // Rc::ptr_eq for rustc < 1.17.0
            &*self.scope as *const _, &*fork.scope as *const _,
            "Fork was not derived from the advancing parse stream"
        );
        // See comment on `cell` in the struct definition.
        self.cell.set(unsafe { mem::transmute::<Cursor, Cursor<'static>>(fork.cursor()) })
    }
}
<|endoftext|>


<commit_before>pub use BackoffTimer;
use std::time::Duration;
use std::thread;

/// ```
/// use backoff_timer::*;
///
/// let mut timer = ExponentialBackoffTimer::new(5);
/// let mut waited = timer.wait();
/// assert_eq!(waited, 2);
/// assert_eq!(timer.is_done(), false);
/// waited = timer.wait();
/// assert_eq!(waited, 4);
/// assert_eq!(timer.is_done(), true);
/// ```
pub struct ExponentialBackoffTimer {
    waited_time:   u64,
    wait_time:     u64,
    max_wait_time: u64,
}

impl BackoffTimer for ExponentialBackoffTimer {

    /// new returns a new ExponentialBackoffTimer configured with the passed in max_wait_time in seconds
    fn new(max_wait_time: u64) -> ExponentialBackoffTimer {
        ExponentialBackoffTimer {
            max_wait_time: max_wait_time,
            wait_time: 2,
            waited_time: 0,
        }
    }

    /// wait is a blocking function that waits for the appropriate amount of time depending on the
    /// timers internal state. It returns the time waited which is 0 if the timer has reached its
    /// max_wait_time
    fn wait(&mut self) -> u64 {
        if self.is_done() {
            return 0;
        }
        thread::sleep(Duration::from_secs(self.wait_time));
        let time_waited = self.wait_time;
        self.wait_time = self.wait_time.pow(2);
        self.waited_time = self.waited_time + self.wait_time;

        return time_waited;
    }

    /// is_done is a helper method to determine whether the timer is done or still has turns to
    /// wait.
    fn is_done(&self) -> bool {
        self.waited_time >= self.max_wait_time
    }

}

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

    #[test]
    fn wait_for_5_seconds() {
        let mut timer = ExponentialBackoffTimer::new(5);
        let mut waited = timer.wait();
        assert_eq!(waited, 2);
        assert_eq!(timer.is_done(), false);
        waited = timer.wait();
        assert_eq!(waited, 4);
        assert_eq!(timer.is_done(), true);
    }
}
<commit_msg>make sure ExponentialBackoffTimer waits for at most max_wait_time<commit_after>pub use BackoffTimer;
use std::time::Duration;
use std::thread;

/// ```
/// use backoff_timer::*;
///
/// let mut timer = ExponentialBackoffTimer::new(6);
/// let mut waited = timer.wait();
/// assert_eq!(waited, 2);
/// assert_eq!(timer.is_done(), false);
/// waited = timer.wait();
/// assert_eq!(waited, 4);
/// assert_eq!(timer.is_done(), true);
/// ```
pub struct ExponentialBackoffTimer {
    waited_time:   u64,
    wait_time:     u64,
    max_wait_time: u64,
}

impl BackoffTimer for ExponentialBackoffTimer {

    /// new returns a new ExponentialBackoffTimer configured with the passed in max_wait_time in seconds
    fn new(max_wait_time: u64) -> ExponentialBackoffTimer {
        ExponentialBackoffTimer {
            max_wait_time: max_wait_time,
            wait_time: 2,
            waited_time: 0,
        }
    }

    /// wait is a blocking function that waits for the appropriate amount of time depending on the
    /// timers internal state. It returns the time waited which is 0 if the timer has reached its
    /// max_wait_time
    fn wait(&mut self) -> u64 {
        if self.is_done() {
            return 0;
        }
        thread::sleep(Duration::from_secs(self.wait_time));
        let time_waited = self.wait_time;
        self.waited_time = self.waited_time + self.wait_time;
        self.wait_time = self.wait_time.pow(2);

        return time_waited;
    }

    /// is_done is a helper method to determine whether the timer is done or still has turns to
    /// wait.
    fn is_done(&self) -> bool {
        (self.waited_time + self.wait_time) > self.max_wait_time
    }

}

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

    #[test]
    fn wait_for_6_seconds() {
        let mut timer = ExponentialBackoffTimer::new(6);
        let mut waited = timer.wait();
        assert_eq!(waited, 2);
        assert_eq!(timer.is_done(), false);
        waited = timer.wait();
        assert_eq!(waited, 4);
        assert_eq!(timer.is_done(), true);
    }

    #[test]
    fn cant_wait_twice_for_five() {
        let mut timer = ExponentialBackoffTimer::new(5);
        let mut waited = timer.wait();
        assert_eq!(waited, 2);
        assert_eq!(timer.is_done(), true);
        waited = timer.wait();
        assert_eq!(waited, 0);
        assert_eq!(timer.is_done(), true);
    }
}
<|endoftext|>