<commit_before>use crate::{
    emulator::Emulator,
    error::IoError,
    host::{DataRecorder, Host, LoadableAsset, SeekFrom, SeekableAsset},
    zx::{machine::ZXMachine, video::colors::ZXColor},
    Result,
};

const SNA_HEADER_SIZE: usize = 27;
const SNA_128K_SECONDARY_HEADER_SIZE: usize = 4;
const SNA_48K_SIZE: usize = 49179;
const SNA_128K_SECONDARY_HEADER_OFFSET: usize = SNA_48K_SIZE;
const SNA_128K_SECONDARY_TAIL_BANKS_OFFSET: usize = 49183;
const SNA_128K_PERSISTENT_BANK_0: u8 = 5;
const SNA_128K_PERSISTENT_BANK_1: u8 = 2;
const SNA_IFF2_BIT_MASK: u8 = 0x04;
const SNA_INTERRUPT_MODE_MASK: u8 = 0x03;
const SNA_BORDER_COLOR_MASK: u8 = 0x07;
const SNA_128K_TAIL_BANKS: &[u8] = &[0, 1, 3, 4, 6, 7];
const SNA_PAGINATED_PAGED_BANK_ADDRESS: u16 = 0xFFFF;
const SNA_48K_RAM_PAGES_COUNT: u8 = 3;

/// SNA snapshot loading function
pub fn load<H, A>(emulator: &mut Emulator<H>, mut asset: A) -> Result<()>
where
    H: Host,
    A: LoadableAsset + SeekableAsset,
{
    let size = asset.seek(SeekFrom::End(0))?;
    asset.seek(SeekFrom::Start(0))?;

    let is_128k = size > SNA_48K_SIZE;

    if !is_128k && size < SNA_48K_SIZE {
        return Err(IoError::UnexpectedEof.into());
    }

    let mut header = [0u8; SNA_HEADER_SIZE];
    asset.read_exact(&mut header)?;

    // i-reg
    emulator.cpu.regs.set_i(header[0]);
    // alt-regs
    emulator
        .cpu
        .regs
        .set_hl(u16::from_le_bytes([header[1], header[2]]));
    emulator
        .cpu
        .regs
        .set_de(u16::from_le_bytes([header[3], header[4]]));
    emulator
        .cpu
        .regs
        .set_bc(u16::from_le_bytes([header[5], header[6]]));
    emulator.cpu.regs.exx();
    // af'
    emulator
        .cpu
        .regs
        .set_af(u16::from_le_bytes([header[7], header[8]]));
    emulator.cpu.regs.swap_af_alt();
    // regs
    emulator
        .cpu
        .regs
        .set_hl(u16::from_le_bytes([header[9], header[10]]));
    emulator
        .cpu
        .regs
        .set_de(u16::from_le_bytes([header[11], header[12]]));
    emulator
        .cpu
        .regs
        .set_bc(u16::from_le_bytes([header[13], header[14]]));
    // index regs
    emulator
        .cpu
        .regs
        .set_iy(u16::from_le_bytes([header[15], header[16]]));
    emulator
        .cpu
        .regs
        .set_ix(u16::from_le_bytes([header[17], header[18]]));
    // iff2, iff1
    let iff = (header[19] & SNA_IFF2_BIT_MASK) != 0;
    emulator.cpu.regs.set_iff1(iff);
    emulator.cpu.regs.set_iff2(iff);
    // r
    emulator.cpu.regs.set_r(header[20]);
    // af
    emulator
        .cpu
        .regs
        .set_af(u16::from_le_bytes([header[21], header[22]]));
    // sp
    emulator
        .cpu
        .regs
        .set_sp(u16::from_le_bytes([header[23], header[24]]));
    // interrupt mode
    emulator.cpu.set_im(header[25] & SNA_INTERRUPT_MODE_MASK);
    // Border color
    emulator
        .controller
        .set_border_color(0, ZXColor::from_bits(header[26] & SNA_BORDER_COLOR_MASK));
    if is_128k {
        // PC, 7ffd port, trdos pagination status
        let mut tmp = [0u8; SNA_128K_SECONDARY_HEADER_SIZE];
        asset.seek(SeekFrom::Start(SNA_128K_SECONDARY_HEADER_OFFSET))?;
        asset.read_exact(&mut tmp)?;
        emulator
            .cpu
            .regs
            .set_pc(u16::from_le_bytes([header[0], header[1]]));
        let port_7ffd = tmp[2];
        let _trdos_paged = tmp[3];
        // This will alsto setup required memory map before banks restore
        emulator.controller.write_7ffd(port_7ffd);

        // Go to the previous position
        asset.seek(SeekFrom::Start(SNA_HEADER_SIZE))?;
        let paginated_bank = match emulator
            .controller
            .memory
            .get_page(SNA_PAGINATED_PAGED_BANK_ADDRESS)
        {
            crate::zx::memory::Page::Ram(bank) => bank,
            crate::zx::memory::Page::Rom(_) => 0,
        };

        // write 3 head banks
        let head_banks = &[
            SNA_128K_PERSISTENT_BANK_0,
            SNA_128K_PERSISTENT_BANK_1,
            paginated_bank,
        ];
        for bank in head_banks {
            let page = emulator.controller.memory.ram_page_data_mut(*bank);
            asset.read_exact(page)?;
        }

        // tail banks
        asset.seek(SeekFrom::Start(SNA_128K_SECONDARY_TAIL_BANKS_OFFSET))?;
        for bank in SNA_128K_TAIL_BANKS {
            if *bank == paginated_bank {
                continue;
            }
            let page = emulator.controller.memory.ram_page_data_mut(*bank);
            asset.read_exact(page)?;
        }
    } else {
        for page_index in 0..SNA_48K_RAM_PAGES_COUNT {
            let page = emulator.controller.memory.ram_page_data_mut(page_index);
            asset.read_exact(page)?;
        }

        emulator.cpu.pop_pc_from_stack(&mut emulator.controller);
    }

    // Refresh screen and other memory-dependent peripheral
    emulator.controller.refresh_memory_dependent_devices();

    Ok(())
}

/// Helper class to place emulator in the state required for
/// snapshoting and return to normal state afterwards
struct ScopedSnapshotState<'a, H: Host> {
    pub emulator: &'a mut Emulator<H>,
    pub is_48k: bool,
}

impl<'a, H: Host> ScopedSnapshotState<'a, H> {
    fn enter(emulator: &'a mut Emulator<H>) -> Self {
        let is_48k = emulator.settings.machine == ZXMachine::Sinclair48K;
        if is_48k {
            emulator.cpu.push_pc_to_stack(&mut emulator.controller);
        }

        Self { emulator, is_48k }
    }
}

impl<'a, H: Host> Drop for ScopedSnapshotState<'a, H> {
    fn drop(&mut self) {
        if self.is_48k {
            self.emulator
                .cpu
                .pop_pc_from_stack(&mut self.emulator.controller);
        }
    }
}

pub fn save<H, R>(emulator: &mut Emulator<H>, mut recorder: R) -> Result<()>
where
    H: Host,
    R: DataRecorder,
{
    let state = ScopedSnapshotState::enter(emulator);
    let ScopedSnapshotState { emulator, is_48k } = &state;

    let mut header = [0u8; SNA_HEADER_SIZE];
    // interrupt register
    header[0] = emulator.cpu.regs.get_i();
    // alt register pairs
    header[1] = emulator.cpu.regs.get_l_alt();
    header[2] = emulator.cpu.regs.get_h_alt();
    header[3] = emulator.cpu.regs.get_e_alt();
    header[4] = emulator.cpu.regs.get_d_alt();
    header[5] = emulator.cpu.regs.get_c_alt();
    header[6] = emulator.cpu.regs.get_b_alt();
    header[7] = emulator.cpu.regs.get_flags_alt();
    header[8] = emulator.cpu.regs.get_acc_alt();
    // hl, de, bc, iy, ix
    header[9] = emulator.cpu.regs.get_l();
    header[10] = emulator.cpu.regs.get_h();
    header[11] = emulator.cpu.regs.get_e();
    header[12] = emulator.cpu.regs.get_d();
    header[13] = emulator.cpu.regs.get_c();
    header[14] = emulator.cpu.regs.get_b();
    let [iyl, iyh] = emulator.cpu.regs.get_iy().to_le_bytes();
    header[15] = iyl;
    header[16] = iyh;
    let [ixl, ixh] = emulator.cpu.regs.get_ix().to_le_bytes();
    header[17] = ixl;
    header[18] = ixh;
    // iff2
    if emulator.cpu.regs.get_iff2() {
        header[19] = SNA_IFF2_BIT_MASK;
    }
    // r
    header[20] = emulator.cpu.regs.get_r();
    // AF
    header[21] = emulator.cpu.regs.get_flags();
    header[22] = emulator.cpu.regs.get_acc();
    // SP
    let [spl, sph] = emulator.cpu.regs.get_sp().to_le_bytes();
    header[23] = spl;
    header[24] = sph;
    // Interrupt mode
    header[25] = emulator.cpu.get_im().into();
    // Border color
    header[26] = emulator.controller.border_color.into();

    recorder.write_all(&header)?;

    if *is_48k {
        for page_index in 0..SNA_48K_RAM_PAGES_COUNT {
            let page = emulator.controller.memory.ram_page_data(page_index);
            recorder.write_all(page)?;
        }
    } else {
        let paginated_bank = match emulator
            .controller
            .memory
            .get_page(SNA_PAGINATED_PAGED_BANK_ADDRESS)
        {
            crate::zx::memory::Page::Ram(bank) => bank,
            crate::zx::memory::Page::Rom(_) => 0,
        };
        let head_banks = &[
            SNA_128K_PERSISTENT_BANK_0,
            SNA_128K_PERSISTENT_BANK_1,
            paginated_bank,
        ];
        for bank in head_banks {
            let page = emulator.controller.memory.ram_page_data(*bank);
            recorder.write_all(page)?;
        }

        // PC, 7ffd, trdos
        let [pcl, pch] = emulator.cpu.regs.get_pc().to_le_bytes();
        let port_7ffd = emulator.controller.read_7ffd();
        let trdos_paged = 0x00;
        recorder.write_all(&[pcl, pch, port_7ffd, trdos_paged])?;

        // remaining banks
        for bank in SNA_128K_TAIL_BANKS {
            if *bank == paginated_bank {
                continue;
            }
            let page = emulator.controller.memory.ram_page_data(*bank);
            recorder.write_all(page)?;
        }
    }

    Ok(())
}
<commit_msg>Fixed SNA loading<commit_after>use crate::{
    emulator::Emulator,
    error::IoError,
    host::{DataRecorder, Host, LoadableAsset, SeekFrom, SeekableAsset},
    zx::{machine::ZXMachine, video::colors::ZXColor},
    Result,
};

const SNA_HEADER_SIZE: usize = 27;
const SNA_128K_SECONDARY_HEADER_SIZE: usize = 4;
const SNA_48K_SIZE: usize = 49179;
const SNA_128K_SECONDARY_HEADER_OFFSET: usize = SNA_48K_SIZE;
const SNA_128K_SECONDARY_TAIL_BANKS_OFFSET: usize = 49183;
const SNA_128K_PERSISTENT_BANK_0: u8 = 5;
const SNA_128K_PERSISTENT_BANK_1: u8 = 2;
const SNA_IFF2_BIT_MASK: u8 = 0x04;
const SNA_INTERRUPT_MODE_MASK: u8 = 0x03;
const SNA_BORDER_COLOR_MASK: u8 = 0x07;
const SNA_128K_TAIL_BANKS: &[u8] = &[0, 1, 3, 4, 6, 7];
const SNA_PAGINATED_PAGED_BANK_ADDRESS: u16 = 0xFFFF;
const SNA_48K_RAM_PAGES_COUNT: u8 = 3;

/// SNA snapshot loading function
pub fn load<H, A>(emulator: &mut Emulator<H>, mut asset: A) -> Result<()>
where
    H: Host,
    A: LoadableAsset + SeekableAsset,
{
    let size = asset.seek(SeekFrom::End(0))?;
    asset.seek(SeekFrom::Start(0))?;

    let is_128k = size > SNA_48K_SIZE;

    if !is_128k && size < SNA_48K_SIZE {
        return Err(IoError::UnexpectedEof.into());
    }

    let mut header = [0u8; SNA_HEADER_SIZE];
    asset.read_exact(&mut header)?;

    // i-reg
    emulator.cpu.regs.set_i(header[0]);
    // alt-regs
    emulator
        .cpu
        .regs
        .set_hl(u16::from_le_bytes([header[1], header[2]]));
    emulator
        .cpu
        .regs
        .set_de(u16::from_le_bytes([header[3], header[4]]));
    emulator
        .cpu
        .regs
        .set_bc(u16::from_le_bytes([header[5], header[6]]));
    emulator.cpu.regs.exx();
    // af'
    emulator
        .cpu
        .regs
        .set_af(u16::from_le_bytes([header[7], header[8]]));
    emulator.cpu.regs.swap_af_alt();
    // regs
    emulator
        .cpu
        .regs
        .set_hl(u16::from_le_bytes([header[9], header[10]]));
    emulator
        .cpu
        .regs
        .set_de(u16::from_le_bytes([header[11], header[12]]));
    emulator
        .cpu
        .regs
        .set_bc(u16::from_le_bytes([header[13], header[14]]));
    // index regs
    emulator
        .cpu
        .regs
        .set_iy(u16::from_le_bytes([header[15], header[16]]));
    emulator
        .cpu
        .regs
        .set_ix(u16::from_le_bytes([header[17], header[18]]));
    // iff2, iff1
    let iff = (header[19] & SNA_IFF2_BIT_MASK) != 0;
    emulator.cpu.regs.set_iff1(iff);
    emulator.cpu.regs.set_iff2(iff);
    // r
    emulator.cpu.regs.set_r(header[20]);
    // af
    emulator
        .cpu
        .regs
        .set_af(u16::from_le_bytes([header[21], header[22]]));
    // sp
    emulator
        .cpu
        .regs
        .set_sp(u16::from_le_bytes([header[23], header[24]]));
    // interrupt mode
    emulator.cpu.set_im(header[25] & SNA_INTERRUPT_MODE_MASK);
    // Border color
    emulator
        .controller
        .set_border_color(0, ZXColor::from_bits(header[26] & SNA_BORDER_COLOR_MASK));
    if is_128k {
        // PC, 7ffd port, trdos pagination status
        let mut tmp = [0u8; SNA_128K_SECONDARY_HEADER_SIZE];
        asset.seek(SeekFrom::Start(SNA_128K_SECONDARY_HEADER_OFFSET))?;
        asset.read_exact(&mut tmp)?;
        emulator
            .cpu
            .regs
            .set_pc(u16::from_le_bytes([tmp[0], tmp[1]]));
        let port_7ffd = tmp[2];
        let _trdos_paged = tmp[3];
        // This will alsto setup required memory map before banks restore
        emulator.controller.write_7ffd(port_7ffd);

        // Go to the previous position
        asset.seek(SeekFrom::Start(SNA_HEADER_SIZE))?;
        let paginated_bank = match emulator
            .controller
            .memory
            .get_page(SNA_PAGINATED_PAGED_BANK_ADDRESS)
        {
            crate::zx::memory::Page::Ram(bank) => bank,
            crate::zx::memory::Page::Rom(_) => 0,
        };

        // write 3 head banks
        let head_banks = &[
            SNA_128K_PERSISTENT_BANK_0,
            SNA_128K_PERSISTENT_BANK_1,
            paginated_bank,
        ];
        for bank in head_banks {
            let page = emulator.controller.memory.ram_page_data_mut(*bank);
            asset.read_exact(page)?;
        }

        // tail banks
        asset.seek(SeekFrom::Start(SNA_128K_SECONDARY_TAIL_BANKS_OFFSET))?;
        for bank in SNA_128K_TAIL_BANKS {
            if *bank == paginated_bank {
                continue;
            }
            let page = emulator.controller.memory.ram_page_data_mut(*bank);
            asset.read_exact(page)?;
        }
    } else {
        for page_index in 0..SNA_48K_RAM_PAGES_COUNT {
            let page = emulator.controller.memory.ram_page_data_mut(page_index);
            asset.read_exact(page)?;
        }

        emulator.cpu.pop_pc_from_stack(&mut emulator.controller);
    }

    // Refresh screen and other memory-dependent peripheral
    emulator.controller.refresh_memory_dependent_devices();

    Ok(())
}

/// Helper class to place emulator in the state required for
/// snapshoting and return to normal state afterwards
struct ScopedSnapshotState<'a, H: Host> {
    pub emulator: &'a mut Emulator<H>,
    pub is_48k: bool,
}

impl<'a, H: Host> ScopedSnapshotState<'a, H> {
    fn enter(emulator: &'a mut Emulator<H>) -> Self {
        let is_48k = emulator.settings.machine == ZXMachine::Sinclair48K;
        if is_48k {
            emulator.cpu.push_pc_to_stack(&mut emulator.controller);
        }

        Self { emulator, is_48k }
    }
}

impl<'a, H: Host> Drop for ScopedSnapshotState<'a, H> {
    fn drop(&mut self) {
        if self.is_48k {
            self.emulator
                .cpu
                .pop_pc_from_stack(&mut self.emulator.controller);
        }
    }
}

pub fn save<H, R>(emulator: &mut Emulator<H>, mut recorder: R) -> Result<()>
where
    H: Host,
    R: DataRecorder,
{
    let state = ScopedSnapshotState::enter(emulator);
    let ScopedSnapshotState { emulator, is_48k } = &state;

    let mut header = [0u8; SNA_HEADER_SIZE];
    // interrupt register
    header[0] = emulator.cpu.regs.get_i();
    // alt register pairs
    header[1] = emulator.cpu.regs.get_l_alt();
    header[2] = emulator.cpu.regs.get_h_alt();
    header[3] = emulator.cpu.regs.get_e_alt();
    header[4] = emulator.cpu.regs.get_d_alt();
    header[5] = emulator.cpu.regs.get_c_alt();
    header[6] = emulator.cpu.regs.get_b_alt();
    header[7] = emulator.cpu.regs.get_flags_alt();
    header[8] = emulator.cpu.regs.get_acc_alt();
    // hl, de, bc, iy, ix
    header[9] = emulator.cpu.regs.get_l();
    header[10] = emulator.cpu.regs.get_h();
    header[11] = emulator.cpu.regs.get_e();
    header[12] = emulator.cpu.regs.get_d();
    header[13] = emulator.cpu.regs.get_c();
    header[14] = emulator.cpu.regs.get_b();
    let [iyl, iyh] = emulator.cpu.regs.get_iy().to_le_bytes();
    header[15] = iyl;
    header[16] = iyh;
    let [ixl, ixh] = emulator.cpu.regs.get_ix().to_le_bytes();
    header[17] = ixl;
    header[18] = ixh;
    // iff2
    if emulator.cpu.regs.get_iff2() {
        header[19] = SNA_IFF2_BIT_MASK;
    }
    // r
    header[20] = emulator.cpu.regs.get_r();
    // AF
    header[21] = emulator.cpu.regs.get_flags();
    header[22] = emulator.cpu.regs.get_acc();
    // SP
    let [spl, sph] = emulator.cpu.regs.get_sp().to_le_bytes();
    header[23] = spl;
    header[24] = sph;
    // Interrupt mode
    header[25] = emulator.cpu.get_im().into();
    // Border color
    header[26] = emulator.controller.border_color.into();

    recorder.write_all(&header)?;

    if *is_48k {
        for page_index in 0..SNA_48K_RAM_PAGES_COUNT {
            let page = emulator.controller.memory.ram_page_data(page_index);
            recorder.write_all(page)?;
        }
    } else {
        let paginated_bank = match emulator
            .controller
            .memory
            .get_page(SNA_PAGINATED_PAGED_BANK_ADDRESS)
        {
            crate::zx::memory::Page::Ram(bank) => bank,
            crate::zx::memory::Page::Rom(_) => 0,
        };
        let head_banks = &[
            SNA_128K_PERSISTENT_BANK_0,
            SNA_128K_PERSISTENT_BANK_1,
            paginated_bank,
        ];
        for bank in head_banks {
            let page = emulator.controller.memory.ram_page_data(*bank);
            recorder.write_all(page)?;
        }

        // PC, 7ffd, trdos
        let [pcl, pch] = emulator.cpu.regs.get_pc().to_le_bytes();
        let port_7ffd = emulator.controller.read_7ffd();
        let trdos_paged = 0x00;
        recorder.write_all(&[pcl, pch, port_7ffd, trdos_paged])?;

        // remaining banks
        for bank in SNA_128K_TAIL_BANKS {
            if *bank == paginated_bank {
                continue;
            }
            let page = emulator.controller.memory.ram_page_data(*bank);
            recorder.write_all(page)?;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>#[test]
fn dogfood() {
    if option_env!("RUSTC_TEST_SUITE").is_some() {
        return;
    }
    let root_dir = std::env::current_dir().unwrap();
    for d in &[".", "clippy_lints", "rustc_tools_util", "clippy_dev"] {
        std::env::set_current_dir(root_dir.join(d)).unwrap();
        let output = std::process::Command::new("cargo")
            .arg("run")
            .arg("--bin")
            .arg("cargo-clippy")
            .arg("--all-features")
            .arg("--manifest-path")
            .arg(root_dir.join("Cargo.toml"))
            .args(&["--", "-W clippy::internal"])
            .env("CLIPPY_DOGFOOD", "true")
            .output()
            .unwrap();
        println!("status: {}", output.status);
        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

        assert!(output.status.success());
    }
}
<commit_msg>Disable dogfood until rust-lang-nursery/rustup.rs#1499 is merged<commit_after>#[test]
fn dogfood() {
    if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) {
        return;
    }
    let root_dir = std::env::current_dir().unwrap();
    for d in &[".", "clippy_lints", "rustc_tools_util", "clippy_dev"] {
        std::env::set_current_dir(root_dir.join(d)).unwrap();
        let output = std::process::Command::new("cargo")
            .arg("run")
            .arg("--bin")
            .arg("cargo-clippy")
            .arg("--all-features")
            .arg("--manifest-path")
            .arg(root_dir.join("Cargo.toml"))
            .args(&["--", "-W clippy::internal"])
            .env("CLIPPY_DOGFOOD", "true")
            .output()
            .unwrap();
        println!("status: {}", output.status);
        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

        assert!(output.status.success());
    }
}
<|endoftext|>


<commit_before>#![no_std]

#[macro_use]
extern crate static_assertions;

assert_eq_size!(byte; u8, u8, (u8,), [u8; 1]);

#[cfg(feature = "failure")]
assert_eq_size!(byte; u8, u8);

mod assoc_type {
    trait Trait {
        type AssocItem;
    }

    impl<T> Trait for T {
        type AssocItem = Self;
    }

    struct Value;

    impl Value {
        assert_eq_size!(test; <Self as Trait>::AssocItem, Self);
    }
}

// Placed in separate module so that DropCounter's fields are private
mod dc {
    /// A type that acts somewhat of a reference counter.
    pub struct DropCounter<'a> {
        count: &'a mut i32
    }

    impl<'a> DropCounter<'a> {
        pub fn new(count: &'a mut i32) -> DropCounter<'a> {
            *count += 1;
            DropCounter { count: count }
        }

        pub fn count(&self) -> i32 {
            *self.count
        }
    }

    impl<'a> Drop for DropCounter<'a> {
        fn drop(&mut self) {
            *self.count -= 1
        }
    }
}
use dc::*;

/// A type that panics on drop.
struct PanicDrop<T>(T);

impl<T> Drop for PanicDrop<T> {
    fn drop(&mut self) {
        panic!("Dropped!");
    }
}

#[test]
fn test_eq_size() {
    assert_eq_size!([u8; 2], u16);
    assert_eq_size!([u8; 2], u16, (u8, u8));
    assert_eq_size!([u8; 4], u32, (u16, u8, u8), (u16, u16));

    assert_eq_size_val!([0u8; 2], 0u16);
    assert_eq_size_val!([0u8; 2], 0u16, (0u8, 0u8));
    assert_eq_size_val!([0u8; 4], 0u32, (0u16, 0u8, 0u8), (0u16, 0u16));

    #[deny(unused_unsafe)]
    unsafe {
        assert_eq_size!(u8, u8);
        assert_eq_size_val!(0u8, 0u8);
    }

    // Should fail to compile (un-comment to test manually):
    // assert_eq_size!(u8, u16);
    // assert_eq_size_val!(0u8, 0u16);
}

#[test]
fn test_eq_size_no_drop() {
    assert_eq_size!(u32, PanicDrop<u32>);
    assert_eq_size!(PanicDrop<u32>, u32);
    assert_eq_size!(PanicDrop<u32>, PanicDrop<u32>);
}

#[test]
fn test_eq_size_drop_count() {
    let mut count = 0;
    {
        let dc = DropCounter::new(&mut count);
        assert_eq!(dc.count(), 1);
        assert_eq_size_val!(dc, 0usize);
        assert_eq!(dc.count(), 1);
        assert_eq_size_val!(dc, 0usize, dc);
        assert_eq!(dc.count(), 1);
    }
    assert_eq!(count, 0);

    assert_eq_size_val!(DropCounter::new(&mut count), 0usize);
    assert_eq!(count, 0);
}

// This test is expected to fail at compile-time
#[cfg(feature = "failure")]
#[test]
fn test_fail() {
    assert_eq_size!(u8, u32);
    assert_eq_size!(u8, u32, u64);
    assert_eq_size!([u8; 1], u8, u8, u64);
}
<commit_msg>Remove label test in eq_size<commit_after>#![no_std]

#[macro_use]
extern crate static_assertions;

assert_eq_size!(byte; u8, u8, (u8,), [u8; 1]);

mod assoc_type {
    trait Trait {
        type AssocItem;
    }

    impl<T> Trait for T {
        type AssocItem = Self;
    }

    struct Value;

    impl Value {
        assert_eq_size!(test; <Self as Trait>::AssocItem, Self);
    }
}

// Placed in separate module so that DropCounter's fields are private
mod dc {
    /// A type that acts somewhat of a reference counter.
    pub struct DropCounter<'a> {
        count: &'a mut i32
    }

    impl<'a> DropCounter<'a> {
        pub fn new(count: &'a mut i32) -> DropCounter<'a> {
            *count += 1;
            DropCounter { count: count }
        }

        pub fn count(&self) -> i32 {
            *self.count
        }
    }

    impl<'a> Drop for DropCounter<'a> {
        fn drop(&mut self) {
            *self.count -= 1
        }
    }
}
use dc::*;

/// A type that panics on drop.
struct PanicDrop<T>(T);

impl<T> Drop for PanicDrop<T> {
    fn drop(&mut self) {
        panic!("Dropped!");
    }
}

#[test]
fn test_eq_size() {
    assert_eq_size!([u8; 2], u16);
    assert_eq_size!([u8; 2], u16, (u8, u8));
    assert_eq_size!([u8; 4], u32, (u16, u8, u8), (u16, u16));

    assert_eq_size_val!([0u8; 2], 0u16);
    assert_eq_size_val!([0u8; 2], 0u16, (0u8, 0u8));
    assert_eq_size_val!([0u8; 4], 0u32, (0u16, 0u8, 0u8), (0u16, 0u16));

    #[deny(unused_unsafe)]
    unsafe {
        assert_eq_size!(u8, u8);
        assert_eq_size_val!(0u8, 0u8);
    }

    // Should fail to compile (un-comment to test manually):
    // assert_eq_size!(u8, u16);
    // assert_eq_size_val!(0u8, 0u16);
}

#[test]
fn test_eq_size_no_drop() {
    assert_eq_size!(u32, PanicDrop<u32>);
    assert_eq_size!(PanicDrop<u32>, u32);
    assert_eq_size!(PanicDrop<u32>, PanicDrop<u32>);
}

#[test]
fn test_eq_size_drop_count() {
    let mut count = 0;
    {
        let dc = DropCounter::new(&mut count);
        assert_eq!(dc.count(), 1);
        assert_eq_size_val!(dc, 0usize);
        assert_eq!(dc.count(), 1);
        assert_eq_size_val!(dc, 0usize, dc);
        assert_eq!(dc.count(), 1);
    }
    assert_eq!(count, 0);

    assert_eq_size_val!(DropCounter::new(&mut count), 0usize);
    assert_eq!(count, 0);
}

// This test is expected to fail at compile-time
#[cfg(feature = "failure")]
#[test]
fn test_fail() {
    assert_eq_size!(u8, u32);
    assert_eq_size!(u8, u32, u64);
    assert_eq_size!([u8; 1], u8, u8, u64);
}
<|endoftext|>


<commit_before>//! A replacement for the old (omnimacro era) expectation!

use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use syn::Token;

/// Convert a special reference type like "&str" into a reference to its owned
/// type like "&String".
fn destrify(ty: &mut syn::Type) {
    if let syn::Type::Reference(ref mut tr) = ty {
        let path_ty: syn::TypePath = syn::parse2(quote!(Path)).unwrap();
        let pathbuf_ty: syn::Type = syn::parse2(quote!(::std::path::PathBuf))
            .unwrap();

        let str_ty: syn::TypePath = syn::parse2(quote!(str)).unwrap();
        let string_ty: syn::Type = syn::parse2(quote!(::std::string::String))
            .unwrap();

        let cstr_ty: syn::TypePath = syn::parse2(quote!(CStr)).unwrap();
        let cstring_ty: syn::Type = syn::parse2(quote!(::std::ffi::CString))
            .unwrap();

        let osstr_ty: syn::TypePath = syn::parse2(quote!(OsStr)).unwrap();
        let osstring_ty: syn::Type = syn::parse2(quote!(::std::ffi::OsString))
            .unwrap();

        match tr.elem.as_ref() {
            syn::Type::Path(ref path) if *path == cstr_ty =>
                *tr.elem = cstring_ty,
            syn::Type::Path(ref path) if *path == osstr_ty =>
                *tr.elem = osstring_ty,
            syn::Type::Path(ref path) if *path == path_ty =>
                *tr.elem = pathbuf_ty,
            syn::Type::Path(ref path) if *path == str_ty =>
                *tr.elem = string_ty,
            _ => (), // Nothing to do
        };
    }
}

fn split_args(args: &syn::punctuated::Punctuated<syn::FnArg, Token![,]>)
    -> (syn::punctuated::Punctuated<syn::Pat, Token![,]>,
        syn::punctuated::Punctuated<syn::Type, Token![,]>)
{
    let mut names = syn::punctuated::Punctuated::new();
    let mut types = syn::punctuated::Punctuated::new();
    for fa in args {
        if let syn::FnArg::Captured(ac) = fa {
            names.push(ac.pat.clone());
            types.push(ac.ty.clone());
        }
    }
    (names, types)
}

fn strip_self(args: &syn::punctuated::Punctuated<syn::FnArg, Token![,]>)
    -> syn::punctuated::Punctuated<syn::FnArg, Token![,]>
{
    let mut out = syn::punctuated::Punctuated::new();
    for fa in args {
        if let syn::FnArg::Captured(_) = fa {
            out.push(fa.clone());
        }
    }
    out
}

/// Generate the code that implements an expectation for a single method
pub(crate) fn expectation(attrs: &TokenStream, vis: &syn::Visibility,
    self_ident: Option<&syn::Ident>,
    ident: &syn::Ident,
    generics: &syn::Generics,
    args: &syn::punctuated::Punctuated<syn::FnArg, Token![,]>,
    return_type: &syn::ReturnType,
    altargs: &syn::punctuated::Punctuated<syn::FnArg, Token![,]>,
    matchexprs: &syn::punctuated::Punctuated<syn::Expr, Token![,]>
    ) -> TokenStream
{
    let mut ref_expectation = false;
    let mut ref_mut_expectation = false;

    let output = match return_type{
        syn::ReturnType::Default => quote!(()),
        syn::ReturnType::Type(_, ty) => {
            let mut rt = ty.clone();
            crate::deimplify(&mut rt);
            destrify(&mut rt);
            if let Some(i) = self_ident {
                crate::deselfify(&mut rt, i);
            }
            if let syn::Type::Reference(ref tr) = rt.as_ref() {
                if tr.lifetime.as_ref().map_or(false, |lt| lt.ident == "static")
                {
                    // Just a static expectation
                } else {
                    if !tr.mutability.is_some() {
                        ref_expectation = true;
                    } else {
                        ref_mut_expectation = true;
                    }
                    rt = tr.elem.clone();
                }
            }
            quote!(#rt)
        }
    };

    let mut macro_g = TokenStream::new();
    let mut bounded_macro_g = TokenStream::new();
    // Convert the TypeGenerics into a sequence of idents, because that's
    // what static_expectations! expects
    // TODO: once static_expectations! is gone, something like this:
    //generics.split_for_impl().1.to_tokens(&mut macro_g)
    for p in generics.params.iter() {
        if let syn::GenericParam::Type(tp) = p {
            tp.ident.to_tokens(&mut macro_g);
            quote!(#ident: 'static).to_tokens(&mut bounded_macro_g);
        }
    }

    let selfless_args = strip_self(args);
    let (argnames, argty) = split_args(args);
    let (altargnames, altargty) = split_args(altargs);
    if ref_expectation {
        quote!(
            pub mod #ident {
            use ::downcast::*;
            use ::fragile::Fragile;
            use ::predicates_tree::CaseTreeExt;
            use ::std::{
                collections::hash_map::HashMap,
                marker::PhantomData,
                mem,
                ops::{DerefMut, Range},
                sync::Mutex
            };
            use super::*;

            ::mockall::common_matcher!{
                [#macro_g] [#argnames] [#altargnames] [#altargty]
            }

            ::mockall::common_methods!{
                [#macro_g] [#argnames] [#altargnames] [#altargty]
            }

            /// Expectation type for methods taking a `&self` argument and returning
            /// immutable references.  This is the type returned by the `expect_*`
            /// methods.
            #vis struct Expectation<#bounded_macro_g> {
                common: Common<#macro_g>,
                result: Option<#output>,
            }

            impl<#bounded_macro_g> Expectation<#macro_g> {
                #vis fn call(&self, #selfless_args ) -> &#output {
                    self.common.call(#matchexprs);
                    &self.result.as_ref()
                        .expect("Must set return value with return_const")
                }

                /// Return a reference to a constant value from the `Expectation`
                #vis fn return_const(&mut self, o: #output) -> &mut Self {
                    self.result = Some(o);
                    self
                }

                ::mockall::expectation_methods!{
                    #vis [#argnames] [#altargnames] [#altargty]
                }
            }

            impl<#bounded_macro_g> Default for Expectation<#macro_g>
            {
                fn default() -> Self {
                    Expectation {
                        common: Common::default(),
                        result: None
                    }
                }
            }

            ::mockall::expectations_methods!{#vis [#macro_g]}
            impl<#bounded_macro_g> Expectations<#macro_g> {
                /// Simulating calling the real method.  Every current expectation
                /// will be checked in FIFO order and the first one with matching
                /// arguments will be used.
                #vis fn call(&self, #selfless_args ) -> &#output {
                    let n = self.0.len();
                    match self.0.iter()
                        .find(|e| e.matches(#matchexprs) &&
                              (!e.is_done() || n == 1))
                    {
                        None => panic!("No matching expectation found"),
                        Some(e) => e.call(#selfless_args)
                    }
                }
            }
            // The Senc + Sync are required for downcast, since Expectation stores
            // an Option<#output>
            impl<#bounded_macro_g>
                ::mockall::AnyExpectations for Expectations<#macro_g>
                    where #output: Send + Sync
            {}

            ::mockall::generic_expectation_methods!{#vis [#macro_g] [#argty] #output}
            impl GenericExpectations {
                /// Simulating calling the real method.
                #vis fn call<#bounded_macro_g>
                    (&self, #selfless_args ) -> &#output
                {
                    let key = ::mockall::Key::new::<(#argty)>();
                    let e: &Expectations<#macro_g> = self.store.get(&key)
                        .expect("No matching expectation found")
                        .downcast_ref()
                        .unwrap();
                    e.call(#selfless_args)
                }

                /// Create a new Expectation.
                #vis fn expect<'e, #bounded_macro_g>(&'e mut self)
                    -> &'e mut Expectation<#macro_g>
                    where #output: Send + Sync
                {
                    let key = ::mockall::Key::new::<(#argty)>();
                    let ee: &mut Expectations<#macro_g> =
                        self.store.entry(key)
                        .or_insert_with(||
                            Box::new(Expectations::<#macro_g>::new())
                        ).downcast_mut()
                        .unwrap();
                    ee.expect()
                }
            }
        }
        )
    } else {
        quote!(pub mod #ident {
            ::mockall::static_expectation!{
                #vis [#macro_g] [#argnames] [#argty] [#altargnames]
                [#altargty] [#matchexprs] #output
            }
        })
    }
}
<commit_msg>Don't forget to emit attrs during mockall_derive::expectation<commit_after>//! A replacement for the old (omnimacro era) expectation!

use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use syn::Token;

/// Convert a special reference type like "&str" into a reference to its owned
/// type like "&String".
fn destrify(ty: &mut syn::Type) {
    if let syn::Type::Reference(ref mut tr) = ty {
        let path_ty: syn::TypePath = syn::parse2(quote!(Path)).unwrap();
        let pathbuf_ty: syn::Type = syn::parse2(quote!(::std::path::PathBuf))
            .unwrap();

        let str_ty: syn::TypePath = syn::parse2(quote!(str)).unwrap();
        let string_ty: syn::Type = syn::parse2(quote!(::std::string::String))
            .unwrap();

        let cstr_ty: syn::TypePath = syn::parse2(quote!(CStr)).unwrap();
        let cstring_ty: syn::Type = syn::parse2(quote!(::std::ffi::CString))
            .unwrap();

        let osstr_ty: syn::TypePath = syn::parse2(quote!(OsStr)).unwrap();
        let osstring_ty: syn::Type = syn::parse2(quote!(::std::ffi::OsString))
            .unwrap();

        match tr.elem.as_ref() {
            syn::Type::Path(ref path) if *path == cstr_ty =>
                *tr.elem = cstring_ty,
            syn::Type::Path(ref path) if *path == osstr_ty =>
                *tr.elem = osstring_ty,
            syn::Type::Path(ref path) if *path == path_ty =>
                *tr.elem = pathbuf_ty,
            syn::Type::Path(ref path) if *path == str_ty =>
                *tr.elem = string_ty,
            _ => (), // Nothing to do
        };
    }
}

fn split_args(args: &syn::punctuated::Punctuated<syn::FnArg, Token![,]>)
    -> (syn::punctuated::Punctuated<syn::Pat, Token![,]>,
        syn::punctuated::Punctuated<syn::Type, Token![,]>)
{
    let mut names = syn::punctuated::Punctuated::new();
    let mut types = syn::punctuated::Punctuated::new();
    for fa in args {
        if let syn::FnArg::Captured(ac) = fa {
            names.push(ac.pat.clone());
            types.push(ac.ty.clone());
        }
    }
    (names, types)
}

fn strip_self(args: &syn::punctuated::Punctuated<syn::FnArg, Token![,]>)
    -> syn::punctuated::Punctuated<syn::FnArg, Token![,]>
{
    let mut out = syn::punctuated::Punctuated::new();
    for fa in args {
        if let syn::FnArg::Captured(_) = fa {
            out.push(fa.clone());
        }
    }
    out
}

/// Generate the code that implements an expectation for a single method
pub(crate) fn expectation(attrs: &TokenStream, vis: &syn::Visibility,
    self_ident: Option<&syn::Ident>,
    ident: &syn::Ident,
    generics: &syn::Generics,
    args: &syn::punctuated::Punctuated<syn::FnArg, Token![,]>,
    return_type: &syn::ReturnType,
    altargs: &syn::punctuated::Punctuated<syn::FnArg, Token![,]>,
    matchexprs: &syn::punctuated::Punctuated<syn::Expr, Token![,]>
    ) -> TokenStream
{
    let mut ref_expectation = false;
    let mut ref_mut_expectation = false;

    let output = match return_type{
        syn::ReturnType::Default => quote!(()),
        syn::ReturnType::Type(_, ty) => {
            let mut rt = ty.clone();
            crate::deimplify(&mut rt);
            destrify(&mut rt);
            if let Some(i) = self_ident {
                crate::deselfify(&mut rt, i);
            }
            if let syn::Type::Reference(ref tr) = rt.as_ref() {
                if tr.lifetime.as_ref().map_or(false, |lt| lt.ident == "static")
                {
                    // Just a static expectation
                } else {
                    if !tr.mutability.is_some() {
                        ref_expectation = true;
                    } else {
                        ref_mut_expectation = true;
                    }
                    rt = tr.elem.clone();
                }
            }
            quote!(#rt)
        }
    };

    let mut macro_g = TokenStream::new();
    let mut bounded_macro_g = TokenStream::new();
    // Convert the TypeGenerics into a sequence of idents, because that's
    // what static_expectations! expects
    // TODO: once static_expectations! is gone, something like this:
    //generics.split_for_impl().1.to_tokens(&mut macro_g)
    for p in generics.params.iter() {
        if let syn::GenericParam::Type(tp) = p {
            tp.ident.to_tokens(&mut macro_g);
            quote!(#ident: 'static).to_tokens(&mut bounded_macro_g);
        }
    }

    let selfless_args = strip_self(args);
    let (argnames, argty) = split_args(args);
    let (altargnames, altargty) = split_args(altargs);
    if ref_expectation {
        quote!(
            #attrs
            pub mod #ident {
            use ::downcast::*;
            use ::fragile::Fragile;
            use ::predicates_tree::CaseTreeExt;
            use ::std::{
                collections::hash_map::HashMap,
                marker::PhantomData,
                mem,
                ops::{DerefMut, Range},
                sync::Mutex
            };
            use super::*;

            ::mockall::common_matcher!{
                [#macro_g] [#argnames] [#altargnames] [#altargty]
            }

            ::mockall::common_methods!{
                [#macro_g] [#argnames] [#altargnames] [#altargty]
            }

            /// Expectation type for methods taking a `&self` argument and returning
            /// immutable references.  This is the type returned by the `expect_*`
            /// methods.
            #vis struct Expectation<#bounded_macro_g> {
                common: Common<#macro_g>,
                result: Option<#output>,
            }

            impl<#bounded_macro_g> Expectation<#macro_g> {
                #vis fn call(&self, #selfless_args ) -> &#output {
                    self.common.call(#matchexprs);
                    &self.result.as_ref()
                        .expect("Must set return value with return_const")
                }

                /// Return a reference to a constant value from the `Expectation`
                #vis fn return_const(&mut self, o: #output) -> &mut Self {
                    self.result = Some(o);
                    self
                }

                ::mockall::expectation_methods!{
                    #vis [#argnames] [#altargnames] [#altargty]
                }
            }

            impl<#bounded_macro_g> Default for Expectation<#macro_g>
            {
                fn default() -> Self {
                    Expectation {
                        common: Common::default(),
                        result: None
                    }
                }
            }

            ::mockall::expectations_methods!{#vis [#macro_g]}
            impl<#bounded_macro_g> Expectations<#macro_g> {
                /// Simulating calling the real method.  Every current expectation
                /// will be checked in FIFO order and the first one with matching
                /// arguments will be used.
                #vis fn call(&self, #selfless_args ) -> &#output {
                    let n = self.0.len();
                    match self.0.iter()
                        .find(|e| e.matches(#matchexprs) &&
                              (!e.is_done() || n == 1))
                    {
                        None => panic!("No matching expectation found"),
                        Some(e) => e.call(#selfless_args)
                    }
                }
            }
            // The Senc + Sync are required for downcast, since Expectation stores
            // an Option<#output>
            impl<#bounded_macro_g>
                ::mockall::AnyExpectations for Expectations<#macro_g>
                    where #output: Send + Sync
            {}

            ::mockall::generic_expectation_methods!{#vis [#macro_g] [#argty] #output}
            impl GenericExpectations {
                /// Simulating calling the real method.
                #vis fn call<#bounded_macro_g>
                    (&self, #selfless_args ) -> &#output
                {
                    let key = ::mockall::Key::new::<(#argty)>();
                    let e: &Expectations<#macro_g> = self.store.get(&key)
                        .expect("No matching expectation found")
                        .downcast_ref()
                        .unwrap();
                    e.call(#selfless_args)
                }

                /// Create a new Expectation.
                #vis fn expect<'e, #bounded_macro_g>(&'e mut self)
                    -> &'e mut Expectation<#macro_g>
                    where #output: Send + Sync
                {
                    let key = ::mockall::Key::new::<(#argty)>();
                    let ee: &mut Expectations<#macro_g> =
                        self.store.entry(key)
                        .or_insert_with(||
                            Box::new(Expectations::<#macro_g>::new())
                        ).downcast_mut()
                        .unwrap();
                    ee.expect()
                }
            }
        }
        )
    } else {
        quote!(
            #attrs
            pub mod #ident {
            ::mockall::static_expectation!{
                #vis [#macro_g] [#argnames] [#argty] [#altargnames]
                [#altargty] [#matchexprs] #output
            }
        })
    }
}
<|endoftext|>


<commit_before>//! Format info tables for DRM formats.
//!
//! This module provides three functions, [`get_opaque`], [`has_alpha`] and [`get_bpp`].
//!
//! [`get_opaque`] returns the opaque alternative of a DRM format with an alpha channel.
//!
//! ```
//! # use smithay::backend::allocator::Fourcc;
//! # use smithay::backend::allocator::format::get_opaque;
//! assert_eq!(Some(Fourcc::Xrgb8888), get_opaque(Fourcc::Argb8888));
//! ```
//!
//! [`has_alpha`] returns true if the format has an alpha channel.
//!
//! ```
//! # use smithay::backend::allocator::Fourcc;
//! # use smithay::backend::allocator::format::has_alpha;
//! assert!(has_alpha(Fourcc::Argb8888));
//! assert!(!has_alpha(Fourcc::Xrgb8888));
//! ```
//!
//! [`get_bpp`] returns the number of bits per pixel of a format.
//!
//! ```
//! # use smithay::backend::allocator::Fourcc;
//! # use smithay::backend::allocator::format::get_bpp;
//! assert_eq!(get_bpp(Fourcc::Argb8888), Some(32));
//! ```

/// Macro to generate table lookup functions for formats.
///
/// See the module documentation for usage details.
macro_rules! format_tables {
    (
        $($fourcc: ident {
            $(opaque: $opaque: ident,)?
            alpha: $alpha: expr,
            bpp: $bpp: expr $(,)?
        }),*
    ) => {
        /// Returns the opaque alternative of the specified format.
        ///
        /// If the format has an alpha channel, this may return the corresponding opaque format.
        ///
        /// Unknown formats will always return [`None`].
        pub const fn get_opaque(
            fourcc: $crate::backend::allocator::Fourcc,
        ) -> Option<$crate::backend::allocator::Fourcc> {
            match fourcc {
                $($(
                    $crate::backend::allocator::Fourcc::$fourcc
                        => Some($crate::backend::allocator::Fourcc::$opaque),
                )?)*
                _ => None,
            }
        }

        /// Returns true if the format has an alpha channel.
        ///
        /// This function may be useful to know if the alpha channel may need to be swizzled when rendering
        /// with some graphics apis.
        ///
        /// Unknown formats will always return `false`.
        pub const fn has_alpha(fourcc: $crate::backend::allocator::Fourcc) -> bool {
            match fourcc {
                $(
                    $crate::backend::allocator::Fourcc::$fourcc => $alpha,
                )*
                _ => false,
            }
        }

        /// Returns the bits per pixel of the specified format.
        ///
        /// Unknown formats will always return [`None`].
        pub const fn get_bpp(
            fourcc: $crate::backend::allocator::Fourcc,
        ) -> Option<usize> {
            match fourcc {
                $($crate::backend::allocator::Fourcc::$fourcc => Some($bpp),)*
                _ => None,
            }
        }

        fn _impl_formats() -> &'static [$crate::backend::allocator::Fourcc] {
            &[
                $(
                    $crate::backend::allocator::Fourcc::$fourcc,
                )*
            ]
        }
    };
}

format_tables! {
    // 8-bit bpp Red
    R8 { alpha: false, bpp: 8 },

    // TODO: Update drm-fourcc
    // 16-bit bpp Red with padding (x:R)
    // R10 { bpp: 16 },
    // R12 { bpp: 16 },

    // 16-bit bpp Red
    R16 { alpha: false, bpp: 16 },

    // 16-bit bpp RG
    Rg88 { alpha: false, bpp: 16 },

    Gr88 { alpha: false, bpp: 16 },

    // 32-bit bpp RG
    Rg1616 { alpha: false, bpp: 16 },

    Gr1616 { alpha: false, bpp: 16 },

    // 8-bit bpp RGB
    Rgb332 { alpha: false, bpp: 8 },

    Bgr233 { alpha: false, bpp: 8 },

    // 16-bit bpp RGB, 4 bits per channel
    Argb4444 {
        opaque: Xrgb4444,
        alpha: true,
        bpp: 16,
    },

    Xrgb4444 { alpha: false, bpp: 16 },

    Abgr4444 {
        opaque: Xbgr4444,
        alpha: true,
        bpp: 16,
    },

    Xbgr4444 { alpha: false, bpp: 16 },

    Rgba4444 {
        opaque: Rgbx4444,
        alpha: true,
        bpp: 16,
    },

    Rgbx4444 { alpha: false, bpp: 16 },

    Bgra4444 {
        opaque: Bgrx4444,
        alpha: true,
        bpp: 16,
    },

    Bgrx4444 { alpha: false, bpp: 16 },

    // 16-bit bpp RGB, 5 bits per color channel, 1 bit for alpha channel
    Argb1555 {
        opaque: Xrgb1555,
        alpha: true,
        bpp: 16,
    },

    Xrgb1555 { alpha: false, bpp: 16 },

    Abgr1555 {
        opaque: Xbgr1555,
        alpha: true,
        bpp: 16,
    },

    Xbgr1555 { alpha: false, bpp: 16 },

    Rgba5551 {
        opaque: Rgbx5551,
        alpha: true,
        bpp: 16,
    },

    Rgbx5551 { alpha: false, bpp: 16 },

    Bgra5551 {
        opaque: Bgrx5551,
        alpha: true,
        bpp: 16,
    },

    Bgrx5551 { alpha: false, bpp: 16 },

    // 16-bit bpp RGB, no alpha, 6 bits for green channel and 5 bits for blue and red
    Rgb565 { alpha: false, bpp: 16 },

    Bgr565 { alpha: false, bpp: 16 },

    // 24-bit bpp RGB
    Rgb888 { alpha: false, bpp: 24 },

    Bgr888 { alpha: false, bpp: 24 },

    // 32-bit bpp RGB, 8 bits per channel
    Argb8888 {
        opaque: Xrgb8888,
        alpha: true,
        bpp: 32,
    },

    Xrgb8888 { alpha: false, bpp: 32 },

    Abgr8888 {
        opaque: Xbgr8888,
        alpha: true,
        bpp: 32,
    },

    Xbgr8888 { alpha: false, bpp: 32 },

    Rgba8888 {
        opaque: Rgbx8888,
        alpha: true,
        bpp: 32,
    },

    Rgbx8888 { alpha: false, bpp: 32 },

    Bgra8888 {
        opaque: Bgrx8888,
        alpha: true,
        bpp: 32,
    },

    Bgrx8888 { alpha: false, bpp: 32 },

    // 32-bit bpp RGB with 10-bits per color channel

    Argb2101010 {
        opaque: Xrgb2101010,
        alpha: true,
        bpp: 32,
    },

    Xrgb2101010 { alpha: false, bpp: 32 },

    Abgr2101010 {
        opaque: Xbgr2101010,
        alpha: true,
        bpp: 32,
    },

    Xbgr2101010 { alpha: false, bpp: 32 },

    Rgba1010102 {
        opaque: Rgbx1010102,
        alpha: true,
        bpp: 32,
    },

    Rgbx1010102 { alpha: false, bpp: 32 },

    Bgra1010102 {
        opaque: Bgrx1010102,
        alpha: true,
        bpp: 32,
    },

    Bgrx1010102 { alpha: false, bpp: 32 },

    // 64-bit RGB, 16-bits per channel
    // TODO: Update drm-fourcc
    // Argb16161616 {
    //     opaque: Xrgb16161616,
    //     alpha: true,
    //     bpp: 64,
    // },
    // Xrgb16161616 { alpha: false, bpp: 64 },
    // Abgr16161616 {
    //     opaque: Xbgr16161616,
    //     alpha: true,
    //     bpp: 64,
    // },
    // Xbgr16161616 { alpha: false, bpp: 64 },

    // Floating point 64bpp RGB
    // IEEE 754-2008 binary16 half-precision float
    Argb16161616f {
        opaque: Xrgb16161616f,
        alpha: true,
        bpp: 64,
    },

    Xrgb16161616f { alpha: false, bpp: 64 },

    Abgr16161616f {
        opaque: Xbgr16161616f,
        alpha: true,
        bpp: 64,
    },

    Xbgr16161616f { alpha: false, bpp: 64 },

    // RGBA with 10-bit components packed in 64-bits per pixel, with 6-bits of unused padding per component

    // Axbxgxrx106106106106 has no direct non-alpha alternative.
    Axbxgxrx106106106106 { alpha: true, bpp: 64 }

    // TODO: YUV and other formats
}

#[cfg(test)]
mod tests {
    use super::{_impl_formats, get_bpp, get_opaque, has_alpha};

    /// Tests that opaque alternatives are not the same as the variant with alpha.
    #[test]
    fn opaque_neq() {
        for &format in _impl_formats() {
            if let Some(opaque) = get_opaque(format) {
                assert_ne!(
                    format, opaque,
                    "{}'s opaque alternative is the same format",
                    format
                );
            }
        }
    }

    /// Tests that opaque alternatives for formats do not have opaque alternatives themselves.
    ///
    /// For example, `Argb8888` should have an opaque alternative of `Xrgb8888` and `Xrgb8888` should have no
    /// opaque alternative.
    #[test]
    fn opaque_alternatives() {
        for &format in _impl_formats() {
            if let Some(opaque) = get_opaque(format) {
                // If a format is considered to be an opaque alternative, the format should not have an opaque
                // alternative.
                let result = get_opaque(opaque);

                assert!(
                    result.is_none(),
                    "Format {format} has an opaque alternative, {opaque}. However {opaque} reports an opaque alternative {opaque_opaque:?} which is incorrect",
                    format = format,
                    opaque = opaque,
                    opaque_opaque = result,
                );
            }
        }
    }

    /// Tests that a format and it's opaque alternative have the same number of bits per pixel.
    #[test]
    fn opaque_has_same_bpp() {
        for &format in _impl_formats() {
            if let Some(opaque) = get_opaque(format) {
                let format_bpp = get_bpp(format);
                let opaque_bpp = get_bpp(opaque);

                assert_eq!(
                    format_bpp,
                    opaque_bpp,
                    "Format {format} has a bpp of {format_bpp:?}. However the opaque alternative {opaque} has a different bpp of {opaque_bpp:?}",
                    format_bpp = get_bpp(format),
                    opaque = opaque,
                    opaque_bpp = get_bpp(opaque),
                );
            }
        }
    }

    /// A format with an opaque alternative should have alpha.
    ///
    /// The opaque alternative should not have alpha.
    #[test]
    fn format_with_opaque_has_alpha() {
        for &format in _impl_formats() {
            if let Some(opaque) = get_opaque(format) {
                // Since the format has an opaque alternative, verify the opaque alternative does not have alpha.
                assert!(
                    has_alpha(format),
                    "{} has an opaque alternative but does not state it has an alpha component",
                    format
                );

                // The opaque alternative should not have alpha.
                assert!(
                    !has_alpha(opaque),
                    "opaque alternative to {} ({}) has an alpha channel",
                    format,
                    opaque
                );
            }
        }
    }
}
<commit_msg>allocator: Add depth to format table<commit_after>//! Format info tables for DRM formats.
//!
//! This module provides three functions, [`get_opaque`], [`has_alpha`] and [`get_bpp`].
//!
//! [`get_opaque`] returns the opaque alternative of a DRM format with an alpha channel.
//!
//! ```
//! # use smithay::backend::allocator::Fourcc;
//! # use smithay::backend::allocator::format::get_opaque;
//! assert_eq!(Some(Fourcc::Xrgb8888), get_opaque(Fourcc::Argb8888));
//! ```
//!
//! [`has_alpha`] returns true if the format has an alpha channel.
//!
//! ```
//! # use smithay::backend::allocator::Fourcc;
//! # use smithay::backend::allocator::format::has_alpha;
//! assert!(has_alpha(Fourcc::Argb8888));
//! assert!(!has_alpha(Fourcc::Xrgb8888));
//! ```
//!
//! [`get_bpp`] returns the number of bits per pixel of a format.
//!
//! ```
//! # use smithay::backend::allocator::Fourcc;
//! # use smithay::backend::allocator::format::get_bpp;
//! assert_eq!(get_bpp(Fourcc::Argb8888), Some(32));
//! ```
//!
//! [`get_depth`] returns the number of used bits per pixel of a format
//! (excluding padding or non-alpha "X" parts of the format).
//!
//! ```
//! # use smithay::backend::allocator::Fourcc;
//! # use smithay::backend::allocator::format::get_depth;
//! assert_eq!(get_depth(Fourcc::Argb8888), Some(32));
//! assert_eq!(get_depth(Fourcc::Xrgb8888), Some(24));
//! ```

/// Macro to generate table lookup functions for formats.
///
/// See the module documentation for usage details.
macro_rules! format_tables {
    (
        $($fourcc: ident {
            $(opaque: $opaque: ident,)?
            alpha: $alpha: expr,
            bpp: $bpp: expr,
            depth: $depth: expr $(,)?
        }),*
    ) => {
        /// Returns the opaque alternative of the specified format.
        ///
        /// If the format has an alpha channel, this may return the corresponding opaque format.
        ///
        /// Unknown formats will always return [`None`].
        pub const fn get_opaque(
            fourcc: $crate::backend::allocator::Fourcc,
        ) -> Option<$crate::backend::allocator::Fourcc> {
            match fourcc {
                $($(
                    $crate::backend::allocator::Fourcc::$fourcc
                        => Some($crate::backend::allocator::Fourcc::$opaque),
                )?)*
                _ => None,
            }
        }

        /// Returns true if the format has an alpha channel.
        ///
        /// This function may be useful to know if the alpha channel may need to be swizzled when rendering
        /// with some graphics apis.
        ///
        /// Unknown formats will always return `false`.
        pub const fn has_alpha(fourcc: $crate::backend::allocator::Fourcc) -> bool {
            match fourcc {
                $(
                    $crate::backend::allocator::Fourcc::$fourcc => $alpha,
                )*
                _ => false,
            }
        }

        /// Returns the bits per pixel of the specified format.
        ///
        /// Unknown formats will always return [`None`].
        pub const fn get_bpp(
            fourcc: $crate::backend::allocator::Fourcc,
        ) -> Option<usize> {
            match fourcc {
                $($crate::backend::allocator::Fourcc::$fourcc => Some($bpp),)*
                _ => None,
            }
        }

        /// Returns the depth of the specified format.
        ///
        /// Unknown formats will always return [`None`].
        pub const fn get_depth(
            fourcc: $crate::backend::allocator::Fourcc,
        ) -> Option<usize> {
            match fourcc {
                $($crate::backend::allocator::Fourcc::$fourcc => Some($depth),)*
                _ => None,
            }
        }

        fn _impl_formats() -> &'static [$crate::backend::allocator::Fourcc] {
            &[
                $(
                    $crate::backend::allocator::Fourcc::$fourcc,
                )*
            ]
        }
    };
}

format_tables! {
    // 8-bit bpp Red
    R8 { alpha: false, bpp: 8, depth: 8 },

    // TODO: Update drm-fourcc
    // 16-bit bpp Red with padding (x:R)
    // R10 { bpp: 16, depth: 10 },
    // R12 { bpp: 16, depth: 12 },

    // 16-bit bpp Red
    R16 { alpha: false, bpp: 16, depth: 16 },

    // 16-bit bpp RG
    Rg88 { alpha: false, bpp: 16, depth: 16 },

    Gr88 { alpha: false, bpp: 16, depth: 16 },

    // 32-bit bpp RG
    Rg1616 { alpha: false, bpp: 32, depth: 32 },

    Gr1616 { alpha: false, bpp: 32, depth: 32 },

    // 8-bit bpp RGB
    Rgb332 { alpha: false, bpp: 8, depth: 8 },

    Bgr233 { alpha: false, bpp: 8, depth: 8 },

    // 16-bit bpp RGB, 4 bits per channel
    Argb4444 {
        opaque: Xrgb4444,
        alpha: true,
        bpp: 16,
        depth: 16,
    },

    Xrgb4444 { alpha: false, bpp: 16, depth: 12 },

    Abgr4444 {
        opaque: Xbgr4444,
        alpha: true,
        bpp: 16,
        depth: 16,
    },

    Xbgr4444 { alpha: false, bpp: 16, depth: 12 },

    Rgba4444 {
        opaque: Rgbx4444,
        alpha: true,
        bpp: 16,
        depth: 16,
    },

    Rgbx4444 { alpha: false, bpp: 16, depth: 12 },

    Bgra4444 {
        opaque: Bgrx4444,
        alpha: true,
        bpp: 16,
        depth: 16,
    },

    Bgrx4444 { alpha: false, bpp: 16, depth: 12 },

    // 16-bit bpp RGB, 5 bits per color channel, 1 bit for alpha channel
    Argb1555 {
        opaque: Xrgb1555,
        alpha: true,
        bpp: 16,
        depth: 16
    },

    Xrgb1555 { alpha: false, bpp: 16, depth: 15 },

    Abgr1555 {
        opaque: Xbgr1555,
        alpha: true,
        bpp: 16,
        depth: 16,
    },

    Xbgr1555 { alpha: false, bpp: 16, depth: 15 },

    Rgba5551 {
        opaque: Rgbx5551,
        alpha: true,
        bpp: 16,
        depth: 16,
    },

    Rgbx5551 { alpha: false, bpp: 16, depth: 15 },

    Bgra5551 {
        opaque: Bgrx5551,
        alpha: true,
        bpp: 16,
        depth: 16,
    },

    Bgrx5551 { alpha: false, bpp: 16, depth: 15 },

    // 16-bit bpp RGB, no alpha, 6 bits for green channel and 5 bits for blue and red
    Rgb565 { alpha: false, bpp: 16, depth: 16 },

    Bgr565 { alpha: false, bpp: 16, depth: 16 },

    // 24-bit bpp RGB
    Rgb888 { alpha: false, bpp: 24, depth: 24 },

    Bgr888 { alpha: false, bpp: 24, depth: 24 },

    // 32-bit bpp RGB, 8 bits per channel
    Argb8888 {
        opaque: Xrgb8888,
        alpha: true,
        bpp: 32,
        depth: 32,
    },

    Xrgb8888 { alpha: false, bpp: 32, depth: 24 },

    Abgr8888 {
        opaque: Xbgr8888,
        alpha: true,
        bpp: 32,
        depth: 32,
    },

    Xbgr8888 { alpha: false, bpp: 32, depth: 24 },

    Rgba8888 {
        opaque: Rgbx8888,
        alpha: true,
        bpp: 32,
        depth: 32,
    },

    Rgbx8888 { alpha: false, bpp: 32, depth: 24 },

    Bgra8888 {
        opaque: Bgrx8888,
        alpha: true,
        bpp: 32,
        depth: 32,
    },

    Bgrx8888 { alpha: false, bpp: 32, depth: 24 },

    // 32-bit bpp RGB with 10-bits per color channel

    Argb2101010 {
        opaque: Xrgb2101010,
        alpha: true,
        bpp: 32,
        depth: 32,
    },

    Xrgb2101010 { alpha: false, bpp: 32, depth: 30 },

    Abgr2101010 {
        opaque: Xbgr2101010,
        alpha: true,
        bpp: 32,
        depth: 32,
    },

    Xbgr2101010 { alpha: false, bpp: 32, depth: 30 },

    Rgba1010102 {
        opaque: Rgbx1010102,
        alpha: true,
        bpp: 32,
        depth: 32,
    },

    Rgbx1010102 { alpha: false, bpp: 32, depth: 30 },

    Bgra1010102 {
        opaque: Bgrx1010102,
        alpha: true,
        bpp: 32,
        depth: 32,
    },

    Bgrx1010102 { alpha: false, bpp: 32, depth: 30 },

    // 64-bit RGB, 16-bits per channel
    // TODO: Update drm-fourcc
    // Argb16161616 {
    //     opaque: Xrgb16161616,
    //     alpha: true,
    //     bpp: 64,
    //     depth: 64,
    // },
    // Xrgb16161616 { alpha: false, bpp: 64, depth: 48 },
    // Abgr16161616 {
    //     opaque: Xbgr16161616,
    //     alpha: true,
    //     bpp: 64,
    //     depth: 64,
    // },
    // Xbgr16161616 { alpha: false, bpp: 64, depth: 48 },

    // Floating point 64bpp RGB
    // IEEE 754-2008 binary16 half-precision float
    Argb16161616f {
        opaque: Xrgb16161616f,
        alpha: true,
        bpp: 64,
        depth: 64
    },

    Xrgb16161616f { alpha: false, bpp: 64, depth: 48 },

    Abgr16161616f {
        opaque: Xbgr16161616f,
        alpha: true,
        bpp: 64,
        depth: 64,
    },

    Xbgr16161616f { alpha: false, bpp: 64, depth: 48 },

    // RGBA with 10-bit components packed in 64-bits per pixel, with 6-bits of unused padding per component

    // Axbxgxrx106106106106 has no direct non-alpha alternative.
    Axbxgxrx106106106106 { alpha: true, bpp: 64, depth: 40 }

    // TODO: YUV and other formats
}

#[cfg(test)]
mod tests {
    use super::{_impl_formats, get_bpp, get_depth, get_opaque, has_alpha};

    /// Tests that opaque alternatives are not the same as the variant with alpha.
    #[test]
    fn opaque_neq() {
        for &format in _impl_formats() {
            if let Some(opaque) = get_opaque(format) {
                assert_ne!(
                    format, opaque,
                    "{}'s opaque alternative is the same format",
                    format
                );
            }
        }
    }

    /// Tests that opaque alternatives for formats do not have opaque alternatives themselves.
    ///
    /// For example, `Argb8888` should have an opaque alternative of `Xrgb8888` and `Xrgb8888` should have no
    /// opaque alternative.
    #[test]
    fn opaque_alternatives() {
        for &format in _impl_formats() {
            if let Some(opaque) = get_opaque(format) {
                // If a format is considered to be an opaque alternative, the format should not have an opaque
                // alternative.
                let result = get_opaque(opaque);

                assert!(
                    result.is_none(),
                    "Format {format} has an opaque alternative, {opaque}. However {opaque} reports an opaque alternative {opaque_opaque:?} which is incorrect",
                    format = format,
                    opaque = opaque,
                    opaque_opaque = result,
                );
            }
        }
    }

    /// Tests that a format and it's opaque alternative have the same number of bits per pixel.
    #[test]
    fn opaque_has_same_bpp() {
        for &format in _impl_formats() {
            if let Some(opaque) = get_opaque(format) {
                let format_bpp = get_bpp(format);
                let opaque_bpp = get_bpp(opaque);

                assert_eq!(
                    format_bpp,
                    opaque_bpp,
                    "Format {format} has a bpp of {format_bpp:?}. However the opaque alternative {opaque} has a different bpp of {opaque_bpp:?}",
                    format_bpp = get_bpp(format),
                    opaque = opaque,
                    opaque_bpp = get_bpp(opaque),
                );
            }
        }
    }

    /// A format with an opaque alternative should have alpha.
    ///
    /// The opaque alternative should not have alpha.
    #[test]
    fn format_with_opaque_has_alpha() {
        for &format in _impl_formats() {
            if let Some(opaque) = get_opaque(format) {
                // Since the format has an opaque alternative, verify the opaque alternative does not have alpha.
                assert!(
                    has_alpha(format),
                    "{} has an opaque alternative but does not state it has an alpha component",
                    format
                );

                // The opaque alternative should not have alpha.
                assert!(
                    !has_alpha(opaque),
                    "opaque alternative to {} ({}) has an alpha channel",
                    format,
                    opaque
                );
            }
        }
    }

    // A format's depth should always be equal or small to it's bits-per-pixel
    #[test]
    fn format_bpp_greater_or_equal_than_depth() {
        for &format in _impl_formats() {
            assert!(
                get_depth(format) <= get_bpp(format),
                "{} has a depth higher than its bpp",
                format
            );
        }
    }
}
<|endoftext|>


<commit_before>//! IO
//!
//! This module contains a number of functions for working with
//! `AsyncRead` and `AsyncWrite` types, including the
//! `AsyncReadExt` and `AsyncWriteExt` traits which add methods
//! to the `AsyncRead` and `AsyncWrite` types.

use std::vec::Vec;

pub use futures_io::{AsyncRead, AsyncWrite, IoVec};

#[cfg(feature = "io-compat")] use crate::compat::Compat;

// Temporarily removed until AsyncBufRead is implemented
// pub use io::lines::{lines, Lines};
// pub use io::read_until::{read_until, ReadUntil};
// mod lines;
// mod read_until;

mod allow_std;
pub use self::allow_std::AllowStdIo;

mod copy_into;
pub use self::copy_into::CopyInto;

mod flush;
pub use self::flush::Flush;

mod read;
pub use self::read::Read;

mod read_exact;
pub use self::read_exact::ReadExact;

mod read_to_end;
pub use self::read_to_end::ReadToEnd;

mod close;
pub use self::close::Close;

mod split;
pub use self::split::{ReadHalf, WriteHalf};

mod window;
pub use self::window::Window;

mod write_all;
pub use self::write_all::WriteAll;

/// An extension trait which adds utility methods to `AsyncRead` types.
pub trait AsyncReadExt: AsyncRead {
    /// Creates a future which copies all the bytes from one object to another.
    ///
    /// The returned future will copy all the bytes read from this `AsyncRead` into the
    /// `writer` specified. This future will only complete once the `reader` has hit
    /// EOF and all bytes have been written to and flushed from the `writer`
    /// provided.
    ///
    /// On success the number of bytes is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut writer = Cursor::new([0u8; 5]);
    ///
    /// let bytes = await!(reader.copy_into(&mut writer))?;
    ///
    /// assert_eq!(bytes, 4);
    /// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn copy_into<'a, W>(
        &'a mut self,
        writer: &'a mut W,
    ) -> CopyInto<'a, Self, W>
        where W: AsyncWrite,
    {
        CopyInto::new(self, writer)
    }

    /// Tries to read some bytes directly into the given `buf` in asynchronous
    /// manner, returning a future type.
    ///
    /// The returned future will resolve to the number of bytes read once the read
    /// operation is completed.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 5];
    ///
    /// let bytes = await!(reader.read(&mut output[..]))?;
    ///
    /// // This is only guaranteed to be 4 because `&[u8]` is a synchronous
    /// // reader. In a real system you could get anywhere from 1 to
    /// // `output.len()` bytes in a single read.
    /// assert_eq!(bytes, 4);
    /// assert_eq!(output, [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> {
        Read::new(self, buf)
    }

    /// Creates a future which will read exactly enough bytes to fill `buf`,
    /// returning an error if end of file (EOF) is hit sooner.
    ///
    /// The returned future will resolve once the read operation is completed.
    ///
    /// In the case of an error the buffer and the object will be discarded, with
    /// the error yielded.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 4];
    ///
    /// await!(reader.read_exact(&mut output))?;
    ///
    /// assert_eq!(output, [1, 2, 3, 4]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    ///
    /// ## EOF is hit before `buf` is filled
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::{self, Cursor};
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 5];
    ///
    /// let result = await!(reader.read_exact(&mut output));
    ///
    /// assert_eq!(result.unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
    /// # });
    /// ```
    fn read_exact<'a>(
        &'a mut self,
        buf: &'a mut [u8],
    ) -> ReadExact<'a, Self> {
        ReadExact::new(self, buf)
    }

    /// Creates a future which will read all the bytes from this `AsyncRead`.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = Vec::with_capacity(4);
    ///
    /// await!(reader.read_to_end(&mut output))?;
    ///
    /// assert_eq!(output, vec![1, 2, 3, 4]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn read_to_end<'a>(
        &'a mut self,
        buf: &'a mut Vec<u8>,
    ) -> ReadToEnd<'a, Self> {
        ReadToEnd::new(self, buf)
    }

    /// Helper method for splitting this read/write object into two halves.
    ///
    /// The two halves returned implement the `AsyncRead` and `AsyncWrite`
    /// traits, respectively.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// // Note that for `Cursor` the read and write halves share a single
    /// // seek position. This may or may not be true for other types that
    /// // implement both `AsyncRead` and `AsyncWrite`.
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut buffer = Cursor::new([0, 0, 0, 0, 5, 6, 7, 8]);
    /// let mut writer = Cursor::new([0u8; 5]);
    ///
    /// {
    ///     let (mut buffer_reader, mut buffer_writer) = (&mut buffer).split();
    ///     await!(reader.copy_into(&mut buffer_writer))?;
    ///     await!(buffer_reader.copy_into(&mut writer))?;
    /// }
    ///
    /// assert_eq!(buffer.into_inner(), [1, 2, 3, 4, 5, 6, 7, 8]);
    /// assert_eq!(writer.into_inner(), [5, 6, 7, 8, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
        where Self: AsyncWrite + Sized,
    {
        split::split(self)
    }

    /// Wraps an [`AsyncRead`] in a compatibility wrapper that allows it to be
    /// used as a futures 0.1 / tokio-io 0.1 `AsyncRead`.
    /// Requires the `io-compat` feature to enable.
    #[cfg(feature = "io-compat")]
    fn compat(self) -> Compat<Self>
        where Self: Sized,
    {
        Compat::new(self)
    }
}

impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}

/// An extension trait which adds utility methods to `AsyncWrite` types.
pub trait AsyncWriteExt: AsyncWrite {
    /// Creates a future which will entirely flush this `AsyncWrite`.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::{AllowStdIo, AsyncWriteExt};
    /// use std::io::{BufWriter, Cursor};
    ///
    /// let mut output = [0u8; 5];
    ///
    /// {
    ///     let mut writer = Cursor::new(&mut output[..]);
    ///     let mut buffered = AllowStdIo::new(BufWriter::new(writer));
    ///     await!(buffered.write_all(&[1, 2]))?;
    ///     await!(buffered.write_all(&[3, 4]))?;
    ///     await!(buffered.flush())?;
    /// }
    ///
    /// assert_eq!(output, [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn flush(&mut self) -> Flush<'_, Self> {
        Flush::new(self)
    }

    /// Creates a future which will entirely close this `AsyncWrite`.
    fn close(&mut self) -> Close<'_, Self> {
        Close::new(self)
    }

    /// Write data into this object.
    ///
    /// Creates a future that will write the entire contents of the buffer `buf` into
    /// this `AsyncWrite`.
    ///
    /// The returned future will not complete until all the data has been written.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncWriteExt;
    /// use std::io::Cursor;
    ///
    /// let mut writer = Cursor::new([0u8; 5]);
    ///
    /// await!(writer.write_all(&[1, 2, 3, 4]))?;
    ///
    /// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> {
        WriteAll::new(self, buf)
    }

    /// Wraps an [`AsyncWrite`] in a compatibility wrapper that allows it to be
    /// used as a futures 0.1 / tokio-io 0.1 `AsyncWrite`.
    /// Requires the `io-compat` feature to enable.
    #[cfg(feature = "io-compat")]
    fn compat_write(self) -> Compat<Self>
        where Self: Sized,
    {
        Compat::new(self)
    }
}

impl<W: AsyncWrite + ?Sized> AsyncWriteExt for W {}
<commit_msg>AsyncRead + AsyncWrite compat doc clarification<commit_after>//! IO
//!
//! This module contains a number of functions for working with
//! `AsyncRead` and `AsyncWrite` types, including the
//! `AsyncReadExt` and `AsyncWriteExt` traits which add methods
//! to the `AsyncRead` and `AsyncWrite` types.

use std::vec::Vec;

pub use futures_io::{AsyncRead, AsyncWrite, IoVec};

#[cfg(feature = "io-compat")] use crate::compat::Compat;

// Temporarily removed until AsyncBufRead is implemented
// pub use io::lines::{lines, Lines};
// pub use io::read_until::{read_until, ReadUntil};
// mod lines;
// mod read_until;

mod allow_std;
pub use self::allow_std::AllowStdIo;

mod copy_into;
pub use self::copy_into::CopyInto;

mod flush;
pub use self::flush::Flush;

mod read;
pub use self::read::Read;

mod read_exact;
pub use self::read_exact::ReadExact;

mod read_to_end;
pub use self::read_to_end::ReadToEnd;

mod close;
pub use self::close::Close;

mod split;
pub use self::split::{ReadHalf, WriteHalf};

mod window;
pub use self::window::Window;

mod write_all;
pub use self::write_all::WriteAll;

/// An extension trait which adds utility methods to `AsyncRead` types.
pub trait AsyncReadExt: AsyncRead {
    /// Creates a future which copies all the bytes from one object to another.
    ///
    /// The returned future will copy all the bytes read from this `AsyncRead` into the
    /// `writer` specified. This future will only complete once the `reader` has hit
    /// EOF and all bytes have been written to and flushed from the `writer`
    /// provided.
    ///
    /// On success the number of bytes is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut writer = Cursor::new([0u8; 5]);
    ///
    /// let bytes = await!(reader.copy_into(&mut writer))?;
    ///
    /// assert_eq!(bytes, 4);
    /// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn copy_into<'a, W>(
        &'a mut self,
        writer: &'a mut W,
    ) -> CopyInto<'a, Self, W>
        where W: AsyncWrite,
    {
        CopyInto::new(self, writer)
    }

    /// Tries to read some bytes directly into the given `buf` in asynchronous
    /// manner, returning a future type.
    ///
    /// The returned future will resolve to the number of bytes read once the read
    /// operation is completed.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 5];
    ///
    /// let bytes = await!(reader.read(&mut output[..]))?;
    ///
    /// // This is only guaranteed to be 4 because `&[u8]` is a synchronous
    /// // reader. In a real system you could get anywhere from 1 to
    /// // `output.len()` bytes in a single read.
    /// assert_eq!(bytes, 4);
    /// assert_eq!(output, [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> {
        Read::new(self, buf)
    }

    /// Creates a future which will read exactly enough bytes to fill `buf`,
    /// returning an error if end of file (EOF) is hit sooner.
    ///
    /// The returned future will resolve once the read operation is completed.
    ///
    /// In the case of an error the buffer and the object will be discarded, with
    /// the error yielded.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 4];
    ///
    /// await!(reader.read_exact(&mut output))?;
    ///
    /// assert_eq!(output, [1, 2, 3, 4]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    ///
    /// ## EOF is hit before `buf` is filled
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::{self, Cursor};
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 5];
    ///
    /// let result = await!(reader.read_exact(&mut output));
    ///
    /// assert_eq!(result.unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
    /// # });
    /// ```
    fn read_exact<'a>(
        &'a mut self,
        buf: &'a mut [u8],
    ) -> ReadExact<'a, Self> {
        ReadExact::new(self, buf)
    }

    /// Creates a future which will read all the bytes from this `AsyncRead`.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = Vec::with_capacity(4);
    ///
    /// await!(reader.read_to_end(&mut output))?;
    ///
    /// assert_eq!(output, vec![1, 2, 3, 4]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn read_to_end<'a>(
        &'a mut self,
        buf: &'a mut Vec<u8>,
    ) -> ReadToEnd<'a, Self> {
        ReadToEnd::new(self, buf)
    }

    /// Helper method for splitting this read/write object into two halves.
    ///
    /// The two halves returned implement the `AsyncRead` and `AsyncWrite`
    /// traits, respectively.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// // Note that for `Cursor` the read and write halves share a single
    /// // seek position. This may or may not be true for other types that
    /// // implement both `AsyncRead` and `AsyncWrite`.
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut buffer = Cursor::new([0, 0, 0, 0, 5, 6, 7, 8]);
    /// let mut writer = Cursor::new([0u8; 5]);
    ///
    /// {
    ///     let (mut buffer_reader, mut buffer_writer) = (&mut buffer).split();
    ///     await!(reader.copy_into(&mut buffer_writer))?;
    ///     await!(buffer_reader.copy_into(&mut writer))?;
    /// }
    ///
    /// assert_eq!(buffer.into_inner(), [1, 2, 3, 4, 5, 6, 7, 8]);
    /// assert_eq!(writer.into_inner(), [5, 6, 7, 8, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
        where Self: AsyncWrite + Sized,
    {
        split::split(self)
    }

    /// Wraps an [`AsyncRead`] in a compatibility wrapper that allows it to be
    /// used as a futures 0.1 / tokio-io 0.1 `AsyncRead`. If the wrapped type
    /// implements [`AsyncWrite`] as well, the result will also implement the
    /// futures 0.1 / tokio 0.1 `AsyncWrite` trait.
    ///
    /// Requires the `io-compat` feature to enable.
    #[cfg(feature = "io-compat")]
    fn compat(self) -> Compat<Self>
        where Self: Sized,
    {
        Compat::new(self)
    }
}

impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}

/// An extension trait which adds utility methods to `AsyncWrite` types.
pub trait AsyncWriteExt: AsyncWrite {
    /// Creates a future which will entirely flush this `AsyncWrite`.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::{AllowStdIo, AsyncWriteExt};
    /// use std::io::{BufWriter, Cursor};
    ///
    /// let mut output = [0u8; 5];
    ///
    /// {
    ///     let mut writer = Cursor::new(&mut output[..]);
    ///     let mut buffered = AllowStdIo::new(BufWriter::new(writer));
    ///     await!(buffered.write_all(&[1, 2]))?;
    ///     await!(buffered.write_all(&[3, 4]))?;
    ///     await!(buffered.flush())?;
    /// }
    ///
    /// assert_eq!(output, [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn flush(&mut self) -> Flush<'_, Self> {
        Flush::new(self)
    }

    /// Creates a future which will entirely close this `AsyncWrite`.
    fn close(&mut self) -> Close<'_, Self> {
        Close::new(self)
    }

    /// Write data into this object.
    ///
    /// Creates a future that will write the entire contents of the buffer `buf` into
    /// this `AsyncWrite`.
    ///
    /// The returned future will not complete until all the data has been written.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncWriteExt;
    /// use std::io::Cursor;
    ///
    /// let mut writer = Cursor::new([0u8; 5]);
    ///
    /// await!(writer.write_all(&[1, 2, 3, 4]))?;
    ///
    /// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> {
        WriteAll::new(self, buf)
    }

    /// Wraps an [`AsyncWrite`] in a compatibility wrapper that allows it to be
    /// used as a futures 0.1 / tokio-io 0.1 `AsyncWrite`.
    /// Requires the `io-compat` feature to enable.
    #[cfg(feature = "io-compat")]
    fn compat_write(self) -> Compat<Self>
        where Self: Sized,
    {
        Compat::new(self)
    }
}

impl<W: AsyncWrite + ?Sized> AsyncWriteExt for W {}
<|endoftext|>