<commit_before>//NOTE: apparently, when looking up statics by ID, they're offset by 0x4000.
export map_tile;
export load_tiles;
export to_bitmap;
export parse_map_tile;

type map_tile = {
    header: u32,
    image: ~[u16] //TODO: Consider making Pixel a type
};

type static_tile = {
    header: u32,
    width: u16,
    height: u16,
    rows: ~[~[run]]
};

type run = {
    offset: u16,
    length: u16,
    data: ~[u8]
};

const transparent: u16 = 0b1000000000000000;
const expected_tile_size: uint = 2048;

fn load_tiles(root_path: ~str) -> (~[map_tile], ~[static_tile]) { //TODO: Find a better return type for this
    let reader:mul_reader::mul_reader = mul_reader::mul_reader(root_path, ~"artidx.mul", ~"art.mul");

    let mut map_tiles: ~[map_tile] = ~[];
    let mut static_tiles: ~[static_tile] = ~[];

    while (reader.eof() != true) {
        let item: option::option<mul_reader::mul_record> = reader.read();
        if option::is_some(item) {
            let unwrapped: mul_reader::mul_record = option::get(item);
            let record_header = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 0, 3));
            //Apparently, these flag values represent whether something is a tile or not
            //Others are not convinced, and think that index is all that matters
            //TODO: provide a check against incorrect lengths, as this causes problems

            if (vec::len(unwrapped.data) == expected_tile_size &&  (record_header > 0xFFFF || record_header == 0)) {
                vec::push(map_tiles, parse_map_tile(unwrapped));
            } else {
            }
        }
    }

    ret (map_tiles, static_tiles);
}

fn parse_map_tile(record: mul_reader::mul_record) -> map_tile {

    let record_header = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 3));
    let mut image: ~[u16] = ~[];
    let data_slice: ~[u8] = vec::slice(record.data, 4, vec::len(record.data));

    let mut data_pointer: uint = 0;
    for uint::range(0, 44) |i| {

        let slice: uint = if (i >= 22) {(44 - i) * 2} else {(i + 1) * 2};
        vec::grow(image, (22 - (slice / 2)), transparent);
        //vec::grow(image, slice, byte_helpers::u8vec_to_u16vec(~[0b00000000, 0b01111100])[0]);
        //io::println(#fmt("%u", vec::len(slice_data)));
        /*let mut slice_data: ~[u8] = ~[];
        for uint::range(0, slice) |j| {
            vec::push(slice_data, 0b01111100);
            vec::push(slice_data, 0b00000000);
        };*/

        let slice_data: ~[u8] = vec::slice(data_slice, data_pointer, data_pointer + (slice * 2));
        vec::push_all(image, byte_helpers::u8vec_to_u16vec(slice_data));
        vec::grow(image, (22 - (slice / 2)), transparent);
        data_pointer += (slice * 2);
    };

    ret {
        header: record_header as u32,
        image: image
    };
}
/*fn parse_static_tile(record: mul_reader::mul_record) -> static_tile {
    let record_header: u32 = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 0, 3)) as u32;
    let width: u16 = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 4, 5)) as u16;
    let height: u16 = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 6, 7)) as u16;

    let mut rows: ~[ mut ~[run]] = ~[mut];

    for uint::range(0, height) |i| {
        //Ze plan - read a row, starting from position 8, all the way to height
        let offset: u16 = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 8 + (2 * i), 9 + (2 * i)), 2) as u16;

    }
}*/

fn to_bitmap(width: u32, height: u32, data: ~[u16]) -> ~[u8] { //TODO: Make this take arbitrary pixel depths
    let signature: ~[u8] = ~[0x42, 0x4D];
    let file_size: ~[u8] = byte_helpers::uint_to_le_bytes(((width * height * 2) + 14 + 40) as u64, 4);
    let reserved: ~[u8] = ~[0, 0, 0, 0];
    let data_offset: ~[u8] = byte_helpers::uint_to_le_bytes(54, 4);

    let header_size: ~[u8] = byte_helpers::uint_to_le_bytes(40, 4);
    let width_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(width as u64, 4); //FIXME: should be signed?
    let height_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(height as u64, 4);
    let colour_panes: ~[u8] = ~[1, 0];
    let depth: ~[u8] = ~[16, 0];
    let compression: ~[u8] = ~[0,0,0,0];
    let image_size: ~[u8] = ~[0,0,0,0];
    let horizontal_res: ~[u8] = ~[0, 0, 0, 0];
    let vertical_res: ~[u8] = ~[0, 0, 0, 0];
    let palette_count: ~[u8] = ~[0, 0, 0, 0];
    let important_colours: ~[u8] = ~[0, 0, 0, 0];

    //54 bytes so far
    //TODO: explode the image vector, iterate backwards, turn it into bytes
    let mut rows: ~[mut ~[u8]] = ~[mut];
    for uint::range(0, height as uint) |i| {
        let slice = vec::slice(data, i * (width as uint), (i+1) * (width as uint));
        let mut row: ~[u8] = ~[];
        for slice.each |sliced| {
            vec::push_all(row, byte_helpers::uint_to_le_bytes(sliced as u64, 2));
        }
        vec::push(rows, row);
    };
    vec::reverse(rows);
    //vec::grow(pixels, 44 * 44 * 4, 0x7f);

    ret vec::concat(~[
        signature,
        file_size,
        reserved,
        data_offset,

        header_size,
        width_bytes,
        height_bytes,
        colour_panes,
        depth,
        compression,
        image_size,
        horizontal_res,
        vertical_res,
        palette_count,
        important_colours,

        vec::concat(rows)
    ]);
}
<commit_msg>Notes<commit_after>//NOTE: apparently, when looking up statics by ID, they're offset by 0x4000.
export map_tile;
export load_tiles;
export to_bitmap;
export parse_map_tile;

type map_tile = {
    header: u32,
    image: ~[u16] //TODO: Consider making Pixel a type
};

type static_tile = {
    header: u32,
    width: u16,
    height: u16,
    rows: ~[~[run]]
};

type run = {
    offset: u16,
    length: u16,
    data: ~[u8]
};

const transparent: u16 = 0b1000000000000000;
const expected_tile_size: uint = 2048;

fn load_tiles(root_path: ~str) -> (~[map_tile], ~[static_tile]) { //TODO: Find a better return type for this
    let reader:mul_reader::mul_reader = mul_reader::mul_reader(root_path, ~"artidx.mul", ~"art.mul");

    let mut map_tiles: ~[map_tile] = ~[];
    let mut static_tiles: ~[static_tile] = ~[];

    while (reader.eof() != true) {
        let item: option::option<mul_reader::mul_record> = reader.read();
        if option::is_some(item) {
            let unwrapped: mul_reader::mul_record = option::get(item);
            let record_header = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 0, 3));
            //Apparently, these flag values represent whether something is a tile or not
            //Others are not convinced, and think that index is all that matters
            //TODO: provide a check against incorrect lengths, as this causes problems

            if (vec::len(unwrapped.data) == expected_tile_size &&  (record_header > 0xFFFF || record_header == 0)) {
                vec::push(map_tiles, parse_map_tile(unwrapped));
            } else {
            }
        }
    }

    ret (map_tiles, static_tiles);
}

fn parse_map_tile(record: mul_reader::mul_record) -> map_tile { //Interestingly, pixels seem to be 565, rather than 555

    let record_header = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 3));
    let mut image: ~[u16] = ~[];
    let data_slice: ~[u8] = vec::slice(record.data, 4, vec::len(record.data));

    let mut data_pointer: uint = 0;
    for uint::range(0, 44) |i| {

        let slice: uint = if (i >= 22) {(44 - i) * 2} else {(i + 1) * 2};
        vec::grow(image, (22 - (slice / 2)), transparent);
        //vec::grow(image, slice, byte_helpers::u8vec_to_u16vec(~[0b00000000, 0b01111100])[0]);
        //io::println(#fmt("%u", vec::len(slice_data)));
        /*let mut slice_data: ~[u8] = ~[];
        for uint::range(0, slice) |j| {
            vec::push(slice_data, 0b01111100);
            vec::push(slice_data, 0b00000000);
        };*/

        let slice_data: ~[u8] = vec::slice(data_slice, data_pointer, data_pointer + (slice * 2));
        vec::push_all(image, byte_helpers::u8vec_to_u16vec(slice_data));
        vec::grow(image, (22 - (slice / 2)), transparent);
        data_pointer += (slice * 2);
    };

    ret {
        header: record_header as u32,
        image: image
    };
}
/*fn parse_static_tile(record: mul_reader::mul_record) -> static_tile {
    let record_header: u32 = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 0, 3)) as u32;
    let width: u16 = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 4, 5)) as u16;
    let height: u16 = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 6, 7)) as u16;

    let mut rows: ~[ mut ~[run]] = ~[mut];

    for uint::range(0, height) |i| {
        //Ze plan - read a row, starting from position 8, all the way to height
        let offset: u16 = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 8 + (2 * i), 9 + (2 * i)), 2) as u16;

    }
}*/

fn to_bitmap(width: u32, height: u32, data: ~[u16]) -> ~[u8] { //TODO: Make this take arbitrary pixel depths
    let signature: ~[u8] = ~[0x42, 0x4D];
    let file_size: ~[u8] = byte_helpers::uint_to_le_bytes(((width * height * 2) + 14 + 40) as u64, 4);
    let reserved: ~[u8] = ~[0, 0, 0, 0];
    let data_offset: ~[u8] = byte_helpers::uint_to_le_bytes(54, 4);

    let header_size: ~[u8] = byte_helpers::uint_to_le_bytes(40, 4);
    let width_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(width as u64, 4); //FIXME: should be signed?
    let height_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(height as u64, 4);
    let colour_panes: ~[u8] = ~[1, 0];
    let depth: ~[u8] = ~[16, 0];
    let compression: ~[u8] = ~[0,0,0,0];
    let image_size: ~[u8] = ~[0,0,0,0];
    let horizontal_res: ~[u8] = ~[0, 0, 0, 0];
    let vertical_res: ~[u8] = ~[0, 0, 0, 0];
    let palette_count: ~[u8] = ~[0, 0, 0, 0];
    let important_colours: ~[u8] = ~[0, 0, 0, 0];

    //54 bytes so far
    //TODO: explode the image vector, iterate backwards, turn it into bytes
    let mut rows: ~[mut ~[u8]] = ~[mut];
    for uint::range(0, height as uint) |i| {
        let slice = vec::slice(data, i * (width as uint), (i+1) * (width as uint));
        let mut row: ~[u8] = ~[];
        for slice.each |sliced| {
            vec::push_all(row, byte_helpers::uint_to_le_bytes(sliced as u64, 2));
        }
        vec::push(rows, row);
    };
    vec::reverse(rows);
    //vec::grow(pixels, 44 * 44 * 4, 0x7f);

    ret vec::concat(~[
        signature,
        file_size,
        reserved,
        data_offset,

        header_size,
        width_bytes,
        height_bytes,
        colour_panes,
        depth,
        compression,
        image_size,
        horizontal_res,
        vertical_res,
        palette_count,
        important_colours,

        vec::concat(rows)
    ]);
}
<|endoftext|>


<commit_before>use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
use std::io::{Error, ErrorKind};
use tokio::net::TcpStream;
use std::net::SocketAddr;
use tokio_codec::Framed;
use tokio::timer::Delay;
use tokio::prelude::*;
use rand;

use super::peer::*;
use super::rpc::*;
use fut_util::*;

mod state;

pub mod event;
use self::event::*;

///
/// Connects to the `SocketAddr` with the specified `PeerType`.
///
pub fn connect(addr: SocketAddr, peer_type: PeerType) -> impl Future<Item = Peer, Error = Error> {
    TcpStream::connect(&addr).and_then(move |stream| {
        let frame = Framed::new(stream, codec::RpcCodec::new());
        let msg = RpcPayload {
            id: 0,
            msg: Some(RpcMsg::Handshake(peer_type))
        };

        debug!("[{}] Sending handshake: {:?}", addr, &msg);
        frame.send(msg)
    }).and_then(move |frame| {
        let (resp, frame) = frame.into_future().map_err(|(e, _)| e).wait()?;
        let resp = resp.ok_or_else(|| Error::from(ErrorKind::UnexpectedEof))?;
        debug!("[{}] Received handshake message: {:?}", addr, &resp);
        if resp.id != 0 {
            return Err(Error::new(ErrorKind::InvalidData, "expected id to be 0"))
        } else if resp.msg.is_some() {
            return Err(Error::new(ErrorKind::InvalidData, "expected msg to be empty"))
        }
        Ok(Peer::new(peer_type, addr, frame))
    })
}

///
/// Creates a persistent connection to the `SocketAddr` provided. Events are
/// emitted via the `ClientReceiver`. When sending a `ClientEvent::Disconnect`
/// event the returned `ClientReceiver` stream will be closed.
///
/// See [`ClientEvent`] for the type of events to send and receive.
///
/// [`ClientEvent`]: ./event/enum.ClientEvent.html
///
/// # Panics
///
/// When attempting to send a message that requires the connection to be open.
///
pub fn connect_loop(addr: SocketAddr, peer_type: PeerType) -> (ClientSender, ClientReceiver) {
    let (out_tx, out_rx) = channel::unbounded();
    let (in_tx, in_rx) = channel::unbounded();
    let state = state::ConnectState::new(addr, peer_type);
    start_connect_loop(state.clone(), out_tx, 0);

    ::tokio::spawn(in_rx.for_each({
        let stay_connected = Arc::clone(&state.stay_connected);
        let inner = Arc::clone(&state.inner);
        move |msg| {
            match msg {
                ClientEvent::Message(msg) => {
                    let guard = inner.lock();
                    let inner = guard.borrow();
                    let inner = inner.as_ref().expect("must be connected to send msg");
                    inner.sender.send(msg);
                },
                ClientEvent::Connect => panic!("cannot connect from event channel"),
                ClientEvent::Disconnect => {
                    stay_connected.store(false, Ordering::Release);
                    let guard = inner.lock();
                    let inner = guard.borrow();
                    let inner = inner.as_ref().expect("must be connected to disconnect");
                    inner.notifier.send(());
                }
            }
            Ok(())
        }
    }));

    (in_tx, out_rx)
}

fn start_connect_loop(state: state::ConnectState, out_tx: ClientSender, mut tries: u8) {
    if !state.stay_connected.load(Ordering::Acquire) { return }
    let c = connect(state.addr, state.peer_type);
    ::tokio::spawn(c.and_then({
        let out_tx = out_tx.clone();
        let state = state.clone();
        move |peer| {
            if !state.stay_connected.load(Ordering::Acquire) { return Ok(()) }
            info!("[{}] Connected to peer", state.addr);

            let connected = Arc::new(AtomicBool::new(true));
            out_tx.send(ClientEvent::Connect);
            tries = 0;

            let rx = {
                let (tx, rx) = channel::unbounded();
                let guard = state.inner.lock();
                *guard.borrow_mut() = Some(state::InternalState {
                    sender: peer.get_sender(),
                    notifier: tx
                });
                rx.map_err(|_| {
                    Error::new(ErrorKind::Other, "rx error")
                })
            };

            ::tokio::spawn(ZipEither::new(peer, rx).take_while({
                let stay_connected = Arc::clone(&state.stay_connected);
                let connected = Arc::clone(&connected);
                move |_| {
                    let stay_connected = stay_connected.load(Ordering::Acquire);
                    let connected = connected.load(Ordering::Acquire);
                    Ok(stay_connected && connected)
                }
            }).for_each({
                let out_tx = out_tx.clone();
                move |(rpc, _)| {
                    if let Some(rpc) = rpc {
                        out_tx.send(ClientEvent::Message(rpc));
                    }
                    Ok(())
                }
            }).and_then({
                let addr = state.addr;
                move |_| {
                    warn!("[{}] Peer disconnected", addr);
                    Ok(())
                }
            }).or_else({
                let addr = state.addr;
                move |e| -> Result<_, ()> {
                    error!("[{}] Peer frame processing error: {}", addr, e);
                    Ok(())
                }
            }).and_then({
                let stay_connected = Arc::clone(&state.stay_connected);
                move |_| {
                    out_tx.send(ClientEvent::Disconnect);
                    {
                        let guard = state.inner.lock();
                        *guard.borrow_mut() = None;
                    }
                    if stay_connected.load(Ordering::Acquire) {
                        try_connect(state, out_tx, tries.saturating_add(1));
                    }
                    Ok(())
                }
            }));

            Ok(())
        }
    }).map_err(move |e| {
        if state.stay_connected.load(Ordering::Acquire) {
            error!("[{}] Failed to connect to peer: {:?}", state.addr, e);
            try_connect(state, out_tx, tries.saturating_add(1));
        }
    }));
}

fn try_connect(state: state::ConnectState, out_tx: ClientSender, tries: u8) {
    use ::std::time::{Duration, Instant};

    let ms = backoff(tries);
    info!("[{}] Attempting to reconnect to peer in {} ms (tries: {})", state.addr, ms, tries);
    let d = Instant::now() + Duration::from_millis(ms);
    ::tokio::spawn(Delay::new(d).map(move |_| {
        start_connect_loop(state, out_tx, tries);
    }).map_err(|e| {
        error!("Connection timer error: {}", e);
    }));
}

fn backoff(tries: u8) -> u64 {
    use rand::Rng;
    let tries = f64::from(tries);
    let max = 15000f64;
    let rand = rand::thread_rng().gen_range::<f64>(0.2f64, 1f64);
    max.min((1.25f64.powf(tries) * 1000f64 * rand).floor()) as u64
}
<commit_msg>Publicize net client events<commit_after>use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
use std::io::{Error, ErrorKind};
use tokio::net::TcpStream;
use std::net::SocketAddr;
use tokio_codec::Framed;
use tokio::timer::Delay;
use tokio::prelude::*;
use rand;

use super::peer::*;
use super::rpc::*;
use fut_util::*;

mod state;

pub mod event;
pub use self::event::*;

///
/// Connects to the `SocketAddr` with the specified `PeerType`.
///
pub fn connect(addr: SocketAddr, peer_type: PeerType) -> impl Future<Item = Peer, Error = Error> {
    TcpStream::connect(&addr).and_then(move |stream| {
        let frame = Framed::new(stream, codec::RpcCodec::new());
        let msg = RpcPayload {
            id: 0,
            msg: Some(RpcMsg::Handshake(peer_type))
        };

        debug!("[{}] Sending handshake: {:?}", addr, &msg);
        frame.send(msg)
    }).and_then(move |frame| {
        let (resp, frame) = frame.into_future().map_err(|(e, _)| e).wait()?;
        let resp = resp.ok_or_else(|| Error::from(ErrorKind::UnexpectedEof))?;
        debug!("[{}] Received handshake message: {:?}", addr, &resp);
        if resp.id != 0 {
            return Err(Error::new(ErrorKind::InvalidData, "expected id to be 0"))
        } else if resp.msg.is_some() {
            return Err(Error::new(ErrorKind::InvalidData, "expected msg to be empty"))
        }
        Ok(Peer::new(peer_type, addr, frame))
    })
}

///
/// Creates a persistent connection to the `SocketAddr` provided. Events are
/// emitted via the `ClientReceiver`. When sending a `ClientEvent::Disconnect`
/// event the returned `ClientReceiver` stream will be closed.
///
/// See [`ClientEvent`] for the type of events to send and receive.
///
/// [`ClientEvent`]: ./event/enum.ClientEvent.html
///
/// # Panics
///
/// When attempting to send a message that requires the connection to be open.
///
pub fn connect_loop(addr: SocketAddr, peer_type: PeerType) -> (ClientSender, ClientReceiver) {
    let (out_tx, out_rx) = channel::unbounded();
    let (in_tx, in_rx) = channel::unbounded();
    let state = state::ConnectState::new(addr, peer_type);
    start_connect_loop(state.clone(), out_tx, 0);

    ::tokio::spawn(in_rx.for_each({
        let stay_connected = Arc::clone(&state.stay_connected);
        let inner = Arc::clone(&state.inner);
        move |msg| {
            match msg {
                ClientEvent::Message(msg) => {
                    let guard = inner.lock();
                    let inner = guard.borrow();
                    let inner = inner.as_ref().expect("must be connected to send msg");
                    inner.sender.send(msg);
                },
                ClientEvent::Connect => panic!("cannot connect from event channel"),
                ClientEvent::Disconnect => {
                    stay_connected.store(false, Ordering::Release);
                    let guard = inner.lock();
                    let inner = guard.borrow();
                    let inner = inner.as_ref().expect("must be connected to disconnect");
                    inner.notifier.send(());
                }
            }
            Ok(())
        }
    }));

    (in_tx, out_rx)
}

fn start_connect_loop(state: state::ConnectState, out_tx: ClientSender, mut tries: u8) {
    if !state.stay_connected.load(Ordering::Acquire) { return }
    let c = connect(state.addr, state.peer_type);
    ::tokio::spawn(c.and_then({
        let out_tx = out_tx.clone();
        let state = state.clone();
        move |peer| {
            if !state.stay_connected.load(Ordering::Acquire) { return Ok(()) }
            info!("[{}] Connected to peer", state.addr);

            let connected = Arc::new(AtomicBool::new(true));
            out_tx.send(ClientEvent::Connect);
            tries = 0;

            let rx = {
                let (tx, rx) = channel::unbounded();
                let guard = state.inner.lock();
                *guard.borrow_mut() = Some(state::InternalState {
                    sender: peer.get_sender(),
                    notifier: tx
                });
                rx.map_err(|_| {
                    Error::new(ErrorKind::Other, "rx error")
                })
            };

            ::tokio::spawn(ZipEither::new(peer, rx).take_while({
                let stay_connected = Arc::clone(&state.stay_connected);
                let connected = Arc::clone(&connected);
                move |_| {
                    let stay_connected = stay_connected.load(Ordering::Acquire);
                    let connected = connected.load(Ordering::Acquire);
                    Ok(stay_connected && connected)
                }
            }).for_each({
                let out_tx = out_tx.clone();
                move |(rpc, _)| {
                    if let Some(rpc) = rpc {
                        out_tx.send(ClientEvent::Message(rpc));
                    }
                    Ok(())
                }
            }).and_then({
                let addr = state.addr;
                move |_| {
                    warn!("[{}] Peer disconnected", addr);
                    Ok(())
                }
            }).or_else({
                let addr = state.addr;
                move |e| -> Result<_, ()> {
                    error!("[{}] Peer frame processing error: {}", addr, e);
                    Ok(())
                }
            }).and_then({
                let stay_connected = Arc::clone(&state.stay_connected);
                move |_| {
                    out_tx.send(ClientEvent::Disconnect);
                    {
                        let guard = state.inner.lock();
                        *guard.borrow_mut() = None;
                    }
                    if stay_connected.load(Ordering::Acquire) {
                        try_connect(state, out_tx, tries.saturating_add(1));
                    }
                    Ok(())
                }
            }));

            Ok(())
        }
    }).map_err(move |e| {
        if state.stay_connected.load(Ordering::Acquire) {
            error!("[{}] Failed to connect to peer: {:?}", state.addr, e);
            try_connect(state, out_tx, tries.saturating_add(1));
        }
    }));
}

fn try_connect(state: state::ConnectState, out_tx: ClientSender, tries: u8) {
    use ::std::time::{Duration, Instant};

    let ms = backoff(tries);
    info!("[{}] Attempting to reconnect to peer in {} ms (tries: {})", state.addr, ms, tries);
    let d = Instant::now() + Duration::from_millis(ms);
    ::tokio::spawn(Delay::new(d).map(move |_| {
        start_connect_loop(state, out_tx, tries);
    }).map_err(|e| {
        error!("Connection timer error: {}", e);
    }));
}

fn backoff(tries: u8) -> u64 {
    use rand::Rng;
    let tries = f64::from(tries);
    let max = 15000f64;
    let rand = rand::thread_rng().gen_range::<f64>(0.2f64, 1f64);
    max.min((1.25f64.powf(tries) * 1000f64 * rand).floor()) as u64
}
<|endoftext|>


<commit_before>use graph::{BasicBlockIndex, FuncGraph};
use env::Environment;
use graph_algorithms::Graph;
use graph_algorithms::bit_set::BitSet;
use nll_repr::repr;
use std::collections::HashMap;

/// Compute the set of live variables at each point.
pub struct Liveness {
    var_bits: HashMap<repr::Variable, usize>,
    liveness: BitSet<FuncGraph>,
}

impl Liveness {
    pub fn new(env: &Environment) -> Liveness {
        let var_bits: HashMap<_, _> = env.graph.decls()
                                               .iter()
                                               .cloned()
                                               .zip(0..)
                                               .collect();
        let liveness = compute(env, &var_bits);
        Liveness { var_bits, liveness }
    }

    pub fn live_on_entry(&self, v: repr::Variable, b: BasicBlockIndex) -> bool {
        let bit = self.var_bits[&v];
        self.liveness.bits(b).get(bit)
    }
}

fn compute(env: &Environment,
           var_bits: &HashMap<repr::Variable, usize>)
           -> BitSet<FuncGraph> {
    let mut liveness = BitSet::new(env.graph, var_bits.len());
    let mut bits = liveness.empty_buf();

    let mut changed = true;
    while changed {
        changed = false;

        for &block in &env.reverse_post_order {
            bits.clear();

            // everything live in a successor is live at the exit of the block
            for succ in env.graph.successors(block) {
                bits.set_from(liveness.bits(succ));
            }

            // walk backwards through the actions
            for action in env.graph.block_data(block).actions.iter().rev() {
                let (def_var, use_var) = action.def_use();

                // anything we write to is no longer live
                for v in def_var {
                    bits.kill(var_bits[&v]);
                }

                // anything we read from, we make live
                for v in use_var {
                    bits.set(var_bits[&v]);
                }
            }

            changed |= liveness.insert_bits_from_slice(block, bits.as_slice());
        }
    }

    liveness
}

trait UseDefs {
    fn def_use(&self) -> (Vec<repr::Variable>, Vec<repr::Variable>);
}

impl UseDefs for repr::Action {
    fn def_use(&self) -> (Vec<repr::Variable>, Vec<repr::Variable>) {
        match *self {
            repr::Action::Borrow(v) => (vec!(v), vec!()),
            repr::Action::Assign(l, r) => (vec!(l), vec![r]),
            repr::Action::Subtype(a, b) => (vec!(), vec![a, b]),
            repr::Action::Use(v) => (vec!(), vec!(v)),
            repr::Action::Write(v) => (vec!(), vec!(v)),
            repr::Action::Noop => (vec!(), vec!()),
        }
    }
}
<commit_msg>refactor how liveness works to use callback<commit_after>use graph::{BasicBlockIndex, FuncGraph};
use env::{Environment, Point};
use graph_algorithms::Graph;
use graph_algorithms::bit_set::{BitBuf, BitSet, BitSlice};
use nll_repr::repr;
use std::collections::HashMap;

/// Compute the set of live variables at each point.
pub struct Liveness {
    var_bits: HashMap<repr::Variable, usize>,
    liveness: BitSet<FuncGraph>,
}

impl Liveness {
    pub fn new(env: &Environment) -> Liveness {
        let var_bits: HashMap<_, _> = env.graph.decls()
                                               .iter()
                                               .cloned()
                                               .zip(0..)
                                               .collect();
        let liveness = BitSet::new(env.graph, var_bits.len());
        let mut this = Liveness { var_bits, liveness };
        this.compute(env);
        this
    }

    pub fn live_on_entry(&self, v: repr::Variable, b: BasicBlockIndex) -> bool {
        let bit = self.var_bits[&v];
        self.liveness.bits(b).get(bit)
    }

    fn compute(&mut self, env: &Environment) {
        let mut bits = self.liveness.empty_buf();
        let mut changed = true;
        while changed {
            changed = false;

            for &block in &env.reverse_post_order {
                self.simulate_block(env, &mut bits, block, |_p, _a, _s| ());
                changed |= self.liveness.insert_bits_from_slice(block, bits.as_slice());
            }
        }
    }

    fn simulate_block<CB>(&mut self,
                          env: &Environment,
                          buf: &mut BitBuf,
                          block: BasicBlockIndex,
                          mut callback: CB)
        where CB: FnMut(Point, &repr::Action, BitSlice)
    {
        buf.clear();

        // everything live in a successor is live at the exit of the block
        for succ in env.graph.successors(block) {
            buf.set_from(self.liveness.bits(succ));
        }

        // walk backwards through the actions
        for (index, action) in env.graph.block_data(block).actions.iter().enumerate().rev() {
            let (def_var, use_var) = action.def_use();

            // anything we write to is no longer live
            for v in def_var {
                buf.kill(self.var_bits[&v]);
            }

            // anything we read from, we make live
            for v in use_var {
                buf.set(self.var_bits[&v]);
            }

            let point = Point { block, action: index };
            callback(point, action, buf.as_slice());
        }
    }
}

trait UseDefs {
    fn def_use(&self) -> (Vec<repr::Variable>, Vec<repr::Variable>);
}

impl UseDefs for repr::Action {
    fn def_use(&self) -> (Vec<repr::Variable>, Vec<repr::Variable>) {
        match *self {
            repr::Action::Borrow(v) => (vec!(v), vec!()),
            repr::Action::Assign(l, r) => (vec!(l), vec![r]),
            repr::Action::Subtype(a, b) => (vec!(), vec![a, b]),
            repr::Action::Use(v) => (vec!(), vec!(v)),
            repr::Action::Write(v) => (vec!(), vec!(v)),
            repr::Action::Noop => (vec!(), vec!()),
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

use cabot;

use std::collections::HashMap;
use std::iter::FromIterator;
use std::net::{AddrParseError, SocketAddr};
use std::pin::Pin;

use async_std;
use async_std::fs::OpenOptions;
use async_std::io::{self, Write};
use async_std::prelude::*;
use async_std::task::Context;
use async_std::task::Poll;
use clap::{App, Arg};
use log::Level::Info;

use cabot::constants;
use cabot::http;
use cabot::request::RequestBuilder;
use cabot::results::CabotResult;

pub async fn run() -> CabotResult<()> {
    let user_agent: String = constants::user_agent();

    let dns_lookup_timeout = format!("{}", constants::DNS_LOOKUP_TIMEOUT);
    let connect_timeout = format!("{}", constants::CONNECT_TIMEOUT);
    let request_timeout = format!("{}", constants::REQUEST_TIMEOUT);
    let read_timeout = format!("{}", constants::READ_TIMEOUT);

    let number_of_redirect = format!("{}", constants::NUMBER_OF_REDIRECT);

    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(constants::VERSION)
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .arg(
            Arg::with_name("URL")
                .index(1)
                .required(true)
                .help("URL to request"),
        )
        .arg(
            Arg::with_name("REQUEST")
                .short("X")
                .long("request")
                .default_value("GET")
                .help("Specify request command to use"),
        )
        .arg(
            Arg::with_name("HEADER")
                .short("H")
                .long("header")
                .takes_value(true)
                .multiple(true)
                .help("Pass custom header to server"),
        )
        .arg(
            Arg::with_name("FILE")
                .short("o")
                .long("output")
                .takes_value(true)
                .help("Write to FILE instead of stdout"),
        )
        .arg(
            Arg::with_name("VERBOSE")
                .short("v")
                .long("verbose")
                .help("Make the operation more talkative"),
        )
        .arg(
            Arg::with_name("BODY")
                .short("d")
                .long("data")
                .takes_value(true)
                .help("Post Data (Using utf-8 encoding)"),
        )
        .arg(
            Arg::with_name("IPv4")
                .short("4")
                .long("ipv4")
                .help("Resolve host names to IPv4 addresses"),
        )
        .arg(
            Arg::with_name("IPv6")
                .short("6")
                .long("ipv6")
                .help("Resolve host names to IPv6 addresses"),
        )
        .arg(
            Arg::with_name("UA")
                .short("A")
                .long("user-agent")
                .default_value(user_agent.as_str())
                .help("The user-agent HTTP header to use"),
        )
        .arg(
            Arg::with_name("DNS_LOOKUP_TIMEOUT")
                .long("dns-timeout")
                .takes_value(true)
                .default_value(dns_lookup_timeout.as_str())
                .help("timeout for the dns lookup resolution in seconds"),
        )
        .arg(
            Arg::with_name("CONNECT_TIMEOUT")
                .long("connect-timeout")
                .takes_value(true)
                .default_value(connect_timeout.as_str())
                .help("timeout for the tcp connection"),
        )
        .arg(
            Arg::with_name("READ_TIMEOUT")
                .long("read-timeout")
                .takes_value(true)
                .default_value(read_timeout.as_str())
                .help("timeout for the tcp read in seconds"),
        )
        .arg(
            Arg::with_name("REQUEST_TIMEOUT")
                .long("max-time")
                .takes_value(true)
                .default_value(request_timeout.as_str())
                .help("timeout for the whole http request in seconds (0 means no timeout)"),
        )
        .arg(
            Arg::with_name("NUMBER_OF_REDIRECT")
                .long("max-redirs")
                .takes_value(true)
                .default_value(number_of_redirect.as_str())
                .help("max number of redirection before returning a response"),
        )
        .arg(
            Arg::with_name("RESOLVE")
                .long("resolve")
                .takes_value(true)
                .multiple(true)
                .help("<host:port:address> Resolve the host+port to this address"),
        )
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");
    let body = matches.value_of("BODY");
    let ua = matches.value_of("UA").unwrap();

    let mut ipv4 = matches.is_present("IPv4");
    let mut ipv6 = matches.is_present("IPv6");

    if !ipv4 && !ipv6 {
        ipv4 = true;
        ipv6 = true;
    }

    let headers: Vec<&str> = match matches.values_of("HEADER") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let resolved: HashMap<String, SocketAddr> = match matches.values_of("RESOLVE") {
        Some(headers) => HashMap::from_iter(
            headers
                .map(|resolv| resolv.splitn(3, ':'))
                .map(|resolv| {
                    let count = resolv.clone().count();
                    if count != 3 {
                        let resolv: Vec<&str> = resolv.collect();
                        let _ =
                            eprintln!("Invalid format in resolve argument: {}", resolv.join(":"));
                        std::process::exit(1);
                    }
                    resolv
                })
                .map(|mut resolv| {
                    (
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                    )
                })
                .map(|(host, port, addr)| {
                    let parsed_port = port.parse::<usize>();
                    if parsed_port.is_err() {
                        let _ = eprintln!(
                            "Invalid port in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr: Result<SocketAddr, AddrParseError> =
                        format!("{}:{}", addr, port).parse();
                    if sockaddr.is_err() {
                        let _ = eprintln!(
                            "Invalid address in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr = sockaddr.unwrap();
                    (format!("{}:{}", host, port), sockaddr)
                }),
        ),
        None => HashMap::new(),
    };

    let dns_timeout = u64::from_str_radix(matches.value_of("DNS_LOOKUP_TIMEOUT").unwrap(), 10)
        .expect("DNS_LOOKUP_TIMEOUT must be an integer")
        * 1_000;
    let connect_timeout = u64::from_str_radix(matches.value_of("CONNECT_TIMEOUT").unwrap(), 10)
        .expect("CONNECT_TIMEOUT must be an integer")
        * 1_000;
    let read_timeout = u64::from_str_radix(matches.value_of("READ_TIMEOUT").unwrap(), 10)
        .expect("READ_TIMEOUT must be an integer")
        * 1_000;
    let request_timeout = u64::from_str_radix(matches.value_of("REQUEST_TIMEOUT").unwrap(), 10)
        .expect("REQUEST_TIMEOUT must be an integer")
        * 1_000;
    let number_of_redirect =
        u8::from_str_radix(matches.value_of("NUMBER_OF_REDIRECT").unwrap(), 10)
            .expect("NUMBER_OF_REDIRECT must be an integer");

    let mut builder = RequestBuilder::new(url)
        .set_http_method(http_method)
        .set_user_agent(ua)
        .add_headers(&headers.as_slice());

    if body.is_some() {
        builder = builder.set_body_as_str(body.unwrap());
    }

    let request = builder.build()?;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
            .await
            .unwrap();
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut f, verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
            number_of_redirect,
        )
        .await?
    } else {
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut io::stdout(), verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
            number_of_redirect,
        )
        .await?
    };
    Ok(())
}

#[async_std::main]
async fn main() {
    #[cfg(feature = "pretty_log")]
    pretty_env_logger::init();
    debug!("Starting cabot");

    run()
        .await
        .map(|ok| {
            debug!("Command cabot ended succesfully");
            ok
        })
        .map_err(|err| {
            eprintln!("{}", err);
            std::process::exit(1);
        })
        .unwrap();
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut (dyn Write + Unpin),
    header_read: bool,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut (dyn Write + Unpin), verbose: bool) -> Self {
        CabotBinWrite {
            out,
            verbose,
            header_read: false,
        }
    }
    fn display_headers(&self, buf: &[u8]) {
        let headers = String::from_utf8_lossy(buf);
        let split: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
        if log_enabled!(Info) {
            for part in split {
                info!("< {}", part);
            }
        } else if self.verbose {
            for part in split {
                eprintln!("< {}", part);
            }
        }
    }
}

impl<'a> Write for CabotBinWrite<'a> {
    // may receive headers
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        let self_ = Pin::get_mut(self);
        if !self_.header_read {
            // the first time write is called, all headers are sent
            // in the buffer. there is no need to parse it again.
            if log_enabled!(Info) || self_.verbose {
                self_.display_headers(&buf);
            }
            self_.header_read = true;
            Poll::Ready(Ok(0))
        } else {
            let towrite = buf.len();
            let mut written = 0;
            loop {
                let res = Pin::new(&mut self_.out).poll_write(cx, &buf[written..towrite]);
                match res {
                    Poll::Ready(Ok(l)) => written += l,
                    _ => {}
                }
                if written >= towrite {
                    break;
                }
            }
            Poll::Ready(Ok(written))
        }
    }

    /// this function is called when the request is done
    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        self_.out.flush();
        Poll::Ready(Ok(()))
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        Pin::new(&mut self_.out).poll_close(cx)
    }
}
<commit_msg>Use a macro to cleanup code<commit_after>#[macro_use]
extern crate log;

use cabot;

use std::collections::HashMap;
use std::iter::FromIterator;
use std::net::{AddrParseError, SocketAddr};
use std::pin::Pin;

use async_std;
use async_std::fs::OpenOptions;
use async_std::io::{self, Write};
use async_std::prelude::*;
use async_std::task::Context;
use async_std::task::Poll;
use clap::{App, Arg};
use log::Level::Info;

use cabot::constants;
use cabot::http;
use cabot::request::RequestBuilder;
use cabot::results::CabotResult;

macro_rules! parse_int {
    ($name:expr, $typ:ty, $matches:ident) => {
        <$typ>::from_str_radix($matches.value_of($name).unwrap(), 10)
            .expect(format!("{} must be an integer", $name).as_str())
    };
}

pub async fn run() -> CabotResult<()> {
    let user_agent: String = constants::user_agent();

    let dns_lookup_timeout = format!("{}", constants::DNS_LOOKUP_TIMEOUT);
    let connect_timeout = format!("{}", constants::CONNECT_TIMEOUT);
    let request_timeout = format!("{}", constants::REQUEST_TIMEOUT);
    let read_timeout = format!("{}", constants::READ_TIMEOUT);

    let number_of_redirect = format!("{}", constants::NUMBER_OF_REDIRECT);

    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(constants::VERSION)
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .arg(
            Arg::with_name("URL")
                .index(1)
                .required(true)
                .help("URL to request"),
        )
        .arg(
            Arg::with_name("REQUEST")
                .short("X")
                .long("request")
                .default_value("GET")
                .help("Specify request command to use"),
        )
        .arg(
            Arg::with_name("HEADER")
                .short("H")
                .long("header")
                .takes_value(true)
                .multiple(true)
                .help("Pass custom header to server"),
        )
        .arg(
            Arg::with_name("FILE")
                .short("o")
                .long("output")
                .takes_value(true)
                .help("Write to FILE instead of stdout"),
        )
        .arg(
            Arg::with_name("VERBOSE")
                .short("v")
                .long("verbose")
                .help("Make the operation more talkative"),
        )
        .arg(
            Arg::with_name("BODY")
                .short("d")
                .long("data")
                .takes_value(true)
                .help("Post Data (Using utf-8 encoding)"),
        )
        .arg(
            Arg::with_name("IPv4")
                .short("4")
                .long("ipv4")
                .help("Resolve host names to IPv4 addresses"),
        )
        .arg(
            Arg::with_name("IPv6")
                .short("6")
                .long("ipv6")
                .help("Resolve host names to IPv6 addresses"),
        )
        .arg(
            Arg::with_name("UA")
                .short("A")
                .long("user-agent")
                .default_value(user_agent.as_str())
                .help("The user-agent HTTP header to use"),
        )
        .arg(
            Arg::with_name("DNS_LOOKUP_TIMEOUT")
                .long("dns-timeout")
                .takes_value(true)
                .default_value(dns_lookup_timeout.as_str())
                .help("timeout for the dns lookup resolution in seconds"),
        )
        .arg(
            Arg::with_name("CONNECT_TIMEOUT")
                .long("connect-timeout")
                .takes_value(true)
                .default_value(connect_timeout.as_str())
                .help("timeout for the tcp connection"),
        )
        .arg(
            Arg::with_name("READ_TIMEOUT")
                .long("read-timeout")
                .takes_value(true)
                .default_value(read_timeout.as_str())
                .help("timeout for the tcp read in seconds"),
        )
        .arg(
            Arg::with_name("REQUEST_TIMEOUT")
                .long("max-time")
                .takes_value(true)
                .default_value(request_timeout.as_str())
                .help("timeout for the whole http request in seconds (0 means no timeout)"),
        )
        .arg(
            Arg::with_name("NUMBER_OF_REDIRECT")
                .long("max-redirs")
                .takes_value(true)
                .default_value(number_of_redirect.as_str())
                .help("max number of redirection before returning a response"),
        )
        .arg(
            Arg::with_name("RESOLVE")
                .long("resolve")
                .takes_value(true)
                .multiple(true)
                .help("<host:port:address> Resolve the host+port to this address"),
        )
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");
    let body = matches.value_of("BODY");
    let ua = matches.value_of("UA").unwrap();

    let mut ipv4 = matches.is_present("IPv4");
    let mut ipv6 = matches.is_present("IPv6");

    if !ipv4 && !ipv6 {
        ipv4 = true;
        ipv6 = true;
    }

    let headers: Vec<&str> = match matches.values_of("HEADER") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let resolved: HashMap<String, SocketAddr> = match matches.values_of("RESOLVE") {
        Some(headers) => HashMap::from_iter(
            headers
                .map(|resolv| resolv.splitn(3, ':'))
                .map(|resolv| {
                    let count = resolv.clone().count();
                    if count != 3 {
                        let resolv: Vec<&str> = resolv.collect();
                        let _ =
                            eprintln!("Invalid format in resolve argument: {}", resolv.join(":"));
                        std::process::exit(1);
                    }
                    resolv
                })
                .map(|mut resolv| {
                    (
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                    )
                })
                .map(|(host, port, addr)| {
                    let parsed_port = port.parse::<usize>();
                    if parsed_port.is_err() {
                        let _ = eprintln!(
                            "Invalid port in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr: Result<SocketAddr, AddrParseError> =
                        format!("{}:{}", addr, port).parse();
                    if sockaddr.is_err() {
                        let _ = eprintln!(
                            "Invalid address in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr = sockaddr.unwrap();
                    (format!("{}:{}", host, port), sockaddr)
                }),
        ),
        None => HashMap::new(),
    };

    let dns_timeout = parse_int!("DNS_LOOKUP_TIMEOUT", u64, matches) * 1_000;
    let connect_timeout = parse_int!("CONNECT_TIMEOUT", u64, matches) * 1_000;
    let read_timeout = parse_int!("READ_TIMEOUT", u64, matches) * 1_000;
    let request_timeout = parse_int!("REQUEST_TIMEOUT", u64, matches) * 1_000;
    let number_of_redirect = parse_int!("NUMBER_OF_REDIRECT", u8, matches);

    let mut builder = RequestBuilder::new(url)
        .set_http_method(http_method)
        .set_user_agent(ua)
        .add_headers(&headers.as_slice());

    if body.is_some() {
        builder = builder.set_body_as_str(body.unwrap());
    }

    let request = builder.build()?;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
            .await
            .unwrap();
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut f, verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
            number_of_redirect,
        )
        .await?
    } else {
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut io::stdout(), verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
            number_of_redirect,
        )
        .await?
    };
    Ok(())
}

#[async_std::main]
async fn main() {
    #[cfg(feature = "pretty_log")]
    pretty_env_logger::init();
    debug!("Starting cabot");

    run()
        .await
        .map(|ok| {
            debug!("Command cabot ended succesfully");
            ok
        })
        .map_err(|err| {
            eprintln!("{}", err);
            std::process::exit(1);
        })
        .unwrap();
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut (dyn Write + Unpin),
    header_read: bool,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut (dyn Write + Unpin), verbose: bool) -> Self {
        CabotBinWrite {
            out,
            verbose,
            header_read: false,
        }
    }
    fn display_headers(&self, buf: &[u8]) {
        let headers = String::from_utf8_lossy(buf);
        let split: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
        if log_enabled!(Info) {
            for part in split {
                info!("< {}", part);
            }
        } else if self.verbose {
            for part in split {
                eprintln!("< {}", part);
            }
        }
    }
}

impl<'a> Write for CabotBinWrite<'a> {
    // may receive headers
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        let self_ = Pin::get_mut(self);
        if !self_.header_read {
            // the first time write is called, all headers are sent
            // in the buffer. there is no need to parse it again.
            if log_enabled!(Info) || self_.verbose {
                self_.display_headers(&buf);
            }
            self_.header_read = true;
            Poll::Ready(Ok(0))
        } else {
            let towrite = buf.len();
            let mut written = 0;
            loop {
                let res = Pin::new(&mut self_.out).poll_write(cx, &buf[written..towrite]);
                match res {
                    Poll::Ready(Ok(l)) => written += l,
                    _ => {}
                }
                if written >= towrite {
                    break;
                }
            }
            Poll::Ready(Ok(written))
        }
    }

    /// this function is called when the request is done
    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        self_.out.flush();
        Poll::Ready(Ok(()))
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        Pin::new(&mut self_.out).poll_close(cx)
    }
}
<|endoftext|>


<commit_before>use url::Url;
use hyper::Client;
use hyper::header::{ContentType, ContentLength};
use hyper::net::Fresh;
use hyper::client::Request;
use hyper::status::StatusCode;

pub struct HttpResponse {
    pub status: StatusCode,
    pub body: String
}

pub fn get<E>(url: &Url) -> Result<HttpResponse, E> {
    let mut client = Client::new();
    let req = client.get(&url.to_string())
        .header(ContentType("application/json".parse().unwrap()))
        .header(ContentLength(0));
    let res = try!(req.send());
}

//pub fn post<E>(url: &Url) -> Result<HttpResponse, E> {
    //let mut client = Client::new();
    //client.post(url.to_string().as_slice()).header(ContentType("application/json".parse().unwrap()));
    //let mut req = Request::post(url.clone()).unwrap();
    //req.headers_mut().set(ContentType(from_str("application/json").unwrap()));
    //req.headers_mut().set(ContentLength(0));
    //make_request(req)
//}

//pub fn post_json<E>(url: &Url, json: &str) -> Result<HttpResponse, E> {
    //let mut client = Client::new();
    //client.post(url.to_string().as_slice()).header(ContentType("application/json".parse().unwrap()));
    //let mut req = Request::post(url.clone()).unwrap();
    //req.headers_mut().set(ContentType(from_str("application/json").unwrap()));
    //req.headers_mut().set(ContentLength(json.len()));
    //match req.start() {
        //Ok(mut req) => {
            //try!(req.write(json.to_string().into_bytes().as_slice()));
            //match req.send() {
                //Ok(mut resp) => {
                    //match resp.read_to_string() {
                        //Ok(body) => Ok(HttpResponse{code: resp.status as u16, body: body}),
                        //Err(e) => Err(FromError::from_error(e))
                    //}
                //},
                //Err(e) => Err(e)
            //}
        //},
        //Err(e) => Err(e)
    //}
//}

//fn make_request<C, E>(client: &mut Client<C>) -> Result<HttpResponse, E> {

    //match req.start() {
        //Ok(req) => {
            //match req.send() {
                //Ok(mut resp) => {
                    //match resp.read_to_string() {
                        //Ok(body) => Ok(HttpResponse{code: resp.status as u16, body: body}),
                        //Err(e) => Err(FromError::from_error(e))
                    //}
                //},
                //Err(e) => Err(e)
            //}
        //},
        //Err(e) => Err(e)
    //}
//}
<commit_msg>Modiefied http_utils#get<commit_after>use url::Url;
use hyper::Client;
use hyper::header::{ContentType, ContentLength};
use hyper::net::Fresh;
use hyper::client::Request;
use hyper::status::StatusCode;
use hyper::error::Error;
use std::io::Read;

pub struct HttpResponse {
    pub status: StatusCode,
    pub body: String
}

pub fn get(url: &Url) -> Result<HttpResponse, Error> {
    let mut client = Client::new();
    let mut res = client.get(&url.to_string())
        .send()
        .unwrap();
    let mut body = String::new();
    let result = res.read_to_string(&mut body);
    match result {
        Ok(_) => {
            Ok(HttpResponse{status: res.status, body: body})
        },
        Err(err) => {
            Err(Error::Io(err))
        }
    }
}

//pub fn post<E>(url: &Url) -> Result<HttpResponse, E> {
    //let mut client = Client::new();
    //client.post(url.to_string().as_slice()).header(ContentType("application/json".parse().unwrap()));
    //let mut req = Request::post(url.clone()).unwrap();
    //req.headers_mut().set(ContentType(from_str("application/json").unwrap()));
    //req.headers_mut().set(ContentLength(0));
    //make_request(req)
//}

//pub fn post_json<E>(url: &Url, json: &str) -> Result<HttpResponse, E> {
    //let mut client = Client::new();
    //client.post(url.to_string().as_slice()).header(ContentType("application/json".parse().unwrap()));
    //let mut req = Request::post(url.clone()).unwrap();
    //req.headers_mut().set(ContentType(from_str("application/json").unwrap()));
    //req.headers_mut().set(ContentLength(json.len()));
    //match req.start() {
        //Ok(mut req) => {
            //try!(req.write(json.to_string().into_bytes().as_slice()));
            //match req.send() {
                //Ok(mut resp) => {
                    //match resp.read_to_string() {
                        //Ok(body) => Ok(HttpResponse{code: resp.status as u16, body: body}),
                        //Err(e) => Err(FromError::from_error(e))
                    //}
                //},
                //Err(e) => Err(e)
            //}
        //},
        //Err(e) => Err(e)
    //}
//}

//fn make_request<C, E>(client: &mut Client<C>) -> Result<HttpResponse, E> {

    //match req.start() {
        //Ok(req) => {
            //match req.send() {
                //Ok(mut resp) => {
                    //match resp.read_to_string() {
                        //Ok(body) => Ok(HttpResponse{code: resp.status as u16, body: body}),
                        //Err(e) => Err(FromError::from_error(e))
                    //}
                //},
                //Err(e) => Err(e)
            //}
        //},
        //Err(e) => Err(e)
    //}
//}
<|endoftext|>


<commit_before>pub mod files;

use std::cmp;
use std::io::Write;

#[derive(Debug)]
pub struct Ips {
    buffer: Vec<u8>
}

macro_rules! copy {
    ($a:expr, $v:expr) => {
        for (to, from) in $a.iter_mut().zip($v) {
            *to = *from;
        }
    }
}

impl Ips {
    pub fn new(buffer: &Vec<u8>) -> Self {
        Ips {
            buffer: buffer.clone()
        }
    }

    pub fn diff(&self, change: &Vec<u8>) -> Vec<Patch> {
        let mut pairs = (0..).zip(self.buffer.iter().zip(change));

        let mut patches: Vec<Patch> = vec![];
        let mut index = 0;
        let mut data = vec![];
        while let Some((offset, (&before, &after))) = pairs.next() {
            if before != after {
                if data.is_empty() {
                    index = offset;
                }
                data.push(after);
            } else if ! data.is_empty() {
                let patch = Patch::new(index, data);
                patches.push(patch);
                data = vec![];
            }
        };
        patches
    }

    pub fn patch(&self, change: &Vec<Patch>) -> Vec<u8> {
        let total_size = cmp::max(self.buffer.len(), change.iter().max_by_key(|x| x.addr as usize + x.data.len()).unwrap().addr as usize);
        let mut output = Vec::with_capacity(total_size);
        output.extend(&self.buffer);

        println!("before: {:?}", output);
        for patch in change {
            println!("{:?}", patch);
            let (_, mut skipped) = output.split_at_mut(patch.addr as usize);
            skipped.write(&patch.data);
        }
        println!("after: {:?}", output);
        output
    }

    pub fn serialize_patches(&self, patches: Vec<Patch>) -> Vec<u8> {
        let patch_contents: Vec<u8> = patches.iter().flat_map(|p| p.bytes()).collect();
        let mut binary: Vec<u8> = "PATCH".bytes().collect();
        binary.extend(patch_contents);
        binary.extend("EOF".bytes().collect::<Vec<_>>());
        binary
    }
}

pub fn unserialize_patches(binary: Vec<u8>) -> Option<Vec<Patch>> {
    let mut patches: Vec<Patch> = Vec::new();

    let slice = &binary;
    let (header, mut slice) = slice.split_at(5);

    if header != b"PATCH" {
        return None;
    }

    loop {
        // TODO support RLE'd patches
        let (addr_slice, rest) = slice.split_at(3);
        let (len_slice, rest) = rest.split_at(2);

        if (! addr_slice.is_empty()) && len_slice.len() < 2 {
            // Malformed data
            return None;
        }

        let mut addr_array = [0; 3];
        copy!(addr_array, addr_slice);
        let addr = Patch::unserialize_addr_array(addr_array);

        let mut len_array = [0; 2];
        copy!(len_array, len_slice);
        let len = Patch::unserialize_len(len_array);

        let (data, rest) = rest.split_at(len);

        if data.len() < len {
            // Malformed data
            return None;
        }

        let patch = Patch {
            addr: addr,
            data: data.to_vec()
        };

        patches.push(patch);

        slice = rest;

        let possible_eof: Vec<u8> = rest.iter().take(3).cloned().collect();
        if &possible_eof == b"EOF" {
            // We are done here
            break;
        }
    }

    Some(patches)
}

#[derive(Debug, PartialEq)]
pub struct Patch {
    addr: u32,
    data: Vec<u8>
}

impl Patch {
    pub fn new(addr: u32, data: Vec<u8>) -> Self {
        assert!(addr <= 0xFFFFFF);
        Patch {
            addr: addr,
            data: data
        }
    }

    pub fn bytes(&self) -> Vec<u8> {
        let mut bytes: Vec<u8> = self.serialize_addr();
        let len = self.serialize_len();
        bytes.extend(len);
        bytes.extend(&self.data);
        bytes
    }

    pub fn unserialize_addr_array(addr: [u8; 3]) -> u32 {
        ((addr[0] as u32) << 16) | ((addr[1] as u32) << 8) | addr[2] as u32
    }

    pub fn unserialize_addr_bytes(a3: u8, a2: u8, a1: u8) -> u32 {
        ((a3 as u32) << 16) | ((a2 as u32) << 8) | a1 as u32
    }

    pub fn serialize_addr(&self) -> Vec<u8> {
        vec![(self.addr >> 16) as u8, (self.addr >> 8) as u8, self.addr as u8]
    }

    pub fn unserialize_len(addr: [u8; 2]) -> usize {
        (((addr[0] as u32) << 8) | addr[1] as u32) as usize
    }

    pub fn serialize_len(&self) -> Vec<u8> {
        vec![(self.data.len() >> 8) as u8, self.data.len() as u8]
    }

    //pub fn apply_to(&self, &[mut u8]
}
<commit_msg>Replace custom macro with now-stable clone_from_slice<commit_after>pub mod files;

use std::cmp;
use std::io::Write;

#[derive(Debug)]
pub struct Ips {
    buffer: Vec<u8>
}

impl Ips {
    pub fn new(buffer: &Vec<u8>) -> Self {
        Ips {
            buffer: buffer.clone()
        }
    }

    pub fn diff(&self, change: &Vec<u8>) -> Vec<Patch> {
        let mut pairs = (0..).zip(self.buffer.iter().zip(change));

        let mut patches: Vec<Patch> = vec![];
        let mut index = 0;
        let mut data = vec![];
        while let Some((offset, (&before, &after))) = pairs.next() {
            if before != after {
                if data.is_empty() {
                    index = offset;
                }
                data.push(after);
            } else if ! data.is_empty() {
                let patch = Patch::new(index, data);
                patches.push(patch);
                data = vec![];
            }
        };
        patches
    }

    pub fn patch(&self, change: &Vec<Patch>) -> Vec<u8> {
        let total_size = cmp::max(self.buffer.len(), change.iter().max_by_key(|x| x.addr as usize + x.data.len()).unwrap().addr as usize);
        let mut output = Vec::with_capacity(total_size);
        output.extend(&self.buffer);

        println!("before: {:?}", output);
        for patch in change {
            println!("{:?}", patch);
            let (_, mut skipped) = output.split_at_mut(patch.addr as usize);
            skipped.write(&patch.data);
        }
        println!("after: {:?}", output);
        output
    }

    pub fn serialize_patches(&self, patches: Vec<Patch>) -> Vec<u8> {
        let patch_contents: Vec<u8> = patches.iter().flat_map(|p| p.bytes()).collect();
        let mut binary: Vec<u8> = "PATCH".bytes().collect();
        binary.extend(patch_contents);
        binary.extend("EOF".bytes().collect::<Vec<_>>());
        binary
    }
}

pub fn unserialize_patches(binary: Vec<u8>) -> Option<Vec<Patch>> {
    let mut patches: Vec<Patch> = Vec::new();

    let slice = &binary;
    let (header, mut slice) = slice.split_at(5);

    if header != b"PATCH" {
        return None;
    }

    loop {
        // TODO support RLE'd patches
        let (addr_slice, rest) = slice.split_at(3);
        let (len_slice, rest) = rest.split_at(2);

        if (! addr_slice.is_empty()) && len_slice.len() < 2 {
            // Malformed data
            return None;
        }

        let mut addr_array = [0; 3];
        addr_array.clone_from_slice(addr_slice);
        let addr = Patch::unserialize_addr_array(addr_array);

        let mut len_array = [0; 2];
        len_array.clone_from_slice(len_slice);
        let len = Patch::unserialize_len(len_array);

        let (data, rest) = rest.split_at(len);

        if data.len() < len {
            // Malformed data
            return None;
        }

        let patch = Patch {
            addr: addr,
            data: data.to_vec()
        };

        patches.push(patch);

        slice = rest;

        let possible_eof: Vec<u8> = rest.iter().take(3).cloned().collect();
        if &possible_eof == b"EOF" {
            // We are done here
            break;
        }
    }

    Some(patches)
}

#[derive(Debug, PartialEq)]
pub struct Patch {
    addr: u32,
    data: Vec<u8>
}

impl Patch {
    pub fn new(addr: u32, data: Vec<u8>) -> Self {
        assert!(addr <= 0xFFFFFF);
        Patch {
            addr: addr,
            data: data
        }
    }

    pub fn bytes(&self) -> Vec<u8> {
        let mut bytes: Vec<u8> = self.serialize_addr();
        let len = self.serialize_len();
        bytes.extend(len);
        bytes.extend(&self.data);
        bytes
    }

    pub fn unserialize_addr_array(addr: [u8; 3]) -> u32 {
        ((addr[0] as u32) << 16) | ((addr[1] as u32) << 8) | addr[2] as u32
    }

    pub fn unserialize_addr_bytes(a3: u8, a2: u8, a1: u8) -> u32 {
        ((a3 as u32) << 16) | ((a2 as u32) << 8) | a1 as u32
    }

    pub fn serialize_addr(&self) -> Vec<u8> {
        vec![(self.addr >> 16) as u8, (self.addr >> 8) as u8, self.addr as u8]
    }

    pub fn unserialize_len(addr: [u8; 2]) -> usize {
        (((addr[0] as u32) << 8) | addr[1] as u32) as usize
    }

    pub fn serialize_len(&self) -> Vec<u8> {
        vec![(self.data.len() >> 8) as u8, self.data.len() as u8]
    }

    //pub fn apply_to(&self, &[mut u8]
}
<|endoftext|>


<commit_before>extern crate rand;

use atty::Stream;
use std;
use rand::Rng;
use std::thread::sleep;
use std::time::Duration;

// A struct to contain info we need to print with every character
pub struct Control {
    pub seed: f64,
    pub spread: f64,
    pub frequency: f64,
    pub background_mode: bool,
    pub dialup_mode: bool,
}

pub fn print_lines_lol<I : Iterator<Item=S>, S : AsRef<str>>(lines: I, c: &mut Control) {
    for line in lines {
        print_line_lol(line.as_ref(), c);

        if c.dialup_mode {
            let stall = Duration::from_millis(rand::thread_rng().gen_range(30, 700));
            sleep(stall);
        }
    }
}

// Takes in s a string of characters
// prints them using colored_print, and a newline at the end
// Ignores most escape sequences
// TODO Adds the color to a color escape sequence
fn print_line_lol(s: &str, c: &mut Control) {
    let original_seed = c.seed;
    let mut ignore_whitespace = c.background_mode;

    if !atty::is(Stream::Stdout) {
        println!("{}", s);
        return;
    }

    let mut iter = s.chars();
    while let Some(character) = iter.next() {
        // Consume escape sequences
        if character == '\x1b' {
            // Escape sequences seem to be one of many different categories
            // CSI sequences are \e \[ [bytes in 0x30-0x3F] [bytes in 0x20-0x2F] [final byte in 0x40-0x7E]
            // nF Escape seq are \e [bytes in 0x20-0x2F] [byte in 0x30-0x7E]
            // Fp Escape seq are \e [byte in 0x30-0x3F] [I have no idea, but `sl` creates one where the next byte is the end of the escape sequence, so assume that]
            // Fe Escape seq are \e [byte in 0x40-0x5F] [I have no idea, '' though sl doesn't make one]
            // Fs Escape seq are \e [byte in 0x60-0x7E] [I have no idea, '' though sl doesn't make one]
            // Otherwise the next byte is the whole escape sequence (maybe? I can't exactly tell, but I will go with it)
            // We will consume up to, but not through, the next printable character
            // In addition, we print everything in the escape sequence, even if it is a color (that will be overriden)
            print!("\x1b");
            let mut escape_sequence_character = iter.next().expect("Escape character with no escape sequence after it");
            print!("{}", escape_sequence_character);
            match escape_sequence_character {
            '[' => {
                loop {
                    escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x30' ..= '\x3F' => continue,
                    '\x20' ..= '\x2F' => {
                        loop {
                            escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                            print!("{}", escape_sequence_character);
                            match escape_sequence_character {
                            '\x20' ..= '\x2F' => continue,
                            '\x40' ..= '\x7E' => break,
                            _ => panic!("CSI escape sequence terminated with an incorrect value"),
                            }
                        }
                        break;
                    },
                    '\x40' ..= '\x7E' => break,
                    _ => panic!("CSI escape sequence terminated with an incorrect value"),
                    }
                }
            },
            '\x20' ..= '\x2F' => {
                loop {
                    escape_sequence_character = iter.next().expect("nF escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x20' ..= '\x2F' => continue,
                    '\x30' ..= '\x7E' => break,
                    _ => panic!("nF escape sequence terminated with an incorrect value"),
                    }
                }
            },
//            '\x30' ..= '\x3F' => panic!("Fp escape sequences are not supported"),
//            '\x40' ..= '\x5F' => panic!("Fe escape sequences are not supported"),
//            '\x60' ..= '\x7E' => panic!("Fs escape sequences are not supported"),
            // be lazy and assume in all other cases we consume exactly 1 byte
            _ => (),
            }
        }

        // In background mode, don't print colorful whitespace until the first printable character
        if ignore_whitespace && character.is_whitespace() {
            print!("{}", character);
            continue;
        } else {
            ignore_whitespace = false;
        }

        colored_print(character, c);
        c.seed += 1.0;
    }

    // Reset the background color if we should, since otherwise it will bleed all the way to the
    // end of the terminal
    if c.background_mode {
        print!("\x1b[49m");
    }

    // Reset the foreground color, since we are at the end of the output, and print the last newline
    // This has to happen here, rather than only at the end of the program, because otherwise
    // newlines become weird
    println!("\x1b[39m");

    c.seed = original_seed + 1.0; // Reset the seed, but bump it a bit
}

fn calc_fg_color(bg: (u8, u8, u8)) -> (u8, u8, u8) {
    // Currently, it only computes the forground clolor based on some threshold
    // on grayscale value.
    // TODO: Add a better algorithm for computing forground color
    if conv_grayscale(bg) > 0xA0_u8 {
        (0u8, 0u8, 0u8)
    } else {
        (0xffu8, 0xffu8, 0xffu8)
    }
}

fn linear_to_srgb(intensity: f64) -> f64 {
    if intensity <= 0.003_130_8 {
        12.92 * intensity
    } else {
        1.055 * intensity.powf(1.0 / 2.4) - 0.055
    }
}

fn srgb_to_linear(intensity: f64) -> f64 {
    if intensity < 0.04045 {
        intensity / 12.92
    } else {
        ((intensity + 0.055) / 1.055).powf(2.4)
    }
}

fn conv_grayscale(color: (u8, u8, u8)) -> u8 {
    // See https://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
    const SCALE: f64 = 256.0;

    // Changing SRGB to Linear for gamma correction
    let red = srgb_to_linear(f64::from(color.0) / SCALE);
    let green = srgb_to_linear(f64::from(color.1) / SCALE);
    let blue = srgb_to_linear(f64::from(color.2) / SCALE);

    // Converting to grayscale
    let gray_linear = red * 0.299 + green * 0.587 + blue * 0.114;

    // Gamma correction
    let gray_srgb = linear_to_srgb(gray_linear);

    (gray_srgb * SCALE) as u8
}

fn colored_print(character: char, c: &mut Control) {
    if c.background_mode {
        let bg = get_color_tuple(c);
        let fg = calc_fg_color(bg);
        print!(
            "\x1b[38;2;{};{};{};48;2;{};{};{}m{}",
            fg.0, fg.1, fg.2, bg.0, bg.1, bg.2, character
        );
    } else {
        let fg = get_color_tuple(c);
        print!("\x1b[38;2;{};{};{}m{}", fg.0, fg.1, fg.2, character);
    }
}

fn get_color_tuple(c: &Control) -> (u8, u8, u8) {
    let i = c.frequency * c.seed / c.spread;
    let red = i.sin() * 127.00 + 128.00;
    let green = (i + (std::f64::consts::PI * 2.00 / 3.00)).sin() * 127.00 + 128.00;
    let blue = (i + (std::f64::consts::PI * 4.00 / 3.00)).sin() * 127.00 + 128.00;

    (red as u8, green as u8, blue as u8)
}
<commit_msg>Use iterators more effectively, will be helpful when I want stdin to be unbuffered by newlines<commit_after>extern crate rand;

use atty::Stream;
use std;
use rand::Rng;
use std::thread::sleep;
use std::time::Duration;

// A struct to contain info we need to print with every character
pub struct Control {
    pub seed: f64,
    pub spread: f64,
    pub frequency: f64,
    pub background_mode: bool,
    pub dialup_mode: bool,
}

pub fn print_lines_lol<I: Iterator<Item=S>, S: AsRef<str>>(lines: I, c: &mut Control) {
    for line in lines {
        print_chars_lol(line.as_ref().chars().chain(Some('\n')), c);
    }
}

// Takes in s an iterator over characters
// duplicates escape sequences, otherwise prints printable characters with colored_print
// Print newlines correctly
// TODO Adds the color to a color escape sequence
fn print_chars_lol<I: Iterator<Item=char>>(mut iter: I, c: &mut Control) {
    let original_seed = c.seed;
    let mut ignore_whitespace = c.background_mode;

    if !atty::is(Stream::Stdout) {
        for s in iter {
            print!("{}", s);
        }
        return;
    }

    while let Some(character) = iter.next() {
        match character {
        // Consume escape sequences
        '\x1b' => {
            // Escape sequences seem to be one of many different categories
            // CSI sequences are \e \[ [bytes in 0x30-0x3F] [bytes in 0x20-0x2F] [final byte in 0x40-0x7E]
            // nF Escape seq are \e [bytes in 0x20-0x2F] [byte in 0x30-0x7E]
            // Fp Escape seq are \e [byte in 0x30-0x3F] [I have no idea, but `sl` creates one where the next byte is the end of the escape sequence, so assume that]
            // Fe Escape seq are \e [byte in 0x40-0x5F] [I have no idea, '' though sl doesn't make one]
            // Fs Escape seq are \e [byte in 0x60-0x7E] [I have no idea, '' though sl doesn't make one]
            // Otherwise the next byte is the whole escape sequence (maybe? I can't exactly tell, but I will go with it)
            // We will consume up to, but not through, the next printable character
            // In addition, we print everything in the escape sequence, even if it is a color (that will be overriden)
            print!("\x1b");
            let mut escape_sequence_character = iter.next().expect("Escape character with no escape sequence after it");
            print!("{}", escape_sequence_character);
            match escape_sequence_character {
            '[' => {
                loop {
                    escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x30' ..= '\x3F' => continue,
                    '\x20' ..= '\x2F' => {
                        loop {
                            escape_sequence_character = iter.next().expect("CSI escape sequence did not terminate");
                            print!("{}", escape_sequence_character);
                            match escape_sequence_character {
                            '\x20' ..= '\x2F' => continue,
                            '\x40' ..= '\x7E' => break,
                            _ => panic!("CSI escape sequence terminated with an incorrect value"),
                            }
                        }
                        break;
                    },
                    '\x40' ..= '\x7E' => break,
                    _ => panic!("CSI escape sequence terminated with an incorrect value"),
                    }
                }
            },
            '\x20' ..= '\x2F' => {
                loop {
                    escape_sequence_character = iter.next().expect("nF escape sequence did not terminate");
                    print!("{}", escape_sequence_character);
                    match escape_sequence_character {
                    '\x20' ..= '\x2F' => continue,
                    '\x30' ..= '\x7E' => break,
                    _ => panic!("nF escape sequence terminated with an incorrect value"),
                    }
                }
            },
//            '\x30' ..= '\x3F' => panic!("Fp escape sequences are not supported"),
//            '\x40' ..= '\x5F' => panic!("Fe escape sequences are not supported"),
//            '\x60' ..= '\x7E' => panic!("Fs escape sequences are not supported"),
            // be lazy and assume in all other cases we consume exactly 1 byte
            _ => (),
            }
            continue;
        },
        // Newlines print escape sequences to end background prints, and in dialup mode sleep
        '\n' => {
            if atty::is(Stream::Stdout) {
                // Reset the background color if we should, since otherwise it will bleed all the way to the
                // end of the terminal
                if c.background_mode {
                    print!("\x1b[49m");
                }

                // Reset the foreground color, since we are at the end of the output, and print the last newline
                // This has to happen here, rather than only at the end of the program, because otherwise
                // newlines become weird
                print!("\x1b[39m");
            }
            println!();
            if c.dialup_mode {
                let stall = Duration::from_millis(rand::thread_rng().gen_range(30, 700));
                sleep(stall);
            }
        },
        _ => {
            // In background mode, don't print colorful whitespace until the first printable character
            if ignore_whitespace && character.is_whitespace() {
                print!("{}", character);
                continue;
            } else {
                ignore_whitespace = false;
            }

            colored_print(character, c);
            c.seed += 1.0;
        },
        }
    }

    c.seed = original_seed + 1.0; // Reset the seed, but bump it a bit
}

fn calc_fg_color(bg: (u8, u8, u8)) -> (u8, u8, u8) {
    // Currently, it only computes the forground clolor based on some threshold
    // on grayscale value.
    // TODO: Add a better algorithm for computing forground color
    if conv_grayscale(bg) > 0xA0_u8 {
        (0u8, 0u8, 0u8)
    } else {
        (0xffu8, 0xffu8, 0xffu8)
    }
}

fn linear_to_srgb(intensity: f64) -> f64 {
    if intensity <= 0.003_130_8 {
        12.92 * intensity
    } else {
        1.055 * intensity.powf(1.0 / 2.4) - 0.055
    }
}

fn srgb_to_linear(intensity: f64) -> f64 {
    if intensity < 0.04045 {
        intensity / 12.92
    } else {
        ((intensity + 0.055) / 1.055).powf(2.4)
    }
}

fn conv_grayscale(color: (u8, u8, u8)) -> u8 {
    // See https://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
    const SCALE: f64 = 256.0;

    // Changing SRGB to Linear for gamma correction
    let red = srgb_to_linear(f64::from(color.0) / SCALE);
    let green = srgb_to_linear(f64::from(color.1) / SCALE);
    let blue = srgb_to_linear(f64::from(color.2) / SCALE);

    // Converting to grayscale
    let gray_linear = red * 0.299 + green * 0.587 + blue * 0.114;

    // Gamma correction
    let gray_srgb = linear_to_srgb(gray_linear);

    (gray_srgb * SCALE) as u8
}

fn colored_print(character: char, c: &mut Control) {
    if c.background_mode {
        let bg = get_color_tuple(c);
        let fg = calc_fg_color(bg);
        print!(
            "\x1b[38;2;{};{};{};48;2;{};{};{}m{}",
            fg.0, fg.1, fg.2, bg.0, bg.1, bg.2, character
        );
    } else {
        let fg = get_color_tuple(c);
        print!("\x1b[38;2;{};{};{}m{}", fg.0, fg.1, fg.2, character);
    }
}

fn get_color_tuple(c: &Control) -> (u8, u8, u8) {
    let i = c.frequency * c.seed / c.spread;
    let red = i.sin() * 127.00 + 128.00;
    let green = (i + (std::f64::consts::PI * 2.00 / 3.00)).sin() * 127.00 + 128.00;
    let blue = (i + (std::f64::consts::PI * 4.00 / 3.00)).sin() * 127.00 + 128.00;

    (red as u8, green as u8, blue as u8)
}
<|endoftext|>


<commit_before>use scoped_threadpool::Pool;
use std::sync::Arc;
use std::collections::HashSet;
use std::process;

use tfl::*;
use gtfs::*;
use format::{OutputFormat};

pub fn fetch_lines(format: OutputFormat, thread_number: u32) {
    let lines = load_lines(DataSource::API, thread_number);

    match format {
        OutputFormat::GTFS => transform_gtfs(lines),
        _ => process::exit(0),
    }
}

pub fn transform(format: OutputFormat, thread_number: u32) {
    let lines = load_lines(DataSource::Cache, thread_number);

    match format {
        OutputFormat::GTFS => transform_gtfs(lines),
        _ => process::exit(0),
    }
}

fn load_lines(data_source: DataSource, thread_number: u32) -> Vec<Line> {
    let mut pool = Pool::new(thread_number);
    let client = Arc::new(Client::new());

    let mut lines = match data_source {
        DataSource::Cache => client.get_cached_lines(),
        DataSource::API   => client.get_lines(),
    };

    pool.scoped(|scope| {
        for line in &mut lines {
            let client = client.clone();
            scope.execute(move || {
                line.inbound_sequence = client.get_sequence(&line.id, "inbound");
                line.outbound_sequence = client.get_sequence(&line.id, "outbound");
                line.stops = Some(client.get_stops(&line.id));
                for route_section in &mut line.routeSections {
                    println!("Getting Timetable for Line: {}, Route Section: {} ...", line.name, route_section.name);
                    route_section.timetable = client.get_timetable(&line.id, &route_section.originator, &route_section.destination);
                }
            });
        }
    });

    lines
}

fn transform_gtfs(lines: Vec<Line>) {
    let mut line_count = 0;
    let mut line_ids: HashSet<String> = HashSet::new();
    let mut route_section_count = 0;
    let mut route_section_ids: HashSet<String> = HashSet::new();
    let mut schedule_names: HashSet<String> = HashSet::new();

    for line in &lines {
        println!("{}, Duplicate: {}", line.id, line_ids.contains(&line.id));
        for route_section in &line.routeSections {
            let has_timetable = true; //TODO: Fix me

            match route_section.timetable {
                Some(ref timetable) => {
                    let names = collect_schedule_names(timetable);
                    schedule_names = schedule_names.union(&names).cloned().collect::<HashSet<String>>();
                    names.is_empty()
                },
                None => false,
            };

            let id = route_section_id(&line, &route_section);
            println!("\t{}, Has Timetable: {}, Duplicate: {}", id, has_timetable, route_section_ids.contains(&id));
            route_section_ids.insert(id.clone());
            route_section_count += 1;
        }
        line_count += 1;
        line_ids.insert(line.id.clone());
    }
    println!("Duplicate Lines: {}, Duplicate Route Sections: {}", line_count - line_ids.len(), route_section_count-route_section_ids.len());

    println!("Schedule Names:");
    for schedule_name in &schedule_names {
        println!("\t{}", schedule_name);
    }

    // Generate CSV files from fetched data
    write_gtfs(&lines);
}
<commit_msg>Fix has_timetable hack<commit_after>use scoped_threadpool::Pool;
use std::sync::Arc;
use std::collections::HashSet;
use std::process;

use tfl::*;
use gtfs::*;
use format::{OutputFormat};

pub fn fetch_lines(format: OutputFormat, thread_number: u32) {
    let lines = load_lines(DataSource::API, thread_number);

    match format {
        OutputFormat::GTFS => transform_gtfs(lines),
        _ => process::exit(0),
    }
}

pub fn transform(format: OutputFormat, thread_number: u32) {
    let lines = load_lines(DataSource::Cache, thread_number);

    match format {
        OutputFormat::GTFS => transform_gtfs(lines),
        _ => process::exit(0),
    }
}

fn load_lines(data_source: DataSource, thread_number: u32) -> Vec<Line> {
    let mut pool = Pool::new(thread_number);
    let client = Arc::new(Client::new());

    let mut lines = match data_source {
        DataSource::Cache => client.get_cached_lines(),
        DataSource::API   => client.get_lines(),
    };

    pool.scoped(|scope| {
        for line in &mut lines {
            let client = client.clone();
            scope.execute(move || {
                line.inbound_sequence = client.get_sequence(&line.id, "inbound");
                line.outbound_sequence = client.get_sequence(&line.id, "outbound");
                line.stops = Some(client.get_stops(&line.id));
                for route_section in &mut line.routeSections {
                    println!("Getting Timetable for Line: {}, Route Section: {} ...", line.name, route_section.name);
                    route_section.timetable = client.get_timetable(&line.id, &route_section.originator, &route_section.destination);
                }
            });
        }
    });

    lines
}

fn transform_gtfs(lines: Vec<Line>) {
    let mut line_count = 0;
    let mut line_ids: HashSet<String> = HashSet::new();
    let mut route_section_count = 0;
    let mut route_section_ids: HashSet<String> = HashSet::new();
    let mut schedule_names: HashSet<String> = HashSet::new();

    for line in &lines {
        println!("{}, Duplicate: {}", line.id, line_ids.contains(&line.id));
        for route_section in &line.routeSections {
            let has_timetable = match route_section.timetable {
                Some(ref timetable) => {
                    let names = collect_schedule_names(timetable);
                    schedule_names = schedule_names.union(&names).cloned().collect::<HashSet<String>>();
                    names.is_empty()
                },
                None => false,
            };

            let id = route_section_id(&line, &route_section);
            println!("\t{}, Has Timetable: {}, Duplicate: {}", id, has_timetable, route_section_ids.contains(&id));
            route_section_ids.insert(id.clone());
            route_section_count += 1;
        }
        line_count += 1;
        line_ids.insert(line.id.clone());
    }
    println!("Duplicate Lines: {}, Duplicate Route Sections: {}", line_count - line_ids.len(), route_section_count-route_section_ids.len());

    println!("Schedule Names:");
    for schedule_name in &schedule_names {
        println!("\t{}", schedule_name);
    }

    // Generate CSV files from fetched data
    write_gtfs(&lines);
}
<|endoftext|>