<commit_before>use std::io;
use std::ops::{Deref, DerefMut};

use mio::{Token, Sender};
use time::{Timespec};

use handler::Notify;
use loop_api::LoopApi;
use loop_time::{estimate_timespec};
use notify::create_notifier;
use {Notifier, Time};
use {Evented, EventSet, PollOpt, Timeout, TimerError};

/// The structure passed to every action handler
///
/// Scope is used for the following purposes:
///
/// 1. Register/deregister sockets in the event loop
/// 2. Register timeouts
/// 3. Create a special `Notifier` object to wakeup sibling state machines
/// 4. Access to global state of the loop (Context)
///
/// All methods here operate on **enclosed state machine**, which means the
/// state machine that was called with this scope. Or in other words the
/// state machine that actually performs an action.
///
/// The only way to notify another state machine is to create a `notifier()`
/// (the `Notifier` is only able to wakeup this state machine still), transfer
/// it to another state machine (for example putting it into the context)
/// and call `Notifier::wakeup()`.
///
/// The structure derefs to the context (``C``) for convenience
pub struct Scope<'a, C:Sized+'a>{
    token: Token,
    ctx: &'a mut C,
    channel: &'a mut Sender<Notify>,
    loop_api: &'a mut LoopApi,
    time: Time,
}

/// This is a structure that works similarly to Scope, but doesn't
/// have a context
///
/// The primary (and probably the only) use case for the `EarlyScope` is to
/// allow to create a state machine before context has been intialized. This
/// is useful if you want to put a `Notifier` of the FSM to a context itself.
pub struct EarlyScope<'a> {
    token: Token,
    channel: &'a mut Sender<Notify>,
    loop_api: &'a mut LoopApi,
}

/// A common part of `Scope` and `EarlyScope`
///
/// For most cases `Scope` scope should be used directly. The trait is here
/// so you can create a constructor for state machine that is generic over
/// type of scope used.
pub trait GenericScope {
    fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>;
    fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>;
    fn deregister(&mut self, io: &Evented) -> io::Result<()>;

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>;
    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    fn clear_timeout(&mut self, token: Timeout) -> bool;

    /// Returns an object that can be used to wake up the enclosed
    /// state machine
    fn notifier(&mut self) -> Notifier;

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    fn now(&self) -> Time;

    /// Returns the Timespec that corresponds to the Time in this loop
    ///
    /// Note: this is an estimate, because we use *monotonic* time under the
    /// hood, but `Timespec` is a subject for adjustments of the system clock.
    ///
    /// I.e. it is fine to use this time to present it to the user, but it's
    /// wrong to rely on it in code.
    fn estimate_timespec(&self, time: Time) -> Timespec {
        estimate_timespec(self.now(), time)
    }
}

impl<'a, C:Sized+'a> Scope<'a, C> {

    pub fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.register(io, self.token, interest, opt)
    }

    pub fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.reregister(io, self.token, interest, opt)
    }

    pub fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.loop_api.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    pub fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.loop_api.timeout_ms(self.token, delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    pub fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.loop_api.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    pub fn notifier(&mut self) -> Notifier {
        create_notifier(self.token, self.channel)
    }

    /// Shutdown the event loop
    pub fn shutdown_loop(&mut self) {
        self.loop_api.shutdown()
    }

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    pub fn now(&self) -> Time {
        self.time
    }

    /// Returns the Timespec that corresponds to the Time in this loop
    ///
    /// Note: this is an estimate, because we use *monotonic* time under the
    /// hood, but `Timespec` is a subject for adjustments of the system clock.
    ///
    /// I.e. it is fine to use this time to present it to the user, but it's
    /// wrong to rely on it in code.
    pub fn estimate_timespec(&self, time: Time) -> Timespec {
        estimate_timespec(self.now(), time)
    }
}

impl<'a, C:Sized+'a> GenericScope for Scope<'a, C> {

    fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.register(io, interest, opt)
    }

    fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.reregister(io, interest, opt)
    }

    fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.timeout_ms(delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    fn notifier(&mut self) -> Notifier {
        self.notifier()
    }

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    fn now(&self) -> Time {
        self.time
    }
}

impl<'a, C> Deref for Scope<'a, C> {
    type Target = C;
    fn deref(&self) -> &C {
        self.ctx
    }
}

impl<'a, C> DerefMut for Scope<'a, C> {
    fn deref_mut(&mut self) -> &mut C {
        self.ctx
    }
}

impl<'a> EarlyScope<'a> {

    pub fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.register(io, self.token, interest, opt)
    }

    pub fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.reregister(io, self.token, interest, opt)
    }

    pub fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.loop_api.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    pub fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.loop_api.timeout_ms(self.token, delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    pub fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.loop_api.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    pub fn notifier(&mut self) -> Notifier {
        create_notifier(self.token, self.channel)
    }

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    pub fn now(&self) -> Time {
        // Early scope is only used when creating a context. It's definitely
        // at the start of the things. But we may review this in future.
        Time::zero()
    }

    /// Returns the Timespec that corresponds to the Time in this loop
    ///
    /// Note: this is an estimate, because we use *monotonic* time under the
    /// hood, but `Timespec` is a subject for adjustments of the system clock.
    ///
    /// I.e. it is fine to use this time to present it to the user, but it's
    /// wrong to rely on it in code.
    pub fn estimate_timespec(&self, time: Time) -> Timespec {
        estimate_timespec(self.now(), time)
    }
}

impl<'a> GenericScope for EarlyScope<'a> {

    fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.register(io, interest, opt)
    }

    fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.reregister(io, interest, opt)
    }

    fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.timeout_ms(delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    fn notifier(&mut self) -> Notifier {
        self.notifier()
    }
    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    fn now(&self) -> Time {
        // Early scope is only used when creating a context. It's definitely
        // at the start of the things. But we may review this in future.
        Time::zero()
    }
}

#[doc(hidden)]
pub fn scope<'x, C, L:LoopApi>(time: Time, token: Token, ctx: &'x mut C,
    channel: &'x mut Sender<Notify>, loop_api: &'x mut L)
    -> Scope<'x, C>
{
    Scope {
        token: token,
        ctx: ctx,
        channel: channel,
        loop_api: loop_api,
        time: time,
    }
}

#[doc(hidden)]
pub fn early_scope<'x, L:LoopApi>(token: Token,
    channel: &'x mut Sender<Notify>, loop_api: &'x mut L)
    -> EarlyScope<'x>
{
    EarlyScope {
        token: token,
        channel: channel,
        loop_api: loop_api,
    }
}
<commit_msg>Make `Scope::notifier` receiving self by immutable borrow<commit_after>use std::io;
use std::ops::{Deref, DerefMut};

use mio::{Token, Sender};
use time::{Timespec};

use handler::Notify;
use loop_api::LoopApi;
use loop_time::{estimate_timespec};
use notify::create_notifier;
use {Notifier, Time};
use {Evented, EventSet, PollOpt, Timeout, TimerError};

/// The structure passed to every action handler
///
/// Scope is used for the following purposes:
///
/// 1. Register/deregister sockets in the event loop
/// 2. Register timeouts
/// 3. Create a special `Notifier` object to wakeup sibling state machines
/// 4. Access to global state of the loop (Context)
///
/// All methods here operate on **enclosed state machine**, which means the
/// state machine that was called with this scope. Or in other words the
/// state machine that actually performs an action.
///
/// The only way to notify another state machine is to create a `notifier()`
/// (the `Notifier` is only able to wakeup this state machine still), transfer
/// it to another state machine (for example putting it into the context)
/// and call `Notifier::wakeup()`.
///
/// The structure derefs to the context (``C``) for convenience
pub struct Scope<'a, C:Sized+'a>{
    token: Token,
    ctx: &'a mut C,
    channel: &'a mut Sender<Notify>,
    loop_api: &'a mut LoopApi,
    time: Time,
}

/// This is a structure that works similarly to Scope, but doesn't
/// have a context
///
/// The primary (and probably the only) use case for the `EarlyScope` is to
/// allow to create a state machine before context has been intialized. This
/// is useful if you want to put a `Notifier` of the FSM to a context itself.
pub struct EarlyScope<'a> {
    token: Token,
    channel: &'a mut Sender<Notify>,
    loop_api: &'a mut LoopApi,
}

/// A common part of `Scope` and `EarlyScope`
///
/// For most cases `Scope` scope should be used directly. The trait is here
/// so you can create a constructor for state machine that is generic over
/// type of scope used.
pub trait GenericScope {
    fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>;
    fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>;
    fn deregister(&mut self, io: &Evented) -> io::Result<()>;

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>;
    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    fn clear_timeout(&mut self, token: Timeout) -> bool;

    /// Returns an object that can be used to wake up the enclosed
    /// state machine
    fn notifier(&self) -> Notifier;

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    fn now(&self) -> Time;

    /// Returns the Timespec that corresponds to the Time in this loop
    ///
    /// Note: this is an estimate, because we use *monotonic* time under the
    /// hood, but `Timespec` is a subject for adjustments of the system clock.
    ///
    /// I.e. it is fine to use this time to present it to the user, but it's
    /// wrong to rely on it in code.
    fn estimate_timespec(&self, time: Time) -> Timespec {
        estimate_timespec(self.now(), time)
    }
}

impl<'a, C:Sized+'a> Scope<'a, C> {

    pub fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.register(io, self.token, interest, opt)
    }

    pub fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.reregister(io, self.token, interest, opt)
    }

    pub fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.loop_api.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    pub fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.loop_api.timeout_ms(self.token, delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    pub fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.loop_api.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    pub fn notifier(&self) -> Notifier {
        create_notifier(self.token, self.channel)
    }

    /// Shutdown the event loop
    pub fn shutdown_loop(&mut self) {
        self.loop_api.shutdown()
    }

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    pub fn now(&self) -> Time {
        self.time
    }

    /// Returns the Timespec that corresponds to the Time in this loop
    ///
    /// Note: this is an estimate, because we use *monotonic* time under the
    /// hood, but `Timespec` is a subject for adjustments of the system clock.
    ///
    /// I.e. it is fine to use this time to present it to the user, but it's
    /// wrong to rely on it in code.
    pub fn estimate_timespec(&self, time: Time) -> Timespec {
        estimate_timespec(self.now(), time)
    }
}

impl<'a, C:Sized+'a> GenericScope for Scope<'a, C> {

    fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.register(io, interest, opt)
    }

    fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.reregister(io, interest, opt)
    }

    fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.timeout_ms(delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    fn notifier(&self) -> Notifier {
        self.notifier()
    }

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    fn now(&self) -> Time {
        self.time
    }
}

impl<'a, C> Deref for Scope<'a, C> {
    type Target = C;
    fn deref(&self) -> &C {
        self.ctx
    }
}

impl<'a, C> DerefMut for Scope<'a, C> {
    fn deref_mut(&mut self) -> &mut C {
        self.ctx
    }
}

impl<'a> EarlyScope<'a> {

    pub fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.register(io, self.token, interest, opt)
    }

    pub fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.reregister(io, self.token, interest, opt)
    }

    pub fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.loop_api.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    pub fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.loop_api.timeout_ms(self.token, delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    pub fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.loop_api.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    pub fn notifier(&self) -> Notifier {
        create_notifier(self.token, self.channel)
    }

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    pub fn now(&self) -> Time {
        // Early scope is only used when creating a context. It's definitely
        // at the start of the things. But we may review this in future.
        Time::zero()
    }

    /// Returns the Timespec that corresponds to the Time in this loop
    ///
    /// Note: this is an estimate, because we use *monotonic* time under the
    /// hood, but `Timespec` is a subject for adjustments of the system clock.
    ///
    /// I.e. it is fine to use this time to present it to the user, but it's
    /// wrong to rely on it in code.
    pub fn estimate_timespec(&self, time: Time) -> Timespec {
        estimate_timespec(self.now(), time)
    }
}

impl<'a> GenericScope for EarlyScope<'a> {

    fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.register(io, interest, opt)
    }

    fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.reregister(io, interest, opt)
    }

    fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.timeout_ms(delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    fn notifier(&self) -> Notifier {
        self.notifier()
    }
    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    fn now(&self) -> Time {
        // Early scope is only used when creating a context. It's definitely
        // at the start of the things. But we may review this in future.
        Time::zero()
    }
}

#[doc(hidden)]
pub fn scope<'x, C, L:LoopApi>(time: Time, token: Token, ctx: &'x mut C,
    channel: &'x mut Sender<Notify>, loop_api: &'x mut L)
    -> Scope<'x, C>
{
    Scope {
        token: token,
        ctx: ctx,
        channel: channel,
        loop_api: loop_api,
        time: time,
    }
}

#[doc(hidden)]
pub fn early_scope<'x, L:LoopApi>(token: Token,
    channel: &'x mut Sender<Notify>, loop_api: &'x mut L)
    -> EarlyScope<'x>
{
    EarlyScope {
        token: token,
        channel: channel,
        loop_api: loop_api,
    }
}
<|endoftext|>


<commit_before>#![cfg(test)]
extern crate rand;

use super::*;
use rand::Rng;

#[test]
fn test_0nnn(){
    assert!(false);
}

#[test]
fn test_00e0(){
    assert!(false);
}

#[test]
fn test_1nnn(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        // start at 202 to not overwrite first instruction
        let nnn = rng.gen_range(0x202,0xFFF);
        let zn = ((nnn >> 0x8) | 0x10) as u8;
        let nn = (nnn & 0x0FF) as u8;

        let mut memory:[u8;0xE00] = [0;0xE00];
        // set jump command
        memory[0] = zn | 0x10;
        memory[1] = nn;

        // set jumped to command
        memory[nnn - 0x200] = 0x65;
        memory[nnn - 0x200 + 1] = 0x55;

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();

        // verify two cycles caused jumped to command to be executed
        assert!(machine.v[0x5] == 0x55);
    }
}

#[test]
fn test_2nnn(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        // start at 202 to not overwrite first instruction
        let nnn = rng.gen_range(0x202,0xFFF);
        let zn = ((nnn >> 8) | 0x20) as u8;
        let nn = (nnn & 0x0FF) as u8;

        let mut memory:[u8;0xE00] = [0;0xE00];
        // set call command
        memory[0] = zn;
        memory[1] = nn;

        // set jumped to command
        memory[nnn - 0x200] = 0x65;
        memory[nnn - 0x200 + 1] = 0x55;

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();

        // verify two cycles caused jumped to command to be executed
        assert!(machine.v[0x5] == 0x55);
        assert!(machine.sp == 1);
        assert!(machine.stack[0] == 0x200);
    }
}

#[test]
fn test_3xnn(){
    assert!(false);
}

#[test]
fn test_4xnn(){
    assert!(false);
}

#[test]
fn test_5xy0(){
    assert!(false);
}

#[test]
fn test_6xnn(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let n = rand::random::<u8>() & 0xFF;

        let memory = [
            0x60 | x, n,
        ];

    let mut machine = Chip8::default();
    machine.load_rom(&memory);
    machine.cycle();

    assert!(machine.v[x as usize] == n);
    }
}

#[test]
fn test_7xnn(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let xbase = rand::random::<u8>();
        let n = rand::random::<u8>();

        let memory = [
            0x60 | x, xbase,
            0x70 | x, n,
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();

        assert!(machine.v[x as usize] == xbase.wrapping_add(n));
    }
}

#[test]
fn test_8xy1(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let mut y = x;
        while y == x {y = rand::random::<u8>() & 0x0F;}
        let y = y;

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = rand::random::<u8>();

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x01 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        assert!(machine.v[x as usize] == xval | yval);
    }
}

#[test]
fn test_8xy2(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let mut y = x;
        while y == x {y = rand::random::<u8>() & 0x0F;}
        let y = y;

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = rand::random::<u8>();

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x02 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        assert!(machine.v[x as usize] == xval & yval);
    }
}

#[test]
fn test_8xy3(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let mut y = x;
        while y == x {y = rand::random::<u8>() & 0x0F;}
        let y = y;

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = rand::random::<u8>();

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x03 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        assert!(machine.v[x as usize] == xval ^ yval);
    }
}

#[test]
fn test_8xy4(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        let x = rng.gen_range(0x0, 0x0F);
        let y = rng.gen_range(0x0, 0x0F);

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = if x != y {rand::random::<u8>()} else {xval};

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x04 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        let (sum, flag) = xval.overflowing_add(yval);
        assert!(machine.v[x as usize] == sum);
        assert!(machine.v[0xF] == if flag {1} else {0});
    }
}

#[test]
fn test_8xy5(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        let x = rng.gen_range(0x0, 0x0F);
        let y = rng.gen_range(0x0, 0x0F);

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = if x != y {rand::random::<u8>()} else {xval};

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x05 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        let (sum, flag) = xval.overflowing_sub(yval);
        assert!(machine.v[x as usize] == sum);
        assert!(machine.v[0xF] == if flag {0} else {1});
    }
}

#[test]
fn test_8xy6(){
    assert!(false);
}

#[test]
fn test_8xy7(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        let x = rng.gen_range(0x0, 0x0F);
        let y = rng.gen_range(0x0, 0x0F);

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = if x != y {rand::random::<u8>()} else {xval};

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x07 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        let (sum, flag) = yval.overflowing_sub(xval);
        assert!(machine.v[x as usize] == sum);
        assert!(machine.v[0xF] == if flag {0} else {1});
    }
    assert!(false);
}

#[test]
fn test_8xye(){
    assert!(false);
}

#[test]
fn test_9xy0(){
    assert!(false);
}

#[test]
fn test_annn(){
    assert!(false);
}

#[test]
fn test_bnnn(){
    let mut rng = rand::thread_rng();

    let nnn:u16 = rng.gen_range(0x204, 0xF00);
    let val:u8 = rand::random::<u8>();

    let zn = ((nnn >> 0x8) | 0xB0) as u8;
    let nn = (nnn & 0x0FF) as u8;

    let mut memory:[u8;0xE00] = [0;0xE00];
    memory[0] = 0x60;
    memory[1] = val;
    memory[2] = zn;
    memory[3] = nn;

    memory[(nnn as usize) - 0x200 + (val as usize)] = 0x65;
    memory[(nnn as usize) - 0x200 + (val as usize) + 1] = 0x55;

    let mut machine = Chip8::default();
    machine.load_rom(&memory);
    machine.cycle();
    machine.cycle();
    machine.cycle();

    assert!(machine.v[5] == 0x55);
}

#[test]
fn test_cxnn(){
    assert!(false);
}

#[test]
fn test_dxyn(){
    assert!(false);
}

#[test]
fn test_ex9e(){

    let opt:u16  = 0xE09E;
    let xval = rand::random::<u16>() & 0x0F00;
    let key = xval >> 0x8;

    // set up machine
    let mut machine = Chip8::default();
    machine.key[key as usize] = true;
    assert!(false);
}

#[test]
fn test_exa1(){
    assert!(false);
}

#[test]
fn test_fx07(){
    assert!(false);
}

#[test]
fn test_fx0a(){
    assert!(false);
}

#[test]
fn test_fx15(){
    assert!(false);
}

#[test]
fn test_fx18(){
    assert!(false);
}

#[test]
fn test_fx1e(){
    assert!(false);
}

#[test]
fn test_fx29(){
    assert!(false);
}

#[test]
fn test_fx33(){
    assert!(false);
}

#[test]
fn test_fx55(){
    assert!(false);
}

#[test]
fn test_fx65(){
    assert!(false);
}
<commit_msg>commented out broken tests<commit_after>#![cfg(test)]
extern crate rand;

use super::*;
use super::std;
use self::rand::Rng;

/*
#[test]
fn test_0nnn(){
    assert!(false);
}

#[test]
fn test_00e0(){
    assert!(false);
}

#[test]
fn test_1nnn(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        // start at 202 to not overwrite first instruction
        let nnn = rng.gen_range(0x202,0xFFF);
        let zn = ((nnn >> 0x8) | 0x10) as u8;
        let nn = (nnn & 0x0FF) as u8;

        let mut memory:[u8;0xE00] = [0;0xE00];
        // set jump command
        memory[0] = zn | 0x10;
        memory[1] = nn;

        // set jumped to command
        memory[nnn - 0x200] = 0x65;
        memory[nnn - 0x200 + 1] = 0x55;

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();

        // verify two cycles caused jumped to command to be executed
        assert!(machine.v[0x5] == 0x55);
    }
}

#[test]
fn test_2nnn(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        // start at 202 to not overwrite first instruction
        let nnn = rng.gen_range(0x202,0xFFF);
        let zn = ((nnn >> 8) | 0x20) as u8;
        let nn = (nnn & 0x0FF) as u8;

        let mut memory:[u8;0xE00] = [0;0xE00];
        // set call command
        memory[0] = zn;
        memory[1] = nn;

        // set jumped to command
        memory[nnn - 0x200] = 0x65;
        memory[nnn - 0x200 + 1] = 0x55;

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();

        // verify two cycles caused jumped to command to be executed
        assert!(machine.v[0x5] == 0x55);
        assert!(machine.sp == 1);
        assert!(machine.stack[0] == 0x200);
    }
}

#[test]
fn test_3xnn(){
    assert!(false);
}

#[test]
fn test_4xnn(){
    assert!(false);
}

#[test]
fn test_5xy0(){
    assert!(false);
}

#[test]
fn test_6xnn(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let n = rand::random::<u8>() & 0xFF;

        let memory = [
            0x60 | x, n,
        ];

    let mut machine = Chip8::default();
    machine.load_rom(&memory);
    machine.cycle();

    assert!(machine.v[x as usize] == n);
    }
}

#[test]
fn test_7xnn(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let xbase = rand::random::<u8>();
        let n = rand::random::<u8>();

        let memory = [
            0x60 | x, xbase,
            0x70 | x, n,
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();

        assert!(machine.v[x as usize] == xbase.wrapping_add(n));
    }
}

#[test]
fn test_8xy1(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let mut y = x;
        while y == x {y = rand::random::<u8>() & 0x0F;}
        let y = y;

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = rand::random::<u8>();

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x01 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        assert!(machine.v[x as usize] == xval | yval);
    }
}

#[test]
fn test_8xy2(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let mut y = x;
        while y == x {y = rand::random::<u8>() & 0x0F;}
        let y = y;

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = rand::random::<u8>();

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x02 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        assert!(machine.v[x as usize] == xval & yval);
    }
}

#[test]
fn test_8xy3(){
    for _ in 0..1000 {
        let x = rand::random::<u8>() & 0x0F;
        let mut y = x;
        while y == x {y = rand::random::<u8>() & 0x0F;}
        let y = y;

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = rand::random::<u8>();

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x03 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        assert!(machine.v[x as usize] == xval ^ yval);
    }
}

#[test]
fn test_8xy4(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        let x = rng.gen_range(0x0, 0x0F);
        let y = rng.gen_range(0x0, 0x0F);

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = if x != y {rand::random::<u8>()} else {xval};

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x04 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        let (sum, flag) = xval.overflowing_add(yval);
        assert!(machine.v[x as usize] == sum);
        assert!(machine.v[0xF] == if flag {1} else {0});
    }
}

#[test]
fn test_8xy5(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        let x = rng.gen_range(0x0, 0x0F);
        let y = rng.gen_range(0x0, 0x0F);

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = if x != y {rand::random::<u8>()} else {xval};

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x05 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        let (sum, flag) = xval.overflowing_sub(yval);
        assert!(machine.v[x as usize] == sum);
        assert!(machine.v[0xF] == if flag {0} else {1});
    }
}

#[test]
fn test_8xy6(){
    assert!(false);
}

#[test]
fn test_8xy7(){
    let mut rng = rand::thread_rng();
    for _ in 0..1000 {
        let x = rng.gen_range(0x0, 0x0F);
        let y = rng.gen_range(0x0, 0x0F);

        let xval:u8 = rand::random::<u8>();
        let yval:u8 = if x != y {rand::random::<u8>()} else {xval};

        let memory = [
            0x60 | x, xval,
            0x60 | y, yval,
            0x80 | x, 0x07 | (y << 0x4),
        ];

        let mut machine = Chip8::default();
        machine.load_rom(&memory);
        machine.cycle();
        machine.cycle();
        machine.cycle();

        let (sum, flag) = yval.overflowing_sub(xval);
        assert!(machine.v[x as usize] == sum);
        assert!(machine.v[0xF] == if flag {0} else {1});
    }
    assert!(false);
}

#[test]
fn test_8xye(){
    assert!(false);
}

#[test]
fn test_9xy0(){
    assert!(false);
}

#[test]
fn test_annn(){
    assert!(false);
}

#[test]
fn test_bnnn(){
    let mut rng = rand::thread_rng();

    let nnn:u16 = rng.gen_range(0x204, 0xF00);
    let val:u8 = rand::random::<u8>();

    let zn = ((nnn >> 0x8) | 0xB0) as u8;
    let nn = (nnn & 0x0FF) as u8;

    let mut memory:[u8;0xE00] = [0;0xE00];
    memory[0] = 0x60;
    memory[1] = val;
    memory[2] = zn;
    memory[3] = nn;

    memory[(nnn as usize) - 0x200 + (val as usize)] = 0x65;
    memory[(nnn as usize) - 0x200 + (val as usize) + 1] = 0x55;

    let mut machine = Chip8::default();
    machine.load_rom(&memory);
    machine.cycle();
    machine.cycle();
    machine.cycle();

    assert!(machine.v[5] == 0x55);
}

#[test]
fn test_cxnn(){
    assert!(false);
}

#[test]
fn test_dxyn(){
    assert!(false);
}

#[test]
fn test_ex9e(){

    let opt:u16  = 0xE09E;
    let xval = rand::random::<u16>() & 0x0F00;
    let key = xval >> 0x8;

    // set up machine
    let mut machine = Chip8::default();
    machine.key[key as usize] = true;
    assert!(false);
}

#[test]
fn test_exa1(){
    assert!(false);
}

#[test]
fn test_fx07(){
    assert!(false);
}

#[test]
fn test_fx0a(){
    assert!(false);
}

#[test]
fn test_fx15(){
    assert!(false);
}

#[test]
fn test_fx18(){
    assert!(false);
}

#[test]
fn test_fx1e(){
    assert!(false);
}

#[test]
fn test_fx29(){
    assert!(false);
}

#[test]
fn test_fx33(){
    assert!(false);
}

#[test]
fn test_fx55(){
    assert!(false);
}

#[test]
fn test_fx65(){
    assert!(false);
}*/
<|endoftext|>


<commit_before>extern crate base64;

use self::base64::encode;
use http::retrieve_asset;
use regex::Regex;
use std::collections::HashMap;
use url::{ParseError, Url};

lazy_static! {
    static ref HAS_PROTOCOL: Regex = Regex::new(r"^[a-z0-9]+:").unwrap();
    static ref REGEX_URL: Regex = Regex::new(r"^https?://").unwrap();
}

const MAGIC: [[&[u8]; 2]; 19] = [
    // Image
    [b"GIF87a", b"image/gif"],
    [b"GIF89a", b"image/gif"],
    [b"\xFF\xD8\xFF", b"image/jpeg"],
    [b"\x89PNG\x0D\x0A\x1A\x0A", b"image/png"],
    [b"<?xml ", b"image/svg+xml"],
    [b"<svg ", b"image/svg+xml"],
    [b"RIFF....WEBPVP8 ", b"image/webp"],
    [b"\x00\x00\x01\x00", b"image/x-icon"],
    // Audio
    [b"ID3", b"audio/mpeg"],
    [b"\xFF\x0E", b"audio/mpeg"],
    [b"\xFF\x0F", b"audio/mpeg"],
    [b"OggS", b"audio/ogg"],
    [b"RIFF....WAVEfmt ", b"audio/wav"],
    [b"fLaC", b"audio/x-flac"],
    // Video
    [b"RIFF....AVI LIST", b"video/avi"],
    [b"....ftyp", b"video/mp4"],
    [b"\x00\x00\x01\x0B", b"video/mpeg"],
    [b"....moov", b"video/quicktime"],
    [b"\x1A\x45\xDF\xA3", b"video/webm"],
];

pub fn data_to_dataurl(mime: &str, data: &[u8]) -> String {
    let mimetype = if mime.is_empty() {
        detect_mimetype(data)
    } else {
        mime.to_string()
    };
    format!("data:{};base64,{}", mimetype, encode(data))
}

pub fn detect_mimetype(data: &[u8]) -> String {
    for item in MAGIC.iter() {
        if data.starts_with(item[0]) {
            return String::from_utf8(item[1].to_vec()).unwrap();
        }
    }
    "".to_owned()
}

pub fn url_has_protocol<T: AsRef<str>>(url: T) -> bool {
    HAS_PROTOCOL.is_match(url.as_ref().to_lowercase().as_str())
}

pub fn is_data_url<T: AsRef<str>>(url: T) -> Result<bool, ParseError> {
    Url::parse(url.as_ref()).and_then(|u| Ok(u.scheme() == "data"))
}

pub fn is_valid_url<T: AsRef<str>>(path: T) -> bool {
    REGEX_URL.is_match(path.as_ref())
}

pub fn resolve_url<T: AsRef<str>, U: AsRef<str>>(from: T, to: U) -> Result<String, ParseError> {
    let result = if is_valid_url(to.as_ref()) {
        to.as_ref().to_string()
    } else {
        Url::parse(from.as_ref())?
            .join(to.as_ref())?
            .as_ref()
            .to_string()
    };
    Ok(result)
}

pub fn resolve_css_imports(
    cache: &mut HashMap<String, String>,
    css_string: &str,
    as_dataurl: bool,
    href: &str,
    opt_user_agent: &str,
    opt_silent: bool,
    opt_insecure: bool,
) -> String {
    let mut resolved_css = String::from(css_string);
    let re =
        Regex::new(r###"(?P<import>@import )?url\((?P<to_repl>"?(?P<url>[^"]+)"?)\)"###).unwrap();

    for link in re.captures_iter(&css_string) {
        let target_link = link.name("url").unwrap().as_str();

        // Generate absolute URL for content
        let embedded_url = match resolve_url(href, target_link) {
            Ok(url) => url,
            Err(_) => continue, // Malformed URL
        };

        // Download the asset.  If it's more CSS, resolve that too
        let content = match link.name("import") {
            // The link is an @import link
            Some(_) => retrieve_asset(
                cache,
                &embedded_url,
                false,      // Formating as data URL will be done later
                "text/css", // Expect CSS
                opt_user_agent,
                opt_silent,
                opt_insecure,
            )
            .map(|(content, _)| {
                resolve_css_imports(
                    cache,
                    &content,
                    true, //NOW, convert to data URL
                    &embedded_url,
                    opt_user_agent,
                    opt_silent,
                    opt_insecure,
                )
            }),

            // The link is some other, non-@import link
            None => retrieve_asset(
                cache,
                &embedded_url,
                true, // Format as data URL
                "",   // Unknown MIME type
                opt_user_agent,
                opt_silent,
                opt_insecure,
            )
            .map(|(a, _)| a),
        }
        .unwrap_or_else(|e| {
            eprintln!("Warning: {}", e,);

            //If failed to resolve, replace with absolute URL
            embedded_url
        });

        let replacement = format!("\"{}\"", &content);
        let dest = link.name("to_repl").unwrap();

        resolved_css.replace_range(dest.start()..dest.end(), &replacement);
    }

    if as_dataurl {
        data_to_dataurl("text/css", resolved_css.as_bytes())
    } else {
        resolved_css
    }
}
<commit_msg>Fixed css replacement with more than one linked asset<commit_after>extern crate base64;

use self::base64::encode;
use http::retrieve_asset;
use regex::Regex;
use std::collections::HashMap;
use url::{ParseError, Url};

lazy_static! {
    static ref HAS_PROTOCOL: Regex = Regex::new(r"^[a-z0-9]+:").unwrap();
    static ref REGEX_URL: Regex = Regex::new(r"^https?://").unwrap();
}

const MAGIC: [[&[u8]; 2]; 19] = [
    // Image
    [b"GIF87a", b"image/gif"],
    [b"GIF89a", b"image/gif"],
    [b"\xFF\xD8\xFF", b"image/jpeg"],
    [b"\x89PNG\x0D\x0A\x1A\x0A", b"image/png"],
    [b"<?xml ", b"image/svg+xml"],
    [b"<svg ", b"image/svg+xml"],
    [b"RIFF....WEBPVP8 ", b"image/webp"],
    [b"\x00\x00\x01\x00", b"image/x-icon"],
    // Audio
    [b"ID3", b"audio/mpeg"],
    [b"\xFF\x0E", b"audio/mpeg"],
    [b"\xFF\x0F", b"audio/mpeg"],
    [b"OggS", b"audio/ogg"],
    [b"RIFF....WAVEfmt ", b"audio/wav"],
    [b"fLaC", b"audio/x-flac"],
    // Video
    [b"RIFF....AVI LIST", b"video/avi"],
    [b"....ftyp", b"video/mp4"],
    [b"\x00\x00\x01\x0B", b"video/mpeg"],
    [b"....moov", b"video/quicktime"],
    [b"\x1A\x45\xDF\xA3", b"video/webm"],
];

pub fn data_to_dataurl(mime: &str, data: &[u8]) -> String {
    let mimetype = if mime.is_empty() {
        detect_mimetype(data)
    } else {
        mime.to_string()
    };
    format!("data:{};base64,{}", mimetype, encode(data))
}

pub fn detect_mimetype(data: &[u8]) -> String {
    for item in MAGIC.iter() {
        if data.starts_with(item[0]) {
            return String::from_utf8(item[1].to_vec()).unwrap();
        }
    }
    "".to_owned()
}

pub fn url_has_protocol<T: AsRef<str>>(url: T) -> bool {
    HAS_PROTOCOL.is_match(url.as_ref().to_lowercase().as_str())
}

pub fn is_data_url<T: AsRef<str>>(url: T) -> Result<bool, ParseError> {
    Url::parse(url.as_ref()).and_then(|u| Ok(u.scheme() == "data"))
}

pub fn is_valid_url<T: AsRef<str>>(path: T) -> bool {
    REGEX_URL.is_match(path.as_ref())
}

pub fn resolve_url<T: AsRef<str>, U: AsRef<str>>(from: T, to: U) -> Result<String, ParseError> {
    let result = if is_valid_url(to.as_ref()) {
        to.as_ref().to_string()
    } else {
        Url::parse(from.as_ref())?
            .join(to.as_ref())?
            .as_ref()
            .to_string()
    };
    Ok(result)
}

pub fn resolve_css_imports(
    cache: &mut HashMap<String, String>,
    css_string: &str,
    as_dataurl: bool,
    href: &str,
    opt_user_agent: &str,
    opt_silent: bool,
    opt_insecure: bool,
) -> String {
    let mut resolved_css = String::from(css_string);
    let re =
        Regex::new(r###"(?P<import>@import )?url\((?P<to_repl>"?(?P<url>[^"]+)"?)\)"###).unwrap();

    for link in re.captures_iter(&css_string) {
        let target_link = link.name("url").unwrap().as_str();

        // Generate absolute URL for content
        let embedded_url = match resolve_url(href, target_link) {
            Ok(url) => url,
            Err(_) => continue, // Malformed URL
        };

        // Download the asset.  If it's more CSS, resolve that too
        let content = match link.name("import") {
            // The link is an @import link
            Some(_) => retrieve_asset(
                cache,
                &embedded_url,
                false,      // Formating as data URL will be done later
                "text/css", // Expect CSS
                opt_user_agent,
                opt_silent,
                opt_insecure,
            )
            .map(|(content, _)| {
                resolve_css_imports(
                    cache,
                    &content,
                    true, //NOW, convert to data URL
                    &embedded_url,
                    opt_user_agent,
                    opt_silent,
                    opt_insecure,
                )
            }),

            // The link is some other, non-@import link
            None => retrieve_asset(
                cache,
                &embedded_url,
                true, // Format as data URL
                "",   // Unknown MIME type
                opt_user_agent,
                opt_silent,
                opt_insecure,
            )
            .map(|(a, _)| a),
        }
        .unwrap_or_else(|e| {
            eprintln!("Warning: {}", e,);

            //If failed to resolve, replace with absolute URL
            embedded_url
        });

        let replacement = format!("\"{}\"", &content);
        let dest = link.name("to_repl").unwrap();
        let offset = resolved_css.len() - css_string.len();
        let target_range = (dest.start() + offset)..(dest.end() + offset);

        resolved_css.replace_range(target_range, &replacement);
    }

    if as_dataurl {
        data_to_dataurl("text/css", resolved_css.as_bytes())
    } else {
        resolved_css
    }
}
<|endoftext|>


<commit_before>use std::path::Path;

pub fn is_song(path: &Path) -> bool {
	let extension = match path.extension() {
		Some(e) => e,
		_ => return false,
	};
	let extension = match extension.to_str() {
		Some(e) => e,
		_ => return false,
	};
	match extension {
		"mp3" => true,
		"ogg" => true,
		"m4a" => true,
		"flac" => true,
		_ => false,
	}
}

pub fn is_image(path: &Path) -> bool {
	let extension = match path.extension() {
		Some(e) => e,
		_ => return false,
	};
	let extension = match extension.to_str() {
		Some(e) => e,
		_ => return false,
	};
	match extension {
		"png" => true,
		"gif" => true,
		"jpg" => true,
		"bmp" => true,
		_ => false,
	}
}<commit_msg>Added jpeg to image extensions<commit_after>use std::path::Path;

pub fn is_song(path: &Path) -> bool {
	let extension = match path.extension() {
		Some(e) => e,
		_ => return false,
	};
	let extension = match extension.to_str() {
		Some(e) => e,
		_ => return false,
	};
	match extension {
		"mp3" => true,
		"ogg" => true,
		"m4a" => true,
		"flac" => true,
		_ => false,
	}
}

pub fn is_image(path: &Path) -> bool {
	let extension = match path.extension() {
		Some(e) => e,
		_ => return false,
	};
	let extension = match extension.to_str() {
		Some(e) => e,
		_ => return false,
	};
	match extension {
		"png" => true,
		"gif" => true,
		"jpg" => true,
		"jpeg" => true,
		"bmp" => true,
		_ => false,
	}
}<|endoftext|>


<commit_before>

/// The default target to pass to cargo, to workaround issue #11.
pub fn default_target() -> &'static str {
    current_platform::CURRENT_PLATFORM
}
<commit_msg>whitespace<commit_after>/// The default target to pass to cargo, to workaround issue #11.
pub fn default_target() -> &'static str {
    current_platform::CURRENT_PLATFORM
}
<|endoftext|>


<commit_before>
use std::rc::Rc;
use std::cell::RefCell;
use std::mem::replace;

pub const BCSIZE: usize = 4;
pub const BCSIZEP4: usize = BCSIZE+4;

pub mod bc{
  pub const HALT: u8 = 0;
  pub const INT:  u8 = 1;
  pub const NEG:  u8 = 2;
  pub const ADD:  u8 = 3;
  pub const SUB:  u8 = 4;
  pub const MPY:  u8 = 5;
  pub const DIV:  u8 = 6;
  pub const IDIV: u8 = 7;
  pub const LIST: u8 = 8;
}

pub struct List{
  v: Vec<Object>
}

impl List{
  pub fn new_object(v: Vec<Object>) -> Object{
    return Object::List(Rc::new(RefCell::new(List{v: v})));
  }
}

pub enum Object{
  Null, Bool(bool), Int(i32), Float(f64),
  List(Rc<RefCell<List>>)
}

fn list_to_string(a: &[Object]) -> String{
  let mut s = String::from("[");
  for i in 0..a.len() {
    if i!=0 {s.push_str(", ");}
    s.push_str(&object_to_string(&a[i]));
  }
  s.push_str("]");
  return s;
}

fn object_to_string(x: &Object) -> String{
  match x {
    &Object::Null => String::from("null"),
    &Object::Bool(b) => String::from(if b {"true"} else {"false"}),
    &Object::Int(i) => format!("{}",i),
    &Object::Float(f) => format!("{}",f),
    &Object::List(ref a) => {
      list_to_string(&a.borrow().v)
    }
  }
}

fn operator_plus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x+y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_minus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x-y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_mpy(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x*y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_div(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Float((x as f64)/(y as f64));
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_idiv(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x/y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_list(sp: usize, stack: &mut Vec<Object>, size: usize) -> usize{
  let mut sp = sp;
  let mut v: Vec<Object> = Vec::new();
  for i in 0..size {
    v.push(replace(&mut stack[sp-size+i],Object::Null));
  }
  sp-=size;
  stack[sp] = List::new_object(v);
  sp+=1;
  return sp;
}

fn compose_i32(b1: u8, b2: u8, b3: u8, b4: u8) -> i32{
  return (b4 as i32)<<24 | (b3 as i32)<<16 | (b2 as i32)<<8 | (b1 as i32);
}

pub fn eval(a: &[u8]){
  let mut ip=0;
  let mut stack: Vec<Object> = Vec::new();
  for _ in 0..100 {
    stack.push(Object::Null);
  }
  let mut sp=0;
  loop{
    match a[ip] {
      bc::INT => {
        ip+=BCSIZEP4;
        stack[sp] = Object::Int(compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]));
        sp+=1;
      },
      bc::ADD => {
        sp = operator_plus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::SUB => {
        sp = operator_minus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::MPY => {
        sp = operator_mpy(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::DIV => {
        sp = operator_div(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::IDIV => {
        sp = operator_idiv(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::LIST => {
        ip+=BCSIZEP4;
        let size = compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]) as usize;
        sp = operator_list(sp,&mut stack,size);
      },
      bc::HALT => {
        break;
      },
      _ => {panic!()}
    }
  }
  if sp>0 {
    println!("{}",object_to_string(&stack[sp-1]));
  }
}
<commit_msg>update<commit_after>
use std::rc::Rc;
use std::cell::RefCell;
use std::mem::replace;

pub const BCSIZE: usize = 4;
pub const BCSIZEP4: usize = BCSIZE+4;

pub mod bc{
  pub const HALT: u8 = 0;
  pub const INT:  u8 = 1;
  pub const NEG:  u8 = 2;
  pub const ADD:  u8 = 3;
  pub const SUB:  u8 = 4;
  pub const MPY:  u8 = 5;
  pub const DIV:  u8 = 6;
  pub const IDIV: u8 = 7;
  pub const LIST: u8 = 8;
}

pub struct List{
  v: Vec<Object>
}

impl List{
  pub fn new_object(v: Vec<Object>) -> Object{
    return Object::List(Rc::new(RefCell::new(List{v: v})));
  }
}

pub enum Object{
  Null, Bool(bool), Int(i32), Float(f64),
  List(Rc<RefCell<List>>)
}

fn list_to_string(a: &[Object]) -> String{
  let mut s = String::from("[");
  for i in 0..a.len() {
    if i!=0 {s.push_str(", ");}
    s.push_str(&object_to_string(&a[i]));
  }
  s.push_str("]");
  return s;
}

fn object_to_string(x: &Object) -> String{
  match x {
    &Object::Null => String::from("null"),
    &Object::Bool(b) => String::from(if b {"true"} else {"false"}),
    &Object::Int(i) => format!("{}",i),
    &Object::Float(f) => format!("{}",f),
    &Object::List(ref a) => {
      list_to_string(&a.borrow().v)
    }
  }
}

fn operator_plus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x+y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_minus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x-y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_mpy(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x*y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_div(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Float((x as f64)/(y as f64));
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_idiv(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x/y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_list(sp: usize, stack: &mut Vec<Object>, size: usize) -> usize{
  let mut sp = sp;
  let mut v: Vec<Object> = Vec::new();
  for i in 0..size {
    v.push(replace(&mut stack[sp-size+i],Object::Null));
  }
  sp-=size;
  stack[sp] = List::new_object(v);
  sp+=1;
  return sp;
}

fn compose_i32(b1: u8, b2: u8, b3: u8, b4: u8) -> i32{
  return (b4 as i32)<<24 | (b3 as i32)<<16 | (b2 as i32)<<8 | (b1 as i32);
}

fn compose_u32(b1: u8, b2: u8, b3: u8, b4: u8) -> u32{
  return (b4 as u32)<<24 | (b3 as u32)<<16 | (b2 as u32)<<8 | (b1 as u32);
}

pub fn eval(a: &[u8]){
  let mut ip=0;
  let mut stack: Vec<Object> = Vec::new();
  for _ in 0..100 {
    stack.push(Object::Null);
  }
  let mut sp=0;
  loop{
    match a[ip] {
      bc::INT => {
        ip+=BCSIZEP4;
        stack[sp] = Object::Int(compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]));
        sp+=1;
      },
      bc::ADD => {
        sp = operator_plus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::SUB => {
        sp = operator_minus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::MPY => {
        sp = operator_mpy(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::DIV => {
        sp = operator_div(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::IDIV => {
        sp = operator_idiv(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::LIST => {
        ip+=BCSIZEP4;
        let size = compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]) as usize;
        sp = operator_list(sp,&mut stack,size);
      },
      bc::HALT => {
        break;
      },
      _ => {panic!()}
    }
  }
  if sp>0 {
    println!("{}",object_to_string(&stack[sp-1]));
  }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate failure;
extern crate openssl;
extern crate rand;
extern crate xor;

use openssl::symm::{decrypt, encrypt};
use rand::Rng;
use xor::XOR;

pub const BLOCK_SIZE: usize = 16;

use failure::Error;

#[derive(Copy, Clone, Eq, PartialEq)]
pub enum MODE {
    ECB,
    CBC,
    CTR,
}

#[derive(Debug, Fail)]
pub enum AesError {
    #[fail(display = "invalid padding")]
    InvalidPadding,

    #[fail(display = "failed to encrypt block {:?}", block)]
    EncryptionFailed { block: Vec<u8> },

    #[fail(display = "failed to decrypt block {:?}", block)]
    DecryptionFailed { block: Vec<u8> },
}

pub fn pad_inplace(u: &mut Vec<u8>, k: u8) -> Result<(), Error> {
    ensure!(k >= 2, "invalid parameter");

    let p = k - (u.len() % k as usize) as u8;
    for _ in 0..p {
        u.push(p);
    }
    Ok(())
}

pub fn unpad_inplace(u: &mut Vec<u8>, k: u8) -> Result<(), Error> {
    if !padding_valid(u, k)? {
        return Err(AesError::InvalidPadding.into());
    }

    let len_new = u.len() - u[u.len() - 1] as usize;
    u.truncate(len_new);
    Ok(())
}

fn padding_valid(u: &[u8], k: u8) -> Result<bool, Error> {
    ensure!(k >= 2, "invalid parameter");

    if u.is_empty() || u.len() % k as usize != 0 {
        return Ok(false);
    }

    let padding = u[u.len() - 1];
    if !(1 <= padding && padding <= k) {
        return Ok(false);
    }

    Ok(u[u.len() - padding as usize..]
        .iter()
        .all(|&b| b == padding))
}

pub trait Aes128 {
    fn pad(&self) -> Vec<u8>;
    fn padding_valid(&self) -> bool;
    fn encrypt(&self, key: &Self, iv: Option<&Self>, mode: MODE) -> Result<Vec<u8>, Error>;
    fn decrypt(&self, key: &Self, iv: Option<&Self>, mode: MODE) -> Result<Vec<u8>, Error>;
}

impl Aes128 for [u8] {
    fn pad(&self) -> Vec<u8> {
        let mut v = self.to_vec();
        pad_inplace(&mut v, BLOCK_SIZE as u8).unwrap(); // unwrap is ok
        v
    }

    fn padding_valid(&self) -> bool {
        padding_valid(self, BLOCK_SIZE as u8).unwrap()
    }

    fn encrypt(&self, key: &Self, iv: Option<&Self>, mode: MODE) -> Result<Vec<u8>, Error> {
        match mode {
            MODE::ECB => {
                ensure!(iv.is_none(), "iv not supported for ECB mode");
                encrypt_aes128_ecb(&self, key)
            }

            MODE::CBC => {
                ensure!(iv.is_some(), "iv required for CBC mode");
                encrypt_aes128_cbc(&self, key, iv.unwrap())
            }

            MODE::CTR => {
                ensure!(iv.is_none(), "iv not supported for CTR mode");
                aes128_ctr(&self, key)
            }
        }
    }

    fn decrypt(&self, key: &Self, iv: Option<&Self>, mode: MODE) -> Result<Vec<u8>, Error> {
        match mode {
            MODE::ECB => {
                ensure!(iv.is_none(), "iv not supported for ECB mode");
                decrypt_aes128_ecb(&self, key)
            }

            MODE::CBC => {
                ensure!(iv.is_some(), "iv required for CBC mode");
                decrypt_aes128_cbc(&self, key, iv.unwrap())
            }

            MODE::CTR => {
                ensure!(iv.is_none(), "iv not supported for CTR mode");
                aes128_ctr(&self, key)
            }
        }
    }
}

fn encrypt_aes128_block(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    ensure!(
        input.len() == BLOCK_SIZE,
        format!("input does not consist of {} bytes", BLOCK_SIZE)
    );

    // The OpenSSL call pads the cleartext before encrypting.
    let mut ciphertext =
        encrypt(openssl::symm::Cipher::aes_128_ecb(), key, None, input).map_err(|_| {
            AesError::EncryptionFailed {
                block: input.to_vec(),
            }
        })?;

    ciphertext.truncate(BLOCK_SIZE);
    Ok(ciphertext)
}

fn decrypt_aes128_block(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    ensure!(
        input.len() == BLOCK_SIZE,
        format!("input does not consist of {} bytes", BLOCK_SIZE)
    );

    // The OpenSSL call expects a padded cleartext.
    let padding = encrypt_aes128_block(&[BLOCK_SIZE as u8; BLOCK_SIZE], key)?;
    let mut u = input.to_vec();
    u.extend_from_slice(&padding);
    decrypt(openssl::symm::Cipher::aes_128_ecb(), key, None, &u).map_err(|_| {
        AesError::DecryptionFailed {
            block: input.to_vec(),
        }.into()
    })
}

fn encrypt_aes128_ecb(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    let u = input.pad();
    let mut ciphertext = Vec::new();
    for block in u.chunks(BLOCK_SIZE) {
        ciphertext.extend_from_slice(&encrypt_aes128_block(block, key)?);
    }
    Ok(ciphertext)
}

fn decrypt_aes128_ecb(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    if input.len() % BLOCK_SIZE != 0 {
        bail!(format!("input length not a multiple of {}", BLOCK_SIZE));
    }

    let mut cleartext = Vec::new();
    for block in input.chunks(BLOCK_SIZE) {
        cleartext.extend_from_slice(&decrypt_aes128_block(block, key)?);
    }
    unpad_inplace(&mut cleartext, BLOCK_SIZE as u8)?;
    Ok(cleartext)
}

fn encrypt_aes128_cbc(input: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>, Error> {
    let u = input.pad();
    let mut ciphertext = Vec::new();
    let mut cur = iv.to_vec();
    for block in u.chunks(BLOCK_SIZE) {
        cur = encrypt_aes128_block(&block.xor(&cur), key)?;
        ciphertext.extend_from_slice(&cur);
    }
    Ok(ciphertext)
}

fn decrypt_aes128_cbc_blocks(input: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>, Error> {
    if input.len() % BLOCK_SIZE != 0 {
        bail!(format!("input length not a multiple of {}", BLOCK_SIZE));
    }

    let mut cleartext = Vec::new();
    let mut prev = iv;
    for block in input.chunks(BLOCK_SIZE) {
        let cur = decrypt_aes128_block(block, key)?.xor(prev);
        cleartext.extend_from_slice(&cur);
        prev = block;
    }
    Ok(cleartext)
}

fn decrypt_aes128_cbc(input: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>, Error> {
    let mut cleartext = decrypt_aes128_cbc_blocks(input, key, iv)?;
    unpad_inplace(&mut cleartext, BLOCK_SIZE as u8)?;
    Ok(cleartext)
}

fn aes128_ctr(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    let mut ciphertext = Vec::new();
    let mut keystream = vec![0; BLOCK_SIZE];
    for b in input.chunks(BLOCK_SIZE) {
        ciphertext.extend_from_slice(&b.xor(&encrypt_aes128_ecb(&keystream, key)?));
        increment_counter(&mut keystream[BLOCK_SIZE / 2..]);
    }
    Ok(ciphertext)
}

fn increment_counter(v: &mut [u8]) {
    for b in v.iter_mut() {
        *b += 1;
        if *b != 0 {
            break;
        }
    }
}

pub fn random_block() -> Vec<u8> {
    let mut rng = rand::thread_rng();
    rng.gen_iter().take(BLOCK_SIZE).collect()
}

// Returns a pair (chunks_count, fill_len), where chunks_count is the number of
// chunks resulting from dividing a message of length len into chunks of size
// BLOCK_SIZE. This count explicitly includes the last chunk, which may
// be shorter than BLOCK_SIZE. The number fill_len is the difference between
// chunks_count * BLOCK_SIZE and len.
pub fn chunks_count(len: usize) -> (usize, usize) {
    let q = (len + BLOCK_SIZE - 1) / BLOCK_SIZE;
    let r = q * BLOCK_SIZE - len;
    (q, r)
}

#[test]
fn aes_128_cbc() {
    let iv = [0; BLOCK_SIZE];
    let key = b"YELLOW SUBMARINE";
    let input = b"ABCDEFGHIJKLMNOP";
    assert_eq!(
        input.as_ref(),
        &input
            .encrypt(key, Some(&iv), MODE::CBC)
            .unwrap()
            .decrypt(key, Some(&iv), MODE::CBC)
            .unwrap()[..]
    );
}

#[test]
fn test_padding_valid() {
    assert!(padding_valid("ICE ICE BABY\x04\x04\x04\x04".as_bytes(), 16).unwrap() == true);
    assert!(padding_valid("ICE ICE BABY\x05\x05\x05\x05".as_bytes(), 16).unwrap() == false);
    assert!(padding_valid("ICE ICE BABY\x03\x03\x03".as_bytes(), 16).unwrap() == false);
    assert!(padding_valid("ICE ICE BABY\x01\x02\x03\x04".as_bytes(), 16).unwrap() == false);
    assert!(
        padding_valid(
            "ICE ICE BABY\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C".as_bytes(),
            12
        ).unwrap()
            == true
    );
}
<commit_msg>Validate length of iv<commit_after>#[macro_use]
extern crate failure;
extern crate openssl;
extern crate rand;
extern crate xor;

use openssl::symm::{decrypt, encrypt};
use rand::Rng;
use xor::XOR;

pub const BLOCK_SIZE: usize = 16;

use failure::Error;

#[derive(Copy, Clone, Eq, PartialEq)]
pub enum MODE {
    ECB,
    CBC,
    CTR,
}

#[derive(Debug, Fail)]
pub enum AesError {
    #[fail(display = "invalid padding")]
    InvalidPadding,

    #[fail(display = "failed to encrypt block {:?}", block)]
    EncryptionFailed { block: Vec<u8> },

    #[fail(display = "failed to decrypt block {:?}", block)]
    DecryptionFailed { block: Vec<u8> },
}

pub fn pad_inplace(u: &mut Vec<u8>, k: u8) -> Result<(), Error> {
    ensure!(k >= 2, "invalid parameter");

    let p = k - (u.len() % k as usize) as u8;
    for _ in 0..p {
        u.push(p);
    }
    Ok(())
}

pub fn unpad_inplace(u: &mut Vec<u8>, k: u8) -> Result<(), Error> {
    if !padding_valid(u, k)? {
        return Err(AesError::InvalidPadding.into());
    }

    let len_new = u.len() - u[u.len() - 1] as usize;
    u.truncate(len_new);
    Ok(())
}

fn padding_valid(u: &[u8], k: u8) -> Result<bool, Error> {
    ensure!(k >= 2, "invalid parameter");

    if u.is_empty() || u.len() % k as usize != 0 {
        return Ok(false);
    }

    let padding = u[u.len() - 1];
    if !(1 <= padding && padding <= k) {
        return Ok(false);
    }

    Ok(u[u.len() - padding as usize..]
        .iter()
        .all(|&b| b == padding))
}

pub trait Aes128 {
    fn pad(&self) -> Vec<u8>;
    fn padding_valid(&self) -> bool;
    fn encrypt(&self, key: &Self, iv: Option<&Self>, mode: MODE) -> Result<Vec<u8>, Error>;
    fn decrypt(&self, key: &Self, iv: Option<&Self>, mode: MODE) -> Result<Vec<u8>, Error>;
}

impl Aes128 for [u8] {
    fn pad(&self) -> Vec<u8> {
        let mut v = self.to_vec();
        pad_inplace(&mut v, BLOCK_SIZE as u8).unwrap(); // unwrap is ok
        v
    }

    fn padding_valid(&self) -> bool {
        padding_valid(self, BLOCK_SIZE as u8).unwrap()
    }

    fn encrypt(&self, key: &Self, iv: Option<&Self>, mode: MODE) -> Result<Vec<u8>, Error> {
        match mode {
            MODE::ECB => {
                ensure!(iv.is_none(), "iv not supported for ECB mode");
                encrypt_aes128_ecb(&self, key)
            }

            MODE::CBC => {
                ensure!(iv.is_some(), "iv required for CBC mode");
                encrypt_aes128_cbc(&self, key, iv.unwrap())
            }

            MODE::CTR => {
                ensure!(iv.is_none(), "iv not supported for CTR mode");
                aes128_ctr(&self, key)
            }
        }
    }

    fn decrypt(&self, key: &Self, iv: Option<&Self>, mode: MODE) -> Result<Vec<u8>, Error> {
        match mode {
            MODE::ECB => {
                ensure!(iv.is_none(), "iv not supported for ECB mode");
                decrypt_aes128_ecb(&self, key)
            }

            MODE::CBC => {
                ensure!(iv.is_some(), "iv required for CBC mode");
                decrypt_aes128_cbc(&self, key, iv.unwrap())
            }

            MODE::CTR => {
                ensure!(iv.is_none(), "iv not supported for CTR mode");
                aes128_ctr(&self, key)
            }
        }
    }
}

fn encrypt_aes128_block(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    ensure!(
        input.len() == BLOCK_SIZE,
        format!("input does not consist of {} bytes", BLOCK_SIZE)
    );

    // The OpenSSL call pads the cleartext before encrypting.
    let mut ciphertext =
        encrypt(openssl::symm::Cipher::aes_128_ecb(), key, None, input).map_err(|_| {
            AesError::EncryptionFailed {
                block: input.to_vec(),
            }
        })?;

    ciphertext.truncate(BLOCK_SIZE);
    Ok(ciphertext)
}

fn decrypt_aes128_block(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    ensure!(
        input.len() == BLOCK_SIZE,
        format!("input does not consist of {} bytes", BLOCK_SIZE)
    );

    // The OpenSSL call expects a padded cleartext.
    let padding = encrypt_aes128_block(&[BLOCK_SIZE as u8; BLOCK_SIZE], key)?;
    let mut u = input.to_vec();
    u.extend_from_slice(&padding);
    decrypt(openssl::symm::Cipher::aes_128_ecb(), key, None, &u).map_err(|_| {
        AesError::DecryptionFailed {
            block: input.to_vec(),
        }.into()
    })
}

fn encrypt_aes128_ecb(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    let u = input.pad();
    let mut ciphertext = Vec::new();
    for block in u.chunks(BLOCK_SIZE) {
        ciphertext.extend_from_slice(&encrypt_aes128_block(block, key)?);
    }
    Ok(ciphertext)
}

fn decrypt_aes128_ecb(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    ensure!(input.len() % BLOCK_SIZE == 0, format!("input length not a multiple of {}", BLOCK_SIZE));

    let mut cleartext = Vec::new();
    for block in input.chunks(BLOCK_SIZE) {
        cleartext.extend_from_slice(&decrypt_aes128_block(block, key)?);
    }
    unpad_inplace(&mut cleartext, BLOCK_SIZE as u8)?;
    Ok(cleartext)
}

fn encrypt_aes128_cbc(input: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>, Error> {
    ensure!(iv.len() == BLOCK_SIZE, format!("iv length not equal to {}", BLOCK_SIZE));

    let u = input.pad();
    let mut ciphertext = Vec::new();
    let mut previous = iv.to_vec();
    for block in u.chunks(BLOCK_SIZE) {
        let current = encrypt_aes128_block(&block.xor(&previous), key)?;
        ciphertext.extend_from_slice(&current);
        previous = current;
    }
    Ok(ciphertext)
}

fn decrypt_aes128_cbc(input: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>, Error> {
    ensure!(input.len() % BLOCK_SIZE == 0, format!("input length not a multiple of {}", BLOCK_SIZE));
    ensure!(iv.len() == BLOCK_SIZE, format!("iv length not equal to {}", BLOCK_SIZE));

    let mut cleartext = Vec::new();
    let mut previous = iv;
    for block in input.chunks(BLOCK_SIZE) {
        cleartext.extend_from_slice(&decrypt_aes128_block(block, key)?.xor(previous));
        previous = block;
    }
    unpad_inplace(&mut cleartext, BLOCK_SIZE as u8)?;
    Ok(cleartext)
}

fn aes128_ctr(input: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    let mut ciphertext = Vec::new();
    let mut keystream = vec![0; BLOCK_SIZE];
    for b in input.chunks(BLOCK_SIZE) {
        ciphertext.extend_from_slice(&b.xor(&encrypt_aes128_ecb(&keystream, key)?));
        increment_counter(&mut keystream[BLOCK_SIZE / 2..]);
    }
    Ok(ciphertext)
}

fn increment_counter(v: &mut [u8]) {
    for b in v.iter_mut() {
        *b += 1;
        if *b != 0 {
            break;
        }
    }
}

pub fn random_block() -> Vec<u8> {
    let mut rng = rand::thread_rng();
    rng.gen_iter().take(BLOCK_SIZE).collect()
}

// Returns a pair (chunks_count, fill_len), where chunks_count is the number of
// chunks resulting from dividing a message of length len into chunks of size
// BLOCK_SIZE. This count explicitly includes the last chunk, which may
// be shorter than BLOCK_SIZE. The number fill_len is the difference between
// chunks_count * BLOCK_SIZE and len.
pub fn chunks_count(len: usize) -> (usize, usize) {
    let q = (len + BLOCK_SIZE - 1) / BLOCK_SIZE;
    let r = q * BLOCK_SIZE - len;
    (q, r)
}

#[test]
fn aes_128_cbc() {
    let iv = [0; BLOCK_SIZE];
    let key = b"YELLOW SUBMARINE";
    let input = b"ABCDEFGHIJKLMNOP";
    assert_eq!(
        input.as_ref(),
        &input
            .encrypt(key, Some(&iv), MODE::CBC)
            .unwrap()
            .decrypt(key, Some(&iv), MODE::CBC)
            .unwrap()[..]
    );
}

#[test]
fn test_padding_valid() {
    assert!(padding_valid("ICE ICE BABY\x04\x04\x04\x04".as_bytes(), 16).unwrap() == true);
    assert!(padding_valid("ICE ICE BABY\x05\x05\x05\x05".as_bytes(), 16).unwrap() == false);
    assert!(padding_valid("ICE ICE BABY\x03\x03\x03".as_bytes(), 16).unwrap() == false);
    assert!(padding_valid("ICE ICE BABY\x01\x02\x03\x04".as_bytes(), 16).unwrap() == false);
    assert!(
        padding_valid(
            "ICE ICE BABY\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C".as_bytes(),
            12
        ).unwrap()
            == true
    );
}
<|endoftext|>


<commit_before>// Copyright (C) 2020, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use quiche_apps::args::*;

use quiche_apps::common::*;

use quiche_apps::client::*;

fn main() {
    env_logger::builder()
        .default_format_timestamp_nanos(true)
        .init();

    // Parse CLI parameters.
    let docopt = docopt::Docopt::new(CLIENT_USAGE).unwrap();
    let conn_args = CommonArgs::with_docopt(&docopt);
    let args = ClientArgs::with_docopt(&docopt);

    match connect(args, conn_args, stdout_sink) {
        Err(ClientError::HandshakeFail) => std::process::exit(-1),
        Err(ClientError::HttpFail) => std::process::exit(-2),
        Err(ClientError::Other(e)) => panic!(e),
        Ok(_) => (),
    }
}
<commit_msg>apps: fix non_fmt_panic warning<commit_after>// Copyright (C) 2020, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use quiche_apps::args::*;

use quiche_apps::common::*;

use quiche_apps::client::*;

fn main() {
    env_logger::builder()
        .default_format_timestamp_nanos(true)
        .init();

    // Parse CLI parameters.
    let docopt = docopt::Docopt::new(CLIENT_USAGE).unwrap();
    let conn_args = CommonArgs::with_docopt(&docopt);
    let args = ClientArgs::with_docopt(&docopt);

    match connect(args, conn_args, stdout_sink) {
        Err(ClientError::HandshakeFail) => std::process::exit(-1),

        Err(ClientError::HttpFail) => std::process::exit(-2),

        Err(ClientError::Other(e)) => panic!("{}", e),

        Ok(_) => (),
    }
}
<|endoftext|>


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

/// Invocations of this macro instruct Rerast to replace the first expression/statement with the one
/// after the =>. For example replace!(5 => 6) says to replace all occurences of the literal 5 with
/// the literal 6.
///
/// The macro should be invoked inside a function definition. The arguments to the function
/// represent placeholders within the search and replace expressions.
#[macro_export]
macro_rules! replace {
    ($a:expr => $b:expr) => {
        // Suppress warnings about unused values in case we're replacing something like a Result.
        #[allow(unused_must_use)]
        // If we have a search or replacement pattern that is just a placeholder then this macro
        // will turn that into a statement. Normally a reference to a variable is not permitted as a
        // statement, allow it.
        #[allow(path_statements)]
        #[allow(unreachable_code)]
        {
            if false {
                use $crate::GetMode;
                match $crate::_ExprRuleMarker.get_mode() {
                    $crate::Mode::Search => {&$a;}
                    $crate::Mode::Replace => {&$b;}
                }
                // Some of the placeholders used in this replace! invocation might have been
                // moved. To avoid use-after-move errors, we mark this as unreachable.
                unreachable!();
            }
        }
    };
}

/// Replaces one type with another. This will not match trait bounds (e.g. in where clauses), since
/// they are not types. If you want to replace all references to a trait, use `replace_trait_ref!`
/// instead.
#[macro_export]
macro_rules! replace_type {
    ($a:ty => $b:ty) => {
        {
            use $crate::GetMode;
            match $crate::_TypeRuleMarker.get_mode() {
                $crate::Mode::Search => {
                    let _t: &$a;
                }
                $crate::Mode::Replace => {
                    let _t: &$b;
                }
            }
        }
    };
}

#[macro_export]
macro_rules! replace_trait_ref {
    ($a:ty => $b:ty) => {
        {
            use $crate::GetMode;
            match $crate::_TraitRefRuleMarker.get_mode() {
                $crate::Mode::Search => {
                    let _t: &$a;
                }
                $crate::Mode::Replace => {
                    let _t: &$b;
                }
            }
        }
    };
}

/// Replaces a pattern with another pattern. A placeholder is required in order to specify the types
/// of the search and replacement pattern. Although they can be the same if you're replacing a
/// pattern with another of the same type.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate rerast;
/// # struct Foo(i32);
/// fn some_foo_to_result_foo(p1: Option<Foo>, p2: Result<Foo, ()>) {
///     replace_pattern!(Some(f1) = p1 => Result::Ok(f1) = p2);
///     replace_pattern!(None = p1 => Result::Err(()) = p2);
/// }
/// # fn main () {}
/// ```
///
/// This will transform:
///
/// ```
/// # #[derive(Copy, Clone)] struct Foo(i32);
/// # fn f() -> Option<Foo> {Some(Foo(42))}
/// match f() {
///     Some(Foo(x)) => x,
///     None => 0,
/// }
/// ```
///
/// Into:
///
/// ```
/// # fn f() -> Foo {Foo(42)}
/// match f() {
///     Result::Ok(Foo(x)) => x,
///     Result::Err(()) => 0,
/// }
/// ```
#[macro_export]
macro_rules! replace_pattern {
    ($a:pat = $at:ident => $b:pat = $bt:ident) => {
        if false {
            use $crate::GetMode;
            match $crate::_PatternRuleMarker.get_mode() {
                $crate::Mode::Search => {
                    if let Some($a) = Some($at) {};
                }
                $crate::Mode::Replace => {
                    if let Some($b) = Some($bt) {};
                }
            }
            // Some of the placeholders used in this replace_pattern! invocation might have been
            // moved. To avoid use-after-move errors, we mark this as unreachable.
            unreachable!();
        }
    }
}

/// A placeholder that matches zero or more statements
/// IMPORTANT: This is currently broken and will most likely be replaced with a macro.
pub type Statements = &'static Fn() -> _Statements;

// These types are internal markers to help rerast find and identify things in rules. They're not
// intended to be referenced directly.
pub enum Mode {
    Search,
    Replace,
}
pub struct _Statements;
pub trait GetMode {
    fn get_mode(&self) -> Mode {
        Mode::Search
    }
}
pub struct _TypeRuleMarker;
impl GetMode for _TypeRuleMarker {}
pub struct _ExprRuleMarker;
impl GetMode for _ExprRuleMarker {}
pub struct _PatternRuleMarker;
impl GetMode for _PatternRuleMarker {}
pub struct _TraitRefRuleMarker;
impl GetMode for _TraitRefRuleMarker {}

pub const _RERAST_MACROS_SRC: &'static str = include_str!("lib.rs");
<commit_msg>Override deny(missing_docs) to isolate rerast's macro code from crates' settings<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// global `#[deny()]` in the processed crate affects this file as well,
// and could cause compilation-breaking warnings.
#![allow(missing_docs, warnings)]

/// Invocations of this macro instruct Rerast to replace the first expression/statement with the one
/// after the =>. For example replace!(5 => 6) says to replace all occurences of the literal 5 with
/// the literal 6.
///
/// The macro should be invoked inside a function definition. The arguments to the function
/// represent placeholders within the search and replace expressions.
#[macro_export]
macro_rules! replace {
    ($a:expr => $b:expr) => {
        // Suppress warnings about unused values in case we're replacing something like a Result.
        #[allow(unused_must_use)]
        // If we have a search or replacement pattern that is just a placeholder then this macro
        // will turn that into a statement. Normally a reference to a variable is not permitted as a
        // statement, allow it.
        #[allow(path_statements)]
        #[allow(unreachable_code)]
        {
            if false {
                use $crate::GetMode;
                match $crate::_ExprRuleMarker.get_mode() {
                    $crate::Mode::Search => {&$a;}
                    $crate::Mode::Replace => {&$b;}
                }
                // Some of the placeholders used in this replace! invocation might have been
                // moved. To avoid use-after-move errors, we mark this as unreachable.
                unreachable!();
            }
        }
    };
}

/// Replaces one type with another. This will not match trait bounds (e.g. in where clauses), since
/// they are not types. If you want to replace all references to a trait, use `replace_trait_ref!`
/// instead.
#[macro_export]
macro_rules! replace_type {
    ($a:ty => $b:ty) => {
        {
            use $crate::GetMode;
            match $crate::_TypeRuleMarker.get_mode() {
                $crate::Mode::Search => {
                    let _t: &$a;
                }
                $crate::Mode::Replace => {
                    let _t: &$b;
                }
            }
        }
    };
}

#[macro_export]
macro_rules! replace_trait_ref {
    ($a:ty => $b:ty) => {
        {
            use $crate::GetMode;
            match $crate::_TraitRefRuleMarker.get_mode() {
                $crate::Mode::Search => {
                    let _t: &$a;
                }
                $crate::Mode::Replace => {
                    let _t: &$b;
                }
            }
        }
    };
}

/// Replaces a pattern with another pattern. A placeholder is required in order to specify the types
/// of the search and replacement pattern. Although they can be the same if you're replacing a
/// pattern with another of the same type.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate rerast;
/// # struct Foo(i32);
/// fn some_foo_to_result_foo(p1: Option<Foo>, p2: Result<Foo, ()>) {
///     replace_pattern!(Some(f1) = p1 => Result::Ok(f1) = p2);
///     replace_pattern!(None = p1 => Result::Err(()) = p2);
/// }
/// # fn main () {}
/// ```
///
/// This will transform:
///
/// ```
/// # #[derive(Copy, Clone)] struct Foo(i32);
/// # fn f() -> Option<Foo> {Some(Foo(42))}
/// match f() {
///     Some(Foo(x)) => x,
///     None => 0,
/// }
/// ```
///
/// Into:
///
/// ```
/// # fn f() -> Foo {Foo(42)}
/// match f() {
///     Result::Ok(Foo(x)) => x,
///     Result::Err(()) => 0,
/// }
/// ```
#[macro_export]
macro_rules! replace_pattern {
    ($a:pat = $at:ident => $b:pat = $bt:ident) => {
        if false {
            use $crate::GetMode;
            match $crate::_PatternRuleMarker.get_mode() {
                $crate::Mode::Search => {
                    if let Some($a) = Some($at) {};
                }
                $crate::Mode::Replace => {
                    if let Some($b) = Some($bt) {};
                }
            }
            // Some of the placeholders used in this replace_pattern! invocation might have been
            // moved. To avoid use-after-move errors, we mark this as unreachable.
            unreachable!();
        }
    }
}

/// A placeholder that matches zero or more statements
/// IMPORTANT: This is currently broken and will most likely be replaced with a macro.
pub type Statements = &'static Fn() -> _Statements;

// These types are internal markers to help rerast find and identify things in rules. They're not
// intended to be referenced directly.
pub enum Mode {
    Search,
    Replace,
}
pub struct _Statements;
pub trait GetMode {
    fn get_mode(&self) -> Mode {
        Mode::Search
    }
}
pub struct _TypeRuleMarker;
impl GetMode for _TypeRuleMarker {}
pub struct _ExprRuleMarker;
impl GetMode for _ExprRuleMarker {}
pub struct _PatternRuleMarker;
impl GetMode for _PatternRuleMarker {}
pub struct _TraitRefRuleMarker;
impl GetMode for _TraitRefRuleMarker {}

pub const _RERAST_MACROS_SRC: &'static str = include_str!("lib.rs");
<|endoftext|>