<commit_before>//  based on:
//  http://shootout.alioth.debian.org/
//   u64q/program.php?test=mandelbrot&lang=python3&id=2
//
//  takes 3 optional args:
//   square image size, defaults to 80_u
//   yield frequency, defaults to 10_u (yield every 10 spawns)
//   output path, default is "" (no output), "-" means stdout
//
//  in the shootout, they use 16000 as image size
//  yield frequency doesn't seem to have much effect
//
//  writes pbm image to output path

use std;
import io::writer_util;
import std::map::hashmap;

type cmplx = {re: f64, im: f64};
type line = {i: uint, b: [u8]};

impl arith for cmplx {
    fn *(x: cmplx) -> cmplx {
        {re: self.re*x.re - self.im*x.im, im: self.re*x.im + self.im*x.re}
    }

    fn +(x: cmplx) -> cmplx {
        {re: self.re + x.re, im: self.im + x.im}
    }
}

pure fn cabs(x: cmplx) -> f64
{
    x.re*x.re + x.im*x.im
}

fn mb(x: cmplx) -> bool
{
    let mut z = {re: 0., im: 0.};
    let mut i = 0;
    let mut in = true;
    while i < 50 {
        z = z*z + x;
        if cabs(z) >= 4. {
            in = false;
            break;
        }
        i += 1;
    }
    in
}

fn fillbyte(x: cmplx, incr: f64) -> u8 {
    let mut rv = 0_u8;
    let mut i = 0_u8;
    while i < 8_u8 {
        let z = {re: x.re + (i as f64)*incr, im: x.im};
        if mb(z) {
            rv += 1_u8 << (7_u8 - i);
        }
        i += 1_u8;
    }
    rv
}

fn chanmb(i: uint, size: uint, ch: comm::chan<line>) -> ()
{
    let mut crv = [];
    let incr = 2./(size as f64);
    let y = incr*(i as f64) - 1.;
    let xincr = 8.*incr;
    for uint::range(0_u, size/8_u) {
        |j|
        let x = {re: xincr*(j as f64) - 1.5, im: y};
        crv += [fillbyte(x, incr)];
    };
    comm::send(ch, {i:i, b:crv});
}

type devnull = {dn: int};

impl of io::writer for devnull {
    fn write(_b: [const u8]/&) {}
    fn seek(_i: int, _s: io::seek_style) {}
    fn tell() -> uint {0_u}
    fn flush() -> int {0}
}

fn writer(path: str, writech: comm::chan<comm::chan<line>>, size: uint)
{
    let p: comm::port<line> = comm::port();
    let ch = comm::chan(p);
    comm::send(writech, ch);
    let cout: io::writer = alt path {
        "" {
            {dn: 0} as io::writer
        }
        "-" {
            io::stdout()
        }
        _ {
            result::get(
                io::file_writer(path,
                [io::create, io::truncate]))
        }
    };
    cout.write_line("P4");
    cout.write_line(#fmt("%u %u", size, size));
    let lines = std::map::uint_hash();
    let mut done = 0_u;
    let mut i = 0_u;
    while i < size {
        let aline = comm::recv(p);
        if aline.i == done {
            #debug("W %u", aline.i);
            cout.write(aline.b);
            done += 1_u;
            let mut prev = done;
            while prev <= i {
                if lines.contains_key(prev) {
                    #debug("WS %u", prev);
                    // FIXME (#2280): this temporary shouldn't be
                    // necessary, but seems to be, for borrowing.
                    let v : [u8] = lines.get(prev);
                    cout.write(v);
                    done += 1_u;
                    lines.remove(prev);
                    prev += 1_u;
                }
                else {
                    break
                }
            };
        }
        else {
            #debug("S %u", aline.i);
            lines.insert(aline.i, aline.b);
        };
        i += 1_u;
    }
}

fn main(args: [str]) {
    let path = if vec::len(args) < 4_u { "" }
    else { args[3] };

    let args = if os::getenv("RUST_BENCH").is_some() {
        ["", "4000", "10"]
    } else if args.len() <= 1u {
        ["", "80", "10"]
    } else {
        args
    };

    let size = uint::from_str(args[1]).get();
    let yieldevery = uint::from_str(args[2]).get();

    let writep = comm::port();
    let writech = comm::chan(writep);
    task::spawn {||
        writer(path, writech, size);
    };
    let ch = comm::recv(writep);
    for uint::range(0_u, size) {|j|
        task::spawn {|| chanmb(j, size, ch);};
        if j % yieldevery == 0_u {
            #debug("Y %u", j);
            task::yield();
        };
    };
}
<commit_msg>fix args to shootout-mandelbrot benchmark<commit_after>//  based on:
//  http://shootout.alioth.debian.org/
//   u64q/program.php?test=mandelbrot&lang=python3&id=2
//
//  takes 3 optional args:
//   square image size, defaults to 80_u
//   yield frequency, defaults to 10_u (yield every 10 spawns)
//   output path, default is "" (no output), "-" means stdout
//
//  in the shootout, they use 16000 as image size
//  yield frequency doesn't seem to have much effect
//
//  writes pbm image to output path

use std;
import io::writer_util;
import std::map::hashmap;

type cmplx = {re: f64, im: f64};
type line = {i: uint, b: [u8]};

impl arith for cmplx {
    fn *(x: cmplx) -> cmplx {
        {re: self.re*x.re - self.im*x.im, im: self.re*x.im + self.im*x.re}
    }

    fn +(x: cmplx) -> cmplx {
        {re: self.re + x.re, im: self.im + x.im}
    }
}

pure fn cabs(x: cmplx) -> f64
{
    x.re*x.re + x.im*x.im
}

fn mb(x: cmplx) -> bool
{
    let mut z = {re: 0., im: 0.};
    let mut i = 0;
    let mut in = true;
    while i < 50 {
        z = z*z + x;
        if cabs(z) >= 4. {
            in = false;
            break;
        }
        i += 1;
    }
    in
}

fn fillbyte(x: cmplx, incr: f64) -> u8 {
    let mut rv = 0_u8;
    let mut i = 0_u8;
    while i < 8_u8 {
        let z = {re: x.re + (i as f64)*incr, im: x.im};
        if mb(z) {
            rv += 1_u8 << (7_u8 - i);
        }
        i += 1_u8;
    }
    rv
}

fn chanmb(i: uint, size: uint, ch: comm::chan<line>) -> ()
{
    let mut crv = [];
    let incr = 2./(size as f64);
    let y = incr*(i as f64) - 1.;
    let xincr = 8.*incr;
    for uint::range(0_u, size/8_u) {
        |j|
        let x = {re: xincr*(j as f64) - 1.5, im: y};
        crv += [fillbyte(x, incr)];
    };
    comm::send(ch, {i:i, b:crv});
}

type devnull = {dn: int};

impl of io::writer for devnull {
    fn write(_b: [const u8]/&) {}
    fn seek(_i: int, _s: io::seek_style) {}
    fn tell() -> uint {0_u}
    fn flush() -> int {0}
}

fn writer(path: str, writech: comm::chan<comm::chan<line>>, size: uint)
{
    let p: comm::port<line> = comm::port();
    let ch = comm::chan(p);
    comm::send(writech, ch);
    let cout: io::writer = alt path {
        "" {
            {dn: 0} as io::writer
        }
        "-" {
            io::stdout()
        }
        _ {
            result::get(
                io::file_writer(path,
                [io::create, io::truncate]))
        }
    };
    cout.write_line("P4");
    cout.write_line(#fmt("%u %u", size, size));
    let lines = std::map::uint_hash();
    let mut done = 0_u;
    let mut i = 0_u;
    while i < size {
        let aline = comm::recv(p);
        if aline.i == done {
            #debug("W %u", aline.i);
            cout.write(aline.b);
            done += 1_u;
            let mut prev = done;
            while prev <= i {
                if lines.contains_key(prev) {
                    #debug("WS %u", prev);
                    // FIXME (#2280): this temporary shouldn't be
                    // necessary, but seems to be, for borrowing.
                    let v : [u8] = lines.get(prev);
                    cout.write(v);
                    done += 1_u;
                    lines.remove(prev);
                    prev += 1_u;
                }
                else {
                    break
                }
            };
        }
        else {
            #debug("S %u", aline.i);
            lines.insert(aline.i, aline.b);
        };
        i += 1_u;
    }
}

fn main(args: [str]) {
    let args = if os::getenv("RUST_BENCH").is_some() {
        ["", "4000", "10"]
    } else {
        args
    };

    let path = if vec::len(args) < 4_u { "" }
    else { args[3] };

    let yieldevery = if vec::len(args) < 3_u { 10_u }
    else { uint::from_str(args[2]).get() };

    let size = if vec::len(args) < 2_u { 80_u }
    else { uint::from_str(args[1]).get() };

    let writep = comm::port();
    let writech = comm::chan(writep);
    task::spawn {||
        writer(path, writech, size);
    };
    let ch = comm::recv(writep);
    for uint::range(0_u, size) {|j|
        task::spawn {|| chanmb(j, size, ch);};
        if j % yieldevery == 0_u {
            #debug("Y %u", j);
            task::yield();
        };
    };
}
<|endoftext|>


<commit_before>
pub struct UnwindState {
	regs: [u32; 16],
	vsp: u32,
}

#[derive(Debug)]
#[allow(raw_pointer_derive)]
pub enum Error
{
	Refuse,	// Not an error
	Malformed,
	BadPointer(*const (),usize),
	Todo,
}

macro_rules! getreg {
	($r:ident) => {{ let v; asm!( concat!("mov $0, ", stringify!($r)) : "=r"(v)); v }};
}

impl UnwindState {
	#[inline(always)]
	pub fn new_cur() -> UnwindState {
		// SAFE: Just reads register states
		unsafe {
			UnwindState {
				regs: [
					getreg!(r0), getreg!(r1), getreg!(r2), getreg!(r3),
					getreg!(r4), getreg!(r5), getreg!(r6), getreg!(r7),
					getreg!(r8), getreg!(r9), getreg!(r10), getreg!(r11),
					getreg!(r12), getreg!(sp), getreg!(lr), getreg!(pc),
					],
				vsp: { let v; asm!("mov $0, sp" : "=r" (v)); v },
			}
		}
	}
	pub fn from_regs(regs: [u32; 16]) -> UnwindState {
		UnwindState {
			regs: regs,
			vsp: regs[13],
		}
	}

	pub fn get_ip(&self) -> u32 { self.regs[15] }
	pub fn get_lr(&self) -> u32 { self.regs[14] }

	pub fn unwind_step(&mut self, info: &u32) -> Result<(),Error> {
		let base = info as *const _ as usize;
		let info = *info;
		if info == 0x1 {
			// Can't unwind
			return Err( Error::Refuse );
		}
		else if (info >> 31) == 1 {
			// Inline information
			if info >> 24 != 0x80 {
				log_error!("BUG: Malformed entry at {:#x}: SBZ bits set 0x{:x} != 0x8", base+4, info >> 24);
				return Err( Error::Malformed );
			}
			try!( self.unwind_short16(info) );
		}
		else {
			// Indirect pointer
			let ofs = (info | (1 << 31)) as usize;
			let ptr = (base + ofs) as *const u32;
			//log_debug!("ptr = {:#x} + {:#x} = {:p}", base, ofs, ptr);
			// SAFE: Validity checked
			let word = unsafe {
				if ! ::memory::virt::is_reserved(ptr) {
					log_error!("BUG: Malformed entry at {:#x} - ptr={:p}", base+4, ptr);
					return Err( Error::Malformed );
				}
				*ptr
				};
			if word & 0x8000_0000 != 0 {
				if (word >> 28) & 0xF != 0x8 {
					log_error!("BUG: Malformed entry at {:p}: SBZ bits set 0x{:x} != 0x8", ptr, word >> 28);
					return Err( Error::Malformed );
				}
				let personality = (word >> 24) & 0xF;
				let words = if personality == 1 || personality == 2 {
						let word_count = (word >> 16) & 0xff;
						// SAFE: Will be checked
						let words_ptr = unsafe { ptr.offset(1) };
						// SAFE: Lifetime is 'static, data is POD
						match unsafe { ::memory::buf_to_slice(words_ptr, word_count as usize) }
						{
						Some(b) => b,
						None => {
							log_error!("BUG: Malformed entry at {:p}: {} words not valid afterwards", ptr, word_count);
							return Err( Error::Malformed );
							},
						}
					}
					else {
						&[] as &[u32]
					};

				match personality
				{
				0 => {
					try!( self.unwind_short16(word) );
					},
				1 => {
					try!( self.unwind_long16(word, words) );
					},
				2 => {
					// SAFE: Lifetime is 'static, data is POD
					try!( self.unwind_long32(word, words) );
					},
				v @ _ => {
					log_error!("TODO: Handle extra-word compact v={}", v);
					return Err( Error::Todo );
					},
				}
			}
			else {
				log_error!("TODO: Custom exception routine? word={:#x}", word);
				return Err( Error::Todo );
			}
		}

		Ok( () )
	}

	fn pop(&mut self) -> Result<u32,Error> {
		// SAFE: Memory is present
		let v = unsafe {
			let ptr = self.vsp as *const u32;
			if ! ::memory::virt::is_reserved(ptr) {
				log_error!("BUG: Stack pointer {:p} invalid", ptr);
				return Err( Error::BadPointer(ptr as *const (), 4) );
			}
			*ptr
			};
		self.vsp += 4;
		Ok( v )
	}

	/// Returns `true` if instruction stream is complete
	fn unwind_instr<F>(&mut self, byte: u8, mut getb: F) -> Result<bool,Error>
	where
		F: FnMut() -> Result<u8,Error>
	{
		match byte >> 4
		{
		0x0 ... 0x3 => {	// ARM_EXIDX_CMD_DATA_POP
			let count = (byte & 0x3F) as u32 * 4 + 4;
			//log_debug!("VSP += {:#x}*4+4 ({})", byte & 0x3F, count);
			self.vsp += count;
			},
		0x4 ... 0x7 => {	// ARM_EXIDX_CMD_DATA_PUSH
			let count = (byte & 0x3F) as u32 * 4 + 4;
			//log_debug!("VSP -= {:#x}*4+4 ({})", byte & 0x3F, count);
			self.vsp -= count;
			},
		0x8 => {	// ARM_EXIDX_CMD_REG_POP
			let extra = try!( getb() );
			if byte == 0x80 && extra == 0x00 {
				// Refuse to unwind
				return Err( Error::Refuse );
			}
			//log_debug!("POP mask {:#x}{:02x}", byte & 0xF, extra);

			if extra & 0x01 != 0 { self.regs[4] = try!(self.pop()); }	// R4
			if extra & 0x02 != 0 { self.regs[5] = try!(self.pop()); }	// R5
			if extra & 0x04 != 0 { self.regs[6] = try!(self.pop()); }	// R6
			if extra & 0x08 != 0 { self.regs[7] = try!(self.pop()); }	// R7
			if extra & 0x10 != 0 { self.regs[8] = try!(self.pop()); }	// R8
			if extra & 0x20 != 0 { self.regs[9] = try!(self.pop()); }	// R9
			if extra & 0x40 != 0 { self.regs[10] = try!(self.pop()); }	// R10
			if extra & 0x80 != 0 { self.regs[11] = try!(self.pop()); }	// R11
			if byte & 0x1 != 0 { self.regs[12] = try!(self.pop()); }	// R12
			if byte & 0x2 != 0 { self.regs[13] = try!(self.pop()); }	// R13
			if byte & 0x4 != 0 { self.regs[14] = try!(self.pop()); }	// R14
			if byte & 0x8 != 0 { self.regs[15] = try!(self.pop()); }	// R15
			},
		0x9 => {	// ARM_EXIDX_CMD_REG_TO_SP
			//log_debug!("VSP = R{}", byte & 0xF);
			self.vsp = self.regs[(byte & 0xF) as usize];
			},
		0xA => {	// ARM_EXIDX_CMD_REG_POP
			let pop_lr = byte & 0x8 != 0;
			let count = (byte&0x7) as usize;
			//log_debug!("POP {{r4-r{}{}}}", 4 + count, if pop_lr { ",lr" } else { "" });
			for r in 4 .. 4 + count + 1 {
				self.regs[r] = try!(self.pop());
			}
			if pop_lr { self.regs[14] = try!(self.pop()); }
			},
		0xB => match byte & 0xF
			{
			0 => return Ok(true),	// ARM_EXIDX_CMD_FINISH
			_ => {
				log_error!("TODO: EXIDX opcode {:#02x}", byte);
				return Err( Error::Todo );
				},
			},
		_ => {
			log_error!("TODO: EXIDX opcode {:#02x}", byte);
			return Err( Error::Todo );
			},
		}
		Ok( false )
	}

	fn getb<I: Iterator<Item=u8>>(it: &mut I) -> Result<u8,Error> {
		match it.next()
		{
		Some(v) => {
			//log_trace!("(G) byte {:#x}", v);
			Ok(v)
			},
		None => {
			log_warning!("Out of bytes for unwind mid-instruction");
			Err( Error::Malformed )
			},
		}
	}

	pub fn unwind_short16(&mut self, instrs: u32) -> Result<(), Error> {
		let mut it = WordBytesLE(instrs, 3);
		while let Some(b) = it.next()
		{
			if try!( self.unwind_instr(b, || Self::getb(&mut it)) ) {
				break ;
			}
		}
		Ok( () )
	}
	pub fn unwind_long16(&mut self, instrs: u32, extra: &[u32]) -> Result<(), Error> {
		let mut it = WordBytesLE(instrs, 2).chain( extra.iter().flat_map(|w| WordBytesLE(*w, 4)) );
		while let Some(b) = it.next()
		{
			if try!( self.unwind_instr(b, || Self::getb(&mut it)) ) {
				break ;
			}
		}
		Ok( () )
	}
	pub fn unwind_long32(&mut self, instrs: u32, extra: &[u32]) -> Result<(), Error> {
		log_error!("TODO: unwind_long32");
		Err( Error::Todo )
	}
}

struct WordBytesLE(u32, u8);
impl ::core::iter::Iterator for WordBytesLE {
	type Item = u8;
	fn next(&mut self) -> Option<u8> {
		//log_trace!("self = ({:#x},{})", self.0, self.1);
		if self.1 == 0 {
			None
		}
		else {
			self.1 -= 1;
			Some( (self.0 >> (8 * self.1 as usize)) as u8 )
		}
	}
}

pub fn get_unwind_info_for(addr: usize) -> Option<(usize, &'static u32)>
{
	extern "C" {
		static __exidx_start: [u32; 2];
		static __exidx_end: ::Void;
	}

	let base = &__exidx_start as *const _ as usize;
	// SAFE: 'static slice
	let exidx_tab: &[ [u32; 2] ] = unsafe { ::core::slice::from_raw_parts(&__exidx_start, (&__exidx_end as *const _ as usize - base) / (2*4)) };

	let mut best = (0,0);
	// Locate the closest entry before the return address
	for (i,e) in exidx_tab.iter().enumerate() {
		assert!(e[0] < 0x8000_0000);
		let fcn_start = e[0] as usize + 0x8000_0000 + &e[0] as *const _ as usize;
		// If before the address, but after the previous closest
		if fcn_start < addr && fcn_start > best.0 {
			// then use it
			//log_trace!("{}: Use fcn_start={:#x}", i, fcn_start);
			best = (fcn_start, i);
		}
		else {
			//log_trace!("{}: Skip fcn_start={:#x}", i, fcn_start);
		}
	}
	//log_debug!("get_unwind_info_for({:#x}) : best = ({:#x}, {})", addr, best.0, best.1);
	if best.0 == 0 {
		None
	}
	else {
		Some( (best.0, &exidx_tab[best.1][1]) )
	}
}
<commit_msg>Kernel/ARMv7 - Support an extra unwind opcode<commit_after>
pub struct UnwindState {
	regs: [u32; 16],
	vsp: u32,
}

#[derive(Debug)]
#[allow(raw_pointer_derive)]
pub enum Error
{
	Refuse,	// Not an error
	Malformed,
	BadPointer(*const (),usize),
	Todo,
}

macro_rules! getreg {
	($r:ident) => {{ let v; asm!( concat!("mov $0, ", stringify!($r)) : "=r"(v)); v }};
}

impl UnwindState {
	#[inline(always)]
	pub fn new_cur() -> UnwindState {
		// SAFE: Just reads register states
		unsafe {
			UnwindState {
				regs: [
					getreg!(r0), getreg!(r1), getreg!(r2), getreg!(r3),
					getreg!(r4), getreg!(r5), getreg!(r6), getreg!(r7),
					getreg!(r8), getreg!(r9), getreg!(r10), getreg!(r11),
					getreg!(r12), getreg!(sp), getreg!(lr), getreg!(pc),
					],
				vsp: { let v; asm!("mov $0, sp" : "=r" (v)); v },
			}
		}
	}
	pub fn from_regs(regs: [u32; 16]) -> UnwindState {
		UnwindState {
			regs: regs,
			vsp: regs[13],
		}
	}

	pub fn get_ip(&self) -> u32 { self.regs[15] }
	pub fn get_lr(&self) -> u32 { self.regs[14] }

	pub fn unwind_step(&mut self, info: &u32) -> Result<(),Error> {
		let base = info as *const _ as usize;
		let info = *info;
		if info == 0x1 {
			// Can't unwind
			return Err( Error::Refuse );
		}
		else if (info >> 31) == 1 {
			// Inline information
			if info >> 24 != 0x80 {
				log_error!("BUG: Malformed entry at {:#x}: SBZ bits set 0x{:x} != 0x8", base+4, info >> 24);
				return Err( Error::Malformed );
			}
			try!( self.unwind_short16(info) );
		}
		else {
			// Indirect pointer
			let ofs = (info | (1 << 31)) as usize;
			let ptr = (base + ofs) as *const u32;
			//log_debug!("ptr = {:#x} + {:#x} = {:p}", base, ofs, ptr);
			// SAFE: Validity checked
			let word = unsafe {
				if ! ::memory::virt::is_reserved(ptr) {
					log_error!("BUG: Malformed entry at {:#x} - ptr={:p}", base+4, ptr);
					return Err( Error::Malformed );
				}
				*ptr
				};
			if word & 0x8000_0000 != 0 {
				if (word >> 28) & 0xF != 0x8 {
					log_error!("BUG: Malformed entry at {:p}: SBZ bits set 0x{:x} != 0x8", ptr, word >> 28);
					return Err( Error::Malformed );
				}
				let personality = (word >> 24) & 0xF;
				let words = if personality == 1 || personality == 2 {
						let word_count = (word >> 16) & 0xff;
						// SAFE: Will be checked
						let words_ptr = unsafe { ptr.offset(1) };
						// SAFE: Lifetime is 'static, data is POD
						match unsafe { ::memory::buf_to_slice(words_ptr, word_count as usize) }
						{
						Some(b) => b,
						None => {
							log_error!("BUG: Malformed entry at {:p}: {} words not valid afterwards", ptr, word_count);
							return Err( Error::Malformed );
							},
						}
					}
					else {
						&[] as &[u32]
					};

				match personality
				{
				0 => {
					try!( self.unwind_short16(word) );
					},
				1 => {
					try!( self.unwind_long16(word, words) );
					},
				2 => {
					// SAFE: Lifetime is 'static, data is POD
					try!( self.unwind_long32(word, words) );
					},
				v @ _ => {
					log_error!("TODO: Handle extra-word compact v={}", v);
					return Err( Error::Todo );
					},
				}
			}
			else {
				log_error!("TODO: Custom exception routine? word={:#x}", word);
				return Err( Error::Todo );
			}
		}

		Ok( () )
	}

	fn pop(&mut self) -> Result<u32,Error> {
		// SAFE: Memory is present
		let v = unsafe {
			let ptr = self.vsp as *const u32;
			if ! ::memory::virt::is_reserved(ptr) {
				log_error!("BUG: Stack pointer {:p} invalid", ptr);
				return Err( Error::BadPointer(ptr as *const (), 4) );
			}
			*ptr
			};
		self.vsp += 4;
		Ok( v )
	}

	/// Returns `true` if instruction stream is complete
	fn unwind_instr<F>(&mut self, byte: u8, mut getb: F) -> Result<bool,Error>
	where
		F: FnMut() -> Result<u8,Error>
	{
		match byte >> 4
		{
		0x0 ... 0x3 => {	// ARM_EXIDX_CMD_DATA_POP
			let count = (byte & 0x3F) as u32 * 4 + 4;
			//log_debug!("VSP += {:#x}*4+4 ({})", byte & 0x3F, count);
			self.vsp += count;
			},
		0x4 ... 0x7 => {	// ARM_EXIDX_CMD_DATA_PUSH
			let count = (byte & 0x3F) as u32 * 4 + 4;
			//log_debug!("VSP -= {:#x}*4+4 ({})", byte & 0x3F, count);
			self.vsp -= count;
			},
		0x8 => {	// ARM_EXIDX_CMD_REG_POP
			let extra = try!( getb() );
			if byte == 0x80 && extra == 0x00 {
				// Refuse to unwind
				return Err( Error::Refuse );
			}
			//log_debug!("POP mask {:#x}{:02x}", byte & 0xF, extra);

			// Lowest register at lowest stack
			if extra & 0x01 != 0 { self.regs[4] = try!(self.pop()); }	// R4
			if extra & 0x02 != 0 { self.regs[5] = try!(self.pop()); }	// R5
			if extra & 0x04 != 0 { self.regs[6] = try!(self.pop()); }	// R6
			if extra & 0x08 != 0 { self.regs[7] = try!(self.pop()); }	// R7
			if extra & 0x10 != 0 { self.regs[8] = try!(self.pop()); }	// R8
			if extra & 0x20 != 0 { self.regs[9] = try!(self.pop()); }	// R9
			if extra & 0x40 != 0 { self.regs[10] = try!(self.pop()); }	// R10
			if extra & 0x80 != 0 { self.regs[11] = try!(self.pop()); }	// R11
			if byte & 0x1 != 0 { self.regs[12] = try!(self.pop()); }	// R12
			if byte & 0x2 != 0 { self.regs[13] = try!(self.pop()); }	// R13
			if byte & 0x4 != 0 { self.regs[14] = try!(self.pop()); }	// R14
			if byte & 0x8 != 0 { self.regs[15] = try!(self.pop()); }	// R15
			},
		0x9 => {	// ARM_EXIDX_CMD_REG_TO_SP
			//log_debug!("VSP = R{}", byte & 0xF);
			self.vsp = self.regs[(byte & 0xF) as usize];
			},
		0xA => {	// ARM_EXIDX_CMD_REG_POP
			let pop_lr = byte & 0x8 != 0;
			let count = (byte&0x7) as usize;
			//log_debug!("POP {{r4-r{}{}}}", 4 + count, if pop_lr { ",lr" } else { "" });
			for r in 4 .. 4 + count + 1 {
				self.regs[r] = try!(self.pop());
			}
			if pop_lr { self.regs[14] = try!(self.pop()); }
			},
		0xB => match byte & 0xF
			{
			0 => return Ok(true),	// ARM_EXIDX_CMD_FINISH
			1 => {
				let extra = try!( getb() );
				if extra == 0 {
					log_error!("EXIDX opcode 0xB1 {:#02x} listed as Spare", extra);
				}
				else if extra & 0xF0 != 0 {
					log_error!("EXIDX opcode 0xB1 {:#02x} listed as Spare", extra);
				}
				else {
					// Pop registers
					//log_debug!("POP mask 0-3 {:#x}", extra & 0xFF);
					if extra & 0x1 != 0 { self.regs[0] = try!(self.pop()); }	// R0
					if extra & 0x2 != 0 { self.regs[1] = try!(self.pop()); }	// R1
					if extra & 0x4 != 0 { self.regs[2] = try!(self.pop()); }	// R2
					if extra & 0x8 != 0 { self.regs[3] = try!(self.pop()); }	// R3
				}
				},
			_ => {
				log_error!("TODO: EXIDX opcode {:#02x}", byte);
				return Err( Error::Todo );
				},
			},
		_ => {
			log_error!("TODO: EXIDX opcode {:#02x}", byte);
			return Err( Error::Todo );
			},
		}
		Ok( false )
	}

	fn getb<I: Iterator<Item=u8>>(it: &mut I) -> Result<u8,Error> {
		match it.next()
		{
		Some(v) => {
			//log_trace!("(G) byte {:#x}", v);
			Ok(v)
			},
		None => {
			log_warning!("Out of bytes for unwind mid-instruction");
			Err( Error::Malformed )
			},
		}
	}

	pub fn unwind_short16(&mut self, instrs: u32) -> Result<(), Error> {
		let mut it = WordBytesLE(instrs, 3);
		while let Some(b) = it.next()
		{
			if try!( self.unwind_instr(b, || Self::getb(&mut it)) ) {
				break ;
			}
		}
		Ok( () )
	}
	pub fn unwind_long16(&mut self, instrs: u32, extra: &[u32]) -> Result<(), Error> {
		let mut it = WordBytesLE(instrs, 2).chain( extra.iter().flat_map(|w| WordBytesLE(*w, 4)) );
		while let Some(b) = it.next()
		{
			if try!( self.unwind_instr(b, || Self::getb(&mut it)) ) {
				break ;
			}
		}
		Ok( () )
	}
	pub fn unwind_long32(&mut self, instrs: u32, extra: &[u32]) -> Result<(), Error> {
		log_error!("TODO: unwind_long32");
		Err( Error::Todo )
	}
}

struct WordBytesLE(u32, u8);
impl ::core::iter::Iterator for WordBytesLE {
	type Item = u8;
	fn next(&mut self) -> Option<u8> {
		//log_trace!("self = ({:#x},{})", self.0, self.1);
		if self.1 == 0 {
			None
		}
		else {
			self.1 -= 1;
			Some( (self.0 >> (8 * self.1 as usize)) as u8 )
		}
	}
}

pub fn get_unwind_info_for(addr: usize) -> Option<(usize, &'static u32)>
{
	extern "C" {
		static __exidx_start: [u32; 2];
		static __exidx_end: ::Void;
	}

	let base = &__exidx_start as *const _ as usize;
	// SAFE: 'static slice
	let exidx_tab: &[ [u32; 2] ] = unsafe { ::core::slice::from_raw_parts(&__exidx_start, (&__exidx_end as *const _ as usize - base) / (2*4)) };

	let mut best = (0,0);
	// Locate the closest entry before the return address
	for (i,e) in exidx_tab.iter().enumerate() {
		assert!(e[0] < 0x8000_0000);
		let fcn_start = e[0] as usize + 0x8000_0000 + &e[0] as *const _ as usize;
		// If before the address, but after the previous closest
		if fcn_start < addr && fcn_start > best.0 {
			// then use it
			//log_trace!("{}: Use fcn_start={:#x}", i, fcn_start);
			best = (fcn_start, i);
		}
		else {
			//log_trace!("{}: Skip fcn_start={:#x}", i, fcn_start);
		}
	}
	//log_debug!("get_unwind_info_for({:#x}) : best = ({:#x}, {})", addr, best.0, best.1);
	if best.0 == 0 {
		None
	}
	else {
		Some( (best.0, &exidx_tab[best.1][1]) )
	}
}
<|endoftext|>


<commit_before>#![cfg(not(windows))]

extern crate futures;
extern crate log;
extern crate tokio_core;
extern crate trust_dns;
extern crate trust_dns_proto;

mod server_harness;

use std::env;
use std::fs;
use std::fs::File;
use std::path::Path;
use std::io::*;
use std::net::*;

use tokio_core::reactor::Core;

use trust_dns::client::*;
use trust_dns::tcp::TcpClientStream;
use trust_dns::rr::dnssec::*;

use server_harness::*;

#[cfg(all(not(feature = "ring"), feature = "openssl"))]
fn confg_toml() -> &'static str {
    "openssl_dnssec.toml"
}

#[cfg(all(feature = "ring", not(feature = "openssl")))]
fn confg_toml() -> &'static str {
    "ring_dnssec.toml"
}

#[cfg(all(feature = "ring", feature = "openssl"))]
fn confg_toml() -> &'static str {
    "all_supported_dnssec.toml"
}

fn trust_anchor(public_key_path: &Path, format: KeyFormat, algorithm: Algorithm) -> TrustAnchor {
    let mut file = File::open(public_key_path).expect("key not found");
    let mut buf = Vec::<u8>::new();

    file.read_to_end(&mut buf).expect("could not read key");
    let key_pair = format.decode_key(&buf, Some("123456"), algorithm).expect(
        "could not decode key",
    );

    let public_key = key_pair.to_public_key().unwrap();
    let mut trust_anchor = TrustAnchor::new();

    trust_anchor.insert_trust_anchor(public_key);
    trust_anchor
}

fn standard_conn(port: u16, io_loop: &Core) -> BasicClientHandle {
    let addr: SocketAddr = ("127.0.0.1", port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = TcpClientStream::new(addr, &io_loop.handle());
    ClientFuture::new(stream, sender, &io_loop.handle(), None)
}

fn generic_test(config_toml: &str, key_path: &str, key_format: KeyFormat, algorithm: Algorithm) {
    // use trust_dns::logger;
    // use log::LogLevel;
    // logger::TrustDnsLogger::enable_logging(LogLevel::Debug);

    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);

    named_test_harness(config_toml, |port, _| {
        let mut io_loop = Core::new().unwrap();

        // verify all records are present
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_with_rfc6975(&mut io_loop, client, algorithm);
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_wo_rfc6975(&mut io_loop, client, algorithm);

        // test that request with Secure client is successful, i.e. validates chain
        let trust_anchor = trust_anchor(&server_path.join(key_path), key_format, algorithm);
        let client = standard_conn(port, &io_loop);
        let mut client = SecureClientHandle::with_trust_anchor(client, trust_anchor);

        query_a(&mut io_loop, &mut client);
    });
}

#[test]
#[cfg(feature = "openssl")]
fn test_rsa_sha256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );
}

#[test]
#[cfg(feature = "openssl")]
fn test_rsa_sha512() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA512,
    );
}

#[test]
#[cfg(feature = "openssl")]
fn test_ecdsa_p256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p256.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP256SHA256,
    );
}

#[test]
#[cfg(feature = "openssl")]
fn test_ecdsa_p384() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p384.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP384SHA384,
    );
}

#[test]
#[cfg(feature = "ring")]
fn test_ed25519() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ed25519.pk8",
        KeyFormat::Pkcs8,
        Algorithm::ED25519,
    );
}

#[test]
#[should_panic]
fn test_rsa_sha1_fails() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA1,
    );
}

#[test]
fn test_dnssec_restart_with_update_journal() {
    // TODO: make journal path configurable, it should be in target/tests/...
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);
    let journal = server_path.join("tests/named_test_configs/example.com.jrnl");
    fs::remove_file(&journal).ok();

    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // after running the above test, the journal file should exist
    assert!(journal.exists());

    // and all dnssec tests should still pass
    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // and journal should still exist
    assert!(journal.exists());

    // cleanup...
    // TODO: fix journal path so that it doesn't leave the dir dirty...
    fs::remove_file(&journal).expect("failed to cleanup after test");
}
<commit_msg>Server: Fix --no-default-features --features=dnssec-ring.<commit_after>#![cfg(not(windows))]

extern crate futures;
extern crate log;
extern crate tokio_core;
extern crate trust_dns;
extern crate trust_dns_proto;

mod server_harness;

use std::env;
use std::fs::File;
use std::path::Path;
use std::io::*;
use std::net::*;

use tokio_core::reactor::Core;

use trust_dns::client::*;
use trust_dns::tcp::TcpClientStream;
use trust_dns::rr::dnssec::*;

use server_harness::*;

#[cfg(all(not(feature = "dnssec-ring"), feature = "dnssec-openssl"))]
fn confg_toml() -> &'static str {
    "openssl_dnssec.toml"
}

#[cfg(all(feature = "dnssec-ring", not(feature = "dnssec-openssl")))]
fn confg_toml() -> &'static str {
    "ring_dnssec.toml"
}

#[cfg(all(feature = "dnssec-ring", feature = "dnssec-openssl"))]
fn confg_toml() -> &'static str {
    "all_supported_dnssec.toml"
}

fn trust_anchor(public_key_path: &Path, format: KeyFormat, algorithm: Algorithm) -> TrustAnchor {
    let mut file = File::open(public_key_path).expect("key not found");
    let mut buf = Vec::<u8>::new();

    file.read_to_end(&mut buf).expect("could not read key");
    let key_pair = format.decode_key(&buf, Some("123456"), algorithm).expect(
        "could not decode key",
    );

    let public_key = key_pair.to_public_key().unwrap();
    let mut trust_anchor = TrustAnchor::new();

    trust_anchor.insert_trust_anchor(public_key);
    trust_anchor
}

fn standard_conn(port: u16, io_loop: &Core) -> BasicClientHandle {
    let addr: SocketAddr = ("127.0.0.1", port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = TcpClientStream::new(addr, &io_loop.handle());
    ClientFuture::new(stream, sender, &io_loop.handle(), None)
}

fn generic_test(config_toml: &str, key_path: &str, key_format: KeyFormat, algorithm: Algorithm) {
    // use trust_dns::logger;
    // use log::LogLevel;
    // logger::TrustDnsLogger::enable_logging(LogLevel::Debug);

    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);

    named_test_harness(config_toml, |port, _| {
        let mut io_loop = Core::new().unwrap();

        // verify all records are present
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_with_rfc6975(&mut io_loop, client, algorithm);
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_wo_rfc6975(&mut io_loop, client, algorithm);

        // test that request with Secure client is successful, i.e. validates chain
        let trust_anchor = trust_anchor(&server_path.join(key_path), key_format, algorithm);
        let client = standard_conn(port, &io_loop);
        let mut client = SecureClientHandle::with_trust_anchor(client, trust_anchor);

        query_a(&mut io_loop, &mut client);
    });
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_rsa_sha256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_rsa_sha512() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA512,
    );
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_ecdsa_p256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p256.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP256SHA256,
    );
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_ecdsa_p384() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p384.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP384SHA384,
    );
}

#[test]
#[cfg(feature = "dnssec-ring")]
fn test_ed25519() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ed25519.pk8",
        KeyFormat::Pkcs8,
        Algorithm::ED25519,
    );
}

#[test]
#[should_panic]
fn test_rsa_sha1_fails() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA1,
    );
}

#[cfg(feature = "dnssec-openssl")]
#[test]
fn test_dnssec_restart_with_update_journal() {
    // TODO: make journal path configurable, it should be in target/tests/...
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);
    let journal = server_path.join("tests/named_test_configs/example.com.jrnl");
    std::fs::remove_file(&journal).ok();

    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // after running the above test, the journal file should exist
    assert!(journal.exists());

    // and all dnssec tests should still pass
    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // and journal should still exist
    assert!(journal.exists());

    // cleanup...
    // TODO: fix journal path so that it doesn't leave the dir dirty...
    std::fs::remove_file(&journal).expect("failed to cleanup after test");
}
<|endoftext|>


<commit_before>use log_parser::*;
use timing_analyzer::Timing;

#[derive(Clone, Debug)]
pub struct RequestResponsePair {
    pub request: log_events::Request,
    pub response: log_events::Response,
}

pub fn extract_matching_request_response_pairs(requests: &mut Vec<log_events::Request>,
                                               responses: &mut Vec<log_events::Response>)
                                               -> Vec<RequestResponsePair> {
    let mut request_response_pairs: Vec<RequestResponsePair> = Vec::new();

    for request_index in 0..requests.len() {
        {
            let request = requests.get(request_index);

            if request.is_none() {
                continue;
            }
        }

        let matching_response_index: Option<usize> = responses.iter()
            .position(|response| requests[request_index].id == response.id);

        if matching_response_index.is_some() {
            let request = requests.remove(request_index);
            let response = responses.remove(matching_response_index.unwrap());

            let pair = RequestResponsePair {
                request: request,
                response: response,
            };

            request_response_pairs.push(pair);
        }
    }

    request_response_pairs
}

impl Timing for RequestResponsePair {
    fn num_milliseconds(&self) -> i64 {
        self.response.response_time.num_milliseconds()
    }
}

#[cfg(test)]
mod tests {
    use chrono::*;
    use super::*;
    use log_parser;
    use timing_analyzer::Timing;

    #[test]
    fn test_extract_matching_request_response_pairs() {
        let mut requests = vec![log_parser::log_events::Request {
                                    id: 1,
                                    time: DateTime::parse_from_str("08/Apr/2016:09:57:47 +0200",
                                                                   "%d/%b/%Y:%H:%M:%S %z")
                                        .unwrap(),
                                    original_log_line: "whatever".to_string(),
                                },
                                log_parser::log_events::Request {
                                    id: 77,
                                    time: DateTime::parse_from_str("08/Apr/2016:09:57:47 +0200",
                                                                   "%d/%b/%Y:%H:%M:%S %z")
                                        .unwrap(),
                                    original_log_line: "whatever".to_string(),
                                }];

        let mut responses = vec![log_parser::log_events::Response {
                                     id: 1,
                                     response_time: Duration::milliseconds(7),
                                     original_log_line: "whatever".to_string(),
                                 },
                                 log_parser::log_events::Response {
                                     id: 99,
                                     response_time: Duration::milliseconds(10),
                                     original_log_line: "whatever".to_string(),
                                 }];

        let result = extract_matching_request_response_pairs(&mut requests, &mut responses);

        assert_eq!(result.len(), 1);
        assert_eq!(result[0].request.id, 1);
        assert_eq!(result[0].response.id, 1);

        assert_eq!(requests.len(), 1);
        assert_eq!(responses.len(), 1);
    }

    #[test]
    fn test_timing_trait() {
        let timing: &Timing = &RequestResponsePair {
            request: log_parser::log_events::Request {
                id: 1,
                time: DateTime::parse_from_str("08/Apr/2016:09:57:47 +0200",
                                               "%d/%b/%Y:%H:%M:%S %z")
                    .unwrap(),
                original_log_line: "whatever".to_string(),
            },
            response: log_parser::log_events::Response {
                id: 1,
                response_time: Duration::milliseconds(7),
                original_log_line: "whatever".to_string(),
            },
        } as &Timing;

        let result: i64 = timing.num_milliseconds();
        assert_eq!(result, 7);
    }
}
<commit_msg>Boxed Timings should be Timings, too<commit_after>use log_parser::*;
use timing_analyzer::Timing;

#[derive(Clone, Debug)]
pub struct RequestResponsePair {
    pub request: log_events::Request,
    pub response: log_events::Response,
}

pub fn extract_matching_request_response_pairs(requests: &mut Vec<log_events::Request>,
                                               responses: &mut Vec<log_events::Response>)
                                               -> Vec<RequestResponsePair> {
    let mut request_response_pairs: Vec<RequestResponsePair> = Vec::new();

    for request_index in 0..requests.len() {
        {
            let request = requests.get(request_index);

            if request.is_none() {
                continue;
            }
        }

        let matching_response_index: Option<usize> = responses.iter()
            .position(|response| requests[request_index].id == response.id);

        if matching_response_index.is_some() {
            let request = requests.remove(request_index);
            let response = responses.remove(matching_response_index.unwrap());

            let pair = RequestResponsePair {
                request: request,
                response: response,
            };

            request_response_pairs.push(pair);
        }
    }

    request_response_pairs
}

impl Timing for RequestResponsePair {
    fn num_milliseconds(&self) -> i64 {
        self.response.response_time.num_milliseconds()
    }
}

impl Timing for Box<Timing> {
    fn num_milliseconds(&self) -> i64 {
        (**self).num_milliseconds()
    }
}

#[cfg(test)]
mod tests {
    use chrono::*;
    use super::*;
    use log_parser;
    use timing_analyzer::Timing;

    #[test]
    fn test_extract_matching_request_response_pairs() {
        let mut requests = vec![log_parser::log_events::Request {
                                    id: 1,
                                    time: DateTime::parse_from_str("08/Apr/2016:09:57:47 +0200",
                                                                   "%d/%b/%Y:%H:%M:%S %z")
                                        .unwrap(),
                                    original_log_line: "whatever".to_string(),
                                },
                                log_parser::log_events::Request {
                                    id: 77,
                                    time: DateTime::parse_from_str("08/Apr/2016:09:57:47 +0200",
                                                                   "%d/%b/%Y:%H:%M:%S %z")
                                        .unwrap(),
                                    original_log_line: "whatever".to_string(),
                                }];

        let mut responses = vec![log_parser::log_events::Response {
                                     id: 1,
                                     response_time: Duration::milliseconds(7),
                                     original_log_line: "whatever".to_string(),
                                 },
                                 log_parser::log_events::Response {
                                     id: 99,
                                     response_time: Duration::milliseconds(10),
                                     original_log_line: "whatever".to_string(),
                                 }];

        let result = extract_matching_request_response_pairs(&mut requests, &mut responses);

        assert_eq!(result.len(), 1);
        assert_eq!(result[0].request.id, 1);
        assert_eq!(result[0].response.id, 1);

        assert_eq!(requests.len(), 1);
        assert_eq!(responses.len(), 1);
    }

    #[test]
    fn test_timing_trait() {
        let timing: &Timing = &RequestResponsePair {
            request: log_parser::log_events::Request {
                id: 1,
                time: DateTime::parse_from_str("08/Apr/2016:09:57:47 +0200",
                                               "%d/%b/%Y:%H:%M:%S %z")
                    .unwrap(),
                original_log_line: "whatever".to_string(),
            },
            response: log_parser::log_events::Response {
                id: 1,
                response_time: Duration::milliseconds(7),
                original_log_line: "whatever".to_string(),
            },
        } as &Timing;

        let result: i64 = timing.num_milliseconds();
        assert_eq!(result, 7);

        let boxed_timing = Box::new(timing);

        let result: i64 = boxed_timing.num_milliseconds();
        assert_eq!(result, 7);
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul, Div, Neg, Shr};
use std::cmp::{max, min};

use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

/**

A numeric-ish type for dealing with integer math that has possible rounding error.

A Range represents an inclusive range of real-number values.

(A: Range `operator` B: Range) yields a Range that is a (non-strict) superset of (for all a in A and all b in B, a `operator` b). It prefers to yield as SMALL a possible set as it can, but doesn't guarantee that. For addition, subtraction, and multiplication, this is a generalization of i64 math. For division, it is slightly different (effectively, it rounds in BOTH directions).

Range is also a partially floating-point type: it handles overflow by increasing an exponent value and rounding off. In keeping with its strict behavior, this rounding can only INCREASE the size of the Range, not decrease it.

*/

#[derive (Copy, Clone, Debug)]
pub struct Range {
min: i64,
max: i64,
exponent: u32,
}

fn right_shift_round_up (value: i64, shift: u32)->i64 {(value - 1 + (1 << shift)) >> shift}

impl Range {
pub fn new (min: i64, max: i64)->Range {assert! (max >= min, "invalid Range"); Range {min: min, max: max, exponent: 0}}
pub fn exactly (value: i64)->Range {Range {min: value, max: value, exponent: 0}}
pub fn everywhere ()->Range {Range {min: - i64::max_value(), max: i64::max_value(), exponent: u32::max_value()}}
fn increase_exponent_to (&mut self, new: u32) {
assert! (new >= self.exponent);
let increase =new - self.exponent;
self.increase_exponent_by (increase);
}
fn increase_exponent_by (&mut self, increase: u32) {
self.min >>= increase;
self.max =right_shift_round_up (self.max, increase);
self.exponent += increase;
}
fn minimize_exponent(&mut self) {
while self.exponent >0 && self.min.abs() <(i64::max_value() >> 1) && self.max.abs() <(i64::max_value() >> 1) {
self.min <<= 1;
self.max <<= 1;
self.exponent -= 1;
}
}
}

macro_rules! binary_operation_fill {
($implementor: ident, $joiner: ident, $operation: ident, $method:ident) => {

impl<'a> $operation <& 'a $joiner> for $implementor{
type Output = $implementor;
fn $method (self, other: & 'a $joiner)->$implementor{
(& self).$method (other)
}
}

impl<'a> $operation <$joiner> for & 'a $implementor{
type Output = $implementor;
fn $method (self, other: $joiner)->$implementor{
self.$method (& other)
}
}

impl $operation <$joiner> for $implementor{
type Output = $implementor;
fn $method (self, other: $joiner)->$implementor{
(& self).$method (& other)
}
}

}

}

impl<'a> Neg for & 'a Range {
type Output = Range;
fn neg (self)->Range {
Range {min: - self.max, max: - self.min, exponent: self.exponent}
}
}
impl Neg for Range {
type Output = Range;
fn neg (self)->Range {
Range {min: - self.max, max: - self.min, exponent: self.exponent}
}
}

impl<'a> Add for & 'a Range {
type Output = Range;
fn add (self, other: Self)->Range {
let possibly_needed = max (self.exponent, other.exponent) + 1;
let mut result = self.clone();
let mut other = other.clone();
result.increase_exponent_to (possibly_needed);
other.increase_exponent_to (possibly_needed);
result.min += other.min;
result.max += other.max;
result.minimize_exponent();
result
}
}

binary_operation_fill! (Range, Range, Add, add);

impl<'a> Sub for &'a Range {
type Output = Range;
fn sub (self, other: Self)->Range {
self + (- other)
}
}

binary_operation_fill! (Range, Range, Sub, sub);

impl<'a> Mul for &'a Range {
type Output = Range;
fn mul(self, other: Self)->Range {
let mut result = self.clone();
let mut other = other.clone();
while result.min.abs() >= (1i64 << 32) || result.max.abs() >= (1i64 << 32) {result.increase_exponent_by (1)}
while other.min.abs() >= (1i64 << 32) || other.max.abs() >= (1i64 << 32) {other.increase_exponent_by (1)}
let mut extremes = [result.min*other.min, result.max*other.max, result.min*other.max, result.max*other.min];
extremes.sort();
result = Range {min: extremes [0], max: extremes [3], exponent: result.exponent + other.exponent};
result.minimize_exponent();
result
}
}

impl<'a> Mul<& 'a i64>  for &'a Range {
type Output = Range;
fn mul(self, other: & 'a i64)->Range {
self*Range::exactly (other.clone())
}
}

binary_operation_fill! (Range, Range, Mul, mul);
binary_operation_fill! (Range, i64, Mul, mul);

impl<'a> Div for &'a Range {
type Output = Range;
fn div (self, other: Self)->Range {
let mut result = self.clone();
let mut other = other.clone();
if other.min <= 0 && other.max >= 0 {return Range::everywhere()}
if other.max <0 {other = - other; result = - result;}
//TODO: mess with exponent
if result.min <0 {result.min = (result.min + 1 - other.min)/other.min;}
 else {result.min = (result.min + 1 - other.max)/other.max;}
 if result.max <0 {result.max = (result.max)/other.max;}
  else {result.min = (result.max)/other.min;}
result
}
}

binary_operation_fill! (Range, Range, Div, div);

impl <'a> Shr <& 'a u32> for &'a Range {
type Output = Range;
fn shr (self, other: & u32)->Range {
let mut result = self.clone();
if result.exponent >= other.clone() {
  result.exponent -= other.clone();
  return result;
}
let mut shift = other.clone();
shift -= result.exponent;
result.exponent = 0;
result.min >>= shift;
result.max =right_shift_round_up (self.max, shift);
result
}
}
binary_operation_fill! (Range, u32, Shr, shr);

impl Range {
///Squaring is a slightly narrower operation than self*self, because it never invokes (for instance) self.min*self.max.
fn squared (&self)->Range {
let mut result = self.clone();
while result.min.abs() >= (1i64 << 32) || result.max.abs() >= (1i64 << 32) {result.increase_exponent_by (1)}
if result.min <= 0 && result.max >= 0 {
  result.max = max (result.min*result.min, result.max*result.max);
  result.min = 0;
}
else {
  let mut extrema = [result.min*result.min, result.max*result.max];
  extrema.sort();
  result.max = extrema [1];
  result.min = extrema [0];
}
result.minimize_exponent();
result
}

fn sqrt (&self)->Option <Range> {
let mut result = self.clone();
if result.exponent % 2 == 1 {result.increase_exponent_by (1)}
result.exponent >>= 1;
if result.max <0 {return None;}
if result.min <0 {result.min = 0;}
let mut lower_bound = 0;
let mut upper_bound = 1i64 << 32;
let mut move_size = 1i64 << 31;
while move_size >0 {
if (lower_bound + move_size)*(lower_bound + move_size) <= result.min {lower_bound += move_size;}
if (upper_bound - move_size)*(upper_bound - move_size) >= result.max {upper_bound -= move_size;}
move_size >>= 1;
}
result.min = lower_bound;
result.max = upper_bound;
Some (result)
}
}

/**

A polynomial pseudo-solver, using Range.

Returns a collection of ranges that include the exact roots.

TODO: instead of Vec<Range>, these should return a stack-allocated type.

*/

pub fn roots_linear (coefficients: [Range; 2])->Vec<Range> {
  if coefficients [1].min == 0 && coefficients [1].max == 0 && (coefficients [0].min >0 ||coefficients [0].max <0) {return Vec:: new()}
  //TODO: there's also the case where exactly one of the linear term's extrema is 0, which makes the result be a half open interval... But we are, after all, allowed to return strict supersets of the actual result
  vec![(- coefficients [0])/coefficients [1]]
}
pub fn roots_quadratic (terms: [Range; 3])->Vec<Range> {
let a = terms [2];
let b = terms [1];
let c = terms [0];
let discriminant = b.squared() + a*c*Range::exactly (4);
printlnerr!(" discriminant {:?}", discriminant);
if discriminant.max <0 {return Vec:: new();}
let sqrt = discriminant.sqrt().expect ("I thought we just ruled out the case where the square root would be nonexistent");
printlnerr!(" sqrt {:?}", sqrt);
let result_0 = (- b - sqrt)/(a*2);
let result_1 = (- b + sqrt)/(a*2);
printlnerr!(" result 0 {:?}", result_0);
printlnerr!(" result 1 {:?}", result_1);
//if one of the results is this huge, something bad probably happened
if result_0.exponent >0 || result_1.exponent >0 {return vec![Range::everywhere()];}
if result_0.max >= result_1.min {
  vec![Range {min: result_0.min, max: result_1.max, exponent: 0}]
}
else {
vec![result_0, result_1]
}
}

pub fn roots (terms: & [Range])->Vec<Range> {
  match terms.len() {
    0 => vec![Range::everywhere()],
    1 => if terms [0].min <= 0 && terms [0].max >= 0 {vec![Range::everywhere()]} else {Vec:: new()},
    2 => roots_linear ([terms [0], terms [1]]),
    3 => roots_quadratic ([terms [0], terms [1], terms [2]]),
    size => {
      let derivative: Vec<Range> = terms [1..]. iter().enumerate().map (| (which, term) | term*(which as i64 + 1)).collect();
      vec![]
    }
  }
}

#[test]
fn tests() {
printlnerr!(" {:?}", roots_quadratic ([Range::new (- 900, - 800), Range::new (500, 501), Range::exactly (50)]))
}
<commit_msg>More math work<commit_after>use std::ops::{Add, Sub, Mul, Div, Neg, Shr, Shl};
use std::cmp::{max, min};

use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

/**

A numeric-ish type for dealing with integer math that has possible rounding error.

A Range represents an inclusive range of real-number values.

(A: Range `operator` B: Range) yields a Range that is a (non-strict) superset of (for all a in A and all b in B, a `operator` b). Specifically, it chooses the smallest such Range that has integer endpoints. For addition, subtraction, and multiplication, this is a generalization of i64 math. For division, it is slightly different (effectively, it rounds in BOTH directions).

Range is also a partially floating-point type: it handles overflow by increasing an exponent value and rounding off. This rounding never removes elements from the Range, but sometimes adds new ones.

*/

#[derive (Copy, Clone, Debug)]
pub struct Range {
min: i64,
max: i64,
exponent: u32,
}

fn right_shift_round_up (value: i64, shift: u32)->i64 {(value - 1 + (1 << shift)) >> shift}

impl Range {
pub fn new (min: i64, max: i64)->Range {assert! (max >= min, "invalid Range"); Range {min: min, max: max, exponent: 0}}
pub fn exactly (value: i64)->Range {Range {min: value, max: value, exponent: 0}}
pub fn everywhere ()->Range {Range {min: - i64::max_value(), max: i64::max_value(), exponent: u32::max_value()}}
fn increase_exponent_to (&mut self, new: u32) {
assert! (new >= self.exponent);
let increase =new - self.exponent;
self.increase_exponent_by (increase);
}
fn increase_exponent_by (&mut self, increase: u32) {
self.min >>= increase;
self.max =right_shift_round_up (self.max, increase);
self.exponent += increase;
}
fn minimize_exponent(&mut self) {
while self.exponent >0 && self.min.abs() <(i64::max_value() >> 1) && self.max.abs() <(i64::max_value() >> 1) {
self.min <<= 1;
self.max <<= 1;
self.exponent -= 1;
}
}
pub fn includes_0 (&self)->bool {self.min <= 0 && self.max >= 0}
}

macro_rules! binary_operation_fill {
($implementor: ident, $joiner: ident, $operation: ident, $method:ident) => {

impl<'a> $operation <& 'a $joiner> for $implementor{
type Output = $implementor;
fn $method (self, other: & 'a $joiner)->$implementor{
(& self).$method (other)
}
}

impl<'a> $operation <$joiner> for & 'a $implementor{
type Output = $implementor;
fn $method (self, other: $joiner)->$implementor{
self.$method (& other)
}
}

impl $operation <$joiner> for $implementor{
type Output = $implementor;
fn $method (self, other: $joiner)->$implementor{
(& self).$method (& other)
}
}

}

}

impl<'a> Neg for & 'a Range {
type Output = Range;
fn neg (self)->Range {
Range {min: - self.max, max: - self.min, exponent: self.exponent}
}
}
impl Neg for Range {
type Output = Range;
fn neg (self)->Range {
Range {min: - self.max, max: - self.min, exponent: self.exponent}
}
}

impl<'a> Add for & 'a Range {
type Output = Range;
fn add (self, other: Self)->Range {
let possibly_needed = max (self.exponent, other.exponent) + 1;
let mut result = self.clone();
let mut other = other.clone();
result.increase_exponent_to (possibly_needed);
other.increase_exponent_to (possibly_needed);
result.min += other.min;
result.max += other.max;
result.minimize_exponent();
result
}
}

binary_operation_fill! (Range, Range, Add, add);

impl<'a> Sub for &'a Range {
type Output = Range;
fn sub (self, other: Self)->Range {
self + (- other)
}
}

binary_operation_fill! (Range, Range, Sub, sub);

impl<'a> Mul for &'a Range {
type Output = Range;
fn mul(self, other: Self)->Range {
let mut result = self.clone();
let mut other = other.clone();
while result.min.abs() >= (1i64 << 32) || result.max.abs() >= (1i64 << 32) {result.increase_exponent_by (1)}
while other.min.abs() >= (1i64 << 32) || other.max.abs() >= (1i64 << 32) {other.increase_exponent_by (1)}
let mut extremes = [result.min*other.min, result.max*other.max, result.min*other.max, result.max*other.min];
extremes.sort();
result = Range {min: extremes [0], max: extremes [3], exponent: result.exponent + other.exponent};
result.minimize_exponent();
result
}
}

impl<'a> Mul<& 'a i64>  for &'a Range {
type Output = Range;
fn mul(self, other: & 'a i64)->Range {
self*Range::exactly (other.clone())
}
}

binary_operation_fill! (Range, Range, Mul, mul);
binary_operation_fill! (Range, i64, Mul, mul);

impl<'a> Div for &'a Range {
type Output = Range;
fn div (self, other: Self)->Range {
let mut result = self.clone();
let mut other = other.clone();
if other.min <= 0 && other.max >= 0 {return Range::everywhere()}
if other.max <0 {other = - other; result = - result;}

if other.exponent >result.exponent {
result.increase_exponent_to (other.exponent);
}
result.exponent -= other.exponent;

if result.min <0 {result.min = (result.min + 1 - other.min)/other.min;}
 else {result.min = (result.min)/other.max;}
 if result.max <0 {result.max = (result.max)/other.max;}
  else {result.min = (result.max - 1 + other.min)/other.min;}
result.minimize_exponent();
result
}
}

binary_operation_fill! (Range, Range, Div, div);

impl <'a> Shr <& 'a u32> for &'a Range {
type Output = Range;
fn shr (self, other: & u32)->Range {
let mut result = self.clone();
if result.exponent >= other.clone() {
  result.exponent -= other.clone();
  return result;
}
let mut shift = other.clone();
shift -= result.exponent;
result.exponent = 0;
result.min >>= shift;
result.max =right_shift_round_up (self.max, shift);
result
}
}
binary_operation_fill! (Range, u32, Shr, shr);

impl <'a> Shl <& 'a u32> for &'a Range {
type Output = Range;
fn shl (self, other: & u32)->Range {
let mut result = self.clone();
result.exponent += other.clone();
result.minimize_exponent();
result
}
}
binary_operation_fill! (Range, u32, Shl, shl);

impl Range {
///Squaring is a slightly narrower operation than self*self, because it never invokes (for instance) self.min*self.max.
fn squared (&self)->Range {
let mut result = self.clone();
while result.min.abs() >= (1i64 << 32) || result.max.abs() >= (1i64 << 32) {result.increase_exponent_by (1)}
if result.min <= 0 && result.max >= 0 {
  result.max = max (result.min*result.min, result.max*result.max);
  result.min = 0;
}
else {
  let mut extrema = [result.min*result.min, result.max*result.max];
  extrema.sort();
  result.max = extrema [1];
  result.min = extrema [0];
}
result.minimize_exponent();
result
}

fn sqrt (&self)->Option <Range> {
let mut result = self.clone();
if result.exponent % 2 == 1 {result.increase_exponent_by (1)}
result.exponent >>= 1;
if result.max <0 {return None;}
if result.min <0 {result.min = 0;}
let mut lower_bound = 0;
let mut upper_bound = 1i64 << 32;
let mut move_size = 1i64 << 31;
while move_size >0 {
if (lower_bound + move_size)*(lower_bound + move_size) <= result.min {lower_bound += move_size;}
if (upper_bound - move_size)*(upper_bound - move_size) >= result.max {upper_bound -= move_size;}
move_size >>= 1;
}
result.min = lower_bound;
result.max = upper_bound;
Some (result)
}
}

/**

A polynomial pseudo-solver, using Range.

Returns a collection of ranges that include the exact roots. False-positives are possible.

TODO: instead of Vec<Range>, these should return a stack-allocated type.

*/

pub fn roots_linear (coefficients: [Range; 2])->Vec<Range> {
  if coefficients [1].min == 0 && coefficients [1].max == 0 && (coefficients [0].min >0 ||coefficients [0].max <0) {return Vec:: new()}
  //TODO: there's also the case where exactly one of the linear term's extrema is 0, which makes the result be a half open interval... But we are, after all, allowed to return strict supersets of the actual result
  vec![(- coefficients [0])/coefficients [1]]
}
pub fn roots_quadratic (terms: [Range; 3])->Vec<Range> {
let a = terms [2];
let b = terms [1];
let c = terms [0];
let discriminant = b.squared() + a*c*Range::exactly (4);
//printlnerr!(" discriminant {:?}", discriminant);
if discriminant.max <0 {return Vec:: new();}
let sqrt = discriminant.sqrt().expect ("I thought we just ruled out the case where the square root would be nonexistent");
//printlnerr!(" sqrt {:?}", sqrt);
let result_0 = (- b - sqrt)/(a*2);
let result_1 = (- b + sqrt)/(a*2);
//printlnerr!(" result 0 {:?}", result_0);
//printlnerr!(" result 1 {:?}", result_1);
//if one of the results is this huge, something bad probably happened
if result_0.exponent >0 || result_1.exponent >0 {return vec![Range::everywhere()];}
if result_0.max >= result_1.min {
  vec![Range {min: result_0.min, max: result_1.max, exponent: 0}]
}
else {
vec![result_0, result_1]
}
}

fn find_root (terms: & [Range], min: i64, max: i64)->Option <Range> {
let min_value = evaluate (terms, min);
let max_value = evaluate (terms, max);
let direction;
if min_value.includes_0() {
if max_value.includes_0() {return Some (Range::new (min, max));}
direction = max_value.min.signum();
}
else if max_value.includes_0() {direction = - min_value.min.signum();}
else if max_value.min.signum() == min_value.min.signum(){return None;} else {
direction = max_value.min.signum();
}

let mut lower_bound = min;
let mut upper_bound = max;
let mut move_size = 1i64 << 63;
while move_size >max - min {move_size >>= 1}
while move_size >0 {
if (evaluate (terms, lower_bound + move_size)*direction).max < 0 {lower_bound += move_size;}
if (evaluate (terms, upper_bound - move_size)*direction).min > 0 {upper_bound -= move_size;}
move_size >>= 1;
}
Some (Range::new (lower_bound, upper_bound))

}
fn collect_root (terms: & [Range], min: i64, max: i64, bucket: &mut Vec<Range>) {find_root (terms, min, max).map (| root | bucket.push (root));}

pub fn roots (terms: & [Range])->Vec<Range> {
  match terms.len() {
    0 => vec![Range::everywhere()],
    1 => if terms [0].min <= 0 && terms [0].max >= 0 {vec![Range::everywhere()]} else {Vec:: new()},
    2 => roots_linear ([terms [0], terms [1]]),
    3 => roots_quadratic ([terms [0], terms [1], terms [2]]),
    size => {
      let derivative: Vec<Range> = terms [1..]. iter().enumerate().map (| (which, term) | term*(which as i64 + 1)).collect();
      let extrema = roots (derivative.as_slice());
      if extrema.iter().any (| range | range.exponent >0) {return vec![Range::everywhere()];}
      let mut results = Vec:: new();
      if extrema.is_empty() {collect_root (terms, - i64::max_value(),i64::max_value(), &mut results);}
      else {
        collect_root (terms, - i64::max_value(), extrema [0].min, &mut results);
        for which in 0..(extrema.len() - 1) {
          results.push (extrema [which]);
          if extrema [which].max <extrema [which +1].min {
            collect_root (terms, extrema [which].max, extrema [which +1].min , &mut results);
          }
        }
        collect_root (terms, extrema.last().unwrap().max, i64::max_value(), &mut results);
      }
      results
    }
  }
}

pub fn evaluate(terms: & [Range], input: i64)->Range {
let mut factor = 1;
let mut result = Range::exactly (0);
for term in terms.iter() {
result = result + (term*factor);
factor*= input;
}
result
}

#[test]
fn tests() {
printlnerr!(" {:?}", roots(& [Range::new (- 900, - 800), Range::new (500, 501), Range::exactly (50)]));
printlnerr!(" {:?}", roots(& [Range::new (- 900, - 800), Range::new (500, 501), Range::exactly (50), Range::exactly (1)]));
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::sync::Arc;

use device::Device;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Used to provide synchronization between command buffers during their execution.
///
/// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
/// semaphore's status or wait for it to be signaled.
#[derive(Debug)]
pub struct Semaphore {
    device: Arc<Device>,
    semaphore: vk::Semaphore,
}

impl Semaphore {
    /// See the docs of new().
    #[inline]
    pub fn raw(device: &Arc<Device>) -> Result<Semaphore, OomError> {
        let vk = device.pointers();

        let semaphore = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::SemaphoreCreateInfo = vk::SemaphoreCreateInfo {
                sType: vk::STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
                pNext: 0 as *const _,   // ptr::null()
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSemaphore(device.internal_object(), &INFOS,
                                                 ptr::null(), &mut output)));
            output
        };

        Ok(Semaphore {
            device: device.clone(),
            semaphore: semaphore,
        })
    }

    /// Builds a new semaphore.
    ///
    /// # Panic
    ///
    /// - Panicks if the device or host ran out of memory.
    ///
    #[inline]
    pub fn new(device: &Arc<Device>) -> Arc<Semaphore> {
        Arc::new(Semaphore::raw(device).unwrap())
    }
}

unsafe impl VulkanObject for Semaphore {
    type Object = vk::Semaphore;

    #[inline]
    fn internal_object(&self) -> vk::Semaphore {
        self.semaphore
    }
}

impl Drop for Semaphore {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySemaphore(self.device.internal_object(), self.semaphore, ptr::null());
        }
    }
}

#[cfg(test)]
mod tests {
    use sync::Semaphore;

    #[test]
    fn semaphore_create() {
        let (device, _) = gfx_dev_and_queue!();
        let _ = Semaphore::new(&device);
    }
}
<commit_msg>Make semaphores generic over device type<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::sync::Arc;

use device::Device;
use OomError;
use SafeDeref;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Used to provide synchronization between command buffers during their execution.
///
/// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
/// semaphore's status or wait for it to be signaled.
#[derive(Debug)]
pub struct Semaphore<D = Arc<Device>> where D: SafeDeref<Target = Device> {
    semaphore: vk::Semaphore,
    device: D,
}

impl<D> Semaphore<D> where D: SafeDeref<Target = Device> {
    /// See the docs of new().
    #[inline]
    pub fn raw(device: &D) -> Result<Semaphore<D>, OomError>
        where D: Clone
    {
        let vk = device.pointers();

        let semaphore = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::SemaphoreCreateInfo = vk::SemaphoreCreateInfo {
                sType: vk::STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
                pNext: 0 as *const _,   // ptr::null()
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSemaphore(device.internal_object(), &INFOS,
                                                 ptr::null(), &mut output)));
            output
        };

        Ok(Semaphore {
            device: device.clone(),
            semaphore: semaphore,
        })
    }

    /// Builds a new semaphore.
    ///
    /// # Panic
    ///
    /// - Panicks if the device or host ran out of memory.
    ///
    #[inline]
    pub fn new(device: &D) -> Arc<Semaphore<D>>
        where D: Clone
    {
        Arc::new(Semaphore::raw(device).unwrap())
    }
}

unsafe impl<D> VulkanObject for Semaphore<D> where D: SafeDeref<Target = Device> {
    type Object = vk::Semaphore;

    #[inline]
    fn internal_object(&self) -> vk::Semaphore {
        self.semaphore
    }
}

impl<D> Drop for Semaphore<D> where D: SafeDeref<Target = Device> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySemaphore(self.device.internal_object(), self.semaphore, ptr::null());
        }
    }
}

#[cfg(test)]
mod tests {
    use sync::Semaphore;

    #[test]
    fn semaphore_create() {
        let (device, _) = gfx_dev_and_queue!();
        let _ = Semaphore::new(&device);
    }
}
<|endoftext|>


<commit_before>use select::SelectCommand;
use super::drilldown::Drilldown;
use command::{Command, Query};
use command::Command::Select;
use selectable::fragmentable::Fragmentable;
use command_query::CommandQuery;
use queryable::Queryable;
use commandable::Commandable;
use command_line::CommandLine;

pub struct DrilldownBuilder {
    select: SelectCommand,
    drilldown: Drilldown,
}

/// Drilldown builder.
///
/// ## Simple usage
///
/// ```
/// extern crate ruroonga_command as ruroonga;
/// let select = ruroonga::select::SelectCommand::new("Entries".to_string())
///                  .filter("content @ \"fast\"".to_string());
/// let drilldown = ruroonga::selectable::drilldown::Drilldown::new()
///                  .drilldown("tag".to_string());
/// let mut builder =
///     ruroonga::selectable::drilldown_builder::DrilldownBuilder::new(select, drilldown);
/// let _ = builder.build();
/// ```
/// In more practical example, please refer to drilldown_builder_xxx
/// in [examples/drilldown_builder.rs]
/// (https://github.com/cosmo0920/ruroonga_command/blob/master/examples/drilldown_builder.rs).
impl DrilldownBuilder {
    pub fn new(select: SelectCommand, drilldown: Drilldown) -> DrilldownBuilder {
        DrilldownBuilder {
            select: select,
            drilldown: drilldown,
        }
    }

    pub fn build(self) -> (Command, Query) {
        let mut query: Query = vec![];
        let (ordered_select, select) = self.select.to_fragment();
        for ordered in ordered_select.iter() {
            query.push(ordered.to_owned());
        }
        for (key, value) in select.iter() {
            query.push((key.to_owned(), value.to_owned()));
        }
        let (_, drilldown) = self.drilldown.to_fragment();
        for (key, value) in drilldown.iter() {
            query.push((key.to_owned(), value.to_owned()));
        }
        (Select, query)
    }
}

impl Queryable for DrilldownBuilder {
    fn to_query(self) -> String {
        let (command, query) = self.build();
        let mut command = CommandQuery::new(command, query);
        command.encode()
    }
}

impl Commandable for DrilldownBuilder {
    fn to_command(self) -> String {
        let (command, query) = self.build();
        let mut command = CommandLine::new(command, query);
        command.encode()
    }
}
<commit_msg>drilldown_builder: Fix document<commit_after>use select::SelectCommand;
use super::drilldown::Drilldown;
use command::{Command, Query};
use command::Command::Select;
use selectable::fragmentable::Fragmentable;
use command_query::CommandQuery;
use queryable::Queryable;
use commandable::Commandable;
use command_line::CommandLine;

pub struct DrilldownBuilder {
    select: SelectCommand,
    drilldown: Drilldown,
}

/// Drilldown builder.
///
/// ## Simple usage
///
/// ```
/// extern crate ruroonga_command as ruroonga;
/// let select = ruroonga::select::SelectCommand::new("Entries".to_string())
///                  .filter("content @ \"fast\"".to_string());
/// let drilldown = ruroonga::selectable::drilldown::Drilldown::new()
///                  .drilldown("tag".to_string());
/// let mut builder =
///     ruroonga::selectable::drilldown_builder::DrilldownBuilder::new(select, drilldown);
/// let _ = builder.build();
/// ```
/// In more practical example, please refer to drilldown_builder examples
/// in [examples/drilldown_builder.rs]
/// (https://github.com/cosmo0920/ruroonga_command/blob/master/examples/drilldown_builder.rs).
impl DrilldownBuilder {
    pub fn new(select: SelectCommand, drilldown: Drilldown) -> DrilldownBuilder {
        DrilldownBuilder {
            select: select,
            drilldown: drilldown,
        }
    }

    pub fn build(self) -> (Command, Query) {
        let mut query: Query = vec![];
        let (ordered_select, select) = self.select.to_fragment();
        for ordered in ordered_select.iter() {
            query.push(ordered.to_owned());
        }
        for (key, value) in select.iter() {
            query.push((key.to_owned(), value.to_owned()));
        }
        let (_, drilldown) = self.drilldown.to_fragment();
        for (key, value) in drilldown.iter() {
            query.push((key.to_owned(), value.to_owned()));
        }
        (Select, query)
    }
}

impl Queryable for DrilldownBuilder {
    fn to_query(self) -> String {
        let (command, query) = self.build();
        let mut command = CommandQuery::new(command, query);
        command.encode()
    }
}

impl Commandable for DrilldownBuilder {
    fn to_command(self) -> String {
        let (command, query) = self.build();
        let mut command = CommandLine::new(command, query);
        command.encode()
    }
}
<|endoftext|>


<commit_before>//! Abstractions for page tables and page table entries.

use core::fmt;
use core::ops::{Index, IndexMut};

use super::{PageSize, PhysFrame, Size4KiB};
use crate::addr::PhysAddr;

use bitflags::bitflags;

/// The error returned by the `PageTableEntry::frame` method.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FrameError {
    /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame.
    FrameNotPresent,
    /// The entry does have the `HUGE_PAGE` flag set. The `frame` method has a standard 4KiB frame
    /// as return type, so a huge frame can't be returned.
    HugeFrame,
}

/// A 64-bit page table entry.
#[derive(Clone)]
#[repr(transparent)]
pub struct PageTableEntry {
    entry: u64,
}

impl PageTableEntry {
    /// Creates an unused page table entry.
    pub const fn new() -> Self {
        PageTableEntry { entry: 0 }
    }

    /// Returns whether this entry is zero.
    pub const fn is_unused(&self) -> bool {
        self.entry == 0
    }

    /// Sets this entry to zero.
    pub fn set_unused(&mut self) {
        self.entry = 0;
    }

    /// Returns the flags of this entry.
    pub const fn flags(&self) -> PageTableFlags {
        PageTableFlags::from_bits_truncate(self.entry)
    }

    /// Returns the physical address mapped by this entry, might be zero.
    pub fn addr(&self) -> PhysAddr {
        PhysAddr::new(self.entry & 0x000fffff_fffff000)
    }

    /// Returns the physical frame mapped by this entry.
    ///
    /// Returns the following errors:
    ///
    /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set.
    /// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the
    ///    `addr` function must be used)
    pub fn frame(&self) -> Result<PhysFrame, FrameError> {
        if !self.flags().contains(PageTableFlags::PRESENT) {
            Err(FrameError::FrameNotPresent)
        } else if self.flags().contains(PageTableFlags::HUGE_PAGE) {
            Err(FrameError::HugeFrame)
        } else {
            Ok(PhysFrame::containing_address(self.addr()))
        }
    }

    /// Map the entry to the specified physical address with the specified flags.
    pub fn set_addr(&mut self, addr: PhysAddr, flags: PageTableFlags) {
        assert!(addr.is_aligned(Size4KiB::SIZE));
        self.entry = (addr.as_u64()) | flags.bits();
    }

    /// Map the entry to the specified physical frame with the specified flags.
    pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags) {
        assert!(!flags.contains(PageTableFlags::HUGE_PAGE));
        self.set_addr(frame.start_address(), flags)
    }

    /// Sets the flags of this entry.
    pub fn set_flags(&mut self, flags: PageTableFlags) {
        self.entry = self.addr().as_u64() | flags.bits();
    }
}

impl fmt::Debug for PageTableEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut f = f.debug_struct("PageTableEntry");
        f.field("addr", &self.addr());
        f.field("flags", &self.flags());
        f.finish()
    }
}

bitflags! {
    /// Possible flags for a page table entry.
    pub struct PageTableFlags: u64 {
        /// Specifies whether the mapped frame or page table is loaded in memory.
        const PRESENT =         1 << 0;
        /// Controls whether writes to the mapped frames are allowed.
        ///
        /// If this bit is unset in a level 1 page table entry, the mapped frame is read-only.
        /// If this bit is unset in a higher level page table entry the complete range of mapped
        /// pages is read-only.
        const WRITABLE =        1 << 1;
        /// Controls whether accesses from userspace (i.e. ring 3) are permitted.
        const USER_ACCESSIBLE = 1 << 2;
        /// If this bit is set, a “write-through” policy is used for the cache, else a “write-back”
        /// policy is used.
        const WRITE_THROUGH =   1 << 3;
        /// Disables caching for the pointed entry is cacheable.
        const NO_CACHE =        1 << 4;
        /// Set by the CPU when the mapped frame or page table is accessed.
        const ACCESSED =        1 << 5;
        /// Set by the CPU on a write to the mapped frame.
        const DIRTY =           1 << 6;
        /// Specifies that the entry maps a huge frame instead of a page table. Only allowed in
        /// P2 or P3 tables.
        const HUGE_PAGE =       1 << 7;
        /// Indicates that the mapping is present in all address spaces, so it isn't flushed from
        /// the TLB on an address space switch.
        const GLOBAL =          1 << 8;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_9 =           1 << 9;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_10 =          1 << 10;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_11 =          1 << 11;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_52 =          1 << 52;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_53 =          1 << 53;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_54 =          1 << 54;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_55 =          1 << 55;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_56 =          1 << 56;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_57 =          1 << 57;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_58 =          1 << 58;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_59 =          1 << 59;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_60 =          1 << 60;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_61 =          1 << 61;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_62 =          1 << 62;
        /// Forbid code execution from the mapped frames.
        ///
        /// Can be only used when the no-execute page protection feature is enabled in the EFER
        /// register.
        const NO_EXECUTE =      1 << 63;
    }
}

/// The number of entries in a page table.
const ENTRY_COUNT: usize = 512;

/// Represents a page table.
///
/// Always page-sized.
///
/// This struct implements the `Index` and `IndexMut` traits, so the entries can be accessed
/// through index operations. For example, `page_table[15]` returns the 15th page table entry.
#[repr(align(4096))]
#[repr(C)]
pub struct PageTable {
    entries: [PageTableEntry; ENTRY_COUNT],
}

impl PageTable {
    /// Creates an empty page table.
    pub const fn new() -> Self {
        PageTable {
            entries: [PageTableEntry::new(); ENTRY_COUNT],
        }
    }

    /// Clears all entries.
    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused();
        }
    }

    /// Returns an iterator over the entries of the page table.
    pub fn iter(&self) -> impl Iterator<Item = &PageTableEntry> {
        self.entries.iter()
    }

    /// Returns an iterator that allows modifying the entries of the page table.
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut PageTableEntry> {
        self.entries.iter_mut()
    }
}

impl Index<usize> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: usize) -> &Self::Output {
        &self.entries[index]
    }
}

impl IndexMut<usize> for PageTable {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.entries[index]
    }
}

impl Index<PageTableIndex> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: PageTableIndex) -> &Self::Output {
        // Safety: A PageTableIndex never contains a value >= 512.
        unsafe { self.entries.get_unchecked(usize::from(index)) }
    }
}

impl IndexMut<PageTableIndex> for PageTable {
    fn index_mut(&mut self, index: PageTableIndex) -> &mut Self::Output {
        // Safety: A PageTableIndex never contains a value >= 512.
        unsafe { self.entries.get_unchecked_mut(usize::from(index)) }
    }
}

impl fmt::Debug for PageTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.entries[..].fmt(f)
    }
}

/// A 9-bit index into a page table.
///
/// Can be used to select one of the 512 entries of a page table.
///
/// Guaranteed to only ever contain 0..512.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PageTableIndex(u16);

impl PageTableIndex {
    /// Creates a new index from the given `u16`. Panics if the given value is >=512.
    pub fn new(index: u16) -> Self {
        assert!(usize::from(index) < ENTRY_COUNT);
        Self(index)
    }

    /// Creates a new index from the given `u16`. Throws away bits if the value is >=512.
    pub const fn new_truncate(index: u16) -> Self {
        Self(index % ENTRY_COUNT as u16)
    }
}

impl From<PageTableIndex> for u16 {
    fn from(index: PageTableIndex) -> Self {
        index.0
    }
}

impl From<PageTableIndex> for u32 {
    fn from(index: PageTableIndex) -> Self {
        u32::from(index.0)
    }
}

impl From<PageTableIndex> for u64 {
    fn from(index: PageTableIndex) -> Self {
        u64::from(index.0)
    }
}

impl From<PageTableIndex> for usize {
    fn from(index: PageTableIndex) -> Self {
        usize::from(index.0)
    }
}

/// A 12-bit offset into a 4KiB Page.
///
/// This type is returned by the `VirtAddr::page_offset` method.
///
/// Guaranteed to only ever contain 0..4096.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PageOffset(u16);

impl PageOffset {
    /// Creates a new offset from the given `u16`. Panics if the passed value is >=4096.
    pub fn new(offset: u16) -> Self {
        assert!(offset < (1 << 12));
        Self(offset)
    }

    /// Creates a new offset from the given `u16`. Throws away bits if the value is >=4096.
    pub const fn new_truncate(offset: u16) -> Self {
        Self(offset % (1 << 12))
    }
}

impl From<PageOffset> for u16 {
    fn from(offset: PageOffset) -> Self {
        offset.0
    }
}

impl From<PageOffset> for u32 {
    fn from(offset: PageOffset) -> Self {
        u32::from(offset.0)
    }
}

impl From<PageOffset> for u64 {
    fn from(offset: PageOffset) -> Self {
        u64::from(offset.0)
    }
}

impl From<PageOffset> for usize {
    fn from(offset: PageOffset) -> Self {
        usize::from(offset.0)
    }
}
<commit_msg>Remove unsafe indexing.<commit_after>//! Abstractions for page tables and page table entries.

use core::fmt;
use core::ops::{Index, IndexMut};

use super::{PageSize, PhysFrame, Size4KiB};
use crate::addr::PhysAddr;

use bitflags::bitflags;

/// The error returned by the `PageTableEntry::frame` method.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FrameError {
    /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame.
    FrameNotPresent,
    /// The entry does have the `HUGE_PAGE` flag set. The `frame` method has a standard 4KiB frame
    /// as return type, so a huge frame can't be returned.
    HugeFrame,
}

/// A 64-bit page table entry.
#[derive(Clone)]
#[repr(transparent)]
pub struct PageTableEntry {
    entry: u64,
}

impl PageTableEntry {
    /// Creates an unused page table entry.
    pub const fn new() -> Self {
        PageTableEntry { entry: 0 }
    }

    /// Returns whether this entry is zero.
    pub const fn is_unused(&self) -> bool {
        self.entry == 0
    }

    /// Sets this entry to zero.
    pub fn set_unused(&mut self) {
        self.entry = 0;
    }

    /// Returns the flags of this entry.
    pub const fn flags(&self) -> PageTableFlags {
        PageTableFlags::from_bits_truncate(self.entry)
    }

    /// Returns the physical address mapped by this entry, might be zero.
    pub fn addr(&self) -> PhysAddr {
        PhysAddr::new(self.entry & 0x000fffff_fffff000)
    }

    /// Returns the physical frame mapped by this entry.
    ///
    /// Returns the following errors:
    ///
    /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set.
    /// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the
    ///    `addr` function must be used)
    pub fn frame(&self) -> Result<PhysFrame, FrameError> {
        if !self.flags().contains(PageTableFlags::PRESENT) {
            Err(FrameError::FrameNotPresent)
        } else if self.flags().contains(PageTableFlags::HUGE_PAGE) {
            Err(FrameError::HugeFrame)
        } else {
            Ok(PhysFrame::containing_address(self.addr()))
        }
    }

    /// Map the entry to the specified physical address with the specified flags.
    pub fn set_addr(&mut self, addr: PhysAddr, flags: PageTableFlags) {
        assert!(addr.is_aligned(Size4KiB::SIZE));
        self.entry = (addr.as_u64()) | flags.bits();
    }

    /// Map the entry to the specified physical frame with the specified flags.
    pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags) {
        assert!(!flags.contains(PageTableFlags::HUGE_PAGE));
        self.set_addr(frame.start_address(), flags)
    }

    /// Sets the flags of this entry.
    pub fn set_flags(&mut self, flags: PageTableFlags) {
        self.entry = self.addr().as_u64() | flags.bits();
    }
}

impl fmt::Debug for PageTableEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut f = f.debug_struct("PageTableEntry");
        f.field("addr", &self.addr());
        f.field("flags", &self.flags());
        f.finish()
    }
}

bitflags! {
    /// Possible flags for a page table entry.
    pub struct PageTableFlags: u64 {
        /// Specifies whether the mapped frame or page table is loaded in memory.
        const PRESENT =         1 << 0;
        /// Controls whether writes to the mapped frames are allowed.
        ///
        /// If this bit is unset in a level 1 page table entry, the mapped frame is read-only.
        /// If this bit is unset in a higher level page table entry the complete range of mapped
        /// pages is read-only.
        const WRITABLE =        1 << 1;
        /// Controls whether accesses from userspace (i.e. ring 3) are permitted.
        const USER_ACCESSIBLE = 1 << 2;
        /// If this bit is set, a “write-through” policy is used for the cache, else a “write-back”
        /// policy is used.
        const WRITE_THROUGH =   1 << 3;
        /// Disables caching for the pointed entry is cacheable.
        const NO_CACHE =        1 << 4;
        /// Set by the CPU when the mapped frame or page table is accessed.
        const ACCESSED =        1 << 5;
        /// Set by the CPU on a write to the mapped frame.
        const DIRTY =           1 << 6;
        /// Specifies that the entry maps a huge frame instead of a page table. Only allowed in
        /// P2 or P3 tables.
        const HUGE_PAGE =       1 << 7;
        /// Indicates that the mapping is present in all address spaces, so it isn't flushed from
        /// the TLB on an address space switch.
        const GLOBAL =          1 << 8;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_9 =           1 << 9;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_10 =          1 << 10;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_11 =          1 << 11;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_52 =          1 << 52;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_53 =          1 << 53;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_54 =          1 << 54;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_55 =          1 << 55;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_56 =          1 << 56;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_57 =          1 << 57;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_58 =          1 << 58;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_59 =          1 << 59;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_60 =          1 << 60;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_61 =          1 << 61;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_62 =          1 << 62;
        /// Forbid code execution from the mapped frames.
        ///
        /// Can be only used when the no-execute page protection feature is enabled in the EFER
        /// register.
        const NO_EXECUTE =      1 << 63;
    }
}

/// The number of entries in a page table.
const ENTRY_COUNT: usize = 512;

/// Represents a page table.
///
/// Always page-sized.
///
/// This struct implements the `Index` and `IndexMut` traits, so the entries can be accessed
/// through index operations. For example, `page_table[15]` returns the 15th page table entry.
#[repr(align(4096))]
#[repr(C)]
pub struct PageTable {
    entries: [PageTableEntry; ENTRY_COUNT],
}

impl PageTable {
    /// Creates an empty page table.
    pub const fn new() -> Self {
        PageTable {
            entries: [PageTableEntry::new(); ENTRY_COUNT],
        }
    }

    /// Clears all entries.
    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused();
        }
    }

    /// Returns an iterator over the entries of the page table.
    pub fn iter(&self) -> impl Iterator<Item = &PageTableEntry> {
        self.entries.iter()
    }

    /// Returns an iterator that allows modifying the entries of the page table.
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut PageTableEntry> {
        self.entries.iter_mut()
    }
}

impl Index<usize> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: usize) -> &Self::Output {
        &self.entries[index]
    }
}

impl IndexMut<usize> for PageTable {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.entries[index]
    }
}

impl Index<PageTableIndex> for PageTable {
    type Output = PageTableEntry;

    #[inline]
    fn index(&self, index: PageTableIndex) -> &Self::Output {
        &self.entries[usize::from(index)]
    }
}

impl IndexMut<PageTableIndex> for PageTable {
    #[inline]
    fn index_mut(&mut self, index: PageTableIndex) -> &mut Self::Output {
        &mut self.entries[usize::from(index)]
    }
}

impl fmt::Debug for PageTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.entries[..].fmt(f)
    }
}

/// A 9-bit index into a page table.
///
/// Can be used to select one of the 512 entries of a page table.
///
/// Guaranteed to only ever contain 0..512.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PageTableIndex(u16);

impl PageTableIndex {
    /// Creates a new index from the given `u16`. Panics if the given value is >=512.
    pub fn new(index: u16) -> Self {
        assert!(usize::from(index) < ENTRY_COUNT);
        Self(index)
    }

    /// Creates a new index from the given `u16`. Throws away bits if the value is >=512.
    pub const fn new_truncate(index: u16) -> Self {
        Self(index % ENTRY_COUNT as u16)
    }
}

impl From<PageTableIndex> for u16 {
    fn from(index: PageTableIndex) -> Self {
        index.0
    }
}

impl From<PageTableIndex> for u32 {
    fn from(index: PageTableIndex) -> Self {
        u32::from(index.0)
    }
}

impl From<PageTableIndex> for u64 {
    fn from(index: PageTableIndex) -> Self {
        u64::from(index.0)
    }
}

impl From<PageTableIndex> for usize {
    fn from(index: PageTableIndex) -> Self {
        usize::from(index.0)
    }
}

/// A 12-bit offset into a 4KiB Page.
///
/// This type is returned by the `VirtAddr::page_offset` method.
///
/// Guaranteed to only ever contain 0..4096.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PageOffset(u16);

impl PageOffset {
    /// Creates a new offset from the given `u16`. Panics if the passed value is >=4096.
    pub fn new(offset: u16) -> Self {
        assert!(offset < (1 << 12));
        Self(offset)
    }

    /// Creates a new offset from the given `u16`. Throws away bits if the value is >=4096.
    pub const fn new_truncate(offset: u16) -> Self {
        Self(offset % (1 << 12))
    }
}

impl From<PageOffset> for u16 {
    fn from(offset: PageOffset) -> Self {
        offset.0
    }
}

impl From<PageOffset> for u32 {
    fn from(offset: PageOffset) -> Self {
        u32::from(offset.0)
    }
}

impl From<PageOffset> for u64 {
    fn from(offset: PageOffset) -> Self {
        u64::from(offset.0)
    }
}

impl From<PageOffset> for usize {
    fn from(offset: PageOffset) -> Self {
        usize::from(offset.0)
    }
}
<|endoftext|>