<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::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();
    }
}

#[derive(Debug, PartialEq, Eq)]
enum BootstrapRequest {
    No,
    Yes,
}

fn test_bootstrap_entry(
    opts: &Opts,
    transport: &TransportWrapper,
    request: BootstrapRequest,
) -> 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")?;

    // Look for the bootstrap signal from the ROM.
    // When enabled, we expect the uart to emit a message indicating bootstrap entry.
    // When disabled, we expect the ROM to indicate boot failure.
    let (success, failure) = match request {
        BootstrapRequest::No => (Regex::new(r"BFV:")?, Regex::new(r"bootstrap:1\r\n")?),
        BootstrapRequest::Yes => (Regex::new(r"bootstrap:1\r\n")?, Regex::new(r"BFV:")?),
    };
    let mut console = UartConsole {
        timeout: Some(opts.timeout),
        exit_success: Some(success),
        exit_failure: Some(failure),
        ..Default::default()
    };

    match request {
        BootstrapRequest::No => transport.remove_pin_strapping("ROM_BOOTSTRAP")?,
        BootstrapRequest::Yes => transport.apply_pin_strapping("ROM_BOOTSTRAP")?,
    }
    let reset_delay = opts
        .init
        .bootstrap
        .options
        .reset_delay
        .unwrap_or(Duration::from_millis(50));
    transport.reset_target(reset_delay, true)?;

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

    // Now check whether the SPI device is responding to status messages.
    // 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")?;
    let status = SpiFlash::read_status(&*spi)?;
    match request {
        BootstrapRequest::Yes => assert_eq!(status, 0x00),
        BootstrapRequest::No => 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 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(transport: &TransportWrapper) -> Result<()> {
    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 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 main() -> Result<()> {
    let opts = Opts::from_args();
    opts.init.init_logging();

    let transport = opts.init.init_target()?;
    execute_test!(
        test_bootstrap_entry,
        &opts,
        &transport,
        BootstrapRequest::No
    );
    execute_test!(
        test_bootstrap_entry,
        &opts,
        &transport,
        BootstrapRequest::Yes
    );
    execute_test!(test_jedec_id, &opts, &transport);
    execute_test!(test_sfdp, &opts, &transport);
    execute_test!(test_write_enable_disable, &transport);
    Ok(())
}
<commit_msg>[test] Split test_bootstrap_entry to two test points<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::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<()> {
    // 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")?;
    let reset_delay = opts
        .init
        .bootstrap
        .options
        .reset_delay
        .unwrap_or(Duration::from_millis(50));
    transport.reset_target(reset_delay, true)?;

    // Now watch the console for the exit conditions.
    let result = console.interact(&*uart, None, Some(&mut std::io::stdout()))?;
    match 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.remove_pin_strapping("ROM_BOOTSTRAP")?;
    let reset_delay = opts
        .init
        .bootstrap
        .options
        .reset_delay
        .unwrap_or(Duration::from_millis(50));
    transport.reset_target(reset_delay, true)?;

    // Now watch the console for the exit conditions.
    let result = console.interact(&*uart, None, Some(&mut std::io::stdout()))?;
    match 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 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(transport: &TransportWrapper) -> Result<()> {
    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 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 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, &transport);
    Ok(())
}
<|endoftext|>


<commit_before>#![feature(collections)]

extern crate macaroons;
pub use macaroons::token::{Token, Tag};
pub use macaroons::caveat::{Caveat, Predicate};

const EXPECTED_TAG: [u8; 32] = [0x19,0x7b,0xac,0x7a,0x04,0x4a,0xf3,0x33
                               ,0x32,0x86,0x5b,0x92,0x66,0xe2,0x6d,0x49
                               ,0x3b,0xdd,0x66,0x8a,0x66,0x0e,0x44,0xd8
                               ,0x8c,0xe1,0xa9,0x98,0xc2,0x3d,0xbd,0x67];

fn example_key() -> Vec<u8> {
  String::from_str("this is our super secret key; only we should know it").into_bytes()
}

fn example_id() -> Vec<u8> {
  String::from_str("we used our secret key").into_bytes()
}

fn example_uri() -> Vec<u8> {
  String::from_str("http://mybank/").into_bytes()
}

fn example_predicate() -> Predicate {
  Predicate(String::from_str("test = caveat").into_bytes())
}

fn example_macaroon() -> Vec<u8> {
  String::from_str("MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVzZWQgb3VyIHNlY3JldCBrZXkKMDAxNmNpZCB0ZXN0ID0gY2F2ZWF0CjAwMmZzaWduYXR1cmUgGXusegRK8zMyhluSZuJtSTvdZopmDkTYjOGpmMI9vWcK").into_bytes()
}

#[test]
fn empty_macaroon_signature() {
  let token = Token::new(example_key(), example_id(), example_uri());
  let Tag(actual_tag) = token.tag;

  let expected_tag = [0xe3,0xd9,0xe0,0x29,0x08,0x52,0x6c,0x4c
                     ,0x00,0x39,0xae,0x15,0x11,0x41,0x15,0xd9
                     ,0x7f,0xdd,0x68,0xbf,0x2b,0xa3,0x79,0xb3
                     ,0x42,0xaa,0xf0,0xf6,0x17,0xd0,0x55,0x2f];

  assert_eq!(expected_tag, actual_tag)
}

#[test]
fn signature_with_first_party_caveat() {
  let token = Token::new(example_key(), example_id(), example_uri());
  let new_token = token.add_caveat(Caveat::new(example_predicate()));

  let Tag(actual_tag) = new_token.tag;
  assert_eq!(EXPECTED_TAG, actual_tag)
}

#[test]
fn binary_serialization() {
  let token = Token::new(example_key(), example_id(), example_uri());
  let new_token = token.add_caveat(Caveat::new(example_predicate()));

  assert_eq!(example_macaroon(), new_token.serialize());
}

#[test]
fn binary_deserialization() {
  let token = Token::deserialize(example_macaroon()).unwrap();

  assert_eq!(example_uri(), token.location);
  assert_eq!(example_id(),  token.identifier);

  let Tag(actual_tag) = token.tag;
  assert_eq!(EXPECTED_TAG, actual_tag)
}
<commit_msg>Refactor tests<commit_after>#![feature(collections)]

extern crate macaroons;
pub use macaroons::token::{Token, Tag};
pub use macaroons::caveat::{Caveat, Predicate};

const EMPTY_TAG:    [u8; 32] = [0xe3,0xd9,0xe0,0x29,0x08,0x52,0x6c,0x4c
                               ,0x00,0x39,0xae,0x15,0x11,0x41,0x15,0xd9
                               ,0x7f,0xdd,0x68,0xbf,0x2b,0xa3,0x79,0xb3
                               ,0x42,0xaa,0xf0,0xf6,0x17,0xd0,0x55,0x2f];

const EXPECTED_TAG: [u8; 32] = [0x19,0x7b,0xac,0x7a,0x04,0x4a,0xf3,0x33
                               ,0x32,0x86,0x5b,0x92,0x66,0xe2,0x6d,0x49
                               ,0x3b,0xdd,0x66,0x8a,0x66,0x0e,0x44,0xd8
                               ,0x8c,0xe1,0xa9,0x98,0xc2,0x3d,0xbd,0x67];

fn example_key() -> Vec<u8> {
  String::from_str("this is our super secret key; only we should know it").into_bytes()
}

fn example_id() -> Vec<u8> {
  String::from_str("we used our secret key").into_bytes()
}

fn example_uri() -> Vec<u8> {
  String::from_str("http://mybank/").into_bytes()
}

fn example_predicate() -> Predicate {
  Predicate(String::from_str("test = caveat").into_bytes())
}

fn example_token() -> Token {
  let token = Token::new(example_key(), example_id(), example_uri());
  token.add_caveat(Caveat::new(example_predicate()))
}

fn example_serialized() -> Vec<u8> {
  String::from_str("MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVzZWQgb3VyIHNlY3JldCBrZXkKMDAxNmNpZCB0ZXN0ID0gY2F2ZWF0CjAwMmZzaWduYXR1cmUgGXusegRK8zMyhluSZuJtSTvdZopmDkTYjOGpmMI9vWcK").into_bytes()
}

#[test]
fn empty_macaroon_signature() {
  let token = Token::new(example_key(), example_id(), example_uri());
  let Tag(actual_tag) = token.tag;

  assert_eq!(EMPTY_TAG, actual_tag)
}

#[test]
fn signature_with_first_party_caveat() {
  let Tag(actual_tag) = example_token().tag;
  assert_eq!(EXPECTED_TAG, actual_tag)
}

#[test]
fn binary_serialization() {
  assert_eq!(example_serialized(), example_token().serialize());
}

#[test]
fn binary_deserialization() {
  let token = Token::deserialize(example_serialized()).unwrap();

  assert_eq!(example_uri(), token.location);
  assert_eq!(example_id(),  token.identifier);

  let Tag(actual_tag) = token.tag;
  assert_eq!(EXPECTED_TAG, actual_tag)
}
<|endoftext|>


<commit_before>use hir::PerNs;

use crate::completion::CompletionContext;

/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Debug)]
pub struct CompletionItem {
    /// Used only internally in tests, to check only specific kind of
    /// completion.
    completion_kind: CompletionKind,
    label: String,
    lookup: Option<String>,
    snippet: Option<String>,
    kind: Option<CompletionItemKind>,
}

pub enum InsertText {
    PlainText { text: String },
    Snippet { text: String },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompletionItemKind {
    Snippet,
    Keyword,
    Module,
    Function,
    Struct,
    Enum,
    EnumVariant,
    Binding,
    Field,
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
}

impl CompletionItem {
    pub(crate) fn new(completion_kind: CompletionKind, label: impl Into<String>) -> Builder {
        let label = label.into();
        Builder {
            completion_kind,
            label,
            lookup: None,
            snippet: None,
            kind: None,
        }
    }
    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup
            .as_ref()
            .map(|it| it.as_str())
            .unwrap_or(self.label())
    }
    /// What is inserted.
    pub fn insert_text(&self) -> InsertText {
        match &self.snippet {
            None => InsertText::PlainText {
                text: self.label.clone(),
            },
            Some(it) => InsertText::Snippet { text: it.clone() },
        }
    }

    pub fn kind(&self) -> Option<CompletionItemKind> {
        self.kind
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
pub(crate) struct Builder {
    completion_kind: CompletionKind,
    label: String,
    lookup: Option<String>,
    snippet: Option<String>,
    kind: Option<CompletionItemKind>,
}

impl Builder {
    pub(crate) fn add_to(self, acc: &mut Completions) {
        acc.add(self.build())
    }

    pub(crate) fn build(self) -> CompletionItem {
        CompletionItem {
            label: self.label,
            lookup: self.lookup,
            snippet: self.snippet,
            kind: self.kind,
            completion_kind: self.completion_kind,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn snippet(mut self, snippet: impl Into<String>) -> Builder {
        self.snippet = Some(snippet.into());
        self
    }
    pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder {
        self.kind = Some(kind);
        self
    }
    pub(super) fn from_resolution(
        mut self,
        ctx: &CompletionContext,
        resolution: &hir::Resolution,
    ) -> Builder {
        let resolved = resolution.def_id.and_then(|d| d.resolve(ctx.db).ok());
        let kind = match resolved {
            PerNs {
                types: Some(hir::Def::Module(..)),
                ..
            } => CompletionItemKind::Module,
            PerNs {
                types: Some(hir::Def::Struct(..)),
                ..
            } => CompletionItemKind::Struct,
            PerNs {
                types: Some(hir::Def::Enum(..)),
                ..
            } => CompletionItemKind::Enum,
            PerNs {
                values: Some(hir::Def::Function(function)),
                ..
            } => return self.from_function(ctx, function),
            _ => return self,
        };
        self.kind = Some(kind);
        self
    }

    fn from_function(mut self, ctx: &CompletionContext, function: hir::Function) -> Builder {
        // If not an import, add parenthesis automatically.
        if ctx.use_item_syntax.is_none() {
            if let Some(sig_info) = function.signature_info(ctx.db) {
                if sig_info.params.is_empty() {
                    self.snippet = Some(format!("{}()$0", self.label));
                } else {
                    self.snippet = Some(format!("{}($0)", self.label));
                }
            }
        }
        self.kind = Some(CompletionItemKind::Function);
        self
    }
}

impl Into<CompletionItem> for Builder {
    fn into(self) -> CompletionItem {
        self.build()
    }
}

/// Represents an in-progress set of completions being built.
#[derive(Debug, Default)]
pub(crate) struct Completions {
    buf: Vec<CompletionItem>,
}

impl Completions {
    pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) {
        self.buf.push(item.into())
    }
    pub(crate) fn add_all<I>(&mut self, items: I)
    where
        I: IntoIterator,
        I::Item: Into<CompletionItem>,
    {
        items.into_iter().for_each(|item| self.add(item.into()))
    }

    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str, kind: CompletionKind) {
        let expected = normalize(expected);
        let actual = self.debug_render(kind);
        test_utils::assert_eq_text!(expected.as_str(), actual.as_str(),);

        /// Normalize the textual representation of `Completions`:
        /// replace `;` with newlines, normalize whitespace
        fn normalize(expected: &str) -> String {
            use ra_syntax::{tokenize, TextUnit, TextRange, SyntaxKind::SEMI};
            let mut res = String::new();
            for line in expected.trim().lines() {
                let line = line.trim();
                let mut start_offset: TextUnit = 0.into();
                // Yep, we use rust tokenize in completion tests :-)
                for token in tokenize(line) {
                    let range = TextRange::offset_len(start_offset, token.len);
                    start_offset += token.len;
                    if token.kind == SEMI {
                        res.push('\n');
                    } else {
                        res.push_str(&line[range]);
                    }
                }

                res.push('\n');
            }
            res
        }
    }

    #[cfg(test)]
    fn debug_render(&self, kind: CompletionKind) -> String {
        let mut res = String::new();
        for c in self.buf.iter() {
            if c.completion_kind == kind {
                if let Some(lookup) = &c.lookup {
                    res.push_str(lookup);
                    res.push_str(&format!(" {:?}", c.label));
                } else {
                    res.push_str(&c.label);
                }
                if let Some(snippet) = &c.snippet {
                    res.push_str(&format!(" {:?}", snippet));
                }
                res.push('\n');
            }
        }
        res
    }
}

impl Into<Vec<CompletionItem>> for Completions {
    fn into(self) -> Vec<CompletionItem> {
        self.buf
    }
}
<commit_msg>use real signature in completion<commit_after>use hir::PerNs;

use crate::completion::CompletionContext;

/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Debug)]
pub struct CompletionItem {
    /// Used only internally in tests, to check only specific kind of
    /// completion.
    completion_kind: CompletionKind,
    label: String,
    lookup: Option<String>,
    snippet: Option<String>,
    kind: Option<CompletionItemKind>,
}

pub enum InsertText {
    PlainText { text: String },
    Snippet { text: String },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompletionItemKind {
    Snippet,
    Keyword,
    Module,
    Function,
    Struct,
    Enum,
    EnumVariant,
    Binding,
    Field,
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
}

impl CompletionItem {
    pub(crate) fn new(completion_kind: CompletionKind, label: impl Into<String>) -> Builder {
        let label = label.into();
        Builder {
            completion_kind,
            label,
            lookup: None,
            snippet: None,
            kind: None,
        }
    }
    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup
            .as_ref()
            .map(|it| it.as_str())
            .unwrap_or(self.label())
    }
    /// What is inserted.
    pub fn insert_text(&self) -> InsertText {
        match &self.snippet {
            None => InsertText::PlainText {
                text: self.label.clone(),
            },
            Some(it) => InsertText::Snippet { text: it.clone() },
        }
    }

    pub fn kind(&self) -> Option<CompletionItemKind> {
        self.kind
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
pub(crate) struct Builder {
    completion_kind: CompletionKind,
    label: String,
    lookup: Option<String>,
    snippet: Option<String>,
    kind: Option<CompletionItemKind>,
}

impl Builder {
    pub(crate) fn add_to(self, acc: &mut Completions) {
        acc.add(self.build())
    }

    pub(crate) fn build(self) -> CompletionItem {
        CompletionItem {
            label: self.label,
            lookup: self.lookup,
            snippet: self.snippet,
            kind: self.kind,
            completion_kind: self.completion_kind,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn snippet(mut self, snippet: impl Into<String>) -> Builder {
        self.snippet = Some(snippet.into());
        self
    }
    pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder {
        self.kind = Some(kind);
        self
    }
    pub(super) fn from_resolution(
        mut self,
        ctx: &CompletionContext,
        resolution: &hir::Resolution,
    ) -> Builder {
        let resolved = resolution.def_id.and_then(|d| d.resolve(ctx.db).ok());
        let kind = match resolved {
            PerNs {
                types: Some(hir::Def::Module(..)),
                ..
            } => CompletionItemKind::Module,
            PerNs {
                types: Some(hir::Def::Struct(..)),
                ..
            } => CompletionItemKind::Struct,
            PerNs {
                types: Some(hir::Def::Enum(..)),
                ..
            } => CompletionItemKind::Enum,
            PerNs {
                values: Some(hir::Def::Function(function)),
                ..
            } => return self.from_function(ctx, function),
            _ => return self,
        };
        self.kind = Some(kind);
        self
    }

    fn from_function(mut self, ctx: &CompletionContext, function: hir::Function) -> Builder {
        // If not an import, add parenthesis automatically.
        if ctx.use_item_syntax.is_none() {
            if function.signature(ctx.db).args().is_empty() {
                self.snippet = Some(format!("{}()$0", self.label));
            } else {
                self.snippet = Some(format!("{}($0)", self.label));
            }
        }
        self.kind = Some(CompletionItemKind::Function);
        self
    }
}

impl Into<CompletionItem> for Builder {
    fn into(self) -> CompletionItem {
        self.build()
    }
}

/// Represents an in-progress set of completions being built.
#[derive(Debug, Default)]
pub(crate) struct Completions {
    buf: Vec<CompletionItem>,
}

impl Completions {
    pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) {
        self.buf.push(item.into())
    }
    pub(crate) fn add_all<I>(&mut self, items: I)
    where
        I: IntoIterator,
        I::Item: Into<CompletionItem>,
    {
        items.into_iter().for_each(|item| self.add(item.into()))
    }

    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str, kind: CompletionKind) {
        let expected = normalize(expected);
        let actual = self.debug_render(kind);
        test_utils::assert_eq_text!(expected.as_str(), actual.as_str(),);

        /// Normalize the textual representation of `Completions`:
        /// replace `;` with newlines, normalize whitespace
        fn normalize(expected: &str) -> String {
            use ra_syntax::{tokenize, TextUnit, TextRange, SyntaxKind::SEMI};
            let mut res = String::new();
            for line in expected.trim().lines() {
                let line = line.trim();
                let mut start_offset: TextUnit = 0.into();
                // Yep, we use rust tokenize in completion tests :-)
                for token in tokenize(line) {
                    let range = TextRange::offset_len(start_offset, token.len);
                    start_offset += token.len;
                    if token.kind == SEMI {
                        res.push('\n');
                    } else {
                        res.push_str(&line[range]);
                    }
                }

                res.push('\n');
            }
            res
        }
    }

    #[cfg(test)]
    fn debug_render(&self, kind: CompletionKind) -> String {
        let mut res = String::new();
        for c in self.buf.iter() {
            if c.completion_kind == kind {
                if let Some(lookup) = &c.lookup {
                    res.push_str(lookup);
                    res.push_str(&format!(" {:?}", c.label));
                } else {
                    res.push_str(&c.label);
                }
                if let Some(snippet) = &c.snippet {
                    res.push_str(&format!(" {:?}", snippet));
                }
                res.push('\n');
            }
        }
        res
    }
}

impl Into<Vec<CompletionItem>> for Completions {
    fn into(self) -> Vec<CompletionItem> {
        self.buf
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use hir::{Ty, TypeCtor};
use ra_syntax::{ast::AstNode, TextRange, TextUnit};
use ra_text_edit::TextEdit;

use crate::{
    completion::{
        completion_context::CompletionContext,
        completion_item::{Builder, CompletionKind, Completions},
    },
    CompletionItem,
};

pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
    if ctx.db.feature_flags.get("completions.enable-postfix") == false {
        return;
    }

    let dot_receiver = match &ctx.dot_receiver {
        Some(it) => it,
        None => return,
    };

    let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
        let text = dot_receiver.syntax().text();
        let without_dot = ..text.len() - TextUnit::of_char('.');
        text.slice(without_dot).to_string()
    } else {
        dot_receiver.syntax().text().to_string()
    };

    let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);

    if is_bool_or_unknown(receiver_ty) {
        postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
            .add_to(acc);
        postfix_snippet(
            ctx,
            "while",
            "while expr {}",
            &format!("while {} {{\n$0\n}}", receiver_text),
        )
        .add_to(acc);
    }

    postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);

    postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
    postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc);

    postfix_snippet(
        ctx,
        "match",
        "match expr {}",
        &format!("match {} {{\n    ${{1:_}} => {{$0\\}},\n}}", receiver_text),
    )
    .add_to(acc);

    postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc);

    postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text))
        .add_to(acc);
}

fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
    let edit = {
        let receiver_range =
            ctx.dot_receiver.as_ref().expect("no receiver available").syntax().text_range();
        let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end());
        TextEdit::replace(delete_range, snippet.to_string())
    };
    CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
        .detail(detail)
        .snippet_edit(edit)
}

fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
    match &ty {
        Some(Ty::Apply(app)) if app.ctor == TypeCtor::Bool => true,
        Some(Ty::Unknown) | None => true,
        Some(_) => false,
    }
}

#[cfg(test)]
mod tests {
    use insta::assert_debug_snapshot;

    use crate::completion::{do_completion, CompletionItem, CompletionKind};

    fn do_postfix_completion(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Postfix)
    }

    #[test]
    fn postfix_completion_works_for_trivial_path_expression() {
        assert_debug_snapshot!(
            do_postfix_completion(
                r#"
                fn main() {
                    let bar = true;
                    bar.<|>
                }
                "#,
            ),
            @r###"[
    CompletionItem {
        label: "box",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "Box::new(bar)",
        detail: "Box::new(expr)",
    },
    CompletionItem {
        label: "dbg",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "dbg!(bar)",
        detail: "dbg!(expr)",
    },
    CompletionItem {
        label: "if",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "if bar {$0}",
        detail: "if expr {}",
    },
    CompletionItem {
        label: "match",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "match bar {\n    ${1:_} => {$0\\},\n}",
        detail: "match expr {}",
    },
    CompletionItem {
        label: "not",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "!bar",
        detail: "!expr",
    },
    CompletionItem {
        label: "ref",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "&bar",
        detail: "&expr",
    },
    CompletionItem {
        label: "refm",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "&mut bar",
        detail: "&mut expr",
    },
    CompletionItem {
        label: "while",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "while bar {\n$0\n}",
        detail: "while expr {}",
    },
]"###
        );
    }

    #[test]
    fn some_postfix_completions_ignored() {
        assert_debug_snapshot!(
            do_postfix_completion(
                r#"
                fn main() {
                    let bar: u8 = 12;
                    bar.<|>
                }
                "#,
            ),
            @r###"[
    CompletionItem {
        label: "box",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "Box::new(bar)",
        detail: "Box::new(expr)",
    },
    CompletionItem {
        label: "dbg",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "dbg!(bar)",
        detail: "dbg!(expr)",
    },
    CompletionItem {
        label: "match",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "match bar {\n    ${1:_} => {$0\\},\n}",
        detail: "match expr {}",
    },
    CompletionItem {
        label: "not",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "!bar",
        detail: "!expr",
    },
    CompletionItem {
        label: "ref",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "&bar",
        detail: "&expr",
    },
    CompletionItem {
        label: "refm",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "&mut bar",
        detail: "&mut expr",
    },
]"###
        );
    }

    #[test]
    fn postfix_completion_works_for_ambiguous_float_literal() {
        assert_debug_snapshot!(
            do_postfix_completion(
                r#"
                fn main() {
                    42.<|>
                }
                "#,
            ),
            @r###"[
    CompletionItem {
        label: "box",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "Box::new(42)",
        detail: "Box::new(expr)",
    },
    CompletionItem {
        label: "dbg",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "dbg!(42)",
        detail: "dbg!(expr)",
    },
    CompletionItem {
        label: "match",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "match 42 {\n    ${1:_} => {$0\\},\n}",
        detail: "match expr {}",
    },
    CompletionItem {
        label: "not",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "!42",
        detail: "!expr",
    },
    CompletionItem {
        label: "ref",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "&42",
        detail: "&expr",
    },
    CompletionItem {
        label: "refm",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "&mut 42",
        detail: "&mut expr",
    },
]"###
        );
    }
}
<commit_msg>fix typo<commit_after>//! FIXME: write short doc here

use hir::{Ty, TypeCtor};
use ra_syntax::{ast::AstNode, TextRange, TextUnit};
use ra_text_edit::TextEdit;

use crate::{
    completion::{
        completion_context::CompletionContext,
        completion_item::{Builder, CompletionKind, Completions},
    },
    CompletionItem,
};

pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
    if ctx.db.feature_flags.get("completion.enable-postfix") == false {
        return;
    }

    let dot_receiver = match &ctx.dot_receiver {
        Some(it) => it,
        None => return,
    };

    let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
        let text = dot_receiver.syntax().text();
        let without_dot = ..text.len() - TextUnit::of_char('.');
        text.slice(without_dot).to_string()
    } else {
        dot_receiver.syntax().text().to_string()
    };

    let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);

    if is_bool_or_unknown(receiver_ty) {
        postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
            .add_to(acc);
        postfix_snippet(
            ctx,
            "while",
            "while expr {}",
            &format!("while {} {{\n$0\n}}", receiver_text),
        )
        .add_to(acc);
    }

    postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);

    postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
    postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc);

    postfix_snippet(
        ctx,
        "match",
        "match expr {}",
        &format!("match {} {{\n    ${{1:_}} => {{$0\\}},\n}}", receiver_text),
    )
    .add_to(acc);

    postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc);

    postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text))
        .add_to(acc);
}

fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
    let edit = {
        let receiver_range =
            ctx.dot_receiver.as_ref().expect("no receiver available").syntax().text_range();
        let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end());
        TextEdit::replace(delete_range, snippet.to_string())
    };
    CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
        .detail(detail)
        .snippet_edit(edit)
}

fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
    match &ty {
        Some(Ty::Apply(app)) if app.ctor == TypeCtor::Bool => true,
        Some(Ty::Unknown) | None => true,
        Some(_) => false,
    }
}

#[cfg(test)]
mod tests {
    use insta::assert_debug_snapshot;

    use crate::completion::{do_completion, CompletionItem, CompletionKind};

    fn do_postfix_completion(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Postfix)
    }

    #[test]
    fn postfix_completion_works_for_trivial_path_expression() {
        assert_debug_snapshot!(
            do_postfix_completion(
                r#"
                fn main() {
                    let bar = true;
                    bar.<|>
                }
                "#,
            ),
            @r###"[
    CompletionItem {
        label: "box",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "Box::new(bar)",
        detail: "Box::new(expr)",
    },
    CompletionItem {
        label: "dbg",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "dbg!(bar)",
        detail: "dbg!(expr)",
    },
    CompletionItem {
        label: "if",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "if bar {$0}",
        detail: "if expr {}",
    },
    CompletionItem {
        label: "match",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "match bar {\n    ${1:_} => {$0\\},\n}",
        detail: "match expr {}",
    },
    CompletionItem {
        label: "not",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "!bar",
        detail: "!expr",
    },
    CompletionItem {
        label: "ref",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "&bar",
        detail: "&expr",
    },
    CompletionItem {
        label: "refm",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "&mut bar",
        detail: "&mut expr",
    },
    CompletionItem {
        label: "while",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "while bar {\n$0\n}",
        detail: "while expr {}",
    },
]"###
        );
    }

    #[test]
    fn some_postfix_completions_ignored() {
        assert_debug_snapshot!(
            do_postfix_completion(
                r#"
                fn main() {
                    let bar: u8 = 12;
                    bar.<|>
                }
                "#,
            ),
            @r###"[
    CompletionItem {
        label: "box",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "Box::new(bar)",
        detail: "Box::new(expr)",
    },
    CompletionItem {
        label: "dbg",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "dbg!(bar)",
        detail: "dbg!(expr)",
    },
    CompletionItem {
        label: "match",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "match bar {\n    ${1:_} => {$0\\},\n}",
        detail: "match expr {}",
    },
    CompletionItem {
        label: "not",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "!bar",
        detail: "!expr",
    },
    CompletionItem {
        label: "ref",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "&bar",
        detail: "&expr",
    },
    CompletionItem {
        label: "refm",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "&mut bar",
        detail: "&mut expr",
    },
]"###
        );
    }

    #[test]
    fn postfix_completion_works_for_ambiguous_float_literal() {
        assert_debug_snapshot!(
            do_postfix_completion(
                r#"
                fn main() {
                    42.<|>
                }
                "#,
            ),
            @r###"[
    CompletionItem {
        label: "box",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "Box::new(42)",
        detail: "Box::new(expr)",
    },
    CompletionItem {
        label: "dbg",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "dbg!(42)",
        detail: "dbg!(expr)",
    },
    CompletionItem {
        label: "match",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "match 42 {\n    ${1:_} => {$0\\},\n}",
        detail: "match expr {}",
    },
    CompletionItem {
        label: "not",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "!42",
        detail: "!expr",
    },
    CompletionItem {
        label: "ref",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "&42",
        detail: "&expr",
    },
    CompletionItem {
        label: "refm",
        source_range: [52; 52),
        delete: [49; 52),
        insert: "&mut 42",
        detail: "&mut expr",
    },
]"###
        );
    }
}
<|endoftext|>


<commit_before>use analysis::ref_mode::RefMode;
use analysis::rust_type::*;
use analysis::imports::Imports;
use analysis::namespaces;
use analysis::override_string_type::override_string_type_return;
use config;
use env::Env;
use library::{self, Nullable, TypeId};

#[derive(Clone, Debug, Default)]
pub struct Info {
    pub parameter: Option<library::Parameter>,
    pub base_tid: Option<library::TypeId>, // Some only if need downcast
    pub commented: bool,
    pub bool_return_is_error: Option<String>,
}

pub fn analyze(
    env: &Env,
    func: &library::Function,
    type_tid: library::TypeId,
    configured_functions: &[&config::functions::Function],
    used_types: &mut Vec<String>,
    imports: &mut Imports,
) -> Info {
    let typ = override_string_type_return(env, func.ret.typ, configured_functions);
    let mut parameter = if typ == Default::default() {
        None
    } else {
        if let Ok(s) = used_rust_type(env, typ, false) {
            used_types.push(s);
        }
        // Since GIRs are bad at specifying return value nullability, assume
        // any returned pointer is nullable unless overridden by the config.
        let mut nullable = func.ret.nullable;
        if !*nullable && can_be_nullable_return(env, typ) {
            *nullable = true;
        }
        let nullable_override = configured_functions
            .iter()
            .filter_map(|f| f.ret.nullable)
            .next();
        if let Some(val) = nullable_override {
            nullable = val;
        }
        Some(library::Parameter {
            typ,
            nullable,
            ..func.ret.clone()
        })
    };

    let commented = if typ == Default::default() {
        false
    } else {
        parameter_rust_type(
            env,
            typ,
            func.ret.direction,
            Nullable(false),
            RefMode::None,
        ).is_err()
    };

    let bool_return_is_error = configured_functions
        .iter()
        .filter_map(|f| f.ret.bool_return_is_error.as_ref())
        .next();
    let bool_return_error_message =
        bool_return_is_error.and_then(|m| if typ != TypeId::tid_bool() {
            error!(
                "Ignoring bool_return_is_error configuration for non-bool returning function {}",
                func.name
            );
            None
        } else {
            let ns = if env.namespaces.glib_ns_id == namespaces::MAIN {
                "error"
            } else {
                "glib"
            };
            imports.add(ns, None);

            Some(m.clone())
        });

    let mut base_tid = None;

    if func.kind == library::FunctionKind::Constructor {
        if let Some(par) = parameter {
            let nullable_override = configured_functions
                .iter()
                .filter_map(|f| f.ret.nullable)
                .next();
            if par.typ != type_tid {
                base_tid = Some(par.typ);
            }
            parameter = Some(library::Parameter {
                typ: type_tid,
                nullable: nullable_override.unwrap_or(Nullable(false)),
                ..par
            });
        }
    }

    Info {
        parameter,
        base_tid,
        commented,
        bool_return_is_error: bool_return_error_message,
    }
}

fn can_be_nullable_return(env: &Env, type_id: library::TypeId) -> bool {
    use library::Type::*;
    use library::Fundamental::*;
    match *env.library.type_(type_id) {
        Fundamental(fund) => match fund {
            Pointer => true,
            Utf8 => true,
            Filename => true,
            OsString => true,
            _ => false,
        },
        Alias(ref alias) => can_be_nullable_return(env, alias.typ),
        Enumeration(_) => false,
        Bitfield(_) => false,
        Record(_) => true,
        Union(_) => true,
        Function(_) => true,
        Interface(_) => true,
        Class(_) => true,
        _ => true,
    }
}
<commit_msg>Use nullable attribute on constructor return value<commit_after>use analysis::ref_mode::RefMode;
use analysis::rust_type::*;
use analysis::imports::Imports;
use analysis::namespaces;
use analysis::override_string_type::override_string_type_return;
use config;
use env::Env;
use library::{self, Nullable, TypeId};

#[derive(Clone, Debug, Default)]
pub struct Info {
    pub parameter: Option<library::Parameter>,
    pub base_tid: Option<library::TypeId>, // Some only if need downcast
    pub commented: bool,
    pub bool_return_is_error: Option<String>,
}

pub fn analyze(
    env: &Env,
    func: &library::Function,
    type_tid: library::TypeId,
    configured_functions: &[&config::functions::Function],
    used_types: &mut Vec<String>,
    imports: &mut Imports,
) -> Info {
    let typ = override_string_type_return(env, func.ret.typ, configured_functions);
    let mut parameter = if typ == Default::default() {
        None
    } else {
        if let Ok(s) = used_rust_type(env, typ, false) {
            used_types.push(s);
        }
        // Since GIRs are bad at specifying return value nullability, assume
        // any returned pointer is nullable unless overridden by the config.
        let mut nullable = func.ret.nullable;
        if !*nullable && can_be_nullable_return(env, typ) {
            *nullable = true;
        }
        let nullable_override = configured_functions
            .iter()
            .filter_map(|f| f.ret.nullable)
            .next();
        if let Some(val) = nullable_override {
            nullable = val;
        }
        Some(library::Parameter {
            typ,
            nullable,
            ..func.ret.clone()
        })
    };

    let commented = if typ == Default::default() {
        false
    } else {
        parameter_rust_type(
            env,
            typ,
            func.ret.direction,
            Nullable(false),
            RefMode::None,
        ).is_err()
    };

    let bool_return_is_error = configured_functions
        .iter()
        .filter_map(|f| f.ret.bool_return_is_error.as_ref())
        .next();
    let bool_return_error_message =
        bool_return_is_error.and_then(|m| if typ != TypeId::tid_bool() {
            error!(
                "Ignoring bool_return_is_error configuration for non-bool returning function {}",
                func.name
            );
            None
        } else {
            let ns = if env.namespaces.glib_ns_id == namespaces::MAIN {
                "error"
            } else {
                "glib"
            };
            imports.add(ns, None);

            Some(m.clone())
        });

    let mut base_tid = None;

    if func.kind == library::FunctionKind::Constructor {
        if let Some(par) = parameter {
            let nullable_override = configured_functions
                .iter()
                .filter_map(|f| f.ret.nullable)
                .next();
            if par.typ != type_tid {
                base_tid = Some(par.typ);
            }
            parameter = Some(library::Parameter {
                typ: type_tid,
                nullable: nullable_override.unwrap_or(func.ret.nullable),
                ..par
            });
        }
    }

    Info {
        parameter,
        base_tid,
        commented,
        bool_return_is_error: bool_return_error_message,
    }
}

fn can_be_nullable_return(env: &Env, type_id: library::TypeId) -> bool {
    use library::Type::*;
    use library::Fundamental::*;
    match *env.library.type_(type_id) {
        Fundamental(fund) => match fund {
            Pointer => true,
            Utf8 => true,
            Filename => true,
            OsString => true,
            _ => false,
        },
        Alias(ref alias) => can_be_nullable_return(env, alias.typ),
        Enumeration(_) => false,
        Bitfield(_) => false,
        Record(_) => true,
        Union(_) => true,
        Function(_) => true,
        Interface(_) => true,
        Class(_) => true,
        _ => true,
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign};

use super::{ffi, Bitmap};

impl fmt::Debug for Bitmap {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Bitmap<{:?}>", self.to_vec())
    }
}

impl PartialEq for Bitmap {
    #[inline]
    fn eq(&self, other: &Bitmap) -> bool {
        unsafe { ffi::roaring_bitmap_equals(self.bitmap, other.bitmap) }
    }
}

impl Clone for Bitmap {
    /// Create a copy of a Bitmap
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(11);
    ///
    /// let bitmap2 = bitmap1.clone();
    ///
    /// assert_eq!(bitmap1, bitmap2);
    /// ```
    #[inline]
    fn clone(&self) -> Bitmap {
        unsafe {
            Bitmap {
                bitmap: ffi::roaring_bitmap_copy(self.bitmap),
            }
        }
    }
}

impl Drop for Bitmap {
    fn drop(&mut self) {
        unsafe { ffi::roaring_bitmap_free(self.bitmap) }
    }
}

impl BitAnd for Bitmap {
    type Output = Bitmap;

    /// Syntactic sugar for `.and`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(1);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(1);
    /// bitmap2.add(2);
    ///
    /// let bitmap3 = bitmap1 & bitmap2;
    ///
    /// assert!(bitmap3.contains(1));
    /// assert!(!bitmap3.contains(2));
    /// ```
    #[inline]
    fn bitand(self, other: Bitmap) -> Bitmap {
        self.and(&other)
    }
}

impl<'a> BitAnd<&'a Bitmap> for Bitmap {
    type Output = Bitmap;

    /// Syntactic sugar for `.and`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(1);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(1);
    /// bitmap2.add(2);
    ///
    /// let bitmap3 = bitmap1 & &bitmap2;
    ///
    /// assert!(bitmap3.contains(1));
    /// assert!(!bitmap3.contains(2));
    /// ```
    #[inline]
    fn bitand(self, other: &'a Bitmap) -> Bitmap {
        self.and(&other)
    }
}

impl<'a, 'b> BitAnd<&'a Bitmap> for &'b Bitmap {
    type Output = Bitmap;

    /// Syntactic sugar for `.and`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1: Bitmap = Bitmap::create();
    /// bitmap1.add(1);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(1);
    /// bitmap2.add(2);
    ///
    /// let bitmap3 = &bitmap1 & &bitmap2;
    ///
    /// assert!(bitmap3.contains(1));
    /// assert!(!bitmap3.contains(2));
    /// ```
    #[inline]
    fn bitand(self, other: &'a Bitmap) -> Bitmap {
        self.and(&other)
    }
}

impl BitAndAssign for Bitmap {
    /// Syntactic sugar for `.and_inplace`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// let mut bitmap3 = Bitmap::create();
    /// bitmap3.add(15);
    ///
    /// let mut bitmap4 = Bitmap::create();
    /// bitmap4.add(15);
    /// bitmap4.add(25);
    ///
    /// bitmap1 &= bitmap2;
    ///
    /// assert!(bitmap1.cardinality() == 0);
    /// assert!(!bitmap1.contains(15));
    /// assert!(!bitmap1.contains(25));
    ///
    /// bitmap3 &= bitmap4;
    ///
    /// assert!(bitmap3.cardinality() == 1);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// ```
    #[inline]
    fn bitand_assign(&mut self, other: Bitmap) {
        self.and_inplace(&other);
    }
}

impl BitOr for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.or`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// let bitmap3 = bitmap1 | bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(bitmap3.contains(25));
    /// ```
    #[inline]
    fn bitor(self, other: Bitmap) -> Bitmap {
        self.or(&other)
    }
}

impl<'a> BitOr<&'a Bitmap> for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.or`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// let bitmap3 = bitmap1 | &bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(bitmap3.contains(25));
    /// ```
    #[inline]
    fn bitor(self, other: &'a Bitmap) -> Bitmap {
        self.or(&other)
    }
}

impl<'a, 'b> BitOr<&'a Bitmap> for &'b Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.or`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// let bitmap3 = &bitmap1 | &bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(bitmap3.contains(25));
    /// ```
    #[inline]
    fn bitor(self, other: &'a Bitmap) -> Bitmap {
        self.or(&other)
    }
}

impl BitOrAssign for Bitmap {
    /// Syntatic sugar for `.or_inplace`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// bitmap1 |= bitmap2;
    ///
    /// assert!(bitmap1.cardinality() == 2);
    /// assert!(bitmap1.contains(15));
    /// assert!(bitmap1.contains(25));
    /// ```
    #[inline]
    fn bitor_assign(&mut self, other: Bitmap) {
        self.or_inplace(&other)
    }
}

impl BitXor for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.xor`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = bitmap1 ^ bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(bitmap3.contains(35));
    /// ```
    #[inline]
    fn bitxor(self, other: Bitmap) -> Bitmap {
        self.xor(&other)
    }
}

impl<'a> BitXor<&'a Bitmap> for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.xor`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = bitmap1 ^ &bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(bitmap3.contains(35));
    /// ```
    #[inline]
    fn bitxor(self, other: &'a Bitmap) -> Bitmap {
        self.xor(&other)
    }
}

impl<'a, 'b> BitXor<&'a Bitmap> for &'b Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.xor`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = &bitmap1 ^ &bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(bitmap3.contains(35));
    /// ```
    #[inline]
    fn bitxor(self, other: &'a Bitmap) -> Bitmap {
        self.xor(&other)
    }
}

impl BitXorAssign for Bitmap {
    /// Syntatic sugar for `.xor_inplace`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// bitmap1 ^= bitmap2;
    ///
    /// assert!(bitmap1.cardinality() == 2);
    /// assert!(bitmap1.contains(15));
    /// assert!(!bitmap1.contains(25));
    /// assert!(bitmap1.contains(35));
    /// ```
    #[inline]
    fn bitxor_assign(&mut self, other: Bitmap) {
        self.xor_inplace(&other)
    }
}

impl Sub for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.andnot`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    ///
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    ///
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = bitmap1 - bitmap2;
    ///
    /// assert_eq!(bitmap3.cardinality(), 1);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(!bitmap3.contains(35));
    /// ```
    #[inline]
    fn sub(self, other: Bitmap) -> Bitmap {
        self.andnot(&other)
    }
}

impl<'a> Sub<&'a Bitmap> for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.andnot`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    ///
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    ///
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = bitmap1 - &bitmap2;
    ///
    /// assert_eq!(bitmap3.cardinality(), 1);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(!bitmap3.contains(35));
    /// ```
    #[inline]
    fn sub(self, other: &'a Bitmap) -> Bitmap {
        self.andnot(&other)
    }
}

impl<'a, 'b> Sub<&'a Bitmap> for &'b Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.andnot`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    ///
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    ///
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = &bitmap1 - &bitmap2;
    ///
    /// assert_eq!(bitmap3.cardinality(), 1);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(!bitmap3.contains(35));
    /// ```
    #[inline]
    fn sub(self, other: &'a Bitmap) -> Bitmap {
        self.andnot(&other)
    }
}

impl SubAssign for Bitmap {
    /// Syntatic sugar for `.andnot_inplace`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    ///
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    ///
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// bitmap1.andnot_inplace(&bitmap2);
    ///
    /// assert_eq!(bitmap1.cardinality(), 1);
    /// assert!(bitmap1.contains(15));
    /// assert!(!bitmap1.contains(25));
    /// assert!(!bitmap1.contains(35));
    /// ```
    #[inline]
    fn sub_assign(&mut self, other: Bitmap) {
        self.andnot_inplace(&other)
    }
}
<commit_msg>Implement a better Debug for the Bitmap<commit_after>use std::fmt;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign};

use super::{ffi, Bitmap};

impl fmt::Debug for Bitmap {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.cardinality() < 32 {
            write!(f, "Bitmap<{:?}>", self.to_vec())
        } else {
            write!(
                f,
                "Bitmap<{:?} values between {:?} and {:?}>",
                self.cardinality(),
                self.minimum().unwrap(),
                self.maximum().unwrap()
            )
        }
    }
}

impl PartialEq for Bitmap {
    #[inline]
    fn eq(&self, other: &Bitmap) -> bool {
        unsafe { ffi::roaring_bitmap_equals(self.bitmap, other.bitmap) }
    }
}

impl Clone for Bitmap {
    /// Create a copy of a Bitmap
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(11);
    ///
    /// let bitmap2 = bitmap1.clone();
    ///
    /// assert_eq!(bitmap1, bitmap2);
    /// ```
    #[inline]
    fn clone(&self) -> Bitmap {
        unsafe {
            Bitmap {
                bitmap: ffi::roaring_bitmap_copy(self.bitmap),
            }
        }
    }
}

impl Drop for Bitmap {
    fn drop(&mut self) {
        unsafe { ffi::roaring_bitmap_free(self.bitmap) }
    }
}

impl BitAnd for Bitmap {
    type Output = Bitmap;

    /// Syntactic sugar for `.and`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(1);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(1);
    /// bitmap2.add(2);
    ///
    /// let bitmap3 = bitmap1 & bitmap2;
    ///
    /// assert!(bitmap3.contains(1));
    /// assert!(!bitmap3.contains(2));
    /// ```
    #[inline]
    fn bitand(self, other: Bitmap) -> Bitmap {
        self.and(&other)
    }
}

impl<'a> BitAnd<&'a Bitmap> for Bitmap {
    type Output = Bitmap;

    /// Syntactic sugar for `.and`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(1);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(1);
    /// bitmap2.add(2);
    ///
    /// let bitmap3 = bitmap1 & &bitmap2;
    ///
    /// assert!(bitmap3.contains(1));
    /// assert!(!bitmap3.contains(2));
    /// ```
    #[inline]
    fn bitand(self, other: &'a Bitmap) -> Bitmap {
        self.and(&other)
    }
}

impl<'a, 'b> BitAnd<&'a Bitmap> for &'b Bitmap {
    type Output = Bitmap;

    /// Syntactic sugar for `.and`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1: Bitmap = Bitmap::create();
    /// bitmap1.add(1);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(1);
    /// bitmap2.add(2);
    ///
    /// let bitmap3 = &bitmap1 & &bitmap2;
    ///
    /// assert!(bitmap3.contains(1));
    /// assert!(!bitmap3.contains(2));
    /// ```
    #[inline]
    fn bitand(self, other: &'a Bitmap) -> Bitmap {
        self.and(&other)
    }
}

impl BitAndAssign for Bitmap {
    /// Syntactic sugar for `.and_inplace`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// let mut bitmap3 = Bitmap::create();
    /// bitmap3.add(15);
    ///
    /// let mut bitmap4 = Bitmap::create();
    /// bitmap4.add(15);
    /// bitmap4.add(25);
    ///
    /// bitmap1 &= bitmap2;
    ///
    /// assert!(bitmap1.cardinality() == 0);
    /// assert!(!bitmap1.contains(15));
    /// assert!(!bitmap1.contains(25));
    ///
    /// bitmap3 &= bitmap4;
    ///
    /// assert!(bitmap3.cardinality() == 1);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// ```
    #[inline]
    fn bitand_assign(&mut self, other: Bitmap) {
        self.and_inplace(&other);
    }
}

impl BitOr for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.or`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// let bitmap3 = bitmap1 | bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(bitmap3.contains(25));
    /// ```
    #[inline]
    fn bitor(self, other: Bitmap) -> Bitmap {
        self.or(&other)
    }
}

impl<'a> BitOr<&'a Bitmap> for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.or`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// let bitmap3 = bitmap1 | &bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(bitmap3.contains(25));
    /// ```
    #[inline]
    fn bitor(self, other: &'a Bitmap) -> Bitmap {
        self.or(&other)
    }
}

impl<'a, 'b> BitOr<&'a Bitmap> for &'b Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.or`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// let bitmap3 = &bitmap1 | &bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(bitmap3.contains(25));
    /// ```
    #[inline]
    fn bitor(self, other: &'a Bitmap) -> Bitmap {
        self.or(&other)
    }
}

impl BitOrAssign for Bitmap {
    /// Syntatic sugar for `.or_inplace`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    ///
    /// bitmap1 |= bitmap2;
    ///
    /// assert!(bitmap1.cardinality() == 2);
    /// assert!(bitmap1.contains(15));
    /// assert!(bitmap1.contains(25));
    /// ```
    #[inline]
    fn bitor_assign(&mut self, other: Bitmap) {
        self.or_inplace(&other)
    }
}

impl BitXor for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.xor`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = bitmap1 ^ bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(bitmap3.contains(35));
    /// ```
    #[inline]
    fn bitxor(self, other: Bitmap) -> Bitmap {
        self.xor(&other)
    }
}

impl<'a> BitXor<&'a Bitmap> for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.xor`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = bitmap1 ^ &bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(bitmap3.contains(35));
    /// ```
    #[inline]
    fn bitxor(self, other: &'a Bitmap) -> Bitmap {
        self.xor(&other)
    }
}

impl<'a, 'b> BitXor<&'a Bitmap> for &'b Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.xor`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = &bitmap1 ^ &bitmap2;
    ///
    /// assert!(bitmap3.cardinality() == 2);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(bitmap3.contains(35));
    /// ```
    #[inline]
    fn bitxor(self, other: &'a Bitmap) -> Bitmap {
        self.xor(&other)
    }
}

impl BitXorAssign for Bitmap {
    /// Syntatic sugar for `.xor_inplace`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// bitmap1 ^= bitmap2;
    ///
    /// assert!(bitmap1.cardinality() == 2);
    /// assert!(bitmap1.contains(15));
    /// assert!(!bitmap1.contains(25));
    /// assert!(bitmap1.contains(35));
    /// ```
    #[inline]
    fn bitxor_assign(&mut self, other: Bitmap) {
        self.xor_inplace(&other)
    }
}

impl Sub for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.andnot`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    ///
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    ///
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = bitmap1 - bitmap2;
    ///
    /// assert_eq!(bitmap3.cardinality(), 1);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(!bitmap3.contains(35));
    /// ```
    #[inline]
    fn sub(self, other: Bitmap) -> Bitmap {
        self.andnot(&other)
    }
}

impl<'a> Sub<&'a Bitmap> for Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.andnot`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    ///
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    ///
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = bitmap1 - &bitmap2;
    ///
    /// assert_eq!(bitmap3.cardinality(), 1);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(!bitmap3.contains(35));
    /// ```
    #[inline]
    fn sub(self, other: &'a Bitmap) -> Bitmap {
        self.andnot(&other)
    }
}

impl<'a, 'b> Sub<&'a Bitmap> for &'b Bitmap {
    type Output = Bitmap;

    /// Syntatic sugar for `.andnot`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    ///
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    ///
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// let bitmap3 = &bitmap1 - &bitmap2;
    ///
    /// assert_eq!(bitmap3.cardinality(), 1);
    /// assert!(bitmap3.contains(15));
    /// assert!(!bitmap3.contains(25));
    /// assert!(!bitmap3.contains(35));
    /// ```
    #[inline]
    fn sub(self, other: &'a Bitmap) -> Bitmap {
        self.andnot(&other)
    }
}

impl SubAssign for Bitmap {
    /// Syntatic sugar for `.andnot_inplace`
    ///
    /// # Examples
    ///
    /// ```
    /// use croaring::Bitmap;
    ///
    /// let mut bitmap1 = Bitmap::create();
    ///
    /// bitmap1.add(15);
    /// bitmap1.add(25);
    ///
    /// let mut bitmap2 = Bitmap::create();
    ///
    /// bitmap2.add(25);
    /// bitmap2.add(35);
    ///
    /// bitmap1.andnot_inplace(&bitmap2);
    ///
    /// assert_eq!(bitmap1.cardinality(), 1);
    /// assert!(bitmap1.contains(15));
    /// assert!(!bitmap1.contains(25));
    /// assert!(!bitmap1.contains(35));
    /// ```
    #[inline]
    fn sub_assign(&mut self, other: Bitmap) {
        self.andnot_inplace(&other)
    }
}
<|endoftext|>


<commit_before>use core::cmp::{Eq, Ord};
use core::f64::consts::pi;

use funs::triganomic::{cos, sin};
use mat::{Mat3, Mat4};
use num::cast::{NumCast, cast};
use quat::Quat;
use vec::Vec3;

/**
 * The base trait for anglular units
 */
pub trait Angle<T>: Add<self,self>
                  , Sub<self,self>
                  , Mul<T,self>
                  , Div<T,self>
                  , Modulo<T,self>
                  , Neg<self>
                  , Eq, Ord {
    static pure fn full_turn() -> self;
    static pure fn half_turn() -> self;
    static pure fn quadrant()  -> self;
    static pure fn sextant()   -> self;
    static pure fn octant()    -> self;

    pure fn to_radians(&self) -> Radians<T>;
    pure fn to_degrees(&self) -> Degrees<T>;
    pure fn wrap(&self) -> self;
    pure fn opposite(&self) -> self;
}

pub enum Radians<T> = T;

pub impl<T:Copy Num NumCast> Radians<T>: Angle<T> {
    #[inline(always)] static pure fn full_turn()    -> Radians<T> { Radians(move cast(2.0 * pi)) }  // TODO: calculate absolute values
    #[inline(always)] static pure fn half_turn()    -> Radians<T> { Radians(move cast(pi))       }
    #[inline(always)] static pure fn quadrant()     -> Radians<T> { Radians(move cast(pi / 2.0)) }
    #[inline(always)] static pure fn sextant()      -> Radians<T> { Radians(move cast(pi / 3.0)) }
    #[inline(always)] static pure fn octant()       -> Radians<T> { Radians(move cast(pi / 4.0)) }

    #[inline(always)] pure fn to_radians(&self) -> Radians<T> { *self }
    #[inline(always)] pure fn to_degrees(&self) -> Degrees<T> { Degrees(**self * cast(180.0 / pi)) }

    #[inline(always)]
    pure fn wrap(&self) -> Radians<T> {
        (*self) % cast(2.0 * pi)   // TODO: keep in the domain of 0 to two_pi
    }

    #[inline(always)]
    pure fn opposite(&self) -> Radians<T> {
        (self + Angle::half_turn()).wrap()     // TODO: test!
    }
}

pub impl<T:Copy Num> Radians<T>: Add<Radians<T>, Radians<T>> {
    #[inline(always)]
    pure fn add(rhs: &Radians<T>) -> Radians<T> {
        Radians(*self + **rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Sub<Radians<T>, Radians<T>> {
    #[inline(always)]
    pure fn sub(&self, rhs: &Radians<T>) -> Radians<T> {
        Radians(**self - **rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Mul<T, Radians<T>> {
    #[inline(always)]
    pure fn mul(&self, rhs: &T) -> Radians<T> {
        Radians(**self * *rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Div<T, Radians<T>> {
    #[inline(always)]
    pure fn div(&self, rhs: &T) -> Radians<T> {
        Radians(**self / *rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Modulo<T, Radians<T>> {
    #[inline(always)]
    pure fn modulo(&self, rhs: &T) -> Radians<T> {
        Radians(**self % *rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Neg<Radians<T>> {
    #[inline(always)]
    pure fn neg(&self) -> Radians<T> {
        Radians(-**self)
    }
}

pub impl<T:Copy Eq> Radians<T>: Eq {
    #[inline(always)] pure fn eq(&self, other: &Radians<T>) -> bool { **self == **other }
    #[inline(always)] pure fn ne(&self, other: &Radians<T>) -> bool { **self != **other }
}

pub impl<T:Copy Ord> Radians<T>: Ord {
    #[inline(always)] pure fn lt(&self, other: &Radians<T>) -> bool { **self <  **other }
    #[inline(always)] pure fn le(&self, other: &Radians<T>) -> bool { **self <= **other }
    #[inline(always)] pure fn ge(&self, other: &Radians<T>) -> bool { **self >= **other }
    #[inline(always)] pure fn gt(&self, other: &Radians<T>) -> bool { **self >  **other }
}

pub impl<T> Radians<T>: ToStr {
    pure fn to_str() -> ~str { fmt!("%? rad", *self) }
}

pub enum Degrees<T> = T;

pub impl<T:Copy Num NumCast> Degrees<T>: Angle<T> {
    #[inline(always)] static pure fn full_turn()    -> Degrees<T> { Degrees(move cast(360.0)) }
    #[inline(always)] static pure fn half_turn()    -> Degrees<T> { Degrees(move cast(180.0)) }
    #[inline(always)] static pure fn quadrant()     -> Degrees<T> { Degrees(move cast(90.0))  }
    #[inline(always)] static pure fn sextant()      -> Degrees<T> { Degrees(move cast(60.0))  }
    #[inline(always)] static pure fn octant()       -> Degrees<T> { Degrees(move cast(45.0))  }

    #[inline(always)] pure fn to_radians(&self) -> Radians<T> { Radians(**self * cast(pi / 180.0)) }
    #[inline(always)] pure fn to_degrees(&self) -> Degrees<T> { *self }

    #[inline(always)]
    pure fn wrap(&self) -> Degrees<T> {
        (*self) % cast(360)   // TODO: keep in the domain of 0 to 360
    }

    #[inline(always)]
    pure fn opposite(&self) -> Degrees<T> {
        (self + Angle::half_turn()).wrap()      // TODO: test!
    }
}

pub impl<T:Copy Num> Degrees<T>: Add<Degrees<T>, Degrees<T>> {
    #[inline(always)]
    pure fn add(rhs: &Degrees<T>) -> Degrees<T> {
        Degrees(*self + **rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Sub<Degrees<T>, Degrees<T>> {
    #[inline(always)]
    pure fn sub(&self, rhs: &Degrees<T>) -> Degrees<T> {
        Degrees(**self - **rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Mul<T, Degrees<T>> {
    #[inline(always)]
    pure fn mul(&self, rhs: &T) -> Degrees<T> {
        Degrees(**self * *rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Div<T, Degrees<T>> {
    #[inline(always)]
    pure fn div(&self, rhs: &T) -> Degrees<T> {
        Degrees(**self / *rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Modulo<T, Degrees<T>> {
    #[inline(always)]
    pure fn modulo(&self, rhs: &T) -> Degrees<T> {
        Degrees(**self % *rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Neg<Degrees<T>> {
    #[inline(always)]
    pure fn neg(&self) -> Degrees<T> {
        Degrees(-**self)
    }
}

pub impl<T:Copy Eq> Degrees<T>: Eq {
    #[inline(always)] pure fn eq(&self, other: &Degrees<T>) -> bool { **self == **other }
    #[inline(always)] pure fn ne(&self, other: &Degrees<T>) -> bool { **self != **other }
}

pub impl<T:Copy Ord> Degrees<T>: Ord {
    #[inline(always)] pure fn lt(&self, other: &Degrees<T>) -> bool { **self <  **other }
    #[inline(always)] pure fn le(&self, other: &Degrees<T>) -> bool { **self <= **other }
    #[inline(always)] pure fn ge(&self, other: &Degrees<T>) -> bool { **self >= **other }
    #[inline(always)] pure fn gt(&self, other: &Degrees<T>) -> bool { **self >  **other }
}

pub impl<T> Degrees<T>: ToStr {
    pure fn to_str() -> ~str { fmt!("%?\xB0", *self) }
}

/**
 * An angular rotation around an arbitary axis
 */
pub struct Rotation<T> {
    theta: Radians<T>,
    axis: Vec3<T>,
}

pub impl<T:Copy Num NumCast> Rotation<T> {
    #[inline(always)]
    static pure fn new(theta: Radians<T>, axis: Vec3<T>) -> Rotation<T> {
        Rotation { theta: move theta, axis: move axis }
    }

    #[inline(always)]
    pure fn to_mat3() -> Mat3<T> {
        let c:  T = cos(&self.theta);
        let s:  T = sin(&self.theta);
        let _0: T = cast(0);
        let _1: T = cast(1);
        let t:  T = _1 - c;

        let x = self.axis.x;
        let y = self.axis.y;
        let z = self.axis.z;

        Mat3::new(t * x * x + c,       t * x * y + s * z,   t * x * z - s * y,
                  t * x * y - s * z,   t * y * y + c,       t * y * z + s * x,
                  t * x * z - s - y,   t * y * z - s * x,   t * z * z + c)
    }

    #[inline(always)]
    pure fn to_mat4() -> Mat4<T> {
        self.to_mat3().to_mat4()
    }

    #[inline(always)]
    pure fn to_quat() -> Quat<T> {
        let half = self.theta / cast(2);
        Quat::from_sv(cos(&half), self.axis.mul_t(sin(&half)))
    }
}

pub struct Euler<T> {
    x: Radians<T>,   // pitch
    y: Radians<T>,   // yaw
    z: Radians<T>,   // roll
}<commit_msg>Add missing trait bounds<commit_after>use core::cmp::{Eq, Ord};
use core::f64::consts::pi;

use funs::triganomic::{cos, sin};
use mat::{Mat3, Mat4};
use num::cast::{NumCast, cast};
use quat::Quat;
use vec::Vec3;

/**
 * The base trait for anglular units
 */
pub trait Angle<T>: Add<self,self>
                  , Sub<self,self>
                  , Mul<T,self>
                  , Div<T,self>
                  , Modulo<T,self>
                  , Neg<self>
                  , Eq, Ord {
    static pure fn full_turn() -> self;
    static pure fn half_turn() -> self;
    static pure fn quadrant()  -> self;
    static pure fn sextant()   -> self;
    static pure fn octant()    -> self;

    pure fn to_radians(&self) -> Radians<T>;
    pure fn to_degrees(&self) -> Degrees<T>;
    pure fn wrap(&self) -> self;
    pure fn opposite(&self) -> self;
}

pub enum Radians<T> = T;

// FIXME: not sure why I need the Eq and Ord trait bounds, but Rust complains if I don't include them
pub impl<T:Copy Num NumCast Eq Ord> Radians<T>: Angle<T> {
    #[inline(always)] static pure fn full_turn()    -> Radians<T> { Radians(move cast(2.0 * pi)) }  // TODO: calculate absolute values
    #[inline(always)] static pure fn half_turn()    -> Radians<T> { Radians(move cast(pi))       }
    #[inline(always)] static pure fn quadrant()     -> Radians<T> { Radians(move cast(pi / 2.0)) }
    #[inline(always)] static pure fn sextant()      -> Radians<T> { Radians(move cast(pi / 3.0)) }
    #[inline(always)] static pure fn octant()       -> Radians<T> { Radians(move cast(pi / 4.0)) }

    #[inline(always)] pure fn to_radians(&self) -> Radians<T> { *self }
    #[inline(always)] pure fn to_degrees(&self) -> Degrees<T> { Degrees(**self * cast(180.0 / pi)) }

    #[inline(always)]
    pure fn wrap(&self) -> Radians<T> {
        (*self) % cast(2.0 * pi)   // TODO: keep in the domain of 0 to two_pi
    }

    #[inline(always)]
    pure fn opposite(&self) -> Radians<T> {
        (self + Angle::half_turn()).wrap()     // TODO: test!
    }
}

pub impl<T:Copy Num> Radians<T>: Add<Radians<T>, Radians<T>> {
    #[inline(always)]
    pure fn add(rhs: &Radians<T>) -> Radians<T> {
        Radians(*self + **rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Sub<Radians<T>, Radians<T>> {
    #[inline(always)]
    pure fn sub(&self, rhs: &Radians<T>) -> Radians<T> {
        Radians(**self - **rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Mul<T, Radians<T>> {
    #[inline(always)]
    pure fn mul(&self, rhs: &T) -> Radians<T> {
        Radians(**self * *rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Div<T, Radians<T>> {
    #[inline(always)]
    pure fn div(&self, rhs: &T) -> Radians<T> {
        Radians(**self / *rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Modulo<T, Radians<T>> {
    #[inline(always)]
    pure fn modulo(&self, rhs: &T) -> Radians<T> {
        Radians(**self % *rhs)
    }
}

pub impl<T:Copy Num> Radians<T>: Neg<Radians<T>> {
    #[inline(always)]
    pure fn neg(&self) -> Radians<T> {
        Radians(-**self)
    }
}

pub impl<T:Copy Eq> Radians<T>: Eq {
    #[inline(always)] pure fn eq(&self, other: &Radians<T>) -> bool { **self == **other }
    #[inline(always)] pure fn ne(&self, other: &Radians<T>) -> bool { **self != **other }
}

pub impl<T:Copy Ord> Radians<T>: Ord {
    #[inline(always)] pure fn lt(&self, other: &Radians<T>) -> bool { **self <  **other }
    #[inline(always)] pure fn le(&self, other: &Radians<T>) -> bool { **self <= **other }
    #[inline(always)] pure fn ge(&self, other: &Radians<T>) -> bool { **self >= **other }
    #[inline(always)] pure fn gt(&self, other: &Radians<T>) -> bool { **self >  **other }
}

pub impl<T> Radians<T>: ToStr {
    pure fn to_str() -> ~str { fmt!("%? rad", *self) }
}

pub enum Degrees<T> = T;

// FIXME: not sure why I need the Eq and Ord trait bounds, but Rust complains if I don't include them
pub impl<T:Copy Num NumCast Eq Ord> Degrees<T>: Angle<T> {
    #[inline(always)] static pure fn full_turn()    -> Degrees<T> { Degrees(move cast(360.0)) }
    #[inline(always)] static pure fn half_turn()    -> Degrees<T> { Degrees(move cast(180.0)) }
    #[inline(always)] static pure fn quadrant()     -> Degrees<T> { Degrees(move cast(90.0))  }
    #[inline(always)] static pure fn sextant()      -> Degrees<T> { Degrees(move cast(60.0))  }
    #[inline(always)] static pure fn octant()       -> Degrees<T> { Degrees(move cast(45.0))  }

    #[inline(always)] pure fn to_radians(&self) -> Radians<T> { Radians(**self * cast(pi / 180.0)) }
    #[inline(always)] pure fn to_degrees(&self) -> Degrees<T> { *self }

    #[inline(always)]
    pure fn wrap(&self) -> Degrees<T> {
        (*self) % cast(360)   // TODO: keep in the domain of 0 to 360
    }

    #[inline(always)]
    pure fn opposite(&self) -> Degrees<T> {
        (self + Angle::half_turn()).wrap()      // TODO: test!
    }
}

pub impl<T:Copy Num> Degrees<T>: Add<Degrees<T>, Degrees<T>> {
    #[inline(always)]
    pure fn add(rhs: &Degrees<T>) -> Degrees<T> {
        Degrees(*self + **rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Sub<Degrees<T>, Degrees<T>> {
    #[inline(always)]
    pure fn sub(&self, rhs: &Degrees<T>) -> Degrees<T> {
        Degrees(**self - **rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Mul<T, Degrees<T>> {
    #[inline(always)]
    pure fn mul(&self, rhs: &T) -> Degrees<T> {
        Degrees(**self * *rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Div<T, Degrees<T>> {
    #[inline(always)]
    pure fn div(&self, rhs: &T) -> Degrees<T> {
        Degrees(**self / *rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Modulo<T, Degrees<T>> {
    #[inline(always)]
    pure fn modulo(&self, rhs: &T) -> Degrees<T> {
        Degrees(**self % *rhs)
    }
}

pub impl<T:Copy Num> Degrees<T>: Neg<Degrees<T>> {
    #[inline(always)]
    pure fn neg(&self) -> Degrees<T> {
        Degrees(-**self)
    }
}

pub impl<T:Copy Eq> Degrees<T>: Eq {
    #[inline(always)] pure fn eq(&self, other: &Degrees<T>) -> bool { **self == **other }
    #[inline(always)] pure fn ne(&self, other: &Degrees<T>) -> bool { **self != **other }
}

pub impl<T:Copy Ord> Degrees<T>: Ord {
    #[inline(always)] pure fn lt(&self, other: &Degrees<T>) -> bool { **self <  **other }
    #[inline(always)] pure fn le(&self, other: &Degrees<T>) -> bool { **self <= **other }
    #[inline(always)] pure fn ge(&self, other: &Degrees<T>) -> bool { **self >= **other }
    #[inline(always)] pure fn gt(&self, other: &Degrees<T>) -> bool { **self >  **other }
}

pub impl<T> Degrees<T>: ToStr {
    pure fn to_str() -> ~str { fmt!("%?\xB0", *self) }
}

/**
 * An angular rotation around an arbitary axis
 */
pub struct Rotation<T> {
    theta: Radians<T>,
    axis: Vec3<T>,
}

pub impl<T:Copy Num NumCast> Rotation<T> {
    #[inline(always)]
    static pure fn new(theta: Radians<T>, axis: Vec3<T>) -> Rotation<T> {
        Rotation { theta: move theta, axis: move axis }
    }

    #[inline(always)]
    pure fn to_mat3() -> Mat3<T> {
        let c:  T = cos(&self.theta);
        let s:  T = sin(&self.theta);
        let _0: T = cast(0);
        let _1: T = cast(1);
        let t:  T = _1 - c;

        let x = self.axis.x;
        let y = self.axis.y;
        let z = self.axis.z;

        Mat3::new(t * x * x + c,       t * x * y + s * z,   t * x * z - s * y,
                  t * x * y - s * z,   t * y * y + c,       t * y * z + s * x,
                  t * x * z - s - y,   t * y * z - s * x,   t * z * z + c)
    }

    #[inline(always)]
    pure fn to_mat4() -> Mat4<T> {
        self.to_mat3().to_mat4()
    }

    #[inline(always)]
    pure fn to_quat() -> Quat<T> {
        let half = self.theta / cast(2);
        Quat::from_sv(cos(&half), self.axis.mul_t(sin(&half)))
    }
}

pub struct Euler<T> {
    x: Radians<T>,   // pitch
    y: Radians<T>,   // yaw
    z: Radians<T>,   // roll
}<|endoftext|>