<commit_before>pub mod fx32;
pub mod vec2;
pub mod vec4;

#[cfg(test)]
mod tests {
	use super::fx32::Fx32;
	use super::vec2::Vec2;

	#[test]
	fn vec () {
		let a = Vec2 {x: Fx32::from_int (2), y: Fx32::from_int (3)};
		let b = Vec2 {x: Fx32::from_int (4), y: Fx32::from_int (5)};
		let c = Vec2 {x: Fx32::from_int (6), y: Fx32::from_int (8)};

		assert_eq! (a + b, c, "Vector add");

		assert_eq! (
			Vec2 {x: Fx32::from_int (3), y: Fx32::from_int (4)}.length (),
			Fx32::from_int (5),
			"pythagorean triple");

		assert_eq! (
			Vec2 {x: Fx32::from_int (10), y: Fx32::from_int (1)}.cross (),
			Vec2 {x: Fx32::from_int (-1), y: Fx32::from_int (10)},
			"2D cross product");
	}

	#[test]
	fn it_works() {
		let a = Fx32::new (5000);
		let b = Fx32::new (4000);

		assert! (a == a, "eq");
		assert! (b == b, "eq");
		assert! (a != b, "eq");

		assert_eq! ((a + b).x, 9000, "Fx32 add failed");
		assert_eq! ((a - b).x, 1000, "Fx32 sub failed");
		assert_eq! (-a.x, -5000, "Fx32 neg failed");

		//assert_eq! (65536, super::fx32::DENOMINATOR, "Denominator is wrong");
		//assert_eq! (65536, Fx32::from_float (1.0f32).x, "Denominator applied wrong");

		let half = Fx32::from_float (0.5f32);
		let quarter = Fx32::from_float (0.25f32);
		let three_quarters = Fx32::from_float (0.75f32);

		assert! (half + quarter == three_quarters, "from_float / add failed");

		assert! (half * half == quarter, "mul");
		assert! (Fx32::from_float (1.0f32 / 64.0f32) * Fx32::from_float (128.0f32) == Fx32::from_float (2.0f32), "mul");

		let biggest_root = 724.0f32;
		assert! (Fx32::from_float (biggest_root) * Fx32::from_float (biggest_root) == Fx32::from_float (biggest_root * biggest_root), "big * big mul");

		assert! (Fx32::from_float (1.0f32 / 64.0f32) * Fx32::from_float (1.0f32 / 32.0f32) == Fx32::from_float (1.0f32 / 32.0f32 / 64.0f32), "small * small mul");

		assert! (Fx32::mul_precise (Fx32::from_float (1.0f32 / 1024.0f32), Fx32::from_float (1024.0f32)) == Fx32::from_float (1.0f32), "small * big mul");

		/*
		Remember, i32 is signed, so our 16.16 is really 15.16
		plus one sign bit
		If we scale this to meters, we have no more than
		32 km negative and positive, with 1/65 millimeter granularity.
		For my plan, this is fine, if I stay within 10 km each way the
		math should be fine and that's a bigger world than I could create.

		Update: Our 20.12 is actually 1.19.12
		We have no more than 524,288 meters negative and positive, with
		1/4 millimeter granularity.

		I am trying 20.12 not because I need a bigger world but because
		I want more headroom for multiplying large numbers.
		*/
		assert! (Fx32::mul_64 (Fx32::from_float (1.0f32 / 2048.0f32), Fx32::from_float (16384.0f32)) == Fx32::from_float (8.0f32), "mul_64");

		assert_eq! (
			Fx32::mul_small (Fx32::from_float (1.0f32 / 1024.0f32),
			Fx32::from_float (0.5f32)),
			Fx32::from_float (1.0f32 / 2048.0f32), "mul_small");

		assert_eq! (
			Fx32::mul_small (Fx32::from_float (1.0f32),
			Fx32::from_float (1.5f32)),
			Fx32::from_float (1.5f32),
			"mul_small");

		assert_eq! (
			Fx32::from_int (512) / Fx32::from_int (8),
			Fx32::from_int (64),
			"div_64");

		assert_eq! (
			Fx32::from_int (1).square_64 (),
			Fx32::from_int (1),
			"square");
		assert_eq! (
			Fx32::from_int (1).sqrt_64 (),
			Fx32::from_int (1),
			"square_root");

		assert_eq! (
			Fx32::from_int (9).square_64 (),
			Fx32::from_int (81),
			"square");
		assert_eq! (
			Fx32::from_int (9).sqrt_64 (),
			Fx32::from_int (3),
			"sqrt");

		// Biggest POT I can square with 20.12, but not the biggest int
		assert_eq! (
			Fx32::from_int (512).square_64 (),
			Fx32::from_int (512 * 512),
			"big square");

		assert_eq! (
			Fx32::from_int (512 * 512).sqrt_64 (),
			Fx32::from_int (512),
			"big sqrt");
    }
}
<commit_msg>Using assert_eq more<commit_after>pub mod fx32;
pub mod vec2;
pub mod vec4;

#[cfg(test)]
mod tests {
	use super::fx32::Fx32;
	use super::vec2::Vec2;

	#[test]
	fn vec () {
		let a = Vec2 {x: Fx32::from_int (2), y: Fx32::from_int (3)};
		let b = Vec2 {x: Fx32::from_int (4), y: Fx32::from_int (5)};
		let c = Vec2 {x: Fx32::from_int (6), y: Fx32::from_int (8)};

		assert_eq! (a + b, c, "Vector add");

		assert_eq! (
			Vec2 {x: Fx32::from_int (3), y: Fx32::from_int (4)}.length (),
			Fx32::from_int (5),
			"pythagorean triple");

		assert_eq! (
			Vec2 {x: Fx32::from_int (10), y: Fx32::from_int (1)}.cross (),
			Vec2 {x: Fx32::from_int (-1), y: Fx32::from_int (10)},
			"2D cross product");
	}

	#[test]
	fn it_works() {
		let a = Fx32::new (5000);
		let b = Fx32::new (4000);

		assert! (a == a, "eq");
		assert! (b == b, "eq");
		assert! (a != b, "eq");

		assert_eq! ((a + b).x, 9000, "Fx32 add failed");
		assert_eq! ((a - b).x, 1000, "Fx32 sub failed");
		assert_eq! (-a.x, -5000, "Fx32 neg failed");

		//assert_eq! (65536, super::fx32::DENOMINATOR, "Denominator is wrong");
		//assert_eq! (65536, Fx32::from_float (1.0f32).x, "Denominator applied wrong");

		let half = Fx32::from_float (0.5f32);
		let quarter = Fx32::from_float (0.25f32);
		let three_quarters = Fx32::from_float (0.75f32);

		assert_eq! (half + quarter, three_quarters, "from_float / add failed");

		assert! (half * half == quarter, "mul");
		assert! (Fx32::from_float (1.0f32 / 64.0f32) * Fx32::from_float (128.0f32) == Fx32::from_float (2.0f32), "mul");

		let biggest_root = 724.0f32;
		assert_eq! (
			Fx32::from_float (biggest_root) * Fx32::from_float (biggest_root),
			Fx32::from_float (biggest_root * biggest_root),
			"big * big mul");

		assert_eq! (
			Fx32::from_float (1.0f32 / 64.0f32) * Fx32::from_float (1.0f32 / 32.0f32),
			Fx32::from_float (1.0f32 / 32.0f32 / 64.0f32),
			"small * small mul");

		assert_eq! (
			Fx32::mul_precise (Fx32::from_float (1.0f32 / 1024.0f32), Fx32::from_float (1024.0f32)),
			Fx32::from_float (1.0f32),
			"small * big mul");

		/*
		Remember, i32 is signed, so our 16.16 is really 15.16
		plus one sign bit
		If we scale this to meters, we have no more than
		32 km negative and positive, with 1/65 millimeter granularity.
		For my plan, this is fine, if I stay within 10 km each way the
		math should be fine and that's a bigger world than I could create.

		Update: Our 20.12 is actually 1.19.12
		We have no more than 524,288 meters negative and positive, with
		1/4 millimeter granularity.

		I am trying 20.12 not because I need a bigger world but because
		I want more headroom for multiplying large numbers.
		*/
		assert_eq! (
			Fx32::mul_64 (Fx32::from_float (1.0f32 / 2048.0f32), Fx32::from_float (16384.0f32)),
			Fx32::from_float (8.0f32),
			"mul_64");

		assert_eq! (
			Fx32::mul_small (Fx32::from_float (1.0f32 / 1024.0f32),
			Fx32::from_float (0.5f32)),
			Fx32::from_float (1.0f32 / 2048.0f32),
			"mul_small");

		assert_eq! (
			Fx32::mul_small (Fx32::from_float (1.0f32),
			Fx32::from_float (1.5f32)),
			Fx32::from_float (1.5f32),
			"mul_small");

		assert_eq! (
			Fx32::from_int (512) / Fx32::from_int (8),
			Fx32::from_int (64),
			"div_64");

		assert_eq! (
			Fx32::from_int (1).square_64 (),
			Fx32::from_int (1),
			"square");
		assert_eq! (
			Fx32::from_int (1).sqrt_64 (),
			Fx32::from_int (1),
			"square_root");

		assert_eq! (
			Fx32::from_int (9).square_64 (),
			Fx32::from_int (81),
			"square");
		assert_eq! (
			Fx32::from_int (9).sqrt_64 (),
			Fx32::from_int (3),
			"sqrt");

		// Biggest POT I can square with 20.12, but not the biggest int
		assert_eq! (
			Fx32::from_int (512).square_64 (),
			Fx32::from_int (512 * 512),
			"big square");

		assert_eq! (
			Fx32::from_int (512 * 512).sqrt_64 (),
			Fx32::from_int (512),
			"big sqrt");
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

use memory::MemoryController;
use x86::bits64::task::TaskStateSegment;

mod idt;
mod gdt;

macro_rules! save_scratch_registers {
    () => {
        asm!("push rax
              push rcx
              push rdx
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_scratch_registers {
    () => {
        asm!("pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rdx
              pop rcx
              pop rax
            " :::: "intel", "volatile");
    }
}

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rdi, rsp
                      add rdi, 9*8 // calculate exception stack frame pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame))
                      : "rdi" : "intel");

                restore_scratch_registers!();
                asm!("iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rsi, [rsp + 9*8] // load error code into rsi
                      mov rdi, rsp
                      add rdi, 10*8 // calculate exception stack frame pointer
                      sub rsp, 8 // align the stack pointer
                      call $0
                      add rsp, 8 // undo stack pointer alignment
                      " :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame, u64))
                      : "rdi","rsi" : "intel");
                restore_scratch_registers!();
                asm!("add rsp, 8 // pop error code
                      iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

lazy_static! {
    static ref IDT: idt::Idt = {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(3, handler!(breakpoint_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(8, handler_with_error_code!(double_fault_handler));
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    };
}

const DOUBLE_FAULT_IST_INDEX: usize = 0;

pub fn init(memory_controller: &mut MemoryController) {
    let double_fault_stack = memory_controller.alloc_stack(1)
        .expect("could not allocate double fault stack");

    let mut tss = TaskStateSegment::new();
    tss.ist[DOUBLE_FAULT_IST_INDEX] = double_fault_stack.top() as u64;

    IDT.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

extern "C" fn divide_by_zero_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame);
    loop {}
}

extern "C" fn breakpoint_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
}

extern "C" fn invalid_opcode_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: &ExceptionStackFrame, error_code: u64) {
    use x86::shared::control_regs;
    println!("\nEXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
             unsafe { control_regs::cr2() },
             PageFaultErrorCode::from_bits(error_code).unwrap(),
             stack_frame);
    loop {}
}

extern "C" fn double_fault_handler(stack_frame: &ExceptionStackFrame, _error_code: u64) {
    println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
    loop {}
}
<commit_msg>Make TSS and GDT statics by using spin::Once<commit_after>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

use memory::MemoryController;
use x86::bits64::task::TaskStateSegment;
use spin::Once;

mod idt;
mod gdt;

macro_rules! save_scratch_registers {
    () => {
        asm!("push rax
              push rcx
              push rdx
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_scratch_registers {
    () => {
        asm!("pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rdx
              pop rcx
              pop rax
            " :::: "intel", "volatile");
    }
}

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rdi, rsp
                      add rdi, 9*8 // calculate exception stack frame pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame))
                      : "rdi" : "intel");

                restore_scratch_registers!();
                asm!("iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rsi, [rsp + 9*8] // load error code into rsi
                      mov rdi, rsp
                      add rdi, 10*8 // calculate exception stack frame pointer
                      sub rsp, 8 // align the stack pointer
                      call $0
                      add rsp, 8 // undo stack pointer alignment
                      " :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame, u64))
                      : "rdi","rsi" : "intel");
                restore_scratch_registers!();
                asm!("add rsp, 8 // pop error code
                      iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

const DOUBLE_FAULT_IST_INDEX: usize = 0;

lazy_static! {
    static ref IDT: idt::Idt = {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(3, handler!(breakpoint_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(8, handler_with_error_code!(double_fault_handler));
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    };
}

static TSS: Once<TaskStateSegment> = Once::new();
static GDT: Once<gdt::Gdt> = Once::new();

pub fn init(memory_controller: &mut MemoryController) {
    let double_fault_stack = memory_controller.alloc_stack(1)
        .expect("could not allocate double fault stack");

    let tss = TSS.call_once(|| {
        let mut tss = TaskStateSegment::new();
        tss.ist[DOUBLE_FAULT_IST_INDEX] = double_fault_stack.top() as u64;
        tss
    });

    let gdt = GDT.call_once(|| {
        let mut gdt = gdt::Gdt::new();
        let code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment());
        let tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss));
        gdt
    });
    gdt.load();

    IDT.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

extern "C" fn divide_by_zero_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame);
    loop {}
}

extern "C" fn breakpoint_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
}

extern "C" fn invalid_opcode_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: &ExceptionStackFrame, error_code: u64) {
    use x86::shared::control_regs;
    println!("\nEXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
             unsafe { control_regs::cr2() },
             PageFaultErrorCode::from_bits(error_code).unwrap(),
             stack_frame);
    loop {}
}

extern "C" fn double_fault_handler(stack_frame: &ExceptionStackFrame, _error_code: u64) {
    println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
    loop {}
}
<|endoftext|>


<commit_before>use std::fmt;
use super::bits::BitField;
use super::packet::Block;
use protocol::packet::Packet;
use protocol::packet::Piece;
use std::vec::Vec;
use std::str;
use std::slice;

type NameSegments<'d> = Vec<&'d[u8]>;

pub struct DomainName<'d> {
    data: Piece<'d>,
    segments: NameSegments<'d>,
}

const TAG:u8 = 0b1100_0000u8;
const SEGMENT:u8 = 0b0000_0000u8;
const POINTER:u8 = 0b1100_0000u8;

impl<'d> DomainName<'d> {
    fn parse_segments(&mut self, start: usize) {
        let mut level = 64; // Allow at most 64 pointers.
        let mut parts = 64; // Allow at most 64 name parts.
        let mut pos = start;
        while level > 0 && parts > 0 {
          match DomainName::parse_segment_at(self.data.whole_packet(), pos)  {
              (Some(piece), Some(next)) => {
                  // Normal name part.
                  self.segments.push(piece);
                  parts -= 1;
                  pos = next;
              },
              (Some(piece), None) => {
                  // Root found. No more name parts.
                  self.segments.push(piece);
                  break
              },
              (None, Some(next)) => {
                  // Pointer. Resume at some random other point in the message.
                  level -= 1;
                  pos = next;
              }
              (None, None) => break, // Invalid segment.
          }
        }
    }

    fn parse_segment_at<'a>(data: &'a[u8], pos: usize) -> (Option<&'a[u8]>, Option<usize>) {
        // The first two bits on the segment header octet are a type tag.

        match (BitField{index:pos, mask:0xff}.get(data)) {
            // End marker: 0 octet. Valid name.
            Some(0) => return (Some(&data[pos..pos]), None),
            Some(segment) if SEGMENT == TAG & segment => {
                // The next 6 bits are the size of this segment.
                let len = (segment & !TAG) as usize;
                let start = pos + 1;
                let end = start + len;
                if end >= data.len() { return (None, None); }
                return (Some(&data[start..end]), Some(end));
            },
            Some(pointer) if POINTER == TAG & pointer => {
                // Jump to the pointed-to byte in the packet.
                // The next 14 bits are the offset from the beginning of the message.
                let high = pointer & !TAG;
                let ptr = match (BitField{index:pos+1,mask:0xff}.get(data)) {
                    Some(low) => Some(((high as usize) << 8) + (low as usize)),
                    None => None,
                };
                return (None, ptr);
            },

            // Unknown tag or pos is outside the packet. Invalid message.
            _ => return (None, None)
        }
    }

    pub fn iter<'a>(&'a self) -> slice::Iter<'a, &'d[u8]> { self.segments.iter() }

    pub fn valid(&self) -> bool {
        // Ends in a root token.
        return 0 == self.segments[self.segments.len() - 1].len();
    }
}

impl<'d> Block<'d, DomainName<'d>> for DomainName<'d> {
     fn at<'p>(src: &'p mut Packet<'d>, at:usize) -> DomainName<'d> {
        // Consume the inline portion of the name from the packet.
        let mut end = at;
        loop {
          match DomainName::parse_segment_at(src.data(), end)  {
              (Some(_), Some(next)) => { end = next; },
              (Some(_), None) => { end += 1; break; }, // Root: 1 octet
              (None, Some(_))=> { end += 2; break; }, // Pointer: 2 octets
              _ => break,
          }
        }
        let mut name = DomainName{
            data: src.next_slice(end - at),
            segments: Vec::with_capacity(6),
        };
        name.parse_segments(at);
        return name;
    }

}

impl<'d> fmt::Debug for DomainName<'d> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("DomainName")
            .field("part count", &self.segments.len())
            .field("parts", &self.segments)
            .finish()
    }
}

#[cfg(test)]
mod test {
    use protocol::packet::Packet;
    use super::DomainName;
    use std::vec::Vec;
    use std::iter::FromIterator;

    #[test]
    fn root() {
        let data = &[0];
        let mut p = Packet::new(data);
        let name = p.next::<DomainName>();
        let v = Vec::from_iter(name.iter());
        assert_eq!(1, v.len());
        assert_eq!(0, v[0].len());
    }

    #[test]
    fn doubleroot() {
        let data = &[0, 0];
        let mut p = Packet::new(data);
        let name = p.next::<DomainName>();
        let v = Vec::from_iter(name.iter());
        assert_eq!(1, v.len());
        assert_eq!(0, v[0].len());

        let name2 = p.next::<DomainName>();
        let v2 = Vec::from_iter(name.iter());
        assert_eq!(1, v2.len());
        assert_eq!(0, v2[0].len());
    }

    #[test]
    fn after_root() {
        let data = &[0, 1, 'x' as u8, 0];
        let mut p = Packet::new(data);
        let name = p.next::<DomainName>();
        let v = Vec::from_iter(name.iter());
        assert_eq!(1, v.len());
        assert_eq!(0, v[0].len());

        let name2 = p.next::<DomainName>();
        let v2 = Vec::from_iter(name2.iter());
        assert_eq!(2, v2.len());
        assert_eq!(&['x' as u8], v2[0]);
        assert_eq!(0, v2[1].len());
    }

    #[test]
    fn only_tld() {
        let data = &[3, 'c' as u8, 'o' as u8, 'm' as u8, 0];
        let mut p = Packet::new(data);
        let name = p.next::<DomainName>();
        let v = Vec::from_iter(name.iter());
        assert_eq!(2, v.len());
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v[0]);
        assert_eq!(0, v[1].len());
    }

    #[test]
    fn two_parts() {
        let data = &[1,'x' as u8, 3, 'c' as u8, 'o' as u8, 'm' as u8, 0];
        let mut p = Packet::new(data);
        let name = p.next::<DomainName>();
        let v = Vec::from_iter(name.iter());
        assert_eq!(3, v.len());
        assert_eq!(&['x' as u8], v[0]);
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v[1]);
        assert_eq!(0, v[2].len());
    }

    #[test]
    fn initial_pointer() {
        let data = &[0xc0, 0x04, 1, 'x' as u8, 3, 'c' as u8, 'o' as u8, 'm' as u8, 0];
        let mut p = Packet::new(data);

        let name1 = p.next::<DomainName>();
        let v1 = Vec::from_iter(name1.iter());
        assert_eq!(2, v1.len());
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v1[0]);
        assert_eq!(0, v1[1].len());

        let name2 = p.next::<DomainName>();
        let v2 = Vec::from_iter(name2.iter());
        assert_eq!(3, v2.len());
        assert_eq!(&['x' as u8], v2[0]);
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v2[1]);
        assert_eq!(0, v2[2].len());
    }

    #[test]
    fn trailing_pointer() {
        let data = &[
            1, 'y' as u8,
            0xc0, 0x06,
            1, 'x' as u8,
            3, 'c' as u8, 'o' as u8, 'm' as u8,
            0];
        let mut p = Packet::new(data);

        let name1 = p.next::<DomainName>();
        let v1 = Vec::from_iter(name1.iter());
        assert_eq!(3, v1.len());
        assert_eq!(&['y' as u8], v1[0]);
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v1[1]);
        assert_eq!(0, v1[2].len());

        let name2 = p.next::<DomainName>();
        let v2 = Vec::from_iter(name2.iter());
        assert_eq!(3, v2.len());
        assert_eq!(&['x' as u8], v2[0]);
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v2[1]);
        assert_eq!(0, v2[2].len());
    }

    #[test]
    fn pointer_recursion_limit() {
        let data = &[ 0xc0, 0, 1, 'x' as u8, 0 ];
        let mut p = Packet::new(data);
        let name = p.next::<DomainName>();
        let v = Vec::from_iter(name.iter());
        assert_eq!(0, v.len());
    }

    #[test]
    fn name_count_limit() {
        let data = &[ 1, 'x' as u8, 1, 'y' as u8, 0xc0, 0];
        let mut p = Packet::new(data);
        let name = p.next::<DomainName>();
        let v = Vec::from_iter(name.iter());
        assert_eq!(64, v.len());
    }
}
<commit_msg>Move domain name parsing to new bits.<commit_after>use std::fmt;
use std::marker::PhantomData;
use std::slice;
use std::str;
use std::vec::Vec;
use super::bits::BitData;
use super::bits::BitField;
use std::ops::Range;

// TODO generalize segment storage over BitData::Slice.

pub struct DomainName<'d> {
    /// The next byte offset in the message after this name.
    end: usize,
    segments: Vec<&'d [u8]>,
}

const TAG:u8 = 0b1100_0000u8;
const SEGMENT:u8 = 0b0000_0000u8;
const POINTER:u8 = 0b1100_0000u8;

impl<'d> DomainName<'d> {
    fn from_message<D: ?Sized + BitData>(message: &'d D, at:usize) -> DomainName<'d>
        where D: BitData<Slice=[u8]> {
        // Consume the inline portion of the name from the message.
        let mut end = at;
        loop {
          match DomainName::parse_segment_at(message, end)  {
              (Some(_), Some(next)) => { end = next; },
              (Some(_), None) => { end += 1; break; }, // Root: 1 octet
              (None, Some(_))=> { end += 2; break; }, // Pointer: 2 octets
              _ => break,
          }
        }
        let mut name = DomainName{
            end: end,
            segments: Vec::with_capacity(6),
        };
        name.parse_segments(message, at);
        return name;
    }

    fn parse_segments<D: ?Sized + BitData>(&mut self, message: &'d D, start: usize)
    where D: BitData<Slice=[u8]> {
        let mut level = 64; // Allow at most 64 pointers. (RFC: unbounded)
        let mut parts = 64; // Allow at most 64 name parts.
        let mut pos = start;
        while level > 0 && parts > 0 {
          match DomainName::parse_segment_at(message, pos)  {
              (Some(piece), Some(next)) => {
                  // Normal name part.
                  self.segments.push(piece);
                  parts -= 1;
                  pos = next;
              },
              (Some(piece), None) => {
                  // Root found. No more name parts.
                  self.segments.push(piece);
                  break
              },
              (None, Some(next)) => {
                  // Pointer. Resume at some random other point in the message.
                  level -= 1;
                  pos = next;
              }
              (None, None) => break, // Invalid segment.
          }
        }
    }

    fn parse_segment_at<D: ?Sized + BitData>(message: &'d D, pos: usize) -> (Option<&'d [u8]>, Option<usize>)
    where D: BitData<Slice=[u8]> {
        // The first two bits on the segment header octet are a type tag.
        // TODO check that this produces reasonable assembly.
        match (BitField{index:pos, mask:0xff}.get(message)) {
            // End marker: 0 octet. Valid name.
            Some(0) => return (message.get_range(Range{start:pos, end:pos}), None),
            Some(segment) if SEGMENT == TAG & segment => {
                // The next 6 bits are the size of this segment.
                let len = (segment & !TAG) as usize;
                let start = pos + 1;
                let end = start + len;
                return (message.get_range(Range{start:start, end:end}), Some(end));
            },
            Some(pointer) if POINTER == TAG & pointer => {
                // Jump to the pointed-to byte in the message.
                // The next 14 bits are the offset from the beginning of the message.
                let high = pointer & !TAG;
                let ptr = match (BitField{index:pos+1,mask:0xff}.get(message)) {
                    Some(low) => Some(((high as usize) << 8) + (low as usize)),
                    None => None,
                };
                return (None, ptr);
            },

            // Unknown tag or pos is outside the message. Invalid message.
            _ => return (None, None)
        }
    }

    pub fn valid(&self) -> bool {
        // Ends in a root token.
        return 0 == self.segments[self.segments.len() - 1].len();
    }

    pub fn iter<'a>(&'a self) -> slice::Iter<&'a [u8]> {
        self.segments.iter()
    }

    pub fn end_offset(&self) -> usize { self.end }
}

impl<'d> fmt::Debug for DomainName<'d> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("DomainName")
            .field("part count", &self.segments.len())
            .field("parts", &self.segments)
            .finish()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::vec::Vec;
    use std::iter::FromIterator;

    #[test]
    fn root() {
        let data = &[0][..];
        let name = DomainName::from_message(data, 0);
        let v = Vec::from_iter(name.iter());
        assert_eq!(1, v.len());
        assert_eq!(0, v[0].len());
    }

    #[test]
    fn doubleroot() {
        let data = &[0, 0][..];
        let name = DomainName::from_message(data, 0);
        let v = Vec::from_iter(name.iter());
        assert_eq!(1, v.len());
        assert_eq!(0, v[0].len());

        let name2 = DomainName::from_message(data, name.end_offset());
        let v2 = Vec::from_iter(name2.iter());
        assert_eq!(1, v2.len());
        assert_eq!(0, v2[0].len());
    }

    #[test]
    fn after_root() {
        let data = &[0, 1, 'x' as u8, 0][..];
        let name = DomainName::from_message(data, 0);
        let v = Vec::from_iter(name.iter());
        assert_eq!(1, v.len());
        assert_eq!(0, v[0].len());

        let name2 = DomainName::from_message(data, name.end_offset());
        let v2 = Vec::from_iter(name2.iter());
        assert_eq!(2, v2.len());
        assert_eq!(&['x' as u8], v2[0]);
        assert_eq!(0, v2[1].len());
    }

    #[test]
    fn only_tld() {
        let data = &[3, 'c' as u8, 'o' as u8, 'm' as u8, 0][..];
        let name = DomainName::from_message(data, 0);
        let v = Vec::from_iter(name.iter());
        assert_eq!(2, v.len());
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v[0]);
        assert_eq!(0, v[1].len());
    }

    #[test]
    fn two_parts() {
        let data = &[1,'x' as u8, 3, 'c' as u8, 'o' as u8, 'm' as u8, 0][..];
        let name = DomainName::from_message(data, 0);
        let v = Vec::from_iter(name.iter());
        assert_eq!(3, v.len());
        assert_eq!(&['x' as u8], v[0]);
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v[1]);
        assert_eq!(0, v[2].len());
    }

    #[test]
    fn initial_pointer() {
        let data = &[0xc0, 0x04, 1, 'x' as u8, 3, 'c' as u8, 'o' as u8, 'm' as u8, 0][..];

        let name1 = DomainName::from_message(data, 0);
        let v1 = Vec::from_iter(name1.iter());
        assert_eq!(2, v1.len());
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v1[0]);
        assert_eq!(0, v1[1].len());

        let name2 = DomainName::from_message(data, name1.end_offset());
        let v2 = Vec::from_iter(name2.iter());
        assert_eq!(3, v2.len());
        assert_eq!(&['x' as u8], v2[0]);
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v2[1]);
        assert_eq!(0, v2[2].len());
    }

    #[test]
    fn trailing_pointer() {
        let data = &[
            1, 'y' as u8,
            0xc0, 0x06,
            1, 'x' as u8,
            3, 'c' as u8, 'o' as u8, 'm' as u8,
            0][..];

        let name1 = DomainName::from_message(data, 0);
        let v1 = Vec::from_iter(name1.iter());
        assert_eq!(3, v1.len());
        assert_eq!(&['y' as u8], v1[0]);
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v1[1]);
        assert_eq!(0, v1[2].len());

        let name2 = DomainName::from_message(data, name1.end_offset());
        let v2 = Vec::from_iter(name2.iter());
        assert_eq!(3, v2.len());
        assert_eq!(&['x' as u8], v2[0]);
        assert_eq!(&['c' as u8, 'o' as u8, 'm' as u8], v2[1]);
        assert_eq!(0, v2[2].len());
    }

    #[test]
    fn pointer_recursion_limit() {
        let data = &[ 0xc0, 0, 1, 'x' as u8, 0 ][..];
        let name = DomainName::from_message(data, 0);
        let v = Vec::from_iter(name.iter());
        assert_eq!(0, v.len());
    }

    #[test]
    fn name_count_limit() {
        let data = &[ 1, 'x' as u8, 1, 'y' as u8, 0xc0, 0][..];
        let name = DomainName::from_message(data, 0);
        let v = Vec::from_iter(name.iter());
        assert_eq!(64, v.len());
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::audionode::AudioNode;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom_struct::dom_struct;
use servo_media::audio::node::{AudioNodeMessage, AudioNodeInit, AudioScheduledSourceNodeMessage};
use std::cell::Cell;

#[dom_struct]
pub struct AudioScheduledSourceNode {
    node: AudioNode,
    started: Cell<bool>,
    stopped: Cell<bool>,
}

impl AudioScheduledSourceNode {
    pub fn new_inherited(
        node_type: AudioNodeInit,
        context: &BaseAudioContext,
        options: &AudioNodeOptions,
        number_of_inputs: u32,
        number_of_outputs: u32,
    ) -> AudioScheduledSourceNode {
        AudioScheduledSourceNode {
            node: AudioNode::new_inherited(
                node_type,
                None, /* node_id */
                context,
                options,
                number_of_inputs,
                number_of_outputs,
            ),
            started: Cell::new(false),
            stopped: Cell::new(false),
        }
    }

    pub fn node(&self) -> &AudioNode {
        &self.node
    }

    pub fn started(&self) -> bool {
        self.started.get()
    }
}

impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode {
    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-onended
    event_handler!(ended, GetOnended, SetOnended);

    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-start
    fn Start(&self, when: Finite<f64>) -> Fallible<()> {
        if self.started.get() || self.stopped.get() {
            return Err(Error::InvalidState);
        }
        self.started.set(true);
        self.node
            .message(AudioNodeMessage::AudioScheduledSourceNode(
                AudioScheduledSourceNodeMessage::Start(*when),
            ));
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-stop
    fn Stop(&self, when: Finite<f64>) -> Fallible<()> {
        if !self.started.get() {
            return Err(Error::InvalidState);
        }
        self.stopped.set(true);
        self.node
            .message(AudioNodeMessage::AudioScheduledSourceNode(
                AudioScheduledSourceNodeMessage::Stop(*when),
            ));
        Ok(())
    }
}
<commit_msg>Reference issue to support the AudioScheduledSourceNode.ended event<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::audionode::AudioNode;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom_struct::dom_struct;
use servo_media::audio::node::{AudioNodeMessage, AudioNodeInit, AudioScheduledSourceNodeMessage};
use std::cell::Cell;

#[dom_struct]
pub struct AudioScheduledSourceNode {
    node: AudioNode,
    started: Cell<bool>,
    stopped: Cell<bool>,
}

impl AudioScheduledSourceNode {
    pub fn new_inherited(
        node_type: AudioNodeInit,
        context: &BaseAudioContext,
        options: &AudioNodeOptions,
        number_of_inputs: u32,
        number_of_outputs: u32,
    ) -> AudioScheduledSourceNode {
        AudioScheduledSourceNode {
            node: AudioNode::new_inherited(
                node_type,
                None, /* node_id */
                context,
                options,
                number_of_inputs,
                number_of_outputs,
            ),
            started: Cell::new(false),
            stopped: Cell::new(false),
        }
    }

    pub fn node(&self) -> &AudioNode {
        &self.node
    }

    pub fn started(&self) -> bool {
        self.started.get()
    }
}

impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode {
    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-onended
    // XXX We should dispatch this when we reach the end. Depends on servo-media #82.
    event_handler!(ended, GetOnended, SetOnended);

    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-start
    fn Start(&self, when: Finite<f64>) -> Fallible<()> {
        if self.started.get() || self.stopped.get() {
            return Err(Error::InvalidState);
        }
        self.started.set(true);
        self.node
            .message(AudioNodeMessage::AudioScheduledSourceNode(
                AudioScheduledSourceNodeMessage::Start(*when),
            ));
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-stop
    fn Stop(&self, when: Finite<f64>) -> Fallible<()> {
        if !self.started.get() {
            return Err(Error::InvalidState);
        }
        self.stopped.set(true);
        self.node
            .message(AudioNodeMessage::AudioScheduledSourceNode(
                AudioScheduledSourceNodeMessage::Stop(*when),
            ));
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;

use nom::{alphanumeric, IResult};
use nom;

#[derive(PartialEq, Debug)]
enum FortranTokenType {
    Comment(String),            // Simgle line comment with !
    Itentifier(String),         // distance, particle_id
}

#[derive(PartialEq, Debug)]
struct Token {
    line_number: u32,
    column: u32,
    token: FortranTokenType
}

fn easy_nom_error<'a>(error_code: u32) -> nom::IResult<&'a str, Option<FortranTokenType>> {
    IResult::Error(nom::Err::Code(nom::ErrorKind::Custom(error_code)))
}

fn parse_comment(input: &str) -> IResult<&str, Option<FortranTokenType>> {
    if input.len() == 0 {
        return IResult::Done(&input, None)
    } else {
        for (i, c) in input.chars().enumerate() {
            match c {
                '!' => return IResult::Done(&input[0..i], Some(FortranTokenType::Comment(input[i+1..].to_owned()))),
                ' ' | '\t' => continue,
                _ => return easy_nom_error(1)
            }
        }
    }
    IResult::Done(&input, None)
}

named!(parse_comment_line<&str, FortranTokenType>, do_parse!(
    tag!("!") >>
    content: take_while!(call!(|c| c != '\n')) >>
    (FortranTokenType::Comment(content.to_string()))
));

named!(parse_many_comment_lines<&str, Vec<FortranTokenType> >, many0!(parse_comment_line));

// fn parse_identifier(input: &str) -> IResult<&str, String> {
//     if input.len() == 0 {
//         IResult::Incomplete(Needed::Unknown)
//     } else {
//         if !input[0].is_alphabetic() {
//             IResult::Error
//         } else {
//             IResult::Done
//         }
//     }
// }

named!(parse_identifier<&str, String>, do_parse!(
    values: many1!(alt!(alphanumeric | tag!("_"))) >>
    (values.join(""))
));

named!(parse_program<&str, Vec<FortranTokenType> >, do_parse!(
    ws!(tag!("program")) >>
    ws!(parse_identifier) >>
    // parse_use_statements >>
    // parse_implicit_statements >>
    // variable_decls: parse_variable_declarations >>
    // statements: parse_statements >>
    // parse_many_comment_lines >>
    ws!(tag!("end")) >>
    ws!(tag!("program")) >>
    ws!(parse_identifier) >>
    parse_comment >>
    parse_many_comment_lines >>
    //(variable_decls.extend(&statements))

    parse_comment >>
    (Vec::new())
));

named!(parse_module<&str, Vec<FortranTokenType> >, do_parse!(
    ws!(tag!("program")) >>
    ws!(parse_identifier) >>
    parse_comment >>
    // TODO: add function and subroutine
    ws!(tag!("end")) >>
    ws!(tag!("program")) >>
    ws!(parse_identifier) >>
    parse_comment >>
    parse_many_comment_lines >>
    (Vec::new())
));

named!(parse_code<&str, Vec<FortranTokenType> >, do_parse!(
    parse_many_comment_lines >>
    actual_code: alt!(parse_program | parse_module) >>
    (actual_code)
));

pub fn process_language_fortran(file_name: &str) {
    println!("processing fortran source file: '{}'", file_name);

    let mut buffer = String::new();

    let mut f = File::open(file_name).expect("unable to open file");

    f.read_to_string(&mut buffer).expect("unable to read to string");

    let result = parse_code(&buffer);
    println!("result: {:?}", result);

}

#[cfg(test)]
mod test {
    use nom::{IResult};

    use super::{FortranTokenType, easy_nom_error, parse_comment, parse_comment_line,
        parse_many_comment_lines, parse_identifier, parse_program, parse_module, parse_code};

    #[test]
    fn parse_comment1() {
        let input = "";
        let expected_output = IResult::Done("", None);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment2() {
        let input = " ";
        let expected_output = IResult::Done(" ", None);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment3() {
        let input = "!";
        let expected_output = IResult::Done("", Some(FortranTokenType::Comment("".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment4() {
        let input = " !";
        let expected_output = IResult::Done(" ", Some(FortranTokenType::Comment("".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment5() {
        let input = " ! ";
        let expected_output = IResult::Done(" ", Some(FortranTokenType::Comment(" ".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment6() {
        let input = "!Test";
        let expected_output = IResult::Done("", Some(FortranTokenType::Comment("Test".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment7() {
        let input = "! Test";
        let expected_output = IResult::Done("", Some(FortranTokenType::Comment(" Test".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment8() {
        let input = " ! Test";
        let expected_output = IResult::Done(" ", Some(FortranTokenType::Comment(" Test".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment9() {
        let input = "x";
        let expected_output = easy_nom_error(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment10() {
        let input = " x";
        let expected_output = easy_nom_error(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment11() {
        let input = " x ";
        let expected_output = easy_nom_error(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment12() {
        let input = " x!";
        let expected_output = easy_nom_error(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment13() {
        let input = " x !";
        let expected_output = easy_nom_error(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment14() {
        let input = " x ! ";
        let expected_output = easy_nom_error(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment15() {
        let input = " x !Test";
        let expected_output = easy_nom_error(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment16() {
        let input = " x ! Test";
        let expected_output = easy_nom_error(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

}
<commit_msg>test cases for parse_comment_line<commit_after>use std::fs::File;
use std::io::Read;

use nom::{alphanumeric, IResult};
use nom;

#[derive(PartialEq, Debug)]
enum FortranTokenType {
    Comment(String),            // Simgle line comment with !
    Itentifier(String),         // distance, particle_id
}

#[derive(PartialEq, Debug)]
struct Token {
    line_number: u32,
    column: u32,
    token: FortranTokenType
}

fn custom_nom_error_option<'a>(error_code: u32) -> nom::IResult<&'a str, Option<FortranTokenType>> {
    IResult::Error(nom::Err::Code(nom::ErrorKind::Custom(error_code)))
}

fn custom_nom_error<'a>(error_code: u32) -> nom::IResult<&'a str, FortranTokenType> {
    IResult::Error(nom::Err::Code(nom::ErrorKind::Custom(error_code)))
}

fn parse_comment(input: &str) -> IResult<&str, Option<FortranTokenType>> {
    if input.len() == 0 {
        return IResult::Done(&input, None)
    } else {
        for (i, c) in input.chars().enumerate() {
            match c {
                '!' => return IResult::Done(&input[0..i], Some(FortranTokenType::Comment(input[i+1..].to_owned()))),
                ' ' | '\t' => continue,
                _ => return custom_nom_error_option(1)
            }
        }
    }
    IResult::Done(&input, None)
}

fn parse_comment_line(input: &str) -> IResult<&str, FortranTokenType> {
    if input.len() == 0 {
        return custom_nom_error(2)
    } else {
        for (i, c) in input.chars().enumerate() {
            match c {
                '!' => return IResult::Done(&input[0..i], FortranTokenType::Comment(input[i+1..].to_owned())),
                ' ' | '\t' => continue,
                _ => return custom_nom_error(2)
            }
        }
    }
    custom_nom_error(2)
}

named!(parse_many_comment_lines<&str, Vec<FortranTokenType> >, many0!(parse_comment_line));

// fn parse_identifier(input: &str) -> IResult<&str, String> {
//     if input.len() == 0 {
//         IResult::Incomplete(Needed::Unknown)
//     } else {
//         if !input[0].is_alphabetic() {
//             IResult::Error
//         } else {
//             IResult::Done
//         }
//     }
// }

named!(parse_identifier<&str, String>, do_parse!(
    values: many1!(alt!(alphanumeric | tag!("_"))) >>
    (values.join(""))
));

named!(parse_program<&str, Vec<FortranTokenType> >, do_parse!(
    ws!(tag!("program")) >>
    ws!(parse_identifier) >>
    // parse_use_statements >>
    // parse_implicit_statements >>
    // variable_decls: parse_variable_declarations >>
    // statements: parse_statements >>
    // parse_many_comment_lines >>
    ws!(tag!("end")) >>
    ws!(tag!("program")) >>
    ws!(parse_identifier) >>
    parse_comment >>
    parse_many_comment_lines >>
    //(variable_decls.extend(&statements))

    parse_comment >>
    (Vec::new())
));

named!(parse_module<&str, Vec<FortranTokenType> >, do_parse!(
    ws!(tag!("program")) >>
    ws!(parse_identifier) >>
    parse_comment >>
    // TODO: add function and subroutine
    ws!(tag!("end")) >>
    ws!(tag!("program")) >>
    ws!(parse_identifier) >>
    parse_comment >>
    parse_many_comment_lines >>
    (Vec::new())
));

named!(parse_code<&str, Vec<FortranTokenType> >, do_parse!(
    parse_many_comment_lines >>
    actual_code: alt!(parse_program | parse_module) >>
    (actual_code)
));

pub fn process_language_fortran(file_name: &str) {
    println!("processing fortran source file: '{}'", file_name);

    let mut buffer = String::new();

    let mut f = File::open(file_name).expect("unable to open file");

    f.read_to_string(&mut buffer).expect("unable to read to string");

    let result = parse_code(&buffer);
    println!("result: {:?}", result);

}

#[cfg(test)]
mod test {
    use nom::{IResult};

    use super::{FortranTokenType, custom_nom_error_option, custom_nom_error, parse_comment,
        parse_comment_line, parse_many_comment_lines, parse_identifier, parse_program,
        parse_module, parse_code};

    #[test]
    fn parse_comment1() {
        let input = "";
        let expected_output = IResult::Done("", None);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment2() {
        let input = " ";
        let expected_output = IResult::Done(" ", None);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment3() {
        let input = "!";
        let expected_output = IResult::Done("", Some(FortranTokenType::Comment("".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment4() {
        let input = " !";
        let expected_output = IResult::Done(" ", Some(FortranTokenType::Comment("".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment5() {
        let input = " ! ";
        let expected_output = IResult::Done(" ", Some(FortranTokenType::Comment(" ".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment6() {
        let input = "!Test";
        let expected_output = IResult::Done("", Some(FortranTokenType::Comment("Test".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment7() {
        let input = "! Test";
        let expected_output = IResult::Done("", Some(FortranTokenType::Comment(" Test".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment8() {
        let input = " ! Test";
        let expected_output = IResult::Done(" ", Some(FortranTokenType::Comment(" Test".to_owned())));

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment9() {
        let input = "x";
        let expected_output = custom_nom_error_option(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment10() {
        let input = " x";
        let expected_output = custom_nom_error_option(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment11() {
        let input = " x ";
        let expected_output = custom_nom_error_option(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment12() {
        let input = " x!";
        let expected_output = custom_nom_error_option(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment13() {
        let input = " x !";
        let expected_output = custom_nom_error_option(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment14() {
        let input = " x ! ";
        let expected_output = custom_nom_error_option(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment15() {
        let input = " x !Test";
        let expected_output = custom_nom_error_option(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment16() {
        let input = " x ! Test";
        let expected_output = custom_nom_error_option(1);

        let result = parse_comment(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment_line1() {
        let input = "";
        let expected_output = custom_nom_error(2);

        let result = parse_comment_line(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment_line2() {
        let input = " ";
        let expected_output = custom_nom_error(2);

        let result = parse_comment_line(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment_line3() {
        let input = "!";
        let expected_output = IResult::Done("", FortranTokenType::Comment("".to_owned()));

        let result = parse_comment_line(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment_line4() {
        let input = " !";
        let expected_output = IResult::Done(" ", FortranTokenType::Comment("".to_owned()));

        let result = parse_comment_line(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment_line5() {
        let input = " ! ";
        let expected_output = IResult::Done(" ", FortranTokenType::Comment(" ".to_owned()));

        let result = parse_comment_line(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment_line6() {
        let input = "! ";
        let expected_output = IResult::Done("", FortranTokenType::Comment(" ".to_owned()));

        let result = parse_comment_line(input);

        assert_eq!(result, expected_output);
    }

    #[test]
    fn parse_comment_line7() {
        let input = "! Test";
        let expected_output = IResult::Done("", FortranTokenType::Comment(" Test".to_owned()));

        let result = parse_comment_line(input);

        assert_eq!(result, expected_output);
    }

}
<|endoftext|>


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

//! Main for building the genesis generation utility.

use std::io::{BufRead, Write};
use std::sync::Arc;
use std::{fs, io, path, process};

use chrono::prelude::Utc;
use chrono::{Datelike, Duration, Timelike};
use curl;
use serde_json;

use cuckoo_miner as cuckoo;
use grin_chain as chain;
use grin_core as core;
use grin_miner_plugin as plugin;
use grin_store as store;
use grin_util as util;

use grin_core::core::verifier_cache::LruVerifierCache;
use grin_keychain::{BlindingFactor, ExtKeychain, Keychain};

static BCHAIN_INFO_URL: &str = "https://blockchain.info/latestblock";
static BCYPHER_URL: &str = "https://api.blockcypher.com/v1/btc/main";
static BCHAIR_URL: &str = "https://api.blockchair.com/bitcoin/blocks?limit=2";

static GENESIS_RS_PATH: &str = "../../core/src/genesis.rs";
static PLUGIN_PATH: &str = "cuckaroo_mean_cuda_29.cuckooplugin";

fn main() {
	if !path::Path::new(GENESIS_RS_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			GENESIS_RS_PATH
		);
	}
	if !path::Path::new(PLUGIN_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			PLUGIN_PATH
		);
	}

	// get the latest bitcoin hash
	let h1 = get_bchain_head();
	let h2 = get_bcypher_head();
	let h3 = get_bchair_head();
	if h1 != h2 || h1 != h3 {
		panic!(
			"Bitcoin chain head is inconsistent, please retry ({}, {}, {}).",
			h1, h2, h3
		);
	}
	println!("Using bitcoin block hash {}", h1);

	// build the basic parts of the genesis block header
	let mut gen = core::genesis::genesis_main();
	gen.header.timestamp = Utc::now() + Duration::minutes(30);
	gen.header.prev_root = core::core::hash::Hash::from_hex(&h1).unwrap();

	// TODO get the proper keychain and/or raw coinbase
	let keychain = ExtKeychain::from_random_seed().unwrap();
	let key_id = ExtKeychain::derive_key_id(0, 1, 0, 0, 0);
	let reward = core::libtx::reward::output(&keychain, &key_id, 0, 0).unwrap();
	gen = gen.with_reward(reward.0, reward.1);

	{
		// setup a tmp chain to set block header roots
		core::global::set_mining_mode(core::global::ChainTypes::AutomatedTesting);
		let tmp_chain = setup_chain(".grin.tmp", core::pow::mine_genesis_block().unwrap());
		tmp_chain.set_txhashset_roots(&mut gen).unwrap();
	}

	// mine a Cuckaroo29 block
	core::global::set_mining_mode(core::global::ChainTypes::Mainnet);
	let plugin_lib = cuckoo::PluginLibrary::new(PLUGIN_PATH).unwrap();
	let solver_ctx = plugin_lib.create_solver_ctx(&mut plugin_lib.get_default_params());

	let mut solver_sols = plugin::SolverSolutions::default();
	let mut solver_stats = plugin::SolverStats::default();
	let mut nonce = 0;
	while solver_sols.num_sols == 0 {
		solver_sols = plugin::SolverSolutions::default();
		plugin_lib.run_solver(
			solver_ctx,
			gen.header.pre_pow(),
			nonce,
			1,
			&mut solver_sols,
			&mut solver_stats,
		);
		nonce += 1;
	}

	// set the PoW solution and make sure the block is mostly valid
	gen.header.pow.nonce = solver_sols.sols[0].nonce as u64;
	gen.header.pow.proof.nonces = solver_sols.sols[0].to_u64s();
	assert!(gen.header.pow.is_secondary(), "Not a secondary header");
	println!("Built genesis:\n{:?}", gen);
	// core::pow::verify_size(&gen.header).unwrap();
	gen.validate(
		&BlindingFactor::zero(),
		Arc::new(util::RwLock::new(LruVerifierCache::new())),
	)
	.unwrap();

	println!("Final genesis hash: {}", gen.hash().to_hex());

	update_genesis_rs(&gen);
	println!("genesis.rs has been updated, check it and run mainnet_genesis_hash test");
	println!("also check bitcoin block {} hasn't been orphaned.", h1);
	println!("press c+enter to proceed.");
	let mut input = String::new();
	io::stdin().read_line(&mut input).unwrap();
	if input != "c\n" {
		return;
	}

	// Commit genesis block info in git and tag
	process::Command::new("git")
		.args(&["commit", "-am", "Minor: finalized genesis block"])
		.status()
		.expect("git commit failed");
	process::Command::new("git")
		.args(&["tag", "-a", "v1.0", "-m", "Mainnet release"])
		.status()
		.expect("git tag failed");
	process::Command::new("git")
		.args(&["push", "origin", "v1.0"])
		.status()
		.expect("git tag push failed");
	println!("All done!");
}

fn update_genesis_rs(gen: &core::core::Block) {
	// set the replacement patterns
	let mut replacements = vec![];
	replacements.push((
		"timestamp".to_string(),
		format!(
			"Utc.ymd({}, {}, {}).and_hms({}, {}, {})",
			gen.header.timestamp.date().year(),
			gen.header.timestamp.date().month(),
			gen.header.timestamp.date().day(),
			gen.header.timestamp.time().hour(),
			gen.header.timestamp.time().minute(),
			gen.header.timestamp.time().second(),
		),
	));
	replacements.push((
		"prev_root".to_string(),
		format!("Hash::from_hex(\"{}\").unwrap()", gen.header.prev_root.to_hex()),
	));
	replacements.push((
		"output_root".to_string(),
		format!("Hash::from_hex(\"{}\").unwrap()", gen.header.output_root.to_hex()),
	));
	replacements.push((
		"range_proof_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.range_proof_root.to_hex()
		),
	));
	replacements.push((
		"kernel_root".to_string(),
		format!("Hash::from_hex(\"{}\").unwrap()", gen.header.kernel_root.to_hex()),
	));
	replacements.push((
		"total_kernel_offset".to_string(),
		format!(
			"BlindingFactor::from_hex(\"{}\").unwrap()",
			gen.header.total_kernel_offset.to_hex()
		),
	));
	replacements.push(("nonce".to_string(), format!("{}", gen.header.pow.nonce)));
	replacements.push((
		"nonces".to_string(),
		format!("vec!{:x?}", gen.header.pow.proof.nonces),
	));
	replacements.push((
		"excess".to_string(),
		format!(
			"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
			util::to_hex(gen.kernels()[0].excess.0.to_vec())
		),
	));
	replacements.push((
		"excess_sig".to_string(),
		format!(
			"Signature::from_raw_data(&{:?}).unwrap()",
			gen.kernels()[0].excess_sig.to_raw_data().to_vec(),
		),
	));
	replacements.push((
		"commit".to_string(),
		format!(
			"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
			util::to_hex(gen.outputs()[0].commitment().0.to_vec())
		),
	));
	replacements.push((
		"proof".to_string(),
		format!("{:?}", gen.outputs()[0].proof.bytes().to_vec()),
	));

	// check each possible replacement in the file, remove the replacement from
	// the list when found to avoid double replacements
	let mut replaced = String::new();
	{
		let genesis_rs = fs::File::open(GENESIS_RS_PATH).unwrap();
		let reader = io::BufReader::new(&genesis_rs);
		for rline in reader.lines() {
			let line = rline.unwrap();
			let mut has_replaced = false;
			if line.contains("REPLACE") {
				for (pos, replacement) in replacements.iter().enumerate() {
					if line.contains(&replacement.0) {
						replaced.push_str(&format!("{}: {},\n", replacement.0, replacement.1));
						replacements.remove(pos);
						has_replaced = true;
						break;
					}
				}
			}
			if !has_replaced {
				replaced.push_str(&format!("{}\n", line));
			}
		}
	}
	let mut genesis_rs = fs::File::create(GENESIS_RS_PATH).unwrap();
	genesis_rs.write_all(replaced.as_bytes()).unwrap();
}

fn setup_chain(dir_name: &str, genesis: core::core::Block) -> chain::Chain {
	util::init_test_logger();
	let _ = fs::remove_dir_all(dir_name);
	let verifier_cache = Arc::new(util::RwLock::new(
		core::core::verifier_cache::LruVerifierCache::new(),
	));
	let db_env = Arc::new(store::new_env(dir_name.to_string()));
	chain::Chain::init(
		dir_name.to_string(),
		db_env,
		Arc::new(chain::types::NoopAdapter {}),
		genesis,
		core::pow::verify_size,
		verifier_cache,
		false,
	)
	.unwrap()
}

fn get_bchain_head() -> String {
	get_json(BCHAIN_INFO_URL)["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_bcypher_head() -> String {
	get_json(BCYPHER_URL)["hash"].as_str().unwrap().to_string()
}

fn get_bchair_head() -> String {
	get_json(BCHAIR_URL)["data"][0]["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_json(url: &str) -> serde_json::Value {
	let mut body = Vec::new();
	let mut easy = curl::easy::Easy::new();
	easy.url(url).unwrap();
	{
		let mut transfer = easy.transfer();
		transfer
			.write_function(|data| {
				body.extend_from_slice(data);
				Ok(data.len())
			})
			.unwrap();
		transfer.perform().unwrap();
	}
	serde_json::from_slice(&body).unwrap()
}
<commit_msg>Check plugin errors, uncomment PoW validation<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Main for building the genesis generation utility.

use std::io::{BufRead, Write};
use std::sync::Arc;
use std::{fs, io, path, process};

use chrono::prelude::Utc;
use chrono::{Datelike, Duration, Timelike};
use curl;
use serde_json;

use cuckoo_miner as cuckoo;
use grin_chain as chain;
use grin_core as core;
use grin_miner_plugin as plugin;
use grin_store as store;
use grin_util as util;

use grin_core::core::verifier_cache::LruVerifierCache;
use grin_keychain::{BlindingFactor, ExtKeychain, Keychain};

static BCHAIN_INFO_URL: &str = "https://blockchain.info/latestblock";
static BCYPHER_URL: &str = "https://api.blockcypher.com/v1/btc/main";
static BCHAIR_URL: &str = "https://api.blockchair.com/bitcoin/blocks?limit=2";

static GENESIS_RS_PATH: &str = "../../core/src/genesis.rs";
static PLUGIN_PATH: &str = "cuckaroo_mean_cuda_29.cuckooplugin";

fn main() {
	if !path::Path::new(GENESIS_RS_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			GENESIS_RS_PATH
		);
	}
	if !path::Path::new(PLUGIN_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			PLUGIN_PATH
		);
	}

	// get the latest bitcoin hash
	let h1 = get_bchain_head();
	let h2 = get_bcypher_head();
	let h3 = get_bchair_head();
	if h1 != h2 || h1 != h3 {
		panic!(
			"Bitcoin chain head is inconsistent, please retry ({}, {}, {}).",
			h1, h2, h3
		);
	}
	println!("Using bitcoin block hash {}", h1);

	// build the basic parts of the genesis block header
	let mut gen = core::genesis::genesis_main();
	gen.header.timestamp = Utc::now() + Duration::minutes(30);
	gen.header.prev_root = core::core::hash::Hash::from_hex(&h1).unwrap();

	// TODO get the proper keychain and/or raw coinbase
	let keychain = ExtKeychain::from_random_seed().unwrap();
	let key_id = ExtKeychain::derive_key_id(0, 1, 0, 0, 0);
	let reward = core::libtx::reward::output(&keychain, &key_id, 0, 0).unwrap();
	gen = gen.with_reward(reward.0, reward.1);

	{
		// setup a tmp chain to set block header roots
		core::global::set_mining_mode(core::global::ChainTypes::AutomatedTesting);
		let tmp_chain = setup_chain(".grin.tmp", core::pow::mine_genesis_block().unwrap());
		tmp_chain.set_txhashset_roots(&mut gen).unwrap();
	}

	// mine a Cuckaroo29 block
	core::global::set_mining_mode(core::global::ChainTypes::Mainnet);
	let plugin_lib = cuckoo::PluginLibrary::new(PLUGIN_PATH).unwrap();
	let solver_ctx = plugin_lib.create_solver_ctx(&mut plugin_lib.get_default_params());

	let mut solver_sols = plugin::SolverSolutions::default();
	let mut solver_stats = plugin::SolverStats::default();
	let mut nonce = 0;
	while solver_sols.num_sols == 0 {
		solver_sols = plugin::SolverSolutions::default();
		plugin_lib.run_solver(
			solver_ctx,
			gen.header.pre_pow(),
			nonce,
			1,
			&mut solver_sols,
			&mut solver_stats,
		);
		if solver_stats.has_errored {
			println!(
				"Plugin {} has errored, device: {}. Reason: {}",
				solver_stats.get_plugin_name(),
				solver_stats.get_device_name(),
				solver_stats.get_error_reason(),
				);
			return;
		}

		nonce += 1;
	}

	// set the PoW solution and make sure the block is mostly valid
	gen.header.pow.nonce = solver_sols.sols[0].nonce as u64;
	gen.header.pow.proof.nonces = solver_sols.sols[0].to_u64s();
	assert!(gen.header.pow.is_secondary(), "Not a secondary header");
	println!("Built genesis:\n{:?}", gen);
	core::pow::verify_size(&gen.header).unwrap();
	gen.validate(
		&BlindingFactor::zero(),
		Arc::new(util::RwLock::new(LruVerifierCache::new())),
	)
	.unwrap();

	println!("Final genesis hash: {}", gen.hash().to_hex());

	update_genesis_rs(&gen);
	println!("genesis.rs has been updated, check it and run mainnet_genesis_hash test");
	println!("also check bitcoin block {} hasn't been orphaned.", h1);
	println!("press c+enter to proceed.");
	let mut input = String::new();
	io::stdin().read_line(&mut input).unwrap();
	if input != "c\n" {
		return;
	}

	// Commit genesis block info in git and tag
	process::Command::new("git")
		.args(&["commit", "-am", "Minor: finalized genesis block"])
		.status()
		.expect("git commit failed");
	process::Command::new("git")
		.args(&["tag", "-a", "v1.0", "-m", "Mainnet release"])
		.status()
		.expect("git tag failed");
	process::Command::new("git")
		.args(&["push", "origin", "v1.0"])
		.status()
		.expect("git tag push failed");
	println!("All done!");
}

fn update_genesis_rs(gen: &core::core::Block) {
	// set the replacement patterns
	let mut replacements = vec![];
	replacements.push((
		"timestamp".to_string(),
		format!(
			"Utc.ymd({}, {}, {}).and_hms({}, {}, {})",
			gen.header.timestamp.date().year(),
			gen.header.timestamp.date().month(),
			gen.header.timestamp.date().day(),
			gen.header.timestamp.time().hour(),
			gen.header.timestamp.time().minute(),
			gen.header.timestamp.time().second(),
		),
	));
	replacements.push((
		"prev_root".to_string(),
		format!("Hash::from_hex(\"{}\").unwrap()", gen.header.prev_root.to_hex()),
	));
	replacements.push((
		"output_root".to_string(),
		format!("Hash::from_hex(\"{}\").unwrap()", gen.header.output_root.to_hex()),
	));
	replacements.push((
		"range_proof_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.range_proof_root.to_hex()
		),
	));
	replacements.push((
		"kernel_root".to_string(),
		format!("Hash::from_hex(\"{}\").unwrap()", gen.header.kernel_root.to_hex()),
	));
	replacements.push((
		"total_kernel_offset".to_string(),
		format!(
			"BlindingFactor::from_hex(\"{}\").unwrap()",
			gen.header.total_kernel_offset.to_hex()
		),
	));
	replacements.push(("nonce".to_string(), format!("{}", gen.header.pow.nonce)));
	replacements.push((
		"nonces".to_string(),
		format!("vec!{:?}", gen.header.pow.proof.nonces),
	));
	replacements.push((
		"excess".to_string(),
		format!(
			"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
			util::to_hex(gen.kernels()[0].excess.0.to_vec())
		),
	));
	replacements.push((
		"excess_sig".to_string(),
		format!(
			"Signature::from_raw_data(&{:?}).unwrap()",
			gen.kernels()[0].excess_sig.to_raw_data().to_vec(),
		),
	));
	replacements.push((
		"commit".to_string(),
		format!(
			"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
			util::to_hex(gen.outputs()[0].commitment().0.to_vec())
		),
	));
	replacements.push((
		"proof".to_string(),
		format!("{:?}", gen.outputs()[0].proof.bytes().to_vec()),
	));

	// check each possible replacement in the file, remove the replacement from
	// the list when found to avoid double replacements
	let mut replaced = String::new();
	{
		let genesis_rs = fs::File::open(GENESIS_RS_PATH).unwrap();
		let reader = io::BufReader::new(&genesis_rs);
		for rline in reader.lines() {
			let line = rline.unwrap();
			let mut has_replaced = false;
			if line.contains("REPLACE") {
				for (pos, replacement) in replacements.iter().enumerate() {
					if line.contains(&replacement.0) {
						replaced.push_str(&format!("{}: {},\n", replacement.0, replacement.1));
						replacements.remove(pos);
						has_replaced = true;
						break;
					}
				}
			}
			if !has_replaced {
				replaced.push_str(&format!("{}\n", line));
			}
		}
	}
	let mut genesis_rs = fs::File::create(GENESIS_RS_PATH).unwrap();
	genesis_rs.write_all(replaced.as_bytes()).unwrap();
}

fn setup_chain(dir_name: &str, genesis: core::core::Block) -> chain::Chain {
	util::init_test_logger();
	let _ = fs::remove_dir_all(dir_name);
	let verifier_cache = Arc::new(util::RwLock::new(
		core::core::verifier_cache::LruVerifierCache::new(),
	));
	let db_env = Arc::new(store::new_env(dir_name.to_string()));
	chain::Chain::init(
		dir_name.to_string(),
		db_env,
		Arc::new(chain::types::NoopAdapter {}),
		genesis,
		core::pow::verify_size,
		verifier_cache,
		false,
	)
	.unwrap()
}

fn get_bchain_head() -> String {
	get_json(BCHAIN_INFO_URL)["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_bcypher_head() -> String {
	get_json(BCYPHER_URL)["hash"].as_str().unwrap().to_string()
}

fn get_bchair_head() -> String {
	get_json(BCHAIR_URL)["data"][0]["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_json(url: &str) -> serde_json::Value {
	let mut body = Vec::new();
	let mut easy = curl::easy::Easy::new();
	easy.url(url).unwrap();
	{
		let mut transfer = easy.transfer();
		transfer
			.write_function(|data| {
				body.extend_from_slice(data);
				Ok(data.len())
			})
			.unwrap();
		transfer.perform().unwrap();
	}
	serde_json::from_slice(&body).unwrap()
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::vec::Vec;
use autograd::variable::*;
use tensor::*;
use ::*;

thread_local! {
    pub static FUNC_TABLE: RefCell<VecDeque<FuncImpl>> = RefCell::new(VecDeque::new());
//    pub static FUNC_INTF_TABLE: RefCell<HashMap<FuncId, &'static FuncIntf>> = RefCell::new(HashMap::new());
}
pub type FuncId = i32;

struct FuncStub {
    delegate: Function,
}
impl_func_delegate!(FuncStub);
impl FuncIntf for FuncStub {
    fn forward(&mut self, input: &TensorKindList) -> TensorKindList {
        unreachable!()
    }
    fn backward(&mut self, input: &TensorKindList) -> TensorKindList {
        unreachable!()
    }
}
impl FuncStub {
    fn new() -> Self {
        FuncStub { delegate: Function::default() }
    }
}

pub struct FuncImpl {
    previous_functions: Vec<Function>,
    saved_variables: Vec<VarId>,
    needs_input_grad: Vec<VarId>,
    non_differentiable: Vec<TensorId>,
    to_save: Vec<TensorId>,
    requires_grad: bool,
    owner: RcMut<FuncIntf>,
}
impl Default for FuncImpl {
    fn default() -> Self {
        FuncImpl {
            previous_functions: Vec::new(),
            saved_variables: Vec::new(),
            needs_input_grad: Vec::new(),
            non_differentiable: Vec::new(),
            to_save: Vec::new(),
            requires_grad: false,
            owner: RcMutNew(FuncStub::new()),
        }
    }
}

impl FuncImpl {
    fn _call_hooks(&self, input: &TensorKindList, output: &TensorKindList) {
        unimplemented!();
    }
    fn init(&self, intf: RcMut<FuncIntf>) {
        self.owner = intf;
    }
}

#[derive(Clone)]
pub struct Function {
    id: FuncId,
}

impl Default for Function {
    fn default() -> Self {
        Function { id: -1 }
    }
}

impl Function {
    pub fn new() -> Self {
        use std::usize;
        let mut id = usize::MAX;
        FUNC_TABLE.with(|f| {
                            let mut table = f.borrow_mut();
                            id = table.len();
                            table.push_back(FuncImpl::default());
                        });
        Function { id: id as i32 }
    }
    pub fn init(&self, intf: RcMut<FuncIntf>) {
        //FUNC_INTF_TABLE.with(|m| m.borrow_mut().insert(self.id, intf));
        self.access().init(intf)
    }
    fn owner(&self) -> &FuncIntf {
        /*
        let owner_tablep = FUNC_INTF_TABLE.with(|m| m.as_ptr());
        let owner_table = unsafe {&mut *owner_tablep};
        owner_table[&self.id]
        */
        unimplemented!()
    }
    fn access(&self) -> &mut FuncImpl {
        let vecp = FUNC_TABLE.with(|f| f.as_ptr());
        let vec = unsafe { &mut *vecp };
        &mut vec[self.id as usize]
    }
    pub fn from(id: FuncId) -> Self {
        Function { id: id }
    }
    pub fn saved_tensors(&mut self) -> TensorKindList {
        // XXX see if we can't avoid the clone
        self.access()
            .saved_variables
            .iter()
            .map(|v| VarKind::from(*v).data())
            .collect()
    }
    pub fn save_for_backward<T>(&mut self, input: &RefTensorList<T>) {
        self.access().to_save = input.iter().map(|t| t.id).collect();
    }
    pub fn _do_backward(&mut self,
                        grad_output: &TensorKindList,
                        retain_variables: bool)
                        -> TensorKindList {
        let inner = self.access();
        if inner.saved_variables.is_empty() {
            panic!("Trying to backward through the graph second \
                    time, but the buffers have already been freed. Please \
                    specify retain_variables=True when calling backward for \
                    the first time.");
        };
        let owner = self.owner();
        let grad_input = owner.backward(grad_output);
        inner._call_hooks(&grad_input, grad_output);
        if !retain_variables {
            inner.saved_variables.clear();
        };
        grad_input.into()
    }
}

pub trait FuncDelegate {
    fn delegate(&mut self) -> &mut Function;
}

pub trait FuncIntf: FuncDelegate {
    fn forward(&mut self, input: &TensorKindList) -> TensorKindList;
    fn backward(&mut self, input: &TensorKindList) -> TensorKindList;
    fn f(&mut self, mut input_: &mut VarKindList) -> VarKindList {
        let is_volatile = input_.iter().any(|v| v.is_volatile());
        {
            // do start graph stuff with f
            let mut f = self.delegate();
            let mut inner = f.access();
            if !is_volatile {
                inner.previous_functions = input_.iter().filter_map(|v| v.grad_fn()).collect();
                inner.needs_input_grad = input_
                    .iter()
                    .filter_map(|v| if v.requires_grad() {
                                    Some(v.varid())
                                } else {
                                    None
                                })
                    .collect();
                inner.requires_grad = inner.needs_input_grad.len() != 0;
            }
        }
        let v;
        {
            let input_tensors = input_.iter_mut().map(|v| v.data()).collect();
            v = self.forward(&input_tensors);
        }
        let f = self.delegate();
        let mut fi = f.access();
        let output = if is_volatile {
            let args = VariableArgs::build().volatile(true).done();
            v.into_iter().map(|t| VarKind::new_args(t, &args)).collect()
        } else {
            let args = VariableArgs::build()
                .creator(Some(f.clone()))
                .requires_grad(fi.requires_grad)
                .done();
            let mut output: VarKindList =
                v.into_iter().map(|t| VarKind::new_args(t, &args)).collect();
            if !fi.to_save.is_empty() {
                /* if a tensor was modified in place replace the old variable with the new one */
                let mut t2v = HashMap::new();
                for ref var in input_.iter() {
                    t2v.insert(var.tid(), var.varid());
                }
                for ref mut var in &mut output.iter() {
                    t2v.insert(var.tid(), var.varid());
                }
                for t in fi.to_save.iter() {
                    fi.saved_variables.push(t2v[t]);
                }
                fi.to_save.clear();
            };
            if !fi.non_differentiable.is_empty() {
                for ref mut var in &mut output {
                    if fi.non_differentiable.contains(&var.tid()) {
                        var.requires_nograd()
                    }
                }
                fi.non_differentiable.clear();
            };
            output
        };
        output
    }
}
<commit_msg>fix mutability complaints, add FIWrap to transparently register FuncIntf and hide necessary borrowing<commit_after>use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::vec::Vec;
use autograd::variable::*;
use tensor::*;
use ::*;

thread_local! {
    pub static FUNC_TABLE: RefCell<VecDeque<FuncImpl>> = RefCell::new(VecDeque::new());
//    pub static FUNC_INTF_TABLE: RefCell<HashMap<FuncId, &'static FuncIntf>> = RefCell::new(HashMap::new());
}
pub type FuncId = i32;

struct FuncStub {
    delegate: Function,
}
impl_func_delegate!(FuncStub);
impl FuncIntf for FuncStub {
    fn forward(&mut self, input: &TensorKindList) -> TensorKindList {
        unreachable!()
    }
    fn backward(&mut self, input: &TensorKindList) -> TensorKindList {
        unreachable!()
    }
}
impl FuncStub {
    fn new() -> Self {
        FuncStub { delegate: Function::default() }
    }
}

pub struct FuncImpl {
    previous_functions: Vec<Function>,
    saved_variables: Vec<VarId>,
    needs_input_grad: Vec<VarId>,
    non_differentiable: Vec<TensorId>,
    to_save: Vec<TensorId>,
    requires_grad: bool,
    owner: RcMut<FuncIntf>,
}
impl Default for FuncImpl {
    fn default() -> Self {
        FuncImpl {
            previous_functions: Vec::new(),
            saved_variables: Vec::new(),
            needs_input_grad: Vec::new(),
            non_differentiable: Vec::new(),
            to_save: Vec::new(),
            requires_grad: false,
            owner: RcMutNew(FuncStub::new()),
        }
    }
}

impl FuncImpl {
    fn _call_hooks(&self, input: &TensorKindList, output: &TensorKindList) {
        unimplemented!();
    }
    fn init(&mut self, intf: RcMut<FuncIntf>) {
        self.owner = intf;
    }
}

#[derive(Clone)]
pub struct Function {
    id: FuncId,
}

impl Default for Function {
    fn default() -> Self {
        Function { id: -1 }
    }
}

pub struct FIWrap<T> {
    value: RcMut<T>,
}
impl<T: 'static + FuncIntf> FIWrap<T> {
    pub fn new(arg: T) -> Self {
        let t = FIWrap { value: RcMutNew(arg) };
        t.value.borrow_mut().delegate().init(t.value.clone());
        t
    }
    pub fn f(&mut self, mut input_: &mut VarKindList) -> VarKindList {
        self.value.borrow_mut().f(input_)
    }
}

impl Function {
    pub fn new() -> Self {
        use std::usize;
        let mut id = usize::MAX;
        FUNC_TABLE.with(|f| {
                            let mut table = f.borrow_mut();
                            id = table.len();
                            table.push_back(FuncImpl::default());
                        });
        Function { id: id as i32 }
    }
    pub fn init(&self, intf: RcMut<FuncIntf>) {
        //FUNC_INTF_TABLE.with(|m| m.borrow_mut().insert(self.id, intf));
        self.access().init(intf)
    }
    fn access(&self) -> &mut FuncImpl {
        let vecp = FUNC_TABLE.with(|f| f.as_ptr());
        let vec = unsafe { &mut *vecp };
        &mut vec[self.id as usize]
    }
    pub fn from(id: FuncId) -> Self {
        Function { id: id }
    }
    pub fn saved_tensors(&mut self) -> TensorKindList {
        // XXX see if we can't avoid the clone
        self.access()
            .saved_variables
            .iter()
            .map(|v| VarKind::from(*v).data())
            .collect()
    }
    pub fn save_for_backward<T>(&mut self, input: &RefTensorList<T>) {
        self.access().to_save = input.iter().map(|t| t.id).collect();
    }
    pub fn _do_backward(&mut self,
                        grad_output: &TensorKindList,
                        retain_variables: bool)
                        -> TensorKindList {
        let inner = self.access();
        if inner.saved_variables.is_empty() {
            panic!("Trying to backward through the graph second \
                    time, but the buffers have already been freed. Please \
                    specify retain_variables=True when calling backward for \
                    the first time.");
        };
        let grad_input = inner.owner.borrow_mut().backward(grad_output);
        inner._call_hooks(&grad_input, grad_output);
        if !retain_variables {
            inner.saved_variables.clear();
        };
        grad_input.into()
    }
}

pub trait FuncDelegate {
    fn delegate(&mut self) -> &mut Function;
}

pub trait FuncIntf: FuncDelegate {
    fn forward(&mut self, input: &TensorKindList) -> TensorKindList;
    fn backward(&mut self, input: &TensorKindList) -> TensorKindList;
    fn f(&mut self, mut input_: &mut VarKindList) -> VarKindList {
        let is_volatile = input_.iter().any(|v| v.is_volatile());
        {
            // do start graph stuff with f
            let mut f = self.delegate();
            let mut inner = f.access();
            if !is_volatile {
                inner.previous_functions = input_.iter().filter_map(|v| v.grad_fn()).collect();
                inner.needs_input_grad = input_
                    .iter()
                    .filter_map(|v| if v.requires_grad() {
                                    Some(v.varid())
                                } else {
                                    None
                                })
                    .collect();
                inner.requires_grad = inner.needs_input_grad.len() != 0;
            }
        }
        let v;
        {
            let input_tensors = input_.iter_mut().map(|v| v.data()).collect();
            v = self.forward(&input_tensors);
        }
        let f = self.delegate();
        let mut fi = f.access();
        let output = if is_volatile {
            let args = VariableArgs::build().volatile(true).done();
            v.into_iter().map(|t| VarKind::new_args(t, &args)).collect()
        } else {
            let args = VariableArgs::build()
                .creator(Some(f.clone()))
                .requires_grad(fi.requires_grad)
                .done();
            let mut output: VarKindList =
                v.into_iter().map(|t| VarKind::new_args(t, &args)).collect();
            if !fi.to_save.is_empty() {
                /* if a tensor was modified in place replace the old variable with the new one */
                let mut t2v = HashMap::new();
                for ref mut var in input_.iter_mut() {
                    t2v.insert(var.tid(), var.varid());
                }
                for ref mut var in &mut output.iter_mut() {
                    t2v.insert(var.tid(), var.varid());
                }
                for t in fi.to_save.iter() {
                    fi.saved_variables.push(t2v[t]);
                }
                fi.to_save.clear();
            };
            if !fi.non_differentiable.is_empty() {
                for ref mut var in &mut output {
                    if fi.non_differentiable.contains(&var.tid()) {
                        var.requires_nograd()
                    }
                }
                fi.non_differentiable.clear();
            };
            output
        };
        output
    }
}
<|endoftext|>


<commit_before>use git_version::git_version;
use target_info::Target;

/// Returns the current version of this build of Lighthouse.
///
/// A plus-sign (`+`) is appended to the git commit if the tree is dirty.
/// Commit hash is omitted if the sources don't include git information.
///
/// ## Example
///
/// `Lighthouse/v1.5.1-67da032+`
pub const VERSION: &str = git_version!(
    args = [
        "--always",
        "--dirty=+",
        "--abbrev=7",
        // NOTE: using --match instead of --exclude for compatibility with old Git
        "--match=thiswillnevermatchlol"
    ],
    prefix = "Lighthouse/v2.5.1-",
    fallback = "Lighthouse/v2.5.1"
);

/// Returns `VERSION`, but with platform information appended to the end.
///
/// ## Example
///
/// `Lighthouse/v1.5.1-67da032+/x86_64-linux`
pub fn version_with_platform() -> String {
    format!("{}/{}-{}", VERSION, Target::arch(), Target::os())
}

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

    #[test]
    fn version_formatting() {
        let re = Regex::new(r"^Lighthouse/v[0-9]+\.[0-9]+\.[0-9]+(-rc.[0-9])?-[[:xdigit:]]{7}\+?$")
            .unwrap();
        assert!(
            re.is_match(VERSION),
            "version doesn't match regex: {}",
            VERSION
        );
    }
}
<commit_msg>lighthouse_version: Fix version string regex (#3451)<commit_after>use git_version::git_version;
use target_info::Target;

/// Returns the current version of this build of Lighthouse.
///
/// A plus-sign (`+`) is appended to the git commit if the tree is dirty.
/// Commit hash is omitted if the sources don't include git information.
///
/// ## Example
///
/// `Lighthouse/v1.5.1-67da032+`
pub const VERSION: &str = git_version!(
    args = [
        "--always",
        "--dirty=+",
        "--abbrev=7",
        // NOTE: using --match instead of --exclude for compatibility with old Git
        "--match=thiswillnevermatchlol"
    ],
    prefix = "Lighthouse/v2.5.1-",
    fallback = "Lighthouse/v2.5.1"
);

/// Returns `VERSION`, but with platform information appended to the end.
///
/// ## Example
///
/// `Lighthouse/v1.5.1-67da032+/x86_64-linux`
pub fn version_with_platform() -> String {
    format!("{}/{}-{}", VERSION, Target::arch(), Target::os())
}

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

    #[test]
    fn version_formatting() {
        let re =
            Regex::new(r"^Lighthouse/v[0-9]+\.[0-9]+\.[0-9]+(-rc.[0-9])?(-[[:xdigit:]]{7})?\+?$")
                .unwrap();
        assert!(
            re.is_match(VERSION),
            "version doesn't match regex: {}",
            VERSION
        );
    }
}
<|endoftext|>