<commit_before>use std::sync::{Arc, Mutex};

use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{
    self, Document, Element, HtmlCanvasElement, KeyboardEvent, MouseEvent, Node, UiEvent, Window,
};

use crate::input::prelude::{InputEvent, MouseButton};
use crate::window::prelude::{Event, WindowEvent, WindowParams};

use crate::math::prelude::Vector2;
use crate::errors::*;

use super::{types, Visitor};

#[allow(dead_code)]
pub struct WebVisitor {
    window: Window,
    document: Document,
    canvas: HtmlCanvasElement,
    events: Arc<Mutex<Vec<Event>>>,
    on_mouse_move: Closure<FnMut(MouseEvent)>,
    on_mouse_down: Closure<FnMut(MouseEvent)>,
    on_mouse_up: Closure<FnMut(MouseEvent)>,
    on_key_down: Closure<FnMut(KeyboardEvent)>,
    on_key_up: Closure<FnMut(KeyboardEvent)>,
    on_resize: Closure<FnMut(UiEvent)>,
    on_focus: Closure<FnMut(UiEvent)>,
    on_lost_focus: Closure<FnMut(UiEvent)>,
}

impl WebVisitor {
    pub fn new(params: WindowParams) -> Result<Self> {
        let window = web_sys::window().expect("no global `window` exists");
        let document = window.document().expect("should have a document on window");
        let body = document.body().expect("document should have a body");

        let header = document.create_element("p").unwrap();
        header.set_inner_html(&params.title);
        AsRef::<Node>::as_ref(&body)
            .append_child(header.as_ref())
            .unwrap();

        let canvas = document
            .create_element("canvas")
            .unwrap()
            .dyn_into::<HtmlCanvasElement>()
            .map_err(|_| ())
            .unwrap();

        canvas
            .unchecked_ref::<Element>()
            .set_attribute("id", "canvas")
            .unwrap();

        AsRef::<Node>::as_ref(&body)
            .append_child(canvas.as_ref())
            .unwrap();

        let events = Arc::new(Mutex::new(Vec::new()));

        let on_mouse_down = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |v: MouseEvent| {
                let button = match v.button() {
                    0 => MouseButton::Left,
                    1 => MouseButton::Middle,
                    2 => MouseButton::Right,
                    i => MouseButton::Other(i as u8),
                };

                let evt = Event::InputDevice(InputEvent::MousePressed { button });
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("mousedown", on_mouse_down.as_ref().unchecked_ref())
            .unwrap();

        let on_mouse_up = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |v: MouseEvent| {
                let button = match v.button() {
                    0 => MouseButton::Left,
                    1 => MouseButton::Middle,
                    2 => MouseButton::Right,
                    i => MouseButton::Other(i as u8),
                };

                let evt = Event::InputDevice(InputEvent::MouseReleased { button });
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("mouseup", on_mouse_up.as_ref().unchecked_ref())
            .unwrap();

        let on_mouse_move = {
            let clone = events.clone();
            let window = window.clone();
            let canvas = canvas.clone();
            Closure::wrap(Box::new(move |v: MouseEvent| {
                let dpr = window.device_pixel_ratio() as f32;
                let height = canvas.height() as f32 / dpr;
                let rect = canvas.get_bounding_client_rect();

                let position = (
                    v.client_x() as f32 - rect.x() as f32,
                    height - v.client_y() as f32 + rect.y() as f32,
                );

                let evt = Event::InputDevice(InputEvent::MouseMoved { position });
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("mousemove", on_mouse_move.as_ref().unchecked_ref())
            .unwrap();

        let on_key_down = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |v: KeyboardEvent| {
                if let Some(key) = types::from_virtual_key_code(&v.key()) {
                    let evt = Event::InputDevice(InputEvent::KeyboardPressed { key });
                    clone.lock().unwrap().push(evt);
                }
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("keydown", on_key_down.as_ref().unchecked_ref())
            .unwrap();

        let on_key_up = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |v: KeyboardEvent| {
                if let Some(key) = types::from_virtual_key_code(&v.key()) {
                    let evt = Event::InputDevice(InputEvent::KeyboardReleased { key });
                    clone.lock().unwrap().push(evt);
                }
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("keyup", on_key_up.as_ref().unchecked_ref())
            .unwrap();

        let on_focus = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |_: UiEvent| {
                let evt = Event::Window(WindowEvent::GainFocus);
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("focus", on_focus.as_ref().unchecked_ref())
            .unwrap();

        let on_lost_focus = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |_: UiEvent| {
                let evt = Event::Window(WindowEvent::GainFocus);
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("blur", on_lost_focus.as_ref().unchecked_ref())
            .unwrap();

        let on_resize = {
            let clone = events.clone();
            let canvas = canvas.clone();
            Closure::wrap(Box::new(move |_: UiEvent| {
                let evt = Event::Window(WindowEvent::Resized(canvas.width(), canvas.height()));
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())
            .unwrap();

        let visitor = WebVisitor {
            window: window,
            document: document,
            canvas: canvas,
            events: events,
            on_mouse_down: on_mouse_down,
            on_mouse_up: on_mouse_up,
            on_mouse_move: on_mouse_move,
            on_key_down: on_key_down,
            on_key_up: on_key_up,
            on_focus: on_focus,
            on_lost_focus: on_lost_focus,
            on_resize: on_resize,
        };

        let dpr = visitor.device_pixel_ratio();
        let dims = Vector2::new(
            (params.size.x as f32 * dpr) as u32,
            (params.size.y as f32 * dpr) as u32,
        );

        visitor.resize(dims);
        Ok(visitor)
    }
}

impl Visitor for WebVisitor {
    #[inline]
    fn show(&self) {
        warn!("It does not make sense to `show` window in browser.")
    }

    #[inline]
    fn hide(&self) {
        warn!("It does not make sense to `hide` window in browser.")
    }

    #[inline]
    fn position(&self) -> Vector2<i32> {
        (0, 0).into()
    }

    #[inline]
    fn dimensions(&self) -> Vector2<u32> {
        let dpr = self.window.device_pixel_ratio() as f32;
        Vector2::new(
            (self.canvas.width() as f32 / dpr) as u32,
            (self.canvas.height() as f32 / dpr) as u32,
        )
    }

    #[inline]
    fn device_pixel_ratio(&self) -> f32 {
        self.window.device_pixel_ratio() as f32
    }

    #[inline]
    fn resize(&self, dims: Vector2<u32>) {
        self.canvas.set_width(dims.x);
        self.canvas.set_height(dims.y);

        let dpr = self.device_pixel_ratio();
        self.canvas
            .unchecked_ref::<Element>()
            .set_attribute(
                "style",
                &format!(
                    "width: {}px; height: {}px;",
                    (dims.x as f32 / dpr) as u32,
                    (dims.y as f32 / dpr) as u32
                ),
            ).unwrap();
    }

    #[inline]
    fn poll_events(&mut self, v: &mut Vec<Event>) {
        let mut events = self.events.lock().unwrap();
        v.extend(events.drain(..));
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.document.has_focus().unwrap_or(false)
    }

    #[inline]
    fn make_current(&self) -> Result<()> {
        warn!("You can not `make_current` in browser.");
        Ok(())
    }

    #[inline]
    fn swap_buffers(&self) -> Result<()> {
        Ok(())
    }
}
<commit_msg>Add tabindex attribute to the canvas element<commit_after>use std::sync::{Arc, Mutex};

use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{
    self, Document, Element, HtmlCanvasElement, KeyboardEvent, MouseEvent, Node, UiEvent, Window,
};

use crate::input::prelude::{InputEvent, MouseButton};
use crate::window::prelude::{Event, WindowEvent, WindowParams};

use crate::math::prelude::Vector2;
use crate::errors::*;

use super::{types, Visitor};

#[allow(dead_code)]
pub struct WebVisitor {
    window: Window,
    document: Document,
    canvas: HtmlCanvasElement,
    events: Arc<Mutex<Vec<Event>>>,
    on_mouse_move: Closure<FnMut(MouseEvent)>,
    on_mouse_down: Closure<FnMut(MouseEvent)>,
    on_mouse_up: Closure<FnMut(MouseEvent)>,
    on_key_down: Closure<FnMut(KeyboardEvent)>,
    on_key_up: Closure<FnMut(KeyboardEvent)>,
    on_resize: Closure<FnMut(UiEvent)>,
    on_focus: Closure<FnMut(UiEvent)>,
    on_lost_focus: Closure<FnMut(UiEvent)>,
}

impl WebVisitor {
    pub fn new(params: WindowParams) -> Result<Self> {
        let window = web_sys::window().expect("no global `window` exists");
        let document = window.document().expect("should have a document on window");
        let body = document.body().expect("document should have a body");

        let header = document.create_element("p").unwrap();
        header.set_inner_html(&params.title);
        AsRef::<Node>::as_ref(&body)
            .append_child(header.as_ref())
            .unwrap();

        let canvas = document
            .create_element("canvas")
            .unwrap()
            .dyn_into::<HtmlCanvasElement>()
            .map_err(|_| ())
            .unwrap();

        canvas
            .unchecked_ref::<Element>()
            .set_attribute("id", "canvas")
            .unwrap();

        canvas
            .unchecked_ref::<Element>()
            .set_attribute("tabindex", "1")
            .unwrap();

        AsRef::<Node>::as_ref(&body)
            .append_child(canvas.as_ref())
            .unwrap();

        let events = Arc::new(Mutex::new(Vec::new()));

        let on_mouse_down = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |v: MouseEvent| {
                let button = match v.button() {
                    0 => MouseButton::Left,
                    1 => MouseButton::Middle,
                    2 => MouseButton::Right,
                    i => MouseButton::Other(i as u8),
                };

                let evt = Event::InputDevice(InputEvent::MousePressed { button });
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("mousedown", on_mouse_down.as_ref().unchecked_ref())
            .unwrap();

        let on_mouse_up = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |v: MouseEvent| {
                let button = match v.button() {
                    0 => MouseButton::Left,
                    1 => MouseButton::Middle,
                    2 => MouseButton::Right,
                    i => MouseButton::Other(i as u8),
                };

                let evt = Event::InputDevice(InputEvent::MouseReleased { button });
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("mouseup", on_mouse_up.as_ref().unchecked_ref())
            .unwrap();

        let on_mouse_move = {
            let clone = events.clone();
            let window = window.clone();
            let canvas = canvas.clone();
            Closure::wrap(Box::new(move |v: MouseEvent| {
                let dpr = window.device_pixel_ratio() as f32;
                let height = canvas.height() as f32 / dpr;
                let rect = canvas.get_bounding_client_rect();

                let position = (
                    v.client_x() as f32 - rect.x() as f32,
                    height - v.client_y() as f32 + rect.y() as f32,
                );

                let evt = Event::InputDevice(InputEvent::MouseMoved { position });
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("mousemove", on_mouse_move.as_ref().unchecked_ref())
            .unwrap();

        let on_key_down = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |v: KeyboardEvent| {
                if let Some(key) = types::from_virtual_key_code(&v.key()) {
                    let evt = Event::InputDevice(InputEvent::KeyboardPressed { key });
                    clone.lock().unwrap().push(evt);
                }
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("keydown", on_key_down.as_ref().unchecked_ref())
            .unwrap();

        let on_key_up = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |v: KeyboardEvent| {
                if let Some(key) = types::from_virtual_key_code(&v.key()) {
                    let evt = Event::InputDevice(InputEvent::KeyboardReleased { key });
                    clone.lock().unwrap().push(evt);
                }
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("keyup", on_key_up.as_ref().unchecked_ref())
            .unwrap();

        let on_focus = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |_: UiEvent| {
                let evt = Event::Window(WindowEvent::GainFocus);
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("focus", on_focus.as_ref().unchecked_ref())
            .unwrap();

        let on_lost_focus = {
            let clone = events.clone();
            Closure::wrap(Box::new(move |_: UiEvent| {
                let evt = Event::Window(WindowEvent::GainFocus);
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("blur", on_lost_focus.as_ref().unchecked_ref())
            .unwrap();

        let on_resize = {
            let clone = events.clone();
            let canvas = canvas.clone();
            Closure::wrap(Box::new(move |_: UiEvent| {
                let evt = Event::Window(WindowEvent::Resized(canvas.width(), canvas.height()));
                clone.lock().unwrap().push(evt);
            }) as Box<FnMut(_)>)
        };

        canvas
            .add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())
            .unwrap();

        let visitor = WebVisitor {
            window: window,
            document: document,
            canvas: canvas,
            events: events,
            on_mouse_down: on_mouse_down,
            on_mouse_up: on_mouse_up,
            on_mouse_move: on_mouse_move,
            on_key_down: on_key_down,
            on_key_up: on_key_up,
            on_focus: on_focus,
            on_lost_focus: on_lost_focus,
            on_resize: on_resize,
        };

        let dpr = visitor.device_pixel_ratio();
        let dims = Vector2::new(
            (params.size.x as f32 * dpr) as u32,
            (params.size.y as f32 * dpr) as u32,
        );

        visitor.resize(dims);
        Ok(visitor)
    }
}

impl Visitor for WebVisitor {
    #[inline]
    fn show(&self) {
        warn!("It does not make sense to `show` window in browser.")
    }

    #[inline]
    fn hide(&self) {
        warn!("It does not make sense to `hide` window in browser.")
    }

    #[inline]
    fn position(&self) -> Vector2<i32> {
        (0, 0).into()
    }

    #[inline]
    fn dimensions(&self) -> Vector2<u32> {
        let dpr = self.window.device_pixel_ratio() as f32;
        Vector2::new(
            (self.canvas.width() as f32 / dpr) as u32,
            (self.canvas.height() as f32 / dpr) as u32,
        )
    }

    #[inline]
    fn device_pixel_ratio(&self) -> f32 {
        self.window.device_pixel_ratio() as f32
    }

    #[inline]
    fn resize(&self, dims: Vector2<u32>) {
        self.canvas.set_width(dims.x);
        self.canvas.set_height(dims.y);

        let dpr = self.device_pixel_ratio();
        self.canvas
            .unchecked_ref::<Element>()
            .set_attribute(
                "style",
                &format!(
                    "width: {}px; height: {}px;",
                    (dims.x as f32 / dpr) as u32,
                    (dims.y as f32 / dpr) as u32
                ),
            ).unwrap();
    }

    #[inline]
    fn poll_events(&mut self, v: &mut Vec<Event>) {
        let mut events = self.events.lock().unwrap();
        v.extend(events.drain(..));
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.document.has_focus().unwrap_or(false)
    }

    #[inline]
    fn make_current(&self) -> Result<()> {
        warn!("You can not `make_current` in browser.");
        Ok(())
    }

    #[inline]
    fn swap_buffers(&self) -> Result<()> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(eq_op)]

#[deny(eq_op)]
fn main() {
	//((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); // does not work with compiletest yet due to multiple errors
	(1 + 2) * 3 - 5 < 3 * (2 + 1) - 5; //~ERROR
}
<commit_msg>Use multi-error compiletest (thanks to laumann)<commit_after>#![feature(plugin)]
#![plugin(eq_op)]

#[deny(eq_op)]
fn main() {
	((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
	//~^ ERROR
					//~^^ ERROR
						//~^^^ ERROR
	(1 + 2) * 3 - 5 < 3 * (2 + 1) - 5; //~ERROR
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::aptos_cli::setup_cli_test;
use anyhow::anyhow;
use aptos::{account::create::DEFAULT_FUNDED_COINS, test::CliTestFramework};
use aptos_config::{config::ApiConfig, utils::get_available_port};
use aptos_crypto::HashValue;
use aptos_rosetta::{
    client::RosettaClient,
    common::{native_coin, BLOCKCHAIN, Y2K_MS},
    types::{
        AccountBalanceRequest, AccountBalanceResponse, Block, BlockIdentifier, BlockRequest,
        NetworkIdentifier, NetworkRequest, PartialBlockIdentifier,
    },
    ROSETTA_VERSION,
};
use aptos_types::{account_address::AccountAddress, chain_id::ChainId};
use forge::{LocalSwarm, Node};
use std::{future::Future, time::Duration};
use tokio::{task::JoinHandle, time::Instant};

const DEFAULT_MAX_WAIT_MS: u64 = 5000;
const DEFAULT_INTERVAL_MS: u64 = 100;
static DEFAULT_MAX_WAIT_DURATION: Duration = Duration::from_millis(DEFAULT_MAX_WAIT_MS);
static DEFAULT_INTERVAL_DURATION: Duration = Duration::from_millis(DEFAULT_INTERVAL_MS);

pub async fn setup_test(
    num_nodes: usize,
    num_accounts: usize,
) -> (LocalSwarm, CliTestFramework, JoinHandle<()>, RosettaClient) {
    let (swarm, cli, faucet) = setup_cli_test(num_nodes, num_accounts).await;
    let validator = swarm.validators().next().unwrap();

    // And the client
    let rosetta_port = get_available_port();
    let rosetta_socket_addr = format!("127.0.0.1:{}", rosetta_port);
    let rosetta_url = format!("http://{}", rosetta_socket_addr.clone())
        .parse()
        .unwrap();
    let rosetta_client = RosettaClient::new(rosetta_url);
    let api_config = ApiConfig {
        enabled: true,
        address: rosetta_socket_addr.parse().unwrap(),
        tls_cert_path: None,
        tls_key_path: None,
        content_length_limit: None,
    };

    // Start the server
    let _rosetta = aptos_rosetta::bootstrap_async(
        swarm.chain_id(),
        api_config,
        Some(aptos_rest_client::Client::new(
            validator.rest_api_endpoint(),
        )),
    )
    .await
    .unwrap();

    // Ensure rosetta can take requests
    try_until_ok_default(|| rosetta_client.network_list())
        .await
        .unwrap();

    (swarm, cli, faucet, rosetta_client)
}

#[tokio::test]
async fn test_network() {
    let (swarm, _, _, rosetta_client) = setup_test(1, 1).await;
    let chain_id = swarm.chain_id();

    // We only support one network, this network
    let networks = try_until_ok_default(|| rosetta_client.network_list())
        .await
        .unwrap();
    assert_eq!(1, networks.network_identifiers.len());
    let network_id = networks.network_identifiers.first().unwrap();
    assert_eq!(BLOCKCHAIN, network_id.blockchain);
    assert_eq!(chain_id.to_string(), network_id.network);

    let request = NetworkRequest {
        network_identifier: NetworkIdentifier::from(chain_id),
    };
    let options = rosetta_client.network_options(&request).await.unwrap();
    assert_eq!(ROSETTA_VERSION, options.version.rosetta_version);

    // TODO: Check other options

    let request = NetworkRequest {
        network_identifier: NetworkIdentifier::from(chain_id),
    };
    let status = rosetta_client.network_status(&request).await.unwrap();
    assert!(status.current_block_identifier.index > 0);
    assert!(status.current_block_timestamp > Y2K_MS);
    assert_eq!(
        BlockIdentifier {
            index: 0,
            hash: HashValue::zero().to_hex()
        },
        status.genesis_block_identifier
    );
    assert_eq!(
        Some(status.genesis_block_identifier),
        status.oldest_block_identifier,
    );
}

#[tokio::test]
async fn test_account_balance() {
    let (swarm, cli, _faucet, rosetta_client) = setup_test(1, 2).await;

    let account_1 = cli.account_id(0);
    let account_2 = cli.account_id(1);
    let chain_id = swarm.chain_id();

    // At time 0, there should be 0 balance
    let response = get_balance(&rosetta_client, chain_id, account_1, Some(0))
        .await
        .unwrap();
    assert_eq!(
        response.block_identifier,
        BlockIdentifier {
            index: 0,
            hash: HashValue::zero().to_hex(),
        }
    );

    // At some time both accounts should exist with initial amounts
    try_until_ok(Duration::from_secs(5), DEFAULT_INTERVAL_DURATION, || {
        account_has_balance(&rosetta_client, chain_id, account_1, DEFAULT_FUNDED_COINS)
    })
    .await
    .unwrap();
    try_until_ok_default(|| {
        account_has_balance(&rosetta_client, chain_id, account_2, DEFAULT_FUNDED_COINS)
    })
    .await
    .unwrap();

    // Send money, and expect the gas and fees to show up accordingly
    const TRANSFER_AMOUNT: u64 = 5000;
    let response = cli.transfer_coins(0, 1, TRANSFER_AMOUNT).await.unwrap();
    let gas_used = response.gas_used.unwrap();

    account_has_balance(
        &rosetta_client,
        chain_id,
        account_1,
        DEFAULT_FUNDED_COINS - TRANSFER_AMOUNT - gas_used,
    )
    .await
    .unwrap();
    account_has_balance(
        &rosetta_client,
        chain_id,
        account_2,
        DEFAULT_FUNDED_COINS + TRANSFER_AMOUNT,
    )
    .await
    .unwrap();

    // TODO: Make a bad transaction, which will cause gas to be spent but no transfer
}

async fn account_has_balance(
    rosetta_client: &RosettaClient,
    chain_id: ChainId,
    account: AccountAddress,
    expected_balance: u64,
) -> anyhow::Result<u64> {
    let response = get_balance(rosetta_client, chain_id, account, None).await?;

    if response.balances.iter().any(|amount| {
        amount.currency == native_coin() && amount.value == expected_balance.to_string()
    }) {
        Ok(response.block_identifier.index)
    } else {
        Err(anyhow!(
            "Failed to find account with {} {:?}, received {:?}",
            expected_balance,
            native_coin(),
            response
        ))
    }
}

async fn get_balance(
    rosetta_client: &RosettaClient,
    chain_id: ChainId,
    account: AccountAddress,
    index: Option<u64>,
) -> anyhow::Result<AccountBalanceResponse> {
    let request = AccountBalanceRequest {
        network_identifier: chain_id.into(),
        account_identifier: account.into(),
        block_identifier: Some(PartialBlockIdentifier { index, hash: None }),
        currencies: Some(vec![native_coin()]),
    };
    try_until_ok_default(|| rosetta_client.account_balance(&request)).await
}

#[ignore]
#[tokio::test]
async fn test_block() {
    let (swarm, _cli, _faucet, rosetta_client) = setup_test(1, 0).await;
    let chain_id = swarm.chain_id();

    // Genesis by version
    let genesis_block = get_block(&rosetta_client, chain_id, 0).await;
    assert_genesis_block(&genesis_block);

    // Get genesis txn by hash
    let genesis_block_by_hash = get_block_by_hash(
        &rosetta_client,
        chain_id,
        genesis_block.block_identifier.hash.clone(),
    )
    .await;

    // Both blocks should be the same
    assert_eq!(
        genesis_block, genesis_block_by_hash,
        "Genesis by hash or by index should be the same"
    );

    // Responses should be idempotent
    let idempotent_block = get_block(&rosetta_client, chain_id, 0).await;
    assert_eq!(
        idempotent_block, genesis_block_by_hash,
        "Blocks should be idempotent"
    );

    // Block 1 is always a reconfig with exactly 1 txn
    let block_1 = get_block(&rosetta_client, chain_id, 1).await;
    assert_eq!(1, block_1.transactions.len());
    // Block metadata won't have operations
    assert!(block_1.transactions.first().unwrap().operations.is_empty());
    assert!(block_1.timestamp > genesis_block.timestamp);

    // Block 2 is always a standard block with 2 or more txns
    let block_2 = get_block(&rosetta_client, chain_id, 2).await;
    assert!(block_2.transactions.len() >= 2);
    // Block metadata won't have operations
    assert!(block_2.transactions.first().unwrap().operations.is_empty());
    // StateCheckpoint won't have operations
    assert!(block_2.transactions.last().unwrap().operations.is_empty());
    assert!(block_2.timestamp >= block_1.timestamp);

    // No input should give the latest version, not the genesis txn
    let request_latest = BlockRequest::latest(chain_id);
    let latest_block = rosetta_client
        .block(&request_latest)
        .await
        .unwrap()
        .block
        .unwrap();

    // The latest block should always come after genesis
    assert!(latest_block.block_identifier.index >= block_2.block_identifier.index);
    assert!(latest_block.timestamp >= block_2.timestamp);

    // The parent should always be exactly one version before
    assert_eq!(
        latest_block.parent_block_identifier.index,
        latest_block.block_identifier.index - 1
    );

    // There should be at least 1 txn
    assert!(!latest_block.transactions.is_empty());

    // We should be able to query it again by hash or by version and it is the same
    let latest_block_by_version = get_block(
        &rosetta_client,
        chain_id,
        latest_block.block_identifier.index,
    )
    .await;
    let latest_block_by_hash = get_block_by_hash(
        &rosetta_client,
        chain_id,
        latest_block.block_identifier.hash.clone(),
    )
    .await;

    assert_eq!(latest_block, latest_block_by_version);
    assert_eq!(latest_block_by_hash, latest_block_by_version);

    // Wait until we get a new block processed
    let network_request = NetworkRequest {
        network_identifier: NetworkIdentifier::from(chain_id),
    };

    let start = Instant::now();
    let max_wait = Duration::from_secs(1);
    let mut successful = false;
    while start.elapsed() < max_wait {
        if rosetta_client
            .network_status(&network_request)
            .await
            .unwrap()
            .current_block_identifier
            .index
            == latest_block.block_identifier.index
        {
            successful = true;
            break;
        }
        tokio::time::sleep(Duration::from_micros(10)).await
    }

    assert!(successful, "Failed to get the next block");

    // And querying latest again should get yet another transaction in the future
    let newer_block = rosetta_client
        .block(&request_latest)
        .await
        .unwrap()
        .block
        .unwrap();
    assert!(newer_block.block_identifier.index >= latest_block.block_identifier.index);
    assert!(newer_block.timestamp >= latest_block.timestamp);
}

fn assert_genesis_block(block: &Block) {
    assert_eq!(
        block.block_identifier, block.parent_block_identifier,
        "The genesis block is also it's own parent"
    );
    assert_eq!(
        HashValue::zero().to_hex(),
        block.block_identifier.hash,
        "The genesis block hash is always 0s"
    );
    assert_eq!(
        0, block.block_identifier.index,
        "The genesis block index is always 0"
    );

    assert_eq!(
        Y2K_MS, block.timestamp,
        "The genesis timestamp should be Y2K seconds"
    );
    assert_eq!(
        1,
        block.transactions.len(),
        "The genesis block should be exactly 1 transaction"
    );

    let genesis_txn = block.transactions.first().unwrap();
    assert_eq!(
        0,
        genesis_txn.metadata.unwrap().version.0,
        "Genesis version should be 0"
    );
    assert_ne!(
        HashValue::zero().to_hex(),
        genesis_txn.transaction_identifier.hash,
        "Genesis should have a txn hash"
    );

    assert!(
        !genesis_txn.operations.is_empty(),
        "There should be at least one operation in genesis"
    );
}

async fn get_block(rosetta_client: &RosettaClient, chain_id: ChainId, index: u64) -> Block {
    let rosetta_client = (*rosetta_client).clone();
    let request = BlockRequest::by_index(chain_id, index);
    try_until_ok_default(|| rosetta_client.block(&request))
        .await
        .unwrap()
        .block
        .unwrap()
}

async fn get_block_by_hash(
    rosetta_client: &RosettaClient,
    chain_id: ChainId,
    hash: String,
) -> Block {
    let rosetta_client = (*rosetta_client).clone();
    let request = BlockRequest::by_hash(chain_id, hash);
    try_until_ok_default(|| rosetta_client.block(&request))
        .await
        .unwrap()
        .block
        .unwrap()
}

/// Try for 2 seconds to get a response.  This handles the fact that it's starting async
async fn try_until_ok_default<F, Fut, T>(function: F) -> anyhow::Result<T>
where
    F: Fn() -> Fut,
    Fut: Future<Output = anyhow::Result<T>>,
{
    try_until_ok(
        DEFAULT_MAX_WAIT_DURATION,
        DEFAULT_INTERVAL_DURATION,
        function,
    )
    .await
}

async fn try_until_ok<F, Fut, T>(
    total_wait: Duration,
    interval: Duration,
    function: F,
) -> anyhow::Result<T>
where
    F: Fn() -> Fut,
    Fut: Future<Output = anyhow::Result<T>>,
{
    let mut result = Err(anyhow::Error::msg("Failed to get response"));
    let start = Instant::now();
    while start.elapsed() < total_wait {
        result = function().await;
        if result.is_ok() {
            break;
        }
        tokio::time::sleep(interval).await;
    }

    result
}
<commit_msg>[testsuite] Re-enable rosetta block test<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::aptos_cli::setup_cli_test;
use anyhow::anyhow;
use aptos::{account::create::DEFAULT_FUNDED_COINS, test::CliTestFramework};
use aptos_config::{config::ApiConfig, utils::get_available_port};
use aptos_crypto::HashValue;
use aptos_rosetta::{
    client::RosettaClient,
    common::{native_coin, BLOCKCHAIN, Y2K_MS},
    types::{
        AccountBalanceRequest, AccountBalanceResponse, Block, BlockIdentifier, BlockRequest,
        NetworkIdentifier, NetworkRequest, PartialBlockIdentifier,
    },
    ROSETTA_VERSION,
};
use aptos_types::{account_address::AccountAddress, chain_id::ChainId};
use forge::{LocalSwarm, Node};
use std::{future::Future, time::Duration};
use tokio::{task::JoinHandle, time::Instant};

const DEFAULT_MAX_WAIT_MS: u64 = 5000;
const DEFAULT_INTERVAL_MS: u64 = 100;
static DEFAULT_MAX_WAIT_DURATION: Duration = Duration::from_millis(DEFAULT_MAX_WAIT_MS);
static DEFAULT_INTERVAL_DURATION: Duration = Duration::from_millis(DEFAULT_INTERVAL_MS);

pub async fn setup_test(
    num_nodes: usize,
    num_accounts: usize,
) -> (LocalSwarm, CliTestFramework, JoinHandle<()>, RosettaClient) {
    let (swarm, cli, faucet) = setup_cli_test(num_nodes, num_accounts).await;
    let validator = swarm.validators().next().unwrap();

    // And the client
    let rosetta_port = get_available_port();
    let rosetta_socket_addr = format!("127.0.0.1:{}", rosetta_port);
    let rosetta_url = format!("http://{}", rosetta_socket_addr.clone())
        .parse()
        .unwrap();
    let rosetta_client = RosettaClient::new(rosetta_url);
    let api_config = ApiConfig {
        enabled: true,
        address: rosetta_socket_addr.parse().unwrap(),
        tls_cert_path: None,
        tls_key_path: None,
        content_length_limit: None,
    };

    // Start the server
    let _rosetta = aptos_rosetta::bootstrap_async(
        swarm.chain_id(),
        api_config,
        Some(aptos_rest_client::Client::new(
            validator.rest_api_endpoint(),
        )),
    )
    .await
    .unwrap();

    // Ensure rosetta can take requests
    try_until_ok_default(|| rosetta_client.network_list())
        .await
        .unwrap();

    (swarm, cli, faucet, rosetta_client)
}

#[tokio::test]
async fn test_network() {
    let (swarm, _, _, rosetta_client) = setup_test(1, 1).await;
    let chain_id = swarm.chain_id();

    // We only support one network, this network
    let networks = try_until_ok_default(|| rosetta_client.network_list())
        .await
        .unwrap();
    assert_eq!(1, networks.network_identifiers.len());
    let network_id = networks.network_identifiers.first().unwrap();
    assert_eq!(BLOCKCHAIN, network_id.blockchain);
    assert_eq!(chain_id.to_string(), network_id.network);

    let request = NetworkRequest {
        network_identifier: NetworkIdentifier::from(chain_id),
    };
    let options = rosetta_client.network_options(&request).await.unwrap();
    assert_eq!(ROSETTA_VERSION, options.version.rosetta_version);

    // TODO: Check other options

    let request = NetworkRequest {
        network_identifier: NetworkIdentifier::from(chain_id),
    };
    let status = rosetta_client.network_status(&request).await.unwrap();
    assert!(status.current_block_identifier.index > 0);
    assert!(status.current_block_timestamp > Y2K_MS);
    assert_eq!(
        BlockIdentifier {
            index: 0,
            hash: HashValue::zero().to_hex()
        },
        status.genesis_block_identifier
    );
    assert_eq!(
        Some(status.genesis_block_identifier),
        status.oldest_block_identifier,
    );
}

#[tokio::test]
async fn test_account_balance() {
    let (swarm, cli, _faucet, rosetta_client) = setup_test(1, 2).await;

    let account_1 = cli.account_id(0);
    let account_2 = cli.account_id(1);
    let chain_id = swarm.chain_id();

    // At time 0, there should be 0 balance
    let response = get_balance(&rosetta_client, chain_id, account_1, Some(0))
        .await
        .unwrap();
    assert_eq!(
        response.block_identifier,
        BlockIdentifier {
            index: 0,
            hash: HashValue::zero().to_hex(),
        }
    );

    // At some time both accounts should exist with initial amounts
    try_until_ok(Duration::from_secs(5), DEFAULT_INTERVAL_DURATION, || {
        account_has_balance(&rosetta_client, chain_id, account_1, DEFAULT_FUNDED_COINS)
    })
    .await
    .unwrap();
    try_until_ok_default(|| {
        account_has_balance(&rosetta_client, chain_id, account_2, DEFAULT_FUNDED_COINS)
    })
    .await
    .unwrap();

    // Send money, and expect the gas and fees to show up accordingly
    const TRANSFER_AMOUNT: u64 = 5000;
    let response = cli.transfer_coins(0, 1, TRANSFER_AMOUNT).await.unwrap();
    let gas_used = response.gas_used.unwrap();

    account_has_balance(
        &rosetta_client,
        chain_id,
        account_1,
        DEFAULT_FUNDED_COINS - TRANSFER_AMOUNT - gas_used,
    )
    .await
    .unwrap();
    account_has_balance(
        &rosetta_client,
        chain_id,
        account_2,
        DEFAULT_FUNDED_COINS + TRANSFER_AMOUNT,
    )
    .await
    .unwrap();

    // TODO: Make a bad transaction, which will cause gas to be spent but no transfer
}

async fn account_has_balance(
    rosetta_client: &RosettaClient,
    chain_id: ChainId,
    account: AccountAddress,
    expected_balance: u64,
) -> anyhow::Result<u64> {
    let response = get_balance(rosetta_client, chain_id, account, None).await?;

    if response.balances.iter().any(|amount| {
        amount.currency == native_coin() && amount.value == expected_balance.to_string()
    }) {
        Ok(response.block_identifier.index)
    } else {
        Err(anyhow!(
            "Failed to find account with {} {:?}, received {:?}",
            expected_balance,
            native_coin(),
            response
        ))
    }
}

async fn get_balance(
    rosetta_client: &RosettaClient,
    chain_id: ChainId,
    account: AccountAddress,
    index: Option<u64>,
) -> anyhow::Result<AccountBalanceResponse> {
    let request = AccountBalanceRequest {
        network_identifier: chain_id.into(),
        account_identifier: account.into(),
        block_identifier: Some(PartialBlockIdentifier { index, hash: None }),
        currencies: Some(vec![native_coin()]),
    };
    try_until_ok_default(|| rosetta_client.account_balance(&request)).await
}

#[tokio::test]
async fn test_block() {
    let (swarm, _cli, _faucet, rosetta_client) = setup_test(1, 0).await;
    let chain_id = swarm.chain_id();

    // Genesis by version
    let genesis_block = get_block(&rosetta_client, chain_id, 0).await;
    assert_genesis_block(&genesis_block);

    // Get genesis txn by hash
    let genesis_block_by_hash = get_block_by_hash(
        &rosetta_client,
        chain_id,
        genesis_block.block_identifier.hash.clone(),
    )
    .await;

    // Both blocks should be the same
    assert_eq!(
        genesis_block, genesis_block_by_hash,
        "Genesis by hash or by index should be the same"
    );

    // Responses should be idempotent
    let idempotent_block = get_block(&rosetta_client, chain_id, 0).await;
    assert_eq!(
        idempotent_block, genesis_block_by_hash,
        "Blocks should be idempotent"
    );

    // Block 1 is always a reconfig with exactly 1 txn
    let block_1 = get_block(&rosetta_client, chain_id, 1).await;
    assert_eq!(1, block_1.transactions.len());
    // Block metadata won't have operations
    assert!(block_1.transactions.first().unwrap().operations.is_empty());
    assert!(block_1.timestamp > genesis_block.timestamp);

    // Block 2 is always a standard block with 2 or more txns
    let block_2 = get_block(&rosetta_client, chain_id, 2).await;
    assert!(block_2.transactions.len() >= 2);
    // Block metadata won't have operations
    assert!(block_2.transactions.first().unwrap().operations.is_empty());
    // StateCheckpoint won't have operations
    assert!(block_2.transactions.last().unwrap().operations.is_empty());
    assert!(block_2.timestamp >= block_1.timestamp);

    // No input should give the latest version, not the genesis txn
    let request_latest = BlockRequest::latest(chain_id);
    let latest_block = rosetta_client
        .block(&request_latest)
        .await
        .unwrap()
        .block
        .unwrap();

    // The latest block should always come after genesis
    assert!(latest_block.block_identifier.index >= block_2.block_identifier.index);
    assert!(latest_block.timestamp >= block_2.timestamp);

    // The parent should always be exactly one version before
    assert_eq!(
        latest_block.parent_block_identifier.index,
        latest_block.block_identifier.index - 1
    );

    // There should be at least 1 txn
    assert!(!latest_block.transactions.is_empty());

    // We should be able to query it again by hash or by version and it is the same
    let latest_block_by_version = get_block(
        &rosetta_client,
        chain_id,
        latest_block.block_identifier.index,
    )
    .await;
    let latest_block_by_hash = get_block_by_hash(
        &rosetta_client,
        chain_id,
        latest_block.block_identifier.hash.clone(),
    )
    .await;

    assert_eq!(latest_block, latest_block_by_version);
    assert_eq!(latest_block_by_hash, latest_block_by_version);

    // Wait until we get a new block processed
    let network_request = NetworkRequest {
        network_identifier: NetworkIdentifier::from(chain_id),
    };

    let start = Instant::now();
    let max_wait = Duration::from_secs(1);
    let mut successful = false;
    while start.elapsed() < max_wait {
        if rosetta_client
            .network_status(&network_request)
            .await
            .unwrap()
            .current_block_identifier
            .index
            == latest_block.block_identifier.index
        {
            successful = true;
            break;
        }
        tokio::time::sleep(Duration::from_micros(10)).await
    }

    assert!(successful, "Failed to get the next block");

    // And querying latest again should get yet another transaction in the future
    let newer_block = rosetta_client
        .block(&request_latest)
        .await
        .unwrap()
        .block
        .unwrap();
    assert!(newer_block.block_identifier.index >= latest_block.block_identifier.index);
    assert!(newer_block.timestamp >= latest_block.timestamp);
}

fn assert_genesis_block(block: &Block) {
    assert_eq!(
        block.block_identifier, block.parent_block_identifier,
        "The genesis block is also it's own parent"
    );
    assert_eq!(
        HashValue::zero().to_hex(),
        block.block_identifier.hash,
        "The genesis block hash is always 0s"
    );
    assert_eq!(
        0, block.block_identifier.index,
        "The genesis block index is always 0"
    );

    assert_eq!(
        Y2K_MS, block.timestamp,
        "The genesis timestamp should be Y2K seconds"
    );
    assert_eq!(
        1,
        block.transactions.len(),
        "The genesis block should be exactly 1 transaction"
    );

    let genesis_txn = block.transactions.first().unwrap();
    assert_eq!(
        0,
        genesis_txn.metadata.unwrap().version.0,
        "Genesis version should be 0"
    );
    assert_ne!(
        HashValue::zero().to_hex(),
        genesis_txn.transaction_identifier.hash,
        "Genesis should have a txn hash"
    );

    assert!(
        !genesis_txn.operations.is_empty(),
        "There should be at least one operation in genesis"
    );
}

async fn get_block(rosetta_client: &RosettaClient, chain_id: ChainId, index: u64) -> Block {
    let rosetta_client = (*rosetta_client).clone();
    let request = BlockRequest::by_index(chain_id, index);
    try_until_ok_default(|| rosetta_client.block(&request))
        .await
        .unwrap()
        .block
        .unwrap()
}

async fn get_block_by_hash(
    rosetta_client: &RosettaClient,
    chain_id: ChainId,
    hash: String,
) -> Block {
    let rosetta_client = (*rosetta_client).clone();
    let request = BlockRequest::by_hash(chain_id, hash);
    try_until_ok_default(|| rosetta_client.block(&request))
        .await
        .unwrap()
        .block
        .unwrap()
}

/// Try for 2 seconds to get a response.  This handles the fact that it's starting async
async fn try_until_ok_default<F, Fut, T>(function: F) -> anyhow::Result<T>
where
    F: Fn() -> Fut,
    Fut: Future<Output = anyhow::Result<T>>,
{
    try_until_ok(
        DEFAULT_MAX_WAIT_DURATION,
        DEFAULT_INTERVAL_DURATION,
        function,
    )
    .await
}

async fn try_until_ok<F, Fut, T>(
    total_wait: Duration,
    interval: Duration,
    function: F,
) -> anyhow::Result<T>
where
    F: Fn() -> Fut,
    Fut: Future<Output = anyhow::Result<T>>,
{
    let mut result = Err(anyhow::Error::msg("Failed to get response"));
    let start = Instant::now();
    while start.elapsed() < total_wait {
        result = function().await;
        if result.is_ok() {
            break;
        }
        tokio::time::sleep(interval).await;
    }

    result
}
<|endoftext|>


<commit_before>#![cfg(feature = "ec2-instance-connect")]

extern crate rusoto_core;
extern crate rusoto_ec2_instance_connect;

use rusoto_core::{Region, RusotoError};
use rusoto_ec2_instance_connect::{
    Ec2InstanceConnect, Ec2InstanceConnectClient, SendSSHPublicKeyError, SendSSHPublicKeyRequest,
};

#[tokio::test]
async fn send_ssh_public_key_correctly_errors_for_unknown_instance() {
    let client = Ec2InstanceConnectClient::new(Region::UsEast1);
    let request = SendSSHPublicKeyRequest {
        availability_zone: "us-east-1a".into(),
        instance_id: "i-00000000".into(),
        instance_os_user: "ec2-user".into(),
        ssh_public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+P68X1LG5rJXQL1ktjhMv84lP8gKgJoPk99GwWoM6lbJAv80WUgauB961I5i/3/Y0XWnYZfzFCP3+fTu/9+vEsfTd38hUW3QBGTPrx/jXyvTBRQc7bTirpeicfwL9SwM4ztYvuM45sGSeZkQIg+TMKVFGnR0ijCitG613fRP/NUw/jQjzUPj2ymCw43MIAD1BPQrznsyoaPWP/bKv91Y9ZtB1fOn3UzgWlwBGxzPNXx8boquLfHWi+ut+v1zfZpUBUjQtI4EIctjqzmxnyB1SPpxk0r5v2GR0qLChKzZ0IqdJmImlz2vqCuwUThJN9d/iF//kCeb76uJVsDOOtDWb user@host".into(),
    };

    match client.send_ssh_public_key(request).await {
        Ok(_) => {
            panic!("send_ssh_public_key should fail");
        }
        Err(error) => match error {
            RusotoError::Service(e) => match e {
                SendSSHPublicKeyError::InvalidArgs(error) => assert!(
                    error.contains("Instance not found"),
                    "Missing error message"
                ),
                _ => panic!("Unexpected error"),
            },
            _ => {
                panic!("Should have a typed error from EC2 Instance Connect");
            }
        },
    };
}
<commit_msg>integration_tests: update ec2 error assertion<commit_after>#![cfg(feature = "ec2-instance-connect")]

extern crate rusoto_core;
extern crate rusoto_ec2_instance_connect;

use rusoto_core::{Region, RusotoError};
use rusoto_ec2_instance_connect::{
    Ec2InstanceConnect, Ec2InstanceConnectClient, SendSSHPublicKeyError, SendSSHPublicKeyRequest,
};

#[tokio::test]
async fn send_ssh_public_key_correctly_errors_for_unknown_instance() {
    let client = Ec2InstanceConnectClient::new(Region::UsEast1);
    let request = SendSSHPublicKeyRequest {
        availability_zone: "us-east-1a".into(),
        instance_id: "i-00000000".into(),
        instance_os_user: "ec2-user".into(),
        ssh_public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+P68X1LG5rJXQL1ktjhMv84lP8gKgJoPk99GwWoM6lbJAv80WUgauB961I5i/3/Y0XWnYZfzFCP3+fTu/9+vEsfTd38hUW3QBGTPrx/jXyvTBRQc7bTirpeicfwL9SwM4ztYvuM45sGSeZkQIg+TMKVFGnR0ijCitG613fRP/NUw/jQjzUPj2ymCw43MIAD1BPQrznsyoaPWP/bKv91Y9ZtB1fOn3UzgWlwBGxzPNXx8boquLfHWi+ut+v1zfZpUBUjQtI4EIctjqzmxnyB1SPpxk0r5v2GR0qLChKzZ0IqdJmImlz2vqCuwUThJN9d/iF//kCeb76uJVsDOOtDWb user@host".into(),
    };

    match client.send_ssh_public_key(request).await {
        Ok(_) => {
            panic!("send_ssh_public_key should fail");
        }
        Err(error) => match error {
            RusotoError::Service(e) => match e {
                SendSSHPublicKeyError::EC2InstanceNotFound(error) => assert!(
                    error.contains("Instance not found"),
                    "Missing error message"
                ),
                _ => panic!("Unexpected error"),
            },
            _ => {
                panic!("Should have a typed error from EC2 Instance Connect");
            }
        },
    };
}
<|endoftext|>


<commit_before>use collect_slice::CollectSlice;

use bits::{Dibit, DibitBytes};
use buffer::{Buffer, DataPayloadStorage};
use coding::trellis;
use data::{crc, interleave};
use error::{Result, P25Error};

use trunking::decode::*;

pub struct TSBKReceiver {
    dibits: Buffer<DataPayloadStorage>,
}

impl TSBKReceiver {
    pub fn new() -> TSBKReceiver {
        TSBKReceiver {
            dibits: Buffer::new(DataPayloadStorage::new()),
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<TSBKFields>> {
        let (count, dibits) = {
            let buf = match self.dibits.feed(dibit) {
                Some(buf) => buf,
                None => return None,
            };

            let mut dibits = [Dibit::default(); 48];
            let count = trellis::DibitDecoder::new(interleave::Deinterleaver::new(buf))
                .filter(|x| x.is_ok()).map(|x| x.unwrap())
                .collect_slice(&mut dibits[..]);

            (count, dibits)
        };

        self.dibits.reset();

        if count != dibits.len() {
            return Some(Err(P25Error::ViterbiUnrecoverable));
        }

        let mut bytes = [0; 12];
        DibitBytes::new(dibits.iter().cloned()).collect_slice_checked(&mut bytes[..]);

        Some(Ok(TSBKFields::new(bytes)))
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TSBKOpcode {
    GroupVoiceGrant,
    GroupVoiceUpdate,
    GroupVoiceUpdateExplicit,
    UnitVoiceGrant,
    UnitCallRequest,
    UnitVoiceUpdate,
    PhoneGrant,
    PhoneCallRequest,
    UnitDataGrant,
    GroupDataGrant,
    GroupDataAnnounce,
    GroupDataAnnounceExplicit,
    UnitStatusUpdate,
    UnitStatusQuery,
    UnitShortMessage,
    UnitMonitor,
    UnitCallAlert,
    AckResponse,
    QueuedResponse,
    ExtendedFunctionResponse,
    DenyResponse,
    GroupAffiliationResponse,
    GroupAffiliationQuery,
    LocRegistrationResponse,
    UnitRegistrationResponse,
    UnitRegistrationCommand,
    AuthCommand,
    DeregistrationAck,
    RoamingAddrCommand,
    RoamingAddrUpdate,
    SystemServiceBroadcast,
    AltControlBroadcast,
    RFSSStatusBroadcast,
    NetworkStatusBroadcast,
    AdjacentSiteBroadcast,
    ChannelParamsUpdate,
    ProtectionParamBroadcast,
    ProtectionParamUpdate,
    Reserved,
}

impl TSBKOpcode {
    pub fn from_bits(bits: u8) -> Option<TSBKOpcode> {
        use self::TSBKOpcode::*;

        match bits {
            0b000000 => Some(GroupVoiceGrant),
            0b000001 => Some(Reserved),
            0b000010 => Some(GroupVoiceUpdate),
            0b000011 => Some(GroupVoiceUpdateExplicit),
            0b000100 => Some(UnitVoiceGrant),
            0b000101 => Some(UnitCallRequest),
            0b000110 => Some(UnitVoiceUpdate),
            0b000111 => Some(Reserved),

            0b001000 => Some(PhoneGrant),
            0b001001 => Some(Reserved),
            0b001010 => Some(PhoneCallRequest),
            0b001011...0b001111 => Some(Reserved),

            0b010000 => Some(UnitDataGrant),
            0b010001 => Some(GroupDataGrant),
            0b010010 => Some(GroupDataAnnounce),
            0b010011 => Some(GroupDataAnnounceExplicit),
            0b010100...0b010111 => Some(Reserved),

            0b011000 => Some(UnitStatusUpdate),
            0b011001 => Some(Reserved),
            0b011010 => Some(UnitStatusQuery),
            0b011011 => Some(Reserved),
            0b011100 => Some(UnitShortMessage),
            0b011101 => Some(UnitMonitor),
            0b011110 => Some(Reserved),
            0b011111 => Some(UnitCallAlert),
            0b100000 => Some(AckResponse),
            0b100001 => Some(QueuedResponse),
            0b100010 => Some(Reserved),
            0b100011 => Some(Reserved),
            0b100100 => Some(ExtendedFunctionResponse),
            0b100101 => Some(Reserved),
            0b100110 => Some(Reserved),
            0b100111 => Some(DenyResponse),

            0b101000 => Some(GroupAffiliationResponse),
            0b101001 => Some(Reserved),
            0b101010 => Some(GroupAffiliationQuery),
            0b101011 => Some(LocRegistrationResponse),
            0b101100 => Some(UnitRegistrationResponse),
            0b101101 => Some(UnitRegistrationCommand),
            0b101110 => Some(AuthCommand),
            0b101111 => Some(DeregistrationAck),

            0b110000...0b110101 => Some(Reserved),
            0b110110 => Some(RoamingAddrCommand),
            0b110111 => Some(RoamingAddrUpdate),

            0b111000 => Some(SystemServiceBroadcast),
            0b111001 => Some(AltControlBroadcast),
            0b111010 => Some(RFSSStatusBroadcast),
            0b111011 => Some(NetworkStatusBroadcast),
            0b111100 => Some(AdjacentSiteBroadcast),
            0b111101 => Some(ChannelParamsUpdate),
            0b111110 => Some(ProtectionParamBroadcast),
            0b111111 => Some(ProtectionParamUpdate),

            _ => None,
        }
    }
}

pub type Buf = [u8; 12];

#[derive(Copy, Clone)]
pub struct TSBKFields(Buf);

impl TSBKFields {
    pub fn new(buf: Buf) -> TSBKFields { TSBKFields(buf) }

    pub fn is_tail(&self) -> bool { self.0[0] >> 7 == 1 }
    pub fn protected(&self) -> bool { self.0[0] >> 6 & 1 == 1 }
    pub fn opcode(&self) -> Option<TSBKOpcode> { TSBKOpcode::from_bits(self.0[0] & 0x3F) }
    pub fn mfg(&self) -> u8 { self.0[1] }
    pub fn crc(&self) -> u16 { slice_u16(&self.0[10..]) }

    pub fn calc_crc(&self) -> u16 {
        crc::CRC16::new()
            .feed_bytes((&self.0[..10]).iter().cloned())
            .finish() as u16
    }
}

pub struct GroupVoiceGrant(Buf);

impl GroupVoiceGrant {
    pub fn new(tsbk: TSBKFields) -> Self { GroupVoiceGrant(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[5..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct GroupVoiceUpdate(Buf);

impl GroupVoiceUpdate {
    pub fn new(tsbk: TSBKFields) -> Self { GroupVoiceUpdate(tsbk.0) }

    pub fn channel_a(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn talk_group_a(&self) -> TalkGroup { TalkGroup::new(&self.0[4..]) }
    pub fn channel_b(&self) -> Channel { Channel::new(&self.0[6..]) }
    pub fn talk_group_b(&self) -> TalkGroup { TalkGroup::new(&self.0[8..]) }
}

pub struct GroupVoiceUpdateExplicit(Buf);

impl GroupVoiceUpdateExplicit {
    pub fn new(tsbk: TSBKFields) -> Self { GroupVoiceUpdateExplicit(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn tx_channel(&self) -> Channel { Channel::new(&self.0[4..]) }
    pub fn rx_channel(&self) -> Channel { Channel::new(&self.0[6..]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[8..]) }
}

pub struct UnitVoiceGrant(Buf);

impl UnitVoiceGrant {
    pub fn new(tsbk: TSBKFields) -> Self { UnitVoiceGrant(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitCallRequest(Buf);

impl UnitCallRequest {
    pub fn new(tsbk: TSBKFields) -> Self { UnitCallRequest(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_id(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitVoiceUpdate(Buf);

impl UnitVoiceUpdate {
    pub fn new(tsbk: TSBKFields) -> Self { UnitVoiceUpdate(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct PhoneGrant(Buf);

impl PhoneGrant {
    pub fn new(tsbk: TSBKFields) -> Self { PhoneGrant(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[3..]) }
    pub fn call_timer(&self) -> u16 { slice_u16(&self.0[5..]) }
    pub fn unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitDataGrant(Buf);

impl UnitDataGrant {
    pub fn new(tsbk: TSBKFields) -> Self { UnitDataGrant(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}
pub struct AltControlBroadcast(Buf);

impl AltControlBroadcast {
    pub fn new(tsbk: TSBKFields) -> Self { AltControlBroadcast(tsbk.0) }

    pub fn rfss(&self) -> u8 { self.0[2] }
    pub fn site(&self) -> u8 { self.0[3] }

    pub fn channel_a(&self) -> Channel { Channel::new(&self.0[4..]) }
    pub fn services_a(&self) -> SystemServices { SystemServices::new(self.0[6]) }

    pub fn channel_b(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn serviced_b(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct NetworkStatusBroadcast(Buf);

impl NetworkStatusBroadcast {
    pub fn new(tsbk: TSBKFields) -> Self { NetworkStatusBroadcast(tsbk.0) }

    pub fn area(&self) -> u8 { self.0[2] }
    pub fn wacn(&self) -> u32 { slice_u24(&self.0[3..]) >> 4 }
    pub fn system(&self) -> u16 { slice_u16(&self.0[5..]) & 0xFFF }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct SiteStatusBroadcast(Buf);

impl SiteStatusBroadcast {
    pub fn new(tsbk: TSBKFields) -> Self { SiteStatusBroadcast(tsbk.0) }

    pub fn area(&self) -> u8 { self.0[2] }
    pub fn is_conventional(&self) -> bool { self.0[3] & 0x80 != 0 }
    pub fn is_down(&self) -> bool { self.0[3] & 0x40 != 0 }
    pub fn is_current(&self) -> bool { self.0[3] & 0x20 != 0 }
    pub fn has_network(&self) -> bool { self.0[3] & 0x10 != 0 }
    pub fn system(&self) -> u16 { slice_u16(&self.0[3..]) & 0xFFF }
    pub fn rfss(&self) -> u8 { self.0[5] }
    pub fn site(&self) -> u8 { self.0[6] }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct ChannelParamsUpdate(Buf);

impl ChannelParamsUpdate {
    pub fn new(tsbk: TSBKFields) -> Self { ChannelParamsUpdate(tsbk.0) }

    pub fn params(&self) -> ChannelParams {
        ChannelParams::new(self.base_freq(), self.channel(), self.bandwidth(),
                           self.offset(), self.spacing())
    }

    fn channel(&self) -> u8 { self.0[2] >> 4 }
    fn bandwidth(&self) -> u16 {
        (self.0[2] as u16 & 0xF) << 5 | (self.0[3] >> 3) as u16
    }
    fn offset(&self) -> u16 {
        (self.0[3] as u16 & 0x7) << 6 | (self.0[4] >> 2) as u16
    }
    fn spacing(&self) -> u16 {
        (self.0[4] as u16 & 0x3) << 8 | self.0[5] as u16
    }
    fn base_freq(&self) -> u32 { slice_u32(&self.0[6..]) }
}
<commit_msg>Use filter_map in TSBKReceiver<commit_after>use collect_slice::CollectSlice;

use bits::{Dibit, DibitBytes};
use buffer::{Buffer, DataPayloadStorage};
use coding::trellis;
use data::{crc, interleave};
use error::{Result, P25Error};

use trunking::decode::*;

pub struct TSBKReceiver {
    dibits: Buffer<DataPayloadStorage>,
}

impl TSBKReceiver {
    pub fn new() -> TSBKReceiver {
        TSBKReceiver {
            dibits: Buffer::new(DataPayloadStorage::new()),
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<TSBKFields>> {
        let (count, dibits) = {
            let buf = match self.dibits.feed(dibit) {
                Some(buf) => buf,
                None => return None,
            };

            let mut dibits = [Dibit::default(); 48];
            let count = trellis::DibitDecoder::new(interleave::Deinterleaver::new(buf))
                .filter_map(|x| x.ok())
                .collect_slice(&mut dibits[..]);

            (count, dibits)
        };

        self.dibits.reset();

        if count != dibits.len() {
            return Some(Err(P25Error::ViterbiUnrecoverable));
        }

        let mut bytes = [0; 12];
        DibitBytes::new(dibits.iter().cloned()).collect_slice_checked(&mut bytes[..]);

        Some(Ok(TSBKFields::new(bytes)))
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TSBKOpcode {
    GroupVoiceGrant,
    GroupVoiceUpdate,
    GroupVoiceUpdateExplicit,
    UnitVoiceGrant,
    UnitCallRequest,
    UnitVoiceUpdate,
    PhoneGrant,
    PhoneCallRequest,
    UnitDataGrant,
    GroupDataGrant,
    GroupDataAnnounce,
    GroupDataAnnounceExplicit,
    UnitStatusUpdate,
    UnitStatusQuery,
    UnitShortMessage,
    UnitMonitor,
    UnitCallAlert,
    AckResponse,
    QueuedResponse,
    ExtendedFunctionResponse,
    DenyResponse,
    GroupAffiliationResponse,
    GroupAffiliationQuery,
    LocRegistrationResponse,
    UnitRegistrationResponse,
    UnitRegistrationCommand,
    AuthCommand,
    DeregistrationAck,
    RoamingAddrCommand,
    RoamingAddrUpdate,
    SystemServiceBroadcast,
    AltControlBroadcast,
    RFSSStatusBroadcast,
    NetworkStatusBroadcast,
    AdjacentSiteBroadcast,
    ChannelParamsUpdate,
    ProtectionParamBroadcast,
    ProtectionParamUpdate,
    Reserved,
}

impl TSBKOpcode {
    pub fn from_bits(bits: u8) -> Option<TSBKOpcode> {
        use self::TSBKOpcode::*;

        match bits {
            0b000000 => Some(GroupVoiceGrant),
            0b000001 => Some(Reserved),
            0b000010 => Some(GroupVoiceUpdate),
            0b000011 => Some(GroupVoiceUpdateExplicit),
            0b000100 => Some(UnitVoiceGrant),
            0b000101 => Some(UnitCallRequest),
            0b000110 => Some(UnitVoiceUpdate),
            0b000111 => Some(Reserved),

            0b001000 => Some(PhoneGrant),
            0b001001 => Some(Reserved),
            0b001010 => Some(PhoneCallRequest),
            0b001011...0b001111 => Some(Reserved),

            0b010000 => Some(UnitDataGrant),
            0b010001 => Some(GroupDataGrant),
            0b010010 => Some(GroupDataAnnounce),
            0b010011 => Some(GroupDataAnnounceExplicit),
            0b010100...0b010111 => Some(Reserved),

            0b011000 => Some(UnitStatusUpdate),
            0b011001 => Some(Reserved),
            0b011010 => Some(UnitStatusQuery),
            0b011011 => Some(Reserved),
            0b011100 => Some(UnitShortMessage),
            0b011101 => Some(UnitMonitor),
            0b011110 => Some(Reserved),
            0b011111 => Some(UnitCallAlert),
            0b100000 => Some(AckResponse),
            0b100001 => Some(QueuedResponse),
            0b100010 => Some(Reserved),
            0b100011 => Some(Reserved),
            0b100100 => Some(ExtendedFunctionResponse),
            0b100101 => Some(Reserved),
            0b100110 => Some(Reserved),
            0b100111 => Some(DenyResponse),

            0b101000 => Some(GroupAffiliationResponse),
            0b101001 => Some(Reserved),
            0b101010 => Some(GroupAffiliationQuery),
            0b101011 => Some(LocRegistrationResponse),
            0b101100 => Some(UnitRegistrationResponse),
            0b101101 => Some(UnitRegistrationCommand),
            0b101110 => Some(AuthCommand),
            0b101111 => Some(DeregistrationAck),

            0b110000...0b110101 => Some(Reserved),
            0b110110 => Some(RoamingAddrCommand),
            0b110111 => Some(RoamingAddrUpdate),

            0b111000 => Some(SystemServiceBroadcast),
            0b111001 => Some(AltControlBroadcast),
            0b111010 => Some(RFSSStatusBroadcast),
            0b111011 => Some(NetworkStatusBroadcast),
            0b111100 => Some(AdjacentSiteBroadcast),
            0b111101 => Some(ChannelParamsUpdate),
            0b111110 => Some(ProtectionParamBroadcast),
            0b111111 => Some(ProtectionParamUpdate),

            _ => None,
        }
    }
}

pub type Buf = [u8; 12];

#[derive(Copy, Clone)]
pub struct TSBKFields(Buf);

impl TSBKFields {
    pub fn new(buf: Buf) -> TSBKFields { TSBKFields(buf) }

    pub fn is_tail(&self) -> bool { self.0[0] >> 7 == 1 }
    pub fn protected(&self) -> bool { self.0[0] >> 6 & 1 == 1 }
    pub fn opcode(&self) -> Option<TSBKOpcode> { TSBKOpcode::from_bits(self.0[0] & 0x3F) }
    pub fn mfg(&self) -> u8 { self.0[1] }
    pub fn crc(&self) -> u16 { slice_u16(&self.0[10..]) }

    pub fn calc_crc(&self) -> u16 {
        crc::CRC16::new()
            .feed_bytes((&self.0[..10]).iter().cloned())
            .finish() as u16
    }
}

pub struct GroupVoiceGrant(Buf);

impl GroupVoiceGrant {
    pub fn new(tsbk: TSBKFields) -> Self { GroupVoiceGrant(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[5..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct GroupVoiceUpdate(Buf);

impl GroupVoiceUpdate {
    pub fn new(tsbk: TSBKFields) -> Self { GroupVoiceUpdate(tsbk.0) }

    pub fn channel_a(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn talk_group_a(&self) -> TalkGroup { TalkGroup::new(&self.0[4..]) }
    pub fn channel_b(&self) -> Channel { Channel::new(&self.0[6..]) }
    pub fn talk_group_b(&self) -> TalkGroup { TalkGroup::new(&self.0[8..]) }
}

pub struct GroupVoiceUpdateExplicit(Buf);

impl GroupVoiceUpdateExplicit {
    pub fn new(tsbk: TSBKFields) -> Self { GroupVoiceUpdateExplicit(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn tx_channel(&self) -> Channel { Channel::new(&self.0[4..]) }
    pub fn rx_channel(&self) -> Channel { Channel::new(&self.0[6..]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[8..]) }
}

pub struct UnitVoiceGrant(Buf);

impl UnitVoiceGrant {
    pub fn new(tsbk: TSBKFields) -> Self { UnitVoiceGrant(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitCallRequest(Buf);

impl UnitCallRequest {
    pub fn new(tsbk: TSBKFields) -> Self { UnitCallRequest(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_id(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitVoiceUpdate(Buf);

impl UnitVoiceUpdate {
    pub fn new(tsbk: TSBKFields) -> Self { UnitVoiceUpdate(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct PhoneGrant(Buf);

impl PhoneGrant {
    pub fn new(tsbk: TSBKFields) -> Self { PhoneGrant(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[3..]) }
    pub fn call_timer(&self) -> u16 { slice_u16(&self.0[5..]) }
    pub fn unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitDataGrant(Buf);

impl UnitDataGrant {
    pub fn new(tsbk: TSBKFields) -> Self { UnitDataGrant(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}
pub struct AltControlBroadcast(Buf);

impl AltControlBroadcast {
    pub fn new(tsbk: TSBKFields) -> Self { AltControlBroadcast(tsbk.0) }

    pub fn rfss(&self) -> u8 { self.0[2] }
    pub fn site(&self) -> u8 { self.0[3] }

    pub fn channel_a(&self) -> Channel { Channel::new(&self.0[4..]) }
    pub fn services_a(&self) -> SystemServices { SystemServices::new(self.0[6]) }

    pub fn channel_b(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn serviced_b(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct NetworkStatusBroadcast(Buf);

impl NetworkStatusBroadcast {
    pub fn new(tsbk: TSBKFields) -> Self { NetworkStatusBroadcast(tsbk.0) }

    pub fn area(&self) -> u8 { self.0[2] }
    pub fn wacn(&self) -> u32 { slice_u24(&self.0[3..]) >> 4 }
    pub fn system(&self) -> u16 { slice_u16(&self.0[5..]) & 0xFFF }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct SiteStatusBroadcast(Buf);

impl SiteStatusBroadcast {
    pub fn new(tsbk: TSBKFields) -> Self { SiteStatusBroadcast(tsbk.0) }

    pub fn area(&self) -> u8 { self.0[2] }
    pub fn is_conventional(&self) -> bool { self.0[3] & 0x80 != 0 }
    pub fn is_down(&self) -> bool { self.0[3] & 0x40 != 0 }
    pub fn is_current(&self) -> bool { self.0[3] & 0x20 != 0 }
    pub fn has_network(&self) -> bool { self.0[3] & 0x10 != 0 }
    pub fn system(&self) -> u16 { slice_u16(&self.0[3..]) & 0xFFF }
    pub fn rfss(&self) -> u8 { self.0[5] }
    pub fn site(&self) -> u8 { self.0[6] }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct ChannelParamsUpdate(Buf);

impl ChannelParamsUpdate {
    pub fn new(tsbk: TSBKFields) -> Self { ChannelParamsUpdate(tsbk.0) }

    pub fn params(&self) -> ChannelParams {
        ChannelParams::new(self.base_freq(), self.channel(), self.bandwidth(),
                           self.offset(), self.spacing())
    }

    fn channel(&self) -> u8 { self.0[2] >> 4 }
    fn bandwidth(&self) -> u16 {
        (self.0[2] as u16 & 0xF) << 5 | (self.0[3] >> 3) as u16
    }
    fn offset(&self) -> u16 {
        (self.0[3] as u16 & 0x7) << 6 | (self.0[4] >> 2) as u16
    }
    fn spacing(&self) -> u16 {
        (self.0[4] as u16 & 0x3) << 8 | self.0[5] as u16
    }
    fn base_freq(&self) -> u32 { slice_u32(&self.0[6..]) }
}
<|endoftext|>


<commit_before>macro_rules! next {
    ($node:expr, Left) => { $node * 2 };
    ($node:expr, Right) => { $node * 2 + 1 };
}

macro_rules! last_parent {
    ($size:expr) => { $size / 2 - 1 };
}

pub fn sort<T: Ord>(v: &mut [T]) {
    let len = v.len();
    let mut h = Heap {
        v: v,
        size: len
    };
    h.sort();
}

struct Heap<'a, T: 'a + Ord> {
    v: &'a mut [T],
    size: usize
}

impl<'a, T: Ord> Heap<'a, T> {
    fn sort(&mut self) {
        self.build_max_heap();
        for node in (1 .. self.size).rev() {
            self.v.swap(0, node);
            self.size -= 1;
            self.max_heapify(0);
        }
    }

    fn build_max_heap(&mut self) {
        let first = last_parent!(self.size);
        for node in (0 .. first + 1).rev() {
            self.max_heapify(node);
        }
    }

    fn max_heapify(&mut self, node: usize) {
        let left = next!(node, Left);
        let right = next!(node, Right);
        let mut largest;

        if left < self.size && self.v[left] > self.v[node] {
            largest = left;
        } else {
            largest = node;
        }
        if right < self.size && self.v[right] > self.v[largest] {
            largest = right;
        }

        if largest != node {
            self.v.swap(node, largest);
            self.max_heapify(largest);
        }
    }
}
<commit_msg>Fix heap<commit_after>macro_rules! next {
    ($node:expr, Left) => { ($node + 1) * 2 - 1};
    ($node:expr, Right) => { ($node + 1) * 2 };
}

macro_rules! last_parent {
    ($size:expr) => { $size / 2 - 1 };
}

pub fn sort<T: Ord>(v: &mut [T]) {
    let len = v.len();
    let mut h = Heap {
        v: v,
        size: len
    };
    h.sort();
}

struct Heap<'a, T: 'a + Ord> {
    v: &'a mut [T],
    size: usize
}

impl<'a, T: Ord> Heap<'a, T> {
    fn sort(&mut self) {
        self.build_max_heap();
        for node in (1 .. self.size).rev() {
            self.v.swap(0, node);
            self.size -= 1;
            self.max_heapify(0);
        }
    }

    fn build_max_heap(&mut self) {
        match self.size {
            0 | 1 => return,
            size => {
                let first = last_parent!(size);
                for node in (0 .. first + 1).rev() {
                    self.max_heapify(node);
                }
            }
        }
    }

    fn max_heapify(&mut self, node: usize) {
        let left = next!(node, Left);
        let right = next!(node, Right);
        let mut largest;

        if left < self.size && self.v[left] > self.v[node] {
            largest = left;
        } else {
            largest = node;
        }
        if right < self.size && self.v[right] > self.v[largest] {
            largest = right;
        }

        if largest != node {
            self.v.swap(node, largest);
            self.max_heapify(largest);
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "weather-client"]

#![feature(core)]

/*!
 * Weather update client
 * Connects SUB socket to tcp://localhost:5556
 * Collects weather updates and find avg temp in zipcode
 */

extern crate zmq;

fn atoi(s: &str) -> i64 {
    s.parse().unwrap()
}

fn main() {
    println!("Collecting updates from weather server...");

    let mut context = zmq::Context::new();
    let mut subscriber = context.socket(zmq::SUB).unwrap();
    assert!(subscriber.connect("tcp://localhost:5556").is_ok());

    let args = std::os::args();
    let filter = if args.len() > 1 { args[1].clone() } else { "10001".to_string() };
    assert!(subscriber.set_subscribe(filter.as_bytes()).is_ok());

    let mut total_temp = 0;

    for _ in 0 .. 100 {
        let string = subscriber.recv_string(0).unwrap().unwrap();
        let chks: Vec<i64> = string.as_slice().split(' ').map(|x| atoi(x)).collect();
        let (_zipcode, temperature, _relhumidity) = (chks[0], chks[1], chks[2]);
        total_temp += temperature;
    }

    println!("Average temperature for zipcode '{}' was {}F", filter, (total_temp / 100));
}
<commit_msg>os -> env<commit_after>#![crate_name = "weather-client"]

#![feature(core, env)]

/*!
 * Weather update client
 * Connects SUB socket to tcp://localhost:5556
 * Collects weather updates and find avg temp in zipcode
 */

extern crate zmq;

use std::env;

fn atoi(s: &str) -> i64 {
    s.parse().unwrap()
}

fn main() {
    println!("Collecting updates from weather server...");

    let mut context = zmq::Context::new();
    let mut subscriber = context.socket(zmq::SUB).unwrap();
    assert!(subscriber.connect("tcp://localhost:5556").is_ok());

    let args: Vec<String> = env::args().collect();
    let filter = if args.len() > 1 { args[1].clone() } else { "10001".to_string() };
    assert!(subscriber.set_subscribe(filter.as_bytes()).is_ok());

    let mut total_temp = 0;

    for _ in 0 .. 100 {
        let string = subscriber.recv_string(0).unwrap().unwrap();
        let chks: Vec<i64> = string.as_slice().split(' ').map(|x| atoi(x)).collect();
        let (_zipcode, temperature, _relhumidity) = (chks[0], chks[1], chks[2]);
        total_temp += temperature;
    }

    println!("Average temperature for zipcode '{}' was {}F", filter, (total_temp / 100));
}
<|endoftext|>


<commit_before>use futures::channel::{mpsc, oneshot};
use futures::{SinkExt, StreamExt};
use std::convert::TryInto;
use std::time::Duration;
use zeromq::prelude::*;

#[tokio::test]
async fn test_pub_sub_sockets() {
    async fn helper(bind_addr: &'static str) {
        let (server_stop_sender, mut server_stop) = oneshot::channel::<()>();
        let (results_sender, results) = mpsc::channel(100);
        tokio::spawn(async move {
            let mut pub_socket = zeromq::PubSocket::new();
            pub_socket
                .bind(bind_addr)
                .await
                .expect("Failed to bind socket");

            loop {
                if let Ok(Some(_)) = server_stop.try_recv() {
                    break;
                }
                pub_socket
                    .send(chrono::Utc::now().to_rfc2822().into())
                    .expect("Failed to send");
                tokio::time::delay_for(Duration::from_millis(100)).await;
            }
        });

        for _ in 0..10 {
            let mut client_sender = results_sender.clone();
            tokio::spawn(async move {
                let mut sub_socket = zeromq::SubSocket::new();
                sub_socket
                    .connect(bind_addr)
                    .await
                    .expect("Failed to connect");

                sub_socket.subscribe("").await.expect("Failed to subscribe");

                for _ in 0..10i32 {
                    let repl: String = sub_socket
                        .recv()
                        .await
                        .expect("Failed to recv")
                        .try_into()
                        .expect("Malformed string");
                    assert_eq!(chrono::Utc::now().to_rfc2822(), repl);
                    client_sender.send(true).await.unwrap();
                }
            });
        }
        drop(results_sender);

        let res_vec: Vec<bool> = results.collect().await;
        server_stop_sender.send(()).unwrap();
        assert_eq!(100, res_vec.len());
    }
    let addrs = vec!["127.0.0.1:5556", "localhost:5555"];
    futures::future::join_all(addrs.into_iter().map(helper)).await;
}
<commit_msg>Fix flaky test<commit_after>use futures::channel::{mpsc, oneshot};
use futures::{SinkExt, StreamExt};
use std::convert::TryInto;
use std::time::Duration;
use zeromq::prelude::*;

#[tokio::test]
async fn test_pub_sub_sockets() {
    async fn helper(bind_addr: &'static str) {
        let payload = chrono::Utc::now().to_rfc2822();

        let cloned_payload = payload.clone();
        let (server_stop_sender, mut server_stop) = oneshot::channel::<()>();
        tokio::spawn(async move {
            let mut pub_socket = zeromq::PubSocket::new();
            pub_socket
                .bind(bind_addr)
                .await
                .expect("Failed to bind socket");

            loop {
                if let Ok(Some(_)) = server_stop.try_recv() {
                    break;
                }

                pub_socket
                    .send(cloned_payload.clone().into())
                    .expect("Failed to send");
                tokio::time::delay_for(Duration::from_millis(1)).await;
            }
        });

        let (sub_results_sender, sub_results) = mpsc::channel(100);
        for _ in 0..10 {
            let mut cloned_sub_sender = sub_results_sender.clone();
            let cloned_payload = payload.clone();
            tokio::spawn(async move {
                let mut sub_socket = zeromq::SubSocket::new();
                sub_socket
                    .connect(bind_addr)
                    .await
                    .expect("Failed to connect");

                sub_socket.subscribe("").await.expect("Failed to subscribe");

                for _ in 0..10 {
                    let recv_payload: String = sub_socket
                        .recv()
                        .await
                        .expect("Failed to recv")
                        .try_into()
                        .expect("Malformed string");
                    assert_eq!(cloned_payload, recv_payload);
                    cloned_sub_sender.send(()).await.unwrap();
                }
            });
        }
        drop(sub_results_sender);
        let res_vec: Vec<()> = sub_results.collect().await;
        assert_eq!(100, res_vec.len());

        server_stop_sender.send(()).unwrap();
    }
    let addrs = vec!["127.0.0.1:5554", "[::1]:5555", "127.0.0.1:5556"];
    futures::future::join_all(addrs.into_iter().map(helper)).await;
}
<|endoftext|>


<commit_before>//! This file contains automated tests, but they require virtual ports and therefore can't work on Windows ...
#![cfg(not(windows))]
extern crate midir;

use std::thread::sleep;
use std::time::Duration;

use midir::{MidiInput, MidiOutput, Ignore};
use midir::os::unix::{VirtualInput, VirtualOutput};

#[test]
fn end_to_end() {
    let mut midi_in = MidiInput::new("My Test Input").unwrap();
    midi_in.ignore(Ignore::None);
    let midi_out = MidiOutput::new("My Test Output").unwrap();

    let previous_count = midi_out.port_count();

    println!("Creating virtual input port ...");
    let conn_in = midi_in.create_virtual("midir-test", |stamp, message, _| {
        println!("{}: {:?} (len = {})", stamp, message, message.len());
    }, ()).unwrap();

    assert_eq!(midi_out.port_count(), previous_count + 1);

    println!("Connecting to port '{}' ...", midi_out.port_name(previous_count).unwrap());
    let mut conn_out = midi_out.connect(previous_count, "midir-test").unwrap();
    println!("Starting to send messages ...");
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(200));
    println!("Closing output ...");
    let midi_out = conn_out.close();
    println!("Closing virtual input ...");
    let midi_in = conn_in.close().0;
    assert_eq!(midi_out.port_count(), previous_count);

    let previous_count = midi_in.port_count();

    // reuse midi_in and midi_out, but swap roles
    println!("\nCreating virtual output port ...");
    let mut conn_out = midi_out.create_virtual("midir-test").unwrap();
    assert_eq!(midi_in.port_count(), previous_count + 1);

    println!("Connecting to port '{}' ...", midi_in.port_name(previous_count).unwrap());
    let conn_in = midi_in.connect(previous_count, "midir-test", |stamp, message, _| {
        println!("{}: {:?} (len = {})", stamp, message, message.len());
    }, ()).unwrap();
    println!("Starting to send messages ...");
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(200));
    println!("Closing input ...");
    let midi_in = conn_in.close().0;
    println!("Closing virtual output ...");
    conn_out.close();
    assert_eq!(midi_in.port_count(), previous_count);
}
<commit_msg>Extend test with a few more messages<commit_after>//! This file contains automated tests, but they require virtual ports and therefore can't work on Windows ...
#![cfg(not(windows))]
extern crate midir;

use std::thread::sleep;
use std::time::Duration;

use midir::{MidiInput, MidiOutput, Ignore};
use midir::os::unix::{VirtualInput, VirtualOutput};

#[test]
fn end_to_end() {
    let mut midi_in = MidiInput::new("My Test Input").unwrap();
    midi_in.ignore(Ignore::None);
    let midi_out = MidiOutput::new("My Test Output").unwrap();

    let previous_count = midi_out.port_count();

    println!("Creating virtual input port ...");
    let conn_in = midi_in.create_virtual("midir-test", |stamp, message, _| {
        println!("{}: {:?} (len = {})", stamp, message, message.len());
    }, ()).unwrap();

    assert_eq!(midi_out.port_count(), previous_count + 1);

    println!("Connecting to port '{}' ...", midi_out.port_name(previous_count).unwrap());
    let mut conn_out = midi_out.connect(previous_count, "midir-test").unwrap();
    println!("Starting to send messages ...");
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(50));
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    println!("Closing output ...");
    let midi_out = conn_out.close();
    println!("Closing virtual input ...");
    let midi_in = conn_in.close().0;
    assert_eq!(midi_out.port_count(), previous_count);

    let previous_count = midi_in.port_count();

    // reuse midi_in and midi_out, but swap roles
    println!("\nCreating virtual output port ...");
    let mut conn_out = midi_out.create_virtual("midir-test").unwrap();
    assert_eq!(midi_in.port_count(), previous_count + 1);

    println!("Connecting to port '{}' ...", midi_in.port_name(previous_count).unwrap());
    let conn_in = midi_in.connect(previous_count, "midir-test", |stamp, message, _| {
        println!("{}: {:?} (len = {})", stamp, message, message.len());
    }, ()).unwrap();
    println!("Starting to send messages ...");
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    sleep(Duration::from_millis(50));
    conn_out.send(&[144, 60, 1]).unwrap();
    sleep(Duration::from_millis(200));
    conn_out.send(&[144, 60, 0]).unwrap();
    println!("Closing input ...");
    let midi_in = conn_in.close().0;
    println!("Closing virtual output ...");
    conn_out.close();
    assert_eq!(midi_in.port_count(), previous_count);
}
<|endoftext|>


<commit_before>
use std;
import std::io;
import std::io::{writer_util, reader_util};
import result;

tag state {
    start(bool);
    field(uint, uint);
    escapedfield(uint, uint);
    inquote(uint, uint);
}

type rowreader = {
    delim: char,
    quote: char,
    f : io::reader,
    mutable offset : uint,
    mutable buffers : [@[char]],
    mutable state : state
};

type row = {
    mutable fields : [ field ]
};

enum field {
    bufferfield([@[char]], uint, uint);
    emptyfield();
}

iface rowiter {
    fn readrow() -> result::t<row, str>;
}

iface rowaccess {
    fn len() -> uint;
    fn getchars(uint) -> [char];
    fn getstr(uint) -> str;
}

fn new_reader(+f: io::reader, +delim: char, +quote: char) -> rowreader {
    let r : rowreader = {
        delim: delim,
        quote: quote,
        f: f,
        mutable offset : 0u,
        mutable buffers : [],
        mutable state : start(false)
    };
    ret r;
}

impl of rowaccess for row {
    fn len() -> uint {
        vec::len(self.fields)
    }
    fn getchars(field: uint) -> [char] {
        alt self.fields[field] {
            emptyfield() { ret []; }
            bufferfield(buffers, so, eo) {
                let r : [char] = [];
                let i = 0u;
                while i < vec::len(buffers) {
                    let from = i == 0u ? so : 0u;
                    let to = (i == vec::len(buffers) - 1u) ? eo : 0u;
                    io::println(#fmt("%u %u %u", i, from, to));
                    r += vec::slice(*buffers[i], from, to);
                    i = i + 1u;
                }
                ret r;
            }
        };
    }
    fn getstr(field: uint) -> str {
        ret str::from_chars(self.getchars(field));
    }
}

impl of rowiter for rowreader {
    fn readrow() -> result::t<row, str> {
        fn row_from_buf(self: rowreader, &r: row) -> bool {
            fn new_bufferfield(self: rowreader, sb: uint, so: uint, eo: uint) -> field {
                let bufs : [@[char]] = vec::slice(self.buffers, sb, vec::len(self.buffers));
                ret bufferfield(bufs, 0u, eo-so);
            }
            let cbuffer = vec::len(self.buffers) - 1u;
            let buf: @[char] = self.buffers[cbuffer];
            while self.offset < vec::len(*buf) {
                let coffset = self.offset;
                let c : char = buf[coffset];
                self.offset += 1u;
                alt self.state {
                    start(after_delim) {
                        //io::println(#fmt("start : after_delim %b", after_delim));
                        if c == self.quote {
                            self.state = escapedfield(cbuffer, coffset);
                        } else if c == '\n' {
                            if after_delim {
                                r.fields += [emptyfield];
                            }
                            ret true;
                        } else if c == self.delim {
                            self.state = start(true);
                            r.fields += [emptyfield];
                        } else {
                            self.state = field(cbuffer, coffset);
                        }
                    }
                    field(b,o) {
                        //io::println(#fmt("field : %u %u", b, o));
                        if c == '\n' {
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                            ret true;
                        } else if c == self.delim {
                            self.state = start(true);
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                        }
                    }
                    escapedfield(b, o) {
                        //io::println(#fmt("escapedfield : %u %u", b, o));
                        if c == self.quote {
                            self.state = inquote(b, o);
                        } else if c == self.delim {
                            self.state = start(true);
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                        }
                    }
                    inquote(b, o) {
                        //io::println(#fmt("inquote : %u %u", b, o));
                        if c == '\n' {
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                            ret true;
                        } else if c == self.quote {
                            // hmm what to do
                            // self.state = escapedfield(x + [self.quote]);
                        } else if c == self.delim {
                            self.state = start(true);
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                        }
                        // swallow odd chars, eg. space between field and "
                    }
                }
            }
            ret false;
        }

        self.state = start(false);
        let do_read = vec::len(self.buffers) == 0u;
        while true {
            if do_read {
                let data: @[char] = @self.f.read_chars(1024u);
                //io::println(#fmt("len %u '%s'", vec::len(*data), str::from_chars(*data)));
                if vec::len(*data) == 0u {
                    ret result::err("EOF");
                }
                self.buffers += [data];
                self.offset = 0u;
            }

            let r: row = { mutable fields: [] };
            if row_from_buf(self, r) {
                ret result::ok(r);
            }
            do_read = true;
        }
        ret result::err("unreachable");
    }
}

fn main(args : [str])
{
    if (vec::len(args) != 2u) {
        ret;
    }
    let f : io::reader = result::get(io::file_reader(args[1]));
    let reader = new_reader(f, ',', '"');
    while true {
        let res = reader.readrow();
        if result::failure(res) {
            break;
        }
        io::println("got a row");
        let row = result::get(res);
        io::println(row.getstr(0u));
    }
}

<commit_msg>works more!<commit_after>
use std;
import std::io;
import std::io::{writer_util, reader_util};
import result;

tag state {
    start(bool);
    field(uint, uint);
    escapedfield(uint, uint);
    inquote(uint, uint);
}

type rowreader = {
    delim: char,
    quote: char,
    f : io::reader,
    mutable offset : uint,
    mutable buffers : [@[char]],
    mutable state : state
};

type row = {
    mutable fields : [ field ]
};

enum field {
    bufferfield([@[char]], uint, uint);
    emptyfield();
}

iface rowiter {
    fn readrow() -> result::t<row, str>;
}

iface rowaccess {
    fn len() -> uint;
    fn getchars(uint) -> [char];
    fn getstr(uint) -> str;
}

fn new_reader(+f: io::reader, +delim: char, +quote: char) -> rowreader {
    let r : rowreader = {
        delim: delim,
        quote: quote,
        f: f,
        mutable offset : 0u,
        mutable buffers : [],
        mutable state : start(false)
    };
    ret r;
}

impl of rowaccess for row {
    fn len() -> uint {
        vec::len(self.fields)
    }
    fn getchars(field: uint) -> [char] {
        alt self.fields[field] {
            emptyfield() { ret []; }
            bufferfield(buffers, so, eo) {
                let r : [char] = [];
                let i = 0u;
                while i < vec::len(buffers) {
                    let from = i == 0u ? so : 0u;
                    let to = (i == vec::len(buffers) - 1u) ? eo : vec::len(*buffers[i]);
                    r += vec::slice(*buffers[i], from, to);
                    i = i + 1u;
                }
                ret r;
            }
        };
    }
    fn getstr(field: uint) -> str {
        ret str::from_chars(self.getchars(field));
    }
}

impl of rowiter for rowreader {
    fn readrow() -> result::t<row, str> {
        fn row_from_buf(self: rowreader, &r: row) -> bool {
            fn new_bufferfield(self: rowreader, sb: uint, so: uint, eo: uint) -> field {
                let bufs : [@[char]] = vec::slice(self.buffers, sb, vec::len(self.buffers));
                ret bufferfield(bufs, so, eo);
            }
            let cbuffer = vec::len(self.buffers) - 1u;
            let buf: @[char] = self.buffers[cbuffer];
            while self.offset < vec::len(*buf) {
                let coffset = self.offset;
                let c : char = buf[coffset];
                self.offset += 1u;
                alt self.state {
                    start(after_delim) {
                        //io::println(#fmt("start : after_delim %b", after_delim));
                        if c == self.quote {
                            self.state = escapedfield(cbuffer, coffset);
                        } else if c == '\n' {
                            if after_delim {
                                r.fields += [emptyfield];
                            }
                            ret true;
                        } else if c == self.delim {
                            self.state = start(true);
                            r.fields += [emptyfield];
                        } else {
                            self.state = field(cbuffer, coffset);
                        }
                    }
                    field(b,o) {
                        //io::println(#fmt("field : %u %u", b, o));
                        if c == '\n' {
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                            ret true;
                        } else if c == self.delim {
                            self.state = start(true);
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                        }
                    }
                    escapedfield(b, o) {
                        //io::println(#fmt("escapedfield : %u %u", b, o));
                        if c == self.quote {
                            self.state = inquote(b, o);
                        } else if c == self.delim {
                            self.state = start(true);
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                        }
                    }
                    inquote(b, o) {
                        //io::println(#fmt("inquote : %u %u", b, o));
                        if c == '\n' {
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                            ret true;
                        } else if c == self.quote {
                            // hmm what to do
                            // self.state = escapedfield(x + [self.quote]);
                        } else if c == self.delim {
                            self.state = start(true);
                            r.fields += [new_bufferfield(self, b, o, coffset)];
                        }
                        // swallow odd chars, eg. space between field and "
                    }
                }
            }
            ret false;
        }

        self.state = start(false);
        let do_read = vec::len(self.buffers) == 0u;
        while true {
            if do_read {
                let data: @[char] = @self.f.read_chars(1024u);
                //io::println(#fmt("len %u '%s'", vec::len(*data), str::from_chars(*data)));
                if vec::len(*data) == 0u {
                    ret result::err("EOF");
                }
                self.buffers += [data];
                self.offset = 0u;
            }

            let r: row = { mutable fields: [] };
            if row_from_buf(self, r) {
                ret result::ok(r);
            }
            do_read = true;
        }
        ret result::err("unreachable");
    }
}

fn main(args : [str])
{
    if (vec::len(args) != 2u) {
        ret;
    }
    let f : io::reader = result::get(io::file_reader(args[1]));
    let reader = new_reader(f, ',', '"');
    while true {
        let res = reader.readrow();
        if result::failure(res) {
            break;
        }
        let row = result::get(res);
        io::println(#fmt("---- ROW %u fields -----", row.len()));
        let i = 0u;
        while i < row.len() {
            io::println(row.getstr(i));
            i = i + 1u;
        }
    }
}

<|endoftext|>


<commit_before><commit_msg>zakocmp: rename policy tests<commit_after><|endoftext|>


<commit_before><commit_msg>complete end-to-end test for renames and restoration correctness<commit_after><|endoftext|>