<commit_before>use std::ops::Range;

use gameboy::{Gpu, Irq, Memory, Timer};
use gameboy::cartridge::{Cartridge, CartridgeDetails};
use gameboy::frame::Frame;
use gameboy::irq::Interrupt;
use gameboy::joypad::{Joypad, JoypadButton};
use super::memory_map::{self, Address};

const MAIN_MEM_SIZE: usize = 0x2000;
const ZRAM_SIZE: usize = 0x80;
const MMAP_SIZE: usize = 0x80;

const BOOT_ROM: &'static [u8] = include_bytes!("boot_rom.gb");

pub struct Interconnect {
    pub booting: bool,
    pub boot_rom: Memory,
    pub gpu: Gpu,
    pub ram: Memory,
    pub zram: Memory,
    pub mmap_io: Memory,
    pub timer: Timer,
    pub irq: Irq,
    pub cart: Option<Cartridge>,
    pub interrupt: u8,
    pub joypad: Joypad,
}

impl Interconnect {
    pub fn new() -> Interconnect {
        Interconnect {
            booting: true,
            boot_rom: Self::init_boot_rom(true),
            gpu: Gpu::new(),
            ram: Memory::new(MAIN_MEM_SIZE),
            zram: Memory::new(ZRAM_SIZE),
            mmap_io: Memory::new(MMAP_SIZE),
            timer: Timer::new(),
            irq: Irq::new(),
            cart: None,
            interrupt: 0x00,
            joypad: Joypad::new(),
        }
    }

    pub fn with_cart(cart: Cartridge, boot_rom_enabled: bool) -> Interconnect {
        Interconnect {
            booting: true,
            boot_rom: Self::init_boot_rom(boot_rom_enabled),
            gpu: Gpu::new(),
            ram: Memory::new(MAIN_MEM_SIZE),
            zram: Memory::new(ZRAM_SIZE),
            mmap_io: Memory::new(MMAP_SIZE),
            timer: Timer::new(),
            irq: Irq::new(),
            cart: Some(cart),
            interrupt: 0x00,
            joypad: Joypad::new(),
        }
    }

    fn init_boot_rom(boot_rom_enabled: bool) -> Memory {
        if boot_rom_enabled {
            let mut mem = Memory::new(BOOT_ROM.len());
            mem.write_bytes(0x00, &BOOT_ROM);
            mem
        } else {
            // This is:
            //
            // LD A, $01
            // LD ($FF00+$32), A
            //

            let mut mem = Memory::new(0x04);
            mem.write_bytes(0x00, &[0x3E, 0x01, 0xE0, 0x50]);
            mem
        }
    }

    pub fn step(&mut self, cycles: usize) -> Result<(), String> {
        self.gpu.step(&mut self.irq, cycles)?;
        self.timer.step(&mut self.irq, cycles)?;
        self.joypad.step(&mut self.irq, cycles)?;

        Ok(())
    }

    pub fn reset(&mut self) {
        self.booting = true;
        self.gpu.reset();
        self.timer.reset();
        self.irq.reset();
    }

    pub fn cart_details(&self) -> CartridgeDetails {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        cart.details(&self)
    }

    pub fn request_frame(&self) -> &Frame {
        &self.gpu.frame
    }

    pub fn press(&mut self, button: JoypadButton) {
        self.joypad.press(button);
    }

    pub fn unpress(&mut self, button: JoypadButton) {
        self.joypad.unpress(button);
    }

    pub fn write_u8(&mut self, addr: u16, byte: u8) {
        // Special case - DMA transfer
        if addr == 0xFF46 {
            self.dma_transfer(byte);
            return;
        }
        let cart = self.cart.as_mut().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(a) => self.ram.write_u8(a, byte),
            Address::RamShadow(a) => self.ram.write_u8(a, byte),
            Address::Gfx(a) => self.gpu.ram.write_u8(a, byte),
            Address::CartRam(a) => cart.ram.write_u8(a, byte),
            Address::CartRom(a) => cart.rom.write_u8(a, byte),
            Address::ZRam(a) => {
                // if a != 0x00 {
                self.zram.write_u8(a, byte);
                // }
            }
            Address::Oam(a) => self.gpu.sprite_data.write_u8(a, byte),
            Address::Unused(_) => (),
            Address::Io(a) => {
                match a {
                    0x00 => self.joypad.from_u8(byte, &mut self.irq),
                    0x01...0x02 => (), // println!("err: write to serial driver not supported"),
                    0x04...0x07 => self.timer.write_u8(a, byte),
                    0x0F => self.irq.request_flag = byte,
                    0x10...0x26 => (), // println!("err: write to sound driver not supported"),
                    0x30...0x3F => (), // println!("err: write to wave pattern RAM not supported"),
                    0x40...0x45 => self.gpu.write_u8(a, byte),
                    0x47...0x49 => self.gpu.write_u8(a, byte),
                    0x50 => {
                        if self.booting {
                            self.booting = false;
                            self.irq.request(Interrupt::LoadGame);
                        } else {
                            self.mmap_io.write_u8(a, byte);
                        }
                    }
                    0x4A...0x4B => self.gpu.write_u8(a, byte),
                    0x7F => self.mmap_io.write_u8(a, byte),
                    _ => panic!("write memory mapped I/O in unsupported range: {:04X}", a),
                }
            }
            Address::InterruptEnableRegister(a) => self.irq.enable_flag = byte,
            _ => {
                panic!("Unable to write byte to: {:#X}, invalid memory region.",
                       addr)
            }
        }
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(addr) => self.ram.read_u8(addr),
            Address::RamShadow(addr) => self.ram.read_u8(addr),
            Address::CartRom(addr) => {
                if self.booting {
                    self.boot_rom.read_u8(addr)
                } else {
                    cart.rom.read_u8(addr)
                }
            }
            Address::CartRomOtherBank(addr) => cart.rom.read_u8(addr),
            Address::Gfx(value) => self.gpu.ram.read_u8(value),
            Address::CartRam(a) => cart.ram.read_u8(a),
            Address::ZRam(a) => self.zram.read_u8(a),
            Address::Oam(a) => self.gpu.sprite_data.read_u8(a),
            Address::Unused(_) => 0xFF, // Always return high
            Address::Io(a) => {
                match a {
                    0x00 => self.joypad.data,
                    0x01...0x02 => {
                        // println!("err: read from serial driver not supported");
                        0
                    }
                    0x04...0x07 => self.timer.read_u8(a),
                    0x0F => self.irq.request_flag,
                    0x10...0x26 => {
                        // println!("err: read from sound driver not supported");
                        0
                    }
                    0x30...0x3F => {
                        // println!("err: write to wave pattern RAM not supported");
                        0
                    }
                    0x40...0x45 => self.gpu.read_u8(a),
                    0x47...0x49 => self.gpu.read_u8(a),
                    0x4A...0x4B => self.gpu.read_u8(a),
                    0x7F => self.mmap_io.read_u8(a),
                    _ => panic!("read memory mapped I/O in unsupported range"),
                }
            }
            Address::InterruptEnableRegister(a) => self.irq.enable_flag,
            _ => panic!("Unable to read address: {:#X}", addr),
        }
    }

    pub fn read_bytes(&self, r: Range<u16>) -> &[u8] {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(r.start) {
            Address::Ram(_) |
            Address::RamShadow(_) => self.ram.read_bytes(r),
            Address::CartRom(_) => {
                if self.booting && r.start < 0xE0 {
                    self.boot_rom.read_bytes(r)
                } else {
                    cart.rom.read_bytes(r)
                }
            }
            Address::CartRomOtherBank(_) => cart.rom.read_bytes(r),
            Address::Gfx(_) => self.gpu.ram.read_bytes(r),
            Address::CartRam(_) => cart.ram.read_bytes(r),
            Address::ZRam(a) => self.zram.read_bytes(r),
            Address::Io(a) => self.mmap_io.read_bytes(r),
            _ => panic!("Unable to read address range: {:?}", r),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(a) => self.ram.write_u16(a, val),
            Address::RamShadow(a) => self.ram.write_u16(a, val),
            Address::ZRam(a) => self.zram.write_u16(a, val),
            _ => panic!("Unable to write address: {:#X}", addr),
        }
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(addr) => self.ram.read_u16(addr),
            Address::RamShadow(addr) => self.ram.read_u16(addr),
            Address::CartRom(addr) => {
                if self.booting {
                    self.boot_rom.read_u16(addr)
                } else {
                    cart.rom.read_u16(addr)
                }
            }
            Address::CartRomOtherBank(addr) => cart.rom.read_u16(addr),
            Address::Gfx(value) => self.gpu.ram.read_u16(value),
            Address::CartRam(a) => cart.ram.read_u16(a),
            Address::ZRam(a) => self.zram.read_u16(a),
            Address::Io(a) => self.mmap_io.read_u16(a),
            _ => panic!("Unable to read address: {:#X}", addr),
        }
    }

    pub fn write_bytes(&mut self, addr: u16, bytes: &[u8]) {
        let cart = self.cart.as_mut().expect("Cartridge is empty");
        match memory_map::map_address(addr) {
            Address::CartRom(addr) => cart.rom.write_bytes(addr, bytes),
            _ => panic!("write_bytes not mapped for specified memory region"),
        }
    }

    fn dma_transfer(&mut self, byte: u8) {
        let addr = (byte as u16) << 0x08; // "The written value specifies the transfer source address divided by 0x100"
        for x in 0..0xA0 {
            let val = self.read_u8(addr + x);
            self.write_u8(0xFE00 + x, val);
        }
    }
}
<commit_msg>Report address being read when panic'ing<commit_after>use std::ops::Range;

use gameboy::{Gpu, Irq, Memory, Timer};
use gameboy::cartridge::{Cartridge, CartridgeDetails};
use gameboy::frame::Frame;
use gameboy::irq::Interrupt;
use gameboy::joypad::{Joypad, JoypadButton};
use super::memory_map::{self, Address};

const MAIN_MEM_SIZE: usize = 0x2000;
const ZRAM_SIZE: usize = 0x80;
const MMAP_SIZE: usize = 0x80;

const BOOT_ROM: &'static [u8] = include_bytes!("boot_rom.gb");

pub struct Interconnect {
    pub booting: bool,
    pub boot_rom: Memory,
    pub gpu: Gpu,
    pub ram: Memory,
    pub zram: Memory,
    pub mmap_io: Memory,
    pub timer: Timer,
    pub irq: Irq,
    pub cart: Option<Cartridge>,
    pub interrupt: u8,
    pub joypad: Joypad,
}

impl Interconnect {
    pub fn new() -> Interconnect {
        Interconnect {
            booting: true,
            boot_rom: Self::init_boot_rom(true),
            gpu: Gpu::new(),
            ram: Memory::new(MAIN_MEM_SIZE),
            zram: Memory::new(ZRAM_SIZE),
            mmap_io: Memory::new(MMAP_SIZE),
            timer: Timer::new(),
            irq: Irq::new(),
            cart: None,
            interrupt: 0x00,
            joypad: Joypad::new(),
        }
    }

    pub fn with_cart(cart: Cartridge, boot_rom_enabled: bool) -> Interconnect {
        Interconnect {
            booting: true,
            boot_rom: Self::init_boot_rom(boot_rom_enabled),
            gpu: Gpu::new(),
            ram: Memory::new(MAIN_MEM_SIZE),
            zram: Memory::new(ZRAM_SIZE),
            mmap_io: Memory::new(MMAP_SIZE),
            timer: Timer::new(),
            irq: Irq::new(),
            cart: Some(cart),
            interrupt: 0x00,
            joypad: Joypad::new(),
        }
    }

    fn init_boot_rom(boot_rom_enabled: bool) -> Memory {
        if boot_rom_enabled {
            let mut mem = Memory::new(BOOT_ROM.len());
            mem.write_bytes(0x00, &BOOT_ROM);
            mem
        } else {
            // This is:
            //
            // LD A, $01
            // LD ($FF00+$32), A
            //

            let mut mem = Memory::new(0x04);
            mem.write_bytes(0x00, &[0x3E, 0x01, 0xE0, 0x50]);
            mem
        }
    }

    pub fn step(&mut self, cycles: usize) -> Result<(), String> {
        self.gpu.step(&mut self.irq, cycles)?;
        self.timer.step(&mut self.irq, cycles)?;
        self.joypad.step(&mut self.irq, cycles)?;

        Ok(())
    }

    pub fn reset(&mut self) {
        self.booting = true;
        self.gpu.reset();
        self.timer.reset();
        self.irq.reset();
    }

    pub fn cart_details(&self) -> CartridgeDetails {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        cart.details(&self)
    }

    pub fn request_frame(&self) -> &Frame {
        &self.gpu.frame
    }

    pub fn press(&mut self, button: JoypadButton) {
        self.joypad.press(button);
    }

    pub fn unpress(&mut self, button: JoypadButton) {
        self.joypad.unpress(button);
    }

    pub fn write_u8(&mut self, addr: u16, byte: u8) {
        // Special case - DMA transfer
        if addr == 0xFF46 {
            self.dma_transfer(byte);
            return;
        }
        let cart = self.cart.as_mut().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(a) => self.ram.write_u8(a, byte),
            Address::RamShadow(a) => self.ram.write_u8(a, byte),
            Address::Gfx(a) => self.gpu.ram.write_u8(a, byte),
            Address::CartRam(a) => cart.ram.write_u8(a, byte),
            Address::CartRom(a) => cart.rom.write_u8(a, byte),
            Address::ZRam(a) => {
                // if a != 0x00 {
                self.zram.write_u8(a, byte);
                // }
            }
            Address::Oam(a) => self.gpu.sprite_data.write_u8(a, byte),
            Address::Unused(_) => (),
            Address::Io(a) => {
                match a {
                    0x00 => self.joypad.from_u8(byte, &mut self.irq),
                    0x01...0x02 => (), // println!("err: write to serial driver not supported"),
                    0x04...0x07 => self.timer.write_u8(a, byte),
                    0x0F => self.irq.request_flag = byte,
                    0x10...0x26 => (), // println!("err: write to sound driver not supported"),
                    0x30...0x3F => (), // println!("err: write to wave pattern RAM not supported"),
                    0x40...0x45 => self.gpu.write_u8(a, byte),
                    0x47...0x49 => self.gpu.write_u8(a, byte),
                    0x50 => {
                        if self.booting {
                            self.booting = false;
                            self.irq.request(Interrupt::LoadGame);
                        } else {
                            self.mmap_io.write_u8(a, byte);
                        }
                    }
                    0x4A...0x4B => self.gpu.write_u8(a, byte),
                    0x7F => self.mmap_io.write_u8(a, byte),
                    _ => panic!("write memory mapped I/O in unsupported range: {:04X}", a),
                }
            }
            Address::InterruptEnableRegister(a) => self.irq.enable_flag = byte,
            _ => {
                panic!("Unable to write byte to: {:#X}, invalid memory region.",
                       addr)
            }
        }
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(addr) => self.ram.read_u8(addr),
            Address::RamShadow(addr) => self.ram.read_u8(addr),
            Address::CartRom(addr) => {
                if self.booting {
                    self.boot_rom.read_u8(addr)
                } else {
                    cart.rom.read_u8(addr)
                }
            }
            Address::CartRomOtherBank(addr) => cart.rom.read_u8(addr),
            Address::Gfx(value) => self.gpu.ram.read_u8(value),
            Address::CartRam(a) => cart.ram.read_u8(a),
            Address::ZRam(a) => self.zram.read_u8(a),
            Address::Oam(a) => self.gpu.sprite_data.read_u8(a),
            Address::Unused(_) => 0xFF, // Always return high
            Address::Io(a) => {
                match a {
                    0x00 => self.joypad.data,
                    0x01...0x02 => {
                        // println!("err: read from serial driver not supported");
                        0
                    }
                    0x04...0x07 => self.timer.read_u8(a),
                    0x0F => self.irq.request_flag,
                    0x10...0x26 => {
                        // println!("err: read from sound driver not supported");
                        0
                    }
                    0x30...0x3F => {
                        // println!("err: write to wave pattern RAM not supported");
                        0
                    }
                    0x40...0x45 => self.gpu.read_u8(a),
                    0x47...0x49 => self.gpu.read_u8(a),
                    0x4A...0x4B => self.gpu.read_u8(a),
                    0x7F => self.mmap_io.read_u8(a),
                    n @ _ => panic!("read memory mapped I/O in unsupported range: {:04X}", n),
                }
            }
            Address::InterruptEnableRegister(a) => self.irq.enable_flag,
            _ => panic!("Unable to read address: {:#X}", addr),
        }
    }

    pub fn read_bytes(&self, r: Range<u16>) -> &[u8] {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(r.start) {
            Address::Ram(_) |
            Address::RamShadow(_) => self.ram.read_bytes(r),
            Address::CartRom(_) => {
                if self.booting && r.start < 0xE0 {
                    self.boot_rom.read_bytes(r)
                } else {
                    cart.rom.read_bytes(r)
                }
            }
            Address::CartRomOtherBank(_) => cart.rom.read_bytes(r),
            Address::Gfx(_) => self.gpu.ram.read_bytes(r),
            Address::CartRam(_) => cart.ram.read_bytes(r),
            Address::ZRam(a) => self.zram.read_bytes(r),
            Address::Io(a) => self.mmap_io.read_bytes(r),
            _ => panic!("Unable to read address range: {:?}", r),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(a) => self.ram.write_u16(a, val),
            Address::RamShadow(a) => self.ram.write_u16(a, val),
            Address::ZRam(a) => self.zram.write_u16(a, val),
            _ => panic!("Unable to write address: {:#X}", addr),
        }
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(addr) => self.ram.read_u16(addr),
            Address::RamShadow(addr) => self.ram.read_u16(addr),
            Address::CartRom(addr) => {
                if self.booting {
                    self.boot_rom.read_u16(addr)
                } else {
                    cart.rom.read_u16(addr)
                }
            }
            Address::CartRomOtherBank(addr) => cart.rom.read_u16(addr),
            Address::Gfx(value) => self.gpu.ram.read_u16(value),
            Address::CartRam(a) => cart.ram.read_u16(a),
            Address::ZRam(a) => self.zram.read_u16(a),
            Address::Io(a) => self.mmap_io.read_u16(a),
            _ => panic!("Unable to read address: {:#X}", addr),
        }
    }

    pub fn write_bytes(&mut self, addr: u16, bytes: &[u8]) {
        let cart = self.cart.as_mut().expect("Cartridge is empty");
        match memory_map::map_address(addr) {
            Address::CartRom(addr) => cart.rom.write_bytes(addr, bytes),
            _ => panic!("write_bytes not mapped for specified memory region"),
        }
    }

    fn dma_transfer(&mut self, byte: u8) {
        let addr = (byte as u16) << 0x08; // "The written value specifies the transfer source address divided by 0x100"
        for x in 0..0xA0 {
            let val = self.read_u8(addr + x);
            self.write_u8(0xFE00 + x, val);
        }
    }
}
<|endoftext|>


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

use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
use wayland_backend::{
    client::{Backend, Handle, ObjectData, ObjectId},
    protocol::{AllowNull, ArgumentType, Message},
};

use crate::{ConnectionHandle, DispatchError, Proxy};

pub trait Dispatch<I: Proxy>: Sized {
    type UserData: Send + Sync + 'static;

    fn event(
        &mut self,
        proxy: &I,
        event: I::Event,
        data: &Self::UserData,
        cxhandle: &mut ConnectionHandle,
        qhandle: &QueueHandle<Self>,
        init: &mut DataInit<'_>,
    );
}

type QueueCallback<D> = fn(
    &mut ConnectionHandle<'_>,
    Message<ObjectId>,
    &mut D,
    &QueueHandle<D>,
) -> Result<(), DispatchError>;

struct QueueEvent<D>(QueueCallback<D>, Message<ObjectId>);

#[cfg(not(tarpaulin_include))]
impl<D> std::fmt::Debug for QueueEvent<D> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("QueueEvent").field("msg", &self.1).finish_non_exhaustive()
    }
}

pub struct EventQueue<D> {
    rx: UnboundedReceiver<QueueEvent<D>>,
    handle: QueueHandle<D>,
    backend: Arc<Mutex<Backend>>,
}

#[cfg(not(tarpaulin_include))]
impl<D> std::fmt::Debug for EventQueue<D> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("EventQueue")
            .field("rx", &self.rx)
            .field("handle", &self.handle)
            .finish_non_exhaustive()
    }
}

impl<D> EventQueue<D> {
    pub(crate) fn new(backend: Arc<Mutex<Backend>>) -> Self {
        let (tx, rx) = unbounded();
        EventQueue { rx, handle: QueueHandle { tx }, backend }
    }

    pub fn handle(&self) -> QueueHandle<D> {
        self.handle.clone()
    }

    pub fn dispatch_pending(&mut self, data: &mut D) -> Result<usize, DispatchError> {
        Self::dispatching_impl(&mut self.backend.lock().unwrap(), &mut self.rx, &self.handle, data)
    }

    pub fn blocking_dispatch(&mut self, data: &mut D) -> Result<usize, DispatchError> {
        let mut backend = self.backend.lock().unwrap();
        let dispatched = Self::dispatching_impl(&mut backend, &mut self.rx, &self.handle, data)?;
        if dispatched > 0 {
            Ok(dispatched)
        } else {
            crate::cx::blocking_dispatch_impl(&mut backend)?;
            Self::dispatching_impl(&mut backend, &mut self.rx, &self.handle, data)
        }
    }

    fn dispatching_impl(
        backend: &mut Backend,
        rx: &mut UnboundedReceiver<QueueEvent<D>>,
        qhandle: &QueueHandle<D>,
        data: &mut D,
    ) -> Result<usize, DispatchError> {
        let mut handle = ConnectionHandle::from_handle(backend.handle());
        let mut dispatched = 0;

        while let Ok(Some(QueueEvent(cb, msg))) = rx.try_next() {
            cb(&mut handle, msg, data, qhandle)?;
            dispatched += 1;
        }
        Ok(dispatched)
    }
}

pub struct QueueHandle<D> {
    tx: UnboundedSender<QueueEvent<D>>,
}

#[cfg(not(tarpaulin_include))]
impl<Data> std::fmt::Debug for QueueHandle<Data> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("QueueHandle").field("tx", &self.tx).finish()
    }
}

impl<Data> Clone for QueueHandle<Data> {
    fn clone(&self) -> Self {
        QueueHandle { tx: self.tx.clone() }
    }
}

pub(crate) struct QueueSender<D> {
    func: QueueCallback<D>,
    pub(crate) handle: QueueHandle<D>,
}

pub(crate) trait ErasedQueueSender<I> {
    fn send(&self, msg: Message<ObjectId>);
}

impl<I: Proxy, D> ErasedQueueSender<I> for QueueSender<D>
where
    D: Dispatch<I>,
{
    fn send(&self, msg: Message<ObjectId>) {
        if self.handle.tx.unbounded_send(QueueEvent(self.func, msg)).is_err() {
            log::error!("Event received for EventQueue after it was dropped.");
        }
    }
}

impl<D: 'static> QueueHandle<D> {
    pub fn make_data<I: Proxy + 'static>(
        &self,
        user_data: <D as Dispatch<I>>::UserData,
    ) -> Arc<dyn ObjectData>
    where
        D: Dispatch<I>,
    {
        let sender = Box::new(QueueSender { func: queue_callback::<I, D>, handle: self.clone() });
        Arc::new(QueueProxyData { sender, udata: user_data })
    }
}

#[derive(Debug)]
pub struct New<I> {
    id: I,
}

impl<I> New<I> {
    pub fn wrap(id: I) -> New<I> {
        New { id }
    }
}

#[derive(Debug)]
pub struct DataInit<'a> {
    store: &'a mut Option<(ObjectId, Arc<dyn ObjectData>)>,
}

impl<'a> DataInit<'a> {
    pub fn init<I: Proxy + 'static, D>(
        &mut self,
        resource: New<I>,
        data: <D as Dispatch<I>>::UserData,
        qhandle: &QueueHandle<D>,
    ) -> I
    where
        D: Dispatch<I> + 'static,
    {
        *self.store = Some((resource.id.id(), qhandle.make_data(data)));
        resource.id
    }
}

fn queue_callback<I: Proxy, D: Dispatch<I> + 'static>(
    handle: &mut ConnectionHandle<'_>,
    msg: Message<ObjectId>,
    data: &mut D,
    qhandle: &QueueHandle<D>,
) -> Result<(), DispatchError> {
    let (proxy, event) = I::parse_event(handle, msg)?;
    let udata =
        proxy.data::<<D as Dispatch<I>>::UserData>().expect("Wrong user_data value for object");
    let mut new_data = None;
    data.event(&proxy, event, udata, handle, qhandle, &mut DataInit { store: &mut new_data });
    if let Some((id, data)) = new_data {
        handle.inner.handle().set_data(id, data).unwrap();
    }
    Ok(())
}

pub struct QueueProxyData<I: Proxy, U> {
    pub(crate) sender: Box<dyn ErasedQueueSender<I> + Send + Sync>,
    pub udata: U,
}

impl<I: Proxy + 'static, U: Send + Sync + 'static> ObjectData for QueueProxyData<I, U> {
    fn event(
        self: Arc<Self>,
        _: &mut Handle,
        msg: Message<ObjectId>,
    ) -> Option<Arc<dyn ObjectData>> {
        let ret = if msg.args.iter().any(|a| a.get_type() == ArgumentType::NewId(AllowNull::No)) {
            Some(Arc::new(TemporaryData) as Arc<dyn ObjectData>)
        } else {
            None
        };
        self.sender.send(msg);
        ret
    }

    fn destroyed(&self, _: ObjectId) {}
}

#[cfg(not(tarpaulin_include))]
impl<I: Proxy, U: std::fmt::Debug> std::fmt::Debug for QueueProxyData<I, U> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("QueueProxyData").field("udata", &self.udata).finish()
    }
}

struct TemporaryData;

impl ObjectData for TemporaryData {
    fn event(self: Arc<Self>, _: &mut Handle, _: Message<ObjectId>) -> Option<Arc<dyn ObjectData>> {
        unreachable!()
    }

    fn destroyed(&self, _: ObjectId) {}
}

/*
 * Dispatch delegation helpers
 */

pub trait DelegateDispatchBase<I: Proxy> {
    type UserData: Send + Sync + 'static;
}

pub trait DelegateDispatch<
    I: Proxy,
    D: Dispatch<I, UserData = <Self as DelegateDispatchBase<I>>::UserData>,
>: Sized + DelegateDispatchBase<I>
{
    fn event(
        &mut self,
        proxy: &I,
        event: I::Event,
        data: &Self::UserData,
        cxhandle: &mut ConnectionHandle,
        qhandle: &QueueHandle<D>,
        init: &mut DataInit<'_>,
    );
}

#[macro_export]
macro_rules! delegate_dispatch {
    ($dispatch_from:ty => $dispatch_to:ty ; [$($interface:ty),*] => $convert:ident) => {
        $(
            impl $crate::Dispatch<$interface> for $dispatch_from {
                type UserData = <$dispatch_to as $crate::DelegateDispatchBase<$interface>>::UserData;

                fn event(
                    &mut self,
                    proxy: &$interface,
                    event: <$interface as $crate::Proxy>::Event,
                    data: &Self::UserData,
                    cxhandle: &mut $crate::ConnectionHandle,
                    qhandle: &$crate::QueueHandle<Self>,
                    init: &mut $crate::DataInit<'_>,
                ) {
                    <$dispatch_to as $crate::DelegateDispatch<$interface, Self>>::event(&mut self.$convert(), proxy, event, data, cxhandle, qhandle, init)
                }
            }
        )*
    }
}
<commit_msg>client: enhance delegate_dispatch macro and document the delegate traits.<commit_after>use std::sync::{Arc, Mutex};

use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
use wayland_backend::{
    client::{Backend, Handle, ObjectData, ObjectId},
    protocol::{AllowNull, ArgumentType, Message},
};

use crate::{ConnectionHandle, DispatchError, Proxy};

pub trait Dispatch<I: Proxy>: Sized {
    type UserData: Send + Sync + 'static;

    fn event(
        &mut self,
        proxy: &I,
        event: I::Event,
        data: &Self::UserData,
        cxhandle: &mut ConnectionHandle,
        qhandle: &QueueHandle<Self>,
        init: &mut DataInit<'_>,
    );
}

type QueueCallback<D> = fn(
    &mut ConnectionHandle<'_>,
    Message<ObjectId>,
    &mut D,
    &QueueHandle<D>,
) -> Result<(), DispatchError>;

struct QueueEvent<D>(QueueCallback<D>, Message<ObjectId>);

#[cfg(not(tarpaulin_include))]
impl<D> std::fmt::Debug for QueueEvent<D> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("QueueEvent").field("msg", &self.1).finish_non_exhaustive()
    }
}

pub struct EventQueue<D> {
    rx: UnboundedReceiver<QueueEvent<D>>,
    handle: QueueHandle<D>,
    backend: Arc<Mutex<Backend>>,
}

#[cfg(not(tarpaulin_include))]
impl<D> std::fmt::Debug for EventQueue<D> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("EventQueue")
            .field("rx", &self.rx)
            .field("handle", &self.handle)
            .finish_non_exhaustive()
    }
}

impl<D> EventQueue<D> {
    pub(crate) fn new(backend: Arc<Mutex<Backend>>) -> Self {
        let (tx, rx) = unbounded();
        EventQueue { rx, handle: QueueHandle { tx }, backend }
    }

    pub fn handle(&self) -> QueueHandle<D> {
        self.handle.clone()
    }

    pub fn dispatch_pending(&mut self, data: &mut D) -> Result<usize, DispatchError> {
        Self::dispatching_impl(&mut self.backend.lock().unwrap(), &mut self.rx, &self.handle, data)
    }

    pub fn blocking_dispatch(&mut self, data: &mut D) -> Result<usize, DispatchError> {
        let mut backend = self.backend.lock().unwrap();
        let dispatched = Self::dispatching_impl(&mut backend, &mut self.rx, &self.handle, data)?;
        if dispatched > 0 {
            Ok(dispatched)
        } else {
            crate::cx::blocking_dispatch_impl(&mut backend)?;
            Self::dispatching_impl(&mut backend, &mut self.rx, &self.handle, data)
        }
    }

    fn dispatching_impl(
        backend: &mut Backend,
        rx: &mut UnboundedReceiver<QueueEvent<D>>,
        qhandle: &QueueHandle<D>,
        data: &mut D,
    ) -> Result<usize, DispatchError> {
        let mut handle = ConnectionHandle::from_handle(backend.handle());
        let mut dispatched = 0;

        while let Ok(Some(QueueEvent(cb, msg))) = rx.try_next() {
            cb(&mut handle, msg, data, qhandle)?;
            dispatched += 1;
        }
        Ok(dispatched)
    }
}

pub struct QueueHandle<D> {
    tx: UnboundedSender<QueueEvent<D>>,
}

#[cfg(not(tarpaulin_include))]
impl<Data> std::fmt::Debug for QueueHandle<Data> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("QueueHandle").field("tx", &self.tx).finish()
    }
}

impl<Data> Clone for QueueHandle<Data> {
    fn clone(&self) -> Self {
        QueueHandle { tx: self.tx.clone() }
    }
}

pub(crate) struct QueueSender<D> {
    func: QueueCallback<D>,
    pub(crate) handle: QueueHandle<D>,
}

pub(crate) trait ErasedQueueSender<I> {
    fn send(&self, msg: Message<ObjectId>);
}

impl<I: Proxy, D> ErasedQueueSender<I> for QueueSender<D>
where
    D: Dispatch<I>,
{
    fn send(&self, msg: Message<ObjectId>) {
        if self.handle.tx.unbounded_send(QueueEvent(self.func, msg)).is_err() {
            log::error!("Event received for EventQueue after it was dropped.");
        }
    }
}

impl<D: 'static> QueueHandle<D> {
    pub fn make_data<I: Proxy + 'static>(
        &self,
        user_data: <D as Dispatch<I>>::UserData,
    ) -> Arc<dyn ObjectData>
    where
        D: Dispatch<I>,
    {
        let sender = Box::new(QueueSender { func: queue_callback::<I, D>, handle: self.clone() });
        Arc::new(QueueProxyData { sender, udata: user_data })
    }
}

#[derive(Debug)]
pub struct New<I> {
    id: I,
}

impl<I> New<I> {
    pub fn wrap(id: I) -> New<I> {
        New { id }
    }
}

#[derive(Debug)]
pub struct DataInit<'a> {
    store: &'a mut Option<(ObjectId, Arc<dyn ObjectData>)>,
}

impl<'a> DataInit<'a> {
    pub fn init<I: Proxy + 'static, D>(
        &mut self,
        resource: New<I>,
        data: <D as Dispatch<I>>::UserData,
        qhandle: &QueueHandle<D>,
    ) -> I
    where
        D: Dispatch<I> + 'static,
    {
        *self.store = Some((resource.id.id(), qhandle.make_data(data)));
        resource.id
    }
}

fn queue_callback<I: Proxy, D: Dispatch<I> + 'static>(
    handle: &mut ConnectionHandle<'_>,
    msg: Message<ObjectId>,
    data: &mut D,
    qhandle: &QueueHandle<D>,
) -> Result<(), DispatchError> {
    let (proxy, event) = I::parse_event(handle, msg)?;
    let udata =
        proxy.data::<<D as Dispatch<I>>::UserData>().expect("Wrong user_data value for object");
    let mut new_data = None;
    data.event(&proxy, event, udata, handle, qhandle, &mut DataInit { store: &mut new_data });
    if let Some((id, data)) = new_data {
        handle.inner.handle().set_data(id, data).unwrap();
    }
    Ok(())
}

pub struct QueueProxyData<I: Proxy, U> {
    pub(crate) sender: Box<dyn ErasedQueueSender<I> + Send + Sync>,
    pub udata: U,
}

impl<I: Proxy + 'static, U: Send + Sync + 'static> ObjectData for QueueProxyData<I, U> {
    fn event(
        self: Arc<Self>,
        _: &mut Handle,
        msg: Message<ObjectId>,
    ) -> Option<Arc<dyn ObjectData>> {
        let ret = if msg.args.iter().any(|a| a.get_type() == ArgumentType::NewId(AllowNull::No)) {
            Some(Arc::new(TemporaryData) as Arc<dyn ObjectData>)
        } else {
            None
        };
        self.sender.send(msg);
        ret
    }

    fn destroyed(&self, _: ObjectId) {}
}

#[cfg(not(tarpaulin_include))]
impl<I: Proxy, U: std::fmt::Debug> std::fmt::Debug for QueueProxyData<I, U> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("QueueProxyData").field("udata", &self.udata).finish()
    }
}

struct TemporaryData;

impl ObjectData for TemporaryData {
    fn event(self: Arc<Self>, _: &mut Handle, _: Message<ObjectId>) -> Option<Arc<dyn ObjectData>> {
        unreachable!()
    }

    fn destroyed(&self, _: ObjectId) {}
}

/*
 * Dispatch delegation helpers
 */

/// The base trait used to define a delegate type to handle some type of proxy.
pub trait DelegateDispatchBase<I: Proxy> {
    /// The type of user data the delegate holds
    type UserData: Send + Sync + 'static;
}

/// A trait which defines a delegate type to handle some type of proxy.
///
/// This trait is useful for building composable handlers of proxies.
///
/// ## Usage
///
/// To explain the trait, let's implement a delegate for handling the events from [`WlRegistry`](crate::protocol::wl_registry::WlRegistry).
///
/// ```
/// # // Maintainers: If this example changes, please make sure you also carry those changes over to the delegate_dispatch macro.
/// use wayland_client::{protocol::wl_registry, DelegateDispatch, DelegateDispatchBase, Dispatch};
///
/// /// The type we want to delegate to
/// struct DelegateToMe;
///
/// // Now implement DelegateDispatchBase.
/// impl DelegateDispatchBase<wl_registry::WlRegistry> for DelegateToMe {
///     /// The type of user data associated with the delegation of events from a registry is defined here.
///     ///
///     /// If you don't need user data, the unit type, `()`, may be used.
///     type UserData = ();
/// }
///
/// // Now implement DelegateDispatch.
/// impl<D> DelegateDispatch<wl_registry::WlRegistry, D> for DelegateToMe
/// where
///     // `D` is the type which has delegated to this type.
///     D: Dispatch<wl_registry::WlRegistry, UserData = Self::UserData>,
/// {
///     fn event(
///         &mut self,
///         _proxy: &wl_registry::WlRegistry,
///         _event: wl_registry::Event,
///         _data: &Self::UserData,
///         _cxhandle: &mut wayland_client::ConnectionHandle,
///         _qhandle: &wayland_client::QueueHandle<D>,
///         _init: &mut wayland_client::DataInit<'_>,
///     ) {
///         // Here the delegate may handle incoming events as it pleases.
///     }
/// }
/// ```
pub trait DelegateDispatch<
    I: Proxy,
    D: Dispatch<I, UserData = <Self as DelegateDispatchBase<I>>::UserData>,
>: Sized + DelegateDispatchBase<I>
{
    fn event(
        &mut self,
        proxy: &I,
        event: I::Event,
        data: &Self::UserData,
        cxhandle: &mut ConnectionHandle,
        qhandle: &QueueHandle<D>,
        init: &mut DataInit<'_>,
    );
}

/// A helper macro which delegates a set of [`Dispatch`] implementations for a proxy to some other type which
/// implements [`DelegateDispatch`] for each proxy.
///
/// This macro allows more easily delegating smaller parts of the protocol an application may wish to handle
/// in a modular fashion.
///
/// # Usage
///
/// For example, say you want to delegate events for [`WlRegistry`](crate::protocol::wl_registry::WlRegistry)
/// to some other type.
///
/// For brevity, we will use the example in the documentation for [`DelegateDispatch`], `DelegateToMe`.
///
/// ```
/// use wayland_client::{delegate_dispatch, protocol::wl_registry};
/// #
/// # use wayland_client::{DelegateDispatch, DelegateDispatchBase, Dispatch};
/// #
/// # struct DelegateToMe;
/// #
/// # impl DelegateDispatchBase<wl_registry::WlRegistry> for DelegateToMe {
/// #     type UserData = ();
/// # }
/// #
/// # impl<D> DelegateDispatch<wl_registry::WlRegistry, D> for DelegateToMe
/// # where
/// #     D: Dispatch<wl_registry::WlRegistry, UserData = Self::UserData>,
/// # {
/// #     fn event(
/// #         &mut self,
/// #         _proxy: &wl_registry::WlRegistry,
/// #         _event: wl_registry::Event,
/// #         _data: &Self::UserData,
/// #         _cxhandle: &mut wayland_client::ConnectionHandle,
/// #         _qhandle: &wayland_client::QueueHandle<D>,
/// #         _init: &mut wayland_client::DataInit<'_>,
/// #     ) {
/// #     }
/// # }
///
/// // ExampleApp is the type events will be dispatched to.
///
/// /// The application state
/// struct ExampleApp {
///     /// The delegate for handling wl_registry events.
///     delegate: DelegateToMe,
/// }
///
/// // Use delegate_dispatch to implement Dispatch<wl_registry::WlRegistry> for ExampleApp.
/// delegate_dispatch!(ExampleApp: [wl_registry::WlRegistry] => DelegateToMe ; |app| {
///     // Return an `&mut` reference to the field the Dispatch implementation provided by the macro should
///     // forward events to.
///     // You may also use a function to get the delegate since this is like a closure.
///     &mut app.delegate
/// });
///
/// // To explain the macro above, you may read it as the following:
/// //
/// // For ExampleApp, delegate WlRegistry to DelegateToMe and use the closure to get an `&mut` reference to
/// // the delegate.
///
/// // Assert ExampleApp can Dispatch events for wl_registry
/// fn assert_is_registry_delegate<T>()
/// where
///     T: Dispatch<wl_registry::WlRegistry, UserData = ()>,
/// {
/// }
///
/// assert_is_registry_delegate::<ExampleApp>();
/// ```
///
/// You may also delegate multiple proxies to a single type. This is especially useful for handling multiple
/// related protocols in the same modular component.
///
/// For example, a type which can dispatch both the `wl_output` and `xdg_output` protocols may be used as a
/// delegate:
///
/// ```ignore
/// # // This is not tested because xdg_output is in wayland-protocols.
/// delegate_dispatch!(ExampleApp: [wl_output::WlOutput, xdg_output::XdgOutput] => OutputDelegate ; |app| {
///     &mut app.output_delegate
/// });
/// ```
///
/// If your delegate contains a lifetime, you will need to explicitly declare the user data type and
/// use the anonymous lifetime.
///
/// ```
/// use std::marker::PhantomData;
///
/// use wayland_client::{delegate_dispatch, DelegateDispatch, DelegateDispatchBase, Dispatch, protocol::wl_registry};
///
/// struct ExampleApp;
///
/// struct DelegateWithLifetime<'a>(PhantomData<&'a mut ()>);
///
/// // ... DelegateDispatch impl here...
/// # impl DelegateDispatchBase<wl_registry::WlRegistry> for DelegateWithLifetime<'_> {
/// #     type UserData = ();
/// # }
/// # impl<D> DelegateDispatch<wl_registry::WlRegistry, D> for DelegateWithLifetime<'_>
/// # where
/// #     D: Dispatch<wl_registry::WlRegistry, UserData = Self::UserData>,
/// # {
/// #     fn event(
/// #         &mut self,
/// #         _proxy: &wl_registry::WlRegistry,
/// #         _event: wl_registry::Event,
/// #         _data: &Self::UserData,
/// #         _cxhandle: &mut wayland_client::ConnectionHandle,
/// #         _qhandle: &wayland_client::QueueHandle<D>,
/// #         _init: &mut wayland_client::DataInit<'_>,
/// #     ) {
/// #     }
/// # }
///
/// delegate_dispatch!(ExampleApp: <UserData = ()> [wl_registry::WlRegistry] => DelegateWithLifetime<'_> ; |_app| {
///     &mut DelegateWithLifetime(PhantomData)
/// });
/// ```
#[macro_export]
macro_rules! delegate_dispatch {
    ($dispatch_from: ty: [$($interface: ty),*] => $dispatch_to: ty ; |$dispatcher: ident| $closure: block) => {
        $(
            impl $crate::Dispatch<$interface> for $dispatch_from {
                type UserData = <$dispatch_to as $crate::DelegateDispatchBase<$interface>>::UserData;

                fn event(
                    &mut self,
                    proxy: &$interface,
                    event: <$interface as $crate::Proxy>::Event,
                    data: &Self::UserData,
                    cxhandle: &mut $crate::ConnectionHandle,
                    qhandle: &$crate::QueueHandle<Self>,
                    init: &mut $crate::DataInit<'_>,
                ) {
                    let $dispatcher = self; // We need to do this so the closure can see the dispatcher field.
                    let delegate: &mut $dispatch_to = { $closure };
                    $crate::DelegateDispatch::<$interface, _>::event(delegate, proxy, event, data, cxhandle, qhandle, init)
                }
            }
        )*
    };

    // Explicitly specify the UserData if there is a lifetime.
    ($dispatch_from: ty: <UserData = $user_data: ty> [$($interface: ty),*] => $dispatch_to: ty ; |$dispatcher: ident| $closure: block) => {
        $(
            impl $crate::Dispatch<$interface> for $dispatch_from {
                type UserData = $user_data;

                fn event(
                    &mut self,
                    proxy: &$interface,
                    event: <$interface as $crate::Proxy>::Event,
                    data: &Self::UserData,
                    cxhandle: &mut $crate::ConnectionHandle,
                    qhandle: &$crate::QueueHandle<Self>,
                    init: &mut $crate::DataInit<'_>,
                ) {
                    let $dispatcher = self; // We need to do this so the closure can see the dispatcher field.
                    let delegate: &mut $dispatch_to = { $closure };
                    $crate::DelegateDispatch::<$interface, _>::event(delegate, proxy, event, data, cxhandle, qhandle, init)
                }
            }
        )*
    };
}
<|endoftext|>


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

use io;
use libc::{self, c_int};
use mem;
use sys::{cvt, cvt_r};
use sys::fd::FileDesc;

////////////////////////////////////////////////////////////////////////////////
// Anonymous pipes
////////////////////////////////////////////////////////////////////////////////

pub struct AnonPipe(FileDesc);

pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
    let mut fds = [0; 2];

    // Unfortunately the only known way right now to create atomically set the
    // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
    // 2.6.27, however, and because we support 2.6.18 we must detect this
    // support dynamically.
    if cfg!(any(target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "linux",
                target_os = "netbsd",
                target_os = "openbsd"))
    {
        weak! { fn pipe2(*mut c_int, c_int) -> c_int }
        if let Some(pipe) = pipe2.get() {
            cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) })?;
            return Ok((AnonPipe(FileDesc::new(fds[0])),
                       AnonPipe(FileDesc::new(fds[1]))));
        }
    }
    cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;

    let fd0 = FileDesc::new(fds[0]);
    let fd1 = FileDesc::new(fds[1]);
    fd0.set_cloexec()?;
    fd1.set_cloexec()?;
    Ok((AnonPipe(fd0), AnonPipe(fd1)))
}

impl AnonPipe {
    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        self.0.read_to_end(buf)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    pub fn fd(&self) -> &FileDesc { &self.0 }
    pub fn into_fd(self) -> FileDesc { self.0 }
}

pub fn read2(p1: AnonPipe,
             v1: &mut Vec<u8>,
             p2: AnonPipe,
             v2: &mut Vec<u8>) -> io::Result<()> {

    // Set both pipes into nonblocking mode as we're gonna be reading from both
    // in the `select` loop below, and we wouldn't want one to block the other!
    let p1 = p1.into_fd();
    let p2 = p2.into_fd();
    p1.set_nonblocking(true)?;
    p2.set_nonblocking(true)?;

    let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
    fds[0].fd = p1.raw();
    fds[0].events = libc::POLLIN;
    fds[1].fd = p2.raw();
    fds[1].events = libc::POLLIN;
    loop {
        // wait for either pipe to become readable using `poll`
        cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;

        // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
        // EAGAIN. If we hit EOF, then this will happen because the underlying
        // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
        // this case we flip the other fd back into blocking mode and read
        // whatever's leftover on that file descriptor.
        let read = |fd: &FileDesc, dst: &mut Vec<u8>| {
            match fd.read_to_end(dst) {
                Ok(_) => Ok(true),
                Err(e) => {
                    if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
                       e.raw_os_error() == Some(libc::EAGAIN) {
                        Ok(false)
                    } else {
                        Err(e)
                    }
                }
            }
        };
        if fds[0].revents != 0 && read(&p1, v1)? {
            p2.set_nonblocking(false)?;
            return p2.read_to_end(v2).map(|_| ());
        }
        if fds[1].revents != 0 && read(&p2, v2)? {
            p1.set_nonblocking(false)?;
            return p1.read_to_end(v1).map(|_| ());
        }
    }
}
<commit_msg>Auto merge of #42521 - alexcrichton:enosys, r=cuviper<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use io;
use libc::{self, c_int};
use mem;
use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
use sys::fd::FileDesc;
use sys::{cvt, cvt_r};

////////////////////////////////////////////////////////////////////////////////
// Anonymous pipes
////////////////////////////////////////////////////////////////////////////////

pub struct AnonPipe(FileDesc);

pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
    weak! { fn pipe2(*mut c_int, c_int) -> c_int }
    static INVALID: AtomicBool = ATOMIC_BOOL_INIT;

    let mut fds = [0; 2];

    // Unfortunately the only known way right now to create atomically set the
    // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
    // 2.6.27, however, and because we support 2.6.18 we must detect this
    // support dynamically.
    if cfg!(any(target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "linux",
                target_os = "netbsd",
                target_os = "openbsd")) &&
       !INVALID.load(Ordering::SeqCst)
    {

        if let Some(pipe) = pipe2.get() {
            // Note that despite calling a glibc function here we may still
            // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
            // emulate on older kernels, so if you happen to be running on
            // an older kernel you may see `pipe2` as a symbol but still not
            // see the syscall.
            match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
                Ok(_) => {
                    return Ok((AnonPipe(FileDesc::new(fds[0])),
                               AnonPipe(FileDesc::new(fds[1]))));
                }
                Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
                    INVALID.store(true, Ordering::SeqCst);
                }
                Err(e) => return Err(e),
            }
        }
    }
    cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;

    let fd0 = FileDesc::new(fds[0]);
    let fd1 = FileDesc::new(fds[1]);
    fd0.set_cloexec()?;
    fd1.set_cloexec()?;
    Ok((AnonPipe(fd0), AnonPipe(fd1)))
}

impl AnonPipe {
    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        self.0.read_to_end(buf)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    pub fn fd(&self) -> &FileDesc { &self.0 }
    pub fn into_fd(self) -> FileDesc { self.0 }
}

pub fn read2(p1: AnonPipe,
             v1: &mut Vec<u8>,
             p2: AnonPipe,
             v2: &mut Vec<u8>) -> io::Result<()> {

    // Set both pipes into nonblocking mode as we're gonna be reading from both
    // in the `select` loop below, and we wouldn't want one to block the other!
    let p1 = p1.into_fd();
    let p2 = p2.into_fd();
    p1.set_nonblocking(true)?;
    p2.set_nonblocking(true)?;

    let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
    fds[0].fd = p1.raw();
    fds[0].events = libc::POLLIN;
    fds[1].fd = p2.raw();
    fds[1].events = libc::POLLIN;
    loop {
        // wait for either pipe to become readable using `poll`
        cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;

        // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
        // EAGAIN. If we hit EOF, then this will happen because the underlying
        // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
        // this case we flip the other fd back into blocking mode and read
        // whatever's leftover on that file descriptor.
        let read = |fd: &FileDesc, dst: &mut Vec<u8>| {
            match fd.read_to_end(dst) {
                Ok(_) => Ok(true),
                Err(e) => {
                    if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
                       e.raw_os_error() == Some(libc::EAGAIN) {
                        Ok(false)
                    } else {
                        Err(e)
                    }
                }
            }
        };
        if fds[0].revents != 0 && read(&p1, v1)? {
            p2.set_nonblocking(false)?;
            return p2.read_to_end(v2).map(|_| ());
        }
        if fds[1].revents != 0 && read(&p2, v2)? {
            p1.set_nonblocking(false)?;
            return p1.read_to_end(v1).map(|_| ());
        }
    }
}
<|endoftext|>


<commit_before>use pitch;
use super::waveform::{self, Waveform};

/// Types that produce a warped frequency in hz for some given frequency in hz.
pub trait FreqWarp {
    /// Step the phase of the frequency warp if necessary.
    fn step_phase(&self, _sample_hz: f64, _freq_warp_phase: &mut f64) {}
    /// Return a warped hz given some hz, sample rate and phase.
    fn warp_hz(&self, hz: f64, freq_warp_phase: f64) -> f64;
}

/// A type for warping the frequency via gaussian randomness.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Gaussian(pub f32);

/// A type for slowly drifting an oscillators pitch via a noise walk.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PitchDrift {
    /// The frequncy at which the pitch should drift.
    pub hz: f64,
    /// How much the pitch should drift in steps.
    pub amp: f32,
}

/// A type that allows switching between various kinds of FreqWarp at runtime.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Dynamic {
    None,
    Gaussian(Gaussian),
    PitchDrift(PitchDrift),
}

impl Dynamic {
    /// Construct a gaussian.
    pub fn gaussian(amt: f32) -> Dynamic {
        Dynamic::Gaussian(Gaussian(amt))
    }
    /// Construct a pitch drift.
    pub fn pitch_drift(amp: f32, hz: f64) -> Dynamic {
        Dynamic::PitchDrift(PitchDrift { amp: amp, hz: hz })
    }
}

impl FreqWarp for () {
    #[inline]
    fn warp_hz(&self, hz: f64, _freq_warp_phase: f64) -> f64 { hz }
}

impl FreqWarp for Gaussian {
    #[inline]
    fn warp_hz(&self, hz: f64, _freq_warp_phase: f64) -> f64 {
        let Gaussian(perc) = *self;
        if perc > 0.0 {
            use gaussian;
            let mels = pitch::Hz(hz as f32).mel();
            let gaus_mels = mels + gaussian::gen(0.5f32, perc.powf(2.0)) * 1000.0 - 500.0;
            pitch::Mel(gaus_mels).hz() as f64
        } else {
            hz
        }
    }
}

impl FreqWarp for PitchDrift {
    #[inline]
    fn step_phase(&self, sample_hz: f64, freq_warp_phase: &mut f64) {
        *freq_warp_phase = *freq_warp_phase + self.hz / sample_hz;
    }
    #[inline]
    fn warp_hz(&self, hz: f64, freq_warp_phase: f64) -> f64 {
        let offset_in_steps = waveform::NoiseWalk.amp_at_phase(freq_warp_phase) * self.amp;
        let warped_hz = pitch::Step(pitch::Hz(hz as f32).step() + offset_in_steps).hz() as f64;
        warped_hz
    }
}

impl FreqWarp for Dynamic {
    #[inline]
    fn step_phase(&self, sample_hz: f64, freq_warp_phase: &mut f64) {
        match *self {
            Dynamic::None                        |
            Dynamic::Gaussian(_)                 => (),
            Dynamic::PitchDrift(ref pitch_drift) => pitch_drift.step_phase(sample_hz, freq_warp_phase),
        }
    }
    #[inline]
    fn warp_hz(&self, hz: f64, freq_warp_phase: f64) -> f64 {
        match *self {
            Dynamic::None                        => hz,
            Dynamic::Gaussian(ref gaussian)      => gaussian.warp_hz(hz, freq_warp_phase),
            Dynamic::PitchDrift(ref pitch_drift) => pitch_drift.warp_hz(hz, freq_warp_phase),
        }
    }
}

<commit_msg>Fix match expr code formatting.<commit_after>use pitch;
use super::waveform::{self, Waveform};

/// Types that produce a warped frequency in hz for some given frequency in hz.
pub trait FreqWarp {
    /// Step the phase of the frequency warp if necessary.
    fn step_phase(&self, _sample_hz: f64, _freq_warp_phase: &mut f64) {}
    /// Return a warped hz given some hz, sample rate and phase.
    fn warp_hz(&self, hz: f64, freq_warp_phase: f64) -> f64;
}

/// A type for warping the frequency via gaussian randomness.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Gaussian(pub f32);

/// A type for slowly drifting an oscillators pitch via a noise walk.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PitchDrift {
    /// The frequncy at which the pitch should drift.
    pub hz: f64,
    /// How much the pitch should drift in steps.
    pub amp: f32,
}

/// A type that allows switching between various kinds of FreqWarp at runtime.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Dynamic {
    None,
    Gaussian(Gaussian),
    PitchDrift(PitchDrift),
}

impl Dynamic {
    /// Construct a gaussian.
    pub fn gaussian(amt: f32) -> Dynamic {
        Dynamic::Gaussian(Gaussian(amt))
    }
    /// Construct a pitch drift.
    pub fn pitch_drift(amp: f32, hz: f64) -> Dynamic {
        Dynamic::PitchDrift(PitchDrift { amp: amp, hz: hz })
    }
}

impl FreqWarp for () {
    #[inline]
    fn warp_hz(&self, hz: f64, _freq_warp_phase: f64) -> f64 { hz }
}

impl FreqWarp for Gaussian {
    #[inline]
    fn warp_hz(&self, hz: f64, _freq_warp_phase: f64) -> f64 {
        let Gaussian(perc) = *self;
        if perc > 0.0 {
            use gaussian;
            let mels = pitch::Hz(hz as f32).mel();
            let gaus_mels = mels + gaussian::gen(0.5f32, perc.powf(2.0)) * 1000.0 - 500.0;
            pitch::Mel(gaus_mels).hz() as f64
        } else {
            hz
        }
    }
}

impl FreqWarp for PitchDrift {
    #[inline]
    fn step_phase(&self, sample_hz: f64, freq_warp_phase: &mut f64) {
        *freq_warp_phase = *freq_warp_phase + self.hz / sample_hz;
    }
    #[inline]
    fn warp_hz(&self, hz: f64, freq_warp_phase: f64) -> f64 {
        let offset_in_steps = waveform::NoiseWalk.amp_at_phase(freq_warp_phase) * self.amp;
        let warped_hz = pitch::Step(pitch::Hz(hz as f32).step() + offset_in_steps).hz() as f64;
        warped_hz
    }
}

impl FreqWarp for Dynamic {
    #[inline]
    fn step_phase(&self, sample_hz: f64, freq_warp_phase: &mut f64) {
        match *self {
            Dynamic::None | Dynamic::Gaussian(_) => (),
            Dynamic::PitchDrift(ref pitch_drift) => pitch_drift.step_phase(sample_hz, freq_warp_phase),
        }
    }
    #[inline]
    fn warp_hz(&self, hz: f64, freq_warp_phase: f64) -> f64 {
        match *self {
            Dynamic::None => hz,
            Dynamic::Gaussian(ref gaussian) => gaussian.warp_hz(hz, freq_warp_phase),
            Dynamic::PitchDrift(ref pitch_drift) => pitch_drift.warp_hz(hz, freq_warp_phase),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

use heck::CamelCase;
use serde_generate::{
    csharp, test_utils,
    test_utils::{Choice, Runtime, Test},
    CodeGeneratorConfig, SourceInstaller,
};
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::Mutex;

lazy_static::lazy_static! {
    // `dotnet build` spuriously fails on linux if run concurrently
    static ref MUTEX: Mutex<()> = Mutex::new(());
}

/// Returns:
/// 1. A `PathBuf` to the directory to write test data into
/// 2. Optionally, a `tempfile::TempDir` which deletes the directory when it goes out of scope
fn create_test_dir(test_name: &'static str) -> (PathBuf, Option<tempfile::TempDir>) {
    // Set env var to generate into subdirectories for inspection
    if std::env::var("TEST_USE_SUBDIR").is_ok() {
        let mut tries = 0;
        while tries < 20 {
            let test_dir_name = if tries == 0 {
                test_name.into()
            } else {
                format!("{}_{}", test_name, tries)
            };
            let dir = Path::new("tests").join(test_dir_name).to_path_buf();
            match std::fs::create_dir(&dir) {
                Ok(()) => return (dir, None),
                Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => tries += 1,
                Err(e) => panic!("Error creating test directory: {:?}", e),
            }
        }
        panic!("Error creating test directory: Too many existing test directories");
    } else {
        let tempdir = tempfile::Builder::new()
            .suffix(&format!("_{}", test_name))
            .tempdir()
            .unwrap();
        (tempdir.path().to_path_buf(), Some(tempdir))
    }
}

fn dotnet_build(proj_dir: &Path) {
    let _lock = MUTEX.lock();
    let status = Command::new("dotnet")
        .arg("build")
        .current_dir(proj_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

fn run_nunit(proj_dir: &Path) {
    let _lock = MUTEX.lock();
    let status = Command::new("dotnet")
        .arg("test")
        .current_dir(proj_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

fn copy_test_project(root_dir: &Path, copy_runtime_tests: bool) -> PathBuf {
    let test_dir = root_dir.join("Serde.Tests").to_path_buf();

    std::fs::create_dir(&test_dir).unwrap();
    std::fs::copy(
        "runtime/csharp/Serde.Tests/Serde.Tests.csproj",
        &test_dir.join("Serde.Tests.csproj"),
    )
    .unwrap();

    if copy_runtime_tests {
        std::fs::copy(
            "runtime/csharp/Serde.Tests/TestLcs.cs",
            &test_dir.join("TestLcs.cs"),
        )
        .unwrap();
    }

    test_dir
}

#[test]
fn test_csharp_lcs_runtime_tests() {
    let (dir, _tmp) = create_test_dir("test_csharp_lcs_runtime_tests");
    let test_dir = copy_test_project(&dir, true);

    let installer = csharp::Installer::new(dir);
    installer.install_serde_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}

#[test]
fn test_csharp_lcs_runtime_on_simple_data() {
    let (dir, _tmp) = create_test_dir("test_csharp_runtime_on_simple_data");
    test_csharp_runtime_on_simple_data(dir, Runtime::Lcs);
}

#[test]
fn test_csharp_bincode_runtime_on_simple_data() {
    let (dir, _tmp) = create_test_dir("test_csharp_bincode_runtime_on_simple_data");
    test_csharp_runtime_on_simple_data(dir, Runtime::Bincode);
}

fn test_csharp_runtime_on_simple_data(dir: PathBuf, runtime: Runtime) {
    let test_dir = copy_test_project(&dir, false);

    let registry = test_utils::get_simple_registry().unwrap();

    let installer = csharp::Installer::new(dir.clone());
    installer.install_serde_runtime().unwrap();
    installer.install_bincode_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    // Generates code into `Serde/Tests`
    let config =
        CodeGeneratorConfig::new("Serde.Tests".to_string()).with_encodings(vec![runtime.into()]);
    let generator = csharp::CodeGenerator::new(&config);
    generator.write_source_files(dir, &registry).unwrap();

    let reference = runtime.serialize(&Test {
        a: vec![4, 6],
        b: (-3, 5),
        c: Choice::C { x: 7 },
    });

    let mut source = File::create(&test_dir.join("TestRuntime.cs")).unwrap();
    writeln!(
        source,
        r#"
using System;
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;

namespace Serde.Tests {{
    public class TestRuntime {{
        [Test]
        public void TestRoundTrip() {{
            byte[] input = new byte[] {{{0}}};

            Test test = Test.{1}Deserialize(input);

            List<uint> a = new List<uint>(new uint[] {{ 4, 6 }});
            var b = ((long)-3, (ulong)5);
            Choice c = new Choice.C((byte) 7);
            Test test2 = new Test(a, b, c);

            Assert.AreEqual(test, test2);

            byte[] output = test2.{1}Serialize();

            CollectionAssert.AreEqual(input, output);

            byte[] input2 = new byte[] {{{0}, 1}};
            Assert.Throws<DeserializationException>(() => Test.{1}Deserialize(input2));
        }}
    }}
}}
"#,
        reference
            .iter()
            .map(|x| format!("{}", *x as u8))
            .collect::<Vec<_>>()
            .join(", "),
        runtime.name().to_camel_case(),
    )
    .unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}

#[test]
fn test_csharp_lcs_runtime_on_supported_types() {
    let (dir, _tmp) = create_test_dir("test_csharp_lcs_runtime_on_supported_types");
    test_csharp_runtime_on_supported_types(dir, Runtime::Lcs);
}

#[test]
fn test_csharp_bincode_runtime_on_supported_types() {
    let (dir, _tmp) = create_test_dir("test_csharp_bincode_runtime_on_supported_types");
    test_csharp_runtime_on_supported_types(dir, Runtime::Bincode);
}

fn quote_bytes(bytes: &[u8]) -> String {
    format!(
        "{{{}}}",
        bytes
            .iter()
            .map(|x| format!("{}", *x as u8))
            .collect::<Vec<_>>()
            .join(", ")
    )
}

fn test_csharp_runtime_on_supported_types(dir: PathBuf, runtime: Runtime) {
    let test_dir = copy_test_project(&dir, false);

    let registry = test_utils::get_registry().unwrap();

    let installer = csharp::Installer::new(dir.clone());
    installer.install_serde_runtime().unwrap();
    installer.install_bincode_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    // Generates code into `Serde/Tests`
    let config =
        CodeGeneratorConfig::new("Serde.Tests".to_string()).with_encodings(vec![runtime.into()]);
    let generator = csharp::CodeGenerator::new(&config);
    generator.write_source_files(dir, &registry).unwrap();

    let positive_encodings = runtime
        .get_positive_samples_quick()
        .iter()
        .map(|bytes| quote_bytes(bytes))
        .collect::<Vec<_>>();

    let negative_encodings = runtime
        .get_negative_samples()
        .iter()
        .map(|bytes| quote_bytes(bytes))
        .collect::<Vec<_>>();

    let mut source = File::create(test_dir.join("TestRuntime.cs")).unwrap();
    writeln!(
        source,
        r#"
using System;
using System.Linq;
using System.IO;
using NUnit.Framework;

namespace Serde.Tests {{
    public class TestRuntime {{
        static void TestPassInput(byte[] input) {{
            SerdeData test = SerdeData.{0}Deserialize(input);
            byte[] output = test.{0}Serialize();

            CollectionAssert.AreEqual(input, output);

            // Test simple mutations of the input.
            for (int i = 0; i < input.Length; i++) {{
                byte[] input2 = input.ToArray();
                input2[i] ^= 0x80;
                SerdeData test2;
                try {{
                    test2 = SerdeData.{0}Deserialize(input2);
                }}
                catch (Exception) {{ continue; }}
                Assert.AreNotEqual(test2, test);
            }}
        }}"#,
        runtime.name().to_camel_case()
    )
    .unwrap();

    for (i, input) in positive_encodings.iter().enumerate() {
        writeln!(
            source,
            r#"
        [Test]
        public void TestPassInput{0}() {{
            byte[] input = new byte[] {1};
            TestPassInput(input);
        }}"#,
            i, input
        )
        .unwrap();
    }

    for (i, input) in negative_encodings.iter().enumerate() {
        writeln!(
            source,
            r#"
        [Test]
        public void TestFailInput{0}() {{
            byte[] input = new byte[] {1};
            Assert.Catch(() => SerdeData.{2}Deserialize(input));
        }}"#,
            i,
            input,
            runtime.name().to_camel_case()
        )
        .unwrap();
    }

    writeln!(source, "\t}}\n}}\n").unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}
<commit_msg>csharp: Test for value-equality of generated types<commit_after>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

use heck::CamelCase;
use serde_generate::{
    csharp, test_utils,
    test_utils::{Choice, Runtime, Test},
    CodeGeneratorConfig, SourceInstaller,
};
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::Mutex;

lazy_static::lazy_static! {
    // `dotnet build` spuriously fails on linux if run concurrently
    static ref MUTEX: Mutex<()> = Mutex::new(());
}

/// Returns:
/// 1. A `PathBuf` to the directory to write test data into
/// 2. Optionally, a `tempfile::TempDir` which deletes the directory when it goes out of scope
fn create_test_dir(test_name: &'static str) -> (PathBuf, Option<tempfile::TempDir>) {
    // Set env var to generate into subdirectories for inspection
    if std::env::var("TEST_USE_SUBDIR").is_ok() {
        let mut tries = 0;
        while tries < 20 {
            let test_dir_name = if tries == 0 {
                test_name.into()
            } else {
                format!("{}_{}", test_name, tries)
            };
            let dir = Path::new("tests").join(test_dir_name).to_path_buf();
            match std::fs::create_dir(&dir) {
                Ok(()) => return (dir, None),
                Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => tries += 1,
                Err(e) => panic!("Error creating test directory: {:?}", e),
            }
        }
        panic!("Error creating test directory: Too many existing test directories");
    } else {
        let tempdir = tempfile::Builder::new()
            .suffix(&format!("_{}", test_name))
            .tempdir()
            .unwrap();
        (tempdir.path().to_path_buf(), Some(tempdir))
    }
}

fn dotnet_build(proj_dir: &Path) {
    let _lock = MUTEX.lock();
    let status = Command::new("dotnet")
        .arg("build")
        .current_dir(proj_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

fn run_nunit(proj_dir: &Path) {
    let _lock = MUTEX.lock();
    let status = Command::new("dotnet")
        .arg("test")
        .current_dir(proj_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

fn copy_test_project(root_dir: &Path, copy_runtime_tests: bool) -> PathBuf {
    let test_dir = root_dir.join("Serde.Tests").to_path_buf();

    std::fs::create_dir(&test_dir).unwrap();
    std::fs::copy(
        "runtime/csharp/Serde.Tests/Serde.Tests.csproj",
        &test_dir.join("Serde.Tests.csproj"),
    )
    .unwrap();

    if copy_runtime_tests {
        std::fs::copy(
            "runtime/csharp/Serde.Tests/TestLcs.cs",
            &test_dir.join("TestLcs.cs"),
        )
        .unwrap();
    }

    test_dir
}

#[test]
fn test_csharp_lcs_runtime_tests() {
    let (dir, _tmp) = create_test_dir("test_csharp_lcs_runtime_tests");
    let test_dir = copy_test_project(&dir, true);

    let installer = csharp::Installer::new(dir);
    installer.install_serde_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}

#[test]
fn test_csharp_lcs_runtime_on_simple_data() {
    let (dir, _tmp) = create_test_dir("test_csharp_runtime_on_simple_data");
    test_csharp_runtime_on_simple_data(dir, Runtime::Lcs);
}

#[test]
fn test_csharp_bincode_runtime_on_simple_data() {
    let (dir, _tmp) = create_test_dir("test_csharp_bincode_runtime_on_simple_data");
    test_csharp_runtime_on_simple_data(dir, Runtime::Bincode);
}

fn test_csharp_runtime_on_simple_data(dir: PathBuf, runtime: Runtime) {
    let test_dir = copy_test_project(&dir, false);

    let registry = test_utils::get_simple_registry().unwrap();

    let installer = csharp::Installer::new(dir.clone());
    installer.install_serde_runtime().unwrap();
    installer.install_bincode_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    // Generates code into `Serde/Tests`
    let config =
        CodeGeneratorConfig::new("Serde.Tests".to_string()).with_encodings(vec![runtime.into()]);
    let generator = csharp::CodeGenerator::new(&config);
    generator.write_source_files(dir, &registry).unwrap();

    let reference = runtime.serialize(&Test {
        a: vec![4, 6],
        b: (-3, 5),
        c: Choice::C { x: 7 },
    });

    let mut source = File::create(&test_dir.join("TestRuntime.cs")).unwrap();
    writeln!(
        source,
        r#"
using System;
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;

namespace Serde.Tests {{
    public class TestRuntime {{
        [Test]
        public void TestRoundTrip() {{
            byte[] input = new byte[] {{{0}}};

            Test test = Test.{1}Deserialize(input);

            List<uint> a = new List<uint>(new uint[] {{ 4, 6 }});
            var b = ((long)-3, (ulong)5);
            Choice c = new Choice.C((byte) 7);
            Test test2 = new Test(a, b, c);

            Assert.AreEqual(test, test2);

            byte[] output = test2.{1}Serialize();

            CollectionAssert.AreEqual(input, output);

            byte[] input2 = new byte[] {{{0}, 1}};
            Assert.Throws<DeserializationException>(() => Test.{1}Deserialize(input2));
        }}
    }}
}}
"#,
        reference
            .iter()
            .map(|x| format!("{}", *x as u8))
            .collect::<Vec<_>>()
            .join(", "),
        runtime.name().to_camel_case(),
    )
    .unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}

#[test]
fn test_csharp_lcs_runtime_on_supported_types() {
    let (dir, _tmp) = create_test_dir("test_csharp_lcs_runtime_on_supported_types");
    test_csharp_runtime_on_supported_types(dir, Runtime::Lcs);
}

#[test]
fn test_csharp_bincode_runtime_on_supported_types() {
    let (dir, _tmp) = create_test_dir("test_csharp_bincode_runtime_on_supported_types");
    test_csharp_runtime_on_supported_types(dir, Runtime::Bincode);
}

fn quote_bytes(bytes: &[u8]) -> String {
    format!(
        "{{{}}}",
        bytes
            .iter()
            .map(|x| format!("{}", *x as u8))
            .collect::<Vec<_>>()
            .join(", ")
    )
}

fn test_csharp_runtime_on_supported_types(dir: PathBuf, runtime: Runtime) {
    let test_dir = copy_test_project(&dir, false);

    let registry = test_utils::get_registry().unwrap();

    let installer = csharp::Installer::new(dir.clone());
    installer.install_serde_runtime().unwrap();
    installer.install_bincode_runtime().unwrap();
    installer.install_lcs_runtime().unwrap();

    // Generates code into `Serde/Tests`
    let config =
        CodeGeneratorConfig::new("Serde.Tests".to_string()).with_encodings(vec![runtime.into()]);
    let generator = csharp::CodeGenerator::new(&config);
    generator.write_source_files(dir, &registry).unwrap();

    let positive_encodings = runtime
        .get_positive_samples_quick()
        .iter()
        .map(|bytes| quote_bytes(bytes))
        .collect::<Vec<_>>();

    let negative_encodings = runtime
        .get_negative_samples()
        .iter()
        .map(|bytes| quote_bytes(bytes))
        .collect::<Vec<_>>();

    let mut source = File::create(test_dir.join("TestRuntime.cs")).unwrap();
    writeln!(
        source,
        r#"
using System;
using System.Linq;
using System.IO;
using NUnit.Framework;

namespace Serde.Tests {{
    public class TestRuntime {{
        static void TestPassInput(byte[] input) {{
            SerdeData test = SerdeData.{0}Deserialize(input);
            byte[] output = test.{0}Serialize();

            CollectionAssert.AreEqual(input, output);

            // Test value equality
            SerdeData test2 = SerdeData.{0}Deserialize(input);
            Assert.AreEqual(test, test2);

            // Test simple mutations of the input.
            for (int i = 0; i < input.Length; i++) {{
                byte[] input2 = input.ToArray();
                input2[i] ^= 0x80;
                try {{
                    test2 = SerdeData.{0}Deserialize(input2);
                }}
                catch (Exception) {{ continue; }}
                Assert.AreNotEqual(test2, test);
            }}
        }}"#,
        runtime.name().to_camel_case()
    )
    .unwrap();

    for (i, input) in positive_encodings.iter().enumerate() {
        writeln!(
            source,
            r#"
        [Test]
        public void TestPassInput{0}() {{
            byte[] input = new byte[] {1};
            TestPassInput(input);
        }}"#,
            i, input
        )
        .unwrap();
    }

    for (i, input) in negative_encodings.iter().enumerate() {
        writeln!(
            source,
            r#"
        [Test]
        public void TestFailInput{0}() {{
            byte[] input = new byte[] {1};
            Assert.Catch(() => SerdeData.{2}Deserialize(input));
        }}"#,
            i,
            input,
            runtime.name().to_camel_case()
        )
        .unwrap();
    }

    writeln!(source, "\t}}\n}}\n").unwrap();

    dotnet_build(&test_dir);
    run_nunit(&test_dir);
}
<|endoftext|>


<commit_before>/// Figure 12.4 Creating a thread in the detached state
///
/// Error handling is still very ugly, I hope I soon get an answer here:
/// http://stackoverflow.com/questions/42772307
///
/// $ f04-detached-thread
/// called!

extern crate libc;
extern crate apue;

use libc::{c_void, PTHREAD_CREATE_DETACHED};
use libc::{pthread_create, pthread_attr_destroy, pthread_attr_init, pthread_attr_setdetachstate, usleep};
use apue::PthreadExpect;

extern "C" fn my_thread(_: *mut c_void) -> *mut c_void {
    println!("called!");
    0 as _
}

unsafe fn makethread(func: extern "C" fn(*mut c_void) -> *mut c_void, arg:*mut c_void) -> Result<i32, i32> {
    let (mut attr, mut tid) = std::mem::uninitialized();
    let err = pthread_attr_init(&mut attr).expect();
    if err > 0 {
        return Err(err);
    }
    let mut err = pthread_attr_setdetachstate(&mut attr, PTHREAD_CREATE_DETACHED);
    if err == 0 {
        err = pthread_create(&mut tid, &attr, func, arg);
    }
    pthread_attr_destroy(&mut attr);
    if err > 0 {
        Err(err)
    } else {
        Ok(0)
    }
}

fn main() {
    unsafe {
        makethread(my_thread, std::ptr::null_mut()).expect("couldn't do a thread");
        usleep(100);
    }
}<commit_msg>Bit better<commit_after>/// Figure 12.4 Creating a thread in the detached state
///
/// Error handling is still very ugly, I hope I soon get an answer here:
/// http://stackoverflow.com/questions/42772307
///
/// $ f04-detached-thread
/// called!

extern crate libc;
extern crate apue;

use libc::{c_void, PTHREAD_CREATE_DETACHED};
use libc::{pthread_create, pthread_attr_destroy, pthread_attr_init, pthread_attr_setdetachstate, usleep};

extern "C" fn my_thread(_: *mut c_void) -> *mut c_void {
    println!("called!");
    0 as _
}

unsafe fn makethread(func: extern "C" fn(*mut c_void) -> *mut c_void, arg:*mut c_void) -> Result<i32, i32> {
    let (mut attr, mut tid) = std::mem::uninitialized();
    let err = pthread_attr_init(&mut attr);
    if err != 0 {
        return Err(err);
    }
    let mut err = pthread_attr_setdetachstate(&mut attr, PTHREAD_CREATE_DETACHED);
    if err == 0 {
        err = pthread_create(&mut tid, &attr, func, arg);
    }
    pthread_attr_destroy(&mut attr);
    match err {
        0 => Ok(0),
        _ => Err(err),
    }
}

fn main() {
    unsafe {
        makethread(my_thread, std::ptr::null_mut()).expect("couldn't do a thread");
        usleep(100);
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use vk;

/// Describes how an image is going to be used. This is **not** an optimization.
///
/// If you try to use an image in a way that you didn't declare, a panic will happen.
///
/// If `transient_attachment` is true, then only `color_attachment`, `depth_stencil_attachment`
/// and `input_attachment` can be true as well. The rest must be false or an error will be returned
/// when creating the image.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ImageUsage {
    /// Can be used a source for transfers. Includes blits.
    pub transfer_source: bool,

    /// Can be used a destination for transfers. Includes blits.
    pub transfer_dest: bool,

    /// Can be sampled from a shader.
    pub sampled: bool,

    /// Can be used as an image storage in a shader.
    pub storage: bool,

    /// Can be attached as a color attachment to a framebuffer.
    pub color_attachment: bool,

    /// Can be attached as a depth, stencil or depth-stencil attachment to a framebuffer.
    pub depth_stencil_attachment: bool,

    /// Indicates that this image will only ever be used as a temporary framebuffer attachment.
    /// As soon as you leave a render pass, the content of transient images becomes undefined.
    ///
    /// This is a hint to the Vulkan implementation that it may not need allocate any memory for
    /// this image if the image can live entirely in some cache.
    pub transient_attachment: bool,

    /// Can be used as an input attachment. In other words, you can draw to it in a subpass then
    /// read from it in a following pass.
    pub input_attachment: bool,
}

impl ImageUsage {
    /// Builds a `ImageUsage` with all values set to true. Note that using the returned value will
    /// produce an error because of `transient_attachment` being true.
    #[inline]
    pub fn all() -> ImageUsage {
        ImageUsage {
            transfer_source: true,
            transfer_dest: true,
            sampled: true,
            storage: true,
            color_attachment: true,
            depth_stencil_attachment: true,
            transient_attachment: true,
            input_attachment: true,
        }
    }

    /// Builds a `ImageUsage` with all values set to false. Useful as a default value.
    ///
    /// # Example
    ///
    /// ```rust
    /// use vulkano::image::ImageUsage as ImageUsage;
    ///
    /// let _usage = ImageUsage {
    ///     transfer_dest: true,
    ///     sampled: true,
    ///     .. ImageUsage::none()
    /// };
    /// ```
    #[inline]
    pub fn none() -> ImageUsage {
        ImageUsage {
            transfer_source: false,
            transfer_dest: false,
            sampled: false,
            storage: false,
            color_attachment: false,
            depth_stencil_attachment: false,
            transient_attachment: false,
            input_attachment: false,
        }
    }

    #[doc(hidden)]
    #[inline]
    pub fn to_usage_bits(&self) -> vk::ImageUsageFlagBits {
        let mut result = 0;
        if self.transfer_source { result |= vk::IMAGE_USAGE_TRANSFER_SRC_BIT; }
        if self.transfer_dest { result |= vk::IMAGE_USAGE_TRANSFER_DST_BIT; }
        if self.sampled { result |= vk::IMAGE_USAGE_SAMPLED_BIT; }
        if self.storage { result |= vk::IMAGE_USAGE_STORAGE_BIT; }
        if self.color_attachment { result |= vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT; }
        if self.depth_stencil_attachment { result |= vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; }
        if self.transient_attachment { result |= vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; }
        if self.input_attachment { result |= vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT; }
        result
    }

    #[inline]
    #[doc(hidden)]
    pub fn from_bits(val: u32) -> ImageUsage {
        ImageUsage {
            transfer_source: (val & vk::IMAGE_USAGE_TRANSFER_SRC_BIT) != 0,
            transfer_dest: (val & vk::IMAGE_USAGE_TRANSFER_DST_BIT) != 0,
            sampled: (val & vk::IMAGE_USAGE_SAMPLED_BIT) != 0,
            storage: (val & vk::IMAGE_USAGE_STORAGE_BIT) != 0,
            color_attachment: (val & vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0,
            depth_stencil_attachment: (val & vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0,
            transient_attachment: (val & vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0,
            input_attachment: (val & vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT) != 0,
        }
    }
}
<commit_msg>Implement BitOr for ImageUsage<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ops::BitOr;
use vk;

/// Describes how an image is going to be used. This is **not** an optimization.
///
/// If you try to use an image in a way that you didn't declare, a panic will happen.
///
/// If `transient_attachment` is true, then only `color_attachment`, `depth_stencil_attachment`
/// and `input_attachment` can be true as well. The rest must be false or an error will be returned
/// when creating the image.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ImageUsage {
    /// Can be used a source for transfers. Includes blits.
    pub transfer_source: bool,

    /// Can be used a destination for transfers. Includes blits.
    pub transfer_dest: bool,

    /// Can be sampled from a shader.
    pub sampled: bool,

    /// Can be used as an image storage in a shader.
    pub storage: bool,

    /// Can be attached as a color attachment to a framebuffer.
    pub color_attachment: bool,

    /// Can be attached as a depth, stencil or depth-stencil attachment to a framebuffer.
    pub depth_stencil_attachment: bool,

    /// Indicates that this image will only ever be used as a temporary framebuffer attachment.
    /// As soon as you leave a render pass, the content of transient images becomes undefined.
    ///
    /// This is a hint to the Vulkan implementation that it may not need allocate any memory for
    /// this image if the image can live entirely in some cache.
    pub transient_attachment: bool,

    /// Can be used as an input attachment. In other words, you can draw to it in a subpass then
    /// read from it in a following pass.
    pub input_attachment: bool,
}

impl ImageUsage {
    /// Builds a `ImageUsage` with all values set to true. Note that using the returned value will
    /// produce an error because of `transient_attachment` being true.
    #[inline]
    pub fn all() -> ImageUsage {
        ImageUsage {
            transfer_source: true,
            transfer_dest: true,
            sampled: true,
            storage: true,
            color_attachment: true,
            depth_stencil_attachment: true,
            transient_attachment: true,
            input_attachment: true,
        }
    }

    /// Builds a `ImageUsage` with all values set to false. Useful as a default value.
    ///
    /// # Example
    ///
    /// ```rust
    /// use vulkano::image::ImageUsage as ImageUsage;
    ///
    /// let _usage = ImageUsage {
    ///     transfer_dest: true,
    ///     sampled: true,
    ///     .. ImageUsage::none()
    /// };
    /// ```
    #[inline]
    pub fn none() -> ImageUsage {
        ImageUsage {
            transfer_source: false,
            transfer_dest: false,
            sampled: false,
            storage: false,
            color_attachment: false,
            depth_stencil_attachment: false,
            transient_attachment: false,
            input_attachment: false,
        }
    }

    #[doc(hidden)]
    #[inline]
    pub fn to_usage_bits(&self) -> vk::ImageUsageFlagBits {
        let mut result = 0;
        if self.transfer_source { result |= vk::IMAGE_USAGE_TRANSFER_SRC_BIT; }
        if self.transfer_dest { result |= vk::IMAGE_USAGE_TRANSFER_DST_BIT; }
        if self.sampled { result |= vk::IMAGE_USAGE_SAMPLED_BIT; }
        if self.storage { result |= vk::IMAGE_USAGE_STORAGE_BIT; }
        if self.color_attachment { result |= vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT; }
        if self.depth_stencil_attachment { result |= vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; }
        if self.transient_attachment { result |= vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; }
        if self.input_attachment { result |= vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT; }
        result
    }

    #[inline]
    #[doc(hidden)]
    pub fn from_bits(val: u32) -> ImageUsage {
        ImageUsage {
            transfer_source: (val & vk::IMAGE_USAGE_TRANSFER_SRC_BIT) != 0,
            transfer_dest: (val & vk::IMAGE_USAGE_TRANSFER_DST_BIT) != 0,
            sampled: (val & vk::IMAGE_USAGE_SAMPLED_BIT) != 0,
            storage: (val & vk::IMAGE_USAGE_STORAGE_BIT) != 0,
            color_attachment: (val & vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0,
            depth_stencil_attachment: (val & vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0,
            transient_attachment: (val & vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0,
            input_attachment: (val & vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT) != 0,
        }
    }
}

impl BitOr for ImageUsage {
    type Output = Self;

    #[inline]
    fn bitor(self, rhs: Self) -> Self {
        ImageUsage {
            transfer_source: self.transfer_source || rhs.transfer_source,
            transfer_dest: self.transfer_dest || rhs.transfer_dest,
            sampled: self.sampled || rhs.sampled,
            storage: self.storage || rhs.storage,
            color_attachment: self.color_attachment || rhs.color_attachment,
            depth_stencil_attachment: self.depth_stencil_attachment || rhs.depth_stencil_attachment,
            transient_attachment: self.transient_attachment || rhs.transient_attachment,
            input_attachment: self.input_attachment || rhs.input_attachment,
        }
    }
}
<|endoftext|>


<commit_before>extern crate structopt;

use std::io::{self, Write};
use ulid::{Ulid, Generator};

use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// Number of ULIDs to generate
    #[structopt(short = "n", long = "count", default_value = "1")]
    count: u32,
    #[structopt(short = "m", long = "monotonic")]
    monotonic: bool,
    /// ULIDs for inspection
    #[structopt(conflicts_with = "count")]
    ulids: Vec<String>,
}

fn main() {
    let opt = Opt::from_args();

    if !opt.ulids.is_empty() {
        inspect(&opt.ulids);
    } else {
        generate(opt.count, opt.monotonic);
    }
}

fn generate(count: u32, monotonic: bool) {
    let stdout = io::stdout();
    let mut locked = stdout.lock();
    if monotonic {
        let mut gen = Generator::new();
        for _ in 0..count {
            writeln!(&mut locked, "{}", gen.generate().unwrap()).unwrap();
        }
    } else {
        for _ in 0..count {
            writeln!(&mut locked, "{}", Ulid::new()).unwrap();
        }
    }
}

fn inspect(values: &[String]) {
    for val in values {
        let ulid = Ulid::from_string(&val);
        match ulid {
            Ok(ulid) => {
                let upper_hex = format!("{:X}", ulid.0);
                println!(
                    "
REPRESENTATION:

  String: {}
     Raw: {}

COMPONENTS:

       Time: {}
  Timestamp: {}
    Payload: {}
",
                    ulid.to_string(),
                    upper_hex,
                    ulid.datetime().to_rfc2822(),
                    ulid.timestamp_ms(),
                    upper_hex.chars().skip(6).collect::<String>()
                );
            }
            Err(e) => {
                println!("{} is not a valid ULID: {}", val, e);
            }
        }
    }
}
<commit_msg>sleep if invalid ulid<commit_after>extern crate structopt;

use std::io::{self, Write};
use ulid::{Generator, Ulid};

use std::{thread, time::Duration};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// Number of ULIDs to generate
    #[structopt(short = "n", long = "count", default_value = "1")]
    count: u32,
    #[structopt(short = "m", long = "monotonic")]
    monotonic: bool,
    /// ULIDs for inspection
    #[structopt(conflicts_with = "count")]
    ulids: Vec<String>,
}

fn main() {
    let opt = Opt::from_args();

    if !opt.ulids.is_empty() {
        inspect(&opt.ulids);
    } else {
        generate(opt.count, opt.monotonic);
    }
}

fn generate(count: u32, monotonic: bool) {
    let stdout = io::stdout();
    let stderr = io::stderr();
    let mut locked = stdout.lock();
    let mut err_locked = stderr.lock();
    if monotonic {
        let mut gen = Generator::new();
        let mut i = 0;
        while i < count {
            match gen.generate() {
                Ok(ulid) => {
                    writeln!(&mut locked, "{}", ulid).unwrap();
                    i += 1;
                }
                Err(_) => {
                    writeln!(&mut err_locked, "unable to create ulid").unwrap();
                    thread::sleep(Duration::from_millis(1));
                    // do not increment i
                }
            }
        }
    } else {
        for _ in 0..count {
            writeln!(&mut locked, "{}", Ulid::new()).unwrap();
        }
    }
}

fn inspect(values: &[String]) {
    for val in values {
        let ulid = Ulid::from_string(&val);
        match ulid {
            Ok(ulid) => {
                let upper_hex = format!("{:X}", ulid.0);
                println!(
                    "
REPRESENTATION:

  String: {}
     Raw: {}

COMPONENTS:

       Time: {}
  Timestamp: {}
    Payload: {}
",
                    ulid.to_string(),
                    upper_hex,
                    ulid.datetime().to_rfc2822(),
                    ulid.timestamp_ms(),
                    upper_hex.chars().skip(6).collect::<String>()
                );
            }
            Err(e) => {
                println!("{} is not a valid ULID: {}", val, e);
            }
        }
    }
}
<|endoftext|>