<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! An iterator over a list of rules.

use context::QuirksMode;
use media_queries::Device;
use shared_lock::SharedRwLockReadGuard;
use smallvec::SmallVec;
use std::slice;
use stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule};
use stylesheets::StylesheetInDocument;
use stylesheets::import_rule::ImportSheet;

/// An iterator over a list of rules.
pub struct RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    device: &'a Device,
    quirks_mode: QuirksMode,
    guard: &'a SharedRwLockReadGuard<'b>,
    stack: SmallVec<[slice::Iter<'a, CssRule>; 3]>,
    _phantom: ::std::marker::PhantomData<C>,
}

impl<'a, 'b, C> RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    /// Creates a new `RulesIterator` to iterate over `rules`.
    pub fn new(
        device: &'a Device,
        quirks_mode: QuirksMode,
        guard: &'a SharedRwLockReadGuard<'b>,
        rules: &'a [CssRule],
    ) -> Self {
        let mut stack = SmallVec::new();
        stack.push(rules.iter());
        Self {
            device: device,
            quirks_mode: quirks_mode,
            guard: guard,
            stack: stack,
            _phantom: ::std::marker::PhantomData,
        }
    }

    /// Skips all the remaining children of the last nested rule processed.
    pub fn skip_children(&mut self) {
        self.stack.pop();
    }
}

impl<'a, 'b, C> Iterator for RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    type Item = &'a CssRule;

    fn next(&mut self) -> Option<Self::Item> {
        let mut nested_iter_finished = false;
        while !self.stack.is_empty() {
            if nested_iter_finished {
                self.stack.pop();
                nested_iter_finished = false;
                continue;
            }

            let rule;
            let sub_iter = {
                let nested_iter = self.stack.last_mut().unwrap();
                rule = match nested_iter.next() {
                    Some(r) => r,
                    None => {
                        nested_iter_finished = true;
                        continue;
                    },
                };

                match *rule {
                    CssRule::Namespace(_) |
                    CssRule::Style(_) |
                    CssRule::FontFace(_) |
                    CssRule::CounterStyle(_) |
                    CssRule::Viewport(_) |
                    CssRule::Keyframes(_) |
                    CssRule::Page(_) |
                    CssRule::FontFeatureValues(_) => return Some(rule),
                    CssRule::Import(ref import_rule) => {
                        let import_rule = import_rule.read_with(self.guard);
                        if !C::process_import(
                            self.guard,
                            self.device,
                            self.quirks_mode,
                            import_rule,
                        ) {
                            continue;
                        }
                        import_rule
                            .stylesheet
                            .rules(self.guard)
                            .iter()
                    },
                    CssRule::Document(ref doc_rule) => {
                        let doc_rule = doc_rule.read_with(self.guard);
                        if !C::process_document(self.guard, self.device, self.quirks_mode, doc_rule)
                        {
                            continue;
                        }
                        doc_rule.rules.read_with(self.guard).0.iter()
                    },
                    CssRule::Media(ref lock) => {
                        let media_rule = lock.read_with(self.guard);
                        if !C::process_media(self.guard, self.device, self.quirks_mode, media_rule)
                        {
                            continue;
                        }
                        media_rule.rules.read_with(self.guard).0.iter()
                    },
                    CssRule::Supports(ref lock) => {
                        let supports_rule = lock.read_with(self.guard);
                        if !C::process_supports(
                            self.guard,
                            self.device,
                            self.quirks_mode,
                            supports_rule,
                        ) {
                            continue;
                        }
                        supports_rule.rules.read_with(self.guard).0.iter()
                    },
                }
            };

            self.stack.push(sub_iter);
            return Some(rule);
        }

        None
    }
}

/// RulesIterator.
pub trait NestedRuleIterationCondition {
    /// Whether we should process the nested rules in a given `@import` rule.
    fn process_import(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &ImportRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@media` rule.
    fn process_media(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &MediaRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@-moz-document`
    /// rule.
    fn process_document(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &DocumentRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@supports` rule.
    fn process_supports(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &SupportsRule,
    ) -> bool;
}

/// A struct that represents the condition that a rule applies to the document.
pub struct EffectiveRules;

impl NestedRuleIterationCondition for EffectiveRules {
    fn process_import(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        _quirks_mode: QuirksMode,
        rule: &ImportRule,
    ) -> bool {
        rule.stylesheet.is_effective_for_device(device, guard)
    }

    fn process_media(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &MediaRule,
    ) -> bool {
        rule.media_queries
            .read_with(guard)
            .evaluate(device, quirks_mode)
    }

    fn process_document(
        _: &SharedRwLockReadGuard,
        device: &Device,
        _: QuirksMode,
        rule: &DocumentRule,
    ) -> bool {
        rule.condition.evaluate(device)
    }

    fn process_supports(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        rule: &SupportsRule,
    ) -> bool {
        rule.enabled
    }
}

/// A filter that processes all the rules in a rule list.
pub struct AllRules;

impl NestedRuleIterationCondition for AllRules {
    fn process_import(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &ImportRule,
    ) -> bool {
        true
    }

    fn process_media(_: &SharedRwLockReadGuard, _: &Device, _: QuirksMode, _: &MediaRule) -> bool {
        true
    }

    fn process_document(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &DocumentRule,
    ) -> bool {
        true
    }

    fn process_supports(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &SupportsRule,
    ) -> bool {
        true
    }
}

/// An iterator over all the effective rules of a stylesheet.
///
/// NOTE: This iterator recurses into `@import` rules.
pub type EffectiveRulesIterator<'a, 'b> = RulesIterator<'a, 'b, EffectiveRules>;
<commit_msg>style: Remove an unused import.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! An iterator over a list of rules.

use context::QuirksMode;
use media_queries::Device;
use shared_lock::SharedRwLockReadGuard;
use smallvec::SmallVec;
use std::slice;
use stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule};
use stylesheets::StylesheetInDocument;

/// An iterator over a list of rules.
pub struct RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    device: &'a Device,
    quirks_mode: QuirksMode,
    guard: &'a SharedRwLockReadGuard<'b>,
    stack: SmallVec<[slice::Iter<'a, CssRule>; 3]>,
    _phantom: ::std::marker::PhantomData<C>,
}

impl<'a, 'b, C> RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    /// Creates a new `RulesIterator` to iterate over `rules`.
    pub fn new(
        device: &'a Device,
        quirks_mode: QuirksMode,
        guard: &'a SharedRwLockReadGuard<'b>,
        rules: &'a [CssRule],
    ) -> Self {
        let mut stack = SmallVec::new();
        stack.push(rules.iter());
        Self {
            device: device,
            quirks_mode: quirks_mode,
            guard: guard,
            stack: stack,
            _phantom: ::std::marker::PhantomData,
        }
    }

    /// Skips all the remaining children of the last nested rule processed.
    pub fn skip_children(&mut self) {
        self.stack.pop();
    }
}

impl<'a, 'b, C> Iterator for RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    type Item = &'a CssRule;

    fn next(&mut self) -> Option<Self::Item> {
        let mut nested_iter_finished = false;
        while !self.stack.is_empty() {
            if nested_iter_finished {
                self.stack.pop();
                nested_iter_finished = false;
                continue;
            }

            let rule;
            let sub_iter = {
                let nested_iter = self.stack.last_mut().unwrap();
                rule = match nested_iter.next() {
                    Some(r) => r,
                    None => {
                        nested_iter_finished = true;
                        continue;
                    },
                };

                match *rule {
                    CssRule::Namespace(_) |
                    CssRule::Style(_) |
                    CssRule::FontFace(_) |
                    CssRule::CounterStyle(_) |
                    CssRule::Viewport(_) |
                    CssRule::Keyframes(_) |
                    CssRule::Page(_) |
                    CssRule::FontFeatureValues(_) => return Some(rule),
                    CssRule::Import(ref import_rule) => {
                        let import_rule = import_rule.read_with(self.guard);
                        if !C::process_import(
                            self.guard,
                            self.device,
                            self.quirks_mode,
                            import_rule,
                        ) {
                            continue;
                        }
                        import_rule
                            .stylesheet
                            .rules(self.guard)
                            .iter()
                    },
                    CssRule::Document(ref doc_rule) => {
                        let doc_rule = doc_rule.read_with(self.guard);
                        if !C::process_document(self.guard, self.device, self.quirks_mode, doc_rule)
                        {
                            continue;
                        }
                        doc_rule.rules.read_with(self.guard).0.iter()
                    },
                    CssRule::Media(ref lock) => {
                        let media_rule = lock.read_with(self.guard);
                        if !C::process_media(self.guard, self.device, self.quirks_mode, media_rule)
                        {
                            continue;
                        }
                        media_rule.rules.read_with(self.guard).0.iter()
                    },
                    CssRule::Supports(ref lock) => {
                        let supports_rule = lock.read_with(self.guard);
                        if !C::process_supports(
                            self.guard,
                            self.device,
                            self.quirks_mode,
                            supports_rule,
                        ) {
                            continue;
                        }
                        supports_rule.rules.read_with(self.guard).0.iter()
                    },
                }
            };

            self.stack.push(sub_iter);
            return Some(rule);
        }

        None
    }
}

/// RulesIterator.
pub trait NestedRuleIterationCondition {
    /// Whether we should process the nested rules in a given `@import` rule.
    fn process_import(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &ImportRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@media` rule.
    fn process_media(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &MediaRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@-moz-document`
    /// rule.
    fn process_document(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &DocumentRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@supports` rule.
    fn process_supports(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &SupportsRule,
    ) -> bool;
}

/// A struct that represents the condition that a rule applies to the document.
pub struct EffectiveRules;

impl NestedRuleIterationCondition for EffectiveRules {
    fn process_import(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        _quirks_mode: QuirksMode,
        rule: &ImportRule,
    ) -> bool {
        rule.stylesheet.is_effective_for_device(device, guard)
    }

    fn process_media(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &MediaRule,
    ) -> bool {
        rule.media_queries
            .read_with(guard)
            .evaluate(device, quirks_mode)
    }

    fn process_document(
        _: &SharedRwLockReadGuard,
        device: &Device,
        _: QuirksMode,
        rule: &DocumentRule,
    ) -> bool {
        rule.condition.evaluate(device)
    }

    fn process_supports(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        rule: &SupportsRule,
    ) -> bool {
        rule.enabled
    }
}

/// A filter that processes all the rules in a rule list.
pub struct AllRules;

impl NestedRuleIterationCondition for AllRules {
    fn process_import(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &ImportRule,
    ) -> bool {
        true
    }

    fn process_media(_: &SharedRwLockReadGuard, _: &Device, _: QuirksMode, _: &MediaRule) -> bool {
        true
    }

    fn process_document(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &DocumentRule,
    ) -> bool {
        true
    }

    fn process_supports(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &SupportsRule,
    ) -> bool {
        true
    }
}

/// An iterator over all the effective rules of a stylesheet.
///
/// NOTE: This iterator recurses into `@import` rules.
pub type EffectiveRulesIterator<'a, 'b> = RulesIterator<'a, 'b, EffectiveRules>;
<|endoftext|>


<commit_before>use gameboy::Gameboy;

use gameboy::{WRAM_BANK_SIZE, WRAM_NUM_BANKS};

trait MmuHelpers {
	fn read_byte_wram(&self, address: u16) -> u8;
	fn write_byte_wram(&mut self, address: u16, value: u8);
	fn read_byte_io(&self, address: u16) -> u8;
	fn write_byte_io(&mut self, address: u16, value: u8);
}

impl MmuHelpers for Gameboy {
	fn read_byte_wram(&self, address: u16) -> u8 {
		let selected_wram_bank = 1;	//TODO: wram banks
		match address {
			0xC000...0xCFFF => self.wram[(address - 0xC000) as usize],
			0xD000...0xDFFF => self.wram[(address - 0xC000) as usize + (WRAM_BANK_SIZE * selected_wram_bank) as usize],
			_ => panic!("gbc::read_byte_wram - invalid arguments, address must be in the range [0xC000, 0xDFFF]"),
		}
	}

	fn write_byte_wram(&mut self, address: u16, value: u8) {
		if self.oam_dma_active {
			return;
		}
		let selected_wram_bank = 1;	//TODO: wram banks
		match address {
			0xC000...0xCFFF => self.wram[(address - 0xC000) as usize] = value,
			0xD000...0xDFFF => self.wram[(address - 0xC000) as usize + (WRAM_BANK_SIZE * selected_wram_bank) as usize] = value,
			_ => panic!("gbc::read_byte_wram - invalid arguments, address must be in the range [0xC000, 0xDFFF]"),
		};
	}

	fn read_byte_io(&self, address: u16) -> u8 {
		match address {
			0xFF00 => self.joypad.read_joyp(),
			0xFF01...0xFF7F => self.io[(address - 0xFF00) as usize],
			_ => panic!("gbc::read_byte_io - invalid arguments, address must be in the range [0xFF00, 0xFF7F]."),
		}
	}

	//FF4F is the io register that controlls the vram bank on gbc
	fn write_byte_io(&mut self, address: u16, value: u8) {
		match address {
			0xFF00 => self.joypad.write_joyp(value),
			0xFF04 => self.timer.reset_div(),
			0xFF46 => self.start_oam_dma(value),
			0xFF01...0xFF45 | 0xFF47...0xFF7F => self.io[(address - 0xFF00) as usize] = value,
			_ => panic!("gbc::write_byte_io - invalid arguments, address must be in the range [0xFF00, 0xFF7F]."),
		};
	}
}

pub trait Mmu {
	fn read_byte(&self, address: u16) -> u8;
	fn write_byte(&mut self, address: u16, value: u8);

	///similar to read/write, but sometimes a coprocessor has
	///exclusive access to a region of memory and the cpu
	///can't read from / write to it.
	fn read_byte_cpu(&self, address: u16) -> u8;
	fn write_byte_cpu(&mut self, address: u16, value: u8);

	fn rom(&self) -> &[u8];
	fn rom_mut(&mut self) -> &mut[u8];

	fn banked_rom(&self) -> &[u8];
	fn banked_rom_mut(&mut self) -> &mut[u8];

	// fn ram(&self) -> &[u8];
	// fn ram_mut(&mut self) -> &mut[u8];

	// fn vram(&self) -> &[u8];
	// fn vram_mut(&mut self) -> &mut[u8];

	// fn wram(&self) -> &[u8];
	// fn wram_mut(&mut self) -> &mut[u8];

	// fn banked_wram(&self) -> &[u8];
	// fn banked_wram_mut(&mut self) -> &mut[u8];

	// fn oam(&self) -> &[u8];
	// fn oam_mut(&mut self) -> &mut[u8];

	// fn io(&self) -> &[u8];
	// fn io_mut(&mut self) -> &mut [u8];

	// fn hram(&self) -> &[u8];
	// fn hram_mut(&mut self) -> &mut[u8];

	// fn ier(&self) -> u8;
	// fn ier_mut(&mut self) -> &mut u8;
}

impl Mmu for Gameboy {
	fn read_byte(&self, address: u16) -> u8 {
		match address {
			0x0000...0x7FFF => self.cart.read_byte_rom(address),
			0x8000...0x9FFF => self.ppu.read_byte_vram(&self.io, address),
			0xA000...0xBFFF => self.cart.read_byte_ram(address),
			0xC000...0xDFFF => self.read_byte_wram(address),
			0xE000...0xFDFF => self.read_byte_wram(address - 0x2000),	//Mirror of wram
			0xFE00...0xFE9F => self.ppu.read_byte_oam(&self.io, address),
			0xFF00...0xFF7F => self.read_byte_io(address),
			0xFF80...0xFFFE => self.cpu.read_byte_hram(address),
			0xFFFF => self.cpu.ier,
			_ => 0xFF,
		}
	}

	fn write_byte(&mut self, address: u16, value: u8) {
		match address {
			0x0000...0x7FFF => self.cart.write_byte_rom(address, value),
			0x8000...0x9FFF => self.ppu.write_byte_vram(&self.io, address, value),
			0xA000...0xBFFF => self.cart.write_byte_ram(address, value),
			0xC000...0xDFFF => self.write_byte_wram(address, value),
			0xE000...0xFDFF => self.write_byte_wram(address - 0x2000, value),	//Mirror of wram
			0xFE00...0xFE9F => self.ppu.write_byte_oam(&self.io, address, value),
			0xFF00...0xFF7F => self.write_byte_io(address, value),
			0xFF80...0xFFFE => self.cpu.write_byte_hram(address, value),
			0xFFFF => self.cpu.ier = value,
			_ => return,
		};
	}

	///Read a byte at $address
	///Not all memory is readable all of the time,
	///for instance, vram and oam can't be read during certain ppu states.
	///and the cpu can't read anything other than hram and iem during a dma transfer
	fn read_byte_cpu(&self, address: u16) -> u8 {
		if self.oam_dma_active && address < 0xFF80 {
			//cpu can't access anything other than hram when oam dma is active
			return 0xFF;
		}
		match address {
			0x0000...0x7FFF => self.cart.read_byte_rom(address),
			0x8000...0x9FFF => self.ppu.read_byte_vram(&self.io, address),
			0xA000...0xBFFF => self.cart.read_byte_ram(address),
			0xC000...0xDFFF => self.read_byte_wram(address),
			0xE000...0xFDFF => self.read_byte_wram(address - 0x2000),	//Mirror of wram
			0xFE00...0xFE9F => self.ppu.read_byte_oam(&self.io, address),
			0xFF00...0xFF7F => self.read_byte_io(address),
			0xFF80...0xFFFE => self.cpu.read_byte_hram(address),
			0xFFFF => self.cpu.ier,
			_ => 0xFF,
		}
	}

	fn write_byte_cpu(&mut self, address: u16, value: u8) {
		if self.oam_dma_active && address < 0xFF80 {
			//cpu can't access anything other than hram when oam dma is active
			return;
		}
		match address {
			0x0000...0x7FFF => self.cart.write_byte_rom(address, value),
			0x8000...0x9FFF => self.ppu.write_byte_vram(&self.io, address, value),
			0xA000...0xBFFF => self.cart.write_byte_ram(address, value),
			0xC000...0xDFFF => self.write_byte_wram(address, value),
			0xE000...0xFDFF => self.write_byte_wram(address - 0x2000, value),	//Mirror of wram
			0xFE00...0xFE9F => self.ppu.write_byte_oam(&self.io, address, value),
			0xFF00...0xFF7F => self.write_byte_io(address, value),
			0xFF80...0xFFFE => self.cpu.write_byte_hram(address, value),
			0xFFFF => self.cpu.ier = value,
			_ => return,
		};
	}

	fn rom(&self) -> &[u8] {
		self.cart.rom()
	}

	fn rom_mut(&mut self) -> &mut[u8] {
		self.cart.rom_mut()
	}

	fn banked_rom(&self) -> &[u8] {
		self.cart.banked_rom()
	}

	fn banked_rom_mut(&mut self) -> &mut[u8] {
		self.cart.banked_rom_mut()
	}

	// fn ram(&self) -> &[u8] {
	// 	self.cart.ram()
	// }
	// fn ram_mut(&mut self) -> &mut[u8] {
	// 	self.cart.ram_mut()
	// }

	// fn vram(&self) -> &[u8] {
	// 	self.ppu.get_vram()
	// }

	// fn vram_mut(&mut self) -> &mut[u8] {
	// 	self.ppu.get_vram_mut()
	// }

	// fn wram(&self) -> &[u8] {
	// 	&self.wram[0..0x1000]
	// }

	// fn wram_mut(&mut self) -> &mut[u8] {
	// 	&mut self.wram[0..0x1000]
	// }

	// fn banked_wram(&self) -> &[u8] {
	// 	//TODO: wram banks on cgb
	// 	&self.wram[0x1000..0x2000]
	// }

	// fn banked_wram_mut(&mut self) -> &mut[u8] {
	// 	//TODO: wram banks on cgb
	// 	&mut self.wram[0x1000..0x2000]
	// }

	// fn oam(&self) -> &[u8] {
	// 	self.ppu.get_oam()
	// }

	// fn oam_mut(&mut self) -> &mut[u8] {
	// 	self.ppu.get_oam_mut()
	// }

	// fn io(&self) -> &[u8] {
	// 	&self.io
	// }

	// fn io_mut(&mut self) -> &mut [u8] {
	// 	&mut self.io
	// }

	// fn hram(&self) -> &[u8] {
	// 	&self.cpu.hram
	// }

	// fn hram_mut(&mut self) -> &mut[u8] {
	// 	&mut self.cpu.hram
	// }

	// fn ier(&self) -> u8 {
	// 	self.cpu.ier
	// }

	// fn ier_mut(&mut self) -> &mut u8 {
	// 	&mut self.cpu.ier
	// }
}
<commit_msg>Removed some unused helpers from the mmu trait.<commit_after>use gameboy::Gameboy;

use gameboy::{WRAM_BANK_SIZE, WRAM_NUM_BANKS};

trait MmuHelpers {
	fn read_byte_wram(&self, address: u16) -> u8;
	fn write_byte_wram(&mut self, address: u16, value: u8);
	fn read_byte_io(&self, address: u16) -> u8;
	fn write_byte_io(&mut self, address: u16, value: u8);
}

impl MmuHelpers for Gameboy {
	fn read_byte_wram(&self, address: u16) -> u8 {
		let selected_wram_bank = 1;	//TODO: wram banks
		match address {
			0xC000...0xCFFF => self.wram[(address - 0xC000) as usize],
			0xD000...0xDFFF => self.wram[(address - 0xC000) as usize + (WRAM_BANK_SIZE * selected_wram_bank) as usize],
			_ => panic!("gbc::read_byte_wram - invalid arguments, address must be in the range [0xC000, 0xDFFF]"),
		}
	}

	fn write_byte_wram(&mut self, address: u16, value: u8) {
		if self.oam_dma_active {
			return;
		}
		let selected_wram_bank = 1;	//TODO: wram banks
		match address {
			0xC000...0xCFFF => self.wram[(address - 0xC000) as usize] = value,
			0xD000...0xDFFF => self.wram[(address - 0xC000) as usize + (WRAM_BANK_SIZE * selected_wram_bank) as usize] = value,
			_ => panic!("gbc::read_byte_wram - invalid arguments, address must be in the range [0xC000, 0xDFFF]"),
		};
	}

	fn read_byte_io(&self, address: u16) -> u8 {
		match address {
			0xFF00 => self.joypad.read_joyp(),
			0xFF01...0xFF7F => self.io[(address - 0xFF00) as usize],
			_ => panic!("gbc::read_byte_io - invalid arguments, address must be in the range [0xFF00, 0xFF7F]."),
		}
	}

	//FF4F is the io register that controlls the vram bank on gbc
	fn write_byte_io(&mut self, address: u16, value: u8) {
		match address {
			0xFF00 => self.joypad.write_joyp(value),
			0xFF04 => self.timer.reset_div(),
			0xFF46 => self.start_oam_dma(value),
			0xFF01...0xFF45 | 0xFF47...0xFF7F => self.io[(address - 0xFF00) as usize] = value,
			_ => panic!("gbc::write_byte_io - invalid arguments, address must be in the range [0xFF00, 0xFF7F]."),
		};
	}
}

pub trait Mmu {
	fn read_byte(&self, address: u16) -> u8;
	fn write_byte(&mut self, address: u16, value: u8);

	///similar to read/write, but sometimes a coprocessor has
	///exclusive access to a region of memory and the cpu
	///can't read from / write to it.
	fn read_byte_cpu(&self, address: u16) -> u8;
	fn write_byte_cpu(&mut self, address: u16, value: u8);

	fn rom(&self) -> &[u8];
	fn rom_mut(&mut self) -> &mut[u8];

	fn banked_rom(&self) -> &[u8];
	fn banked_rom_mut(&mut self) -> &mut[u8];
}

impl Mmu for Gameboy {
	fn read_byte(&self, address: u16) -> u8 {
		match address {
			0x0000...0x7FFF => self.cart.read_byte_rom(address),
			0x8000...0x9FFF => self.ppu.read_byte_vram(&self.io, address),
			0xA000...0xBFFF => self.cart.read_byte_ram(address),
			0xC000...0xDFFF => self.read_byte_wram(address),
			0xE000...0xFDFF => self.read_byte_wram(address - 0x2000),	//Mirror of wram
			0xFE00...0xFE9F => self.ppu.read_byte_oam(&self.io, address),
			0xFF00...0xFF7F => self.read_byte_io(address),
			0xFF80...0xFFFE => self.cpu.read_byte_hram(address),
			0xFFFF => self.cpu.ier,
			_ => 0xFF,
		}
	}

	fn write_byte(&mut self, address: u16, value: u8) {
		match address {
			0x0000...0x7FFF => self.cart.write_byte_rom(address, value),
			0x8000...0x9FFF => self.ppu.write_byte_vram(&self.io, address, value),
			0xA000...0xBFFF => self.cart.write_byte_ram(address, value),
			0xC000...0xDFFF => self.write_byte_wram(address, value),
			0xE000...0xFDFF => self.write_byte_wram(address - 0x2000, value),	//Mirror of wram
			0xFE00...0xFE9F => self.ppu.write_byte_oam(&self.io, address, value),
			0xFF00...0xFF7F => self.write_byte_io(address, value),
			0xFF80...0xFFFE => self.cpu.write_byte_hram(address, value),
			0xFFFF => self.cpu.ier = value,
			_ => return,
		};
	}

	///Read a byte at $address
	///Not all memory is readable all of the time,
	///for instance, vram and oam can't be read during certain ppu states.
	///and the cpu can't read anything other than hram and iem during a dma transfer
	fn read_byte_cpu(&self, address: u16) -> u8 {
		if self.oam_dma_active && address < 0xFF80 {
			//cpu can't access anything other than hram when oam dma is active
			return 0xFF;
		}
		match address {
			0x0000...0x7FFF => self.cart.read_byte_rom(address),
			0x8000...0x9FFF => self.ppu.read_byte_vram(&self.io, address),
			0xA000...0xBFFF => self.cart.read_byte_ram(address),
			0xC000...0xDFFF => self.read_byte_wram(address),
			0xE000...0xFDFF => self.read_byte_wram(address - 0x2000),	//Mirror of wram
			0xFE00...0xFE9F => self.ppu.read_byte_oam(&self.io, address),
			0xFF00...0xFF7F => self.read_byte_io(address),
			0xFF80...0xFFFE => self.cpu.read_byte_hram(address),
			0xFFFF => self.cpu.ier,
			_ => 0xFF,
		}
	}

	fn write_byte_cpu(&mut self, address: u16, value: u8) {
		if self.oam_dma_active && address < 0xFF80 {
			//cpu can't access anything other than hram when oam dma is active
			return;
		}
		match address {
			0x0000...0x7FFF => self.cart.write_byte_rom(address, value),
			0x8000...0x9FFF => self.ppu.write_byte_vram(&self.io, address, value),
			0xA000...0xBFFF => self.cart.write_byte_ram(address, value),
			0xC000...0xDFFF => self.write_byte_wram(address, value),
			0xE000...0xFDFF => self.write_byte_wram(address - 0x2000, value),	//Mirror of wram
			0xFE00...0xFE9F => self.ppu.write_byte_oam(&self.io, address, value),
			0xFF00...0xFF7F => self.write_byte_io(address, value),
			0xFF80...0xFFFE => self.cpu.write_byte_hram(address, value),
			0xFFFF => self.cpu.ier = value,
			_ => return,
		};
	}

	fn rom(&self) -> &[u8] {
		self.cart.rom()
	}

	fn rom_mut(&mut self) -> &mut[u8] {
		self.cart.rom_mut()
	}

	fn banked_rom(&self) -> &[u8] {
		self.cart.banked_rom()
	}

	fn banked_rom_mut(&mut self) -> &mut[u8] {
		self.cart.banked_rom_mut()
	}
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use atomic_refcell::AtomicRefCell;
use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
use data::ElementData;
use dom::{NodeInfo, TNode};
use gecko::wrapper::{GeckoElement, GeckoNode};
use traversal::{DomTraversal, PerLevelTraversalData, recalc_style_at};

pub struct RecalcStyleOnly {
    shared: SharedStyleContext,
}

impl RecalcStyleOnly {
    pub fn new(shared: SharedStyleContext) -> Self {
        RecalcStyleOnly {
            shared: shared,
        }
    }
}

impl<'ln> DomTraversal<GeckoNode<'ln>> for RecalcStyleOnly {
    type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'ln>>;

    fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData,
                        thread_local: &mut Self::ThreadLocalContext,
                        node: GeckoNode<'ln>)
    {
        if node.is_element() {
            let el = node.as_element().unwrap();
            let mut data = unsafe { el.ensure_data() }.borrow_mut();
            let mut context = StyleContext {
                shared: &self.shared,
                thread_local: thread_local,
            };
            recalc_style_at(self, traversal_data, &mut context, el, &mut data);
        }
    }

    fn process_postorder(&self, _: &mut Self::ThreadLocalContext, _: GeckoNode<'ln>) {
        unreachable!();
    }

    /// We don't use the post-order traversal for anything.
    fn needs_postorder_traversal() -> bool { false }

    unsafe fn ensure_element_data<'a>(element: &'a GeckoElement<'ln>) -> &'a AtomicRefCell<ElementData> {
        element.ensure_data()
    }

    unsafe fn clear_element_data<'a>(element: &'a GeckoElement<'ln>) {
        element.clear_data()
    }

    fn shared_context(&self) -> &SharedStyleContext {
        &self.shared
    }

    fn create_thread_local_context(&self) -> Self::ThreadLocalContext {
        ThreadLocalStyleContext::new(&self.shared)
    }
}
<commit_msg>style: Document Gecko's traversal code.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Gecko-specific bits for the styling DOM traversal.

use atomic_refcell::AtomicRefCell;
use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
use data::ElementData;
use dom::{NodeInfo, TNode};
use gecko::wrapper::{GeckoElement, GeckoNode};
use traversal::{DomTraversal, PerLevelTraversalData, recalc_style_at};

/// This is the simple struct that Gecko uses to encapsulate a DOM traversal for
/// styling.
pub struct RecalcStyleOnly {
    shared: SharedStyleContext,
}

impl RecalcStyleOnly {
    /// Create a `RecalcStyleOnly` traversal from a `SharedStyleContext`.
    pub fn new(shared: SharedStyleContext) -> Self {
        RecalcStyleOnly {
            shared: shared,
        }
    }
}

impl<'ln> DomTraversal<GeckoNode<'ln>> for RecalcStyleOnly {
    type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'ln>>;

    fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData,
                        thread_local: &mut Self::ThreadLocalContext,
                        node: GeckoNode<'ln>)
    {
        if node.is_element() {
            let el = node.as_element().unwrap();
            let mut data = unsafe { el.ensure_data() }.borrow_mut();
            let mut context = StyleContext {
                shared: &self.shared,
                thread_local: thread_local,
            };
            recalc_style_at(self, traversal_data, &mut context, el, &mut data);
        }
    }

    fn process_postorder(&self, _: &mut Self::ThreadLocalContext, _: GeckoNode<'ln>) {
        unreachable!();
    }

    /// We don't use the post-order traversal for anything.
    fn needs_postorder_traversal() -> bool { false }

    unsafe fn ensure_element_data<'a>(element: &'a GeckoElement<'ln>) -> &'a AtomicRefCell<ElementData> {
        element.ensure_data()
    }

    unsafe fn clear_element_data<'a>(element: &'a GeckoElement<'ln>) {
        element.clear_data()
    }

    fn shared_context(&self) -> &SharedStyleContext {
        &self.shared
    }

    fn create_thread_local_context(&self) -> Self::ThreadLocalContext {
        ThreadLocalStyleContext::new(&self.shared)
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use std::hash::{Hash, Hasher};

/// A simple implementation of a [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog)
#[derive(Clone)]
pub struct HyperLogLog {
    registers: Vec<u8>,
    b: usize,
}

impl HyperLogLog {
    /// Creates a new, empty HyperLogLog.
    ///
    /// - `b` number of bits used for register selection, number of registers within the
    ///   HyperLogLog will be `2^b`. `b` must be in `[4, 16]`
    ///
    /// Panics when `b` is out of bounds.
    pub fn new(b: usize) -> HyperLogLog {
        assert!(b >= 4);
        assert!(b <= 16);

        let m = (1 as usize) << b;
        let registers = vec![0; m];
        HyperLogLog {
            registers: registers,
            b: b,
        }
    }

    /// Adds an element to the HyperLogLog.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        let mut hasher = DefaultHasher::new();
        obj.hash(&mut hasher);
        let h: u64 = hasher.finish();

        let w = h >> self.b;
        let j = h - (w << self.b);
        let p = w.leading_zeros() + 1 - (self.b as u32);

        let m_old = self.registers[j as usize];
        self.registers[j as usize] = cmp::max(m_old, p as u8);
    }

    /// Guess the number of unique elements seen by the HyperLogLog.
    pub fn count(&self) -> usize {
        let m = self.registers.len() as f64;

        let z = 1f64 /
            self.registers
                .iter()
                .map(|&x| 2f64.powi(-(x as i32)))
                .sum::<f64>();

        let am = if m >= 128. {
            0.7213 / (1. + 1.079 / m)
        } else if m >= 64. {
            0.709
        } else if m >= 32. {
            0.697
        } else {
            0.673
        };

        let e = am * m * m * z;

        let e_star = if e <= 5. / 2. * m {
            // small range correction
            let v = self.registers.iter().filter(|&&x| x == 0).count();
            if v != 0 {
                m * (m / (v as f64)).ln()
            } else {
                e
            }
        } else if e <= 1. / 30. * 2f64.powi(32) {
            // intermediate range => no correction
            e
        } else {
            // large range correction
            -2f64.powi(32) * (1. - e / 2f64.powi(32)).ln()
        };

        e_star as usize
    }

    /// Empties the HyperLogLog.
    pub fn clear(&mut self) {
        self.registers = vec![0; self.registers.len()];
    }

    /// Checks whether the HyperLogLog has never seen an element.
    pub fn is_empty(&self) -> bool {
        self.registers.iter().all(|&x| x == 0)
    }
}

impl fmt::Debug for HyperLogLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "HyperLogLog {{ b: {} }}", self.b)
    }
}

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

    #[test]
    fn empty() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn add_b4_n1k() {
        let mut hll = HyperLogLog::new(4);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 571);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n1k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 966);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n1k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 984);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 998);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n10k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10196);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n10k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10303);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n10k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10055);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n100k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..100000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 100551);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1m() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 1000226);
        assert!(!hll.is_empty());
    }

    #[test]
    fn clear() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        hll.clear();
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn clone() {
        let mut hll1 = HyperLogLog::new(12);
        for i in 0..500 {
            hll1.add(&i);
        }
        let c1a = hll1.count();

        let hll2 = hll1.clone();
        assert_eq!(hll2.count(), c1a);

        for i in 501..1000 {
            hll1.add(&i);
        }
        let c1b = hll1.count();
        assert_ne!(c1b, c1a);
        assert_eq!(hll2.count(), c1a);
    }

    #[test]
    fn debug() {
        let hll = HyperLogLog::new(12);
        assert_eq!(format!("{:?}", hll), "HyperLogLog { b: 12 }");
    }
}
<commit_msg>hyperloglog: impl merge<commit_after>use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use std::hash::{Hash, Hasher};

/// A simple implementation of a [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog)
#[derive(Clone)]
pub struct HyperLogLog {
    registers: Vec<u8>,
    b: usize,
}

impl HyperLogLog {
    /// Creates a new, empty HyperLogLog.
    ///
    /// - `b` number of bits used for register selection, number of registers within the
    ///   HyperLogLog will be `2^b`. `b` must be in `[4, 16]`
    ///
    /// Panics when `b` is out of bounds.
    pub fn new(b: usize) -> HyperLogLog {
        assert!(b >= 4);
        assert!(b <= 16);

        let m = (1 as usize) << b;
        let registers = vec![0; m];
        HyperLogLog {
            registers: registers,
            b: b,
        }
    }

    /// Adds an element to the HyperLogLog.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        let mut hasher = DefaultHasher::new();
        obj.hash(&mut hasher);
        let h: u64 = hasher.finish();

        let w = h >> self.b;
        let j = h - (w << self.b);
        let p = w.leading_zeros() + 1 - (self.b as u32);

        let m_old = self.registers[j as usize];
        self.registers[j as usize] = cmp::max(m_old, p as u8);
    }

    /// Guess the number of unique elements seen by the HyperLogLog.
    pub fn count(&self) -> usize {
        let m = self.registers.len() as f64;

        let z = 1f64 /
            self.registers
                .iter()
                .map(|&x| 2f64.powi(-(x as i32)))
                .sum::<f64>();

        let am = if m >= 128. {
            0.7213 / (1. + 1.079 / m)
        } else if m >= 64. {
            0.709
        } else if m >= 32. {
            0.697
        } else {
            0.673
        };

        let e = am * m * m * z;

        let e_star = if e <= 5. / 2. * m {
            // small range correction
            let v = self.registers.iter().filter(|&&x| x == 0).count();
            if v != 0 {
                m * (m / (v as f64)).ln()
            } else {
                e
            }
        } else if e <= 1. / 30. * 2f64.powi(32) {
            // intermediate range => no correction
            e
        } else {
            // large range correction
            -2f64.powi(32) * (1. - e / 2f64.powi(32)).ln()
        };

        e_star as usize
    }

    /// Merge w/ another HyperLogLog.
    ///
    /// This HyperLogLog will then have the same state as if all elements seen by `other` where
    /// directly added to `self`.
    ///
    /// Panics when `b` parameter of `self` and `other` do not match.
    pub fn merge(&mut self, other: &HyperLogLog) {
        assert_eq!(self.b, other.b);

        self.registers = self.registers
            .iter()
            .zip(other.registers.iter())
            .map(|x| cmp::max(x.0, x.1))
            .cloned()
            .collect();
    }

    /// Empties the HyperLogLog.
    pub fn clear(&mut self) {
        self.registers = vec![0; self.registers.len()];
    }

    /// Checks whether the HyperLogLog has never seen an element.
    pub fn is_empty(&self) -> bool {
        self.registers.iter().all(|&x| x == 0)
    }
}

impl fmt::Debug for HyperLogLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "HyperLogLog {{ b: {} }}", self.b)
    }
}

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

    #[test]
    fn empty() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn add_b4_n1k() {
        let mut hll = HyperLogLog::new(4);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 571);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n1k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 966);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n1k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 984);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 998);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n10k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10196);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n10k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10303);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n10k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10055);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n100k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..100000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 100551);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1m() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 1000226);
        assert!(!hll.is_empty());
    }

    #[test]
    fn clear() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        hll.clear();
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn clone() {
        let mut hll1 = HyperLogLog::new(12);
        for i in 0..500 {
            hll1.add(&i);
        }
        let c1a = hll1.count();

        let hll2 = hll1.clone();
        assert_eq!(hll2.count(), c1a);

        for i in 501..1000 {
            hll1.add(&i);
        }
        let c1b = hll1.count();
        assert_ne!(c1b, c1a);
        assert_eq!(hll2.count(), c1a);
    }

    #[test]
    fn merge() {
        let mut hll1 = HyperLogLog::new(12);
        let mut hll2 = HyperLogLog::new(12);
        let mut hll = HyperLogLog::new(12);
        for i in 0..500 {
            hll.add(&i);
            hll1.add(&i);
        }
        for i in 501..1000 {
            hll.add(&i);
            hll2.add(&i);
        }
        assert_ne!(hll.count(), hll1.count());
        assert_ne!(hll.count(), hll2.count());

        hll1.merge(&hll2);
        assert_eq!(hll.count(), hll1.count());
    }

    #[test]
    fn debug() {
        let hll = HyperLogLog::new(12);
        assert_eq!(format!("{:?}", hll), "HyperLogLog { b: 12 }");
    }
}
<|endoftext|>


<commit_before>extern crate openssl;

use std::io;
use std::fmt;
use std::error;
use self::openssl::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslMethod, SslConnectorBuilder, SslConnector, SslAcceptorBuilder,
                         SslAcceptor, MidHandshakeSslStream, SslContextBuilder, ShutdownResult};
use self::openssl::x509::X509;

use Protocol;

fn supported_protocols(protocols: &[Protocol], ctx: &mut SslContextBuilder) {
    // This constant is only defined on OpenSSL 1.0.2 and above, so manually do it.
    let ssl_op_no_ssl_mask = ssl::SSL_OP_NO_SSLV2 | ssl::SSL_OP_NO_SSLV3 |
        ssl::SSL_OP_NO_TLSV1 | ssl::SSL_OP_NO_TLSV1_1 | ssl::SSL_OP_NO_TLSV1_2;

    ctx.clear_options(ssl_op_no_ssl_mask);
    let mut options = ssl_op_no_ssl_mask;
    for protocol in protocols {
        let op = match *protocol {
            Protocol::Sslv3 => ssl::SSL_OP_NO_SSLV3,
            Protocol::Tlsv10 => ssl::SSL_OP_NO_TLSV1,
            Protocol::Tlsv11 => ssl::SSL_OP_NO_TLSV1_1,
            Protocol::Tlsv12 => ssl::SSL_OP_NO_TLSV1_2,
            Protocol::__NonExhaustive => unreachable!(),
        };
        options &= !op;
    }
    ctx.set_options(options);
}

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Pkcs12(pkcs12::ParsedPkcs12);

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));
        Ok(Pkcs12(parsed))
    }
}

pub struct Certificate(X509);

impl Certificate {
    pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = try!(X509::from_der(buf));
        Ok(Certificate(cert))
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::SetupFailure(e) => {
                HandshakeError::Failure(Error(ssl::Error::Ssl(e)))
            }
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e.into_error())),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

pub struct TlsConnectorBuilder(SslConnectorBuilder);

impl TlsConnectorBuilder {
    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        let ctx = self.0.builder_mut();
        // FIXME clear chain certs to clean up if called multiple times
        try!(ctx.set_certificate(&pkcs12.0.cert));
        try!(ctx.set_private_key(&pkcs12.0.pkey));
        try!(ctx.check_private_key());
        for cert in pkcs12.0.chain {
            try!(ctx.add_extra_chain_cert(cert));
        }
        Ok(())
    }

    pub fn add_root_certificate(&mut self, cert: Certificate) -> Result<(), Error> {
        try!(self.0.builder_mut().cert_store_mut().add_cert(cert.0));
        Ok(())
    }

    pub fn supported_protocols(&mut self, protocols: &[Protocol]) -> Result<(), Error> {
        supported_protocols(protocols, self.0.builder_mut());
        Ok(())
    }

    pub fn build(self) -> Result<TlsConnector, Error> {
        Ok(TlsConnector(self.0.build()))
    }
}

pub struct TlsConnector(SslConnector);

impl TlsConnector {
    pub fn builder() -> Result<TlsConnectorBuilder, Error> {
        let builder = try!(SslConnectorBuilder::new(SslMethod::tls()));
        Ok(TlsConnectorBuilder(builder))
    }

    pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(self.0.connect(domain, stream));
        Ok(TlsStream(s))
    }

    pub fn connect_no_domain<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(self.0.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `TlsConnectorBuilder`.
pub trait TlsConnectorBuilderExt {
    /// Returns a shared reference to the inner `SslConnectorBuilder`.
    fn builder(&self) -> &SslConnectorBuilder;

    /// Returns a mutable reference to the inner `SslConnectorBuilder`.
    fn builder_mut(&mut self) -> &mut SslConnectorBuilder;
}

impl TlsConnectorBuilderExt for ::TlsConnectorBuilder {
    fn builder(&self) -> &SslConnectorBuilder {
        &(self.0).0
    }

    fn builder_mut(&mut self) -> &mut SslConnectorBuilder {
        &mut (self.0).0
    }
}

pub struct TlsAcceptorBuilder(SslAcceptorBuilder);

impl TlsAcceptorBuilder {
    pub fn supported_protocols(&mut self, protocols: &[Protocol]) -> Result<(), Error> {
        supported_protocols(protocols, self.0.builder_mut());
        Ok(())
    }

    pub fn build(self) -> Result<TlsAcceptor, Error> {
        Ok(TlsAcceptor(self.0.build()))
    }
}

pub struct TlsAcceptor(SslAcceptor);

impl TlsAcceptor {
    pub fn builder(pkcs12: Pkcs12) -> Result<TlsAcceptorBuilder, Error> {
        let builder = try!(SslAcceptorBuilder::mozilla_intermediate(
            SslMethod::tls(), &pkcs12.0.pkey, &pkcs12.0.cert, &pkcs12.0.chain));
        Ok(TlsAcceptorBuilder(builder))
    }

    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(self.0.accept(stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `TlsAcceptorBuilder`.
pub trait TlsAcceptorBuilderExt {
    /// Returns a shared reference to the inner `SslAcceptorBuilder`.
    fn builder(&self) -> &SslAcceptorBuilder;

    /// Returns a mutable reference to the inner `SslAcceptorBuilder`.
    fn builder_mut(&mut self) -> &mut SslAcceptorBuilder;
}

impl TlsAcceptorBuilderExt for ::TlsAcceptorBuilder {
    fn builder(&self) -> &SslAcceptorBuilder {
        &(self.0).0
    }

    fn builder_mut(&mut self) -> &mut SslAcceptorBuilder {
        &mut (self.0).0
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        loop {
            match self.0.shutdown() {
                Ok(ShutdownResult::Sent) => {},
                Ok(ShutdownResult::Received) => break,
                Err(ssl::Error::ZeroReturn) => break,
                Err(ssl::Error::Stream(e)) => return Err(e),
                Err(ssl::Error::WantRead(e)) => return Err(e),
                Err(ssl::Error::WantWrite(e)) => return Err(e),
                Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
            }
        }

        Ok(())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}

/// OpenSSL-specific extensions to `Error`
pub trait ErrorExt {
    /// Extract the underlying OpenSSL error for inspection.
    fn openssl_error(&self) -> &ssl::Error;
}

impl ErrorExt for ::Error {
    fn openssl_error(&self) -> &ssl::Error {
        &(self.0).0
    }
}
<commit_msg>Don't try to do a full shutdown on OpenSSL<commit_after>extern crate openssl;

use std::io;
use std::fmt;
use std::error;
use self::openssl::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslMethod, SslConnectorBuilder, SslConnector, SslAcceptorBuilder,
                         SslAcceptor, MidHandshakeSslStream, SslContextBuilder, ShutdownResult};
use self::openssl::x509::X509;

use Protocol;

fn supported_protocols(protocols: &[Protocol], ctx: &mut SslContextBuilder) {
    // This constant is only defined on OpenSSL 1.0.2 and above, so manually do it.
    let ssl_op_no_ssl_mask = ssl::SSL_OP_NO_SSLV2 | ssl::SSL_OP_NO_SSLV3 | ssl::SSL_OP_NO_TLSV1 |
                             ssl::SSL_OP_NO_TLSV1_1 |
                             ssl::SSL_OP_NO_TLSV1_2;

    ctx.clear_options(ssl_op_no_ssl_mask);
    let mut options = ssl_op_no_ssl_mask;
    for protocol in protocols {
        let op = match *protocol {
            Protocol::Sslv3 => ssl::SSL_OP_NO_SSLV3,
            Protocol::Tlsv10 => ssl::SSL_OP_NO_TLSV1,
            Protocol::Tlsv11 => ssl::SSL_OP_NO_TLSV1_1,
            Protocol::Tlsv12 => ssl::SSL_OP_NO_TLSV1_2,
            Protocol::__NonExhaustive => unreachable!(),
        };
        options &= !op;
    }
    ctx.set_options(options);
}

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Pkcs12(pkcs12::ParsedPkcs12);

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));
        Ok(Pkcs12(parsed))
    }
}

pub struct Certificate(X509);

impl Certificate {
    pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = try!(X509::from_der(buf));
        Ok(Certificate(cert))
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::SetupFailure(e) => {
                HandshakeError::Failure(Error(ssl::Error::Ssl(e)))
            }
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e.into_error())),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

pub struct TlsConnectorBuilder(SslConnectorBuilder);

impl TlsConnectorBuilder {
    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        let ctx = self.0.builder_mut();
        // FIXME clear chain certs to clean up if called multiple times
        try!(ctx.set_certificate(&pkcs12.0.cert));
        try!(ctx.set_private_key(&pkcs12.0.pkey));
        try!(ctx.check_private_key());
        for cert in pkcs12.0.chain {
            try!(ctx.add_extra_chain_cert(cert));
        }
        Ok(())
    }

    pub fn add_root_certificate(&mut self, cert: Certificate) -> Result<(), Error> {
        try!(self.0
                 .builder_mut()
                 .cert_store_mut()
                 .add_cert(cert.0));
        Ok(())
    }

    pub fn supported_protocols(&mut self, protocols: &[Protocol]) -> Result<(), Error> {
        supported_protocols(protocols, self.0.builder_mut());
        Ok(())
    }

    pub fn build(self) -> Result<TlsConnector, Error> {
        Ok(TlsConnector(self.0.build()))
    }
}

pub struct TlsConnector(SslConnector);

impl TlsConnector {
    pub fn builder() -> Result<TlsConnectorBuilder, Error> {
        let builder = try!(SslConnectorBuilder::new(SslMethod::tls()));
        Ok(TlsConnectorBuilder(builder))
    }

    pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(self.0.connect(domain, stream));
        Ok(TlsStream(s))
    }

    pub fn connect_no_domain<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(self.0.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `TlsConnectorBuilder`.
pub trait TlsConnectorBuilderExt {
    /// Returns a shared reference to the inner `SslConnectorBuilder`.
    fn builder(&self) -> &SslConnectorBuilder;

    /// Returns a mutable reference to the inner `SslConnectorBuilder`.
    fn builder_mut(&mut self) -> &mut SslConnectorBuilder;
}

impl TlsConnectorBuilderExt for ::TlsConnectorBuilder {
    fn builder(&self) -> &SslConnectorBuilder {
        &(self.0).0
    }

    fn builder_mut(&mut self) -> &mut SslConnectorBuilder {
        &mut (self.0).0
    }
}

pub struct TlsAcceptorBuilder(SslAcceptorBuilder);

impl TlsAcceptorBuilder {
    pub fn supported_protocols(&mut self, protocols: &[Protocol]) -> Result<(), Error> {
        supported_protocols(protocols, self.0.builder_mut());
        Ok(())
    }

    pub fn build(self) -> Result<TlsAcceptor, Error> {
        Ok(TlsAcceptor(self.0.build()))
    }
}

pub struct TlsAcceptor(SslAcceptor);

impl TlsAcceptor {
    pub fn builder(pkcs12: Pkcs12) -> Result<TlsAcceptorBuilder, Error> {
        let builder = try!(SslAcceptorBuilder::mozilla_intermediate(SslMethod::tls(),
                                                                    &pkcs12.0.pkey,
                                                                    &pkcs12.0.cert,
                                                                    &pkcs12.0.chain));
        Ok(TlsAcceptorBuilder(builder))
    }

    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(self.0.accept(stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `TlsAcceptorBuilder`.
pub trait TlsAcceptorBuilderExt {
    /// Returns a shared reference to the inner `SslAcceptorBuilder`.
    fn builder(&self) -> &SslAcceptorBuilder;

    /// Returns a mutable reference to the inner `SslAcceptorBuilder`.
    fn builder_mut(&mut self) -> &mut SslAcceptorBuilder;
}

impl TlsAcceptorBuilderExt for ::TlsAcceptorBuilder {
    fn builder(&self) -> &SslAcceptorBuilder {
        &(self.0).0
    }

    fn builder_mut(&mut self) -> &mut SslAcceptorBuilder {
        &mut (self.0).0
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        match self.0.shutdown() {
            Ok(_) |
            Err(ssl::Error::ZeroReturn) => Ok(()),
            Err(ssl::Error::Stream(e)) |
            Err(ssl::Error::WantRead(e)) |
            Err(ssl::Error::WantWrite(e)) => Err(e),
            Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
        }
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}

/// OpenSSL-specific extensions to `Error`
pub trait ErrorExt {
    /// Extract the underlying OpenSSL error for inspection.
    fn openssl_error(&self) -> &ssl::Error;
}

impl ErrorExt for ::Error {
    fn openssl_error(&self) -> &ssl::Error {
        &(self.0).0
    }
}
<|endoftext|>


<commit_before>extern crate openssl;
extern crate openssl_verify;

use std::io;
use std::fmt;
use std::error;
use self::openssl::crypto::pkey::PKey;
use self::openssl::crypto::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslContext, SslMethod, SSL_VERIFY_PEER, IntoSsl,
                         MidHandshakeSslStream};
use self::openssl::x509::X509;
use self::openssl_verify::verify_callback;

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Pkcs12 {
    cert: X509,
    pkey: PKey,
    chain: Vec<X509>,
}

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));

        Ok(Pkcs12 {
            cert: parsed.cert,
            pkey: parsed.pkey,
            chain: parsed.chain,
        })
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

fn ctx() -> Result<SslContext, Error> {
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ctx.set_default_verify_paths());
    Ok(ctx)
}

pub struct ClientBuilder(SslContext);

impl ClientBuilder {
    pub fn new() -> Result<ClientBuilder, Error> {
        ctx().map(ClientBuilder)
    }

    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        // FIXME clear chain certs to clean up if called multiple times
        try!(self.ctx.set_certificate(&pkcs12.cert));
        try!(self.ctx.set_private_key(&pkcs12.pkey));
        try!(self.ctx.check_private_key());
        for cert in &pkcs12.chain {
            try!(self.ctx.add_extra_chain_cert(&cert));
        }
        Ok(())
    }

    pub fn handshake<S>(&self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut ssl = try!(self.0.into_ssl());
        try!(ssl.set_hostname(domain));
        let domain = domain.to_owned();
        ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify_callback(&domain, p, x));

        let s = try!(ssl::SslStream::connect(ssl, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ClientBuilder`.
pub trait ClientBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ClientBuilderExt for ::ClientBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct ServerBuilder(SslContext);

impl ServerBuilder {
    pub fn new(pkcs12: Pkcs12) -> Result<ServerBuilder, Error> {
        let mut ctx = try!(ctx());
        try!(ctx.set_certificate(&pkcs12.cert));
        try!(ctx.set_private_key(&pkcs12.pkey));
        try!(ctx.check_private_key());
        for cert in &pkcs12.chain {
            try!(ctx.add_extra_chain_cert(&cert));
        }
        Ok(ServerBuilder(ctx))
    }

    pub fn handshake<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(ssl::SslStream::accept(&self.0, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ServerBuilder`.
pub trait ServerBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ServerBuilderExt for ::ServerBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}
<commit_msg>Clean up openssl impl<commit_after>extern crate openssl;
extern crate openssl_verify;

use std::io;
use std::fmt;
use std::error;
use self::openssl::crypto::pkey::PKey;
use self::openssl::crypto::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslContext, SslMethod, SSL_VERIFY_PEER, IntoSsl,
                         MidHandshakeSslStream};
use self::openssl::x509::X509;
use self::openssl_verify::verify_callback;

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Pkcs12(pkcs12::ParsedPkcs12);

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));
        Ok(Pkcs12(parsed))
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

fn ctx() -> Result<SslContext, Error> {
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ctx.set_default_verify_paths());
    Ok(ctx)
}

pub struct ClientBuilder(SslContext);

impl ClientBuilder {
    pub fn new() -> Result<ClientBuilder, Error> {
        ctx().map(ClientBuilder)
    }

    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        // FIXME clear chain certs to clean up if called multiple times
        try!(self.ctx.set_certificate(&pkcs12.0.cert));
        try!(self.ctx.set_private_key(&pkcs12.0.pkey));
        try!(self.ctx.check_private_key());
        for cert in &pkcs12.0.chain {
            try!(self.ctx.add_extra_chain_cert(&cert));
        }
        Ok(())
    }

    pub fn handshake<S>(&self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut ssl = try!(self.0.into_ssl());
        try!(ssl.set_hostname(domain));
        let domain = domain.to_owned();
        ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify_callback(&domain, p, x));

        let s = try!(ssl::SslStream::connect(ssl, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ClientBuilder`.
pub trait ClientBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ClientBuilderExt for ::ClientBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct ServerBuilder(SslContext);

impl ServerBuilder {
    pub fn new(pkcs12: Pkcs12) -> Result<ServerBuilder, Error> {
        let mut ctx = try!(ctx());
        try!(ctx.set_certificate(&pkcs12.0.cert));
        try!(ctx.set_private_key(&pkcs12.0.pkey));
        try!(ctx.check_private_key());
        for cert in &pkcs12.0.chain {
            try!(ctx.add_extra_chain_cert(&cert));
        }
        Ok(ServerBuilder(ctx))
    }

    pub fn handshake<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(ssl::SslStream::accept(&self.0, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ServerBuilder`.
pub trait ServerBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ServerBuilderExt for ::ServerBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}
<|endoftext|>


<commit_before>use buffer::Line;

#[deriving(Copy, Show)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    pub fn is_right(&self) -> bool {
        match *self {
            Direction::Right => true,
            _                => false
        }
    }
    pub fn is_left(&self) -> bool {
        match *self {
            Direction::Left => true,
            _               => false
        }
    }
}

pub struct Cursor<'c> {
    /// The number of bytes the cursor is along the line. This must always be on a character
    /// boundary.
    pub offset: uint,
    line: &'c mut Line,
}

impl<'c> Cursor<'c> {
    /// Create a new cursor instance
    pub fn new(line: &'c mut Line, offset: uint) -> Cursor<'c> {
        let mut cursor = Cursor {
            offset: offset,
            line: line,
        };

        // check that the current offset is longer than the length of the line
        let offset = cursor.get_offset();
        let line_length = cursor.get_line().len();
        if offset > line_length {
            cursor.set_offset(line_length);
        }
        cursor
    }

    pub fn get_position(&self) -> (uint, uint) {
        (self.offset, self.get_linenum())
    }

    pub fn get_linenum(&self) -> uint {
        self.line.linenum
    }

    pub fn get_offset(&self) -> uint {
        self.offset
    }

    pub fn get_visible_offset(&self) -> uint {
        self.get_line().data.slice_to(self.get_offset()).width(false)
    }

    pub fn set_offset(&mut self, offset: uint) {
        self.offset = offset;
    }

    /// Moves the cursor forward one character.
    ///
    /// This can’t simply be `self.offset += 1`, because not all UTF-8 codepoints are exactly one
    /// byte long. This function calculates the width of the current codepoint and increments the
    /// offset by that width, ensuring that the cursor will always be on a character boundary.
    pub fn inc_offset(&mut self) {
        let range = self.get_line().data.char_range_at(self.offset);
        self.set_offset(range.next);
    }

    /// Moves the cursor back one character.
    ///
    /// See `inc_offset` for why this method is needed.
    pub fn dec_offset(&mut self) {
        let range = self.get_line().data.char_range_at_reverse(self.offset);
        self.set_offset(range.next);
    }

    pub fn get_line(&self) -> &Line {
        &*self.line
    }

    pub fn get_line_mut(&mut self) -> &mut Line {
        self.line
    }

    pub fn get_line_length(&self) -> uint {
        self.get_line().len()
    }

    pub fn delete_backward_char(&mut self) {
        let offset = self.get_offset();
        let range = self.get_line().data.char_range_at_reverse(self.offset);
        let back = self.offset - range.next;
        self.dec_offset();
        self.get_line_mut().data.remove(offset-back);
    }

    pub fn delete_forward_char(&mut self) {
        let offset = self.get_offset();
        self.get_line_mut().data.remove(offset);
    }

    pub fn insert_char(&mut self, ch: char) {
        let offset = self.get_offset();
        self.get_line_mut().data.insert(offset, ch);
        self.inc_offset();
    }

    pub fn move_right(&mut self) {
        let line_len = self.get_line().len();
        let current_offset = self.get_offset();
        if line_len > current_offset {
            self.inc_offset();
        }
    }

    pub fn move_left(&mut self) {
        let current_offset = self.get_offset();
        if current_offset > 0 {
            self.dec_offset();
        }
    }

    pub fn get_status_text(&self) -> String {
        let (offset, line_num) = self.get_position();
        format!("({}, {})", offset, line_num)
    }
}

#[cfg(test)]
mod tests {

    use cursor::Cursor;
    use buffer::Line;
    use utils::data_from_str;

    fn setup_cursor<F>(mut f: F) where F: FnMut(Cursor) {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 0);
        f(cursor);
    }

    #[test]
    fn test_moving_right() {
        setup_cursor( |mut cursor| {
            assert_eq!(cursor.offset, 0);
            cursor.move_right();
            assert_eq!(cursor.offset, 1);
        });
    }

    #[test]
    fn test_moving_left() {
        setup_cursor( |mut cursor| {
            cursor.set_offset(1);

            assert_eq!(cursor.offset, 1);
            cursor.move_left();
            assert_eq!(cursor.offset, 0);
        });
    }

    #[test]
    fn test_get_position() {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 0);
        assert_eq!(cursor.get_position(), (0, 1));
    }

    #[test]
    fn test_get_linenum() {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 0);

        assert_eq!(cursor.get_linenum(), 1);
    }

    #[test]
    fn test_get_offset() {
        setup_cursor( |cursor| {
            assert_eq!(cursor.get_offset(), 0)
        });
    }

    #[test]
    fn test_set_offset() {
        setup_cursor( |mut cursor| {
            cursor.set_offset(3);

            assert_eq!(cursor.offset, 3);
        });
    }

    #[test]
    fn test_moving_to_end_of_line_when_set() {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 10);

        assert_eq!(cursor.offset, 4);
    }

    #[test]
    fn test_get_line_length() {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 0);

        assert_eq!(cursor.get_line_length(), 4);
    }

    #[test]
    fn test_delete_backward_char() {
        let ref mut line = Line::new(data_from_str("test"), 1);

        {
            let mut cursor = Cursor::new(line, 1);
            cursor.delete_backward_char();
        }

        assert_eq!(line.data, data_from_str("est"));
    }

    #[test]
    fn test_delete_forward_char() {
        let ref mut line = Line::new(data_from_str("test"), 1);

        {
            let mut cursor = Cursor::new(line, 0);
            cursor.delete_forward_char();
        }

        assert_eq!(line.data, data_from_str("est"));
    }

    #[test]
    fn test_insert_char() {
        let ref mut line = Line::new(data_from_str("test"), 1);

        {
            let mut cursor = Cursor::new(line, 0);
            cursor.insert_char('x');
        }

        assert_eq!(line.data, data_from_str("xtest"));
    }

    #[test]
    fn test_get_status_text() {
        setup_cursor( |cursor| {
            assert_eq!(cursor.get_status_text(), "(0, 1)".to_string());
        } );
    }

}
<commit_msg>Use 1-based indices for the line/column indicator in the status bar<commit_after>use buffer::Line;

#[deriving(Copy, Show)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    pub fn is_right(&self) -> bool {
        match *self {
            Direction::Right => true,
            _                => false
        }
    }
    pub fn is_left(&self) -> bool {
        match *self {
            Direction::Left => true,
            _               => false
        }
    }
}

pub struct Cursor<'c> {
    /// The number of bytes the cursor is along the line. This must always be on a character
    /// boundary.
    pub offset: uint,
    line: &'c mut Line,
}

impl<'c> Cursor<'c> {
    /// Create a new cursor instance
    pub fn new(line: &'c mut Line, offset: uint) -> Cursor<'c> {
        let mut cursor = Cursor {
            offset: offset,
            line: line,
        };

        // check that the current offset is longer than the length of the line
        let offset = cursor.get_offset();
        let line_length = cursor.get_line().len();
        if offset > line_length {
            cursor.set_offset(line_length);
        }
        cursor
    }

    pub fn get_position(&self) -> (uint, uint) {
        (self.offset, self.get_linenum())
    }

    pub fn get_linenum(&self) -> uint {
        self.line.linenum
    }

    pub fn get_offset(&self) -> uint {
        self.offset
    }

    pub fn get_visible_offset(&self) -> uint {
        self.get_line().data.slice_to(self.get_offset()).width(false)
    }

    pub fn set_offset(&mut self, offset: uint) {
        self.offset = offset;
    }

    /// Moves the cursor forward one character.
    ///
    /// This can’t simply be `self.offset += 1`, because not all UTF-8 codepoints are exactly one
    /// byte long. This function calculates the width of the current codepoint and increments the
    /// offset by that width, ensuring that the cursor will always be on a character boundary.
    pub fn inc_offset(&mut self) {
        let range = self.get_line().data.char_range_at(self.offset);
        self.set_offset(range.next);
    }

    /// Moves the cursor back one character.
    ///
    /// See `inc_offset` for why this method is needed.
    pub fn dec_offset(&mut self) {
        let range = self.get_line().data.char_range_at_reverse(self.offset);
        self.set_offset(range.next);
    }

    pub fn get_line(&self) -> &Line {
        &*self.line
    }

    pub fn get_line_mut(&mut self) -> &mut Line {
        self.line
    }

    pub fn get_line_length(&self) -> uint {
        self.get_line().len()
    }

    pub fn delete_backward_char(&mut self) {
        let offset = self.get_offset();
        let range = self.get_line().data.char_range_at_reverse(self.offset);
        let back = self.offset - range.next;
        self.dec_offset();
        self.get_line_mut().data.remove(offset-back);
    }

    pub fn delete_forward_char(&mut self) {
        let offset = self.get_offset();
        self.get_line_mut().data.remove(offset);
    }

    pub fn insert_char(&mut self, ch: char) {
        let offset = self.get_offset();
        self.get_line_mut().data.insert(offset, ch);
        self.inc_offset();
    }

    pub fn move_right(&mut self) {
        let line_len = self.get_line().len();
        let current_offset = self.get_offset();
        if line_len > current_offset {
            self.inc_offset();
        }
    }

    pub fn move_left(&mut self) {
        let current_offset = self.get_offset();
        if current_offset > 0 {
            self.dec_offset();
        }
    }

    pub fn get_status_text(&self) -> String {
        let (offset, line_num) = self.get_position();
        format!("({}, {})", offset + 1, line_num + 1)
    }
}

#[cfg(test)]
mod tests {

    use cursor::Cursor;
    use buffer::Line;
    use utils::data_from_str;

    fn setup_cursor<F>(mut f: F) where F: FnMut(Cursor) {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 0);
        f(cursor);
    }

    #[test]
    fn test_moving_right() {
        setup_cursor( |mut cursor| {
            assert_eq!(cursor.offset, 0);
            cursor.move_right();
            assert_eq!(cursor.offset, 1);
        });
    }

    #[test]
    fn test_moving_left() {
        setup_cursor( |mut cursor| {
            cursor.set_offset(1);

            assert_eq!(cursor.offset, 1);
            cursor.move_left();
            assert_eq!(cursor.offset, 0);
        });
    }

    #[test]
    fn test_get_position() {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 0);
        assert_eq!(cursor.get_position(), (0, 1));
    }

    #[test]
    fn test_get_linenum() {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 0);

        assert_eq!(cursor.get_linenum(), 1);
    }

    #[test]
    fn test_get_offset() {
        setup_cursor( |cursor| {
            assert_eq!(cursor.get_offset(), 0)
        });
    }

    #[test]
    fn test_set_offset() {
        setup_cursor( |mut cursor| {
            cursor.set_offset(3);

            assert_eq!(cursor.offset, 3);
        });
    }

    #[test]
    fn test_moving_to_end_of_line_when_set() {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 10);

        assert_eq!(cursor.offset, 4);
    }

    #[test]
    fn test_get_line_length() {
        let ref mut line = Line::new(data_from_str("test"), 1);
        let cursor = Cursor::new(line, 0);

        assert_eq!(cursor.get_line_length(), 4);
    }

    #[test]
    fn test_delete_backward_char() {
        let ref mut line = Line::new(data_from_str("test"), 1);

        {
            let mut cursor = Cursor::new(line, 1);
            cursor.delete_backward_char();
        }

        assert_eq!(line.data, data_from_str("est"));
    }

    #[test]
    fn test_delete_forward_char() {
        let ref mut line = Line::new(data_from_str("test"), 1);

        {
            let mut cursor = Cursor::new(line, 0);
            cursor.delete_forward_char();
        }

        assert_eq!(line.data, data_from_str("est"));
    }

    #[test]
    fn test_insert_char() {
        let ref mut line = Line::new(data_from_str("test"), 1);

        {
            let mut cursor = Cursor::new(line, 0);
            cursor.insert_char('x');
        }

        assert_eq!(line.data, data_from_str("xtest"));
    }

    #[test]
    fn test_get_status_text() {
        setup_cursor( |cursor| {
            assert_eq!(cursor.get_status_text(), "(1, 2)".to_string());
        } );
    }

}
<|endoftext|>