<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::{bail, Result};
use regex::Regex;
use std::matches;
use std::ops::Drop;
use std::thread;
use std::time::Duration;
use structopt::StructOpt;

use opentitanlib::app::TransportWrapper;
use opentitanlib::execute_test;
use opentitanlib::io::spi::Transfer;
use opentitanlib::spiflash::{
    sfdp, BlockEraseSize, SpiFlash, SupportedAddressModes, WriteGranularity,
};
use opentitanlib::test_utils::init::InitializeTest;
use opentitanlib::uart::console::{ExitStatus, UartConsole};
use opentitanlib::util::parse_int::ParseInt;

#[derive(Debug, StructOpt)]
struct Opts {
    #[structopt(flatten)]
    init: InitializeTest,

    #[structopt(
        long, parse(try_from_str=humantime::parse_duration),
        default_value = "5s",
        help = "Bootstrap detection timeout",
    )]
    timeout: Duration,

    #[structopt(
        long, parse(try_from_str=usize::from_str),
        default_value = "12",
        help = "JEDEC page of manufacturer",
    )]
    jedec_page: usize,

    #[structopt(
        long, parse(try_from_str=u8::from_str),
        default_value = "0xEF",
        help = "JEDEC ID of manufacturer",
    )]
    jedec_id: u8,

    #[structopt(
        long, parse(try_from_str=u8::from_str),
        default_value = "0x08",
        help = "JEDEC manufacturer product ID",
    )]
    jedec_product: u8,

    #[structopt(
        long, parse(try_from_str=u32::from_str),
        default_value = "0x100000",
        help = "Size of the internal flash",
    )]
    flash_size: u32,
}

/// A struct for isolating individual test points.
///
/// This is basically an example of the RAII technique.
/// Calling `BootstrapTest::start()` resets the chip and puts it in bootstrap mode (assuming it's
/// enabled). Strapping pins are released and the chip is reset when the returned struct is
/// dropped, typically at the end of the test point.
struct BootstrapTest<'a> {
    transport: &'a TransportWrapper,
    reset_delay: Duration,
}

impl<'a> BootstrapTest<'a> {
    pub fn start(transport: &'a TransportWrapper, reset_delay: Duration) -> Result<Self> {
        let b = BootstrapTest {
            transport,
            reset_delay,
        };
        transport.apply_pin_strapping("ROM_BOOTSTRAP")?;
        transport.reset_target(b.reset_delay, true)?;

        let spi = transport.spi("0")?;
        while SpiFlash::read_status(&*spi)? != 0 {
            thread::sleep(Duration::from_millis(10));
        }

        Ok(b)
    }
}

impl<'a> Drop for BootstrapTest<'a> {
    fn drop(&mut self) {
        self.transport
            .remove_pin_strapping("ROM_BOOTSTRAP")
            .unwrap();
        self.transport.reset_target(self.reset_delay, true).unwrap();
    }
}

fn test_bootstrap_enabled_requested(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    // TODO: Should really `opts.init.uart_params.create()` here, but we need to refactor
    // BootstrapOptions first.
    //let uart = opts.init.uart_params.create(&transport)?;
    let uart = transport.uart("0")?;
    let mut console = UartConsole {
        timeout: Some(opts.timeout),
        exit_success: Some(Regex::new(r"bootstrap:1\r\n")?),
        exit_failure: Some(Regex::new(r"BFV:")?),
        ..Default::default()
    };

    transport.apply_pin_strapping("ROM_BOOTSTRAP")?;
    transport.reset_target(opts.init.bootstrap.options.reset_delay, true)?;

    // Now watch the console for the exit conditions.
    let result = console.interact(&*uart, None, Some(&mut std::io::stdout()))?;
    if result != ExitStatus::ExitSuccess {
        bail!("FAIL: {:?}", result);
    };
    // Now check whether the SPI device is responding to status messages
    let spi = transport.spi("0")?;
    assert_eq!(SpiFlash::read_status(&*spi)?, 0x00);

    Ok(())
}

fn test_bootstrap_enabled_not_requested(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    // TODO: Should really `opts.init.uart_params.create()` here, but we need to refactor
    // BootstrapOptions first.
    //let uart = opts.init.uart_params.create(&transport)?;
    let uart = transport.uart("0")?;
    let mut console = UartConsole {
        timeout: Some(opts.timeout),
        exit_success: Some(Regex::new(r"BFV:")?),
        exit_failure: Some(Regex::new(r"bootstrap:1\r\n")?),
        ..Default::default()
    };

    transport.reset_target(opts.init.bootstrap.options.reset_delay, true)?;

    // Now watch the console for the exit conditions.
    let result = console.interact(&*uart, None, Some(&mut std::io::stdout()))?;
    if result != ExitStatus::ExitSuccess {
        bail!("FAIL: {:?}", result);
    };

    // Now check whether the SPI device is responding to commands.
    // Note: CIPO line is in high-z state when CMD_INFO registers are not configured.
    // Use READ_SFDP instead of READ_STATUS to avoid false negatives when bootstrap is not
    // requested
    let spi = transport.spi("0")?;
    assert!(matches!(
        SpiFlash::read_sfdp(&*spi)
            .unwrap_err()
            .downcast::<sfdp::Error>()
            .unwrap(),
        sfdp::Error::WrongHeaderSignature(..)
    ));
    Ok(())
}

fn test_jedec_id(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    let spi = transport.spi("0")?;
    let id = SpiFlash::read_jedec_id(&*spi, 16)?;
    log::info!("Read jedec id: {:x?}", id);
    let mut index = 0;
    while id[index] == 0x7f {
        index += 1;
    }
    let page = index;
    let manufacturer = id[index];
    let product = id[index + 1];
    let density = id[index + 2];

    assert_eq!(page, opts.jedec_page);
    assert_eq!(manufacturer, opts.jedec_id);
    assert_eq!(product, opts.jedec_product);
    assert_eq!(1u32 << density, opts.flash_size);
    Ok(())
}

fn test_write_enable_disable(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    let spi = transport.spi("0")?;

    assert_eq!(SpiFlash::read_status(&*spi)?, 0x0);

    SpiFlash::set_write_enable(&*spi)?;
    assert_eq!(SpiFlash::read_status(&*spi)?, 0x2);

    SpiFlash::set_write_disable(&*spi)?;
    assert_eq!(SpiFlash::read_status(&*spi)?, 0x0);

    Ok(())
}

fn test_sfdp(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    let spi = transport.spi("0")?;
    let sfdp = SpiFlash::read_sfdp(&*spi)?;
    log::info!("SFDP: {:#x?}", sfdp);

    // We expect a SFDP header of version 1.10 with no additional phdrs
    // except the mandatory JDEC phdr.
    assert_eq!(sfdp.header.signature, 0x50444653);
    assert_eq!(sfdp.header.minor, 0xa);
    assert_eq!(sfdp.header.major, 0x1);
    assert_eq!(sfdp.header.nph, 0x0);
    assert_eq!(sfdp.header.reserved, 0xff);

    // Check the parameters of the mandatory phdr.
    assert_eq!(sfdp.phdr[0].id, 0x0);
    assert_eq!(sfdp.phdr[0].minor, 0x7);
    assert_eq!(sfdp.phdr[0].major, 0x1);
    assert_eq!(sfdp.phdr[0].dwords, 0x17);
    assert_eq!(sfdp.phdr[0].offset, 0x10);

    // Check the values of the JEDEC parameters.
    // TODO(lowRISC/opentitan#14457): Update these checks after updating the
    // SFDP parser in opentitanlib.
    assert_eq!(sfdp.jedec.block_erase_size, BlockEraseSize::Block4KiB);
    assert_eq!(
        sfdp.jedec.write_granularity,
        WriteGranularity::Granularity64Bytes
    );
    assert_eq!(sfdp.jedec.write_en_required, true);
    assert_eq!(sfdp.jedec.write_en_opcode, 0x50);
    assert_eq!(sfdp.jedec.erase_opcode_4kib, 0x20);
    assert_eq!(sfdp.jedec.support_fast_read_112, false);
    assert_eq!(sfdp.jedec.address_modes, SupportedAddressModes::Mode3b);
    assert_eq!(sfdp.jedec.support_double_rate_clocking, false);
    assert_eq!(sfdp.jedec.support_fast_read_122, false);
    assert_eq!(sfdp.jedec.support_fast_read_144, false);
    assert_eq!(sfdp.jedec.support_fast_read_114, false);
    assert_eq!(sfdp.jedec.support_fast_read_222, false);
    assert_eq!(sfdp.jedec.support_fast_read_444, false);
    assert_eq!(sfdp.jedec.density, opts.flash_size);
    Ok(())
}

fn test_bootstrap_shutdown(
    opts: &Opts,
    transport: &TransportWrapper,
    cmd: u8,
    bfv: &str,
) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    let spi = transport.spi("0")?;
    let uart = transport.uart("0")?;
    let mut console = UartConsole {
        timeout: Some(Duration::new(2, 0)),
        // `kErrorBootPolicyBadIdentifier` (0142500d) is defined in `error.h`.
        exit_success: Some(Regex::new(
            format!("(?s)BFV:{bfv}\r\n.*BFV:0142500d\r\n").as_str(),
        )?),
        ..Default::default()
    };
    // Send CHIP_ERASE to transition to phase 2.
    SpiFlash::from_spi(&*spi)?.chip_erase(&*spi)?;
    // Remove strapping so that chip fails to boot instead of going into bootstrap.
    transport.remove_pin_strapping("ROM_BOOTSTRAP")?;
    // SECTOR_ERASE with invalid address to trigger a shutdown.
    SpiFlash::set_write_enable(&*spi)?;
    let bad_erase = [cmd, 0xff, 0xff, 0xff];
    spi.run_transaction(&mut [Transfer::Write(&bad_erase)])?;
    // We should see the expected BFVs.
    let result = console.interact(&*uart, None, Some(&mut std::io::stdout()))?;
    if result != ExitStatus::ExitSuccess {
        bail!("FAIL: {:?}", result);
    }
    // Also verify that the chip is no longer in bootstrap mode.
    assert!(matches!(
        SpiFlash::read_sfdp(&*spi)
            .unwrap_err()
            .downcast::<sfdp::Error>()
            .unwrap(),
        sfdp::Error::WrongHeaderSignature(..)
    ));

    Ok(())
}

fn main() -> Result<()> {
    let opts = Opts::from_args();
    opts.init.init_logging();

    let transport = opts.init.init_target()?;
    execute_test!(test_bootstrap_enabled_not_requested, &opts, &transport);
    execute_test!(test_bootstrap_enabled_requested, &opts, &transport);
    execute_test!(test_jedec_id, &opts, &transport);
    execute_test!(test_sfdp, &opts, &transport);
    execute_test!(test_write_enable_disable, &opts, &transport);
    // `kErrorBootstrapEraseAddress` (01425303) is defined in `error.h`.
    execute_test!(
        test_bootstrap_shutdown,
        &opts,
        &transport,
        SpiFlash::SECTOR_ERASE,
        "01425303"
    );
    // `kErrorBootstrapProgramAddress` (02425303) is defined in `error.h`.
    execute_test!(
        test_bootstrap_shutdown,
        &opts,
        &transport,
        SpiFlash::PAGE_PROGRAM,
        "02425303"
    );
    Ok(())
}
<commit_msg>[test] Minor cleanup in e2e_boostrap_entry<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::{bail, Result};
use regex::Regex;
use std::matches;
use std::ops::Drop;
use std::thread;
use std::time::Duration;
use structopt::StructOpt;

use opentitanlib::app::TransportWrapper;
use opentitanlib::execute_test;
use opentitanlib::io::spi::Transfer;
use opentitanlib::spiflash::{
    sfdp, BlockEraseSize, SpiFlash, SupportedAddressModes, WriteGranularity,
};
use opentitanlib::test_utils::init::InitializeTest;
use opentitanlib::uart::console::{ExitStatus, UartConsole};
use opentitanlib::util::parse_int::ParseInt;

#[derive(Debug, StructOpt)]
struct Opts {
    #[structopt(flatten)]
    init: InitializeTest,

    #[structopt(
        long, parse(try_from_str=humantime::parse_duration),
        default_value = "5s",
        help = "Bootstrap detection timeout",
    )]
    timeout: Duration,

    #[structopt(
        long, parse(try_from_str=usize::from_str),
        default_value = "12",
        help = "JEDEC page of manufacturer",
    )]
    jedec_page: usize,

    #[structopt(
        long, parse(try_from_str=u8::from_str),
        default_value = "0xEF",
        help = "JEDEC ID of manufacturer",
    )]
    jedec_id: u8,

    #[structopt(
        long, parse(try_from_str=u8::from_str),
        default_value = "0x08",
        help = "JEDEC manufacturer product ID",
    )]
    jedec_product: u8,

    #[structopt(
        long, parse(try_from_str=u32::from_str),
        default_value = "0x100000",
        help = "Size of the internal flash",
    )]
    flash_size: u32,
}

/// A struct for isolating individual test points.
///
/// This is basically an example of the RAII technique.
/// Calling `BootstrapTest::start()` resets the chip and puts it in bootstrap mode (assuming it's
/// enabled). Strapping pins are released and the chip is reset when the returned struct is
/// dropped, typically at the end of the test point.
struct BootstrapTest<'a> {
    transport: &'a TransportWrapper,
    reset_delay: Duration,
}

impl<'a> BootstrapTest<'a> {
    pub fn start(transport: &'a TransportWrapper, reset_delay: Duration) -> Result<Self> {
        let b = BootstrapTest {
            transport,
            reset_delay,
        };
        transport.apply_pin_strapping("ROM_BOOTSTRAP")?;
        transport.reset_target(b.reset_delay, true)?;

        let spi = transport.spi("0")?;
        while SpiFlash::read_status(&*spi)? != 0 {
            thread::sleep(Duration::from_millis(10));
        }

        Ok(b)
    }
}

impl<'a> Drop for BootstrapTest<'a> {
    fn drop(&mut self) {
        self.transport
            .remove_pin_strapping("ROM_BOOTSTRAP")
            .unwrap();
        self.transport.reset_target(self.reset_delay, true).unwrap();
    }
}

fn test_bootstrap_enabled_requested(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    // TODO: Should really `opts.init.uart_params.create()` here, but we need to refactor
    // BootstrapOptions first.
    //let uart = opts.init.uart_params.create(&transport)?;
    let uart = transport.uart("0")?;
    let mut console = UartConsole {
        timeout: Some(opts.timeout),
        exit_success: Some(Regex::new(r"bootstrap:1\r\n")?),
        exit_failure: Some(Regex::new(r"BFV:")?),
        ..Default::default()
    };

    transport.apply_pin_strapping("ROM_BOOTSTRAP")?;
    transport.reset_target(opts.init.bootstrap.options.reset_delay, true)?;

    // Now watch the console for the exit conditions.
    let result = console.interact(&*uart, None, Some(&mut std::io::stdout()))?;
    if result != ExitStatus::ExitSuccess {
        bail!("FAIL: {:?}", result);
    };
    // Now check whether the SPI device is responding to status messages
    let spi = transport.spi("0")?;
    assert_eq!(SpiFlash::read_status(&*spi)?, 0x00);

    Ok(())
}

fn test_bootstrap_enabled_not_requested(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    // TODO: Should really `opts.init.uart_params.create()` here, but we need to refactor
    // BootstrapOptions first.
    //let uart = opts.init.uart_params.create(&transport)?;
    let uart = transport.uart("0")?;
    let mut console = UartConsole {
        timeout: Some(opts.timeout),
        exit_success: Some(Regex::new(r"BFV:")?),
        exit_failure: Some(Regex::new(r"bootstrap:1\r\n")?),
        ..Default::default()
    };

    transport.reset_target(opts.init.bootstrap.options.reset_delay, true)?;

    // Now watch the console for the exit conditions.
    let result = console.interact(&*uart, None, Some(&mut std::io::stdout()))?;
    if result != ExitStatus::ExitSuccess {
        bail!("FAIL: {:?}", result);
    };

    // Now check whether the SPI device is responding to commands.
    // Note: CIPO line is in high-z state when CMD_INFO registers are not configured.
    // Use READ_SFDP instead of READ_STATUS to avoid false negatives when bootstrap is not
    // requested
    let spi = transport.spi("0")?;
    assert!(matches!(
        SpiFlash::read_sfdp(&*spi)
            .unwrap_err()
            .downcast::<sfdp::Error>()
            .unwrap(),
        sfdp::Error::WrongHeaderSignature(..)
    ));
    Ok(())
}

fn test_jedec_id(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    let spi = transport.spi("0")?;
    let id = SpiFlash::read_jedec_id(&*spi, 16)?;
    log::info!("Read jedec id: {:x?}", id);
    let mut index = 0;
    while id[index] == 0x7f {
        index += 1;
    }
    let page = index;
    let manufacturer = id[index];
    let product = id[index + 1];
    let density = id[index + 2];

    assert_eq!(page, opts.jedec_page);
    assert_eq!(manufacturer, opts.jedec_id);
    assert_eq!(product, opts.jedec_product);
    assert_eq!(1u32 << density, opts.flash_size);
    Ok(())
}

fn test_write_enable_disable(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    let spi = transport.spi("0")?;

    assert_eq!(SpiFlash::read_status(&*spi)?, 0x0);

    SpiFlash::set_write_enable(&*spi)?;
    assert_eq!(SpiFlash::read_status(&*spi)?, 0x2);

    SpiFlash::set_write_disable(&*spi)?;
    assert_eq!(SpiFlash::read_status(&*spi)?, 0x0);

    Ok(())
}

fn test_sfdp(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    let spi = transport.spi("0")?;
    let sfdp = SpiFlash::read_sfdp(&*spi)?;
    log::info!("SFDP: {:#x?}", sfdp);

    // We expect a SFDP header of version 1.10 with no additional phdrs
    // except the mandatory JDEC phdr.
    assert_eq!(sfdp.header.signature, 0x50444653);
    assert_eq!(sfdp.header.minor, 0xa);
    assert_eq!(sfdp.header.major, 0x1);
    assert_eq!(sfdp.header.nph, 0x0);
    assert_eq!(sfdp.header.reserved, 0xff);

    // Check the parameters of the mandatory phdr.
    assert_eq!(sfdp.phdr[0].id, 0x0);
    assert_eq!(sfdp.phdr[0].minor, 0x7);
    assert_eq!(sfdp.phdr[0].major, 0x1);
    assert_eq!(sfdp.phdr[0].dwords, 0x17);
    assert_eq!(sfdp.phdr[0].offset, 0x10);

    // Check the values of the JEDEC parameters.
    // TODO(lowRISC/opentitan#14457): Update these checks after updating the
    // SFDP parser in opentitanlib.
    assert_eq!(sfdp.jedec.block_erase_size, BlockEraseSize::Block4KiB);
    assert_eq!(
        sfdp.jedec.write_granularity,
        WriteGranularity::Granularity64Bytes
    );
    assert_eq!(sfdp.jedec.write_en_required, true);
    assert_eq!(sfdp.jedec.write_en_opcode, 0x50);
    assert_eq!(sfdp.jedec.erase_opcode_4kib, 0x20);
    assert_eq!(sfdp.jedec.support_fast_read_112, false);
    assert_eq!(sfdp.jedec.address_modes, SupportedAddressModes::Mode3b);
    assert_eq!(sfdp.jedec.support_double_rate_clocking, false);
    assert_eq!(sfdp.jedec.support_fast_read_122, false);
    assert_eq!(sfdp.jedec.support_fast_read_144, false);
    assert_eq!(sfdp.jedec.support_fast_read_114, false);
    assert_eq!(sfdp.jedec.support_fast_read_222, false);
    assert_eq!(sfdp.jedec.support_fast_read_444, false);
    assert_eq!(sfdp.jedec.density, opts.flash_size);
    Ok(())
}

fn test_bootstrap_shutdown(
    opts: &Opts,
    transport: &TransportWrapper,
    cmd: u8,
    bfv: &str,
) -> Result<()> {
    let _bs = BootstrapTest::start(transport, opts.init.bootstrap.options.reset_delay)?;

    let spi = transport.spi("0")?;
    let uart = transport.uart("0")?;
    let mut console = UartConsole {
        timeout: Some(Duration::new(2, 0)),
        // `kErrorBootPolicyBadIdentifier` (0142500d) is defined in `error.h`.
        exit_success: Some(Regex::new(
            format!("(?s)BFV:{bfv}\r\n.*BFV:0142500d\r\n").as_str(),
        )?),
        ..Default::default()
    };
    // Send CHIP_ERASE to transition to phase 2.
    SpiFlash::from_spi(&*spi)?.chip_erase(&*spi)?;
    // Remove strapping so that chip fails to boot instead of going into bootstrap.
    transport.remove_pin_strapping("ROM_BOOTSTRAP")?;
    // SECTOR_ERASE with invalid address to trigger a shutdown.
    SpiFlash::set_write_enable(&*spi)?;
    let bad_erase = [cmd, 0xff, 0xff, 0xff];
    spi.run_transaction(&mut [Transfer::Write(&bad_erase)])?;
    // We should see the expected BFVs.
    let result = console.interact(&*uart, None, Some(&mut std::io::stdout()))?;
    if result != ExitStatus::ExitSuccess {
        bail!("FAIL: {:?}", result);
    }
    // Also verify that the chip is no longer in bootstrap mode.
    assert!(matches!(
        SpiFlash::read_sfdp(&*spi)
            .unwrap_err()
            .downcast::<sfdp::Error>()
            .unwrap(),
        sfdp::Error::WrongHeaderSignature(..)
    ));

    Ok(())
}

fn main() -> Result<()> {
    let opts = Opts::from_args();
    opts.init.init_logging();
    let transport = opts.init.init_target()?;

    execute_test!(test_bootstrap_enabled_not_requested, &opts, &transport);
    execute_test!(test_bootstrap_enabled_requested, &opts, &transport);
    execute_test!(test_jedec_id, &opts, &transport);
    execute_test!(test_sfdp, &opts, &transport);
    execute_test!(test_write_enable_disable, &opts, &transport);
    for (cmd, bfv) in [
        // `kErrorBootstrapEraseAddress` (01425303) is defined in `error.h`.
        (SpiFlash::SECTOR_ERASE, "01425303"),
        // `kErrorBootstrapProgramAddress` (02425303) is defined in `error.h`.
        (SpiFlash::PAGE_PROGRAM, "02425303"),
    ] {
        execute_test!(test_bootstrap_shutdown, &opts, &transport, cmd, bfv);
    }

    Ok(())
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::ops;
use std::str;

use bytes::Bytes;
use std::fmt;

#[derive(Debug)]
pub struct AsciiError(());

/// Bytes wrapper that guarantees that contained bytes are ASCII.
#[derive(Eq, PartialEq, Hash, Clone)]
pub struct Ascii(Bytes);

impl Ascii {
    pub fn new() -> Ascii {
        Ascii(Bytes::new())
    }

    pub fn from_bytes(bs: Bytes) -> Result<Ascii, (AsciiError, Bytes)> {
        for &b in &bs {
            if b > i8::max_value() as u8 {
                return Err((AsciiError(()), bs));
            }
        }
        Ok(Ascii(bs))
    }

    pub fn as_str(&self) -> &str {
        unsafe { str::from_utf8_unchecked(self.0.as_ref()) }
    }
}

impl ops::Deref for Ascii {
    type Target = str;

    fn deref(&self) -> &str {
        unsafe { str::from_utf8_unchecked(&self.0) }
    }
}

impl fmt::Debug for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_str(), f)
    }
}

impl fmt::Display for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

pub struct AsciiLower(Ascii);

impl AsciiLower {
    pub fn new() -> AsciiLower {
        AsciiLower(Ascii::new())
    }
}

impl ops::Deref for AsciiLower {
    type Target = str;

    fn deref(&self) -> &str {
        self.0.deref()
    }
}

impl<'a> From<&'a str> for AsciiLower {
    fn from(_s: &'a str) -> AsciiLower {
        unimplemented!()
    }
}

#[cfg(test)]
mod test {
    use crate::ascii::Ascii;
    use bytes::Bytes;

    #[test]
    fn ascii_from_bytes() {
        assert!(Ascii::from_bytes(Bytes::from_static("ю".as_bytes())).is_err());
    }
}
<commit_msg>Improvements to AsciiLower type<commit_after>#![allow(dead_code)]

use std::ops;
use std::str;

use bytes::Bytes;
use std::fmt;

#[derive(Debug)]
pub struct AsciiError(());

/// Bytes wrapper that guarantees that contained bytes are ASCII.
#[derive(Eq, PartialEq, Hash, Clone)]
pub struct Ascii(Bytes);

impl Ascii {
    pub fn new() -> Ascii {
        Ascii(Bytes::new())
    }

    pub fn from_bytes(bs: Bytes) -> Result<Ascii, (AsciiError, Bytes)> {
        for &b in &bs {
            if b > i8::max_value() as u8 {
                return Err((AsciiError(()), bs));
            }
        }
        Ok(Ascii(bs))
    }

    /// Create an ASCII string from bytes.
    ///
    /// This is a const fn, and we cannot loop in const fn
    /// so no validation here.
    pub const unsafe fn from_bytes_unchecked(bs: Bytes) -> Ascii {
        Ascii(bs)
    }

    pub fn as_str(&self) -> &str {
        unsafe { str::from_utf8_unchecked(self.0.as_ref()) }
    }
}

impl ops::Deref for Ascii {
    type Target = str;

    fn deref(&self) -> &str {
        unsafe { str::from_utf8_unchecked(&self.0) }
    }
}

impl fmt::Debug for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_str(), f)
    }
}

impl fmt::Display for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

#[derive(Debug)]
pub struct AsciiLowerError(());

/// ASCII lowercase string (any ASCII except uppercase letters).
pub struct AsciiLower(Ascii);

impl AsciiLower {
    pub fn new() -> AsciiLower {
        AsciiLower(Ascii::new())
    }

    /// Validate bytes is an ASCII lowercase string.
    pub fn from_bytes(bs: Bytes) -> Result<AsciiLower, (AsciiLowerError, Bytes)> {
        for &b in &bs {
            if !b.is_ascii() || b.is_ascii_uppercase() {
                return Err((AsciiLowerError(()), bs));
            }
        }
        unsafe { Ok(AsciiLower(Ascii::from_bytes_unchecked(bs))) }
    }

    pub const unsafe fn from_bytes_unchecked(bs: Bytes) -> AsciiLower {
        AsciiLower(Ascii::from_bytes_unchecked(bs))
    }
}

impl fmt::Display for AsciiLower {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl ops::Deref for AsciiLower {
    type Target = str;

    fn deref(&self) -> &str {
        self.0.deref()
    }
}

impl<'a> From<&'a str> for AsciiLower {
    fn from(_s: &'a str) -> AsciiLower {
        unimplemented!()
    }
}

#[cfg(test)]
mod test {
    use crate::ascii::Ascii;
    use crate::ascii::AsciiLower;
    use bytes::Bytes;

    #[test]
    fn ascii_from_bytes() {
        assert!(Ascii::from_bytes(Bytes::from_static("ю".as_bytes())).is_err());
    }

    #[test]
    fn ascii_lower_from_bytes() {
        assert!(AsciiLower::from_bytes(Bytes::from_static("qю".as_bytes())).is_err());
        assert!(AsciiLower::from_bytes(Bytes::from_static("qQ".as_bytes())).is_err());
        assert!(AsciiLower::from_bytes(Bytes::from_static("q".as_bytes())).is_ok());
        assert!(AsciiLower::from_bytes(Bytes::from_static("-".as_bytes())).is_ok());
        assert!(AsciiLower::from_bytes(Bytes::from_static("".as_bytes())).is_ok());
    }

    #[test]
    fn ascii_lower_display() {
        assert_eq!(
            "foo-bar",
            format!(
                "{}",
                AsciiLower::from_bytes(Bytes::from_static(b"foo-bar")).unwrap()
            ),
        );
    }
}
<|endoftext|>


<commit_before>use sdl2::render::Renderer;
use game::gfx::{Sprite, CopySprite, AnimatedSprite};
use game::data::Rectangle;
use game::constants::{CHARACTER_POS_W, CHARACTER_POS_H, CHARACTER_W, CHARACTER_H, FIRE_SPRITE_START_INDEX};
use views::{Orientation};
use data::{load_character};

pub enum Stance {
  Running = 0,
  Firing = 1,
}

pub struct Character {
  pub rect: Rectangle,
  pub sprites: AnimatedSprite,
  pub current: Orientation,
  pub heading: Orientation,
  pub move_anim_index: u32,
  pub fire_anim_index: u32,
}

impl Character {
  pub fn new(renderer: &mut Renderer) -> Character {
    Character {
      rect: Rectangle {
        x: CHARACTER_POS_W,
        y: CHARACTER_POS_H,
        w: CHARACTER_W,
        h: CHARACTER_H,
      },
      sprites: Character::get_sprite(renderer, 30.0),
      current: Orientation::Down,
      heading: Orientation::Down,
      move_anim_index: 0,
      fire_anim_index: 0,
    }
  }

  fn get_sprite(renderer: &mut Renderer, fps: f64) -> AnimatedSprite {
    let character_spritesheet = Sprite::load(&renderer, "assets/character.png").unwrap();

    let character_datapoints = load_character();
    let mut character_sprites = Vec::with_capacity(512);

    for x in 0..(FIRE_SPRITE_START_INDEX - 1) {
      character_sprites.push(character_spritesheet.region(character_datapoints[x]).unwrap());
    }

    for x in FIRE_SPRITE_START_INDEX..255 {
      character_sprites.push(character_spritesheet.region(character_datapoints[x]).unwrap());
    }

    AnimatedSprite::with_fps(character_sprites, fps)
  }

  pub fn update(&mut self, dt: f64, dx: f64, dy: f64, stance: Stance) {
    self.sprites.add_time(dt);
    self.current =
      if dx == 0.0 && dy < 0.0       { Orientation::Up }
      else if dx > 0.0 && dy < 0.0   { Orientation::UpRight }
      else if dx < 0.0 && dy < 0.0   { Orientation::UpLeft }
      else if dx == 0.0 && dy == 0.0 { self.heading }
      else if dx > 0.0 && dy == 0.0  { Orientation::Right }
      else if dx < 0.0 && dy == 0.0  { Orientation::Left }
      else if dx == 0.0 && dy > 0.0  { Orientation::Down }
      else if dx > 0.0 && dy > 0.0   { Orientation::DownRight }
      else if dx < 0.0 && dy > 0.0   { Orientation::DownLeft }
      else { unreachable!() };

    self.heading = self.current;

    if dx == 0.0 && dy == 0.0 {
      let index = self.heading as usize * 28;
      self.sprites.set_curr_frames(index, index+1);
    } else {
      match stance {
        Stance::Running => {
          let index = self.current as usize * 28;
          self.sprites.set_curr_frames(index, index+13);
        },
        Stance::Firing => {
          let index = FIRE_SPRITE_START_INDEX + self.current as usize * 5;
          self.sprites.set_curr_frames(index, index+4);
        }
      }
    }
  }

  pub fn render(&mut self, renderer: &mut Renderer) {
    renderer.copy_sprite(&self.sprites, self.rect);
  }
}
<commit_msg>Fix firing logic<commit_after>use sdl2::render::Renderer;
use game::gfx::{Sprite, CopySprite, AnimatedSprite};
use game::data::Rectangle;
use game::constants::{CHARACTER_POS_W, CHARACTER_POS_H, CHARACTER_W, CHARACTER_H, FIRE_SPRITE_START_INDEX};
use views::{Orientation};
use data::{load_character};

#[derive(PartialEq)]
pub enum Stance {
  Running = 0,
  Firing = 1,
}

pub struct Character {
  pub rect: Rectangle,
  pub sprites: AnimatedSprite,
  pub current: Orientation,
  pub heading: Orientation,
  pub move_anim_index: u32,
  pub fire_anim_index: u32,
}

impl Character {
  pub fn new(renderer: &mut Renderer) -> Character {
    Character {
      rect: Rectangle {
        x: CHARACTER_POS_W,
        y: CHARACTER_POS_H,
        w: CHARACTER_W,
        h: CHARACTER_H,
      },
      sprites: Character::get_sprite(renderer, 30.0),
      current: Orientation::Down,
      heading: Orientation::Down,
      move_anim_index: 0,
      fire_anim_index: 0,
    }
  }

  fn get_sprite(renderer: &mut Renderer, fps: f64) -> AnimatedSprite {
    let character_spritesheet = Sprite::load(&renderer, "assets/character.png").unwrap();

    let character_datapoints = load_character();
    let mut character_sprites = Vec::with_capacity(512);

    for x in 0..(FIRE_SPRITE_START_INDEX - 1) {
      character_sprites.push(character_spritesheet.region(character_datapoints[x]).unwrap());
    }

    for x in FIRE_SPRITE_START_INDEX..255 {
      character_sprites.push(character_spritesheet.region(character_datapoints[x]).unwrap());
    }

    AnimatedSprite::with_fps(character_sprites, fps)
  }

  pub fn update(&mut self, dt: f64, dx: f64, dy: f64, stance: Stance) {
    self.sprites.add_time(dt);
    self.current =
      if dx == 0.0 && dy < 0.0       { Orientation::Up }
      else if dx > 0.0 && dy < 0.0   { Orientation::UpRight }
      else if dx < 0.0 && dy < 0.0   { Orientation::UpLeft }
      else if dx == 0.0 && dy == 0.0 { self.heading }
      else if dx > 0.0 && dy == 0.0  { Orientation::Right }
      else if dx < 0.0 && dy == 0.0  { Orientation::Left }
      else if dx == 0.0 && dy > 0.0  { Orientation::Down }
      else if dx > 0.0 && dy > 0.0   { Orientation::DownRight }
      else if dx < 0.0 && dy > 0.0   { Orientation::DownLeft }
      else { unreachable!() };

    self.heading = self.current;

    if dx == 0.0 && dy == 0.0 && stance != Stance::Firing {
      let index = self.heading as usize * 28;
      self.sprites.set_curr_frames(index, index+1);
    } else {
      match stance {
        Stance::Running => {
          let index = self.current as usize * 28;
          self.sprites.set_curr_frames(index, index+13);
        },
        Stance::Firing => {
          let index = FIRE_SPRITE_START_INDEX + self.current as usize * 5;
          self.sprites.set_curr_frames(index, index+4);
        }
      }
    }
  }

  pub fn render(&mut self, renderer: &mut Renderer) {
    renderer.copy_sprite(&self.sprites, self.rect);
  }
}
<|endoftext|>


<commit_before>//! Diagnostic reporting support for the codespan crate

use codespan::ByteSpan;

use Severity;

/// A style for the label
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum LabelStyle {
    Primary,
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic
#[derive(Clone, Debug)]
pub struct Label {
    /// The span we are going to include in the final snippet.
    pub span: ByteSpan,
    /// A message to provide some additional information for the underlined code.
    pub message: Option<String>,
    /// The style to use for the label.
    pub style: LabelStyle,
}

/// Represents a diagnostic message and associated child messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// The main message associated with this diagnostic
    pub message: String,
    /// The labelled spans marking the regions of code that cause this
    /// diagnostic to be raised
    pub labels: Vec<Label>,
}
<commit_msg>Document LabelStyle<commit_after>//! Diagnostic reporting support for the codespan crate

use codespan::ByteSpan;

use Severity;

/// A style for the label
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum LabelStyle {
    /// The main focus of the diagnostic
    Primary,
    /// Supporting labels that may help to isolate the cause of the diagnostic
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic
#[derive(Clone, Debug)]
pub struct Label {
    /// The span we are going to include in the final snippet.
    pub span: ByteSpan,
    /// A message to provide some additional information for the underlined code.
    pub message: Option<String>,
    /// The style to use for the label.
    pub style: LabelStyle,
}

/// Represents a diagnostic message and associated child messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// The main message associated with this diagnostic
    pub message: String,
    /// The labelled spans marking the regions of code that cause this
    /// diagnostic to be raised
    pub labels: Vec<Label>,
}
<|endoftext|>


<commit_before>#![cfg(feature = "longest-match-cache")]

//! The cache that speeds up ZopfliFindLongestMatch of lz77.c.

use std::mem::size_of;
use std::ptr::null_mut;

use libc::funcs::c95::stdlib::{free, malloc};
use libc::{c_void, size_t};

use util::CACHE_LENGTH;

/// Cache used by ZopfliFindLongestMatch to remember previously found length/dist values.
/// This is needed because the squeeze runs will ask these values multiple times for the same position.
/// Uses large amounts of memory, since it has to remember the distance belonging
/// to every possible shorter-than-the-best length (the so called "sublen" array).
pub struct LongestMatchCache {
    pub length: *mut u16,
    pub dist: *mut u16,
    sublen: *mut u8,
}

impl LongestMatchCache {
    /// Initializes the ZopfliLongestMatchCache.
    unsafe fn new(blocksize: usize) -> LongestMatchCache {
        let length: *mut u16 = malloc((size_of::<u16>() * blocksize) as size_t) as *mut u16;
        let dist: *mut u16 = malloc((size_of::<u16>() * blocksize) as size_t) as *mut u16;

        // Rather large amount of memory.
        let sublen_size = (CACHE_LENGTH * 3 * blocksize) as size_t;
        let sublen: *mut u8 = malloc(sublen_size) as *mut u8;
        if sublen == null_mut() {
            panic!("Error: Out of memory. Tried allocating {} bytes of memory.", sublen_size);
        }

        // length > 0 and dist 0 is invalid combination, which indicates on purpose
        // that this cache value is not filled in yet.
        for i in 0..blocksize {
            *length.offset(i as isize) = 1;
        }
        for i in 0..blocksize {
            *dist.offset(i as isize) = 0;
        }
        for i in 0..sublen_size {
            *sublen.offset(i as isize) = 0;
        }
        LongestMatchCache {
            length: length,
            dist: dist,
            sublen: sublen,
        }
    }
}

/// Frees up the memory of the ZopfliLongestMatchCache.
unsafe fn clean_cache(lmc: *mut LongestMatchCache) {
    free((*lmc).length as *mut c_void);
    free((*lmc).dist as *mut c_void);
    free((*lmc).sublen as *mut c_void);
}

/// Stores sublen array in the cache.
pub unsafe fn sublen_to_cache(sublen: *const u16, pos: usize, length: usize, lmc: *mut LongestMatchCache) {
    if CACHE_LENGTH == 0 {
        return;
    }

    let cache: *mut u8 = (*lmc).sublen.offset((CACHE_LENGTH * pos * 3) as isize);
    if length < 3 {
        return;
    }

    let mut j: usize = 0;
    let mut bestlength: u32 = 0;
    for i in 3..length+1 {
        if i == length || *sublen.offset(i as isize) != *sublen.offset(i as isize + 1) {
            *cache.offset(j as isize * 3) = (i - 3) as u8;
            *cache.offset(j as isize * 3 + 1) = (*sublen.offset(i as isize) % 256) as u8;
            *cache.offset(j as isize * 3 + 2) = ((*sublen.offset(i as isize) >> 8) % 256) as u8;
            bestlength = i as u32;
            j += 1;
            if j >= CACHE_LENGTH {
                break;
            }
        }
    }

    if j < CACHE_LENGTH {
        assert_eq!(bestlength as usize, length);
        *cache.offset((CACHE_LENGTH as isize - 1) * 3) = (bestlength - 3) as u8;
    } else {
        assert!(bestlength as usize <= length, "{} <= {}", bestlength, length);
    }
    assert_eq!(bestlength, max_cached_sublen(lmc, pos, length));
}

/// Extracts sublen array from the cache.
pub unsafe fn cache_to_sublen(lmc: *const LongestMatchCache, pos: usize, length: usize, sublen: *mut u16) {
    if CACHE_LENGTH == 0 {
        return;
    }

    if length < 3 {
        return;
    }
    let cache: *mut u8 = (*lmc).sublen.offset((CACHE_LENGTH * pos * 3) as isize);
    let maxlength: u32 = max_cached_sublen(lmc, pos, length);
    let mut prevlength: u32 = 0;
    for j in 0..CACHE_LENGTH {
        let length: u32 = *cache.offset(j as isize * 3) as u32 + 3;
        let dist: u32 = *cache.offset(j as isize * 3 + 1) as u32 + 256 * *cache.offset(j as isize * 3 + 2) as u32;
        for i in prevlength..length+1 {
            *sublen.offset(i as isize) = dist as u16;
        }
        if length == maxlength {
            break;
        }
        prevlength = length + 1;
    }
}

/// Returns the length up to which could be stored in the cache.
pub unsafe fn max_cached_sublen(lmc: *const LongestMatchCache, pos: usize, _length: usize) -> u32 {
    if CACHE_LENGTH == 0 {
        return 0;
    }
    let cache: *const u8 = (*lmc).sublen.offset((CACHE_LENGTH * pos * 3) as isize);
    if (*cache.offset(1) == 0 && *cache.offset(2) == 0) {
        // No sublen cached.
        return 0;
    }
    *cache.offset(((CACHE_LENGTH - 1) * 3) as isize) as u32 + 3
}
<commit_msg>cleanup<commit_after>#![cfg(feature = "longest-match-cache")]

//! The cache that speeds up ZopfliFindLongestMatch of lz77.c.

use std::mem::size_of;
use std::ptr::null_mut;

use libc::funcs::c95::stdlib::{free, malloc};
use libc::{c_void, size_t};

use util::CACHE_LENGTH;

/// Cache used by ZopfliFindLongestMatch to remember previously found length/dist values.
/// This is needed because the squeeze runs will ask these values multiple times for the same position.
/// Uses large amounts of memory, since it has to remember the distance belonging
/// to every possible shorter-than-the-best length (the so called "sublen" array).
pub struct LongestMatchCache {
    pub length: *mut u16,
    pub dist: *mut u16,
    sublen: *mut u8,
}

impl LongestMatchCache {
    /// Initializes the ZopfliLongestMatchCache.
    unsafe fn new(blocksize: usize) -> LongestMatchCache {
        let length: *mut u16 = malloc((size_of::<u16>() * blocksize) as size_t) as *mut u16;
        let dist: *mut u16 = malloc((size_of::<u16>() * blocksize) as size_t) as *mut u16;

        // Rather large amount of memory.
        let sublen_size = (CACHE_LENGTH * 3 * blocksize) as size_t;
        let sublen: *mut u8 = malloc(sublen_size) as *mut u8;
        if sublen == null_mut() {
            panic!("Error: Out of memory. Tried allocating {} bytes of memory.", sublen_size);
        }

        // length > 0 and dist 0 is invalid combination, which indicates on purpose
        // that this cache value is not filled in yet.
        for i in 0..blocksize {
            *length.offset(i as isize) = 1;
        }
        for i in 0..blocksize {
            *dist.offset(i as isize) = 0;
        }
        for i in 0..sublen_size {
            *sublen.offset(i as isize) = 0;
        }
        LongestMatchCache {
            length: length,
            dist: dist,
            sublen: sublen,
        }
    }
}

/// Frees up the memory of the ZopfliLongestMatchCache.
unsafe fn clean_cache(lmc: *mut LongestMatchCache) {
    free((*lmc).length as *mut c_void);
    free((*lmc).dist as *mut c_void);
    free((*lmc).sublen as *mut c_void);
}

/// Stores sublen array in the cache.
pub unsafe fn sublen_to_cache(sublen: *const u16, pos: usize, length: usize, lmc: *mut LongestMatchCache) {
    if CACHE_LENGTH == 0 {
        return;
    }

    let cache: *mut u8 = (*lmc).sublen.offset((CACHE_LENGTH * pos * 3) as isize);
    if length < 3 {
        return;
    }

    let mut j: usize = 0;
    let mut bestlength: u32 = 0;
    for i in 3..length+1 {
        if i == length || *sublen.offset(i as isize) != *sublen.offset(i as isize + 1) {
            *cache.offset(j as isize * 3) = (i - 3) as u8;
            *cache.offset(j as isize * 3 + 1) = (*sublen.offset(i as isize) % 256) as u8;
            *cache.offset(j as isize * 3 + 2) = ((*sublen.offset(i as isize) >> 8) % 256) as u8;
            bestlength = i as u32;
            j += 1;
            if j >= CACHE_LENGTH {
                break;
            }
        }
    }

    if j < CACHE_LENGTH {
        assert_eq!(bestlength as usize, length);
        *cache.offset((CACHE_LENGTH as isize - 1) * 3) = (bestlength - 3) as u8;
    } else {
        assert!(bestlength as usize <= length, "{} <= {}", bestlength, length);
    }
    assert_eq!(bestlength, max_cached_sublen(lmc, pos, length));
}

/// Extracts sublen array from the cache.
pub unsafe fn cache_to_sublen(lmc: *const LongestMatchCache, pos: usize, length: usize, sublen: *mut u16) {
    if CACHE_LENGTH == 0 {
        return;
    }

    if length < 3 {
        return;
    }
    let cache: *mut u8 = (*lmc).sublen.offset((CACHE_LENGTH * pos * 3) as isize);
    let maxlength: u32 = max_cached_sublen(lmc, pos, length);
    let mut prevlength: u32 = 0;
    for j in 0..CACHE_LENGTH {
        let length: u32 = *cache.offset(j as isize * 3) as u32 + 3;
        let dist: u32 = *cache.offset(j as isize * 3 + 1) as u32 + 256 * *cache.offset(j as isize * 3 + 2) as u32;
        for i in prevlength..length+1 {
            *sublen.offset(i as isize) = dist as u16;
        }
        if length == maxlength {
            break;
        }
        prevlength = length + 1;
    }
}

/// Returns the length up to which could be stored in the cache.
pub unsafe fn max_cached_sublen(lmc: *const LongestMatchCache, pos: usize, _length: usize) -> u32 {
    if CACHE_LENGTH == 0 {
        return 0;
    }
    let cache: *const u8 = (*lmc).sublen.offset((CACHE_LENGTH * pos * 3) as isize);
    if *cache.offset(1) == 0 && *cache.offset(2) == 0 {
        // No sublen cached.
        return 0;
    }
    *cache.offset(((CACHE_LENGTH - 1) * 3) as isize) as u32 + 3
}
<|endoftext|>


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

use std::str::FromStr;

use bodyparser;
use bldr_core::build_config::{BLDR_CFG, BuildCfg};
use github_api_client::GitHubClient;
use hab_core::package::Plan;
use http_gateway::http::controller::*;
use iron::status;
use persistent;
use protocol::originsrv::{OriginProject, OriginProjectGet};
use protocol::scheduler::{Group, GroupCreate};
use router::Router;

use error::Error;
use headers::*;
use types::*;

pub enum GitHubEvent {
    Push,
    Ping,
}

impl FromStr for GitHubEvent {
    type Err = Error;

    fn from_str(event: &str) -> Result<Self, Self::Err> {
        match event {
            "ping" => Ok(GitHubEvent::Ping),
            "push" => Ok(GitHubEvent::Push),
            _ => Err(Error::UnknownGitHubEvent(event.to_string())),
        }
    }
}

enum HandleResult<T> {
    Ok(T),
    Err(Response),
}

pub fn handle_event(req: &mut Request) -> IronResult<Response> {
    let event = match req.headers.get::<XGitHubEvent>() {
        Some(&XGitHubEvent(ref event)) => {
            match GitHubEvent::from_str(event) {
                Ok(event) => event,
                Err(err) => return Ok(Response::with((status::BadRequest, err.to_string()))),
            }
        }
        _ => return Ok(Response::with(status::BadRequest)),
    };
    // JW TODO: Authenticate hook
    match event {
        GitHubEvent::Ping => Ok(Response::with(status::Ok)),
        GitHubEvent::Push => handle_push(req),
    }
}

pub fn repo_file_content(req: &mut Request) -> IronResult<Response> {
    let github = req.get::<persistent::Read<GitHubCli>>().unwrap();
    let session = req.extensions.get::<Authenticated>().unwrap();
    let params = req.extensions.get::<Router>().unwrap();
    let path = match params.find("path") {
        Some(path) => path,
        None => return Ok(Response::with(status::BadRequest)),
    };
    let install_id = match params.find("install_id") {
        Some(install_id) => {
            match install_id.parse::<u32>() {
                Ok(install_id) => install_id,
                Err(_) => return Ok(Response::with(status::BadRequest)),
            }
        }
        None => return Ok(Response::with(status::BadRequest)),
    };
    let token = {
        match github.app_installation_token(install_id) {
            Ok(token) => token,
            Err(err) => {
                return Ok(Response::with((status::BadGateway, err.to_string())));
            }
        }
    };
    let repo = {
        let repo = match params.find("repo") {
            Some(repo) => repo,
            None => return Ok(Response::with(status::BadRequest)),
        };
        let repos = match github.repositories(session.get_auth_token(), install_id) {
            Ok(repos) => repos,
            Err(err) => return Ok(Response::with((status::BadGateway, err.to_string()))),
        };
        match repos.into_iter().find(|r| r.name == repo) {
            Some(repo) => repo,
            None => return Ok(Response::with(status::NotFound)),
        }
    };
    match github.contents(&token, repo.id, path) {
        Ok(search) => Ok(render_json(status::Ok, &search)),
        Err(err) => Ok(Response::with((status::BadGateway, err.to_string()))),
    }
}

pub fn search_code(req: &mut Request) -> IronResult<Response> {
    let github = req.get::<persistent::Read<GitHubCli>>().unwrap();
    let params = req.extensions.get::<Router>().unwrap();
    let query = match req.url.query() {
        Some(query) => query,
        None => return Ok(Response::with(status::BadRequest)),
    };
    let install_id = match params.find("install_id") {
        Some(install_id) => {
            match install_id.parse::<u32>() {
                Ok(install_id) => install_id,
                Err(_) => return Ok(Response::with(status::BadRequest)),
            }
        }
        None => return Ok(Response::with(status::BadRequest)),
    };
    let token = {
        match github.app_installation_token(install_id) {
            Ok(token) => token,
            Err(err) => {
                return Ok(Response::with((status::BadGateway, err.to_string())));
            }
        }
    };
    match github.search_code(&token, query) {
        Ok(search) => Ok(render_json(status::Ok, &search)),
        Err(err) => Ok(Response::with((status::BadGateway, err.to_string()))),
    }
}

fn handle_push(req: &mut Request) -> IronResult<Response> {
    let hook = match req.get::<bodyparser::Struct<GitHubWebhookPush>>() {
        Ok(Some(hook)) => hook,
        Ok(None) => return Ok(Response::with(status::UnprocessableEntity)),
        Err(err) => {
            return Ok(Response::with(
                (status::UnprocessableEntity, err.to_string()),
            ));
        }
    };

    if hook.commits.is_empty() {
        return Ok(Response::with(status::Ok));
    }

    let github = req.get::<persistent::Read<GitHubCli>>().unwrap();
    let token = match github.app_installation_token(hook.installation.id) {
        Ok(token) => token,
        Err(err) => {
            return Ok(Response::with((status::BadGateway, err.to_string())));
        }
    };

    let mut query = format!("q={}+in:path+repo:{}", "plan.sh", hook.repository.full_name);
    let plans = match github.search_code(&token, &query) {
        Ok(search) => search.items,
        Err(err) => return Ok(Response::with((status::BadGateway, err.to_string()))),
    };

    if plans.is_empty() {
        return Ok(Response::with(status::Ok));
    }

    query = format!("q={}+in:path+repo:{}", BLDR_CFG, hook.repository.full_name);

    let config = match github.search_code(&token, &query) {
        Ok(search) => {
            match search
                .items
                .into_iter()
                .filter(|i| i.path == BLDR_CFG)
                .collect::<Vec<SearchItem>>()
                .pop() {
                Some(item) => {
                    match read_bldr_config(&*github, &token, &hook, &item.path) {
                        HandleResult::Ok(cfg) => Some(cfg),
                        HandleResult::Err(response) => return Ok(response),
                    }
                }
                None => None,
            }
        }
        Err(err) => return Ok(Response::with((status::BadGateway, err.to_string()))),
    };

    debug!("Config, {:?}", config);

    let mut plans = match read_plans(&github, &token, &hook, plans) {
        HandleResult::Ok(plans) => plans,
        HandleResult::Err(err) => return Ok(err),
    };

    debug!("Plans, {:?}", plans);

    if let Some(cfg) = config {
        plans.retain(|plan| match cfg.get(&plan.name) {
            Some(project) => hook.changed().iter().any(|f| project.triggered_by(f)),
            None => false,
        })
    }

    build_plans(req, &hook.repository.clone_url, plans)
}

fn build_plans(req: &mut Request, repo_url: &str, plans: Vec<Plan>) -> IronResult<Response> {
    let mut request = GroupCreate::new();

    for plan in plans.into_iter() {
        let mut project_get = OriginProjectGet::new();
        project_get.set_name(format!("{}/{}", &plan.origin, &plan.name));

        match route_message::<OriginProjectGet, OriginProject>(req, &project_get) {
            Ok(project) => {
                if repo_url != project.get_vcs_data() {
                    error!(
                        "Incoming repository URL ({}) doesn't match what's in the project vcs data ({}). Aborting.",
                        repo_url,
                        project.get_vcs_data()
                    );
                    continue;
                }
            }
            Err(err) => {
                error!("Failed to fetch project. err = {:?}", &err);
                continue;
            }
        }

        debug!("Scheduling, {:?}", plan);
        request.set_origin(plan.origin);
        request.set_package(plan.name);
        // JW TODO: We need to be able to determine which platform this build is for based on
        // the directory structure the plan is found in or metadata inside the plan. We will need
        // to have this done before we support building additional targets with Builder.
        request.set_target("x86_64-linux".to_string());
        match route_message::<GroupCreate, Group>(req, &request) {
            Ok(group) => debug!("Group created, {:?}", group),
            Err(err) => debug!("Failed to create group, {:?}", err),
        }
    }

    Ok(Response::with(status::Ok))
}

fn read_bldr_config(
    github: &GitHubClient,
    token: &str,
    hook: &GitHubWebhookPush,
    path: &str,
) -> HandleResult<BuildCfg> {
    match github.contents(token, hook.repository.id, path) {
        Ok(contents) => {
            match contents.decode() {
                Ok(ref bytes) => {
                    match BuildCfg::from_slice(bytes) {
                        Ok(cfg) => HandleResult::Ok(cfg),
                        Err(err) => HandleResult::Err(Response::with(
                            (status::UnprocessableEntity, err.to_string()),
                        )),
                    }
                }
                Err(err) => {
                    HandleResult::Err(Response::with(
                        (status::UnprocessableEntity, err.to_string()),
                    ))
                }
            }
        }
        Err(err) => HandleResult::Err(Response::with((status::BadGateway, err.to_string()))),
    }
}

fn read_plans(
    github: &GitHubClient,
    token: &str,
    hook: &GitHubWebhookPush,
    plans: Vec<SearchItem>,
) -> HandleResult<Vec<Plan>> {
    let mut parsed = Vec::with_capacity(plans.len());
    for plan in plans {
        match github.contents(token, hook.repository.id, &plan.path) {
            Ok(contents) => {
                match contents.decode() {
                    Ok(bytes) => {
                        match Plan::from_bytes(bytes.as_slice()) {
                            Ok(plan) => parsed.push(plan),
                            Err(err) => debug!("{}, {}", plan.path, err),
                        }
                    }
                    Err(err) => {
                        return HandleResult::Err(Response::with((
                            status::UnprocessableEntity,
                            format!("{}, {}", plan.path, err),
                        )))
                    }
                }
            }
            Err(err) => {
                return HandleResult::Err(Response::with(
                    (status::BadGateway, format!("{}, {}", plan.path, err)),
                ))
            }
        }
    }
    HandleResult::Ok(parsed)
}
<commit_msg>Fix spelling mistake from last commit<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::str::FromStr;

use bodyparser;
use bldr_core::build_config::{BLDR_CFG, BuildCfg};
use github_api_client::GitHubClient;
use hab_core::package::Plan;
use http_gateway::http::controller::*;
use iron::status;
use persistent;
use protocol::originsrv::{OriginProject, OriginProjectGet};
use protocol::scheduler::{Group, GroupCreate};
use router::Router;

use error::Error;
use headers::*;
use types::*;

pub enum GitHubEvent {
    Push,
    Ping,
}

impl FromStr for GitHubEvent {
    type Err = Error;

    fn from_str(event: &str) -> Result<Self, Self::Err> {
        match event {
            "ping" => Ok(GitHubEvent::Ping),
            "push" => Ok(GitHubEvent::Push),
            _ => Err(Error::UnknownGitHubEvent(event.to_string())),
        }
    }
}

enum HandleResult<T> {
    Ok(T),
    Err(Response),
}

pub fn handle_event(req: &mut Request) -> IronResult<Response> {
    let event = match req.headers.get::<XGitHubEvent>() {
        Some(&XGitHubEvent(ref event)) => {
            match GitHubEvent::from_str(event) {
                Ok(event) => event,
                Err(err) => return Ok(Response::with((status::BadRequest, err.to_string()))),
            }
        }
        _ => return Ok(Response::with(status::BadRequest)),
    };
    // JW TODO: Authenticate hook
    match event {
        GitHubEvent::Ping => Ok(Response::with(status::Ok)),
        GitHubEvent::Push => handle_push(req),
    }
}

pub fn repo_file_content(req: &mut Request) -> IronResult<Response> {
    let github = req.get::<persistent::Read<GitHubCli>>().unwrap();
    let session = req.extensions.get::<Authenticated>().unwrap();
    let params = req.extensions.get::<Router>().unwrap();
    let path = match params.find("path") {
        Some(path) => path,
        None => return Ok(Response::with(status::BadRequest)),
    };
    let install_id = match params.find("install_id") {
        Some(install_id) => {
            match install_id.parse::<u32>() {
                Ok(install_id) => install_id,
                Err(_) => return Ok(Response::with(status::BadRequest)),
            }
        }
        None => return Ok(Response::with(status::BadRequest)),
    };
    let token = {
        match github.app_installation_token(install_id) {
            Ok(token) => token,
            Err(err) => {
                return Ok(Response::with((status::BadGateway, err.to_string())));
            }
        }
    };
    let repo = {
        let repo = match params.find("repo") {
            Some(repo) => repo,
            None => return Ok(Response::with(status::BadRequest)),
        };
        let repos = match github.repositories(session.get_oauth_token(), install_id) {
            Ok(repos) => repos,
            Err(err) => return Ok(Response::with((status::BadGateway, err.to_string()))),
        };
        match repos.into_iter().find(|r| r.name == repo) {
            Some(repo) => repo,
            None => return Ok(Response::with(status::NotFound)),
        }
    };
    match github.contents(&token, repo.id, path) {
        Ok(search) => Ok(render_json(status::Ok, &search)),
        Err(err) => Ok(Response::with((status::BadGateway, err.to_string()))),
    }
}

pub fn search_code(req: &mut Request) -> IronResult<Response> {
    let github = req.get::<persistent::Read<GitHubCli>>().unwrap();
    let params = req.extensions.get::<Router>().unwrap();
    let query = match req.url.query() {
        Some(query) => query,
        None => return Ok(Response::with(status::BadRequest)),
    };
    let install_id = match params.find("install_id") {
        Some(install_id) => {
            match install_id.parse::<u32>() {
                Ok(install_id) => install_id,
                Err(_) => return Ok(Response::with(status::BadRequest)),
            }
        }
        None => return Ok(Response::with(status::BadRequest)),
    };
    let token = {
        match github.app_installation_token(install_id) {
            Ok(token) => token,
            Err(err) => {
                return Ok(Response::with((status::BadGateway, err.to_string())));
            }
        }
    };
    match github.search_code(&token, query) {
        Ok(search) => Ok(render_json(status::Ok, &search)),
        Err(err) => Ok(Response::with((status::BadGateway, err.to_string()))),
    }
}

fn handle_push(req: &mut Request) -> IronResult<Response> {
    let hook = match req.get::<bodyparser::Struct<GitHubWebhookPush>>() {
        Ok(Some(hook)) => hook,
        Ok(None) => return Ok(Response::with(status::UnprocessableEntity)),
        Err(err) => {
            return Ok(Response::with(
                (status::UnprocessableEntity, err.to_string()),
            ));
        }
    };

    if hook.commits.is_empty() {
        return Ok(Response::with(status::Ok));
    }

    let github = req.get::<persistent::Read<GitHubCli>>().unwrap();
    let token = match github.app_installation_token(hook.installation.id) {
        Ok(token) => token,
        Err(err) => {
            return Ok(Response::with((status::BadGateway, err.to_string())));
        }
    };

    let mut query = format!("q={}+in:path+repo:{}", "plan.sh", hook.repository.full_name);
    let plans = match github.search_code(&token, &query) {
        Ok(search) => search.items,
        Err(err) => return Ok(Response::with((status::BadGateway, err.to_string()))),
    };

    if plans.is_empty() {
        return Ok(Response::with(status::Ok));
    }

    query = format!("q={}+in:path+repo:{}", BLDR_CFG, hook.repository.full_name);

    let config = match github.search_code(&token, &query) {
        Ok(search) => {
            match search
                .items
                .into_iter()
                .filter(|i| i.path == BLDR_CFG)
                .collect::<Vec<SearchItem>>()
                .pop() {
                Some(item) => {
                    match read_bldr_config(&*github, &token, &hook, &item.path) {
                        HandleResult::Ok(cfg) => Some(cfg),
                        HandleResult::Err(response) => return Ok(response),
                    }
                }
                None => None,
            }
        }
        Err(err) => return Ok(Response::with((status::BadGateway, err.to_string()))),
    };

    debug!("Config, {:?}", config);

    let mut plans = match read_plans(&github, &token, &hook, plans) {
        HandleResult::Ok(plans) => plans,
        HandleResult::Err(err) => return Ok(err),
    };

    debug!("Plans, {:?}", plans);

    if let Some(cfg) = config {
        plans.retain(|plan| match cfg.get(&plan.name) {
            Some(project) => hook.changed().iter().any(|f| project.triggered_by(f)),
            None => false,
        })
    }

    build_plans(req, &hook.repository.clone_url, plans)
}

fn build_plans(req: &mut Request, repo_url: &str, plans: Vec<Plan>) -> IronResult<Response> {
    let mut request = GroupCreate::new();

    for plan in plans.into_iter() {
        let mut project_get = OriginProjectGet::new();
        project_get.set_name(format!("{}/{}", &plan.origin, &plan.name));

        match route_message::<OriginProjectGet, OriginProject>(req, &project_get) {
            Ok(project) => {
                if repo_url != project.get_vcs_data() {
                    error!(
                        "Incoming repository URL ({}) doesn't match what's in the project vcs data ({}). Aborting.",
                        repo_url,
                        project.get_vcs_data()
                    );
                    continue;
                }
            }
            Err(err) => {
                error!("Failed to fetch project. err = {:?}", &err);
                continue;
            }
        }

        debug!("Scheduling, {:?}", plan);
        request.set_origin(plan.origin);
        request.set_package(plan.name);
        // JW TODO: We need to be able to determine which platform this build is for based on
        // the directory structure the plan is found in or metadata inside the plan. We will need
        // to have this done before we support building additional targets with Builder.
        request.set_target("x86_64-linux".to_string());
        match route_message::<GroupCreate, Group>(req, &request) {
            Ok(group) => debug!("Group created, {:?}", group),
            Err(err) => debug!("Failed to create group, {:?}", err),
        }
    }

    Ok(Response::with(status::Ok))
}

fn read_bldr_config(
    github: &GitHubClient,
    token: &str,
    hook: &GitHubWebhookPush,
    path: &str,
) -> HandleResult<BuildCfg> {
    match github.contents(token, hook.repository.id, path) {
        Ok(contents) => {
            match contents.decode() {
                Ok(ref bytes) => {
                    match BuildCfg::from_slice(bytes) {
                        Ok(cfg) => HandleResult::Ok(cfg),
                        Err(err) => HandleResult::Err(Response::with(
                            (status::UnprocessableEntity, err.to_string()),
                        )),
                    }
                }
                Err(err) => {
                    HandleResult::Err(Response::with(
                        (status::UnprocessableEntity, err.to_string()),
                    ))
                }
            }
        }
        Err(err) => HandleResult::Err(Response::with((status::BadGateway, err.to_string()))),
    }
}

fn read_plans(
    github: &GitHubClient,
    token: &str,
    hook: &GitHubWebhookPush,
    plans: Vec<SearchItem>,
) -> HandleResult<Vec<Plan>> {
    let mut parsed = Vec::with_capacity(plans.len());
    for plan in plans {
        match github.contents(token, hook.repository.id, &plan.path) {
            Ok(contents) => {
                match contents.decode() {
                    Ok(bytes) => {
                        match Plan::from_bytes(bytes.as_slice()) {
                            Ok(plan) => parsed.push(plan),
                            Err(err) => debug!("{}, {}", plan.path, err),
                        }
                    }
                    Err(err) => {
                        return HandleResult::Err(Response::with((
                            status::UnprocessableEntity,
                            format!("{}, {}", plan.path, err),
                        )))
                    }
                }
            }
            Err(err) => {
                return HandleResult::Err(Response::with(
                    (status::BadGateway, format!("{}, {}", plan.path, err)),
                ))
            }
        }
    }
    HandleResult::Ok(parsed)
}
<|endoftext|>


<commit_before>mod chunk {

    struct Address(u64, u64, u64);

    struct Chunk {
        children: [Option<Box<Chunk>>; 8],
        parent: Option<Box<Chunk>>,
        summary: i32,
        address: Address,
    }

    impl Address {
        fn from_string(&self) -> Address {
            Address(0, 0, 0)
        }

        fn ffs(value: u64) -> u8 {
            let mut mask = value;
            let mut bit: u8 = 0;

            while (mask & 1) != 0 {
                mask = mask >> 1;
                bit += 1;
            }
            bit
        }
    }

    impl ToString for Address {
        fn to_string(&self) -> String {
            String::from_str("")
        }

    }
}
<commit_msg>Implement translation for address<commit_after>#![allow(dead_code)]
mod chunk {

    struct Address(u64, u64, u64);

    struct Chunk {
        children: [Option<Box<Chunk>>; 8],
        parent: Option<Box<Chunk>>,
        summary: i32,
        address: Address,
    }

    impl Address {
        fn from_string(address: String) -> Address {
            let mut x: u64 = 0;
            let mut y: u64 = 0;
            let mut z: u64 = 0;
            let mut xadd: u8 = 0;
            let mut yadd: u8 = 0;
            let mut zadd: u8 = 0;

            for (i, c) in address.split_str("").enumerate() {
                if i > 63 {
                    break;
                }
                let (xadd, yadd, zadd) = match c {
                    "0" => (0, 0, 0),
                    "1" => (0, 0, 1),
                    "2" => (0, 1, 0),
                    "3" => (0, 1, 1),
                    "4" => (1, 0, 0),
                    "5" => (1, 0, 1),
                    "6" => (1, 1, 0),
                    "7" => (1, 1, 1),
                    _ => (0,0,0),
                };
            }
            Address(x, y, z)
        }
    }

    impl ToString for Address {
        fn to_string(&self) -> String {
            String::from_str("")
        }

    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use diem_types::{
    ledger_info::LedgerInfoWithSignatures,
    transaction::{TransactionListWithProof, Version},
};
use serde::{Deserialize, Serialize};
use std::fmt;

/// The response can carry different LedgerInfo types depending on whether the verification
/// is done via the local trusted validator set or a local waypoint.
#[allow(clippy::large_enum_variant)]
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
pub enum ResponseLedgerInfo {
    /// A typical response carries a LedgerInfo with signatures that should be verified using the
    /// local trusted validator set.
    VerifiableLedgerInfo(LedgerInfoWithSignatures),
    /// A response to `TargetType::HighestAvailable` chunk request type.
    ProgressiveLedgerInfo {
        // LedgerInfo that the corresponding GetChunkResponse is built relative to.
        target_li: LedgerInfoWithSignatures,
        // LedgerInfo for a version later than that of `target_li`
        // If `None`, this is the same as `target_li`
        highest_li: Option<LedgerInfoWithSignatures>,
    },
    /// During the initial catchup upon startup the chunks carry LedgerInfo that is verified
    /// using the local waypoint.
    LedgerInfoForWaypoint {
        // LedgerInfo corresponding to the waypoint version.
        waypoint_li: LedgerInfoWithSignatures,
        // In case a chunk terminates an epoch, the LedgerInfo corresponding to the epoch boundary.
        end_of_epoch_li: Option<LedgerInfoWithSignatures>,
    },
}

impl ResponseLedgerInfo {
    /// The version of the LedgerInfo relative to which the transactions proofs are built.
    pub fn version(&self) -> Version {
        match self {
            ResponseLedgerInfo::VerifiableLedgerInfo(li) => li.ledger_info().version(),
            ResponseLedgerInfo::ProgressiveLedgerInfo { target_li, .. } => {
                target_li.ledger_info().version()
            }
            ResponseLedgerInfo::LedgerInfoForWaypoint { waypoint_li, .. } => {
                waypoint_li.ledger_info().version()
            }
        }
    }
}

#[derive(Deserialize, Serialize, Clone, PartialEq, Eq)]
/// The returned chunk is bounded by the end of the known_epoch of the requester
/// (i.e., a chunk never crosses epoch boundaries).
pub struct GetChunkResponse {
    /// The proofs are built relative to the LedgerInfo in `response_ledger_info`.
    /// The specifics of ledger info verification depend on its type.
    pub response_li: ResponseLedgerInfo,
    /// chunk of transactions with proof corresponding to the ledger info carried by the response.
    pub txn_list_with_proof: TransactionListWithProof,
}

impl GetChunkResponse {
    pub fn new(
        response_li: ResponseLedgerInfo,
        txn_list_with_proof: TransactionListWithProof,
    ) -> Self {
        Self {
            response_li,
            txn_list_with_proof,
        }
    }
}
impl fmt::Debug for GetChunkResponse {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

impl fmt::Display for GetChunkResponse {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let txns_repr = match self.txn_list_with_proof.first_transaction_version {
            None => "empty".to_string(),
            Some(first_ver) => format!(
                "versions [{} - {}]",
                first_ver,
                first_ver - 1 + self.txn_list_with_proof.len() as u64
            ),
        };
        let response_li_repr = match &self.response_li {
            ResponseLedgerInfo::VerifiableLedgerInfo(li) => {
                format!("[verifiable LI {}]", li.ledger_info())
            }
            ResponseLedgerInfo::ProgressiveLedgerInfo {
                target_li,
                highest_li,
            } => format!(
                "[progressive LI: target LI {}, highest LI {}]",
                target_li.ledger_info(),
                highest_li.as_ref().unwrap_or(target_li).ledger_info(),
            ),
            ResponseLedgerInfo::LedgerInfoForWaypoint {
                waypoint_li,
                end_of_epoch_li,
            } => format!(
                "[waypoint LI {}, end of epoch LI {}]",
                waypoint_li.ledger_info(),
                end_of_epoch_li
                    .as_ref()
                    .map_or("None".to_string(), |li| li.ledger_info().to_string())
            ),
        };
        write!(
            f,
            "[ChunkResponse: response li: {}, txns: {}]",
            response_li_repr, txns_repr,
        )
    }
}
<commit_msg>[State Sync] Small cleanups to chunk_response<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use diem_types::{
    ledger_info::LedgerInfoWithSignatures,
    transaction::{TransactionListWithProof, Version},
};
use serde::{Deserialize, Serialize};
use std::fmt;

/// The response can carry different LedgerInfo types depending on whether the verification
/// is done via the local trusted validator set or a local waypoint.
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum ResponseLedgerInfo {
    /// A typical response carries a LedgerInfo with signatures that should be verified using the
    /// local trusted validator set.
    VerifiableLedgerInfo(LedgerInfoWithSignatures),
    /// A response to `TargetType::HighestAvailable` chunk request type.
    ProgressiveLedgerInfo {
        // LedgerInfo that the corresponding GetChunkResponse is built relative to.
        target_li: LedgerInfoWithSignatures,
        // LedgerInfo for a version later than that of `target_li`
        // If `None`, this is the same as `target_li`
        highest_li: Option<LedgerInfoWithSignatures>,
    },
    /// During the initial catchup upon startup the chunks carry LedgerInfo that is verified
    /// using the local waypoint.
    LedgerInfoForWaypoint {
        // LedgerInfo corresponding to the waypoint version.
        waypoint_li: LedgerInfoWithSignatures,
        // In case a chunk terminates an epoch, the LedgerInfo corresponding to the epoch boundary.
        end_of_epoch_li: Option<LedgerInfoWithSignatures>,
    },
}

impl ResponseLedgerInfo {
    /// The version of the LedgerInfo relative to which the transactions proofs are built.
    pub fn version(&self) -> Version {
        match self {
            ResponseLedgerInfo::VerifiableLedgerInfo(li) => li.ledger_info().version(),
            ResponseLedgerInfo::ProgressiveLedgerInfo { target_li, .. } => {
                target_li.ledger_info().version()
            }
            ResponseLedgerInfo::LedgerInfoForWaypoint { waypoint_li, .. } => {
                waypoint_li.ledger_info().version()
            }
        }
    }
}

/// The returned chunk is bounded by the end of the known_epoch of the requester
/// (i.e., a chunk never crosses epoch boundaries).
#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
pub struct GetChunkResponse {
    /// The proofs are built relative to the LedgerInfo in `response_li`.
    /// The specifics of ledger info verification depend on its type.
    pub response_li: ResponseLedgerInfo,
    /// Chunk of transactions with proof corresponding to the ledger info carried by the response.
    pub txn_list_with_proof: TransactionListWithProof,
}

impl GetChunkResponse {
    pub fn new(
        response_li: ResponseLedgerInfo,
        txn_list_with_proof: TransactionListWithProof,
    ) -> Self {
        Self {
            response_li,
            txn_list_with_proof,
        }
    }
}

impl fmt::Debug for GetChunkResponse {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

impl fmt::Display for GetChunkResponse {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let txns_repr = match self.txn_list_with_proof.first_transaction_version {
            None => "empty".to_string(),
            Some(first_ver) => format!(
                "versions [{} - {}]",
                first_ver,
                first_ver - 1 + self.txn_list_with_proof.len() as u64
            ),
        };
        let response_li_repr = match &self.response_li {
            ResponseLedgerInfo::VerifiableLedgerInfo(li) => {
                format!("[verifiable LI {}]", li.ledger_info())
            }
            ResponseLedgerInfo::ProgressiveLedgerInfo {
                target_li,
                highest_li,
            } => format!(
                "[progressive LI: target LI {}, highest LI {}]",
                target_li.ledger_info(),
                highest_li.as_ref().unwrap_or(target_li).ledger_info(),
            ),
            ResponseLedgerInfo::LedgerInfoForWaypoint {
                waypoint_li,
                end_of_epoch_li,
            } => format!(
                "[waypoint LI {}, end of epoch LI {}]",
                waypoint_li.ledger_info(),
                end_of_epoch_li
                    .as_ref()
                    .map_or("None".to_string(), |li| li.ledger_info().to_string())
            ),
        };
        write!(
            f,
            "[ChunkResponse: response li: {}, txns: {}]",
            response_li_repr, txns_repr,
        )
    }
}
<|endoftext|>


<commit_before>use cgmath;
use game::constants::{HOUSE_POSITIONS, TREE_POSITIONS};
use shaders::Position;
use specs;
use terrain_object::TerrainObjectDrawable;

#[derive(Debug, Clone)]
pub struct TerrainObjects {
  pub objects: Vec<TerrainObjectDrawable>,
}

impl TerrainObjects {
  pub fn new() -> TerrainObjects {
    TerrainObjects {
      objects: vec![
        TerrainObjectDrawable::new(Position::new(HOUSE_POSITIONS[0])),
        TerrainObjectDrawable::new(Position::new(HOUSE_POSITIONS[1])),
        TerrainObjectDrawable::new(Position::new(TREE_POSITIONS[0])),
        TerrainObjectDrawable::new(Position::new(TREE_POSITIONS[1])),
      ]
    }
  }
}

impl specs::Component for TerrainObjects {
  type Storage = specs::VecStorage<TerrainObjects>;
}
<commit_msg>Remove unused import<commit_after>use game::constants::{HOUSE_POSITIONS, TREE_POSITIONS};
use shaders::Position;
use specs;
use terrain_object::TerrainObjectDrawable;

#[derive(Debug, Clone)]
pub struct TerrainObjects {
  pub objects: Vec<TerrainObjectDrawable>,
}

impl TerrainObjects {
  pub fn new() -> TerrainObjects {
    TerrainObjects {
      objects: vec![
        TerrainObjectDrawable::new(Position::new(HOUSE_POSITIONS[0])),
        TerrainObjectDrawable::new(Position::new(HOUSE_POSITIONS[1])),
        TerrainObjectDrawable::new(Position::new(TREE_POSITIONS[0])),
        TerrainObjectDrawable::new(Position::new(TREE_POSITIONS[1])),
      ]
    }
  }
}

impl specs::Component for TerrainObjects {
  type Storage = specs::VecStorage<TerrainObjects>;
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//  based on:
//  http://shootout.alioth.debian.org/
//   u64q/program.php?test=mandelbrot&lang=python3&id=2
//
//  takes 3 optional args:
//   square image size, defaults to 80_u
//   output path, default is "" (no output), "-" means stdout
//   depth (max iterations per pixel), defaults to 50_u
//
//  in the shootout, they use 16000 as image size, 50 as depth,
//   and write to stdout:
//
//  ./shootout_mandelbrot 16000 "-" 50 > /tmp/mandel.pbm
//
//  writes pbm image to output path

use core::io::WriterUtil;
use core::hashmap::HashMap;

struct cmplx {
    re: f64,
    im: f64
}

impl ops::Mul<cmplx,cmplx> for cmplx {
    fn mul(&self, x: &cmplx) -> cmplx {
        cmplx {
            re: self.re*(*x).re - self.im*(*x).im,
            im: self.re*(*x).im + self.im*(*x).re
        }
    }
}

impl ops::Add<cmplx,cmplx> for cmplx {
    fn add(&self, x: &cmplx) -> cmplx {
        cmplx {
            re: self.re + (*x).re,
            im: self.im + (*x).im
        }
    }
}

struct Line {i: uint, b: ~[u8]}

fn cabs(x: cmplx) -> f64
{
    x.re*x.re + x.im*x.im
}

fn mb(x: cmplx, depth: uint) -> bool
{
    let mut z = x;
    let mut i = 0;
    while i < depth {
        if cabs(z) >= 4_f64 {
            return false;
        }
        z = z*z + x;
        i += 1;
    }
    true
}

fn fillbyte(x: cmplx, incr: f64, depth: uint) -> u8 {
    let mut rv = 0_u8;
    let mut i = 0_u8;
    while i < 8_u8 {
        let z = cmplx {re: x.re + (i as f64)*incr, im: x.im};
        if mb(z, depth) {
            rv += 1_u8 << (7_u8 - i);
        }
        i += 1_u8;
    }
    rv
}

fn chanmb(i: uint, size: uint, depth: uint) -> Line
{
    let bsize = size/8_u;
    let mut crv = vec::with_capacity(bsize);
    let incr = 2_f64/(size as f64);
    let y = incr*(i as f64) - 1_f64;
    let xincr = 8_f64*incr;
    for uint::range(0_u, bsize) |j| {
        let x = cmplx {re: xincr*(j as f64) - 1.5_f64, im: y};
        crv.push(fillbyte(x, incr, depth));
    };
    Line {i:i, b:crv}
}

struct Devnull();

impl io::Writer for Devnull {
    fn write(&self, _b: &const [u8]) {}
    fn seek(&self, _i: int, _s: io::SeekStyle) {}
    fn tell(&self) -> uint {0_u}
    fn flush(&self) -> int {0}
    fn get_type(&self) -> io::WriterType { io::File }
}

fn writer(path: ~str, pport: comm::Port<Line>, size: uint)
{
    let cout: @io::Writer = match path {
        ~"" => {
            @Devnull as @io::Writer
        }
        ~"-" => {
            io::stdout()
        }
        _ => {
            result::get(
                &io::file_writer(&Path(path),
                ~[io::Create, io::Truncate]))
        }
    };
    cout.write_line("P4");
    cout.write_line(fmt!("%u %u", size, size));
    let mut lines: HashMap<uint, Line> = HashMap::new();
    let mut done = 0_u;
    let mut i = 0_u;
    while i < size {
        let aline = pport.recv();
        if aline.i == done {
            debug!("W %u", done);
            cout.write(aline.b);
            done += 1_u;
            let mut prev = done;
            while prev <= i {
                match lines.pop(&prev) {
                    Some(pl) => {
                        debug!("WS %u", prev);
                        cout.write(pl.b);
                        done += 1_u;
                        prev += 1_u;
                    }
                    None => break
                };
            };
        }
        else {
            debug!("S %u", aline.i);
            lines.insert(aline.i, aline);
        };
        i += 1_u;
    }
}

fn main() {
    let args = os::args();
    let args = if os::getenv(~"RUST_BENCH").is_some() {
        ~[~"", ~"4000", ~"50"]
    } else {
        args
    };

    let depth = if vec::len(args) < 4_u { 50_u }
    else { uint::from_str(args[3]).get() };

    let path = if vec::len(args) < 3_u { ~"" }
    else { copy args[2] };  // FIXME: bad for perf

    let size = if vec::len(args) < 2_u { 80_u }
    else { uint::from_str(args[1]).get() };

    let (pport, pchan) = comm::stream();
    let pchan = comm::SharedChan::new(pchan);
    for uint::range(0_u, size) |j| {
        let cchan = pchan.clone();
        do task::spawn { cchan.send(chanmb(j, size, depth)) };
    };
    writer(path, pport, size);
}
<commit_msg>test: Rewrite mandelbrot benchmark.<commit_after>use core::cast::transmute;
use core::from_str::FromStr;
use core::i32::range;
use core::libc::{STDOUT_FILENO, c_int, fdopen, fputc};

static ITER: uint = 50;
static LIMIT: f64 = 2.0;

#[fixed_stack_segment]
fn main() {
    unsafe {
        let w: i32 = FromStr::from_str(os::args()[1]).get(), h = w;
        let mut byte_acc: i8 = 0;
        let mut bit_num: i32 = 0;

        println(fmt!("P4\n%d %d", w as int, h as int));

        let mode = "w";
        let stdout = fdopen(STDOUT_FILENO as c_int, transmute(&mode[0]));

        for range(0, h) |y| {
            let y = y as f64;
            for range(0, w) |x| {
                let mut (Zr, Zi, Tr, Ti) = (0f64, 0f64, 0f64, 0f64);
                let Cr = 2.0 * (x as f64) / (w as f64) - 1.5;
                let Ci = 2.0 * (y as f64) / (h as f64) - 1.0;

                for ITER.times {
                    if Tr + Ti > LIMIT * LIMIT {
                        break;
                    }

                    Zi = 2.0*Zr*Zi + Ci;
                    Zr = Tr - Ti + Cr;
                    Tr = Zr * Zr;
                    Ti = Zi * Zi;
                }

                byte_acc <<= 1;
                if Tr + Ti <= LIMIT * LIMIT {
                    byte_acc |= 1;
                }

                bit_num += 1;

                if bit_num == 8 {
                    fputc(byte_acc as c_int, stdout);
                    byte_acc = 0;
                    bit_num = 0;
                } else if x == w - 1 {
                    byte_acc <<= 8 - w%8;
                    fputc(byte_acc as c_int, stdout);
                    byte_acc = 0;
                    bit_num = 0;
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>#![feature(core)]

extern crate crypto;
extern crate rand;
extern crate rustc_serialize;

use crypto::aes::{self, KeySize};
use crypto::digest::Digest;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha256;
use crypto::symmetriccipher::SynchronousStreamCipher;

use rustc_serialize::base64::{STANDARD, ToBase64};
use rustc_serialize::hex::ToHex;

use std::iter::repeat;
use rand::{OsRng, Rng};

fn main() {
    println!("24 days of Rust - rust-crypto (day 21)");
    let input = "Hello world!";
    let mut sha = Sha256::new();
    sha.input_str(input);
    println!("{}", sha.result_str());
    let mut bytes: Vec<u8> = repeat(0u8).take(sha.output_bytes()).collect();
    sha.result(&mut bytes[..]);
    println!("{}", bytes.to_base64(STANDARD));

    let mut gen = OsRng::new().ok().expect("Failed to get OS random generator");
    let mut key: Vec<u8> = repeat(0u8).take(16).collect();
    gen.fill_bytes(&mut key[..]);
    let mut nonce: Vec<u8> = repeat(0u8).take(16).collect();
    gen.fill_bytes(&mut nonce[..]);
    println!("Key: {}", key.to_base64(STANDARD));
    println!("Nonce: {}", nonce.to_base64(STANDARD));
    let mut cipher = aes::ctr(KeySize::KeySize128, key.as_slice(), nonce.as_slice());
    let secret = "I like Nickelback";
    let mut output: Vec<u8> = repeat(0u8).take(secret.len()).collect();
    cipher.process(secret.as_bytes(), &mut output[..]);
    println!("Ciphertext: {}", output.to_base64(STANDARD));

    let mut hmac_key: Vec<u8> = repeat(0u8).take(32).collect();
    gen.fill_bytes(&mut hmac_key);
    let message = "Ceterum censeo Carthaginem esse delendam";
    println!("Message: {}", message);
    println!("HMAC key: {}", hmac_key.to_base64(STANDARD));
    let mut hmac = Hmac::new(Sha256::new(), hmac_key.as_slice());
    hmac.input(message.as_bytes());
    println!("HMAC digest: {}", hmac.result().code().to_hex());
}
<commit_msg>Cleaned up day 21.<commit_after>extern crate crypto;
extern crate rand;
extern crate rustc_serialize;

use crypto::aes::{self, KeySize};
use crypto::digest::Digest;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha256;
use crypto::symmetriccipher::SynchronousStreamCipher;

use rustc_serialize::base64::{STANDARD, ToBase64};
use rustc_serialize::hex::ToHex;

use std::iter::repeat;
use rand::{OsRng, Rng};

fn main() {
    println!("24 days of Rust - rust-crypto (day 21)");
    let input = "Hello world!";
    let mut sha = Sha256::new();
    sha.input_str(input);
    println!("{}", sha.result_str());
    let mut bytes: Vec<u8> = repeat(0u8).take(sha.output_bytes()).collect();
    sha.result(&mut bytes[..]);
    println!("{}", bytes.to_base64(STANDARD));

    let mut gen = OsRng::new().ok().expect("Failed to get OS random generator");
    let mut key: Vec<u8> = repeat(0u8).take(16).collect();
    gen.fill_bytes(&mut key[..]);
    let mut nonce: Vec<u8> = repeat(0u8).take(16).collect();
    gen.fill_bytes(&mut nonce[..]);
    println!("Key: {}", key.to_base64(STANDARD));
    println!("Nonce: {}", nonce.to_base64(STANDARD));
    let mut cipher = aes::ctr(KeySize::KeySize128, &key, &nonce);
    let secret = "I like Nickelback";
    let mut output: Vec<u8> = repeat(0u8).take(secret.len()).collect();
    cipher.process(secret.as_bytes(), &mut output[..]);
    println!("Ciphertext: {}", output.to_base64(STANDARD));

    let mut hmac_key: Vec<u8> = repeat(0u8).take(32).collect();
    gen.fill_bytes(&mut hmac_key);
    let message = "Ceterum censeo Carthaginem esse delendam";
    println!("Message: {}", message);
    println!("HMAC key: {}", hmac_key.to_base64(STANDARD));
    let mut hmac = Hmac::new(Sha256::new(), &hmac_key);
    hmac.input(message.as_bytes());
    println!("HMAC digest: {}", hmac.result().code().to_hex());
}
<|endoftext|>


<commit_before>use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::sync::Arc;

use assert_types::*;

use hpack::decoder::DecoderError;

use tls_api;

use tokio_timer::TimeoutError;

use common::sender::SendError;
use solicit::error_code::ErrorCode;
use solicit::frame::ParseFrameError;
use void::Void;

/// An enum representing errors that can arise when performing operations involving an HTTP/2
/// connection.
#[derive(Debug)]
pub enum Error {
    /// The underlying IO layer raised an error
    IoError(io::Error),
    TlsError(tls_api::Error),
    CodeError(ErrorCode),
    RstStreamReceived(ErrorCode),
    /// The HTTP/2 connection received an invalid HTTP/2 frame
    InvalidFrame(String),
    /// The HPACK decoder was unable to decode a header chunk and raised an error.
    /// Any decoder error is fatal to the HTTP/2 connection as it means that the decoder contexts
    /// will be out of sync.
    CompressionError(DecoderError),
    /// Indicates that the local peer has discovered an overflow in the size of one of the
    /// connection flow control window, which is a connection error.
    WindowSizeOverflow,
    UnknownStreamId,
    UnableToConnect,
    MalformedResponse,
    ConnectionTimeout,
    /// Shutdown of local client or server
    Shutdown,
    HandlerPanicked(String),
    ParseFrameError(ParseFrameError),
    InternalError(String),
    NotImplemented(&'static str),
    // TODO: replace with variants
    Other(&'static str),
    ClientDied(Option<Arc<Error>>),
    ClientPanicked(String),
    ClientCompletedWithoutError,
    SendError(SendError),
    CallerDied,
}

fn _assert_error_sync_send() {
    assert_send::<Error>();
    assert_sync::<Error>();
}

/// Implement the trait that allows us to automatically convert `io::Error`s
/// into an `HttpError` by wrapping the given `io::Error` into an `HttpError::IoError` variant.
impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<tls_api::Error> for Error {
    fn from(error: tls_api::Error) -> Error {
        Error::TlsError(error)
    }
}

impl<F> From<TimeoutError<F>> for Error {
    fn from(_err: TimeoutError<F>) -> Error {
        Error::ConnectionTimeout
    }
}

impl From<ParseFrameError> for Error {
    fn from(e: ParseFrameError) -> Self {
        Error::ParseFrameError(e)
    }
}

impl From<SendError> for Error {
    fn from(e: SendError) -> Self {
        Error::SendError(e)
    }
}

impl From<Void> for Error {
    fn from(v: Void) -> Self {
        match v {}
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "HTTP/2 Error: {}", self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::IoError(_) => "Encountered an IO error",
            Error::TlsError(_) => "Encountered TLS error",
            Error::CodeError(_) => "Encountered HTTP named error",
            Error::RstStreamReceived(_) => "Received RST_STREAM from peer",
            Error::InvalidFrame(..) => "Encountered an invalid or unexpected HTTP/2 frame",
            Error::CompressionError(_) => "Encountered an error with HPACK compression",
            Error::WindowSizeOverflow => "The connection flow control window overflowed",
            Error::UnknownStreamId => "Attempted an operation with an unknown HTTP/2 stream ID",
            Error::UnableToConnect => "An error attempting to establish an HTTP/2 connection",
            Error::MalformedResponse => "The received response was malformed",
            Error::ConnectionTimeout => "Connection time out",
            Error::Shutdown => "Local shutdown",
            Error::HandlerPanicked(_) => "Handler panicked",
            Error::ParseFrameError(_) => "Failed to parse frame",
            Error::NotImplemented(_) => "Not implemented",
            Error::InternalError(_) => "Internal error",
            Error::ClientDied(_) => "Client died",
            Error::ClientPanicked(_) => "Client panicked",
            Error::ClientCompletedWithoutError => "Client completed without error",
            Error::SendError(_) => "Failed to write message to stream",
            Error::CallerDied => "Request caller died",
            Error::Other(_) => "An unknown error",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::IoError(ref e) => Some(e),
            Error::TlsError(ref e) => Some(e),
            _ => None,
        }
    }
}
<commit_msg>impl From<StreamDead> for Error<commit_after>use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::sync::Arc;

use assert_types::*;

use hpack::decoder::DecoderError;

use tls_api;

use tokio_timer::TimeoutError;

use common::sender::SendError;
use solicit::error_code::ErrorCode;
use solicit::frame::ParseFrameError;
use void::Void;
use StreamDead;

/// An enum representing errors that can arise when performing operations involving an HTTP/2
/// connection.
#[derive(Debug)]
pub enum Error {
    /// The underlying IO layer raised an error
    IoError(io::Error),
    TlsError(tls_api::Error),
    CodeError(ErrorCode),
    RstStreamReceived(ErrorCode),
    /// The HTTP/2 connection received an invalid HTTP/2 frame
    InvalidFrame(String),
    /// The HPACK decoder was unable to decode a header chunk and raised an error.
    /// Any decoder error is fatal to the HTTP/2 connection as it means that the decoder contexts
    /// will be out of sync.
    CompressionError(DecoderError),
    /// Indicates that the local peer has discovered an overflow in the size of one of the
    /// connection flow control window, which is a connection error.
    WindowSizeOverflow,
    UnknownStreamId,
    UnableToConnect,
    MalformedResponse,
    ConnectionTimeout,
    /// Shutdown of local client or server
    Shutdown,
    HandlerPanicked(String),
    ParseFrameError(ParseFrameError),
    InternalError(String),
    NotImplemented(&'static str),
    // TODO: replace with variants
    Other(&'static str),
    ClientDied(Option<Arc<Error>>),
    ClientPanicked(String),
    ClientCompletedWithoutError,
    SendError(SendError),
    StreamDead(StreamDead),
    CallerDied,
}

fn _assert_error_sync_send() {
    assert_send::<Error>();
    assert_sync::<Error>();
}

/// Implement the trait that allows us to automatically convert `io::Error`s
/// into an `HttpError` by wrapping the given `io::Error` into an `HttpError::IoError` variant.
impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<tls_api::Error> for Error {
    fn from(error: tls_api::Error) -> Error {
        Error::TlsError(error)
    }
}

impl<F> From<TimeoutError<F>> for Error {
    fn from(_err: TimeoutError<F>) -> Error {
        Error::ConnectionTimeout
    }
}

impl From<ParseFrameError> for Error {
    fn from(e: ParseFrameError) -> Self {
        Error::ParseFrameError(e)
    }
}

impl From<SendError> for Error {
    fn from(e: SendError) -> Self {
        Error::SendError(e)
    }
}

impl From<StreamDead> for Error {
    fn from(e: StreamDead) -> Self {
        Error::StreamDead(e)
    }
}

impl From<Void> for Error {
    fn from(v: Void) -> Self {
        match v {}
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "HTTP/2 Error: {}", self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::IoError(_) => "Encountered an IO error",
            Error::TlsError(_) => "Encountered TLS error",
            Error::CodeError(_) => "Encountered HTTP named error",
            Error::RstStreamReceived(_) => "Received RST_STREAM from peer",
            Error::InvalidFrame(..) => "Encountered an invalid or unexpected HTTP/2 frame",
            Error::CompressionError(_) => "Encountered an error with HPACK compression",
            Error::WindowSizeOverflow => "The connection flow control window overflowed",
            Error::UnknownStreamId => "Attempted an operation with an unknown HTTP/2 stream ID",
            Error::UnableToConnect => "An error attempting to establish an HTTP/2 connection",
            Error::MalformedResponse => "The received response was malformed",
            Error::ConnectionTimeout => "Connection time out",
            Error::Shutdown => "Local shutdown",
            Error::HandlerPanicked(_) => "Handler panicked",
            Error::ParseFrameError(_) => "Failed to parse frame",
            Error::NotImplemented(_) => "Not implemented",
            Error::InternalError(_) => "Internal error",
            Error::ClientDied(_) => "Client died",
            Error::ClientPanicked(_) => "Client panicked",
            Error::ClientCompletedWithoutError => "Client completed without error",
            Error::SendError(_) => "Failed to write message to stream",
            Error::CallerDied => "Request caller died",
            Error::StreamDead(_) => "Stream dead",
            Error::Other(_) => "An unknown error",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::IoError(ref e) => Some(e),
            Error::TlsError(ref e) => Some(e),
            _ => None,
        }
    }
}
<|endoftext|>