<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {

	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        let new_cpu_state = self.execute(cpu_state,mem);
        // Perform logging, recording here...
        *cpu_state = new_cpu_state
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);
        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( ((mem.read8(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536 ) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
            },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState, mut mem:&Memory) -> CpuState {

    	// The state of the CPU after executing the current instruction.
    	let mut new_cpu_state = cpu_state.clone();

    	// Figure out which opcode is being executed.
    	let ref decode_register = cpu_state.decode_register;

    	match decode_register.info.opcode_class {

    		// ASL (Arithmetic Shift Left)
    		OpcodeClass::ASL => {

				// Shift accumulator to the left.
				new_cpu_state.a = cpu_state.a << 1;
				// Carry flag gets set to the most significant bit.
				new_cpu_state.C = (128 & cpu_state.a) > 0;
				// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// LDA (Load Accumulator)
    		OpcodeClass::LDA => {
    			new_cpu_state.a = decode_register.value_final.unwrap()
    		},

    		// LDX (Load X)
    		OpcodeClass::LDX => {
    			new_cpu_state.x = decode_register.value_final.unwrap()
    		},

    		// LDY (Load Y)
    		OpcodeClass::LDY => {
    			new_cpu_state.y = decode_register.value_final.unwrap()
    		},

    		// LSR (Logical Shift Right)
    		OpcodeClass::LSR => {

    			// Shift accumulator to the right.
    			new_cpu_state.a = cpu_state.a >> 1;
    			// Carry flag gets set to the least significant bit.
    			new_cpu_state.C = 1 & cpu_state.a > 0;
    			// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// NOP (No Operation)
    		OpcodeClass::NOP => {},

    		// Default: not sure what this opcode is.
			_ => panic!("Unrecognised opcode class: {:?}", decode_register.info.opcode_class)

    	}

    	// Expression returned is the updated cpu_state.
    	new_cpu_state
    }

}

<commit_msg>IndexedIndirect can't wrap around<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {

	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        let new_cpu_state = self.execute(cpu_state,mem);
        // Perform logging, recording here...
        *cpu_state = new_cpu_state
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);
        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
            },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState, mut mem:&Memory) -> CpuState {

    	// The state of the CPU after executing the current instruction.
    	let mut new_cpu_state = cpu_state.clone();

    	// Figure out which opcode is being executed.
    	let ref decode_register = cpu_state.decode_register;

    	match decode_register.info.opcode_class {

    		// ASL (Arithmetic Shift Left)
    		OpcodeClass::ASL => {

				// Shift accumulator to the left.
				new_cpu_state.a = cpu_state.a << 1;
				// Carry flag gets set to the most significant bit.
				new_cpu_state.C = (128 & cpu_state.a) > 0;
				// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// LDA (Load Accumulator)
    		OpcodeClass::LDA => {
    			new_cpu_state.a = decode_register.value_final.unwrap()
    		},

    		// LDX (Load X)
    		OpcodeClass::LDX => {
    			new_cpu_state.x = decode_register.value_final.unwrap()
    		},

    		// LDY (Load Y)
    		OpcodeClass::LDY => {
    			new_cpu_state.y = decode_register.value_final.unwrap()
    		},

    		// LSR (Logical Shift Right)
    		OpcodeClass::LSR => {

    			// Shift accumulator to the right.
    			new_cpu_state.a = cpu_state.a >> 1;
    			// Carry flag gets set to the least significant bit.
    			new_cpu_state.C = 1 & cpu_state.a > 0;
    			// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// NOP (No Operation)
    		OpcodeClass::NOP => {},

    		// Default: not sure what this opcode is.
			_ => panic!("Unrecognised opcode class: {:?}", decode_register.info.opcode_class)

    	}

    	// Expression returned is the updated cpu_state.
    	new_cpu_state
    }

}

<|endoftext|>


<commit_before>use std::cmp;
use std::iter::IntoIterator;

use cfg;
use datatypes::{Coords, Direction, Movement};
use datatypes::Movement::*;

/// A concrete, rectangular region of the screen.
///
/// The region is incluse of the top and left boundary and exclusive of the bottom and right
/// boundary.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Region {
    pub left: u32,
    pub top: u32,
    pub right: u32,
    pub bottom: u32,
}

impl Region {
    /// Creates a region. Note that x1/x2 and y1/y2 need not be properly ordered, but one of them
    /// __must__ be greater than the other. This function will panic otherwise.
    pub fn new(x1: u32, y1: u32, x2: u32, y2: u32) -> Region {
        let (left, right) = (cmp::min(x1, x2), cmp::max(x1, x2));
        let (top, bottom) = (cmp::min(y1, y2), cmp::max(y1, y2));
        assert!(right > 0);
        assert!(bottom > 0);
        Region {
            left: left,
            top: top,
            right: right,
            bottom: bottom,
        }
    }

    /// Returns true if a given coordinates is contained within this region.
    pub fn contains(&self, coords: Coords) -> bool {
        self.left <= coords.x && coords.x < self.right
            && self.top <= coords.y && coords.y < self.bottom
    }

    /// Returns the width of this region.
    pub fn width(&self) -> u32 {
        self.right - self.left
    }

    /// Returns the height of this region.
    pub fn height(&self) -> u32 {
        self.bottom - self.top
    }

    pub fn move_and_scroll(&self, Coords {x, y}: Coords, movement: Movement)
            -> (Coords, u32, Direction) {
        match movement {
            UpIndex(n) if self.top + n > y          => {
                (Coords {x: x, y: self.top}, self.top + n - y, Direction::Up)
            }
            DownIndex(n) if n + y >= self.bottom    => {
                (Coords {x: x, y: n + y}, n + y - self.bottom + 1, Direction::Down)
            }
            LeftIndex(n) if self.left + n > x       => {
                (Coords {x: self.left, y: y}, self.left + n - x, Direction::Left)
            }
            RightIndex(n) if n + x >= self.right    => {
                (Coords {x: self.right - 1, y: y}, n + y - self.bottom + 1, Direction::Right)
            }
            PreviousLine(n) if self.top + n > y     => {
                (Coords {x: 0, y: self.top}, self.top + n - y, Direction::Up)
            }
            NextLine(n) if n + y >= self.bottom     => {
                (Coords {x: 0, y: n + y}, n + y - self.bottom + 1, Direction::Down)
            }
            _                                       => {
                (self.move_within(Coords {x: x, y: y}, movement), 0, Direction::Down)
            }
        }
    }

    /// Calculate the movement from one coordinate to another within this region.
    pub fn move_within(&self, Coords {x, y}: Coords, movement: Movement) -> Coords {
        match movement {
            Position(coords)            => self.xy_within(coords),
            Column(n)                   => Coords {x: self.x_within(n), y: y},
            Row(n)                      => Coords {x: x, y: self.y_within(n)},
            UpToEdge                    => Coords {x: x, y: self.top},
            DownToEdge                  => Coords {x: x, y: self.bottom - 1},
            LeftToEdge                  => Coords {x: self.left, y: y},
            RightToEdge                 => Coords {x: self.right - 1, y: y},
            ToBeginning                 => Coords {x: self.left, y: self.top},
            ToEnd                       => Coords {x: self.right - 1, y: self.bottom - 1},
            Up(n) | UpIndex(n)          => {
                Coords {x: x, y: cmp::max(self.top, y.saturating_sub(n))}
            }
            Down(n) | DownIndex(n)      => {
                Coords {x: x, y: cmp::min(y.saturating_add(n), self.bottom - 1)}
            }
            Left(n) | LeftIndex(n)      => {
                Coords {x: cmp::max(self.left, x.saturating_sub(n)), y: y}
            }
            Right(n) | RightIndex(n)    => {
                Coords {x: cmp::min(x.saturating_add(n), self.right - 1), y: y}
            }
            LeftTab(n)                  => {
                let tab = ((x / cfg::TAB_STOP).saturating_sub(n)) * cfg::TAB_STOP;
                Coords {x: cmp::max(tab, self.left), y: y}
            }
            RightTab(n)                 => {
                let tab = ((x / cfg::TAB_STOP) + n) * cfg::TAB_STOP;
                Coords {x: cmp::min(tab, self.right - 1), y: y}
            }
            PreviousLine(n)             => {
                Coords {x: 0, y: cmp::max(y.saturating_sub(n), self.top)}
            }
            NextLine(n)                 => {
                Coords {x: 0, y: cmp::min(y.saturating_add(n), self.bottom - 1)}
            }
        }
    }

    /// Iterate over the coordinates in the region, starting in the upper left and moving rightward
    /// and wrapping at the right edge of the region.
    pub fn iter(&self) -> RegionIter {
        RegionIter {
            region: *self,
            point: Coords {x: self.left, y: self.top},
            back_point: Coords {x: self.left, y: self.bottom},
        }
    }

    /// Calculate the nearest coordinate within the region.
    pub fn xy_within(&self, Coords {x, y}: Coords) -> Coords {
        Coords {
            x: self.x_within(x),
            y: self.y_within(y),
        }
    }

    /// Calculate the nearest x value within the region.
    pub fn x_within(&self, x: u32) -> u32 {
        cmp::max(cmp::min(x, self.right - 1), self.left)
    }

    /// Calculate the naerest y value within the region.
    pub fn y_within(&self, y: u32) -> u32 {
        cmp::max(cmp::min(y, self.bottom - 1), self.top)
    }

}

impl IntoIterator for Region {
    type Item = Coords;
    type IntoIter = RegionIter;

    fn into_iter(self) -> RegionIter {
        self.iter()
    }
}

pub struct RegionIter {
    region: Region,
    point: Coords,
    back_point: Coords,
}

impl Iterator for RegionIter {
    type Item = Coords;

    fn next(&mut self) -> Option<Coords> {
        if self.point != self.back_point {
            let point = self.point;
            self.point = if point.x == self.region.right - 1 {
                Coords {x: self.region.left, y: point.y + 1}
            } else { Coords {x: point.x + 1, y: point.y} };
            Some(point)
        } else { None }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

}

impl DoubleEndedIterator for RegionIter {
    fn next_back(&mut self) -> Option<Coords> {
        if self.point != self.back_point {
            self.back_point = if self.back_point.x == self.region.left {
                Coords {x: self.region.right - 1, y: self.back_point.y - 1}
            } else { Coords {x: self.back_point.x - 1, y: self.back_point.y} };
            Some(self.back_point)
        } else { None }
    }
}

impl ExactSizeIterator for RegionIter {
    fn len(&self) -> usize {
        if self.point.y == self.back_point.y {
            (self.back_point.x  - self.point.x) as usize
        } else {
            let width  = self.region.right - self.region.left;
            let first  = self.region.right - self.point.x;
            let middle = (self.back_point.y - self.point.y - 1) * width;
            let last   = self.back_point.y - self.region.left;
            (first + middle + last) as usize
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    use datatypes::{Coords, Movement};
    use datatypes::Movement::*;

    static REGION: &'static Region = &Region { left: 0, top: 10, right: 100, bottom: 100 };

    static COORDS: &'static [(Coords, bool)] = &[
        (Coords { x: 0, y: 0 }, false),
        (Coords { x: 0, y: 10 }, true),
        (Coords { x: 50, y: 50 }, true),
        (Coords { x: 99, y: 99 }, true),
        (Coords { x: 100, y: 0 }, false),
        (Coords { x: 100, y: 100 }, false),
        (Coords { x: 200, y: 200 }, false),
    ];

    static MOVEMENTS: &'static [(Coords, Movement, bool, Coords)] = &[
        (Coords { x:50, y:50 }, Position(Coords { x:40, y:40 }), true, Coords { x:40, y:40 }),
        (Coords { x:50, y:50 }, Position(Coords { x:200, y:200 }), true, Coords { x:99, y:99}),
        (Coords { x:50, y:50 }, Position(Coords { x:0, y:0 }), true, Coords { x:0, y:10 }),
        (Coords { x:50, y:50 }, Column(0), true, Coords { x:0, y:50 }),
        (Coords { x:50, y:50 }, Column(10), true, Coords { x:10, y:50 }),
        (Coords { x:50, y:50 }, Column(100), true, Coords { x:99, y:50 }),
        (Coords { x:50, y:50 }, Row(0), true, Coords { x:50, y:10 }),
        (Coords { x:50, y:50 }, Row(10), true, Coords { x:50, y:10 }),
        (Coords { x:50, y:50 }, Row(100), true, Coords { x:50, y:99 }),
        (Coords { x:50, y:50 }, UpToEdge, true, Coords { x:50, y:10 }),
        (Coords { x:50, y:50 }, DownToEdge, true, Coords { x:50, y:99 }),
        (Coords { x:50, y:50 }, LeftToEdge, true, Coords { x:0, y:50 }),
        (Coords { x:50, y:50 }, RightToEdge, true, Coords { x:99, y:50 }),
        (Coords { x:50, y:50 }, ToBeginning, true, Coords { x:0, y:10 }),
        (Coords { x:50, y:50 }, ToEnd, true, Coords { x:99, y:99 }),
        (Coords { x:50, y:50 }, Up(5), true, Coords { x:50, y:45 }),
        (Coords { x:50, y:50 }, Down(5), true, Coords { x:50, y:55 }),
        (Coords { x:50, y:50 }, Left(5), false, Coords { x:45, y:50 }),
        (Coords { x:50, y:50 }, Right(5), false, Coords { x:55, y:50 }),
        (Coords { x:50, y:50 }, PreviousLine(1), true, Coords { x:0, y:49 }),
        (Coords { x:50, y:50 }, NextLine(1), true, Coords { x:0, y:51 }),
    ];

    #[test]
    fn region_contains_coords() {
        for &(coords, b) in COORDS {
            assert!(REGION.contains(coords) == b, "{:?}", coords);
        }
    }

    #[test]
    fn region_calculates_movements() {
        for &(from, moves, wrapping, to) in MOVEMENTS {
            assert!(REGION.move_within(from, moves) == to,
                    "{:?} {:?} {} {:?}", from, moves, wrapping, to);
        }
    }

    #[test]
    fn region_iterates() {
        let coords = (10..100).flat_map(|y| (0..100).map(move |x| Coords {x: x, y: y}));
        REGION.iter().zip(coords).all(|(c1, c2)| { assert_eq!(c1, c2); true });
    }

}
<commit_msg>Removed dead method on region move_and_scroll().<commit_after>use std::cmp;
use std::iter::IntoIterator;

use cfg;
use datatypes::{Coords, Direction, Movement};
use datatypes::Movement::*;

/// A concrete, rectangular region of the screen.
///
/// The region is incluse of the top and left boundary and exclusive of the bottom and right
/// boundary.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Region {
    pub left: u32,
    pub top: u32,
    pub right: u32,
    pub bottom: u32,
}

impl Region {
    /// Creates a region. Note that x1/x2 and y1/y2 need not be properly ordered, but one of them
    /// __must__ be greater than the other. This function will panic otherwise.
    pub fn new(x1: u32, y1: u32, x2: u32, y2: u32) -> Region {
        let (left, right) = (cmp::min(x1, x2), cmp::max(x1, x2));
        let (top, bottom) = (cmp::min(y1, y2), cmp::max(y1, y2));
        assert!(right > 0);
        assert!(bottom > 0);
        Region {
            left: left,
            top: top,
            right: right,
            bottom: bottom,
        }
    }

    /// Returns true if a given coordinates is contained within this region.
    pub fn contains(&self, coords: Coords) -> bool {
        self.left <= coords.x && coords.x < self.right
            && self.top <= coords.y && coords.y < self.bottom
    }

    /// Returns the width of this region.
    pub fn width(&self) -> u32 {
        self.right - self.left
    }

    /// Returns the height of this region.
    pub fn height(&self) -> u32 {
        self.bottom - self.top
    }

    /// Calculate the movement from one coordinate to another within this region.
    pub fn move_within(&self, Coords {x, y}: Coords, movement: Movement) -> Coords {
        match movement {
            Position(coords)            => self.xy_within(coords),
            Column(n)                   => Coords {x: self.x_within(n), y: y},
            Row(n)                      => Coords {x: x, y: self.y_within(n)},
            UpToEdge                    => Coords {x: x, y: self.top},
            DownToEdge                  => Coords {x: x, y: self.bottom - 1},
            LeftToEdge                  => Coords {x: self.left, y: y},
            RightToEdge                 => Coords {x: self.right - 1, y: y},
            ToBeginning                 => Coords {x: self.left, y: self.top},
            ToEnd                       => Coords {x: self.right - 1, y: self.bottom - 1},
            Up(n) | UpIndex(n)          => {
                Coords {x: x, y: cmp::max(self.top, y.saturating_sub(n))}
            }
            Down(n) | DownIndex(n)      => {
                Coords {x: x, y: cmp::min(y.saturating_add(n), self.bottom - 1)}
            }
            Left(n) | LeftIndex(n)      => {
                Coords {x: cmp::max(self.left, x.saturating_sub(n)), y: y}
            }
            Right(n) | RightIndex(n)    => {
                Coords {x: cmp::min(x.saturating_add(n), self.right - 1), y: y}
            }
            LeftTab(n)                  => {
                let tab = ((x / cfg::TAB_STOP).saturating_sub(n)) * cfg::TAB_STOP;
                Coords {x: cmp::max(tab, self.left), y: y}
            }
            RightTab(n)                 => {
                let tab = ((x / cfg::TAB_STOP) + n) * cfg::TAB_STOP;
                Coords {x: cmp::min(tab, self.right - 1), y: y}
            }
            PreviousLine(n)             => {
                Coords {x: 0, y: cmp::max(y.saturating_sub(n), self.top)}
            }
            NextLine(n)                 => {
                Coords {x: 0, y: cmp::min(y.saturating_add(n), self.bottom - 1)}
            }
        }
    }

    /// Iterate over the coordinates in the region, starting in the upper left and moving rightward
    /// and wrapping at the right edge of the region.
    pub fn iter(&self) -> RegionIter {
        RegionIter {
            region: *self,
            point: Coords {x: self.left, y: self.top},
            back_point: Coords {x: self.left, y: self.bottom},
        }
    }

    /// Calculate the nearest coordinate within the region.
    pub fn xy_within(&self, Coords {x, y}: Coords) -> Coords {
        Coords {
            x: self.x_within(x),
            y: self.y_within(y),
        }
    }

    /// Calculate the nearest x value within the region.
    pub fn x_within(&self, x: u32) -> u32 {
        cmp::max(cmp::min(x, self.right - 1), self.left)
    }

    /// Calculate the naerest y value within the region.
    pub fn y_within(&self, y: u32) -> u32 {
        cmp::max(cmp::min(y, self.bottom - 1), self.top)
    }

}

impl IntoIterator for Region {
    type Item = Coords;
    type IntoIter = RegionIter;

    fn into_iter(self) -> RegionIter {
        self.iter()
    }
}

pub struct RegionIter {
    region: Region,
    point: Coords,
    back_point: Coords,
}

impl Iterator for RegionIter {
    type Item = Coords;

    fn next(&mut self) -> Option<Coords> {
        if self.point != self.back_point {
            let point = self.point;
            self.point = if point.x == self.region.right - 1 {
                Coords {x: self.region.left, y: point.y + 1}
            } else { Coords {x: point.x + 1, y: point.y} };
            Some(point)
        } else { None }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

}

impl DoubleEndedIterator for RegionIter {
    fn next_back(&mut self) -> Option<Coords> {
        if self.point != self.back_point {
            self.back_point = if self.back_point.x == self.region.left {
                Coords {x: self.region.right - 1, y: self.back_point.y - 1}
            } else { Coords {x: self.back_point.x - 1, y: self.back_point.y} };
            Some(self.back_point)
        } else { None }
    }
}

impl ExactSizeIterator for RegionIter {
    fn len(&self) -> usize {
        if self.point.y == self.back_point.y {
            (self.back_point.x  - self.point.x) as usize
        } else {
            let width  = self.region.right - self.region.left;
            let first  = self.region.right - self.point.x;
            let middle = (self.back_point.y - self.point.y - 1) * width;
            let last   = self.back_point.y - self.region.left;
            (first + middle + last) as usize
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    use datatypes::{Coords, Movement};
    use datatypes::Movement::*;

    static REGION: &'static Region = &Region { left: 0, top: 10, right: 100, bottom: 100 };

    static COORDS: &'static [(Coords, bool)] = &[
        (Coords { x: 0, y: 0 }, false),
        (Coords { x: 0, y: 10 }, true),
        (Coords { x: 50, y: 50 }, true),
        (Coords { x: 99, y: 99 }, true),
        (Coords { x: 100, y: 0 }, false),
        (Coords { x: 100, y: 100 }, false),
        (Coords { x: 200, y: 200 }, false),
    ];

    static MOVEMENTS: &'static [(Coords, Movement, bool, Coords)] = &[
        (Coords { x:50, y:50 }, Position(Coords { x:40, y:40 }), true, Coords { x:40, y:40 }),
        (Coords { x:50, y:50 }, Position(Coords { x:200, y:200 }), true, Coords { x:99, y:99}),
        (Coords { x:50, y:50 }, Position(Coords { x:0, y:0 }), true, Coords { x:0, y:10 }),
        (Coords { x:50, y:50 }, Column(0), true, Coords { x:0, y:50 }),
        (Coords { x:50, y:50 }, Column(10), true, Coords { x:10, y:50 }),
        (Coords { x:50, y:50 }, Column(100), true, Coords { x:99, y:50 }),
        (Coords { x:50, y:50 }, Row(0), true, Coords { x:50, y:10 }),
        (Coords { x:50, y:50 }, Row(10), true, Coords { x:50, y:10 }),
        (Coords { x:50, y:50 }, Row(100), true, Coords { x:50, y:99 }),
        (Coords { x:50, y:50 }, UpToEdge, true, Coords { x:50, y:10 }),
        (Coords { x:50, y:50 }, DownToEdge, true, Coords { x:50, y:99 }),
        (Coords { x:50, y:50 }, LeftToEdge, true, Coords { x:0, y:50 }),
        (Coords { x:50, y:50 }, RightToEdge, true, Coords { x:99, y:50 }),
        (Coords { x:50, y:50 }, ToBeginning, true, Coords { x:0, y:10 }),
        (Coords { x:50, y:50 }, ToEnd, true, Coords { x:99, y:99 }),
        (Coords { x:50, y:50 }, Up(5), true, Coords { x:50, y:45 }),
        (Coords { x:50, y:50 }, Down(5), true, Coords { x:50, y:55 }),
        (Coords { x:50, y:50 }, Left(5), false, Coords { x:45, y:50 }),
        (Coords { x:50, y:50 }, Right(5), false, Coords { x:55, y:50 }),
        (Coords { x:50, y:50 }, PreviousLine(1), true, Coords { x:0, y:49 }),
        (Coords { x:50, y:50 }, NextLine(1), true, Coords { x:0, y:51 }),
    ];

    #[test]
    fn region_contains_coords() {
        for &(coords, b) in COORDS {
            assert!(REGION.contains(coords) == b, "{:?}", coords);
        }
    }

    #[test]
    fn region_calculates_movements() {
        for &(from, moves, wrapping, to) in MOVEMENTS {
            assert!(REGION.move_within(from, moves) == to,
                    "{:?} {:?} {} {:?}", from, moves, wrapping, to);
        }
    }

    #[test]
    fn region_iterates() {
        let coords = (10..100).flat_map(|y| (0..100).map(move |x| Coords {x: x, y: y}));
        REGION.iter().zip(coords).all(|(c1, c2)| { assert_eq!(c1, c2); true });
    }

}
<|endoftext|>


<commit_before>//! Updates crates.io index and builds new packages

use super::{DocBuilder, RustwideBuilder};
use db::connect_db;
use error::Result;
use crates_index_diff::{ChangeKind, Index};
use utils::add_crate_to_queue;

impl DocBuilder {
    /// Updates crates.io-index repository and adds new crates into build queue.
    /// Returns size of queue
    pub fn get_new_crates(&mut self) -> Result<usize> {
        let conn = try!(connect_db());
        let index = try!(Index::from_path_or_cloned(&self.options.crates_io_index_path));
        let mut changes = try!(index.fetch_changes());
        let mut add_count: usize = 0;

        // I belive this will fix ordering of queue if we get more than one crate from changes
        changes.reverse();

        for krate in changes.iter().filter(|k| k.kind != ChangeKind::Yanked) {
            add_crate_to_queue(&conn, &krate.name, &krate.version, 0).ok();
            debug!("{}-{} added into build queue", krate.name, krate.version);
            add_count += 1;
        }

        Ok(add_count)
    }

    pub fn get_queue_count(&self) -> Result<i64> {
        let conn = try!(connect_db());
        Ok(conn.query("SELECT COUNT(*) FROM queue WHERE attempt < 5", &[])
            .unwrap()
            .get(0)
            .get(0))
    }

    /// Builds the top package from the queue. Returns whether the queue was empty.
    pub(crate) fn build_next_queue_package(
        &mut self,
        builder: &mut RustwideBuilder,
    ) -> Result<bool> {
        let conn = try!(connect_db());

        let query = try!(conn.query("SELECT id, name, version
                                     FROM queue
                                     WHERE attempt < 5
                                     ORDER BY priority ASC, attempt ASC, id ASC
                                     LIMIT 1",
                                    &[]));

        if query.is_empty() {
            // nothing in the queue; bail
            return Ok(false);
        }

        let id: i32 = query.get(0).get(0);
        let name: String = query.get(0).get(1);
        let version: String = query.get(0).get(2);

        match builder.build_package(self, &name, &version) {
            Ok(_) => {
                let _ = conn.execute("DELETE FROM queue WHERE id = $1", &[&id]);
            }
            Err(e) => {
                // Increase attempt count
                let _ = conn.execute("UPDATE queue SET attempt = attempt + 1 WHERE id = $1",
                                     &[&id]);
                error!("Failed to build package {}-{} from queue: {}",
                       name,
                       version,
                       e)
            }
        }

        Ok(true)
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::path::PathBuf;
    use {DocBuilder, DocBuilderOptions};

    #[test]
    #[ignore]
    fn test_get_new_crates() {
        let _ = env_logger::try_init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let mut docbuilder = DocBuilder::new(options);
        let res = docbuilder.get_new_crates();
        if res.is_err() {
            error!("{:?}", res);
        }
        assert!(res.is_ok());
    }
}
<commit_msg>increment failed builds when attempts runs out<commit_after>//! Updates crates.io index and builds new packages

use super::{DocBuilder, RustwideBuilder};
use db::connect_db;
use error::Result;
use crates_index_diff::{ChangeKind, Index};
use utils::add_crate_to_queue;

impl DocBuilder {
    /// Updates crates.io-index repository and adds new crates into build queue.
    /// Returns size of queue
    pub fn get_new_crates(&mut self) -> Result<usize> {
        let conn = try!(connect_db());
        let index = try!(Index::from_path_or_cloned(&self.options.crates_io_index_path));
        let mut changes = try!(index.fetch_changes());
        let mut add_count: usize = 0;

        // I belive this will fix ordering of queue if we get more than one crate from changes
        changes.reverse();

        for krate in changes.iter().filter(|k| k.kind != ChangeKind::Yanked) {
            add_crate_to_queue(&conn, &krate.name, &krate.version, 0).ok();
            debug!("{}-{} added into build queue", krate.name, krate.version);
            add_count += 1;
        }

        Ok(add_count)
    }

    pub fn get_queue_count(&self) -> Result<i64> {
        let conn = try!(connect_db());
        Ok(conn.query("SELECT COUNT(*) FROM queue WHERE attempt < 5", &[])
            .unwrap()
            .get(0)
            .get(0))
    }

    /// Builds the top package from the queue. Returns whether the queue was empty.
    pub(crate) fn build_next_queue_package(
        &mut self,
        builder: &mut RustwideBuilder,
    ) -> Result<bool> {
        let conn = try!(connect_db());

        let query = try!(conn.query("SELECT id, name, version, attempt
                                     FROM queue
                                     WHERE attempt < 5
                                     ORDER BY priority ASC, attempt ASC, id ASC
                                     LIMIT 1",
                                    &[]));

        if query.is_empty() {
            // nothing in the queue; bail
            return Ok(false);
        }

        let id: i32 = query.get(0).get(0);
        let name: String = query.get(0).get(1);
        let version: String = query.get(0).get(2);
        let attempt: i32 = query.get(0).get(3);

        match builder.build_package(self, &name, &version) {
            Ok(_) => {
                let _ = conn.execute("DELETE FROM queue WHERE id = $1", &[&id]);
            }
            Err(e) => {
                // Increase attempt count
                let attempt = attempt + 1;
                let _ = conn.execute("UPDATE queue SET attempt = $1 WHERE id = $2",
                                     &[&attempt, &id]);
                if attempt >= 5 {
                    ::web::metrics::FAILED_BUILDS.inc();
                }
                error!("Failed to build package {}-{} from queue: {}",
                       name,
                       version,
                       e)
            }
        }

        Ok(true)
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::path::PathBuf;
    use {DocBuilder, DocBuilderOptions};

    #[test]
    #[ignore]
    fn test_get_new_crates() {
        let _ = env_logger::try_init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let mut docbuilder = DocBuilder::new(options);
        let res = docbuilder.get_new_crates();
        if res.is_err() {
            error!("{:?}", res);
        }
        assert!(res.is_ok());
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use cgmath::vector::Vec2;

pub struct TileIterator {
  cursor: Vec2<i32>
}

impl TileIterator {
  pub fn new() -> TileIterator {
    TileIterator {
      cursor: Vec2::zero()
    }
  }
}

impl Iterator<Vec2<i32>> for TileIterator {
  fn next(&mut self) -> Option<Vec2<i32>> {
    let map_size = Vec2::<i32>{x: 3, y: 4};
    let current_pos = if self.cursor.y > map_size.y {
      None
    } else {
      Some(self.cursor)
    };
    self.cursor.x += 1;
    if self.cursor.x > map_size.x {
      self.cursor.x = 0;
      self.cursor.y += 1;
    }
    current_pos
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Map: Added trailing commas<commit_after>// See LICENSE file for copyright and license details.

use cgmath::vector::Vec2;

pub struct TileIterator {
  cursor: Vec2<i32>,
}

impl TileIterator {
  pub fn new() -> TileIterator {
    TileIterator {
      cursor: Vec2::zero(),
    }
  }
}

impl Iterator<Vec2<i32>> for TileIterator {
  fn next(&mut self) -> Option<Vec2<i32>> {
    let map_size = Vec2::<i32>{x: 3, y: 4};
    let current_pos = if self.cursor.y > map_size.y {
      None
    } else {
      Some(self.cursor)
    };
    self.cursor.x += 1;
    if self.cursor.x > map_size.x {
      self.cursor.x = 0;
      self.cursor.y += 1;
    }
    current_pos
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>use std::str::Chars;
use std::iter::Peekable;
use std::iter::Enumerate;

use ::syntax::lexer::{Token, Lexer, Span};
use ::syntax::next_is;

pub struct RustSyntax;

impl Lexer for RustSyntax {
    fn handle_char(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize, idx: usize) -> Option<Span> {
        match ch {
            '#' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '!') || next_is(&mut iter, '[') {
                    let mut s = String::from("#");
                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Attribute(s),
                    });
                }
                return Some(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Hash})
            }

            '/' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '/') {
                    let mut s = String::from("/");
                    s.push(iter.next().unwrap().1);

                    let mut doc_comment = false;
                    if next_is(&mut iter, '/') {
                        doc_comment = true;
                    }

                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }

                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: if doc_comment{ Token::DocComment(s) } else { Token::SingleLineComment(s) },
                    });
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::ForwardSlash,
                });
            }

            '"' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\"");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '\\' {
                        if let Some(&(e, c_)) = iter.peek() {
                            // this is handling escaped single quotes...
                            if c_ == '"' {
                                s.push(iter.next().unwrap().1);
                                continue;
                            }
                        }
                    }
                    if c == '"' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::String(s),
                });
            }

            '\'' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\'");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '\\' {
                        if let Some(&(e, c_)) = iter.peek() {
                            // this is handling escaped single quotes...
                            if c_ == '\'' {
                                s.push(iter.next().unwrap().1);
                                continue;
                            }
                        }
                    }
                    if c == '\'' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::Special(s),
                });
            }

            ':' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, ':') {
                    let (e, c) = iter.next().unwrap();
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: e,
                        token: Token::Special(String::from("::")),
                    });
                } else {
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Colon,
                    });
                }
            }

            _ => None,
        }

    }

    fn handle_ident(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span {
        let mut ident = String::new();
        ident.push(ch);
        let start = iter.peek().unwrap().0 - 1;

        while self.is_ident(iter.peek()) {
            ident.push(iter.next().unwrap().1)
        }

        Span {
            y_pos: y_pos,
            start: start,
            end: start + ident.len() - 1,
            token: Token::Ident(ident),
        }
    }
}

<commit_msg>Fix entering content in empty files<commit_after>use std::str::Chars;
use std::iter::Peekable;
use std::iter::Enumerate;

use ::syntax::lexer::{Token, Lexer, Span};
use ::syntax::next_is;

pub struct RustSyntax;

impl Lexer for RustSyntax {
    fn handle_char(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize, idx: usize) -> Option<Span> {
        match ch {
            '#' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '!') || next_is(&mut iter, '[') {
                    let mut s = String::from("#");
                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Attribute(s),
                    });
                }
                return Some(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Hash})
            }

            '/' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '/') {
                    let mut s = String::from("/");
                    s.push(iter.next().unwrap().1);

                    let mut doc_comment = false;
                    if next_is(&mut iter, '/') {
                        doc_comment = true;
                    }

                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }

                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: if doc_comment{ Token::DocComment(s) } else { Token::SingleLineComment(s) },
                    });
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::ForwardSlash,
                });
            }

            '"' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\"");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '\\' {
                        if let Some(&(e, c_)) = iter.peek() {
                            // this is handling escaped single quotes...
                            if c_ == '"' {
                                s.push(iter.next().unwrap().1);
                                continue;
                            }
                        }
                    }
                    if c == '"' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::String(s),
                });
            }

            '\'' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\'");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '\\' {
                        if let Some(&(e, c_)) = iter.peek() {
                            // this is handling escaped single quotes...
                            if c_ == '\'' {
                                s.push(iter.next().unwrap().1);
                                continue;
                            }
                        }
                    }
                    if c == '\'' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::Special(s),
                });
            }

            ':' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, ':') {
                    let (e, c) = iter.next().unwrap();
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: e,
                        token: Token::Special(String::from("::")),
                    });
                } else {
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Colon,
                    });
                }
            }

            _ => None,
        }

    }

    fn handle_ident(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span {
        let mut ident = String::new();
        ident.push(ch);
        let mut start = 0;

        if let Some(&(x, c)) = iter.peek() {
            start = x - 1;
        }

        while self.is_ident(iter.peek()) {
            ident.push(iter.next().unwrap().1)
        }

        Span {
            y_pos: y_pos,
            start: start,
            end: start + ident.len() - 1,
            token: Token::Ident(ident),
        }
    }
}

<|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/. */

//! Implementation of cookie storage as specified in
//! http://tools.ietf.org/html/rfc6265

use cookie::Cookie;
use cookie_rs;
use net_traits::CookieSource;
use net_traits::pub_domains::reg_suffix;
use servo_url::ServoUrl;
use std::cmp::Ordering;
use std::collections::HashMap;
use time::Tm;

extern crate time;

#[derive(Clone, Debug, RustcDecodable, RustcEncodable)]
pub struct CookieStorage {
    version: u32,
    cookies_map: HashMap<String, Vec<Cookie>>,
    max_per_host: usize,
}

impl CookieStorage {
    pub fn new(max_cookies: usize) -> CookieStorage {
        CookieStorage {
            version: 1,
            cookies_map: HashMap::new(),
            max_per_host: max_cookies,
        }
    }

    // http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn remove(&mut self, cookie: &Cookie, url: &ServoUrl, source: CookieSource) -> Result<Option<Cookie>, ()> {
        let domain = reg_host(cookie.cookie.domain.as_ref().unwrap_or(&"".to_string()));
        let cookies = self.cookies_map.entry(domain).or_insert(vec![]);

        // https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt Step 2
        if !cookie.cookie.secure && url.scheme() != "https" && url.scheme() != "wss" {
            let new_domain = cookie.cookie.domain.as_ref().unwrap();
            let new_path = cookie.cookie.path.as_ref().unwrap();

            let any_overlapping = cookies.iter().any(|c| {
                let existing_domain = c.cookie.domain.as_ref().unwrap();
                let existing_path = c.cookie.path.as_ref().unwrap();

                c.cookie.name == cookie.cookie.name &&
                c.cookie.secure &&
                (Cookie::domain_match(new_domain, existing_domain) ||
                 Cookie::domain_match(existing_domain, new_domain)) &&
                Cookie::path_match(new_path, existing_path)
            });

            if any_overlapping {
                return Err(());
            }
        }

        // Step 11.1
        let position = cookies.iter().position(|c| {
            c.cookie.domain == cookie.cookie.domain &&
            c.cookie.path == cookie.cookie.path &&
            c.cookie.name == cookie.cookie.name
        });

        if let Some(ind) = position {
            // Step 11.4
            let c = cookies.remove(ind);

            // http://tools.ietf.org/html/rfc6265#section-5.3 step 11.2
            if c.cookie.httponly && source == CookieSource::NonHTTP {
                // Undo the removal.
                cookies.push(c);
                Err(())
            } else {
                Ok(Some(c))
            }
        } else {
            Ok(None)
        }
    }

    // http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn push(&mut self, mut cookie: Cookie, url: &ServoUrl, source: CookieSource) {
        // https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt Step 1
        if cookie.cookie.secure && url.scheme() != "https" && url.scheme() != "wss" {
            return;
        }

        let old_cookie = self.remove(&cookie, url, source);
        if old_cookie.is_err() {
            // This new cookie is not allowed to overwrite an existing one.
            return;
        }

        // Step 11
        if let Some(old_cookie) = old_cookie.unwrap() {
            // Step 11.3
            cookie.creation_time = old_cookie.creation_time;
        }

        // Step 12
        let domain = reg_host(&cookie.cookie.domain.as_ref().unwrap_or(&"".to_string()));
        let mut cookies = self.cookies_map.entry(domain).or_insert(vec![]);

        if cookies.len() == self.max_per_host {
            let old_len = cookies.len();
            cookies.retain(|c| !is_cookie_expired(&c));
            let new_len = cookies.len();

            // https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt
            if new_len == old_len && !evict_one_cookie(cookie.cookie.secure, cookies) {
                return;
            }
        }
        cookies.push(cookie);
    }

    pub fn cookie_comparator(a: &Cookie, b: &Cookie) -> Ordering {
        let a_path_len = a.cookie.path.as_ref().map_or(0, |p| p.len());
        let b_path_len = b.cookie.path.as_ref().map_or(0, |p| p.len());
        match a_path_len.cmp(&b_path_len) {
            Ordering::Equal => {
                let a_creation_time = a.creation_time.to_timespec();
                let b_creation_time = b.creation_time.to_timespec();
                a_creation_time.cmp(&b_creation_time)
            }
            // Ensure that longer paths are sorted earlier than shorter paths
            Ordering::Greater => Ordering::Less,
            Ordering::Less => Ordering::Greater,
        }
    }

    // http://tools.ietf.org/html/rfc6265#section-5.4
    pub fn cookies_for_url(&mut self, url: &ServoUrl, source: CookieSource) -> Option<String> {
        let filterer = |c: &&mut Cookie| -> bool {
            info!(" === SENT COOKIE : {} {} {:?} {:?}",
                  c.cookie.name,
                  c.cookie.value,
                  c.cookie.domain,
                  c.cookie.path);
            info!(" === SENT COOKIE RESULT {}",
                  c.appropriate_for_url(url, source));
            // Step 1
            c.appropriate_for_url(url, source)
        };
        // Step 2
        let domain = reg_host(url.host_str().unwrap_or(""));
        let cookies = self.cookies_map.entry(domain).or_insert(vec![]);

        let mut url_cookies: Vec<&mut Cookie> = cookies.iter_mut().filter(filterer).collect();
        url_cookies.sort_by(|a, b| CookieStorage::cookie_comparator(*a, *b));

        let reducer = |acc: String, c: &mut &mut Cookie| -> String {
            // Step 3
            c.touch();

            // Step 4
            (match acc.len() {
                0 => acc,
                _ => acc + "; ",
            }) + &c.cookie.name + "=" + &c.cookie.value
        };
        let result = url_cookies.iter_mut().fold("".to_owned(), reducer);

        info!(" === COOKIES SENT: {}", result);
        match result.len() {
            0 => None,
            _ => Some(result),
        }
    }

    pub fn cookies_data_for_url<'a>(&'a mut self,
                                    url: &'a ServoUrl,
                                    source: CookieSource)
                                    -> Box<Iterator<Item = cookie_rs::Cookie> + 'a> {
        let domain = reg_host(url.host_str().unwrap_or(""));
        let cookies = self.cookies_map.entry(domain).or_insert(vec![]);

        Box::new(cookies.iter_mut().filter(move |c| c.appropriate_for_url(url, source)).map(|c| {
            c.touch();
            c.cookie.clone()
        }))
    }
}

fn reg_host<'a>(url: &'a str) -> String {
    reg_suffix(url).to_string()
}

fn is_cookie_expired(cookie: &Cookie) -> bool {
    match cookie.expiry_time {
        Some(t) => t.to_timespec() <= time::get_time(),
        None => false,
    }
}

fn evict_one_cookie(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> bool {
    // Remove non-secure cookie with oldest access time
    let oldest_accessed: Option<(usize, Tm)> = get_oldest_accessed(false, cookies);

    if let Some((index, _)) = oldest_accessed {
        cookies.remove(index);
    } else {
        // All secure cookies were found
        if !is_secure_cookie {
            return false;
        }
        let oldest_accessed: Option<(usize, Tm)> = get_oldest_accessed(true, cookies);
        if let Some((index, _)) = oldest_accessed {
            cookies.remove(index);
        }
    }
    return true;
}

fn get_oldest_accessed(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> Option<(usize, Tm)> {
    let mut oldest_accessed: Option<(usize, Tm)> = None;
    for (i, c) in cookies.iter().enumerate() {
        if (c.cookie.secure == is_secure_cookie) &&
           oldest_accessed.as_ref().map_or(true, |a| c.last_access < a.1) {
            oldest_accessed = Some((i, c.last_access));
        }
    }
    oldest_accessed
}
<commit_msg>Refactor to use ServoUrl::is_secure_scheme<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/. */

//! Implementation of cookie storage as specified in
//! http://tools.ietf.org/html/rfc6265

use cookie::Cookie;
use cookie_rs;
use net_traits::CookieSource;
use net_traits::pub_domains::reg_suffix;
use servo_url::ServoUrl;
use std::cmp::Ordering;
use std::collections::HashMap;
use time::Tm;

extern crate time;

#[derive(Clone, Debug, RustcDecodable, RustcEncodable)]
pub struct CookieStorage {
    version: u32,
    cookies_map: HashMap<String, Vec<Cookie>>,
    max_per_host: usize,
}

impl CookieStorage {
    pub fn new(max_cookies: usize) -> CookieStorage {
        CookieStorage {
            version: 1,
            cookies_map: HashMap::new(),
            max_per_host: max_cookies,
        }
    }

    // http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn remove(&mut self, cookie: &Cookie, url: &ServoUrl, source: CookieSource) -> Result<Option<Cookie>, ()> {
        let domain = reg_host(cookie.cookie.domain.as_ref().unwrap_or(&"".to_string()));
        let cookies = self.cookies_map.entry(domain).or_insert(vec![]);

        // https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt Step 2
        if !cookie.cookie.secure && !url.is_secure_scheme() {
            let new_domain = cookie.cookie.domain.as_ref().unwrap();
            let new_path = cookie.cookie.path.as_ref().unwrap();

            let any_overlapping = cookies.iter().any(|c| {
                let existing_domain = c.cookie.domain.as_ref().unwrap();
                let existing_path = c.cookie.path.as_ref().unwrap();

                c.cookie.name == cookie.cookie.name &&
                c.cookie.secure &&
                (Cookie::domain_match(new_domain, existing_domain) ||
                 Cookie::domain_match(existing_domain, new_domain)) &&
                Cookie::path_match(new_path, existing_path)
            });

            if any_overlapping {
                return Err(());
            }
        }

        // Step 11.1
        let position = cookies.iter().position(|c| {
            c.cookie.domain == cookie.cookie.domain &&
            c.cookie.path == cookie.cookie.path &&
            c.cookie.name == cookie.cookie.name
        });

        if let Some(ind) = position {
            // Step 11.4
            let c = cookies.remove(ind);

            // http://tools.ietf.org/html/rfc6265#section-5.3 step 11.2
            if c.cookie.httponly && source == CookieSource::NonHTTP {
                // Undo the removal.
                cookies.push(c);
                Err(())
            } else {
                Ok(Some(c))
            }
        } else {
            Ok(None)
        }
    }

    // http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn push(&mut self, mut cookie: Cookie, url: &ServoUrl, source: CookieSource) {
        // https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt Step 1
        if cookie.cookie.secure && !url.is_secure_scheme() {
            return;
        }

        let old_cookie = self.remove(&cookie, url, source);
        if old_cookie.is_err() {
            // This new cookie is not allowed to overwrite an existing one.
            return;
        }

        // Step 11
        if let Some(old_cookie) = old_cookie.unwrap() {
            // Step 11.3
            cookie.creation_time = old_cookie.creation_time;
        }

        // Step 12
        let domain = reg_host(&cookie.cookie.domain.as_ref().unwrap_or(&"".to_string()));
        let mut cookies = self.cookies_map.entry(domain).or_insert(vec![]);

        if cookies.len() == self.max_per_host {
            let old_len = cookies.len();
            cookies.retain(|c| !is_cookie_expired(&c));
            let new_len = cookies.len();

            // https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt
            if new_len == old_len && !evict_one_cookie(cookie.cookie.secure, cookies) {
                return;
            }
        }
        cookies.push(cookie);
    }

    pub fn cookie_comparator(a: &Cookie, b: &Cookie) -> Ordering {
        let a_path_len = a.cookie.path.as_ref().map_or(0, |p| p.len());
        let b_path_len = b.cookie.path.as_ref().map_or(0, |p| p.len());
        match a_path_len.cmp(&b_path_len) {
            Ordering::Equal => {
                let a_creation_time = a.creation_time.to_timespec();
                let b_creation_time = b.creation_time.to_timespec();
                a_creation_time.cmp(&b_creation_time)
            }
            // Ensure that longer paths are sorted earlier than shorter paths
            Ordering::Greater => Ordering::Less,
            Ordering::Less => Ordering::Greater,
        }
    }

    // http://tools.ietf.org/html/rfc6265#section-5.4
    pub fn cookies_for_url(&mut self, url: &ServoUrl, source: CookieSource) -> Option<String> {
        let filterer = |c: &&mut Cookie| -> bool {
            info!(" === SENT COOKIE : {} {} {:?} {:?}",
                  c.cookie.name,
                  c.cookie.value,
                  c.cookie.domain,
                  c.cookie.path);
            info!(" === SENT COOKIE RESULT {}",
                  c.appropriate_for_url(url, source));
            // Step 1
            c.appropriate_for_url(url, source)
        };
        // Step 2
        let domain = reg_host(url.host_str().unwrap_or(""));
        let cookies = self.cookies_map.entry(domain).or_insert(vec![]);

        let mut url_cookies: Vec<&mut Cookie> = cookies.iter_mut().filter(filterer).collect();
        url_cookies.sort_by(|a, b| CookieStorage::cookie_comparator(*a, *b));

        let reducer = |acc: String, c: &mut &mut Cookie| -> String {
            // Step 3
            c.touch();

            // Step 4
            (match acc.len() {
                0 => acc,
                _ => acc + "; ",
            }) + &c.cookie.name + "=" + &c.cookie.value
        };
        let result = url_cookies.iter_mut().fold("".to_owned(), reducer);

        info!(" === COOKIES SENT: {}", result);
        match result.len() {
            0 => None,
            _ => Some(result),
        }
    }

    pub fn cookies_data_for_url<'a>(&'a mut self,
                                    url: &'a ServoUrl,
                                    source: CookieSource)
                                    -> Box<Iterator<Item = cookie_rs::Cookie> + 'a> {
        let domain = reg_host(url.host_str().unwrap_or(""));
        let cookies = self.cookies_map.entry(domain).or_insert(vec![]);

        Box::new(cookies.iter_mut().filter(move |c| c.appropriate_for_url(url, source)).map(|c| {
            c.touch();
            c.cookie.clone()
        }))
    }
}

fn reg_host<'a>(url: &'a str) -> String {
    reg_suffix(url).to_string()
}

fn is_cookie_expired(cookie: &Cookie) -> bool {
    match cookie.expiry_time {
        Some(t) => t.to_timespec() <= time::get_time(),
        None => false,
    }
}

fn evict_one_cookie(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> bool {
    // Remove non-secure cookie with oldest access time
    let oldest_accessed: Option<(usize, Tm)> = get_oldest_accessed(false, cookies);

    if let Some((index, _)) = oldest_accessed {
        cookies.remove(index);
    } else {
        // All secure cookies were found
        if !is_secure_cookie {
            return false;
        }
        let oldest_accessed: Option<(usize, Tm)> = get_oldest_accessed(true, cookies);
        if let Some((index, _)) = oldest_accessed {
            cookies.remove(index);
        }
    }
    return true;
}

fn get_oldest_accessed(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> Option<(usize, Tm)> {
    let mut oldest_accessed: Option<(usize, Tm)> = None;
    for (i, c) in cookies.iter().enumerate() {
        if (c.cookie.secure == is_secure_cookie) &&
           oldest_accessed.as_ref().map_or(true, |a| c.last_access < a.1) {
            oldest_accessed = Some((i, c.last_access));
        }
    }
    oldest_accessed
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! An implementation of SipHash 2-4.

use prelude::v1::*;

use ptr;
use super::Hasher;

/// An implementation of SipHash 2-4.
///
/// See: http://131002.net/siphash/
///
/// This is currently the default hashing function used by standard library
/// (eg. `collections::HashMap` uses it by default).
///
/// SipHash is a general-purpose hashing function: it runs at a good
/// speed (competitive with Spooky and City) and permits strong _keyed_
/// hashing. This lets you key your hashtables from a strong RNG, such as
/// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
///
/// Although the SipHash algorithm is considered to be generally strong,
/// it is not intended for cryptographic purposes. As such, all
/// cryptographic uses of this implementation are _strongly discouraged_.
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SipHasher {
    k0: u64,
    k1: u64,
    length: usize, // how many bytes we've processed
    // v0, v2 and v1, v3 show up in pairs in the algorithm,
    // and simd implementations of SipHash will use vectors
    // of v02 and v13. By placing them in this order in the struct,
    // the compiler can pick up on just a few simd optimizations by itself.
    v0: u64, // hash state
    v2: u64,
    v1: u64,
    v3: u64,
    tail: u64, // unprocessed bytes le
    ntail: usize, // how many bytes in tail are valid
}

// sadly, these macro definitions can't appear later,
// because they're needed in the following defs;
// this design could be improved.

macro_rules! u8to64_le {
    ($buf:expr, $i:expr) =>
    ($buf[0+$i] as u64 |
     ($buf[1+$i] as u64) << 8 |
     ($buf[2+$i] as u64) << 16 |
     ($buf[3+$i] as u64) << 24 |
     ($buf[4+$i] as u64) << 32 |
     ($buf[5+$i] as u64) << 40 |
     ($buf[6+$i] as u64) << 48 |
     ($buf[7+$i] as u64) << 56);
    ($buf:expr, $i:expr, $len:expr) =>
    ({
        let mut t = 0;
        let mut out = 0;
        while t < $len {
            out |= ($buf[t+$i] as u64) << t*8;
            t += 1;
        }
        out
    });
}

/// Load a full u64 word from a byte stream, in LE order. Use
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
/// to load u64 from a possibly unaligned address.
///
/// Unsafe because: unchecked indexing at i..i+8
#[inline]
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
    debug_assert!(i + 8 <= buf.len());
    let mut data = 0u64;
    ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8);
    data.to_le()
}

macro_rules! rotl {
    ($x:expr, $b:expr) =>
    (($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
}

macro_rules! compress {
    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
    ({
        $v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
        $v0 = rotl!($v0, 32);
        $v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
        $v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
        $v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
        $v2 = rotl!($v2, 32);
    })
}

impl SipHasher {
    /// Creates a new `SipHasher` with the two initial keys set to 0.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new() -> SipHasher {
        SipHasher::new_with_keys(0, 0)
    }

    /// Creates a `SipHasher` that is keyed off the provided keys.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
        let mut state = SipHasher {
            k0: key0,
            k1: key1,
            length: 0,
            v0: 0,
            v1: 0,
            v2: 0,
            v3: 0,
            tail: 0,
            ntail: 0,
        };
        state.reset();
        state
    }

    #[inline]
    fn reset(&mut self) {
        self.length = 0;
        self.v0 = self.k0 ^ 0x736f6d6570736575;
        self.v1 = self.k1 ^ 0x646f72616e646f6d;
        self.v2 = self.k0 ^ 0x6c7967656e657261;
        self.v3 = self.k1 ^ 0x7465646279746573;
        self.ntail = 0;
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Hasher for SipHasher {
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        let length = msg.len();
        self.length += length;

        let mut needed = 0;

        if self.ntail != 0 {
            needed = 8 - self.ntail;
            if length < needed {
                self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail;
                self.ntail += length;
                return
            }

            let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail;

            self.v3 ^= m;
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= m;

            self.ntail = 0;
        }

        // Buffered tail is now flushed, process new input.
        let len = length - needed;
        let left = len & 0x7;

        let mut i = needed;
        while i < len - left {
            let mi = unsafe { load_u64_le(msg, i) };

            self.v3 ^= mi;
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= mi;

            i += 8;
        }

        self.tail = u8to64_le!(msg, i, left);
        self.ntail = left;
    }

    #[inline]
    fn finish(&self) -> u64 {
        let mut v0 = self.v0;
        let mut v1 = self.v1;
        let mut v2 = self.v2;
        let mut v3 = self.v3;

        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;

        v3 ^= b;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        v0 ^= b;

        v2 ^= 0xff;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);

        v0 ^ v1 ^ v2 ^ v3
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for SipHasher {
    #[inline]
    fn clone(&self) -> SipHasher {
        SipHasher {
            k0: self.k0,
            k1: self.k1,
            length: self.length,
            v0: self.v0,
            v1: self.v1,
            v2: self.v2,
            v3: self.v3,
            tail: self.tail,
            ntail: self.ntail,
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Default for SipHasher {
    fn default() -> SipHasher {
        SipHasher::new()
    }
}
<commit_msg>Prefer HTTPS when linking to 131002.net.<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! An implementation of SipHash 2-4.

use prelude::v1::*;

use ptr;
use super::Hasher;

/// An implementation of SipHash 2-4.
///
/// See: https://131002.net/siphash/
///
/// This is currently the default hashing function used by standard library
/// (eg. `collections::HashMap` uses it by default).
///
/// SipHash is a general-purpose hashing function: it runs at a good
/// speed (competitive with Spooky and City) and permits strong _keyed_
/// hashing. This lets you key your hashtables from a strong RNG, such as
/// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
///
/// Although the SipHash algorithm is considered to be generally strong,
/// it is not intended for cryptographic purposes. As such, all
/// cryptographic uses of this implementation are _strongly discouraged_.
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SipHasher {
    k0: u64,
    k1: u64,
    length: usize, // how many bytes we've processed
    // v0, v2 and v1, v3 show up in pairs in the algorithm,
    // and simd implementations of SipHash will use vectors
    // of v02 and v13. By placing them in this order in the struct,
    // the compiler can pick up on just a few simd optimizations by itself.
    v0: u64, // hash state
    v2: u64,
    v1: u64,
    v3: u64,
    tail: u64, // unprocessed bytes le
    ntail: usize, // how many bytes in tail are valid
}

// sadly, these macro definitions can't appear later,
// because they're needed in the following defs;
// this design could be improved.

macro_rules! u8to64_le {
    ($buf:expr, $i:expr) =>
    ($buf[0+$i] as u64 |
     ($buf[1+$i] as u64) << 8 |
     ($buf[2+$i] as u64) << 16 |
     ($buf[3+$i] as u64) << 24 |
     ($buf[4+$i] as u64) << 32 |
     ($buf[5+$i] as u64) << 40 |
     ($buf[6+$i] as u64) << 48 |
     ($buf[7+$i] as u64) << 56);
    ($buf:expr, $i:expr, $len:expr) =>
    ({
        let mut t = 0;
        let mut out = 0;
        while t < $len {
            out |= ($buf[t+$i] as u64) << t*8;
            t += 1;
        }
        out
    });
}

/// Load a full u64 word from a byte stream, in LE order. Use
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
/// to load u64 from a possibly unaligned address.
///
/// Unsafe because: unchecked indexing at i..i+8
#[inline]
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
    debug_assert!(i + 8 <= buf.len());
    let mut data = 0u64;
    ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8);
    data.to_le()
}

macro_rules! rotl {
    ($x:expr, $b:expr) =>
    (($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
}

macro_rules! compress {
    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
    ({
        $v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
        $v0 = rotl!($v0, 32);
        $v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
        $v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
        $v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
        $v2 = rotl!($v2, 32);
    })
}

impl SipHasher {
    /// Creates a new `SipHasher` with the two initial keys set to 0.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new() -> SipHasher {
        SipHasher::new_with_keys(0, 0)
    }

    /// Creates a `SipHasher` that is keyed off the provided keys.
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
        let mut state = SipHasher {
            k0: key0,
            k1: key1,
            length: 0,
            v0: 0,
            v1: 0,
            v2: 0,
            v3: 0,
            tail: 0,
            ntail: 0,
        };
        state.reset();
        state
    }

    #[inline]
    fn reset(&mut self) {
        self.length = 0;
        self.v0 = self.k0 ^ 0x736f6d6570736575;
        self.v1 = self.k1 ^ 0x646f72616e646f6d;
        self.v2 = self.k0 ^ 0x6c7967656e657261;
        self.v3 = self.k1 ^ 0x7465646279746573;
        self.ntail = 0;
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Hasher for SipHasher {
    #[inline]
    fn write(&mut self, msg: &[u8]) {
        let length = msg.len();
        self.length += length;

        let mut needed = 0;

        if self.ntail != 0 {
            needed = 8 - self.ntail;
            if length < needed {
                self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail;
                self.ntail += length;
                return
            }

            let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail;

            self.v3 ^= m;
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= m;

            self.ntail = 0;
        }

        // Buffered tail is now flushed, process new input.
        let len = length - needed;
        let left = len & 0x7;

        let mut i = needed;
        while i < len - left {
            let mi = unsafe { load_u64_le(msg, i) };

            self.v3 ^= mi;
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= mi;

            i += 8;
        }

        self.tail = u8to64_le!(msg, i, left);
        self.ntail = left;
    }

    #[inline]
    fn finish(&self) -> u64 {
        let mut v0 = self.v0;
        let mut v1 = self.v1;
        let mut v2 = self.v2;
        let mut v3 = self.v3;

        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;

        v3 ^= b;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        v0 ^= b;

        v2 ^= 0xff;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);

        v0 ^ v1 ^ v2 ^ v3
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for SipHasher {
    #[inline]
    fn clone(&self) -> SipHasher {
        SipHasher {
            k0: self.k0,
            k1: self.k1,
            length: self.length,
            v0: self.v0,
            v1: self.v1,
            v2: self.v2,
            v3: self.v3,
            tail: self.tail,
            ntail: self.ntail,
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Default for SipHasher {
    fn default() -> SipHasher {
        SipHasher::new()
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// ignore-test needs networking

extern crate extra;

use extra::net::tcp::TcpSocketBuf;

use std::io;
use std::isize;

use std::io::{ReaderUtil,WriterUtil};

enum Result {
  Nil,
  Int(isize),
  Data(~[u8]),
  List(~[Result]),
  Error(String),
  Status(String)
}

priv fn parse_data(len: usize, io: @io::Reader) -> Result {
  let res =
      if (len > 0) {
      let bytes = io.read_bytes(len as usize);
      assert_eq!(bytes.len(), len);
      Data(bytes)
  } else {
      Data(~[])
  };
  assert_eq!(io.read_char(), '\r');
  assert_eq!(io.read_char(), '\n');
  return res;
}

priv fn parse_list(len: usize, io: @io::Reader) -> Result {
    let mut list: ~[Result] = ~[];
    for _ in 0..len {
        let v = match io.read_char() {
            '$' => parse_bulk(io),
            ':' => parse_int(io),
             _ => panic!()
        };
        list.push(v);
    }
    return List(list);
}

priv fn chop(s: String) -> String {
  s.slice(0, s.len() - 1).to_string()
}

priv fn parse_bulk(io: @io::Reader) -> Result {
    match from_str::<isize>(chop(io.read_line())) {
    None => panic!(),
    Some(-1) => Nil,
    Some(len) if len >= 0 => parse_data(len as usize, io),
    Some(_) => panic!()
    }
}

priv fn parse_multi(io: @io::Reader) -> Result {
    match from_str::<isize>(chop(io.read_line())) {
    None => panic!(),
    Some(-1) => Nil,
    Some(0) => List(~[]),
    Some(len) if len >= 0 => parse_list(len as usize, io),
    Some(_) => panic!()
    }
}

priv fn parse_int(io: @io::Reader) -> Result {
    match from_str::<isize>(chop(io.read_line())) {
    None => panic!(),
    Some(i) => Int(i)
    }
}

priv fn parse_response(io: @io::Reader) -> Result {
    match io.read_char() {
    '$' => parse_bulk(io),
    '*' => parse_multi(io),
    '+' => Status(chop(io.read_line())),
    '-' => Error(chop(io.read_line())),
    ':' => parse_int(io),
    _ => panic!()
    }
}

priv fn cmd_to_string(cmd: ~[String]) -> String {
  let mut res = "*".to_string();
  res.push_str(cmd.len().to_string());
  res.push_str("\r\n");
    for s in &cmd {
    res.push_str(["$".to_string(), s.len().to_string(), "\r\n".to_string(),
                  (*s).clone(), "\r\n".to_string()].concat() );
    }
  res
}

fn query(cmd: ~[String], sb: TcpSocketBuf) -> Result {
  let cmd = cmd_to_string(cmd);
  //println!("{}", cmd);
  sb.write_str(cmd);
  let res = parse_response(@sb as @io::Reader);
  res
}

fn query2(cmd: ~[String]) -> Result {
  let _cmd = cmd_to_string(cmd);
    io::with_str_reader("$3\r\nXXX\r\n".to_string())(|sb| {
    let res = parse_response(@sb as @io::Reader);
    println!("{}", res);
    res
    });
}

pub fn main() {
}
<commit_msg>Remove `priv` from tests that aren't testing deprecated `priv`<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// ignore-test needs networking

extern crate extra;

use extra::net::tcp::TcpSocketBuf;

use std::io;
use std::isize;

use std::io::{ReaderUtil,WriterUtil};

enum Result {
  Nil,
  Int(isize),
  Data(~[u8]),
  List(~[Result]),
  Error(String),
  Status(String)
}

fn parse_data(len: usize, io: @io::Reader) -> Result {
  let res =
      if (len > 0) {
      let bytes = io.read_bytes(len as usize);
      assert_eq!(bytes.len(), len);
      Data(bytes)
  } else {
      Data(~[])
  };
  assert_eq!(io.read_char(), '\r');
  assert_eq!(io.read_char(), '\n');
  return res;
}

fn parse_list(len: usize, io: @io::Reader) -> Result {
    let mut list: ~[Result] = ~[];
    for _ in 0..len {
        let v = match io.read_char() {
            '$' => parse_bulk(io),
            ':' => parse_int(io),
             _ => panic!()
        };
        list.push(v);
    }
    return List(list);
}

fn chop(s: String) -> String {
  s.slice(0, s.len() - 1).to_string()
}

fn parse_bulk(io: @io::Reader) -> Result {
    match from_str::<isize>(chop(io.read_line())) {
    None => panic!(),
    Some(-1) => Nil,
    Some(len) if len >= 0 => parse_data(len as usize, io),
    Some(_) => panic!()
    }
}

fn parse_multi(io: @io::Reader) -> Result {
    match from_str::<isize>(chop(io.read_line())) {
    None => panic!(),
    Some(-1) => Nil,
    Some(0) => List(~[]),
    Some(len) if len >= 0 => parse_list(len as usize, io),
    Some(_) => panic!()
    }
}

fn parse_int(io: @io::Reader) -> Result {
    match from_str::<isize>(chop(io.read_line())) {
    None => panic!(),
    Some(i) => Int(i)
    }
}

fn parse_response(io: @io::Reader) -> Result {
    match io.read_char() {
    '$' => parse_bulk(io),
    '*' => parse_multi(io),
    '+' => Status(chop(io.read_line())),
    '-' => Error(chop(io.read_line())),
    ':' => parse_int(io),
    _ => panic!()
    }
}

fn cmd_to_string(cmd: ~[String]) -> String {
  let mut res = "*".to_string();
  res.push_str(cmd.len().to_string());
  res.push_str("\r\n");
    for s in &cmd {
    res.push_str(["$".to_string(), s.len().to_string(), "\r\n".to_string(),
                  (*s).clone(), "\r\n".to_string()].concat() );
    }
  res
}

fn query(cmd: ~[String], sb: TcpSocketBuf) -> Result {
  let cmd = cmd_to_string(cmd);
  //println!("{}", cmd);
  sb.write_str(cmd);
  let res = parse_response(@sb as @io::Reader);
  res
}

fn query2(cmd: ~[String]) -> Result {
  let _cmd = cmd_to_string(cmd);
    io::with_str_reader("$3\r\nXXX\r\n".to_string())(|sb| {
    let res = parse_response(@sb as @io::Reader);
    println!("{}", res);
    res
    });
}

pub fn main() {
}
<|endoftext|>


<commit_before>extern crate rand;
use rand::Rng;
use std::env;

const CYPHERBYTES: usize = 32;

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() != 2 {
        println!("usage: {} file-to-encrypt", args[0]);
        return
    }

    let mut rng = rand::thread_rng();

    let mut cyphertext = [0u8; CYPHERBYTES];
    rng.fill_bytes(&mut cyphertext);
    for x in &cyphertext { print!("{:02x}", *x); }
    println!()
}
<commit_msg>Rustc 1.13.0 needs empty string in final println!<commit_after>extern crate rand;
use rand::Rng;
use std::env;

const CYPHERBYTES: usize = 32;

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() != 2 {
        println!("usage: {} file-to-encrypt", args[0]);
        return
    }

    let mut rng = rand::thread_rng();

    let mut cyphertext = [0u8; CYPHERBYTES];
    rng.fill_bytes(&mut cyphertext);
    for x in &cyphertext { print!("{:02x}", *x); }
    println!("")
}
<|endoftext|>


<commit_before>const EXPECTED: &str = "\
cxxbridge $VERSION
David Tolnay <dtolnay@gmail.com>
https://github.com/dtolnay/cxx

USAGE:
    cxxbridge <input>.rs              Emit .cc file for bridge to stdout
    cxxbridge <input>.rs --header     Emit .h file for bridge to stdout
    cxxbridge --header                Emit \"rust/cxx.h\" header to stdout

ARGS:
    <input>
            Input Rust source file containing #[cxx::bridge].

OPTIONS:
        --cxx-impl-annotations <annotation>
            Optional annotation for implementations of C++ function wrappers
            that may be exposed to Rust. You may for example need to provide
            __declspec(dllexport) or __attribute__((visibility(\"default\")))
            if Rust code from one shared object or executable depends on
            these C++ functions in another.
               \x20
    -h, --help
            Print help information.

        --header
            Emit header with declarations only.

    -i, --include <include>...
            Any additional headers to #include. The cxxbridge tool does not
            parse or even require the given paths to exist; they simply go
            into the generated C++ code as #include lines.
               \x20
    -o, --output <output>
            Path of file to write as output. Output goes to stdout if -o is
            not specified.
               \x20
    -V, --version
            Print version information.
";

#[test]
fn test_help() {
    let mut app = super::app();
    let mut out = Vec::new();
    app.write_long_help(&mut out).unwrap();
    let help = String::from_utf8(out).unwrap();
    let version = option_env!("CARGO_PKG_VERSION").unwrap_or_default();
    let expected = EXPECTED.replace("$VERSION", version);
    assert_eq!(help, expected);
}
<commit_msg>Update help text test<commit_after>const EXPECTED: &str = "\
cxxbridge $VERSION
David Tolnay <dtolnay@gmail.com>
https://github.com/dtolnay/cxx

USAGE:
    cxxbridge <input>.rs              Emit .cc file for bridge to stdout
    cxxbridge <input>.rs --header     Emit .h file for bridge to stdout
    cxxbridge --header                Emit \"rust/cxx.h\" header to stdout

ARGS:
    <input>
            Input Rust source file containing #[cxx::bridge].

OPTIONS:
        --cxx-impl-annotations <annotation>
            Optional annotation for implementations of C++ function wrappers
            that may be exposed to Rust. You may for example need to provide
            __declspec(dllexport) or __attribute__((visibility(\"default\")))
            if Rust code from one shared object or executable depends on
            these C++ functions in another.
               \x20
    -h, --help
            Print help information.

        --header
            Emit header with declarations only. Optional if using `-o` with
            a path ending in `.h`.
               \x20
    -i, --include <include>...
            Any additional headers to #include. The cxxbridge tool does not
            parse or even require the given paths to exist; they simply go
            into the generated C++ code as #include lines.
               \x20
    -o, --output <output>
            Path of file to write as output. Output goes to stdout if -o is
            not specified.
               \x20
    -V, --version
            Print version information.
";

#[test]
fn test_help() {
    let mut app = super::app();
    let mut out = Vec::new();
    app.write_long_help(&mut out).unwrap();
    let help = String::from_utf8(out).unwrap();
    let version = option_env!("CARGO_PKG_VERSION").unwrap_or_default();
    let expected = EXPECTED.replace("$VERSION", version);
    assert_eq!(help, expected);
}
<|endoftext|>