<commit_before>use addressable::Addressable;
use addressable::AddressableUtil;

#[cfg(test)]
use testmemory::TestMemory;

// General information on 65xx: http://en.wikipedia.org/wiki/MOS_Technology_6510
// Web simulator and much info: http://e-tradition.net/bytes/6502/
// Good reference and overview: http://www.obelisk.demon.co.uk/index.html

static NMI_VECTOR: u16 = 0xfffa;
static RESET_VECTOR: u16 = 0xfffc;
static IRQ_VECTOR: u16 = 0xfffe;

enum Operand {
	Implied,							// OPC				// operand implied
	Immediate(u8),						// OPC #$BB			// operand is byte (BB)
	Accumulator,						// OPC A			// operand is AC
	Relative(i8),						// OPC $BB			// branch target is PC + offset (BB), bit 7 signifies negative offset
	Absolute(u16),						// OPC $HHLL		// operand is address $HHLL
	AbsoluteIndexedWithX(u16),			// OPC $HHLL,X		// operand is address $HHLL incremented by X with carry
	AbsoluteIndexedWithY(u16),			// OPC $HHLL,Y		// operand is address $HHLL incremented by Y with carry
	Indirect(u16),						// OPC ($HHLL)		// operand is effective address; effective address is value of address
	ZeroPage(u8),						// OPC $LL			// operand is address $00LL
	ZeroPageIndexedWithX(u8),			// OPC $LL,X		// operand is address $00LL incremented by X, no page transition
	ZeroPageIndexedWithY(u8),			// OPC $LL,Y		// operand is address $00LL incremented by Y, no page transition
	ZeroPageIndexedWithXIndirect(u8),	// OPC ($LL,X)		// operand is effective address; effective address is $00LL incremented by X without carry
	ZeroPageIndirectIndexedWithY(u8),	// OPC ($LL),Y		// operand is effective address incremented by Y with carry; effective address is word at $00LL
}

impl Operand {
	fn indirect<M: Addressable<u16>> (mem: &M, addr: u16) -> u16 {
		// Get a little endian u16 from the given address, simulating the 6502 MSB bug
		// (i.e. take values from $c0ff/$c000 instead of $c0ff/$c100)
		let addr1 = (addr & 0xff00) | (addr+1 & 0x00ff);
		mem.get(addr) as u16 | mem.get(addr1) as u16 << 8
	}

	fn addr<M: Addressable<u16>> (&self, cpu: &Mos6502, mem: &M) -> u16 {
		match *self {
			Implied								=> fail!("mos65xx: Implied operand is never targetted to an address"),
			Immediate(_)						=> fail!("mos65xx: Immediate operand is never targetted to an address"),
			Accumulator							=> fail!("mos65xx: Accumulator operand is never targetted to an address"),
			Relative(offset)					=> cpu.pc + offset as u16,
			Absolute(addr)						=> addr,
			AbsoluteIndexedWithX(addr)			=> addr + cpu.x as u16,
			AbsoluteIndexedWithY(addr)			=> addr + cpu.y as u16,
			Indirect(addr)						=> Operand::indirect(mem, addr),
			ZeroPage(addr)						=> addr as u16,
			ZeroPageIndexedWithX(addr)			=> (addr + cpu.x) as u16,						// no page transition
			ZeroPageIndexedWithY(addr)			=> (addr + cpu.y) as u16,						// no page transition
			ZeroPageIndexedWithXIndirect(addr)	=> mem.get_le((addr + cpu.x) as u16),			// no page transition
			ZeroPageIndirectIndexedWithY(addr)	=> { let iaddr: u16 = mem.get_le(addr as u16); iaddr + cpu.y as u16 },
		}
	}

	fn get<M: Addressable<u16>> (&self, cpu: &Mos6502, mem: &M) -> u8 {
		match *self {
			Implied								=> fail!("mos65xx: Implied operand never has a value"),
			Immediate(val)						=> val,
			Accumulator							=> cpu.ac,
			Relative(_target)					=> fail!("mos65xx: Relative operand never has a value"),
			op									=> { let addr = op.addr(cpu, mem); mem.get(addr) },
		}
	}

	fn set<M: Addressable<u16>> (&self, cpu: &mut Mos6502, mem: &mut M, val: u8) {
		match *self {
			Implied								=> fail!("mos65xx: Implied operand never sets a value"),
			Immediate(_)						=> fail!("mos65xx: Immediate operand never sets a value"),
			Accumulator							=> cpu.ac = val,
			Relative(_target)					=> fail!("mos65xx: Relative operand never sets a value"),
			op									=> { let addr = op.addr(cpu, mem); mem.set(addr, val); },
		}
	}
}

pub struct Mos6502 {
	priv pc: u16,						// program counter
	priv ac: u8,						// accumulator
	priv x: u8,							// x register
	priv y: u8,							// y register
	priv sr: u8,						// status register (NV-BDIZC: Negative, oVerflow, Break, Decimal, Interrupt, Zero, Carry)
	priv sp: u8,						// stack pointer
}

impl Mos6502 {
	pub fn new () -> Mos6502 {
		Mos6502 { pc: 0, ac: 0, x: 0, y: 0, sr: 0, sp: 0 }
	}

	fn get_opcode<M: Addressable<u16>> (&self, mem: &M) -> u8 {
		mem.get(self.pc)
	}

	fn get_argument<M: Addressable<u16>, T: Int> (&self, mem: &M) -> T {
		mem.get_le(self.pc + 1)
	}

	pub fn step<M: Addressable<u16>> (&mut self, mem: &mut M) -> uint {
		// TODO
		0
	}
}

pub struct Mos6510 {
	priv cpu: Mos6502,						// Core CPU
	priv port_ddr: u8,						// CPU port data direction register
	priv port_dat: u8,						// CPU port data register
}

impl Mos6510 {
	pub fn new () -> Mos6510 {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		Mos6510 { cpu: Mos6502::new(), port_ddr: 0, port_dat: 0 }
	}

	pub fn step<M: Addressable<u16>> (&mut self, mem: &mut M) -> uint {
		self.cpu.step(mem)
	}
}

#[test]
fn test_addressing_modes () {
	let mut cpu = Mos6502 { pc: 0x1337, ac: 0x88, x: 0x11, y: 0x22, sr: 0, sp: 0 };
	let mut mem = TestMemory::new::<u16>();
	// Immediate
	assert_eq!(Immediate(0x55).get(&cpu, &mem), 0x55);
	// Accumulator
	assert_eq!(Accumulator.get(&cpu, &mem), 0x88);
	Accumulator.set(&mut cpu, &mut mem, 0x99); assert_eq!(cpu.ac, 0x99);
	// Relative
	assert_eq!(Relative(0x33).addr(&cpu, &mem), 0x136a);
	assert_eq!(Relative(0x99).addr(&cpu, &mem), 0x12d0);
	// Absolute
	assert_eq!(Absolute(0x0123).addr(&cpu, &mem), 0x0123);
	assert_eq!(Absolute(0x0123).get(&cpu, &mem), 0x24);
	Absolute(0x0123).set(&mut cpu, &mut mem, 0x24);
	// AbsoluteIndexedWithX
	assert_eq!(AbsoluteIndexedWithX(0x0123).addr(&cpu, &mem), 0x0134);
	assert_eq!(AbsoluteIndexedWithX(0x0123).get(&cpu, &mem), 0x35);
	AbsoluteIndexedWithX(0x0123).set(&mut cpu, &mut mem, 0x35);
	// AbsoluteIndexedWithY
	assert_eq!(AbsoluteIndexedWithY(0x0123).addr(&cpu, &mem), 0x0145);
	assert_eq!(AbsoluteIndexedWithY(0x0123).get(&cpu, &mem), 0x46);
	AbsoluteIndexedWithY(0x0123).set(&mut cpu, &mut mem, 0x46);
	// Indirect
	assert_eq!(Indirect(0x0123).addr(&cpu, &mem), 0x2524);
	assert_eq!(Indirect(0x0123).get(&cpu, &mem), 0x49);
	Indirect(0x0123).set(&mut cpu, &mut mem, 0x49);
	// ZeroPage
	assert_eq!(ZeroPage(0x12).addr(&cpu, &mem), 0x0012);
	assert_eq!(ZeroPage(0x12).get(&cpu, &mem), 0x12);
	ZeroPage(0x12).set(&mut cpu, &mut mem, 0x12);
	// ZeroPageIndexedWithX
	assert_eq!(ZeroPageIndexedWithX(0x12).addr(&cpu, &mem), 0x0023);
	assert_eq!(ZeroPageIndexedWithX(0x12).get(&cpu, &mem), 0x23);
	ZeroPageIndexedWithX(0x12).set(&mut cpu, &mut mem, 0x23);
	// ZeroPageIndexedWithY
	assert_eq!(ZeroPageIndexedWithY(0x12).addr(&cpu, &mem), 0x0034);
	assert_eq!(ZeroPageIndexedWithY(0x12).get(&cpu, &mem), 0x34);
	ZeroPageIndexedWithY(0x12).set(&mut cpu, &mut mem, 0x34);
	// ZeroPageIndexedWithXIndirect
	assert_eq!(ZeroPageIndexedWithXIndirect(0x12).addr(&cpu, &mem), 0x2423);
	assert_eq!(ZeroPageIndexedWithXIndirect(0x12).get(&cpu, &mem), 0x47);
	ZeroPageIndexedWithXIndirect(0x12).set(&mut cpu, &mut mem, 0x47);
	// ZeroPageIndirectIndexedWithY
	assert_eq!(ZeroPageIndirectIndexedWithY(0x12).addr(&cpu, &mem), 0x1334);
	assert_eq!(ZeroPageIndirectIndexedWithY(0x12).get(&cpu, &mem), 0x47);
	ZeroPageIndirectIndexedWithY(0x12).set(&mut cpu, &mut mem, 0x47);
}

#[test]
fn test_indirect_addressing_bug () {
	let cpu = Mos6502 { pc: 0x1337, ac: 0x88, x: 0x11, y: 0x22, sr: 0, sp: 0 };
	let mem = TestMemory::new::<u16>();
	// Indirect jump to ($c0ff) will get erroneously address from $c0ff/$c000 instead of $c0ff/$c100
	assert_eq!(Indirect(0xc0ff).addr(&cpu, &mem), 0xc0bf);	// must be $c0bf instead of $c1bf
}
<commit_msg>Added comment with link to common processor bugs and caveats<commit_after>use addressable::Addressable;
use addressable::AddressableUtil;

#[cfg(test)]
use testmemory::TestMemory;

// General information on 65xx: http://en.wikipedia.org/wiki/MOS_Technology_6510
// Web simulator and much info: http://e-tradition.net/bytes/6502/
// Good reference and overview: http://www.obelisk.demon.co.uk/index.html
// Processor bugs and caveats : http://www.textfiles.com/apple/6502.bugs.txt

static NMI_VECTOR: u16 = 0xfffa;
static RESET_VECTOR: u16 = 0xfffc;
static IRQ_VECTOR: u16 = 0xfffe;

enum Operand {
	Implied,							// OPC				// operand implied
	Immediate(u8),						// OPC #$BB			// operand is byte (BB)
	Accumulator,						// OPC A			// operand is AC
	Relative(i8),						// OPC $BB			// branch target is PC + offset (BB), bit 7 signifies negative offset
	Absolute(u16),						// OPC $HHLL		// operand is address $HHLL
	AbsoluteIndexedWithX(u16),			// OPC $HHLL,X		// operand is address $HHLL incremented by X with carry
	AbsoluteIndexedWithY(u16),			// OPC $HHLL,Y		// operand is address $HHLL incremented by Y with carry
	Indirect(u16),						// OPC ($HHLL)		// operand is effective address; effective address is value of address
	ZeroPage(u8),						// OPC $LL			// operand is address $00LL
	ZeroPageIndexedWithX(u8),			// OPC $LL,X		// operand is address $00LL incremented by X, no page transition
	ZeroPageIndexedWithY(u8),			// OPC $LL,Y		// operand is address $00LL incremented by Y, no page transition
	ZeroPageIndexedWithXIndirect(u8),	// OPC ($LL,X)		// operand is effective address; effective address is $00LL incremented by X without carry
	ZeroPageIndirectIndexedWithY(u8),	// OPC ($LL),Y		// operand is effective address incremented by Y with carry; effective address is word at $00LL
}

impl Operand {
	fn indirect<M: Addressable<u16>> (mem: &M, addr: u16) -> u16 {
		// Get a little endian u16 from the given address, simulating the 6502 MSB bug
		// (i.e. take values from $c0ff/$c000 instead of $c0ff/$c100)
		let addr1 = (addr & 0xff00) | (addr+1 & 0x00ff);
		mem.get(addr) as u16 | mem.get(addr1) as u16 << 8
	}

	fn addr<M: Addressable<u16>> (&self, cpu: &Mos6502, mem: &M) -> u16 {
		match *self {
			Implied								=> fail!("mos65xx: Implied operand is never targetted to an address"),
			Immediate(_)						=> fail!("mos65xx: Immediate operand is never targetted to an address"),
			Accumulator							=> fail!("mos65xx: Accumulator operand is never targetted to an address"),
			Relative(offset)					=> cpu.pc + offset as u16,
			Absolute(addr)						=> addr,
			AbsoluteIndexedWithX(addr)			=> addr + cpu.x as u16,
			AbsoluteIndexedWithY(addr)			=> addr + cpu.y as u16,
			Indirect(addr)						=> Operand::indirect(mem, addr),
			ZeroPage(addr)						=> addr as u16,
			ZeroPageIndexedWithX(addr)			=> (addr + cpu.x) as u16,						// no page transition
			ZeroPageIndexedWithY(addr)			=> (addr + cpu.y) as u16,						// no page transition
			ZeroPageIndexedWithXIndirect(addr)	=> mem.get_le((addr + cpu.x) as u16),			// no page transition
			ZeroPageIndirectIndexedWithY(addr)	=> { let iaddr: u16 = mem.get_le(addr as u16); iaddr + cpu.y as u16 },
		}
	}

	fn get<M: Addressable<u16>> (&self, cpu: &Mos6502, mem: &M) -> u8 {
		match *self {
			Implied								=> fail!("mos65xx: Implied operand never has a value"),
			Immediate(val)						=> val,
			Accumulator							=> cpu.ac,
			Relative(_target)					=> fail!("mos65xx: Relative operand never has a value"),
			op									=> { let addr = op.addr(cpu, mem); mem.get(addr) },
		}
	}

	fn set<M: Addressable<u16>> (&self, cpu: &mut Mos6502, mem: &mut M, val: u8) {
		match *self {
			Implied								=> fail!("mos65xx: Implied operand never sets a value"),
			Immediate(_)						=> fail!("mos65xx: Immediate operand never sets a value"),
			Accumulator							=> cpu.ac = val,
			Relative(_target)					=> fail!("mos65xx: Relative operand never sets a value"),
			op									=> { let addr = op.addr(cpu, mem); mem.set(addr, val); },
		}
	}
}

pub struct Mos6502 {
	priv pc: u16,						// program counter
	priv ac: u8,						// accumulator
	priv x: u8,							// x register
	priv y: u8,							// y register
	priv sr: u8,						// status register (NV-BDIZC: Negative, oVerflow, Break, Decimal, Interrupt, Zero, Carry)
	priv sp: u8,						// stack pointer
}

impl Mos6502 {
	pub fn new () -> Mos6502 {
		Mos6502 { pc: 0, ac: 0, x: 0, y: 0, sr: 0, sp: 0 }
	}

	fn get_opcode<M: Addressable<u16>> (&self, mem: &M) -> u8 {
		mem.get(self.pc)
	}

	fn get_argument<M: Addressable<u16>, T: Int> (&self, mem: &M) -> T {
		mem.get_le(self.pc + 1)
	}

	pub fn step<M: Addressable<u16>> (&mut self, mem: &mut M) -> uint {
		// TODO
		0
	}
}

pub struct Mos6510 {
	priv cpu: Mos6502,						// Core CPU
	priv port_ddr: u8,						// CPU port data direction register
	priv port_dat: u8,						// CPU port data register
}

impl Mos6510 {
	pub fn new () -> Mos6510 {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		Mos6510 { cpu: Mos6502::new(), port_ddr: 0, port_dat: 0 }
	}

	pub fn step<M: Addressable<u16>> (&mut self, mem: &mut M) -> uint {
		self.cpu.step(mem)
	}
}

#[test]
fn test_addressing_modes () {
	let mut cpu = Mos6502 { pc: 0x1337, ac: 0x88, x: 0x11, y: 0x22, sr: 0, sp: 0 };
	let mut mem = TestMemory::new::<u16>();
	// Immediate
	assert_eq!(Immediate(0x55).get(&cpu, &mem), 0x55);
	// Accumulator
	assert_eq!(Accumulator.get(&cpu, &mem), 0x88);
	Accumulator.set(&mut cpu, &mut mem, 0x99); assert_eq!(cpu.ac, 0x99);
	// Relative
	assert_eq!(Relative(0x33).addr(&cpu, &mem), 0x136a);
	assert_eq!(Relative(0x99).addr(&cpu, &mem), 0x12d0);
	// Absolute
	assert_eq!(Absolute(0x0123).addr(&cpu, &mem), 0x0123);
	assert_eq!(Absolute(0x0123).get(&cpu, &mem), 0x24);
	Absolute(0x0123).set(&mut cpu, &mut mem, 0x24);
	// AbsoluteIndexedWithX
	assert_eq!(AbsoluteIndexedWithX(0x0123).addr(&cpu, &mem), 0x0134);
	assert_eq!(AbsoluteIndexedWithX(0x0123).get(&cpu, &mem), 0x35);
	AbsoluteIndexedWithX(0x0123).set(&mut cpu, &mut mem, 0x35);
	// AbsoluteIndexedWithY
	assert_eq!(AbsoluteIndexedWithY(0x0123).addr(&cpu, &mem), 0x0145);
	assert_eq!(AbsoluteIndexedWithY(0x0123).get(&cpu, &mem), 0x46);
	AbsoluteIndexedWithY(0x0123).set(&mut cpu, &mut mem, 0x46);
	// Indirect
	assert_eq!(Indirect(0x0123).addr(&cpu, &mem), 0x2524);
	assert_eq!(Indirect(0x0123).get(&cpu, &mem), 0x49);
	Indirect(0x0123).set(&mut cpu, &mut mem, 0x49);
	// ZeroPage
	assert_eq!(ZeroPage(0x12).addr(&cpu, &mem), 0x0012);
	assert_eq!(ZeroPage(0x12).get(&cpu, &mem), 0x12);
	ZeroPage(0x12).set(&mut cpu, &mut mem, 0x12);
	// ZeroPageIndexedWithX
	assert_eq!(ZeroPageIndexedWithX(0x12).addr(&cpu, &mem), 0x0023);
	assert_eq!(ZeroPageIndexedWithX(0x12).get(&cpu, &mem), 0x23);
	ZeroPageIndexedWithX(0x12).set(&mut cpu, &mut mem, 0x23);
	// ZeroPageIndexedWithY
	assert_eq!(ZeroPageIndexedWithY(0x12).addr(&cpu, &mem), 0x0034);
	assert_eq!(ZeroPageIndexedWithY(0x12).get(&cpu, &mem), 0x34);
	ZeroPageIndexedWithY(0x12).set(&mut cpu, &mut mem, 0x34);
	// ZeroPageIndexedWithXIndirect
	assert_eq!(ZeroPageIndexedWithXIndirect(0x12).addr(&cpu, &mem), 0x2423);
	assert_eq!(ZeroPageIndexedWithXIndirect(0x12).get(&cpu, &mem), 0x47);
	ZeroPageIndexedWithXIndirect(0x12).set(&mut cpu, &mut mem, 0x47);
	// ZeroPageIndirectIndexedWithY
	assert_eq!(ZeroPageIndirectIndexedWithY(0x12).addr(&cpu, &mem), 0x1334);
	assert_eq!(ZeroPageIndirectIndexedWithY(0x12).get(&cpu, &mem), 0x47);
	ZeroPageIndirectIndexedWithY(0x12).set(&mut cpu, &mut mem, 0x47);
}

#[test]
fn test_indirect_addressing_bug () {
	let cpu = Mos6502 { pc: 0x1337, ac: 0x88, x: 0x11, y: 0x22, sr: 0, sp: 0 };
	let mem = TestMemory::new::<u16>();
	// Indirect jump to ($c0ff) will get erroneously address from $c0ff/$c000 instead of $c0ff/$c100
	assert_eq!(Indirect(0xc0ff).addr(&cpu, &mem), 0xc0bf);	// must be $c0bf instead of $c1bf
}
<|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/. */

// Timing functions.
use std::comm::{Port, SharedChan};
use std::iterator::AdditiveIterator;
use std::rt::io::timer::Timer;
use std::task::spawn_with;

use extra::sort::tim_sort;
use extra::time::precise_time_ns;
use extra::treemap::TreeMap;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan(SharedChan<ProfilerMsg>);
impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan(SharedChan::new(chan))
    }
}

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, float),
    // Message used to force print the profiling metrics
    PrintMsg,
}

#[deriving(Eq, Clone, TotalEq, TotalOrd)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingDrawingCategory,
    RenderingPrepBuffCategory,
    RenderingCategory,
    // FIXME(rust#8803): workaround for lack of CTFE function on enum types to return length
    NumBuckets,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NumBuckets as uint
    }

    // enumeration of all ProfilerCategory types
    fn empty_buckets() -> ProfilerBuckets {
        let mut buckets = TreeMap::new();
        buckets.insert(CompositingCategory, ~[]);
        buckets.insert(LayoutQueryCategory, ~[]);
        buckets.insert(LayoutPerformCategory, ~[]);
        buckets.insert(LayoutAuxInitCategory, ~[]);
        buckets.insert(LayoutSelectorMatchCategory, ~[]);
        buckets.insert(LayoutTreeBuilderCategory, ~[]);
        buckets.insert(LayoutMainCategory, ~[]);
        buckets.insert(LayoutShapingCategory, ~[]);
        buckets.insert(LayoutDispListBuildCategory, ~[]);
        buckets.insert(GfxRegenAvailableFontsCategory, ~[]);
        buckets.insert(RenderingDrawingCategory, ~[]);
        buckets.insert(RenderingPrepBuffCategory, ~[]);
        buckets.insert(RenderingCategory, ~[]);

        buckets
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

type ProfilerBuckets = TreeMap<ProfilerCategory, ~[float]>;

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ProfilerBuckets,
    last_msg: Option<ProfilerMsg>,
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>, chan: ProfilerChan, period: Option<float>) {
        match period {
            Some(period) => {
                let period = (period * 1000f) as u64;
                do spawn {
                    let mut timer = Timer::new().unwrap();
                    loop {
                        timer.sleep(period);
                        if !chan.try_send(PrintMsg) {
                            break;
                        }
                    }
                }
                // Spawn the profiler
                do spawn_with(port) |port| {
                    let mut profiler = Profiler::new(port);
                    profiler.start();
                }
            }
            None => {
                // no-op to handle profiler messages when the profiler is inactive
                do spawn_with(port) |port| {
                    while port.try_recv().is_some() {}
                }
            }
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.try_recv();
            match msg {
               Some (msg) => self.handle_msg(msg),
               None => break
            }
        }
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => self.buckets.find_mut(&category).unwrap().push(t),
            PrintMsg => match self.last_msg {
                // only print if more data has arrived since the last printout
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => ()
            },
        };
        self.last_msg = Some(msg);
    }

    fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for (category, data) in self.buckets.iter() {
            // FIXME(XXX): TreeMap currently lacks mut_iter()
            let mut data = data.clone();
            tim_sort(data);
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, &min, &max) =
                    (data.iter().map(|&x|x).sum() / (data_len as float),
                     data[data_len / 2],
                     data.iter().min().unwrap(),
                     data.iter().max().unwrap());
                println(fmt!("%-30s: %15.4f %15.4f %15.4f %15.4f %15u",
                             category.format(), mean, median, min, max, data_len));
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    profiler_chan.send(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    if ms >= 5f {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

#[cfg(test)]
mod test {
    // ensure that the order of the buckets matches the order of the enum categories
    #[test]
    fn check_order() {
        let buckets = ProfilerCategory::empty_buckets();
        assert!(buckets.len() == NumBuckets as uint);
    }
}
<commit_msg>util: Change profiling to use send_deferred. Large win.<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/. */

// Timing functions.
use extra::sort::tim_sort;
use extra::time::precise_time_ns;
use extra::treemap::TreeMap;
use std::cell::Cell;
use std::comm::{Port, SendDeferred, SharedChan};
use std::iterator::AdditiveIterator;
use std::rt::io::timer::Timer;
use std::task::spawn_with;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan(SharedChan<ProfilerMsg>);
impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan(SharedChan::new(chan))
    }
    pub fn send_deferred(&self, msg: ProfilerMsg) {
        self.chan.send_deferred(msg);
    }
}

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, float),
    // Message used to force print the profiling metrics
    PrintMsg,
}

#[deriving(Eq, Clone, TotalEq, TotalOrd)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingDrawingCategory,
    RenderingPrepBuffCategory,
    RenderingCategory,
    // FIXME(rust#8803): workaround for lack of CTFE function on enum types to return length
    NumBuckets,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NumBuckets as uint
    }

    // enumeration of all ProfilerCategory types
    fn empty_buckets() -> ProfilerBuckets {
        let mut buckets = TreeMap::new();
        buckets.insert(CompositingCategory, ~[]);
        buckets.insert(LayoutQueryCategory, ~[]);
        buckets.insert(LayoutPerformCategory, ~[]);
        buckets.insert(LayoutAuxInitCategory, ~[]);
        buckets.insert(LayoutSelectorMatchCategory, ~[]);
        buckets.insert(LayoutTreeBuilderCategory, ~[]);
        buckets.insert(LayoutMainCategory, ~[]);
        buckets.insert(LayoutShapingCategory, ~[]);
        buckets.insert(LayoutDispListBuildCategory, ~[]);
        buckets.insert(GfxRegenAvailableFontsCategory, ~[]);
        buckets.insert(RenderingDrawingCategory, ~[]);
        buckets.insert(RenderingPrepBuffCategory, ~[]);
        buckets.insert(RenderingCategory, ~[]);

        buckets
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

type ProfilerBuckets = TreeMap<ProfilerCategory, ~[float]>;

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ProfilerBuckets,
    last_msg: Option<ProfilerMsg>,
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>, chan: ProfilerChan, period: Option<float>) {
        match period {
            Some(period) => {
                let period = (period * 1000f) as u64;
                do spawn {
                    let mut timer = Timer::new().unwrap();
                    loop {
                        timer.sleep(period);
                        if !chan.try_send(PrintMsg) {
                            break;
                        }
                    }
                }
                // Spawn the profiler
                do spawn_with(port) |port| {
                    let mut profiler = Profiler::new(port);
                    profiler.start();
                }
            }
            None => {
                // no-op to handle profiler messages when the profiler is inactive
                do spawn_with(port) |port| {
                    while port.try_recv().is_some() {}
                }
            }
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.try_recv();
            match msg {
               Some (msg) => self.handle_msg(msg),
               None => break
            }
        }
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => self.buckets.find_mut(&category).unwrap().push(t),
            PrintMsg => match self.last_msg {
                // only print if more data has arrived since the last printout
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => ()
            },
        };
        self.last_msg = Some(msg);
    }

    fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for (category, data) in self.buckets.iter() {
            // FIXME(XXX): TreeMap currently lacks mut_iter()
            let mut data = data.clone();
            tim_sort(data);
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, &min, &max) =
                    (data.iter().map(|&x|x).sum() / (data_len as float),
                     data[data_len / 2],
                     data.iter().min().unwrap(),
                     data.iter().max().unwrap());
                println(fmt!("%-30s: %15.4f %15.4f %15.4f %15.4f %15u",
                             category.format(), mean, median, min, max, data_len));
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    profiler_chan.send_deferred(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    if ms >= 5f {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

#[cfg(test)]
mod test {
    // ensure that the order of the buckets matches the order of the enum categories
    #[test]
    fn check_order() {
        let buckets = ProfilerCategory::empty_buckets();
        assert!(buckets.len() == NumBuckets as uint);
    }
}
<|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/. */

// Timing functions.
use std::time::precise_time_ns;
use core::cell::Cell;
use core::comm::{Port, SharedChan};
use std::sort::tim_sort;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan {
    chan: SharedChan<ProfilerMsg>,
}

impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: ProfilerMsg) {
        self.chan.send(msg);
    }
}

#[deriving(Eq)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingPrepBuffCategory,
    RenderingWaitSubtasksCategory,
    RenderingCategory,
    // hackish but helps prevent errors when adding new categories
    NUM_BUCKETS,
}
// FIXME(#5873) this should be initialized by a NUM_BUCKETS cast,
static BUCKETS: uint = 13;

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, f64),
    // Message used to force print the profiling metrics
    PrintMsg,
}

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ~[(ProfilerCategory, ~[f64])],
    last_msg: Option<ProfilerMsg>,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NUM_BUCKETS as uint
    }

    // enumeration of all ProfilerCategory types
    // FIXME(tkuehn): this is ugly and error-prone,
    // but currently we lack better alternatives without an enum enumeration
    priv fn empty_buckets() -> ~[(ProfilerCategory, ~[f64])] {
        let mut vec = ~[];
        vec.push((CompositingCategory, ~[]));
        vec.push((LayoutQueryCategory, ~[]));
        vec.push((LayoutPerformCategory, ~[]));
        vec.push((LayoutAuxInitCategory, ~[]));
        vec.push((LayoutSelectorMatchCategory, ~[]));
        vec.push((LayoutTreeBuilderCategory, ~[]));
        vec.push((LayoutMainCategory, ~[]));
        vec.push((LayoutShapingCategory, ~[]));
        vec.push((LayoutDispListBuildCategory, ~[]));
        vec.push((GfxRegenAvailableFontsCategory, ~[]));
        vec.push((RenderingPrepBuffCategory, ~[]));
        vec.push((RenderingWaitSubtasksCategory, ~[]));
        vec.push((RenderingCategory, ~[]));

        ProfilerCategory::check_order(vec);
        vec
    }

    priv fn check_order(vec: &[(ProfilerCategory, ~[f64])]) {
        for vec.each |&(category, _)| {
            if category != vec[category as uint].first() {
                fail!("Enum category does not match bucket index. This is a bug.");
            }
        }
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>) {
        let port = Cell(port);
        do spawn {
            let mut profiler = Profiler::new(port.take());
            profiler.start();
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.recv();
            self.handle_msg(msg);
        }
    }

    priv fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => match self.buckets[category as uint] {
                // FIXME(#3874): this should be a let (cat, ref mut bucket) = ...,
                // not a match
                (_, ref mut data) => {
                    data.push(t);
                }
            },
            PrintMsg => match self.last_msg {
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => {}
            },
        };
        self.last_msg = Some(msg);
    }

    priv fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category (ms)_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for vec::each_mut(self.buckets) |bucket| {
            match *bucket {
                (category, ref mut data) => {
                    tim_sort(*data);
                    let data_len = data.len();
                    if data_len > 0 {
                        let (mean, median, min, max) =
                            (data.foldl(0f64, |a, b| a + *b) / (data_len as f64),
                             data[data_len / 2],
                             data.min(),
                             data.max());
                        println(fmt!("%-30s: %15.4? %15.4? %15.4? %15.4? %15u",
                                     category.format(), mean, median, min, max, data_len));
                    }
                }
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as f64 / 1000000f64);
    profiler_chan.send(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as f64 / 1000000f64);
    if ms >= 5f64 {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

<commit_msg>Adding renderer drawing category to profiler.<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/. */

// Timing functions.
use std::time::precise_time_ns;
use core::cell::Cell;
use core::comm::{Port, SharedChan};
use std::sort::tim_sort;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan {
    chan: SharedChan<ProfilerMsg>,
}

impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: ProfilerMsg) {
        self.chan.send(msg);
    }
}

#[deriving(Eq)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingDrawingCategory,
    RenderingPrepBuffCategory,
    RenderingWaitSubtasksCategory,
    RenderingCategory,
    // hackish but helps prevent errors when adding new categories
    NUM_BUCKETS,
}
// FIXME(#5873) this should be initialized by a NUM_BUCKETS cast,
static BUCKETS: uint = 13;

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, f64),
    // Message used to force print the profiling metrics
    PrintMsg,
}

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ~[(ProfilerCategory, ~[f64])],
    last_msg: Option<ProfilerMsg>,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NUM_BUCKETS as uint
    }

    // enumeration of all ProfilerCategory types
    // FIXME(tkuehn): this is ugly and error-prone,
    // but currently we lack better alternatives without an enum enumeration
    priv fn empty_buckets() -> ~[(ProfilerCategory, ~[f64])] {
        let mut vec = ~[];
        vec.push((CompositingCategory, ~[]));
        vec.push((LayoutQueryCategory, ~[]));
        vec.push((LayoutPerformCategory, ~[]));
        vec.push((LayoutAuxInitCategory, ~[]));
        vec.push((LayoutSelectorMatchCategory, ~[]));
        vec.push((LayoutTreeBuilderCategory, ~[]));
        vec.push((LayoutMainCategory, ~[]));
        vec.push((LayoutShapingCategory, ~[]));
        vec.push((LayoutDispListBuildCategory, ~[]));
        vec.push((GfxRegenAvailableFontsCategory, ~[]));
        vec.push((RenderingDrawingCategory, ~[]));
        vec.push((RenderingPrepBuffCategory, ~[]));
        vec.push((RenderingWaitSubtasksCategory, ~[]));
        vec.push((RenderingCategory, ~[]));

        ProfilerCategory::check_order(vec);
        vec
    }

    priv fn check_order(vec: &[(ProfilerCategory, ~[f64])]) {
        for vec.each |&(category, _)| {
            if category != vec[category as uint].first() {
                fail!("Enum category does not match bucket index. This is a bug.");
            }
        }
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>) {
        let port = Cell(port);
        do spawn {
            let mut profiler = Profiler::new(port.take());
            profiler.start();
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.recv();
            self.handle_msg(msg);
        }
    }

    priv fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => match self.buckets[category as uint] {
                // FIXME(#3874): this should be a let (cat, ref mut bucket) = ...,
                // not a match
                (_, ref mut data) => {
                    data.push(t);
                }
            },
            PrintMsg => match self.last_msg {
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => {}
            },
        };
        self.last_msg = Some(msg);
    }

    priv fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category (ms)_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for vec::each_mut(self.buckets) |bucket| {
            match *bucket {
                (category, ref mut data) => {
                    tim_sort(*data);
                    let data_len = data.len();
                    if data_len > 0 {
                        let (mean, median, min, max) =
                            (data.foldl(0f64, |a, b| a + *b) / (data_len as f64),
                             data[data_len / 2],
                             data.min(),
                             data.max());
                        println(fmt!("%-30s: %15.4? %15.4? %15.4? %15.4? %15u",
                                     category.format(), mean, median, min, max, data_len));
                    }
                }
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as f64 / 1000000f64);
    profiler_chan.send(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as f64 / 1000000f64);
    if ms >= 5f64 {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

<|endoftext|>


<commit_before>use std::fmt;
use std::marker::PhantomData;

use hyper::method::Method;
use serde::json;

use response;
use request::RequestBuilder;
use request::DoRequest;

/// Lists the types of supported DNS records
doapi_enum! {
    #[derive(Debug)]
    pub enum DnsRecType {
        A,
        AAAA,
        CNAME,
        MX,
        NS,
        SRV,
        TXT
    }
}

// type     string  The record type (A, MX, CNAME, etc).    All Records
// name     string  The host name, alias, or service being defined by the record.   A, AAAA, CNAME, TXT, SRV
// data     string  Variable data depending on record type. See the [Domain Records]() section for more detail on each record type. A, AAAA, CNAME, MX, TXT, SRV, NS
// priority    nullable number The priority of the host (for SRV and MX records. null otherwise).  MX, SRV
// port     nullable number The port that the service is accessible on (for SRV records only. null otherwise).  SRV
// weight   nullable number The weight of records with the same priority (for SRV records only. null otherwise).    SRV
/// A struct for creating a DNS Record
#[derive(Serialize)]
pub struct DnsRecord {
    /// The type of record (A, AAAA, MX, NS, etc.)
    ///
    /// **NOTE:** You can use the `DnsRecType`'s implementation of `std::fmt::Display` to get a
    /// `String`
    #[serde(rename = "type")]
    pub rec_type: String,
    /// The name of the record (Required for: A, AAAA, CNAME, TXT, and SRV)
    pub name: Option<String>,
    /// The priority of the record (Required for: MX and SRV)
    pub priority: Option<u64>,
    /// The port of the record (Required for: SRV)
    pub port: Option<u64>,
    /// Various data used for record (Required for: A, AAAA, CNAME, MX, TXT, SRV, NS)
    pub data: Option<String>,
    /// The weight of the record (Required for: SRV)
    pub weight: Option<u64>,
}

impl fmt::Display for DnsRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
            "Record Type: {}\n\
             Name: {}\n\
             Data: {}\n\
             Priority: {}\n\
             Port: {}\n\
             Weight: {}\n",
             self.rec_type,
             if let Some(n) = self.name.clone() {
                n
             } else {
                "None".to_owned()
             },
             if let Some(d) = self.data.clone() {
                d
             } else {
                "None".to_owned()
             },
             if let Some(p) = self.priority {
                p.to_string()
             } else {
                "None".to_owned()
             },
             if let Some(p) = self.port {
                p.to_string()
             } else {
                "None".to_owned()
             },
             if let Some(w) = self.weight {
                w.to_string()
             } else {
                "None".to_owned()
             }
        )
    }
}

/// A type of `RequestBuilder` which allows you make requests related to a single DNS record
///
/// # Example
///
/// ```no_run
/// # use doapi::DoManager;
/// # use doapi::DoRequest;
/// let domgr = DoManager::with_token("<token>");
/// let dnsrecord_request = domgr.domain("super.com").dns_record("<record id>");
/// ```
pub type DnsRecordRequest<'t> = RequestBuilder<'t, response::DnsRecord>;
impl<'t> DoRequest<response::DnsRecord> for DnsRecordRequest<'t> {}

impl<'t> DnsRecordsRequest<'t> {
    /// Returns a `RequestBuilder` for creating a DNS record.
    ///
    /// **Parameters:**
    /// `record`: The instance of `DnsRecord` you'd like to create
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use doapi::DoManager;
    /// # use doapi::DoRequest;
    /// # use doapi::request::DnsRecord;
    /// # let domgr = DoManager::with_token("asfasdfasdf");
    /// # let record = DnsRecord {
    /// #   rec_type: "A".to_owned(),
    /// #   name: None,
    /// #   priority: None,
    /// #   port: None,
    /// #   data: None,
    /// #   weight: None,
    /// # };
    /// // ... domgr set up same as before
    /// // ... assumes "record" is an instance of doapi::request::DnsRecord
    /// match domgr.domain("super.com")
    ///            .dns_records()
    ///            .create(&record)
    ///            .retrieve() {
    ///     Ok(dns_rec) => println!("Record: {}", dns_rec),
    ///     Err(e)     => println!("Error: {}", e)
    /// }
    /// ```
    pub fn create(self, record: &DnsRecord) -> DnsRecordRequest<'t> {
        // POST: "https://api.digitalocean.com/v2/domains/$DOMAIN/records"
        // body:
        //      "type" : "MX"            All records
        //      "name" : "alias"         A, AAAA, CNAME, TXT, SRV
        //      "data" : "varies"        A, AAAA, CNAME, MX, TXT, SRV, NS
        //      "priority" : 20          MX, SRV
        //      "port" : 80              SRV
        //      "weight" : 200           SRV

        // FIXME: Don't unwrap()
        RequestBuilder {
            method: Method::Post,
            auth: self.auth,
            url: self.url,
            resp_t: PhantomData,
            body: Some(json::to_string(record).ok().unwrap())
        }
    }
}

/// A type of `RequestBuilder` which allows you make requests related to multiple DNS records or
/// the concept of "DNS Records" as a whole
///
/// # Example
///
/// ```no_run
/// # use doapi::DoManager;
/// # use doapi::DoRequest;
/// let domgr = DoManager::with_token("<token>");
/// let dnsrecords_request = domgr.domain("super.com").dns_records();
/// ```
pub type DnsRecordsRequest<'t> = RequestBuilder<'t, response::DnsRecords>;

impl<'t> DnsRecordsRequest<'t> {
    /// Returns a `RequestBuilder` for updating an existing DNS record.
    ///
    /// **Parameters:**
    /// `record`: The new instance of `DnsRecord` you'd like to update to
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use doapi::DoManager;
    /// # use doapi::DoRequest;
    /// # use doapi::request::DnsRecord;
    /// # let domgr = DoManager::with_token("asfasdfasdf");
    /// # let record = DnsRecord {
    /// #   rec_type: "A".to_owned(),
    /// #   name: None,
    /// #   priority: None,
    /// #   port: None,
    /// #   data: None,
    /// #   weight: None,
    /// # };
    /// // ... domgr set up same as before
    /// // ... assumes "record" is an instance of doapi::request::DnsRecord
    /// match domgr.domain("super.com")
    ///            .dns_record("1234")
    ///            .update(&record)
    ///            .retrieve() {
    ///     Ok(dns_rec) => println!("Record: {}", dns_rec),
    ///     Err(e)     => println!("Error: {}", e)
    /// }
    /// ```
    pub fn update(self, record: &DnsRecord) -> DnsRecordRequest<'t> {
        // PUT: "https://api.digitalocean.com/v2/domains/$DOMAIN/records/$ID"
        // body:
        //      "type" : "MX"           All records
        //      "name" : "alias"        A, AAAA, CNAME, TXT, SRV
        //      "data" : "varies"       A, AAAA, CNAME, MX, TXT, SRV, NS
        //      "priority" : 20         MX, SRV
        //      "port" : 80             SRV
        //      "weight" : 200          SRV
        // FIXME: Don't unwrap()
        RequestBuilder {
            method: Method::Put,
            auth: self.auth,
            url: self.url,
            resp_t: PhantomData,
            body: Some(json::to_string(record).ok().unwrap())
        }
    }

    /// Returns a `RequestBuilder` for deleting an existing DNS record.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use doapi::DoManager;
    /// # use doapi::DoRequest;
    /// # let domgr = DoManager::with_token("asfasdfasdf");
    /// // ... domgr set up same as before
    /// match domgr.domain("super.com")
    ///            .dns_record("1234")
    ///            .delete()
    ///            .retrieve() {
    ///     Ok(_)  => println!("Success"),
    ///     Err(_) => println!("Error")
    /// }
    /// ```
    pub fn delete(self) -> RequestBuilder<'t, response::HeaderOnly> {
        // DELETE: "https://api.digitalocean.com/v2/domains/$id"
        RequestBuilder {
            method: Method::Delete,
            auth: self.auth,
            url: self.url,
            resp_t: PhantomData,
            body: None
        }
    }
}
<commit_msg>refactor: fix typos<commit_after>use std::fmt;
use std::marker::PhantomData;

use hyper::method::Method;
use serde::json;

use response;
use request::RequestBuilder;
use request::DoRequest;

/// Lists the types of supported DNS records
doapi_enum! {
    #[derive(Debug)]
    pub enum DnsRecType {
        A,
        AAAA,
        CNAME,
        MX,
        NS,
        SRV,
        TXT
    }
}

// type     string  The record type (A, MX, CNAME, etc).    All Records
// name     string  The host name, alias, or service being defined by the record.   A, AAAA, CNAME, TXT, SRV
// data     string  Variable data depending on record type. See the [Domain Records]() section for more detail on each record type. A, AAAA, CNAME, MX, TXT, SRV, NS
// priority    nullable number The priority of the host (for SRV and MX records. null otherwise).  MX, SRV
// port     nullable number The port that the service is accessible on (for SRV records only. null otherwise).  SRV
// weight   nullable number The weight of records with the same priority (for SRV records only. null otherwise).    SRV
/// A struct for creating a DNS Record
#[derive(Serialize)]
pub struct DnsRecord {
    /// The type of record (A, AAAA, MX, NS, etc.)
    ///
    /// **NOTE:** You can use the `DnsRecType`'s implementation of `std::fmt::Display` to get a
    /// `String`
    #[serde(rename = "type")]
    pub rec_type: String,
    /// The name of the record (Required for: A, AAAA, CNAME, TXT, and SRV)
    pub name: Option<String>,
    /// The priority of the record (Required for: MX and SRV)
    pub priority: Option<u64>,
    /// The port of the record (Required for: SRV)
    pub port: Option<u64>,
    /// Various data used for record (Required for: A, AAAA, CNAME, MX, TXT, SRV, NS)
    pub data: Option<String>,
    /// The weight of the record (Required for: SRV)
    pub weight: Option<u64>,
}

impl fmt::Display for DnsRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
            "Record Type: {}\n\
             Name: {}\n\
             Data: {}\n\
             Priority: {}\n\
             Port: {}\n\
             Weight: {}\n",
             self.rec_type,
             if let Some(n) = self.name.clone() {
                n
             } else {
                "None".to_owned()
             },
             if let Some(d) = self.data.clone() {
                d
             } else {
                "None".to_owned()
             },
             if let Some(p) = self.priority {
                p.to_string()
             } else {
                "None".to_owned()
             },
             if let Some(p) = self.port {
                p.to_string()
             } else {
                "None".to_owned()
             },
             if let Some(w) = self.weight {
                w.to_string()
             } else {
                "None".to_owned()
             }
        )
    }
}

/// A type of `RequestBuilder` which allows you make requests related to multiple DNS records or
/// the concept of "DNS Records" as a whole
///
/// # Example
///
/// ```no_run
/// # use doapi::DoManager;
/// # use doapi::DoRequest;
/// let domgr = DoManager::with_token("<token>");
/// let dnsrecords_request = domgr.domain("super.com").dns_records();
/// ```
pub type DnsRecordsRequest<'t> = RequestBuilder<'t, response::DnsRecords>;

impl<'t> DnsRecordsRequest<'t> {
    /// Returns a `RequestBuilder` for creating a DNS record.
    ///
    /// **Parameters:**
    /// `record`: The instance of `DnsRecord` you'd like to create
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use doapi::DoManager;
    /// # use doapi::DoRequest;
    /// # use doapi::request::DnsRecord;
    /// # let domgr = DoManager::with_token("asfasdfasdf");
    /// # let record = DnsRecord {
    /// #   rec_type: "A".to_owned(),
    /// #   name: None,
    /// #   priority: None,
    /// #   port: None,
    /// #   data: None,
    /// #   weight: None,
    /// # };
    /// // ... domgr set up same as before
    /// // ... assumes "record" is an instance of doapi::request::DnsRecord
    /// match domgr.domain("super.com")
    ///            .dns_records()
    ///            .create(&record)
    ///            .retrieve() {
    ///     Ok(dns_rec) => println!("Record: {}", dns_rec),
    ///     Err(e)     => println!("Error: {}", e)
    /// }
    /// ```
    pub fn create(self, record: &DnsRecord) -> DnsRecordRequest<'t> {
        // POST: "https://api.digitalocean.com/v2/domains/$DOMAIN/records"
        // body:
        //      "type" : "MX"            All records
        //      "name" : "alias"         A, AAAA, CNAME, TXT, SRV
        //      "data" : "varies"        A, AAAA, CNAME, MX, TXT, SRV, NS
        //      "priority" : 20          MX, SRV
        //      "port" : 80              SRV
        //      "weight" : 200           SRV

        // FIXME: Don't unwrap()
        RequestBuilder {
            method: Method::Post,
            auth: self.auth,
            url: self.url,
            resp_t: PhantomData,
            body: Some(json::to_string(record).ok().unwrap())
        }
    }
}

/// A type of `RequestBuilder` which allows you make requests related to a single DNS record
///
/// # Example
///
/// ```no_run
/// # use doapi::DoManager;
/// # use doapi::DoRequest;
/// let domgr = DoManager::with_token("<token>");
/// let dnsrecord_request = domgr.domain("super.com").dns_record("<record id>");
/// ```
pub type DnsRecordRequest<'t> = RequestBuilder<'t, response::DnsRecord>;
impl<'t> DoRequest<response::DnsRecord> for DnsRecordRequest<'t> {}

impl<'t> DnsRecordRequest<'t> {
    /// Returns a `RequestBuilder` for updating an existing DNS record.
    ///
    /// **Parameters:**
    /// `record`: The new instance of `DnsRecord` you'd like to update to
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use doapi::DoManager;
    /// # use doapi::DoRequest;
    /// # use doapi::request::DnsRecord;
    /// # let domgr = DoManager::with_token("asfasdfasdf");
    /// # let record = DnsRecord {
    /// #   rec_type: "A".to_owned(),
    /// #   name: None,
    /// #   priority: None,
    /// #   port: None,
    /// #   data: None,
    /// #   weight: None,
    /// # };
    /// // ... domgr set up same as before
    /// // ... assumes "record" is an instance of doapi::request::DnsRecord
    /// match domgr.domain("super.com")
    ///            .dns_record("1234")
    ///            .update(&record)
    ///            .retrieve() {
    ///     Ok(dns_rec) => println!("Record: {}", dns_rec),
    ///     Err(e)     => println!("Error: {}", e)
    /// }
    /// ```
    pub fn update(self, record: &DnsRecord) -> DnsRecordRequest<'t> {
        // PUT: "https://api.digitalocean.com/v2/domains/$DOMAIN/records/$ID"
        // body:
        //      "type" : "MX"           All records
        //      "name" : "alias"        A, AAAA, CNAME, TXT, SRV
        //      "data" : "varies"       A, AAAA, CNAME, MX, TXT, SRV, NS
        //      "priority" : 20         MX, SRV
        //      "port" : 80             SRV
        //      "weight" : 200          SRV
        // FIXME: Don't unwrap()
        RequestBuilder {
            method: Method::Put,
            auth: self.auth,
            url: self.url,
            resp_t: PhantomData,
            body: Some(json::to_string(record).ok().unwrap())
        }
    }

    /// Returns a `RequestBuilder` for deleting an existing DNS record.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use doapi::DoManager;
    /// # use doapi::DoRequest;
    /// # let domgr = DoManager::with_token("asfasdfasdf");
    /// // ... domgr set up same as before
    /// match domgr.domain("super.com")
    ///            .dns_record("1234")
    ///            .delete()
    ///            .retrieve() {
    ///     Ok(_)  => println!("Success"),
    ///     Err(_) => println!("Error")
    /// }
    /// ```
    pub fn delete(self) -> RequestBuilder<'t, response::HeaderOnly> {
        // DELETE: "https://api.digitalocean.com/v2/domains/$id"
        RequestBuilder {
            method: Method::Delete,
            auth: self.auth,
            url: self.url,
            resp_t: PhantomData,
            body: None
        }
    }
}
<|endoftext|>


<commit_before>// $ cargo bench --features full --bench file

#![feature(rustc_private, test)]
#![recursion_limit = "1024"]
#![allow(clippy::missing_panics_doc, clippy::must_use_candidate)]

extern crate test;

#[macro_use]
#[path = "../tests/macros/mod.rs"]
mod macros;

#[path = "../tests/common/mod.rs"]
mod common;
#[path = "../tests/repo/mod.rs"]
pub mod repo;

use proc_macro2::TokenStream;
use std::fs;
use std::str::FromStr;
use test::Bencher;

const FILE: &str = "tests/rust/library/core/src/str/mod.rs";

#[bench]
fn parse_file(b: &mut Bencher) {
    repo::clone_rust();
    let content = fs::read_to_string(FILE).unwrap();
    let tokens = TokenStream::from_str(&content).unwrap();
    b.iter(|| syn::parse2::<syn::File>(tokens.clone()));
}
<commit_msg>Add baseline benchmark to distinguish TokenStream::clone from syn::parse2<commit_after>// $ cargo bench --features full --bench file

#![feature(rustc_private, test)]
#![recursion_limit = "1024"]
#![allow(clippy::missing_panics_doc, clippy::must_use_candidate)]

extern crate test;

#[macro_use]
#[path = "../tests/macros/mod.rs"]
mod macros;

#[path = "../tests/common/mod.rs"]
mod common;
#[path = "../tests/repo/mod.rs"]
pub mod repo;

use proc_macro2::TokenStream;
use std::fs;
use std::str::FromStr;
use test::Bencher;

const FILE: &str = "tests/rust/library/core/src/str/mod.rs";

fn get_tokens() -> TokenStream {
    repo::clone_rust();
    let content = fs::read_to_string(FILE).unwrap();
    TokenStream::from_str(&content).unwrap()
}

#[bench]
fn baseline(b: &mut Bencher) {
    let tokens = get_tokens();
    b.iter(|| drop(tokens.clone()));
}

#[bench]
fn parse_file(b: &mut Bencher) {
    let tokens = get_tokens();
    b.iter(|| syn::parse2::<syn::File>(tokens.clone()));
}
<|endoftext|>


<commit_before>// $ cargo bench --features full --bench rust
//
// Syn only, useful for profiling:
// $ RUSTFLAGS='--cfg syn_only' cargo build --release --features full --bench rust

#![cfg_attr(not(syn_only), feature(rustc_private))]

#[path = "../tests/repo/mod.rs"]
mod repo;

#[cfg(not(syn_only))]
mod imports {
    pub extern crate rustc_data_structures;
    pub extern crate syntax;
    pub extern crate syntax_pos;

    pub use proc_macro2::TokenStream;
    pub use rustc_data_structures::sync::Lrc;
    pub use std::str::FromStr;
    pub use syntax::edition::Edition;
    pub use syntax::errors::{emitter::Emitter, DiagnosticBuilder, Handler};
    pub use syntax::parse::ParseSess;
    pub use syntax::source_map::{FilePathMapping, SourceMap};
    pub use syntax_pos::FileName;
}

#[cfg(not(syn_only))]
use imports::*;

use std::fs;
use std::time::{Duration, Instant};

#[cfg(not(syn_only))]
fn tokenstream_parse(content: &str) -> Result<(), ()> {
    TokenStream::from_str(content).map(drop).map_err(drop)
}

fn syn_parse(content: &str) -> Result<(), ()> {
    syn::parse_file(content).map(drop).map_err(drop)
}

#[cfg(not(syn_only))]
fn libsyntax_parse(content: &str) -> Result<(), ()> {
    struct SilentEmitter;

    impl Emitter for SilentEmitter {
        fn emit_diagnostic(&mut self, _db: &DiagnosticBuilder) {}
    }

    syntax::with_globals(Edition::Edition2018, || {
        let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
        let emitter = Box::new(SilentEmitter);
        let handler = Handler::with_emitter(false, None, emitter);
        let sess = ParseSess::with_span_handler(handler, cm);
        if let Err(mut diagnostic) = syntax::parse::parse_crate_from_source_str(
            FileName::Custom("bench".to_owned()),
            content.to_owned(),
            &sess,
        ) {
            diagnostic.cancel();
            return Err(());
        };
        Ok(())
    })
}

#[cfg(not(syn_only))]
fn read_from_disk(content: &str) -> Result<(), ()> {
    let _ = content;
    Ok(())
}

fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration {
    let begin = Instant::now();
    let mut success = 0;
    let mut total = 0;

    walkdir::WalkDir::new("tests/rust/src")
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .for_each(|entry| {
            let entry = entry.unwrap();
            let path = entry.path();
            if path.is_dir() {
                return;
            }
            let content = fs::read_to_string(path).unwrap();
            let ok = codepath(&content).is_ok();
            success += ok as usize;
            total += 1;
            if !ok {
                eprintln!("FAIL {}", path.display());
            }
        });

    assert_eq!(success, total);
    begin.elapsed()
}

fn main() {
    repo::clone_rust();

    macro_rules! testcases {
        ($($(#[$cfg:meta])* $name:ident,)*) => {
            vec![
                $(
                    $(#[$cfg])*
                    (stringify!($name), $name as fn(&str) -> Result<(), ()>),
                )*
            ]
        };
    }

    #[cfg(not(syn_only))]
    {
        let mut lines = 0;
        let mut files = 0;
        exec(|content| {
            lines += content.lines().count();
            files += 1;
            Ok(())
        });
        eprintln!("\n{} lines in {} files", lines, files);
    }

    for (name, f) in testcases!(
        #[cfg(not(syn_only))]
        read_from_disk,
        #[cfg(not(syn_only))]
        tokenstream_parse,
        syn_parse,
        #[cfg(not(syn_only))]
        libsyntax_parse,
    ) {
        eprint!("{:20}", format!("{}:", name));
        let elapsed = exec(f);
        eprintln!(
            "elapsed={}.{:03}s",
            elapsed.as_secs(),
            elapsed.subsec_millis(),
        );
    }
    eprintln!();
}
<commit_msg>Reorganize the rust repo benchmark<commit_after>// $ cargo bench --features full --bench rust
//
// Syn only, useful for profiling:
// $ RUSTFLAGS='--cfg syn_only' cargo build --release --features full --bench rust

#![cfg_attr(not(syn_only), feature(rustc_private))]

#[path = "../tests/repo/mod.rs"]
mod repo;

use std::fs;
use std::time::{Duration, Instant};

#[cfg(not(syn_only))]
mod tokenstream_parse {
    use proc_macro2::TokenStream;
    use std::str::FromStr;

    pub fn bench(content: &str) -> Result<(), ()> {
        TokenStream::from_str(content).map(drop).map_err(drop)
    }
}

mod syn_parse {
    pub fn bench(content: &str) -> Result<(), ()> {
        syn::parse_file(content).map(drop).map_err(drop)
    }
}

#[cfg(not(syn_only))]
mod libsyntax_parse {
    extern crate rustc_data_structures;
    extern crate syntax;
    extern crate syntax_pos;

    use rustc_data_structures::sync::Lrc;
    use syntax::edition::Edition;
    use syntax::errors::{emitter::Emitter, DiagnosticBuilder, Handler};
    use syntax::parse::ParseSess;
    use syntax::source_map::{FilePathMapping, SourceMap};
    use syntax_pos::FileName;

    pub fn bench(content: &str) -> Result<(), ()> {
        struct SilentEmitter;

        impl Emitter for SilentEmitter {
            fn emit_diagnostic(&mut self, _db: &DiagnosticBuilder) {}
        }

        syntax::with_globals(Edition::Edition2018, || {
            let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
            let emitter = Box::new(SilentEmitter);
            let handler = Handler::with_emitter(false, None, emitter);
            let sess = ParseSess::with_span_handler(handler, cm);
            if let Err(mut diagnostic) = syntax::parse::parse_crate_from_source_str(
                FileName::Custom("bench".to_owned()),
                content.to_owned(),
                &sess,
            ) {
                diagnostic.cancel();
                return Err(());
            };
            Ok(())
        })
    }
}

#[cfg(not(syn_only))]
mod read_from_disk {
    pub fn bench(content: &str) -> Result<(), ()> {
        let _ = content;
        Ok(())
    }
}

fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration {
    let begin = Instant::now();
    let mut success = 0;
    let mut total = 0;

    walkdir::WalkDir::new("tests/rust/src")
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .for_each(|entry| {
            let entry = entry.unwrap();
            let path = entry.path();
            if path.is_dir() {
                return;
            }
            let content = fs::read_to_string(path).unwrap();
            let ok = codepath(&content).is_ok();
            success += ok as usize;
            total += 1;
            if !ok {
                eprintln!("FAIL {}", path.display());
            }
        });

    assert_eq!(success, total);
    begin.elapsed()
}

fn main() {
    repo::clone_rust();

    macro_rules! testcases {
        ($($(#[$cfg:meta])* $name:path,)*) => {
            vec![
                $(
                    $(#[$cfg])*
                    (stringify!($name), $name as fn(&str) -> Result<(), ()>),
                )*
            ]
        };
    }

    #[cfg(not(syn_only))]
    {
        let mut lines = 0;
        let mut files = 0;
        exec(|content| {
            lines += content.lines().count();
            files += 1;
            Ok(())
        });
        eprintln!("\n{} lines in {} files", lines, files);
    }

    for (name, f) in testcases!(
        #[cfg(not(syn_only))]
        read_from_disk::bench,
        #[cfg(not(syn_only))]
        tokenstream_parse::bench,
        syn_parse::bench,
        #[cfg(not(syn_only))]
        libsyntax_parse::bench,
    ) {
        eprint!("{:20}", format!("{}:", name));
        let elapsed = exec(f);
        eprintln!(
            "elapsed={}.{:03}s",
            elapsed.as_secs(),
            elapsed.subsec_millis(),
        );
    }
    eprintln!();
}
<|endoftext|>


<commit_before>// crypto_generichash_blake2b.h

pub const crypto_generichash_blake2b_BYTES_MIN: usize = 16;
pub const crypto_generichash_blake2b_BYTES_MAX: usize = 64;
pub const crypto_generichash_blake2b_BYTES: usize = 32;
pub const crypto_generichash_blake2b_KEYBYTES_MIN: usize = 16;
pub const crypto_generichash_blake2b_KEYBYTES_MAX: usize = 64;
pub const crypto_generichash_blake2b_KEYBYTES: usize = 32;
pub const crypto_generichash_blake2b_SALTBYTES: usize = 16;
pub const crypto_generichash_blake2b_PERSONALBYTES: usize = 16;

extern {
    pub fn crypto_generichash_blake2b_bytes_min() -> size_t;
    pub fn crypto_generichash_blake2b_bytes_max() -> size_t;
    pub fn crypto_generichash_blake2b_bytes() -> size_t;
    pub fn crypto_generichash_blake2b_keybytes_min() -> size_t;
    pub fn crypto_generichash_blake2b_keybytes_max() -> size_t;
    pub fn crypto_generichash_blake2b_keybytes() -> size_t;
    pub fn crypto_generichash_blake2b_saltbytes() -> size_t;
    pub fn crypto_generichash_blake2b_personalbytes() -> size_t;

    pub fn crypto_generichash_blake2b(
        out: *mut u8,
        outlen: size_t,
        in_: *const u8,
        inlen: c_ulonglong,
        key: *const u8,
        keylen: size_t)
        -> c_int;

    pub fn crypto_generichash_blake2b_salt_personal(
        out: *mut u8,
        outlen: size_t,
        in_: *const u8,
        inlen: c_ulonglong,
        key: *const u8,
        keylen: size_t,
        salt: *const [u8; crypto_generichash_blake2b_SALTBYTES],
        personal: *const [u8; crypto_generichash_blake2b_PERSONALBYTES])
        -> c_int;
}

#[test]
fn test_crypto_generichash_blake2b_bytes_min() {
    assert_eq!(unsafe { crypto_generichash_blake2b_bytes_min() as usize },
                        crypto_generichash_blake2b_BYTES_MIN)
}

#[test]
fn test_crypto_generichash_blake2b_bytes_max() {
    assert_eq!(unsafe { crypto_generichash_blake2b_bytes_max() as usize },
                        crypto_generichash_blake2b_BYTES_MAX)
}

#[test]
fn test_crypto_generichash_blake2b_bytes() {
    assert_eq!(unsafe { crypto_generichash_blake2b_bytes() as usize },
                        crypto_generichash_blake2b_BYTES)
}

#[test]
fn test_crypto_generichash_blake2b_keybytes_min() {
    assert_eq!(unsafe { crypto_generichash_blake2b_keybytes_min() as usize },
                        crypto_generichash_blake2b_KEYBYTES_MIN)
}

#[test]
fn test_crypto_generichash_blake2b_keybytes_max() {
    assert_eq!(unsafe { crypto_generichash_blake2b_keybytes_max() as usize },
                        crypto_generichash_blake2b_KEYBYTES_MAX)
}

#[test]
fn test_crypto_generichash_blake2b_keybytes() {
    assert_eq!(unsafe { crypto_generichash_blake2b_keybytes() as usize },
                        crypto_generichash_blake2b_KEYBYTES)
}

#[test]
fn test_crypto_generichash_blake2b_saltbytes() {
    assert_eq!(unsafe { crypto_generichash_blake2b_saltbytes() as usize },
                        crypto_generichash_blake2b_SALTBYTES)
}

#[test]
fn test_crypto_generichash_blake2b_personalbytes() {
    assert_eq!(unsafe { crypto_generichash_blake2b_personalbytes() as usize },
                        crypto_generichash_blake2b_PERSONALBYTES)
}
<commit_msg>Whitespace changes<commit_after>// crypto_generichash_blake2b.h

pub const crypto_generichash_blake2b_BYTES_MIN: usize = 16;
pub const crypto_generichash_blake2b_BYTES_MAX: usize = 64;
pub const crypto_generichash_blake2b_BYTES: usize = 32;
pub const crypto_generichash_blake2b_KEYBYTES_MIN: usize = 16;
pub const crypto_generichash_blake2b_KEYBYTES_MAX: usize = 64;
pub const crypto_generichash_blake2b_KEYBYTES: usize = 32;
pub const crypto_generichash_blake2b_SALTBYTES: usize = 16;
pub const crypto_generichash_blake2b_PERSONALBYTES: usize = 16;

extern {
    pub fn crypto_generichash_blake2b_bytes_min() -> size_t;
    pub fn crypto_generichash_blake2b_bytes_max() -> size_t;
    pub fn crypto_generichash_blake2b_bytes() -> size_t;
    pub fn crypto_generichash_blake2b_keybytes_min() -> size_t;
    pub fn crypto_generichash_blake2b_keybytes_max() -> size_t;
    pub fn crypto_generichash_blake2b_keybytes() -> size_t;
    pub fn crypto_generichash_blake2b_saltbytes() -> size_t;
    pub fn crypto_generichash_blake2b_personalbytes() -> size_t;

    pub fn crypto_generichash_blake2b(
        out: *mut u8,
        outlen: size_t,
        in_: *const u8,
        inlen: c_ulonglong,
        key: *const u8,
        keylen: size_t)
        -> c_int;

    pub fn crypto_generichash_blake2b_salt_personal(
        out: *mut u8,
        outlen: size_t,
        in_: *const u8,
        inlen: c_ulonglong,
        key: *const u8,
        keylen: size_t,
        salt: *const [u8; crypto_generichash_blake2b_SALTBYTES],
        personal: *const [u8; crypto_generichash_blake2b_PERSONALBYTES])
        -> c_int;
}

#[test]
fn test_crypto_generichash_blake2b_bytes_min() {
    assert_eq!(unsafe { crypto_generichash_blake2b_bytes_min() as usize },
                        crypto_generichash_blake2b_BYTES_MIN)
}

#[test]
fn test_crypto_generichash_blake2b_bytes_max() {
    assert_eq!(unsafe { crypto_generichash_blake2b_bytes_max() as usize },
                        crypto_generichash_blake2b_BYTES_MAX)
}

#[test]
fn test_crypto_generichash_blake2b_bytes() {
    assert_eq!(unsafe { crypto_generichash_blake2b_bytes() as usize },
                        crypto_generichash_blake2b_BYTES)
}

#[test]
fn test_crypto_generichash_blake2b_keybytes_min() {
    assert_eq!(unsafe { crypto_generichash_blake2b_keybytes_min() as usize },
                        crypto_generichash_blake2b_KEYBYTES_MIN)
}

#[test]
fn test_crypto_generichash_blake2b_keybytes_max() {
    assert_eq!(unsafe { crypto_generichash_blake2b_keybytes_max() as usize },
                        crypto_generichash_blake2b_KEYBYTES_MAX)
}

#[test]
fn test_crypto_generichash_blake2b_keybytes() {
    assert_eq!(unsafe { crypto_generichash_blake2b_keybytes() as usize },
                        crypto_generichash_blake2b_KEYBYTES)
}

#[test]
fn test_crypto_generichash_blake2b_saltbytes() {
    assert_eq!(unsafe { crypto_generichash_blake2b_saltbytes() as usize },
                        crypto_generichash_blake2b_SALTBYTES)
}

#[test]
fn test_crypto_generichash_blake2b_personalbytes() {
    assert_eq!(unsafe { crypto_generichash_blake2b_personalbytes() as usize },
                        crypto_generichash_blake2b_PERSONALBYTES)
}
<|endoftext|>


<commit_before>//! Defines the BSDF which acts as a container for composing the various BRDFs
//! and BTDFs that describe the surface's properties

use std::vec::Vec;
use std::cmp;
use enum_set::EnumSet;

use linalg::{self, Normal, Vector, Point};
use film::Colorf;
use geometry::DifferentialGeometry;
use bxdf::{BxDF, BxDFType};
use sampler::Sample;

/// The BSDF contains the various BRDFs and BTDFs that describe the surface's properties
/// at some point. It also transforms incident and outgoing light directions into
/// shading space to make the BxDFs easier to implement.
/// TODO: We really need the memory pool. Each time we get the bsdf from a
/// material we need to allocate a decent amount of stuff since they each need
/// their own tangent, bitangent and differential geometry reference.
pub struct BSDF<'a> {
    /// The hit point
    pub p: Point,
    /// Shading normal, may be perturbed by bump mapping
    pub n: Normal,
    /// The actual geometry normal
    pub ng: Normal,
    /// Tangent vector for the surface
    pub tan: Vector,
    /// Bitangent vector for the surface
    pub bitan: Vector,
    /// Refractive index of the geometry
    pub eta: f32,
    /// TODO: Currently a Vec is safe to use but once in the memory pool it
    /// will leak since it won't be dropped. This would also migrate our BxDFs
    /// from Box<BxDF> to &BxDF. When unboxed traits land we can move to unboxed
    /// BxDFs here though.
    bxdfs: &'a Vec<Box<BxDF + Send + Sync>>,
}

impl<'a> BSDF<'a> {
    /// Create a new BSDF using the BxDFs passed to shade the differential geometry with
    /// refractive index `eta`
    pub fn new(bxdfs: &'a Vec<Box<BxDF + Send + Sync>>, eta: f32,
               dg: &DifferentialGeometry<'a>)
               -> BSDF<'a> {
        let n = dg.n.normalized();
        let bitan = dg.dp_du.normalized();
        let tan = linalg::cross(&n, &bitan);
        BSDF { p: dg.p, n: n, ng: dg.ng, tan: tan, bitan: bitan, bxdfs: bxdfs, eta: eta }
    }
    /// Return the total number of BxDFs
    pub fn num_bxdfs(&self) -> usize { self.bxdfs.len() }
    /// Return the number of BxDFs matching the flags
    pub fn num_matching(&self, flags: EnumSet<BxDFType>) -> usize {
        self.bxdfs.iter().filter(|ref x| x.matches(flags)).count()
    }
    /// Transform the vector from world space to shading space
    pub fn to_shading(&self, v: &Vector) -> Vector {
        Vector::new(linalg::dot(v, &self.bitan), linalg::dot(v, &self.tan),
                    linalg::dot(v, &self.n))
    }
    /// Transform the vectro from shading space to world space
    pub fn from_shading(&self, v: &Vector) -> Vector {
        Vector::new(self.bitan.x * v.x + self.tan.x * v.y + self.n.x * v.z,
                    self.bitan.y * v.x + self.tan.y * v.y + self.n.y * v.z,
                    self.bitan.z * v.x + self.tan.z * v.y + self.n.z * v.z)
    }
    /// Evaluate the BSDF for the outgoing and incident light directions
    /// `w_o` and `w_i` in world space, sampling the desired subset of BxDFs
    /// selected by the flags passed. `wo_world` and `wi_world` should point from
    /// the hit point in the outgoing and incident light directions respectively.
    pub fn eval(&self, wo_world: &Vector, wi_world: &Vector, mut flags: EnumSet<BxDFType>) -> Colorf {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        // Determine if we should evaluate reflection or transmission based on the
        // geometry normal and the light directions
        if linalg::dot(wo_world, &self.ng) * linalg::dot(wi_world, &self.ng) > 0.0 {
            flags.remove(&BxDFType::Transmission);
        } else {
            flags.remove(&BxDFType::Reflection);
        }
        // Find all matching BxDFs and add their contribution to the material's color
        self.bxdfs.iter().filter_map(|ref x| if x.matches(flags) { Some(x.eval(&w_o, &w_i)) } else { None })
            .fold(Colorf::broadcast(0.0), |x, y| x + y)
    }
    /// Sample a component of the BSDF to get an incident light direction for light
    /// leaving the surface along `w_o`.
    /// `samples` are the 3 random values to use when sampling a component of the BSDF
    /// and a the chosen BSDF
    /// Returns the color, direction, pdf and the type of BxDF that was sampled.
    pub fn sample(&self, wo_world: &Vector, flags: EnumSet<BxDFType>, samples: &Sample)
        -> (Colorf, Vector, f32, EnumSet<BxDFType>) {
        let n_matching = self.num_matching(flags);
        if n_matching == 0 {
            return (Colorf::broadcast(0.0), Vector::broadcast(0.0), 0.0, EnumSet::new());
        }
        let comp = cmp::min((samples.one_d * n_matching as f32) as usize, n_matching - 1);
        let bxdf = self.matching_at(comp, flags);
        let w_o = self.to_shading(wo_world);
        let (mut f, w_i, mut pdf) = bxdf.sample(&w_o, &samples.two_d);
        if pdf == 0.0 {
            return (Colorf::broadcast(0.0), Vector::broadcast(0.0), 0.0, EnumSet::new());
        }

        let wi_world = self.from_shading(&w_i);
        // TODO: We re-use our functions but actually do a lot of redundant computation. I'm not
        // sure that the compiler will eliminate it. Should just copy in the code from pdf and eval
        if !bxdf.bxdf_type().contains(&BxDFType::Specular) && n_matching > 1 {
            pdf = self.pdf(wo_world, &wi_world, flags);
        }
        if n_matching > 1 {
            pdf /= n_matching as f32;
        }

        if !bxdf.bxdf_type().contains(&BxDFType::Specular) {
            f = self.eval(wo_world, &wi_world, flags);
        }
        (f, wi_world, pdf, bxdf.bxdf_type())
    }
    /// Compute the pdf for sampling the pair of incident and outgoing light directions for
    /// the BxDFs matching the flags set
    pub fn pdf(&self, wo_world: &Vector, wi_world: &Vector, flags: EnumSet<BxDFType>) -> f32 {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        let (pdf_val, n_comps) = self.bxdfs.iter()
            .filter_map(|ref x| if x.matches(flags) { Some(x.pdf(&w_o, &w_i)) } else { None })
            .fold((0.0, 0), |(p, n), y| (p + y, n + 1));
        if n_comps > 0 {
            pdf_val / n_comps as f32
        } else {
            0.0
        }
    }
    /// Get the `i`th BxDF that matches the flags passed. There should not be fewer than i
    /// BxDFs that match the flags
    fn matching_at(&self, i: usize, flags: EnumSet<BxDFType>) -> &Box<BxDF + Send + Sync> {
        let mut it = self.bxdfs.iter().filter(|ref x| x.matches(flags)).skip(i);
        match it.next() {
            Some(b) => b,
            None => panic!("Out of bounds index for BxDF type {:?}", flags)
        }
    }
}

<commit_msg>Ensure that [normal, tangent, bitangent] are actually orthonormal<commit_after>//! Defines the BSDF which acts as a container for composing the various BRDFs
//! and BTDFs that describe the surface's properties

use std::vec::Vec;
use std::cmp;
use enum_set::EnumSet;

use linalg::{self, Normal, Vector, Point};
use film::Colorf;
use geometry::DifferentialGeometry;
use bxdf::{BxDF, BxDFType};
use sampler::Sample;

/// The BSDF contains the various BRDFs and BTDFs that describe the surface's properties
/// at some point. It also transforms incident and outgoing light directions into
/// shading space to make the BxDFs easier to implement.
/// TODO: We really need the memory pool. Each time we get the bsdf from a
/// material we need to allocate a decent amount of stuff since they each need
/// their own tangent, bitangent and differential geometry reference.
pub struct BSDF<'a> {
    /// The hit point
    pub p: Point,
    /// Shading normal, may be perturbed by bump mapping
    pub n: Normal,
    /// The actual geometry normal
    pub ng: Normal,
    /// Tangent vector for the surface
    pub tan: Vector,
    /// Bitangent vector for the surface
    pub bitan: Vector,
    /// Refractive index of the geometry
    pub eta: f32,
    /// TODO: Currently a Vec is safe to use but once in the memory pool it
    /// will leak since it won't be dropped. This would also migrate our BxDFs
    /// from Box<BxDF> to &BxDF. When unboxed traits land we can move to unboxed
    /// BxDFs here though.
    bxdfs: &'a Vec<Box<BxDF + Send + Sync>>,
}

impl<'a> BSDF<'a> {
    /// Create a new BSDF using the BxDFs passed to shade the differential geometry with
    /// refractive index `eta`
    pub fn new(bxdfs: &'a Vec<Box<BxDF + Send + Sync>>, eta: f32,
               dg: &DifferentialGeometry<'a>)
               -> BSDF<'a> {
        let n = dg.n.normalized();
        let mut bitan = dg.dp_du.normalized();
        let tan = linalg::cross(&n, &bitan);
        bitan = linalg::cross(&tan, &n);
        BSDF { p: dg.p, n: n, ng: dg.ng, tan: tan, bitan: bitan, bxdfs: bxdfs, eta: eta }
    }
    /// Return the total number of BxDFs
    pub fn num_bxdfs(&self) -> usize { self.bxdfs.len() }
    /// Return the number of BxDFs matching the flags
    pub fn num_matching(&self, flags: EnumSet<BxDFType>) -> usize {
        self.bxdfs.iter().filter(|ref x| x.matches(flags)).count()
    }
    /// Transform the vector from world space to shading space
    pub fn to_shading(&self, v: &Vector) -> Vector {
        Vector::new(linalg::dot(v, &self.bitan), linalg::dot(v, &self.tan),
                    linalg::dot(v, &self.n))
    }
    /// Transform the vectro from shading space to world space
    pub fn from_shading(&self, v: &Vector) -> Vector {
        Vector::new(self.bitan.x * v.x + self.tan.x * v.y + self.n.x * v.z,
                    self.bitan.y * v.x + self.tan.y * v.y + self.n.y * v.z,
                    self.bitan.z * v.x + self.tan.z * v.y + self.n.z * v.z)
    }
    /// Evaluate the BSDF for the outgoing and incident light directions
    /// `w_o` and `w_i` in world space, sampling the desired subset of BxDFs
    /// selected by the flags passed. `wo_world` and `wi_world` should point from
    /// the hit point in the outgoing and incident light directions respectively.
    pub fn eval(&self, wo_world: &Vector, wi_world: &Vector, mut flags: EnumSet<BxDFType>) -> Colorf {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        // Determine if we should evaluate reflection or transmission based on the
        // geometry normal and the light directions
        if linalg::dot(wo_world, &self.ng) * linalg::dot(wi_world, &self.ng) > 0.0 {
            flags.remove(&BxDFType::Transmission);
        } else {
            flags.remove(&BxDFType::Reflection);
        }
        // Find all matching BxDFs and add their contribution to the material's color
        self.bxdfs.iter().filter_map(|ref x| if x.matches(flags) { Some(x.eval(&w_o, &w_i)) } else { None })
            .fold(Colorf::broadcast(0.0), |x, y| x + y)
    }
    /// Sample a component of the BSDF to get an incident light direction for light
    /// leaving the surface along `w_o`.
    /// `samples` are the 3 random values to use when sampling a component of the BSDF
    /// and a the chosen BSDF
    /// Returns the color, direction, pdf and the type of BxDF that was sampled.
    pub fn sample(&self, wo_world: &Vector, flags: EnumSet<BxDFType>, samples: &Sample)
        -> (Colorf, Vector, f32, EnumSet<BxDFType>) {
        let n_matching = self.num_matching(flags);
        if n_matching == 0 {
            return (Colorf::broadcast(0.0), Vector::broadcast(0.0), 0.0, EnumSet::new());
        }
        let comp = cmp::min((samples.one_d * n_matching as f32) as usize, n_matching - 1);
        let bxdf = self.matching_at(comp, flags);
        let w_o = self.to_shading(wo_world);
        let (mut f, w_i, mut pdf) = bxdf.sample(&w_o, &samples.two_d);
        if pdf == 0.0 {
            return (Colorf::broadcast(0.0), Vector::broadcast(0.0), 0.0, EnumSet::new());
        }

        let wi_world = self.from_shading(&w_i);
        // TODO: We re-use our functions but actually do a lot of redundant computation. I'm not
        // sure that the compiler will eliminate it. Should just copy in the code from pdf and eval
        if !bxdf.bxdf_type().contains(&BxDFType::Specular) && n_matching > 1 {
            pdf = self.pdf(wo_world, &wi_world, flags);
        }
        if n_matching > 1 {
            pdf /= n_matching as f32;
        }

        if !bxdf.bxdf_type().contains(&BxDFType::Specular) {
            f = self.eval(wo_world, &wi_world, flags);
        }
        (f, wi_world, pdf, bxdf.bxdf_type())
    }
    /// Compute the pdf for sampling the pair of incident and outgoing light directions for
    /// the BxDFs matching the flags set
    pub fn pdf(&self, wo_world: &Vector, wi_world: &Vector, flags: EnumSet<BxDFType>) -> f32 {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        let (pdf_val, n_comps) = self.bxdfs.iter()
            .filter_map(|ref x| if x.matches(flags) { Some(x.pdf(&w_o, &w_i)) } else { None })
            .fold((0.0, 0), |(p, n), y| (p + y, n + 1));
        if n_comps > 0 {
            pdf_val / n_comps as f32
        } else {
            0.0
        }
    }
    /// Get the `i`th BxDF that matches the flags passed. There should not be fewer than i
    /// BxDFs that match the flags
    fn matching_at(&self, i: usize, flags: EnumSet<BxDFType>) -> &Box<BxDF + Send + Sync> {
        let mut it = self.bxdfs.iter().filter(|ref x| x.matches(flags)).skip(i);
        match it.next() {
            Some(b) => b,
            None => panic!("Out of bounds index for BxDF type {:?}", flags)
        }
    }
}

<|endoftext|>


<commit_before>//! Callback methods for rustwlc
use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::*;
use rustwlc::input::{pointer, keyboard};
use rustwlc::xkb::Keysym;

use super::keys;
use super::lua;
use super::keys::{KeyEvent, KeyPress};

/// If the event is handled by way-cooler
const EVENT_HANDLED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

// wlc callbacks

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
             output, *old_size_ptr, *new_size_ptr);
}
/*
pub extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

pub extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}
*/
pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    return true;
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_geometry(view: WlcView, geometry: &Geometry) {
    trace!("view_request_geometry: {:?} wants {:?}", view, geometry);
    view.set_geometry(EDGE_NONE, geometry);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("view_request_state: {}, {:?}, handled: {}",
    view.get_title(), state, handled);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, dest: &Point) {
    // Called by views when they have a dang resize mouse thing, we should only
    // let it happen in view floating mode
    trace!("view_request_move: to {}, start interactive mode.", *dest);
}

pub extern fn view_request_resize(view: WlcView,
                              edge: ResizeEdge, location: &Point) {
    trace!("view_request_resize: edge {:?}, to {}, start interactive mode.",
             edge, location);
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    if state == KeyState::Pressed {
        // TODO this function will throw an error in Rustwlc right now
        // let mut keys = keyboard::get_current_keys().into_iter()
        //      .map(|&k| Keysym::from(k)).collect();
        let sym = keyboard::get_keysym_for_key(key, &KeyMod::empty());
        let mut keys = vec![sym];

        let press = KeyPress::new(mods.mods, keys);
        trace!("keypress: {:?}", press);

        if let Some(action) = keys::get(&press) {
            info!("[key] Found a key!");
            action();
            return EVENT_HANDLED;
        }
        else {
            trace!("keypress: No callback");
        }
    }

    return EVENT_PASS_THROUGH;
}

pub extern fn pointer_button(view: WlcView, _time: u32,
                         mods: &KeyboardModifiers, button: u32,
                         state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        trace!("button: 0x{:x}, point {}", &button, point);

        if !view.is_root() {
            view.focus();
        }

        if button == 0xfee9 {
            trace!("Found left click?");
        }

        //let sym = keyboard::get_keysym_for_key(key, &KeyMod::empty());
        let sym = Keysym::from(button);
        let press = KeyPress::new(mods.mods, vec![sym.clone()]);
        trace!("sym: {} {:?}", &sym.get_name().unwrap(), press);
    }
    false
}

pub extern fn pointer_scroll(_view: WlcView, button: u32,
                         _mods_ptr: &KeyboardModifiers, axis: ScrollAxis,
                         heights: [u64; 2]) -> bool {
    trace!("pointer_scroll: press {}, {:?} to {:?}", button, axis, heights);
    false
}

pub extern fn pointer_motion(_view: WlcView, _time: u32, point: &Point) -> bool {
    pointer::set_position(point);
    false
}

/*
pub extern fn touch(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: &Point) -> bool {
    false
}
*/

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    trace!("compositor_ready");
    info!("Initializing lua...");
    lua::init();
}
<commit_msg>Update pointer_scroll callback to floats<commit_after>//! Callback methods for rustwlc
use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::*;
use rustwlc::input::{pointer, keyboard};
use rustwlc::xkb::Keysym;

use super::keys;
use super::lua;
use super::keys::{KeyEvent, KeyPress};

/// If the event is handled by way-cooler
const EVENT_HANDLED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

// wlc callbacks

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
             output, *old_size_ptr, *new_size_ptr);
}
/*
pub extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

pub extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}
*/
pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    return true;
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_geometry(view: WlcView, geometry: &Geometry) {
    trace!("view_request_geometry: {:?} wants {:?}", view, geometry);
    view.set_geometry(EDGE_NONE, geometry);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("view_request_state: {}, {:?}, handled: {}",
    view.get_title(), state, handled);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, dest: &Point) {
    // Called by views when they have a dang resize mouse thing, we should only
    // let it happen in view floating mode
    trace!("view_request_move: to {}, start interactive mode.", *dest);
}

pub extern fn view_request_resize(view: WlcView,
                              edge: ResizeEdge, location: &Point) {
    trace!("view_request_resize: edge {:?}, to {}, start interactive mode.",
             edge, location);
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    if state == KeyState::Pressed {
        // TODO this function will throw an error in Rustwlc right now
        // let mut keys = keyboard::get_current_keys().into_iter()
        //      .map(|&k| Keysym::from(k)).collect();
        let sym = keyboard::get_keysym_for_key(key, &KeyMod::empty());
        let mut keys = vec![sym];

        let press = KeyPress::new(mods.mods, keys);
        trace!("keypress: {:?}", press);

        if let Some(action) = keys::get(&press) {
            info!("[key] Found a key!");
            action();
            return EVENT_HANDLED;
        }
        else {
            trace!("keypress: No callback");
        }
    }

    return EVENT_PASS_THROUGH;
}

pub extern fn pointer_button(view: WlcView, _time: u32,
                         mods: &KeyboardModifiers, button: u32,
                         state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        trace!("button: 0x{:x}, point {}", &button, point);

        if !view.is_root() {
            view.focus();
        }

        if button == 0xfee9 {
            trace!("Found left click?");
        }

        //let sym = keyboard::get_keysym_for_key(key, &KeyMod::empty());
        let sym = Keysym::from(button);
        let press = KeyPress::new(mods.mods, vec![sym.clone()]);
        trace!("sym: {} {:?}", &sym.get_name().unwrap(), press);
    }
    false
}

pub extern fn pointer_scroll(_view: WlcView, button: u32,
                         _mods_ptr: &KeyboardModifiers, axis: ScrollAxis,
                         heights: [f64; 2]) -> bool {
    trace!("pointer_scroll: press {}, {:?} to {:?}", button, axis, heights);
    false
}

pub extern fn pointer_motion(_view: WlcView, _time: u32, point: &Point) -> bool {
    pointer::set_position(point);
    false
}

/*
pub extern fn touch(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: &Point) -> bool {
    false
}
*/

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    trace!("compositor_ready");
    info!("Initializing lua...");
    lua::init();
}
<|endoftext|>