<commit_before>//! A flat representation of memory provided by lifters, typically used in a
//! read-only fashion
//!
//! This memory model implements the `TranslationMemory` trait, allowing lifters
//! to use it to lift instructions.

use architecture::Endian;
use error::*;
use executor;
use il;
use memory::MemoryPermissions;
use std::collections::Bound::Included;
use std::collections::BTreeMap;
use translator::TranslationMemory;

/// A section of backed memory. Essentially a vector of type `u8` with
/// permissions.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Section {
    data: Vec<u8>,
    permissions: MemoryPermissions,
}

impl Section {
    /// Create a new memory section.
    pub fn new(data: Vec<u8>, permissions: MemoryPermissions) -> Section {
        Section {
            data: data,
            permissions: permissions,
        }
    }

    /// Get this memory section's data.
    pub fn data(&self) -> &[u8] {
        &self.data
    }

    /// Get the length of this memory section.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Get the permissions of this memory section.
    pub fn permissions(&self) -> MemoryPermissions {
        self.permissions.clone()
    }

    /// Truncate the data of this memory section.
    fn truncate(&mut self, size: usize) {
        self.data.truncate(size);
    }
}

/// A simple memory model, containing permissioned sections of type `u8`.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Memory {
    endian: Endian,
    sections: BTreeMap<u64, Section>
}

impl Memory {
    /// Create a new backed memory module with the given endianness.
    pub fn new(endian: Endian) -> Memory {
        Memory {
            endian: endian,
            sections: BTreeMap::new()
        }
    }

    /// Get the sections in this memory module.
    pub fn sections(&self) -> &BTreeMap<u64, Section> {
        &self.sections
    }

    /// Get the permissions at the given address.
    pub fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        match self.section_address(address) {
            Some(section_address) =>
                Some(self.sections
                        .get(&section_address)
                        .expect(&format!(
                            "Failed to get section at 0x{:x} in \
                             backing::Memory::permissions()",
                            section_address))
                        .permissions()),
            None => None
        }
    }

    /// Get the `u8` value at the given address.
    pub fn get8(&self, address: u64) -> Option<u8> {
        match self.section_address_offset(address) {
            Some((address, offset)) =>
                Some(*self.sections
                        .get(&address)
                        .expect(&format!(
                            "Failed to get section at 0x{:x} in \
                             backing::Memory::permissions()",
                            address))
                        .data()
                        .get(offset)
                        .expect(&format!(
                            "Failed to get offset 0x{:x} from 0x{:x} in \
                             backing::Memory::permissions()",
                            offset, address))),
            None => None
        }
    }

    /// Set the 32-bit value at the given address, allowing the memory model
    /// to account for the underlying endianness.
    pub fn set32(&mut self, address: u64, value: u32) -> Result<()> {
        let (section_address, offset) =
            self.section_address_offset(address)
                .expect(&format!("Address 0x{:x} has no section", address));

        let section = self.sections.get_mut(&section_address).unwrap();

        if offset + 4 > section.len() {
            bail!(format!("Section at 0x{:x} is of size {}, and not big \
                           enough to hold 32-bit value",
                           section_address,
                           section.len()));
        }

        match self.endian {
            Endian::Big => {
                *section.data.get_mut(offset    ).unwrap() = (value >> 24) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 8 ) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value      ) as u8;
            },
            Endian::Little => {
                *section.data.get_mut(offset    ).unwrap() = (value      ) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 8 ) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value >> 24) as u8;
            }
        }

        Ok(())
    }

    /// Get the 32-bit value at the given address, allowing the memory model to
    /// account for the underlying endianness.
    pub fn get32(&self, address: u64) -> Option<u32> {
        let (section_address, offset) = match self.section_address_offset(address) {
            Some((section_address, offset)) => (section_address, offset),
            None => return None
        };

        let section = self.sections.get(&section_address).unwrap();

        if offset + 4 > section.len() {
            return None;
        }

        Some(match self.endian {
            Endian::Big => {
                (section.data[offset    ] as u32) << 24 |
                (section.data[offset + 1] as u32) << 16 |
                (section.data[offset + 2] as u32) <<  8 |
                (section.data[offset + 3] as u32)
            },
            Endian::Little => {
                (section.data[offset    ] as u32)       |
                (section.data[offset + 1] as u32) <<  8 |
                (section.data[offset + 2] as u32) << 16 |
                (section.data[offset + 3] as u32) << 24
            }
        })
    }

    /// Get a constant value up to a certain number of bits
    pub fn get(&self, address: u64, bits: usize) -> Option<il::Constant> {
        if bits % 8 > 0 || bits == 0 {
            return None;
        }

        let mut value = il::expr_const(self.get8(address)? as u64, 8);

        match self.endian {
            Endian::Big => {
                for i in 1..(bits / 8) {
                    let expr_bits = (i + 1) * 8;
                    value = il::Expression::or(
                        il::Expression::shl(
                            il::Expression::zext(expr_bits, value).unwrap(),
                            il::expr_const(8, expr_bits)).unwrap(),

                        il::expr_const(self.get8(address + i as u64).unwrap() as u64, expr_bits)
                    ).unwrap();
                }
                Some(executor::eval(&value).unwrap())
            },
            Endian::Little => {
                for i in 1..(bits / 8) {
                    let expr_bits = value.bits() + 8;
                    value = il::Expression::or(
                        il::Expression::shl(
                            il::expr_const(self.get8(address + i as u64).unwrap() as u64, expr_bits),
                            il::expr_const((i * 8) as u64, expr_bits)).unwrap(),
                        il::Expression::zext(expr_bits,
                            il::Expression::zext(expr_bits, value).unwrap()
                        ).unwrap()).unwrap();
                }
                Some(executor::eval(&value).unwrap())
            }
        }
    }

    /// Set the memory at the given address, and give that memory the given
    /// permissions.
    ///
    /// This takes care of the underlying memory sections automatically.
    pub fn set_memory(
        &mut self,
        address: u64,
        data: Vec<u8>,
        permissions: MemoryPermissions
    ) {
        // All overlapping memory sections need to be adjusted
        // Start by collecting addresses and lengths
        let als = self.sections
                      .iter()
                      .map(|(address, section)| (*address, section.len()))
                      .collect::<Vec<(u64, usize)>>();

        // Adjust overlapping memory sections
        for al in als {
            let (a, l) = (al.0, al.1 as u64);
            if a < address && a + l > address {
                if a + l <= address + data.len() as u64 {
                    let new_length = (address - a) as usize;
                    self.sections
                        .get_mut(&a)
                        .expect(&format!(
                            "Failed to get section 0x{:x} in \
                            backing::Memory::set_memory(). This should never \
                            happen.", a))
                        .truncate(new_length);
                }
                else {
                    let offset = address + data.len() as u64 - a;
                    let split =
                        self.sections
                            .get_mut(&a)
                            .expect(&format!(
                                "Failed to get section 0x{:x} in \
                                backing::Memory::set_memory(). This should \
                                never happen.", a))
                            .data
                            .split_off(offset as usize);
                    let permissions =
                        self.sections
                            .get(&a)
                            .expect(&format!(
                                "Failed to get section 0x{:x} in \
                                 backing::Memory::set_memory(). This should \
                                 never happen.", a))
                            .permissions();
                    self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions)
                    );

                    let new_length = (address - a) as usize;
                    self.sections.get_mut(&a).unwrap().truncate(new_length);
                }
            }
            else if a >= address && a + l <= address + data.len() as u64 {
                if self.sections.get(&a).is_none() {
                    panic!("About to remove 0x{:x} from sections in \
                            backing::Memory::set_memory, but address does not
                            exist");
                }
                self.sections.remove(&a);
            }
            else if a >= address &&
                    a < address + data.len() as u64 &&
                    a + l > address + data.len() as u64 {
                let offset = address + data.len() as u64 - a;
                let data_len = self.sections
                                .get(&a)
                                .unwrap()
                                .data
                                .len() as u64;
                if offset > data_len {
                    panic!("offset 0x{:x} is > data.len() 0x{:x}", offset, data_len);
                }
                let split = self.sections
                                .get_mut(&a)
                                .unwrap()
                                .data
                                .split_off(offset as usize);
                let permissions =
                    self.sections
                        .get(&a)
                        .expect(&format!(
                            "Failed to get section for 0x{:x} while updating \
                             permissions in backing::Memory::set_memory(). \
                             This should never happen.", a))
                        .permissions();
                self.sections.remove(&a);
                self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions)
                );
            }
        }

        self.sections.insert(address, Section::new(data, permissions));
    }

    fn section_address(&self, address: u64) -> Option<u64> {
        let mut sections = self.sections.range((Included(0), Included(address)));
        if let Some((section_address, section)) = sections.next_back() {
            if    *section_address <= address
               && *section_address + section.len() as u64 > address {
                return Some(*section_address);
            }
        }
        None
    }

    fn section_address_offset(&self, address: u64) -> Option<(u64, usize)> {
        match self.section_address(address) {
            Some(section_address) =>
                Some((section_address, (address - section_address) as usize)),
            None => None
        }
    }
}

impl TranslationMemory for Memory {
    fn get_u8(&self, address: u64) -> Option<u8> {
        self.get8(address)
    }

    fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        self.permissions(address)
    }
}<commit_msg>fix backing::Memory::get()<commit_after>//! A flat representation of memory provided by lifters, typically used in a
//! read-only fashion
//!
//! This memory model implements the `TranslationMemory` trait, allowing lifters
//! to use it to lift instructions.

use architecture::Endian;
use error::*;
use executor;
use il;
use memory::MemoryPermissions;
use std::collections::Bound::Included;
use std::collections::BTreeMap;
use translator::TranslationMemory;

/// A section of backed memory. Essentially a vector of type `u8` with
/// permissions.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Section {
    data: Vec<u8>,
    permissions: MemoryPermissions,
}

impl Section {
    /// Create a new memory section.
    pub fn new(data: Vec<u8>, permissions: MemoryPermissions) -> Section {
        Section {
            data: data,
            permissions: permissions,
        }
    }

    /// Get this memory section's data.
    pub fn data(&self) -> &[u8] {
        &self.data
    }

    /// Get the length of this memory section.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Get the permissions of this memory section.
    pub fn permissions(&self) -> MemoryPermissions {
        self.permissions.clone()
    }

    /// Truncate the data of this memory section.
    fn truncate(&mut self, size: usize) {
        self.data.truncate(size);
    }
}

/// A simple memory model, containing permissioned sections of type `u8`.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Memory {
    endian: Endian,
    sections: BTreeMap<u64, Section>
}

impl Memory {
    /// Create a new backed memory module with the given endianness.
    pub fn new(endian: Endian) -> Memory {
        Memory {
            endian: endian,
            sections: BTreeMap::new()
        }
    }

    /// Get the sections in this memory module.
    pub fn sections(&self) -> &BTreeMap<u64, Section> {
        &self.sections
    }

    /// Get the permissions at the given address.
    pub fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        match self.section_address(address) {
            Some(section_address) =>
                Some(self.sections
                        .get(&section_address)
                        .expect(&format!(
                            "Failed to get section at 0x{:x} in \
                             backing::Memory::permissions()",
                            section_address))
                        .permissions()),
            None => None
        }
    }

    /// Get the `u8` value at the given address.
    pub fn get8(&self, address: u64) -> Option<u8> {
        match self.section_address_offset(address) {
            Some((address, offset)) =>
                Some(*self.sections
                        .get(&address)
                        .expect(&format!(
                            "Failed to get section at 0x{:x} in \
                             backing::Memory::permissions()",
                            address))
                        .data()
                        .get(offset)
                        .expect(&format!(
                            "Failed to get offset 0x{:x} from 0x{:x} in \
                             backing::Memory::permissions()",
                            offset, address))),
            None => None
        }
    }

    /// Set the 32-bit value at the given address, allowing the memory model
    /// to account for the underlying endianness.
    pub fn set32(&mut self, address: u64, value: u32) -> Result<()> {
        let (section_address, offset) =
            self.section_address_offset(address)
                .expect(&format!("Address 0x{:x} has no section", address));

        let section = self.sections.get_mut(&section_address).unwrap();

        if offset + 4 > section.len() {
            bail!(format!("Section at 0x{:x} is of size {}, and not big \
                           enough to hold 32-bit value",
                           section_address,
                           section.len()));
        }

        match self.endian {
            Endian::Big => {
                *section.data.get_mut(offset    ).unwrap() = (value >> 24) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 8 ) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value      ) as u8;
            },
            Endian::Little => {
                *section.data.get_mut(offset    ).unwrap() = (value      ) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 8 ) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value >> 24) as u8;
            }
        }

        Ok(())
    }

    /// Get the 32-bit value at the given address, allowing the memory model to
    /// account for the underlying endianness.
    pub fn get32(&self, address: u64) -> Option<u32> {
        let (section_address, offset) = match self.section_address_offset(address) {
            Some((section_address, offset)) => (section_address, offset),
            None => return None
        };

        let section = self.sections.get(&section_address).unwrap();

        if offset + 4 > section.len() {
            return None;
        }

        Some(match self.endian {
            Endian::Big => {
                (section.data[offset    ] as u32) << 24 |
                (section.data[offset + 1] as u32) << 16 |
                (section.data[offset + 2] as u32) <<  8 |
                (section.data[offset + 3] as u32)
            },
            Endian::Little => {
                (section.data[offset    ] as u32)       |
                (section.data[offset + 1] as u32) <<  8 |
                (section.data[offset + 2] as u32) << 16 |
                (section.data[offset + 3] as u32) << 24
            }
        })
    }

    /// Get a constant value up to a certain number of bits
    pub fn get(&self, address: u64, bits: usize) -> Option<il::Constant> {
        if bits % 8 > 0 || bits == 0 {
            return None;
        }

        let mut value = il::expr_const(self.get8(address)? as u64, bits);

        match self.endian {
            Endian::Big => {
                for i in 1..(bits / 8) {
                    value = il::Expression::or(
                        il::Expression::shl(
                            value,
                            il::expr_const(8, bits)
                        ).unwrap(),
                        il::expr_const(self.get8(address + i as u64).unwrap() as u64, bits)
                    ).unwrap();
                }
                Some(executor::eval(&value).unwrap())
            },
            Endian::Little => {
                for i in 1..(bits / 8) {
                    value = il::Expression::or(
                        il::Expression::shl(
                            il::expr_const(self.get8(address + i as u64).unwrap() as u64, bits),
                            il::expr_const((i * 8) as u64, bits)
                        ).unwrap(),
                        value
                    ).unwrap();
                }
                Some(executor::eval(&value).unwrap())
            }
        }
    }

    /// Set the memory at the given address, and give that memory the given
    /// permissions.
    ///
    /// This takes care of the underlying memory sections automatically.
    pub fn set_memory(
        &mut self,
        address: u64,
        data: Vec<u8>,
        permissions: MemoryPermissions
    ) {
        // All overlapping memory sections need to be adjusted
        // Start by collecting addresses and lengths
        let als = self.sections
                      .iter()
                      .map(|(address, section)| (*address, section.len()))
                      .collect::<Vec<(u64, usize)>>();

        // Adjust overlapping memory sections
        for al in als {
            let (a, l) = (al.0, al.1 as u64);
            if a < address && a + l > address {
                if a + l <= address + data.len() as u64 {
                    let new_length = (address - a) as usize;
                    self.sections
                        .get_mut(&a)
                        .expect(&format!(
                            "Failed to get section 0x{:x} in \
                            backing::Memory::set_memory(). This should never \
                            happen.", a))
                        .truncate(new_length);
                }
                else {
                    let offset = address + data.len() as u64 - a;
                    let split =
                        self.sections
                            .get_mut(&a)
                            .expect(&format!(
                                "Failed to get section 0x{:x} in \
                                backing::Memory::set_memory(). This should \
                                never happen.", a))
                            .data
                            .split_off(offset as usize);
                    let permissions =
                        self.sections
                            .get(&a)
                            .expect(&format!(
                                "Failed to get section 0x{:x} in \
                                 backing::Memory::set_memory(). This should \
                                 never happen.", a))
                            .permissions();
                    self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions)
                    );

                    let new_length = (address - a) as usize;
                    self.sections.get_mut(&a).unwrap().truncate(new_length);
                }
            }
            else if a >= address && a + l <= address + data.len() as u64 {
                if self.sections.get(&a).is_none() {
                    panic!("About to remove 0x{:x} from sections in \
                            backing::Memory::set_memory, but address does not
                            exist");
                }
                self.sections.remove(&a);
            }
            else if a >= address &&
                    a < address + data.len() as u64 &&
                    a + l > address + data.len() as u64 {
                let offset = address + data.len() as u64 - a;
                let data_len = self.sections
                                .get(&a)
                                .unwrap()
                                .data
                                .len() as u64;
                if offset > data_len {
                    panic!("offset 0x{:x} is > data.len() 0x{:x}", offset, data_len);
                }
                let split = self.sections
                                .get_mut(&a)
                                .unwrap()
                                .data
                                .split_off(offset as usize);
                let permissions =
                    self.sections
                        .get(&a)
                        .expect(&format!(
                            "Failed to get section for 0x{:x} while updating \
                             permissions in backing::Memory::set_memory(). \
                             This should never happen.", a))
                        .permissions();
                self.sections.remove(&a);
                self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions)
                );
            }
        }

        self.sections.insert(address, Section::new(data, permissions));
    }

    fn section_address(&self, address: u64) -> Option<u64> {
        let mut sections = self.sections.range((Included(0), Included(address)));
        if let Some((section_address, section)) = sections.next_back() {
            if    *section_address <= address
               && *section_address + section.len() as u64 > address {
                return Some(*section_address);
            }
        }
        None
    }

    fn section_address_offset(&self, address: u64) -> Option<(u64, usize)> {
        match self.section_address(address) {
            Some(section_address) =>
                Some((section_address, (address - section_address) as usize)),
            None => None
        }
    }
}

impl TranslationMemory for Memory {
    fn get_u8(&self, address: u64) -> Option<u8> {
        self.get8(address)
    }

    fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        self.permissions(address)
    }
}<|endoftext|>


<commit_before>//! Game loop.

// External crates.
use std::mem::replace;
use sync::{Mutex, Arc};

// Local crate.
use GameWindow;
use RenderWindow;

use GameIteratorSettings;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use MouseScroll;
use MouseScrollArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait ConcurrentGame<R>: Copy + Send {
    /// Render graphics.
    fn render(&self, _resources: &mut R, _args: &RenderArgs) {}

    /// Update the physical state of the game.
    fn update(&mut self, _args: &UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Scrolled mouse.
    fn mouse_scroll(&mut self, _args: &MouseScrollArgs) {}

    /// Executes a game loop.
    fn run<W: GameWindow + Send, RW: RenderWindow> (
        mut self,
        game_window: W,
        render_window: RW,
        game_iter_settings: GameIteratorSettings,
        mut render_resources: R
    ) {

        // Setup.

        self.load();
        let mutex_self1 = Arc::new( Mutex::new( self ) );
        let mutex_self2 = mutex_self1.clone();
        let (tx, rx) = channel();

        // Game_loop thread.

        spawn(proc() {
            let mut buf2 = self;
            let mut game_window = game_window;

            let mut game_iter = GameIterator::new(
                &mut game_window,
                &game_iter_settings
             );

            loop {
                match game_iter.next() {
                    None => break,
                    Some(e) => match e {
                        Render(args) => {
                            let mut mutex_guard = mutex_self2.lock();
                            {
                                let render_buf = mutex_guard.deref_mut();
                                replace( render_buf, buf2 );
                            }
                            mutex_guard.cond.signal();
                            tx.send(Some(args));
                        },
                        Update(ref args) => buf2.update(args),
                        KeyPress(ref args) => buf2.key_press(args),
                        KeyRelease(ref args) => buf2.key_release(args),
                        MousePress(ref args) => buf2.mouse_press(args),
                        MouseRelease(ref args) => buf2.mouse_release(args),
                        MouseMove(ref args) => buf2.mouse_move(args),
                        MouseRelativeMove(ref args) => buf2.mouse_relative_move(args),
                        MouseScroll(ref args) => buf2.mouse_scroll(args),
                    }
                }
            }
            tx.send(None);
        });

        // Rendering thread.

        loop {
            let mut args: RenderArgs = match rx.recv() {
                Some( args ) => args,
                None => break,
            };

            let mut mutex_guard = mutex_self1.lock();
            {
                let render_buf = mutex_guard.deref_mut();
                render_buf.render( &mut render_resources, &mut args);
                render_window.swap_buffers();
            }
            mutex_guard.cond.signal();
        }
    }
}
<commit_msg>Move windows into tuple<commit_after>//! Game loop.

// External crates.
use std::mem::replace;
use sync::{Mutex, Arc};

// Local crate.
use GameWindow;
use RenderWindow;

use GameIteratorSettings;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use MouseScroll;
use MouseScrollArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait ConcurrentGame<R>: Copy + Send {
    /// Render graphics.
    fn render(&self, _resources: &mut R, _args: &RenderArgs) {}

    /// Update the physical state of the game.
    fn update(&mut self, _args: &UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Scrolled mouse.
    fn mouse_scroll(&mut self, _args: &MouseScrollArgs) {}

    /// Executes a game loop.
    fn run<W: GameWindow + Send, RW: RenderWindow> (
        mut self,
        windows: (W, RW),
        game_iter_settings: GameIteratorSettings,
        mut render_resources: R
    ) {
        let (game_window, render_window) = windows;

        // Setup.

        self.load();
        let mutex_self1 = Arc::new( Mutex::new( self ) );
        let mutex_self2 = mutex_self1.clone();
        let (tx, rx) = channel();

        // Game_loop thread.

        spawn(proc() {
            let mut buf2 = self;
            let mut game_window = game_window;

            let mut game_iter = GameIterator::new(
                &mut game_window,
                &game_iter_settings
             );

            loop {
                match game_iter.next() {
                    None => break,
                    Some(e) => match e {
                        Render(args) => {
                            let mut mutex_guard = mutex_self2.lock();
                            {
                                let render_buf = mutex_guard.deref_mut();
                                replace( render_buf, buf2 );
                            }
                            mutex_guard.cond.signal();
                            tx.send(Some(args));
                        },
                        Update(ref args) => buf2.update(args),
                        KeyPress(ref args) => buf2.key_press(args),
                        KeyRelease(ref args) => buf2.key_release(args),
                        MousePress(ref args) => buf2.mouse_press(args),
                        MouseRelease(ref args) => buf2.mouse_release(args),
                        MouseMove(ref args) => buf2.mouse_move(args),
                        MouseRelativeMove(ref args) => buf2.mouse_relative_move(args),
                        MouseScroll(ref args) => buf2.mouse_scroll(args),
                    }
                }
            }
            tx.send(None);
        });

        // Rendering thread.

        loop {
            let mut args: RenderArgs = match rx.recv() {
                Some( args ) => args,
                None => break,
            };

            let mut mutex_guard = mutex_self1.lock();
            {
                let render_buf = mutex_guard.deref_mut();
                render_buf.render( &mut render_resources, &mut args);
                render_window.swap_buffers();
            }
            mutex_guard.cond.signal();
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 The Grin Developers
//
// 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.

//! Provides a connection wrapper that handles the lower level tasks in sending
//! or receiving data from the TCP socket, as well as dealing with timeouts.
//!
//! Because of a few idiosyncracies in the Rust `TcpStream`, this has to use
//! async I/O to be able to both read *and* write on the connection. Which
//! forces us to go through some additional gymnastic to loop over the async
//! stream and make sure we get the right number of bytes out.

use crate::core::ser;
use crate::core::ser::{FixedLength, ProtocolVersion};
use crate::msg::{
	read_body, read_discard, read_header, read_item, write_message, Msg, MsgHeader,
	MsgHeaderWrapper,
};
use crate::types::Error;
use crate::util::{RateCounter, RwLock};
use std::io::{self, Read, Write};
use std::net::{Shutdown, TcpStream};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::time::Duration;
use std::{
	cmp,
	thread::{self, JoinHandle},
};

const IO_TIMEOUT: Duration = Duration::from_millis(1000);

/// A trait to be implemented in order to receive messages from the
/// connection. Allows providing an optional response.
pub trait MessageHandler: Send + 'static {
	fn consume<'a>(&self, msg: Message<'a>, tracker: Arc<Tracker>) -> Result<Option<Msg>, Error>;
}

// Macro to simplify the boilerplate around async I/O error handling,
// especially with WouldBlock kind of errors.
macro_rules! try_break {
	($inner:expr) => {
		match $inner {
			Ok(v) => Some(v),
			Err(Error::Connection(ref e)) if e.kind() == io::ErrorKind::TimedOut => None,
			Err(Error::Connection(ref e)) if e.kind() == io::ErrorKind::WouldBlock => {
				// to avoid the heavy polling which will consume CPU 100%
				thread::sleep(Duration::from_millis(10));
				None
				}
			Err(Error::Store(_))
			| Err(Error::Chain(_))
			| Err(Error::Internal)
			| Err(Error::NoDandelionRelay) => None,
			Err(ref e) => {
				debug!("try_break: exit the loop: {:?}", e);
				break;
				}
			}
	};
}

/// A message as received by the connection. Provides access to the message
/// header lazily consumes the message body, handling its deserialization.
pub struct Message<'a> {
	pub header: MsgHeader,
	stream: &'a mut dyn Read,
	version: ProtocolVersion,
}

impl<'a> Message<'a> {
	fn from_header(
		header: MsgHeader,
		stream: &'a mut dyn Read,
		version: ProtocolVersion,
	) -> Message<'a> {
		Message {
			header,
			stream,
			version,
		}
	}

	/// Read the message body from the underlying connection
	pub fn body<T: ser::Readable>(&mut self) -> Result<T, Error> {
		read_body(&self.header, self.stream, self.version)
	}

	/// Read a single "thing" from the underlying connection.
	/// Return the thing and the total bytes read.
	pub fn streaming_read<T: ser::Readable>(&mut self) -> Result<(T, u64), Error> {
		read_item(self.stream, self.version)
	}

	pub fn copy_attachment(&mut self, len: usize, writer: &mut dyn Write) -> Result<usize, Error> {
		let mut written = 0;
		while written < len {
			let read_len = cmp::min(8000, len - written);
			let mut buf = vec![0u8; read_len];
			self.stream.read_exact(&mut buf[..])?;
			writer.write_all(&mut buf)?;
			written += read_len;
		}
		Ok(written)
	}
}

pub const SEND_CHANNEL_CAP: usize = 100;

pub struct StopHandle {
	/// Channel to close the connection
	stopped: Arc<AtomicBool>,
	// we need Option to take ownhership of the handle in stop()
	reader_thread: Option<JoinHandle<()>>,
	writer_thread: Option<JoinHandle<()>>,
}

impl StopHandle {
	/// Schedule this connection to safely close via the async close_channel.
	pub fn stop(&self) {
		self.stopped.store(true, Ordering::Relaxed);
	}

	pub fn wait(&mut self) {
		if let Some(reader_thread) = self.reader_thread.take() {
			self.join_thread(reader_thread);
		}
		if let Some(writer_thread) = self.writer_thread.take() {
			self.join_thread(writer_thread);
		}
	}

	fn join_thread(&self, peer_thread: JoinHandle<()>) {
		// wait only if other thread is calling us, eg shutdown
		if thread::current().id() != peer_thread.thread().id() {
			debug!("waiting for thread {:?} exit", peer_thread.thread().id());
			if let Err(e) = peer_thread.join() {
				error!("failed to stop peer thread: {:?}", e);
			}
		} else {
			debug!(
				"attempt to stop thread {:?} from itself",
				peer_thread.thread().id()
			);
		}
	}
}

#[derive(Clone)]
pub struct ConnHandle {
	/// Channel to allow sending data through the connection
	pub send_channel: mpsc::SyncSender<Msg>,
}

impl ConnHandle {
	pub fn send(&self, msg: Msg) -> Result<(), Error> {
		self.send_channel.try_send(msg)?;
		Ok(())
	}
}

pub struct Tracker {
	/// Bytes we've sent.
	pub sent_bytes: Arc<RwLock<RateCounter>>,
	/// Bytes we've received.
	pub received_bytes: Arc<RwLock<RateCounter>>,
}

impl Tracker {
	pub fn new() -> Tracker {
		let received_bytes = Arc::new(RwLock::new(RateCounter::new()));
		let sent_bytes = Arc::new(RwLock::new(RateCounter::new()));
		Tracker {
			received_bytes,
			sent_bytes,
		}
	}

	pub fn inc_received(&self, size: u64) {
		self.received_bytes.write().inc(size);
	}

	pub fn inc_sent(&self, size: u64) {
		self.sent_bytes.write().inc(size);
	}

	pub fn inc_quiet_received(&self, size: u64) {
		self.received_bytes.write().inc_quiet(size);
	}

	pub fn inc_quiet_sent(&self, size: u64) {
		self.sent_bytes.write().inc_quiet(size);
	}
}

/// Start listening on the provided connection and wraps it. Does not hang
/// the current thread, instead just returns a future and the Connection
/// itself.
pub fn listen<H>(
	stream: TcpStream,
	version: ProtocolVersion,
	tracker: Arc<Tracker>,
	handler: H,
) -> io::Result<(ConnHandle, StopHandle)>
where
	H: MessageHandler,
{
	let (send_tx, send_rx) = mpsc::sync_channel(SEND_CHANNEL_CAP);

	stream
		.set_read_timeout(Some(IO_TIMEOUT))
		.expect("can't set read timeout");
	stream
		.set_write_timeout(Some(IO_TIMEOUT))
		.expect("can't set read timeout");

	let stopped = Arc::new(AtomicBool::new(false));

	let conn_handle = ConnHandle {
		send_channel: send_tx,
	};

	let (reader_thread, writer_thread) = poll(
		stream,
		conn_handle.clone(),
		version,
		handler,
		send_rx,
		stopped.clone(),
		tracker,
	)?;

	Ok((
		conn_handle,
		StopHandle {
			stopped,
			reader_thread: Some(reader_thread),
			writer_thread: Some(writer_thread),
		},
	))
}

fn poll<H>(
	conn: TcpStream,
	conn_handle: ConnHandle,
	version: ProtocolVersion,
	handler: H,
	send_rx: mpsc::Receiver<Msg>,
	stopped: Arc<AtomicBool>,
	tracker: Arc<Tracker>,
) -> io::Result<(JoinHandle<()>, JoinHandle<()>)>
where
	H: MessageHandler,
{
	// Split out tcp stream out into separate reader/writer halves.
	let mut reader = conn.try_clone().expect("clone conn for reader failed");
	let mut writer = conn.try_clone().expect("clone conn for writer failed");
	let reader_stopped = stopped.clone();

	let reader_tracker = tracker.clone();
	let writer_tracker = tracker.clone();

	let reader_thread = thread::Builder::new()
		.name("peer_read".to_string())
		.spawn(move || {
			loop {
				// check the read end
				match try_break!(read_header(&mut reader, version)) {
					Some(MsgHeaderWrapper::Known(header)) => {
						let msg = Message::from_header(header, &mut reader, version);

						trace!(
							"Received message header, type {:?}, len {}.",
							msg.header.msg_type,
							msg.header.msg_len
						);

						// Increase received bytes counter
						reader_tracker.inc_received(MsgHeader::LEN as u64 + msg.header.msg_len);

						let resp_msg = try_break!(handler.consume(msg, reader_tracker.clone()));
						if let Some(Some(resp_msg)) = resp_msg {
							try_break!(conn_handle.send(resp_msg));
						}
					}
					Some(MsgHeaderWrapper::Unknown(msg_len)) => {
						// Increase received bytes counter
						reader_tracker.inc_received(MsgHeader::LEN as u64 + msg_len);

						try_break!(read_discard(msg_len, &mut reader));
					}
					None => {}
				}

				// check the close channel
				if reader_stopped.load(Ordering::Relaxed) {
					break;
				}
			}

			debug!(
				"Shutting down reader connection with {}",
				reader
					.peer_addr()
					.map(|a| a.to_string())
					.unwrap_or("?".to_owned())
			);
			let _ = reader.shutdown(Shutdown::Both);
		})?;

	let writer_thread = thread::Builder::new()
		.name("peer_write".to_string())
		.spawn(move || {
			let mut retry_send = Err(());
			loop {
				let maybe_data = retry_send.or_else(|_| send_rx.recv_timeout(IO_TIMEOUT));
				retry_send = Err(());
				if let Ok(data) = maybe_data {
					let written =
						try_break!(write_message(&mut writer, &data, writer_tracker.clone()));
					if written.is_none() {
						retry_send = Ok(data);
					}
				}
				// check the close channel
				if stopped.load(Ordering::Relaxed) {
					break;
				}
			}

			debug!(
				"Shutting down writer connection with {}",
				writer
					.peer_addr()
					.map(|a| a.to_string())
					.unwrap_or("?".to_owned())
			);
		})?;
	Ok((reader_thread, writer_thread))
}
<commit_msg>Increase IO_TIMEOUT to allow nodes on high-latency connections to sync (#3109)<commit_after>// Copyright 2019 The Grin Developers
//
// 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.

//! Provides a connection wrapper that handles the lower level tasks in sending
//! or receiving data from the TCP socket, as well as dealing with timeouts.
//!
//! Because of a few idiosyncracies in the Rust `TcpStream`, this has to use
//! async I/O to be able to both read *and* write on the connection. Which
//! forces us to go through some additional gymnastic to loop over the async
//! stream and make sure we get the right number of bytes out.

use crate::core::ser;
use crate::core::ser::{FixedLength, ProtocolVersion};
use crate::msg::{
	read_body, read_discard, read_header, read_item, write_message, Msg, MsgHeader,
	MsgHeaderWrapper,
};
use crate::types::Error;
use crate::util::{RateCounter, RwLock};
use std::io::{self, Read, Write};
use std::net::{Shutdown, TcpStream};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::time::Duration;
use std::{
	cmp,
	thread::{self, JoinHandle},
};

const IO_TIMEOUT: Duration = Duration::from_millis(10000);

/// A trait to be implemented in order to receive messages from the
/// connection. Allows providing an optional response.
pub trait MessageHandler: Send + 'static {
	fn consume<'a>(&self, msg: Message<'a>, tracker: Arc<Tracker>) -> Result<Option<Msg>, Error>;
}

// Macro to simplify the boilerplate around async I/O error handling,
// especially with WouldBlock kind of errors.
macro_rules! try_break {
	($inner:expr) => {
		match $inner {
			Ok(v) => Some(v),
			Err(Error::Connection(ref e)) if e.kind() == io::ErrorKind::TimedOut => None,
			Err(Error::Connection(ref e)) if e.kind() == io::ErrorKind::WouldBlock => {
				// to avoid the heavy polling which will consume CPU 100%
				thread::sleep(Duration::from_millis(10));
				None
				}
			Err(Error::Store(_))
			| Err(Error::Chain(_))
			| Err(Error::Internal)
			| Err(Error::NoDandelionRelay) => None,
			Err(ref e) => {
				debug!("try_break: exit the loop: {:?}", e);
				break;
				}
			}
	};
}

/// A message as received by the connection. Provides access to the message
/// header lazily consumes the message body, handling its deserialization.
pub struct Message<'a> {
	pub header: MsgHeader,
	stream: &'a mut dyn Read,
	version: ProtocolVersion,
}

impl<'a> Message<'a> {
	fn from_header(
		header: MsgHeader,
		stream: &'a mut dyn Read,
		version: ProtocolVersion,
	) -> Message<'a> {
		Message {
			header,
			stream,
			version,
		}
	}

	/// Read the message body from the underlying connection
	pub fn body<T: ser::Readable>(&mut self) -> Result<T, Error> {
		read_body(&self.header, self.stream, self.version)
	}

	/// Read a single "thing" from the underlying connection.
	/// Return the thing and the total bytes read.
	pub fn streaming_read<T: ser::Readable>(&mut self) -> Result<(T, u64), Error> {
		read_item(self.stream, self.version)
	}

	pub fn copy_attachment(&mut self, len: usize, writer: &mut dyn Write) -> Result<usize, Error> {
		let mut written = 0;
		while written < len {
			let read_len = cmp::min(8000, len - written);
			let mut buf = vec![0u8; read_len];
			self.stream.read_exact(&mut buf[..])?;
			writer.write_all(&mut buf)?;
			written += read_len;
		}
		Ok(written)
	}
}

pub const SEND_CHANNEL_CAP: usize = 100;

pub struct StopHandle {
	/// Channel to close the connection
	stopped: Arc<AtomicBool>,
	// we need Option to take ownhership of the handle in stop()
	reader_thread: Option<JoinHandle<()>>,
	writer_thread: Option<JoinHandle<()>>,
}

impl StopHandle {
	/// Schedule this connection to safely close via the async close_channel.
	pub fn stop(&self) {
		self.stopped.store(true, Ordering::Relaxed);
	}

	pub fn wait(&mut self) {
		if let Some(reader_thread) = self.reader_thread.take() {
			self.join_thread(reader_thread);
		}
		if let Some(writer_thread) = self.writer_thread.take() {
			self.join_thread(writer_thread);
		}
	}

	fn join_thread(&self, peer_thread: JoinHandle<()>) {
		// wait only if other thread is calling us, eg shutdown
		if thread::current().id() != peer_thread.thread().id() {
			debug!("waiting for thread {:?} exit", peer_thread.thread().id());
			if let Err(e) = peer_thread.join() {
				error!("failed to stop peer thread: {:?}", e);
			}
		} else {
			debug!(
				"attempt to stop thread {:?} from itself",
				peer_thread.thread().id()
			);
		}
	}
}

#[derive(Clone)]
pub struct ConnHandle {
	/// Channel to allow sending data through the connection
	pub send_channel: mpsc::SyncSender<Msg>,
}

impl ConnHandle {
	pub fn send(&self, msg: Msg) -> Result<(), Error> {
		self.send_channel.try_send(msg)?;
		Ok(())
	}
}

pub struct Tracker {
	/// Bytes we've sent.
	pub sent_bytes: Arc<RwLock<RateCounter>>,
	/// Bytes we've received.
	pub received_bytes: Arc<RwLock<RateCounter>>,
}

impl Tracker {
	pub fn new() -> Tracker {
		let received_bytes = Arc::new(RwLock::new(RateCounter::new()));
		let sent_bytes = Arc::new(RwLock::new(RateCounter::new()));
		Tracker {
			received_bytes,
			sent_bytes,
		}
	}

	pub fn inc_received(&self, size: u64) {
		self.received_bytes.write().inc(size);
	}

	pub fn inc_sent(&self, size: u64) {
		self.sent_bytes.write().inc(size);
	}

	pub fn inc_quiet_received(&self, size: u64) {
		self.received_bytes.write().inc_quiet(size);
	}

	pub fn inc_quiet_sent(&self, size: u64) {
		self.sent_bytes.write().inc_quiet(size);
	}
}

/// Start listening on the provided connection and wraps it. Does not hang
/// the current thread, instead just returns a future and the Connection
/// itself.
pub fn listen<H>(
	stream: TcpStream,
	version: ProtocolVersion,
	tracker: Arc<Tracker>,
	handler: H,
) -> io::Result<(ConnHandle, StopHandle)>
where
	H: MessageHandler,
{
	let (send_tx, send_rx) = mpsc::sync_channel(SEND_CHANNEL_CAP);

	stream
		.set_read_timeout(Some(IO_TIMEOUT))
		.expect("can't set read timeout");
	stream
		.set_write_timeout(Some(IO_TIMEOUT))
		.expect("can't set read timeout");

	let stopped = Arc::new(AtomicBool::new(false));

	let conn_handle = ConnHandle {
		send_channel: send_tx,
	};

	let (reader_thread, writer_thread) = poll(
		stream,
		conn_handle.clone(),
		version,
		handler,
		send_rx,
		stopped.clone(),
		tracker,
	)?;

	Ok((
		conn_handle,
		StopHandle {
			stopped,
			reader_thread: Some(reader_thread),
			writer_thread: Some(writer_thread),
		},
	))
}

fn poll<H>(
	conn: TcpStream,
	conn_handle: ConnHandle,
	version: ProtocolVersion,
	handler: H,
	send_rx: mpsc::Receiver<Msg>,
	stopped: Arc<AtomicBool>,
	tracker: Arc<Tracker>,
) -> io::Result<(JoinHandle<()>, JoinHandle<()>)>
where
	H: MessageHandler,
{
	// Split out tcp stream out into separate reader/writer halves.
	let mut reader = conn.try_clone().expect("clone conn for reader failed");
	let mut writer = conn.try_clone().expect("clone conn for writer failed");
	let reader_stopped = stopped.clone();

	let reader_tracker = tracker.clone();
	let writer_tracker = tracker.clone();

	let reader_thread = thread::Builder::new()
		.name("peer_read".to_string())
		.spawn(move || {
			loop {
				// check the read end
				match try_break!(read_header(&mut reader, version)) {
					Some(MsgHeaderWrapper::Known(header)) => {
						let msg = Message::from_header(header, &mut reader, version);

						trace!(
							"Received message header, type {:?}, len {}.",
							msg.header.msg_type,
							msg.header.msg_len
						);

						// Increase received bytes counter
						reader_tracker.inc_received(MsgHeader::LEN as u64 + msg.header.msg_len);

						let resp_msg = try_break!(handler.consume(msg, reader_tracker.clone()));
						if let Some(Some(resp_msg)) = resp_msg {
							try_break!(conn_handle.send(resp_msg));
						}
					}
					Some(MsgHeaderWrapper::Unknown(msg_len)) => {
						// Increase received bytes counter
						reader_tracker.inc_received(MsgHeader::LEN as u64 + msg_len);

						try_break!(read_discard(msg_len, &mut reader));
					}
					None => {}
				}

				// check the close channel
				if reader_stopped.load(Ordering::Relaxed) {
					break;
				}
			}

			debug!(
				"Shutting down reader connection with {}",
				reader
					.peer_addr()
					.map(|a| a.to_string())
					.unwrap_or("?".to_owned())
			);
			let _ = reader.shutdown(Shutdown::Both);
		})?;

	let writer_thread = thread::Builder::new()
		.name("peer_write".to_string())
		.spawn(move || {
			let mut retry_send = Err(());
			loop {
				let maybe_data = retry_send.or_else(|_| send_rx.recv_timeout(IO_TIMEOUT));
				retry_send = Err(());
				if let Ok(data) = maybe_data {
					let written =
						try_break!(write_message(&mut writer, &data, writer_tracker.clone()));
					if written.is_none() {
						retry_send = Ok(data);
					}
				}
				// check the close channel
				if stopped.load(Ordering::Relaxed) {
					break;
				}
			}

			debug!(
				"Shutting down writer connection with {}",
				writer
					.peer_addr()
					.map(|a| a.to_string())
					.unwrap_or("?".to_owned())
			);
		})?;
	Ok((reader_thread, writer_thread))
}
<|endoftext|>


<commit_before>pub mod line;

use core::codepointinfo::CodepointInfo;

use self::line::Line;
use self::line::LineCellIndex;

pub type LineIndex = usize;

// the screen is composed of lines
#[derive(Debug, Clone)]
pub struct Screen {
    pub line: Vec<Line>,
    pub current_line_index: LineCellIndex,
    pub width: usize,
    pub height: usize,
    pub nb_push: usize,
}

impl Screen {
    pub fn new(width: usize, height: usize) -> Screen {
        let mut line: Vec<Line> = Vec::new();
        for _ in 0..height {
            line.push(Line::new(width));
        }

        Screen {
            line: line,
            current_line_index: 0,
            width: width,
            height: height,
            nb_push: 0,
        }
    }

    pub fn resize(&mut self, width: usize, height: usize) {

        self.line.resize(height, Line::new(width));
        for i in 0..height {
            self.line[i].resize(width);
        }
        self.width = width;
        self.height = height;
        self.current_line_index = 0;
        self.nb_push = 0;
    }

    /// append
    pub fn push(&mut self, cpi: CodepointInfo) -> (bool, usize) {

        if self.current_line_index == self.height {
            return (false, self.current_line_index);
        }

        if self.line[self.current_line_index].read_only {
            self.current_line_index += 1;
        }

        if self.current_line_index == self.height {
            return (false, self.current_line_index);
        }

        let cp = cpi.cp;
        let line = &mut self.line[self.current_line_index];
        let (ok, _) = line.push(cpi);

        if ok {
            self.nb_push += 1;
            if cp == '\n' || cp == '\r' {
                line.read_only = true;
            }
        }
        (ok, self.current_line_index)
    }

    pub fn clear(&mut self) {
        for h in 0..self.height {
            self.line[h].clear();
        }
        self.current_line_index = 0;
        self.nb_push = 0;
    }

    pub fn get_mut_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.height {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_line(&self, index: usize) -> Option<&Line> {
        if index < self.height {
            Some(&self.line[index])
        } else {
            None
        }
    }

    pub fn get_mut_used_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.current_line_index {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_used_line_clipped(&mut self, index: usize) -> (Option<&Line>, LineIndex) {
        let index = ::std::cmp::min(index, self.current_line_index);
        (self.get_used_line(index), index)
    }

    pub fn get_used_line(&self, index: usize) -> Option<&Line> {
        if index < self.current_line_index {
            Some(&self.line[index])
        } else {
            None
        }
    }

    /// there must be 2 line a least
    pub fn get_first_used_line(&self) -> Option<&Line> {
        if 0 < self.current_line_index {
            Some(&self.line[0])
        } else {
            None
        }
    }

    /// there must be 2 line a least
    pub fn get_last_used_line(&self) -> Option<&Line> {
        if self.current_line_index > 0 {
            Some(&self.line[self.current_line_index - 1])
        } else {
            None
        }
    }

    pub fn get_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_line(y) {
            None => None,
            Some(l) => l.get_cpi(x),
        }
    }

    pub fn get_mut_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_line(y) {
            None => None,
            Some(l) => l.get_mut_cpi(x),
        }
    }

    pub fn get_used_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_used_line(y) {
            None => None,
            Some(l) => l.get_used_cpi(x),
        }
    }

    pub fn get_mut_used_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_used_line(y) {
            None => None,
            Some(l) => l.get_mut_used_cpi(x),
        }
    }

    pub fn get_mut_first_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        match self.get_mut_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_mut_used_cpi(0), 0, 0),
        }
    }

    pub fn get_mut_last_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        let y = self.current_line_index;
        match self.get_mut_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                let x = l.nb_cells;
                (l.get_mut_used_cpi(0), x, y)
            }
        }
    }

    pub fn get_first_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        match self.get_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_used_cpi(0), 0, 0),
        }
    }

    pub fn get_last_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        let y = self.current_line_index;
        match self.get_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                if l.nb_cells > 0 {
                    let x = l.nb_cells - 1;
                    (l.get_used_cpi(0), x, y)
                } else {
                    (None, 0, 0)
                }
            }
        }
    }

    pub fn get_used_cpinfo_clipped(&mut self,
                                   x: usize,
                                   y: usize)
                                   -> (Option<&CodepointInfo>, LineCellIndex, LineIndex) {

        match self.get_used_line_clipped(y) {
            (None, li) => (None, x, li),
            (Some(l), li) => {
                match l.get_used_cpi_clipped(x) {
                    (optcpi, lci) => (optcpi, lci, li),
                }
            }
        }
    }

    pub fn find_cpi_by_offset(&self, offset: u64) -> (Option<&CodepointInfo>, usize, usize) {
        // TODO: use dichotomic search
        for y in 0..self.height {
            let l = self.get_line(y).unwrap();
            for x in 0..l.width {
                if l.nb_cells == 0 {
                    break;
                }
                let cpi = l.get_cpi(x).unwrap();
                if cpi.offset == offset {
                    return (Some(cpi), x, y);
                }
            }
        }
        (None, 0, 0)
    }

    pub fn contains_offset(&self, offset: u64) -> bool {
        //TODO: cache first/las_ offset as self.members
        let (cpi, _, _) = self.find_cpi_by_offset(offset);
        match cpi {
            Some(_) => true,
            _ => false,
        }
    }
}

#[test]
fn test_screen() {

    let mut scr = Screen::new(640, 480);
    assert_eq!(640, scr.width);
    assert_eq!(480, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].cells.len());

    scr.resize(800, 600);
    assert_eq!(800, scr.width);
    assert_eq!(600, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].cells.len());

    scr.resize(1024, 768);
    assert_eq!(1024, scr.width);
    assert_eq!(768, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].cells.len());

    scr.resize(640, 480);
    assert_eq!(640, scr.width);
    assert_eq!(480, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].cells.len());
}
<commit_msg>find_cpi_by_offset : move test out of loop<commit_after>pub mod line;

use core::codepointinfo::CodepointInfo;

use self::line::Line;
use self::line::LineCellIndex;

pub type LineIndex = usize;

// the screen is composed of lines
#[derive(Debug, Clone)]
pub struct Screen {
    pub line: Vec<Line>,
    pub current_line_index: LineCellIndex,
    pub width: usize,
    pub height: usize,
    pub nb_push: usize,
}

impl Screen {
    pub fn new(width: usize, height: usize) -> Screen {
        let mut line: Vec<Line> = Vec::new();
        for _ in 0..height {
            line.push(Line::new(width));
        }

        Screen {
            line: line,
            current_line_index: 0,
            width: width,
            height: height,
            nb_push: 0,
        }
    }

    pub fn resize(&mut self, width: usize, height: usize) {

        self.line.resize(height, Line::new(width));
        for i in 0..height {
            self.line[i].resize(width);
        }
        self.width = width;
        self.height = height;
        self.current_line_index = 0;
        self.nb_push = 0;
    }

    /// append
    pub fn push(&mut self, cpi: CodepointInfo) -> (bool, usize) {

        if self.current_line_index == self.height {
            return (false, self.current_line_index);
        }

        if self.line[self.current_line_index].read_only {
            self.current_line_index += 1;
        }

        if self.current_line_index == self.height {
            return (false, self.current_line_index);
        }

        let cp = cpi.cp;
        let line = &mut self.line[self.current_line_index];
        let (ok, _) = line.push(cpi);

        if ok {
            self.nb_push += 1;
            if cp == '\n' || cp == '\r' {
                line.read_only = true;
            }
        }
        (ok, self.current_line_index)
    }

    pub fn clear(&mut self) {
        for h in 0..self.height {
            self.line[h].clear();
        }
        self.current_line_index = 0;
        self.nb_push = 0;
    }

    pub fn get_mut_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.height {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_line(&self, index: usize) -> Option<&Line> {
        if index < self.height {
            Some(&self.line[index])
        } else {
            None
        }
    }

    pub fn get_mut_used_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.current_line_index {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_used_line_clipped(&mut self, index: usize) -> (Option<&Line>, LineIndex) {
        let index = ::std::cmp::min(index, self.current_line_index);
        (self.get_used_line(index), index)
    }

    pub fn get_used_line(&self, index: usize) -> Option<&Line> {
        if index < self.current_line_index {
            Some(&self.line[index])
        } else {
            None
        }
    }

    /// there must be 2 line a least
    pub fn get_first_used_line(&self) -> Option<&Line> {
        if 0 < self.current_line_index {
            Some(&self.line[0])
        } else {
            None
        }
    }

    /// there must be 2 line a least
    pub fn get_last_used_line(&self) -> Option<&Line> {
        if self.current_line_index > 0 {
            Some(&self.line[self.current_line_index - 1])
        } else {
            None
        }
    }

    pub fn get_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_line(y) {
            None => None,
            Some(l) => l.get_cpi(x),
        }
    }

    pub fn get_mut_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_line(y) {
            None => None,
            Some(l) => l.get_mut_cpi(x),
        }
    }

    pub fn get_used_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_used_line(y) {
            None => None,
            Some(l) => l.get_used_cpi(x),
        }
    }

    pub fn get_mut_used_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_used_line(y) {
            None => None,
            Some(l) => l.get_mut_used_cpi(x),
        }
    }

    pub fn get_mut_first_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        match self.get_mut_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_mut_used_cpi(0), 0, 0),
        }
    }

    pub fn get_mut_last_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        let y = self.current_line_index;
        match self.get_mut_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                let x = l.nb_cells;
                (l.get_mut_used_cpi(0), x, y)
            }
        }
    }

    pub fn get_first_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        match self.get_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_used_cpi(0), 0, 0),
        }
    }

    pub fn get_last_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        let y = self.current_line_index;
        match self.get_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                if l.nb_cells > 0 {
                    let x = l.nb_cells - 1;
                    (l.get_used_cpi(0), x, y)
                } else {
                    (None, 0, 0)
                }
            }
        }
    }

    pub fn get_used_cpinfo_clipped(&mut self,
                                   x: usize,
                                   y: usize)
                                   -> (Option<&CodepointInfo>, LineCellIndex, LineIndex) {

        match self.get_used_line_clipped(y) {
            (None, li) => (None, x, li),
            (Some(l), li) => {
                match l.get_used_cpi_clipped(x) {
                    (optcpi, lci) => (optcpi, lci, li),
                }
            }
        }
    }

    pub fn find_cpi_by_offset(&self, offset: u64) -> (Option<&CodepointInfo>, usize, usize) {
        // TODO: use dichotomic search
        for y in 0..self.height {
            let l = self.get_line(y).unwrap();
            if l.nb_cells == 0 {
                continue;
            }

            for x in 0..l.width {
                let cpi = l.get_cpi(x).unwrap();
                if cpi.offset == offset {
                    return (Some(cpi), x, y);
                }
            }
        }
        (None, 0, 0)
    }

    pub fn contains_offset(&self, offset: u64) -> bool {
        //TODO: cache first/las_ offset as self.members
        let (cpi, _, _) = self.find_cpi_by_offset(offset);
        match cpi {
            Some(_) => true,
            _ => false,
        }
    }
}

#[test]
fn test_screen() {

    let mut scr = Screen::new(640, 480);
    assert_eq!(640, scr.width);
    assert_eq!(480, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].cells.len());

    scr.resize(800, 600);
    assert_eq!(800, scr.width);
    assert_eq!(600, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].cells.len());

    scr.resize(1024, 768);
    assert_eq!(1024, scr.width);
    assert_eq!(768, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].cells.len());

    scr.resize(640, 480);
    assert_eq!(640, scr.width);
    assert_eq!(480, scr.height);
    assert_eq!(scr.height, scr.line.len());
    assert_eq!(scr.width, scr.line[0].cells.len());
}
<|endoftext|>


<commit_before>use config;
use config::action::message::MessageActionBuilder;
use conditions::ConditionsBuilder;
use Correlator;
use message::MessageBuilder;

use handlebars::Template;
use uuid::Uuid;
use serde_json::from_str;
use std::rc::Rc;
use std::cell::RefCell;
use std::thread;
use std::time::Duration;

use test_utils::correlator::MessageEventHandler;

const JSON_CONFIG: &'static str = r#"
      [
        {
          "name": "CONTEXT_NAME_1",
          "uuid": "185e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 100,
            "patterns": [
              "p1",
              "p2",
              "p3"
            ],
            "first_opens": true
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid1",
                  "when": {
                    "on_opened": "true",
                    "on_closed": "true"
                  },
                  "message": "message_1"
              }
            }
          ]
        },
        {
          "name": "CONTEXT_NAME_2",
          "uuid": "285e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 10000,
            "max_size": 5
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid1",
                  "message": "message_2"
              }
            },
            {
              "message": {
                  "uuid": "uuid2",
                  "message": "message_2"
              }
            }
          ]
        },
        {
          "name": "CONTEXT_NAME_3",
          "uuid": "385e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 100,
            "patterns": [
              "p1"
            ]
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid2",
                  "message": "message_3"
              }
            }
          ]
        }
      ]
    "#;

#[test]
fn test_given_manually_built_correlator_when_it_closes_a_context_then_the_actions_are_executed() {
    let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid3 = "3b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let patterns = vec![
        uuid1.clone(),
        uuid2.clone(),
        uuid3.clone(),
    ];
    let condition = ConditionsBuilder::new(Duration::from_millis(100))
                        .patterns(patterns)
                        .first_opens(true)
                        .last_closes(true)
                        .build();
    let message = Template::compile("message".to_string())
                      .ok()
                      .expect("Failed to compile a handlebars template");
    let contexts = vec![
        config::ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(vec![MessageActionBuilder::new("uuid", message.clone()).build().into()]).build(),
        config::ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(vec![MessageActionBuilder::new("uuid", message.clone()).build().into()]).build(),
        config::ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(vec![MessageActionBuilder::new("uuid", message).build().into()]).build(),
    ];
    let responses = Rc::new(RefCell::new(Vec::new()));
    let message_event_handler = Box::new(MessageEventHandler { responses: responses.clone() });
    let mut correlator = Correlator::new(contexts);
    correlator.register_handler(message_event_handler);
    let _ = correlator.push_message(MessageBuilder::new(&uuid1, "message").build());
    thread::sleep(Duration::from_millis(20));
    let _ = correlator.push_message(MessageBuilder::new(&uuid2, "message").build());
    thread::sleep(Duration::from_millis(80));
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message").build());
    let _ = correlator.stop();
    assert_eq!(3, responses.borrow().len());
}

#[test]
fn test_given_correlator_when_it_is_built_from_json_then_we_get_the_expected_correlator() {
    let result = from_str::<Vec<config::Context>>(JSON_CONFIG);
    let expected_name = "CONTEXT_NAME_1".to_string();
    let expected_uuid = "185e96da-c00e-454b-b4fe-9d0a14a86335".to_string();
    let mut contexts = result.ok().expect("Failed to deserialize a config::Context from JSON");
    for i in &contexts {
        assert_eq!(true, i.name.is_some());
    }
    let context = contexts.remove(0);
    assert_eq!(Some(&expected_name), context.name.as_ref());
    assert_eq!(&expected_uuid, &context.uuid.to_hyphenated_string());
}

#[test]
fn test_given_correlator_when_it_is_built_from_json_then_it_produces_the_expected_number_of_messages
    () {
    let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid3 = "3b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let result = from_str::<Vec<config::Context>>(JSON_CONFIG);
    let contexts = result.ok().expect("Failed to deserialize a config::Context from JSON");
    let responses = Rc::new(RefCell::new(Vec::new()));
    let message_event_handler = Box::new(MessageEventHandler { responses: responses.clone() });
    let mut correlator = Correlator::new(contexts);
    correlator.register_handler(message_event_handler);
    let _ = correlator.push_message(MessageBuilder::new(&uuid1, "message")
                                        .name(Some("p1"))
                                        .build());
    thread::sleep(Duration::from_millis(20));
    let _ = correlator.push_message(MessageBuilder::new(&uuid2, "message")
                                        .name(Some("p2"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    thread::sleep(Duration::from_millis(200));
    let _ = correlator.stop();
    println!("{:?}", &responses.borrow());
    assert_eq!(5, responses.borrow().len());
}
<commit_msg>correlator/test: import Context<commit_after>use config::{ContextBuilder, Context};
use config::action::message::MessageActionBuilder;
use conditions::ConditionsBuilder;
use Correlator;
use message::MessageBuilder;

use handlebars::Template;
use uuid::Uuid;
use serde_json::from_str;
use std::rc::Rc;
use std::cell::RefCell;
use std::thread;
use std::time::Duration;

use test_utils::correlator::MessageEventHandler;

const JSON_CONFIG: &'static str = r#"
      [
        {
          "name": "CONTEXT_NAME_1",
          "uuid": "185e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 100,
            "patterns": [
              "p1",
              "p2",
              "p3"
            ],
            "first_opens": true
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid1",
                  "when": {
                    "on_opened": "true",
                    "on_closed": "true"
                  },
                  "message": "message_1"
              }
            }
          ]
        },
        {
          "name": "CONTEXT_NAME_2",
          "uuid": "285e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 10000,
            "max_size": 5
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid1",
                  "message": "message_2"
              }
            },
            {
              "message": {
                  "uuid": "uuid2",
                  "message": "message_2"
              }
            }
          ]
        },
        {
          "name": "CONTEXT_NAME_3",
          "uuid": "385e96da-c00e-454b-b4fe-9d0a14a86335",
          "conditions": {
            "timeout": 100,
            "patterns": [
              "p1"
            ]
          },
          "actions": [
            {
              "message": {
                  "uuid": "uuid2",
                  "message": "message_3"
              }
            }
          ]
        }
      ]
    "#;

#[test]
fn test_given_manually_built_correlator_when_it_closes_a_context_then_the_actions_are_executed() {
    let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid3 = "3b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let patterns = vec![
        uuid1.clone(),
        uuid2.clone(),
        uuid3.clone(),
    ];
    let condition = ConditionsBuilder::new(Duration::from_millis(100))
                        .patterns(patterns)
                        .first_opens(true)
                        .last_closes(true)
                        .build();
    let message = Template::compile("message".to_string())
                      .ok()
                      .expect("Failed to compile a handlebars template");
    let contexts = vec![
        ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(vec![MessageActionBuilder::new("uuid", message.clone()).build().into()]).build(),
        ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(vec![MessageActionBuilder::new("uuid", message.clone()).build().into()]).build(),
        ContextBuilder::new(Uuid::new_v4(), condition.clone()).actions(vec![MessageActionBuilder::new("uuid", message).build().into()]).build(),
    ];
    let responses = Rc::new(RefCell::new(Vec::new()));
    let message_event_handler = Box::new(MessageEventHandler { responses: responses.clone() });
    let mut correlator = Correlator::new(contexts);
    correlator.register_handler(message_event_handler);
    let _ = correlator.push_message(MessageBuilder::new(&uuid1, "message").build());
    thread::sleep(Duration::from_millis(20));
    let _ = correlator.push_message(MessageBuilder::new(&uuid2, "message").build());
    thread::sleep(Duration::from_millis(80));
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message").build());
    let _ = correlator.stop();
    assert_eq!(3, responses.borrow().len());
}

#[test]
fn test_given_correlator_when_it_is_built_from_json_then_we_get_the_expected_correlator() {
    let result = from_str::<Vec<Context>>(JSON_CONFIG);
    let expected_name = "CONTEXT_NAME_1".to_string();
    let expected_uuid = "185e96da-c00e-454b-b4fe-9d0a14a86335".to_string();
    let mut contexts = result.ok().expect("Failed to deserialize a config::Context from JSON");
    for i in &contexts {
        assert_eq!(true, i.name.is_some());
    }
    let context = contexts.remove(0);
    assert_eq!(Some(&expected_name), context.name.as_ref());
    assert_eq!(&expected_uuid, &context.uuid.to_hyphenated_string());
}

#[test]
fn test_given_correlator_when_it_is_built_from_json_then_it_produces_the_expected_number_of_messages
    () {
    let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let uuid3 = "3b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
    let result = from_str::<Vec<Context>>(JSON_CONFIG);
    let contexts = result.ok().expect("Failed to deserialize a config::Context from JSON");
    let responses = Rc::new(RefCell::new(Vec::new()));
    let message_event_handler = Box::new(MessageEventHandler { responses: responses.clone() });
    let mut correlator = Correlator::new(contexts);
    correlator.register_handler(message_event_handler);
    let _ = correlator.push_message(MessageBuilder::new(&uuid1, "message")
                                        .name(Some("p1"))
                                        .build());
    thread::sleep(Duration::from_millis(20));
    let _ = correlator.push_message(MessageBuilder::new(&uuid2, "message")
                                        .name(Some("p2"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    let _ = correlator.push_message(MessageBuilder::new(&uuid3, "message")
                                        .name(Some("p3"))
                                        .build());
    thread::sleep(Duration::from_millis(200));
    let _ = correlator.stop();
    println!("{:?}", &responses.borrow());
    assert_eq!(5, responses.borrow().len());
}
<|endoftext|>


<commit_before>use std::io::Cursor;
use std::io::{Read, Write};

use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use db::row::Row;

// mis info about what's on each page.
const HEADER_SIZE_IN_BYTES : usize = 64;
pub const PAGE_SIZE : usize = 4096;

pub struct Page {
    header: Header,
//    data: [u8; PAGE_SIZE - HEADER_SIZE_IN_BYTES],
    data: Vec<u8>,
    bytes_used: usize, // tracking where we are in the current page

                                      // if we go past the page boundary on a write we fault
}

#[derive(Debug)]
pub enum PageError {
    Full
}

pub type PageResult<T> = Result<T, PageError>;

struct Header;

impl Header {
    fn as_vec(&self) -> Vec<u8> {
        let mut result = Vec::with_capacity(HEADER_SIZE_IN_BYTES);
        result.resize(HEADER_SIZE_IN_BYTES, 0);
        result
    }
}

// page deals with bytes, and has zero knowledge of a Row
// storage engine needs to serialize
impl Page {
    pub fn new() -> Page {
        let tmp: [u8; PAGE_SIZE - HEADER_SIZE_IN_BYTES];

        Page{header: Header::new(),
             data: Vec::with_capacity(PAGE_SIZE),
             bytes_used: 0,
             }
    }

    // attempt to write to a page
    // can fail if the page is already full
    // if it fails, the storage engine will have to flush this page
    // then allocate a new page
    pub fn write(&mut self, bytes: &[u8]) -> PageResult<()> {
        if bytes.len() > self.space_available() {
            return Err(PageError::Full)
        }
        // we need the length of the row
        let len = bytes.len() as u16;
        self.data.write_u16::<BigEndian>(len);
        self.data.write(bytes);

        self.bytes_used += 2 + len as usize;

        // TODO: update indexes
        Ok(())
    }

    // internal call, try to write instead since it holds a mutable ref
    fn space_available(&self) -> usize {
        PAGE_SIZE - HEADER_SIZE_IN_BYTES - self.bytes_used
    }

    // returns PAGE_SIZE bytes
    pub fn to_bytes(&self) -> Vec<u8> {
        let mut result = Vec::with_capacity(PAGE_SIZE);
        // get the header
        let header = self.header.as_vec();
        result.extend(header);
        result.extend(&self.data);
        result.resize(PAGE_SIZE, 0);
        result
    }

}

impl Header {
    fn new() -> Header {
        Header{}
    }
}

#[cfg(test)]
mod tests {
    use super::{Page, HEADER_SIZE_IN_BYTES, PAGE_SIZE};
    #[test]
    fn test_page_insert_ok() {
        let mut p = Page::new();

        assert_eq!(p.space_available(), PAGE_SIZE - HEADER_SIZE_IN_BYTES);
        assert_eq!(p.bytes_used, 0);

        let data: [u8; 16] = [0; 16];
        p.write(&data).expect("Data written");
        // 2 extra bytes from the size
        assert_eq!(p.bytes_used, 18);

        let result = p.to_bytes();
        assert_eq!(result.len(), PAGE_SIZE);
    }

    #[test]
    #[should_panic]
    fn test_page_fault() {
        let mut p = Page::new();
        let data: [u8; 5000] = [0; 5000];
        p.write(&data).expect("Failure is expected");
    }
}

<commit_msg>working on page header<commit_after>use std::io::Cursor;
use std::io::{Read, Write};

use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use db::row::Row;

// mis info about what's on each page.
const HEADER_SIZE_IN_BYTES : usize = 32;
pub const PAGE_SIZE : usize = 4096;

pub struct Page {
    header: Header,
//    data: [u8; PAGE_SIZE - HEADER_SIZE_IN_BYTES],
    data: Vec<u8>,
    bytes_used: usize, // tracking where we are in the current page

                                      // if we go past the page boundary on a write we fault
}

#[derive(Debug)]
pub enum PageError {
    Full
}

pub type PageResult<T> = Result<T, PageError>;

struct Header {
    first_id: u64,
    last_id: u64
}

impl Header {
    fn as_vec(&self) -> Vec<u8> {
        let mut result = Vec::with_capacity(HEADER_SIZE_IN_BYTES);
//        result.resize(HEADER_SIZE_IN_BYTES, 0);
        result.write_u64::<BigEndian>(self.first_id);
        result.write_u64::<BigEndian>(self.last_id);
        result
    }
}

impl Header {
    fn new() -> Header {
        Header{first_id: 0, last_id: 0}
    }
    fn from_bytes(bytes: &[u8]) -> Header {
        let mut cur = Cursor::new(bytes);
        let first_id = cur.read_u64::<BigEndian>().unwrap();
        let last_id = cur.read_u64::<BigEndian>().unwrap();
        Header{first_id: first_id, last_id: last_id}
    }
}

// page deals with bytes, and has zero knowledge of a Row
// storage engine needs to serialize
impl Page {
    pub fn new() -> Page {
        let tmp: [u8; PAGE_SIZE - HEADER_SIZE_IN_BYTES];

        Page{header: Header::new(),
             data: Vec::with_capacity(PAGE_SIZE),
             bytes_used: 0,
             }
    }

    // attempt to write to a page
    // can fail if the page is already full
    // if it fails, the storage engine will have to flush this page
    // then allocate a new page
    pub fn write(&mut self, bytes: &[u8]) -> PageResult<()> {
        if bytes.len() > self.space_available() {
            return Err(PageError::Full)
        }
        // we need the length of the row
        let len = bytes.len() as u16;
        self.data.write_u16::<BigEndian>(len);
        self.data.write(bytes);

        self.bytes_used += 2 + len as usize;

        // TODO: update indexes
        Ok(())
    }

    // internal call, try to write instead since it holds a mutable ref
    fn space_available(&self) -> usize {
        PAGE_SIZE - HEADER_SIZE_IN_BYTES - self.bytes_used
    }

    // returns PAGE_SIZE bytes
    pub fn to_bytes(&self) -> Vec<u8> {
        let mut result = Vec::with_capacity(PAGE_SIZE);
        // get the header
        let header = self.header.as_vec();
        result.extend(header);
        result.extend(&self.data);
        result.resize(PAGE_SIZE, 0);
        result
    }

}

#[cfg(test)]
mod tests {
    use super::{Page, HEADER_SIZE_IN_BYTES, PAGE_SIZE};
    #[test]
    fn test_page_insert_ok() {
        let mut p = Page::new();

        assert_eq!(p.space_available(), PAGE_SIZE - HEADER_SIZE_IN_BYTES);
        assert_eq!(p.bytes_used, 0);

        let data: [u8; 16] = [0; 16];
        p.write(&data).expect("Data written");
        // 2 extra bytes from the size
        assert_eq!(p.bytes_used, 18);

        let result = p.to_bytes();
        assert_eq!(result.len(), PAGE_SIZE);
    }

    #[test]
    #[should_panic]
    fn test_page_fault() {
        let mut p = Page::new();
        let data: [u8; 5000] = [0; 5000];
        p.write(&data).expect("Failure is expected");
    }
}

<|endoftext|>