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

use core::mem::{self, MaybeUninit};
use core::ptr;
use core::slice;

use crate::addr::*;
use crate::arch::*;
use crate::boot_params::*;
use crate::cpio::*;
use crate::cpu::*;
use crate::layout::*;
use crate::memiter::*;
use crate::mm::*;
use crate::mpool::*;
use crate::page::*;
use crate::std::*;
use crate::types::*;
use crate::utils::*;
use crate::vm::*;

use arrayvec::ArrayVec;

/// Copies data to an unmapped location by mapping it for write, copying the
/// data, then unmapping it.
///
/// The data is written so that it is available to all cores with the cache
/// disabled. When switching to the partitions, the caching is initially
/// disabled so the data must be available without the cache.
unsafe fn copy_to_unmapped(
    hypervisor_ptable: &mut PageTable<Stage1>,
    to: paddr_t,
    from: *const c_void,
    size: usize,
    ppool: &mut MPool,
) -> bool {
    let to_end = pa_add(to, size);

    if hypervisor_ptable
        .identity_map(to, to_end, Mode::W, ppool)
        .is_err()
    {
        return false;
    }

    memcpy_s(pa_addr(to) as *mut _, size, from, size);
    arch_mm_write_back_dcache(pa_addr(to), size);

    hypervisor_ptable.unmap(to, to_end, ppool).unwrap();

    true
}

/// Loads the primary VM.
pub unsafe fn load_primary(
    hypervisor_ptable: &mut PageTable<Stage1>,
    cpio: *const MemIter,
    kernel_arg: uintreg_t,
    ppool: &mut MPool,
) -> Result<MemIter, ()> {
    let mut it = mem::uninitialized();
    let primary_begin = layout_primary_begin();

    if !cpio_find_file(cpio, "vmlinuz\0".as_ptr(), &mut it) {
        dlog!("Unable to find vmlinuz\n");
        return Err(());
    }

    dlog!(
        "Copying primary to {:p}\n",
        pa_addr(primary_begin) as *const u8
    );
    if !copy_to_unmapped(
        hypervisor_ptable,
        primary_begin,
        it.next as usize as *mut _,
        it.limit.offset_from(it.next) as usize,
        ppool,
    ) {
        dlog!("Unable to relocate kernel for primary vm.\n");
        return Err(());
    }

    let mut initrd = MaybeUninit::uninit();
    if !cpio_find_file(cpio, "initrd.img\0".as_ptr(), initrd.get_mut()) {
        dlog!("Unable to find initrd.img\n");
        return Err(());
    }

    let initrd = initrd.assume_init();

    {
        let mut vm = mem::uninitialized();
        if !vm_init(MAX_CPUS as u16, ppool, &mut vm) {
            dlog!("Unable to initialise primary vm\n");
            return Err(());
        }

        if (*vm).id != HF_PRIMARY_VM_ID {
            dlog!("Primary vm was not given correct id\n");
            return Err(());
        }

        // Map the 1TB of memory.
        // TODO: We should do a whitelist rather than blacklist.
        if !mm_vm_identity_map(
            &mut (*vm).inner.get_mut_unchecked().ptable,
            pa_init(0),
            pa_init(1024usize * 1024 * 1024 * 1024),
            Mode::R | Mode::W | Mode::X,
            ptr::null_mut(),
            ppool,
        ) {
            dlog!("Unable to initialise memory for primary vm\n");
            return Err(());
        }

        if !mm_vm_unmap_hypervisor(&mut (*vm).inner.get_mut_unchecked().ptable, ppool) {
            dlog!("Unable to unmap hypervisor from primary vm\n");
            return Err(());
        }

        (*vm_get_vcpu(vm, 0))
            .inner
            .lock()
            .on(ipa_from_pa(primary_begin), kernel_arg);
    }

    Ok(initrd)
}

/// Try to find a memory range of the given size within the given ranges, and
/// remove it from them. Return true on success, or false if no large enough
/// contiguous range is found.
fn carve_out_mem_range(
    mem_ranges: &mut [MemRange],
    size_to_find: u64,
) -> Result<(paddr_t, paddr_t), ()> {
    // TODO(b/116191358): Consider being cleverer about how we pack VMs
    // together, with a non-greedy algorithm.
    for mem_range in mem_ranges.iter_mut() {
        if size_to_find <= pa_difference(mem_range.begin, mem_range.end) as u64 {
            // This range is big enough, take some of it from the end and reduce
            // its size accordingly.
            let found_end = mem_range.end;
            let found_begin = pa_init(pa_addr(mem_range.end) - size_to_find as usize);
            mem_range.end = found_begin;
            return Ok((found_begin, found_end));
        }
    }

    Err(())
}

/// Given arrays of memory ranges before and after memory was removed for
/// secondary VMs, add the difference to the reserved ranges of the given
/// update. Return true on success, or false if there would be more than
/// MAX_MEM_RANGES reserved ranges after adding the new ones.
/// `before` and `after` must be arrays of exactly `mem_ranges_count` elements.
unsafe fn update_reserved_ranges(
    update: &mut BootParamsUpdate,
    before: &[MemRange],
    after: &[MemRange],
) -> Result<(), ()> {
    assert_eq!(before.len(), after.len());

    for (before, after) in before.iter().zip(after.iter()) {
        if pa_addr(after.begin) > pa_addr(before.begin) {
            if (*update).reserved_ranges_count >= MAX_MEM_RANGES {
                dlog!("Too many reserved ranges after loading secondary VMs.\n");
                return Err(());
            }

            update.reserved_ranges[update.reserved_ranges_count].begin = after.end;
            update.reserved_ranges[update.reserved_ranges_count].end = before.end;
            update.reserved_ranges_count += 1;
        }
    }

    Ok(())
}

/// Loads all secondary VMs into the memory ranges from the given params.
/// Memory reserved for the VMs is added to the `reserved_ranges` of `update`.
pub unsafe fn load_secondary(
    hypervisor_ptable: &mut PageTable<Stage1>,
    cpio: *const MemIter,
    params: *const BootParams,
    update: &mut BootParamsUpdate,
    ppool: &mut MPool,
) -> Result<(), ()> {
    let mut mem_ranges_available: ArrayVec<[MemRange; MAX_MEM_RANGES]> = ArrayVec::new();
    // static_assert(
    //  sizeof(mem_ranges_available) == sizeof(params->mem_ranges),
    //  "mem_range arrays must be the same size for memcpy.");

    const_assert!(mem::size_of::<MemRange>() * MAX_MEM_RANGES < 500);
    mem_ranges_available.clone_from_slice(&(*params).mem_ranges);
    mem_ranges_available.truncate((*params).mem_ranges_count);

    let primary = vm_find(HF_PRIMARY_VM_ID);
    let mut it = mem::uninitialized();

    if !cpio_find_file(cpio, "vms.txt\0".as_ptr(), &mut it) {
        dlog!("vms.txt is missing\n");
        return Ok(());
    }

    // Round the last addresses down to the page size.
    for mem_range in mem_ranges_available.iter_mut() {
        mem_range.end = pa_init(round_down(pa_addr(mem_range.end), PAGE_SIZE));
    }

    let mut mem = mem::uninitialized();
    let mut cpu = mem::uninitialized();
    let mut name = mem::uninitialized();

    while memiter_parse_uint(&mut it, &mut mem)
        && memiter_parse_uint(&mut it, &mut cpu)
        && memiter_parse_str(&mut it, &mut name)
    {
        dlog!("Loading ");
        let mut p = name.next;
        while p != name.limit {
            dlog!("{}", *p as char);
            p = p.add(1);
        }
        dlog!("\n");

        let mut kernel = mem::uninitialized();

        if !cpio_find_file_memiter(cpio, &name, &mut kernel) {
            dlog!("Unable to load kernel\n");
            continue;
        }

        // Round up to page size.
        mem = (mem + PAGE_SIZE as u64 - 1) & !(PAGE_SIZE as u64 - 1);

        if mem < kernel.limit.offset_from(kernel.next) as u64 {
            dlog!("Kernel is larger than available memory\n");
            continue;
        }

        let (secondary_mem_begin, secondary_mem_end) =
            match carve_out_mem_range(&mut mem_ranges_available, mem as u64) {
                Ok(range) => range,
                Err(_) => {
                    dlog!("Not enough memory ({} bytes)\n", mem);
                    continue;
                }
            };

        if !copy_to_unmapped(
            hypervisor_ptable,
            secondary_mem_begin,
            kernel.next as usize as *const _,
            kernel.limit.offset_from(kernel.next) as usize,
            ppool,
        ) {
            dlog!("Unable to copy kernel\n");
            continue;
        }

        let mut vm = mem::uninitialized();
        if !vm_init(cpu as spci_vcpu_count_t, ppool, &mut vm) {
            dlog!("Unable to initialise VM\n");
            continue;
        }

        let mut secondary_entry = mem::uninitialized();

        // Grant the VM access to the memory.
        if !mm_vm_identity_map(
            &mut (*vm).inner.get_mut_unchecked().ptable,
            secondary_mem_begin,
            secondary_mem_end,
            Mode::R | Mode::W | Mode::X,
            &mut secondary_entry,
            ppool,
        ) {
            dlog!("Unable to initialise memory\n");
            continue;
        }

        // Deny the primary VM access to this memory.
        if !mm_vm_unmap(
            &mut (*primary).inner.get_mut_unchecked().ptable,
            secondary_mem_begin,
            secondary_mem_end,
            ppool,
        ) {
            dlog!("Unable to unmap secondary VM from primary VM\n");
            return Err(());
        }

        dlog!(
            "Loaded with {} vcpus, entry at 0x{:x}\n",
            cpu,
            pa_addr(secondary_mem_begin)
        );

        let vcpu = vm_get_vcpu(vm, 0);
        vcpu_secondary_reset_and_start(
            vcpu,
            secondary_entry,
            pa_difference(secondary_mem_begin, secondary_mem_end) as uintreg_t,
        );
    }

    // Add newly reserved areas to update params by looking at the difference
    // between the available ranges from the original params and the updated
    // mem_ranges_available. We assume that the number and order of available
    // ranges is the same, i.e. we don't remove any ranges above only make them
    // smaller.
    update_reserved_ranges(
        update,
        &(*params).mem_ranges[0..(*params).mem_ranges_count],
        &mem_ranges_available,
    )
}
<commit_msg>Fix mem_ranges_available to be initialized properly<commit_after>/*
 * Copyright 2019 Sanguk Park
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use core::mem::{self, MaybeUninit};
use core::ptr;

use crate::addr::*;
use crate::arch::*;
use crate::boot_params::*;
use crate::cpio::*;
use crate::cpu::*;
use crate::layout::*;
use crate::memiter::*;
use crate::mm::*;
use crate::mpool::*;
use crate::page::*;
use crate::std::*;
use crate::types::*;
use crate::utils::*;
use crate::vm::*;

use arrayvec::ArrayVec;

/// Copies data to an unmapped location by mapping it for write, copying the
/// data, then unmapping it.
///
/// The data is written so that it is available to all cores with the cache
/// disabled. When switching to the partitions, the caching is initially
/// disabled so the data must be available without the cache.
unsafe fn copy_to_unmapped(
    hypervisor_ptable: &mut PageTable<Stage1>,
    to: paddr_t,
    from: *const c_void,
    size: usize,
    ppool: &mut MPool,
) -> bool {
    let to_end = pa_add(to, size);

    if hypervisor_ptable
        .identity_map(to, to_end, Mode::W, ppool)
        .is_err()
    {
        return false;
    }

    memcpy_s(pa_addr(to) as *mut _, size, from, size);
    arch_mm_write_back_dcache(pa_addr(to), size);

    hypervisor_ptable.unmap(to, to_end, ppool).unwrap();

    true
}

/// Loads the primary VM.
pub unsafe fn load_primary(
    hypervisor_ptable: &mut PageTable<Stage1>,
    cpio: *const MemIter,
    kernel_arg: uintreg_t,
    ppool: &mut MPool,
) -> Result<MemIter, ()> {
    let mut it = mem::uninitialized();
    let primary_begin = layout_primary_begin();

    if !cpio_find_file(cpio, "vmlinuz\0".as_ptr(), &mut it) {
        dlog!("Unable to find vmlinuz\n");
        return Err(());
    }

    dlog!(
        "Copying primary to {:p}\n",
        pa_addr(primary_begin) as *const u8
    );
    if !copy_to_unmapped(
        hypervisor_ptable,
        primary_begin,
        it.next as usize as *mut _,
        it.limit.offset_from(it.next) as usize,
        ppool,
    ) {
        dlog!("Unable to relocate kernel for primary vm.\n");
        return Err(());
    }

    let mut initrd = MaybeUninit::uninit();
    if !cpio_find_file(cpio, "initrd.img\0".as_ptr(), initrd.get_mut()) {
        dlog!("Unable to find initrd.img\n");
        return Err(());
    }

    let initrd = initrd.assume_init();

    {
        let mut vm = mem::uninitialized();
        if !vm_init(MAX_CPUS as u16, ppool, &mut vm) {
            dlog!("Unable to initialise primary vm\n");
            return Err(());
        }

        if (*vm).id != HF_PRIMARY_VM_ID {
            dlog!("Primary vm was not given correct id\n");
            return Err(());
        }

        // Map the 1TB of memory.
        // TODO: We should do a whitelist rather than blacklist.
        if !mm_vm_identity_map(
            &mut (*vm).inner.get_mut_unchecked().ptable,
            pa_init(0),
            pa_init(1024usize * 1024 * 1024 * 1024),
            Mode::R | Mode::W | Mode::X,
            ptr::null_mut(),
            ppool,
        ) {
            dlog!("Unable to initialise memory for primary vm\n");
            return Err(());
        }

        if !mm_vm_unmap_hypervisor(&mut (*vm).inner.get_mut_unchecked().ptable, ppool) {
            dlog!("Unable to unmap hypervisor from primary vm\n");
            return Err(());
        }

        (*vm_get_vcpu(vm, 0))
            .inner
            .lock()
            .on(ipa_from_pa(primary_begin), kernel_arg);
    }

    Ok(initrd)
}

/// Try to find a memory range of the given size within the given ranges, and
/// remove it from them. Return true on success, or false if no large enough
/// contiguous range is found.
fn carve_out_mem_range(
    mem_ranges: &mut [MemRange],
    size_to_find: u64,
) -> Result<(paddr_t, paddr_t), ()> {
    // TODO(b/116191358): Consider being cleverer about how we pack VMs
    // together, with a non-greedy algorithm.
    for mem_range in mem_ranges.iter_mut() {
        if size_to_find <= pa_difference(mem_range.begin, mem_range.end) as u64 {
            // This range is big enough, take some of it from the end and reduce
            // its size accordingly.
            let found_end = mem_range.end;
            let found_begin = pa_init(pa_addr(mem_range.end) - size_to_find as usize);
            mem_range.end = found_begin;
            return Ok((found_begin, found_end));
        }
    }

    Err(())
}

/// Given arrays of memory ranges before and after memory was removed for
/// secondary VMs, add the difference to the reserved ranges of the given
/// update. Return true on success, or false if there would be more than
/// MAX_MEM_RANGES reserved ranges after adding the new ones.
/// `before` and `after` must be arrays of exactly `mem_ranges_count` elements.
unsafe fn update_reserved_ranges(
    update: &mut BootParamsUpdate,
    before: &[MemRange],
    after: &[MemRange],
) -> Result<(), ()> {
    assert_eq!(before.len(), after.len());

    for (before, after) in before.iter().zip(after.iter()) {
        if pa_addr(after.begin) > pa_addr(before.begin) {
            if update.reserved_ranges_count >= MAX_MEM_RANGES {
                dlog!("Too many reserved ranges after loading secondary VMs.\n");
                return Err(());
            }

            update.reserved_ranges[update.reserved_ranges_count].begin = after.end;
            update.reserved_ranges[update.reserved_ranges_count].end = before.end;
            update.reserved_ranges_count += 1;
        }
    }

    Ok(())
}

/// Loads all secondary VMs into the memory ranges from the given params.
/// Memory reserved for the VMs is added to the `reserved_ranges` of `update`.
pub unsafe fn load_secondary(
    hypervisor_ptable: &mut PageTable<Stage1>,
    cpio: &MemIter,
    params: &BootParams,
    update: &mut BootParamsUpdate,
    ppool: &mut MPool,
) -> Result<(), ()> {
    let mut mem_ranges_available: ArrayVec<[MemRange; MAX_MEM_RANGES]> = ArrayVec::new();
    // static_assert(
    //  sizeof(mem_ranges_available) == sizeof(params->mem_ranges),
    //  "mem_range arrays must be the same size for memcpy.");

    const_assert!(mem::size_of::<MemRange>() * MAX_MEM_RANGES < 500);
    mem_ranges_available.set_len(MAX_MEM_RANGES);
    mem_ranges_available.clone_from_slice(&params.mem_ranges);
    mem_ranges_available.truncate(params.mem_ranges_count);

    let primary = vm_find(HF_PRIMARY_VM_ID);
    let mut it = mem::uninitialized();

    if !cpio_find_file(cpio, "vms.txt\0".as_ptr(), &mut it) {
        dlog!("vms.txt is missing\n");
        return Ok(());
    }

    // Round the last addresses down to the page size.
    for mem_range in mem_ranges_available.iter_mut() {
        mem_range.end = pa_init(round_down(pa_addr(mem_range.end), PAGE_SIZE));
    }

    let mut mem = mem::uninitialized();
    let mut cpu = mem::uninitialized();
    let mut name = mem::uninitialized();

    while memiter_parse_uint(&mut it, &mut mem)
        && memiter_parse_uint(&mut it, &mut cpu)
        && memiter_parse_str(&mut it, &mut name)
    {
        dlog!("Loading ");
        let mut p = name.next;
        while p != name.limit {
            dlog!("{}", *p as char);
            p = p.add(1);
        }
        dlog!("\n");

        let mut kernel = mem::uninitialized();

        if !cpio_find_file_memiter(cpio, &name, &mut kernel) {
            dlog!("Unable to load kernel\n");
            continue;
        }

        // Round up to page size.
        mem = (mem + PAGE_SIZE as u64 - 1) & !(PAGE_SIZE as u64 - 1);

        if mem < kernel.limit.offset_from(kernel.next) as u64 {
            dlog!("Kernel is larger than available memory\n");
            continue;
        }

        let (secondary_mem_begin, secondary_mem_end) =
            match carve_out_mem_range(&mut mem_ranges_available, mem as u64) {
                Ok(range) => range,
                Err(_) => {
                    dlog!("Not enough memory ({} bytes)\n", mem);
                    continue;
                }
            };

        if !copy_to_unmapped(
            hypervisor_ptable,
            secondary_mem_begin,
            kernel.next as usize as *const _,
            kernel.limit.offset_from(kernel.next) as usize,
            ppool,
        ) {
            dlog!("Unable to copy kernel\n");
            continue;
        }

        let mut vm = mem::uninitialized();
        if !vm_init(cpu as spci_vcpu_count_t, ppool, &mut vm) {
            dlog!("Unable to initialise VM\n");
            continue;
        }

        let mut secondary_entry = mem::uninitialized();

        // Grant the VM access to the memory.
        if !mm_vm_identity_map(
            &mut (*vm).inner.get_mut_unchecked().ptable,
            secondary_mem_begin,
            secondary_mem_end,
            Mode::R | Mode::W | Mode::X,
            &mut secondary_entry,
            ppool,
        ) {
            dlog!("Unable to initialise memory\n");
            continue;
        }

        // Deny the primary VM access to this memory.
        if !mm_vm_unmap(
            &mut (*primary).inner.get_mut_unchecked().ptable,
            secondary_mem_begin,
            secondary_mem_end,
            ppool,
        ) {
            dlog!("Unable to unmap secondary VM from primary VM\n");
            return Err(());
        }

        dlog!(
            "Loaded with {} vcpus, entry at 0x{:x}\n",
            cpu,
            pa_addr(secondary_mem_begin)
        );

        let vcpu = vm_get_vcpu(vm, 0);
        vcpu_secondary_reset_and_start(
            vcpu,
            secondary_entry,
            pa_difference(secondary_mem_begin, secondary_mem_end) as uintreg_t,
        );
    }

    // Add newly reserved areas to update params by looking at the difference
    // between the available ranges from the original params and the updated
    // mem_ranges_available. We assume that the number and order of available
    // ranges is the same, i.e. we don't remove any ranges above only make them
    // smaller.
    update_reserved_ranges(
        update,
        &params.mem_ranges[0..params.mem_ranges_count],
        &mem_ranges_available,
    )
}
<|endoftext|>


<commit_before>mod config;

use crate::config::{cli_parse, Config};
use iced::{
  canvas, executor, keyboard, mouse, Application, Canvas, Color, Command, Element, Length, Point, Rectangle, Settings,
  Vector,
};
use oppai_field::field::{self, Field, Pos};
use oppai_field::player::Player;
use oppai_field::zobrist::Zobrist;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

pub fn main() -> iced::Result {
  let config = cli_parse();

  Game::run(Settings {
    antialiasing: true,
    flags: config,
    ..Settings::default()
  })
}

struct Game {
  player: Player,
  field: Field,
  captures: Vec<(Vec<Pos>, Player, usize)>,
  field_cache: canvas::Cache,
}

#[derive(Debug, Clone, Copy)]
enum CanvasMessage {
  PutPoint(Pos),
  Undo,
}

#[derive(Debug, Clone, Copy)]
enum Message {
  Canvas(CanvasMessage),
}

impl Application for Game {
  type Executor = executor::Default;
  type Message = Message;
  type Flags = Config;

  fn new(flags: Config) -> (Self, Command<Self::Message>) {
    let mut rng = XorShiftRng::from_entropy();
    let zobrist = Zobrist::new(field::length(flags.width, flags.height) * 2, &mut rng);
    let field = Field::new(flags.width, flags.height, std::sync::Arc::new(zobrist));
    (
      Game {
        player: Player::Red,
        field,
        captures: Vec::new(),
        field_cache: Default::default(),
      },
      Command::none(),
    )
  }

  fn title(&self) -> String {
    "OpPAI".into()
  }

  fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
    match message {
      Message::Canvas(CanvasMessage::PutPoint(pos)) => {
        if self.field.put_point(pos, self.player) {
          let last_chain = self.field.get_last_chain();
          if let Some(&pos) = last_chain.first() {
            let player = self.field.cell(pos).get_player();
            self.captures.push((last_chain, player, self.field.moves_count()));
          }

          let n = self.field.n(pos);
          let s = self.field.s(pos);
          let w = self.field.w(pos);
          let e = self.field.e(pos);
          let nw = self.field.nw(pos);
          let ne = self.field.ne(pos);
          let sw = self.field.sw(pos);
          let se = self.field.se(pos);

          let mut check = |pos1: Pos, pos2: Pos| {
            if self.field.cell(pos1).get_players_point() == Some(self.player)
              && self.field.cell(pos2).get_players_point() == Some(self.player)
            {
              self
                .captures
                .push((vec![pos, pos1, pos2], self.player, self.field.moves_count()));
              true
            } else {
              false
            }
          };

          let _ = !check(s, e) && (check(s, se) || check(e, se));
          let _ = !check(e, n) && (check(e, ne) || check(n, ne));
          let _ = !check(n, w) && (check(n, nw) || check(w, nw));
          let _ = !check(w, s) && (check(w, sw) || check(s, sw));

          self.player = self.player.next();

          self.field_cache.clear();
        }
      }
      Message::Canvas(CanvasMessage::Undo) => {
        if let Some(player) = self.field.last_player() {
          self.player = player;
          self.field.undo();

          while self
            .captures
            .last()
            .map_or(false, |&(_, _, c)| c > self.field.moves_count())
          {
            self.captures.pop();
          }

          self.field_cache.clear();
        }
      }
    }

    Command::none()
  }

  fn view(&mut self) -> iced::Element<'_, Self::Message> {
    let canvas = Canvas::new(self).height(Length::Fill).width(Length::Fill);
    Element::<CanvasMessage>::from(canvas).map(Message::Canvas)
  }
}

impl canvas::Program<CanvasMessage> for Game {
  fn update(
    &mut self,
    event: canvas::Event,
    bounds: Rectangle,
    cursor: canvas::Cursor,
  ) -> (canvas::event::Status, Option<CanvasMessage>) {
    match event {
      canvas::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
        let cursor_position = if let Some(position) = cursor.position_in(&bounds) {
          position
        } else {
          return (canvas::event::Status::Ignored, None);
        };

        let field_width = self.field.width();
        let field_height = self.field.height();
        let width = bounds
          .width
          .min(bounds.height / field_height as f32 * field_width as f32);
        let height = bounds
          .height
          .min(bounds.width / field_width as f32 * field_height as f32);
        let step_x = width / field_width as f32;
        let step_y = height / field_height as f32;
        let shift = Vector::new(
          ((bounds.width - width) / 2.0).round(),
          ((bounds.height - height) / 2.0).round(),
        );
        let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

        let point = cursor_position - shift;
        if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
          let point = point - cursor_shift;
          let x = (point.x / step_x).round() as u32;
          let y = (point.y / step_y).round() as u32;
          (
            canvas::event::Status::Captured,
            Some(CanvasMessage::PutPoint(self.field.to_pos(x, y))),
          )
        } else {
          (canvas::event::Status::Captured, None)
        }
      }
      canvas::Event::Keyboard(keyboard::Event::KeyPressed {
        key_code: keyboard::KeyCode::Backspace,
        ..
      }) => (canvas::event::Status::Captured, Some(CanvasMessage::Undo)),
      _ => (canvas::event::Status::Ignored, None),
    }
  }

  fn draw(&self, bounds: Rectangle, cursor: canvas::Cursor) -> Vec<canvas::Geometry> {
    fn color(player: Player) -> Color {
      match player {
        Player::Red => Color::from_rgb8(0xFF, 0x00, 0x00),
        Player::Black => Color::BLACK,
      }
    }

    let field_width = self.field.width();
    let field_height = self.field.height();
    let width = bounds
      .width
      .min(bounds.height / field_height as f32 * field_width as f32);
    let height = bounds
      .height
      .min(bounds.width / field_width as f32 * field_height as f32);
    let step_x = width / field_width as f32;
    let step_y = height / field_height as f32;
    let shift = Vector::new(
      ((bounds.width - width) / 2.0).round(),
      ((bounds.height - height) / 2.0).round(),
    );
    let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

    let xy_to_point = |x: u32, y: u32| {
      let offset_x = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
      let offset_y = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
      Point::new(offset_x, offset_y) + shift
    };
    let pos_to_point = |pos: Pos| {
      let x = self.field.to_x(pos);
      let y = self.field.to_y(pos);
      xy_to_point(x, y)
    };

    let point_radius = width / field_width as f32 / 6.0;

    let field = self.field_cache.draw(bounds.size(), |frame| {
      let grid = canvas::Path::new(|path| {
        for x in 0..field_width {
          let offset = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
          path.move_to(Point::new(offset, 0.0) + shift);
          path.line_to(Point::new(offset, height) + shift);
        }
        for y in 0..field_height {
          let offset = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
          path.move_to(Point::new(0.0, offset) + shift);
          path.line_to(Point::new(width, offset) + shift);
        }
      });

      frame.stroke(
        &grid,
        canvas::Stroke {
          width: 1.0,
          color: Color::BLACK,
          ..canvas::Stroke::default()
        },
      );

      for &player in &[Player::Red, Player::Black] {
        let points = canvas::Path::new(|path| {
          for &pos in self
            .field
            .points_seq()
            .iter()
            .filter(|&&pos| self.field.cell(pos).is_players_point(player))
          {
            path.circle(pos_to_point(pos), point_radius)
          }
        });

        frame.fill(&points, color(player));
      }

      for (chain, player, _) in &self.captures {
        let path = canvas::Path::new(|path| {
          path.move_to(pos_to_point(chain[0]));
          for &pos in chain.iter().skip(1) {
            path.line_to(pos_to_point(pos));
          }
        });

        let mut color = color(*player);
        color.a = 0.5;

        frame.fill(&path, color);
      }

      if let Some(&pos) = self.field.points_seq().last() {
        let last_point = canvas::Path::new(|path| path.circle(pos_to_point(pos), point_radius * 1.5));

        let color = color(self.field.cell(pos).get_player());

        frame.stroke(
          &last_point,
          canvas::Stroke {
            width: 2.0,
            color,
            ..canvas::Stroke::default()
          },
        );
      }
    });

    let mut frame = canvas::Frame::new(bounds.size());

    if let Some(point) = cursor.position().and_then(|cursor_position| {
      let point = cursor_position - shift;
      if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
        let point = point - cursor_shift;
        let x = (point.x / step_x).round() as u32;
        let y = (point.y / step_y).round() as u32;
        let pos = self.field.to_pos(x, y);
        if self.field.is_putting_allowed(pos) {
          Some(xy_to_point(x, y))
        } else {
          None
        }
      } else {
        None
      }
    }) {
      let cursor_point = canvas::Path::new(|path| path.circle(point, point_radius));

      let mut color = color(self.player);
      color.a = 0.5;

      frame.fill(&cursor_point, color);
    }

    vec![field, frame.into_geometry()]
  }
}
<commit_msg>Display score.<commit_after>mod config;

use crate::config::{cli_parse, Config};
use iced::{
  canvas, executor, keyboard, mouse, Application, Canvas, Color, Command, Container, Element, Length, Point, Rectangle,
  Row, Settings, Text, Vector,
};
use oppai_field::field::{self, Field, Pos};
use oppai_field::player::Player;
use oppai_field::zobrist::Zobrist;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

pub fn main() -> iced::Result {
  let config = cli_parse();

  Game::run(Settings {
    antialiasing: true,
    flags: config,
    ..Settings::default()
  })
}

struct Game {
  player: Player,
  field: Field,
  captures: Vec<(Vec<Pos>, Player, usize)>,
  field_cache: canvas::Cache,
}

#[derive(Debug, Clone, Copy)]
enum CanvasMessage {
  PutPoint(Pos),
  Undo,
}

#[derive(Debug, Clone, Copy)]
enum Message {
  Canvas(CanvasMessage),
}

impl Application for Game {
  type Executor = executor::Default;
  type Message = Message;
  type Flags = Config;

  fn new(flags: Config) -> (Self, Command<Self::Message>) {
    let mut rng = XorShiftRng::from_entropy();
    let zobrist = Zobrist::new(field::length(flags.width, flags.height) * 2, &mut rng);
    let field = Field::new(flags.width, flags.height, std::sync::Arc::new(zobrist));
    (
      Game {
        player: Player::Red,
        field,
        captures: Vec::new(),
        field_cache: Default::default(),
      },
      Command::none(),
    )
  }

  fn title(&self) -> String {
    "OpPAI".into()
  }

  fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
    match message {
      Message::Canvas(CanvasMessage::PutPoint(pos)) => {
        if self.field.put_point(pos, self.player) {
          let last_chain = self.field.get_last_chain();
          if let Some(&pos) = last_chain.first() {
            let player = self.field.cell(pos).get_player();
            self.captures.push((last_chain, player, self.field.moves_count()));
          }

          let n = self.field.n(pos);
          let s = self.field.s(pos);
          let w = self.field.w(pos);
          let e = self.field.e(pos);
          let nw = self.field.nw(pos);
          let ne = self.field.ne(pos);
          let sw = self.field.sw(pos);
          let se = self.field.se(pos);

          let mut check = |pos1: Pos, pos2: Pos| {
            if self.field.cell(pos1).get_players_point() == Some(self.player)
              && self.field.cell(pos2).get_players_point() == Some(self.player)
            {
              self
                .captures
                .push((vec![pos, pos1, pos2], self.player, self.field.moves_count()));
              true
            } else {
              false
            }
          };

          let _ = !check(s, e) && (check(s, se) || check(e, se));
          let _ = !check(e, n) && (check(e, ne) || check(n, ne));
          let _ = !check(n, w) && (check(n, nw) || check(w, nw));
          let _ = !check(w, s) && (check(w, sw) || check(s, sw));

          self.player = self.player.next();

          self.field_cache.clear();
        }
      }
      Message::Canvas(CanvasMessage::Undo) => {
        if let Some(player) = self.field.last_player() {
          self.player = player;
          self.field.undo();

          while self
            .captures
            .last()
            .map_or(false, |&(_, _, c)| c > self.field.moves_count())
          {
            self.captures.pop();
          }

          self.field_cache.clear();
        }
      }
    }

    Command::none()
  }

  fn view(&mut self) -> iced::Element<'_, Self::Message> {
    let score = Row::new()
      .push(Text::new(self.field.captured_count(Player::Red).to_string()).color(Color::from_rgb8(0xFF, 0x00, 0x00)))
      .push(Text::new(":"))
      .push(Text::new(self.field.captured_count(Player::Black).to_string()).color(Color::BLACK));

    let canvas = Canvas::new(self).height(Length::Fill).width(Length::Fill);
    let canvas_element = Element::<CanvasMessage>::from(canvas).map(Message::Canvas);

    let content = Row::new().push(canvas_element).push(score);

    Container::new(content).width(Length::Fill).height(Length::Fill).into()
  }
}

impl canvas::Program<CanvasMessage> for Game {
  fn update(
    &mut self,
    event: canvas::Event,
    bounds: Rectangle,
    cursor: canvas::Cursor,
  ) -> (canvas::event::Status, Option<CanvasMessage>) {
    match event {
      canvas::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
        let cursor_position = if let Some(position) = cursor.position_in(&bounds) {
          position
        } else {
          return (canvas::event::Status::Ignored, None);
        };

        let field_width = self.field.width();
        let field_height = self.field.height();
        let width = bounds
          .width
          .min(bounds.height / field_height as f32 * field_width as f32);
        let height = bounds
          .height
          .min(bounds.width / field_width as f32 * field_height as f32);
        let step_x = width / field_width as f32;
        let step_y = height / field_height as f32;
        let shift = Vector::new(
          ((bounds.width - width) / 2.0).round(),
          ((bounds.height - height) / 2.0).round(),
        );
        let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

        let point = cursor_position - shift;
        if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
          let point = point - cursor_shift;
          let x = (point.x / step_x).round() as u32;
          let y = (point.y / step_y).round() as u32;
          (
            canvas::event::Status::Captured,
            Some(CanvasMessage::PutPoint(self.field.to_pos(x, y))),
          )
        } else {
          (canvas::event::Status::Captured, None)
        }
      }
      canvas::Event::Keyboard(keyboard::Event::KeyPressed {
        key_code: keyboard::KeyCode::Backspace,
        ..
      }) => (canvas::event::Status::Captured, Some(CanvasMessage::Undo)),
      _ => (canvas::event::Status::Ignored, None),
    }
  }

  fn draw(&self, bounds: Rectangle, cursor: canvas::Cursor) -> Vec<canvas::Geometry> {
    fn color(player: Player) -> Color {
      match player {
        Player::Red => Color::from_rgb8(0xFF, 0x00, 0x00),
        Player::Black => Color::BLACK,
      }
    }

    let field_width = self.field.width();
    let field_height = self.field.height();
    let width = bounds
      .width
      .min(bounds.height / field_height as f32 * field_width as f32);
    let height = bounds
      .height
      .min(bounds.width / field_width as f32 * field_height as f32);
    let step_x = width / field_width as f32;
    let step_y = height / field_height as f32;
    let shift = Vector::new(
      ((bounds.width - width) / 2.0).round(),
      ((bounds.height - height) / 2.0).round(),
    );
    let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

    let xy_to_point = |x: u32, y: u32| {
      let offset_x = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
      let offset_y = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
      Point::new(offset_x, offset_y) + shift
    };
    let pos_to_point = |pos: Pos| {
      let x = self.field.to_x(pos);
      let y = self.field.to_y(pos);
      xy_to_point(x, y)
    };

    let point_radius = width / field_width as f32 / 6.0;

    let field = self.field_cache.draw(bounds.size(), |frame| {
      let grid = canvas::Path::new(|path| {
        for x in 0..field_width {
          let offset = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
          path.move_to(Point::new(offset, 0.0) + shift);
          path.line_to(Point::new(offset, height) + shift);
        }
        for y in 0..field_height {
          let offset = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
          path.move_to(Point::new(0.0, offset) + shift);
          path.line_to(Point::new(width, offset) + shift);
        }
      });

      frame.stroke(
        &grid,
        canvas::Stroke {
          width: 1.0,
          color: Color::BLACK,
          ..canvas::Stroke::default()
        },
      );

      for &player in &[Player::Red, Player::Black] {
        let points = canvas::Path::new(|path| {
          for &pos in self
            .field
            .points_seq()
            .iter()
            .filter(|&&pos| self.field.cell(pos).is_players_point(player))
          {
            path.circle(pos_to_point(pos), point_radius)
          }
        });

        frame.fill(&points, color(player));
      }

      for (chain, player, _) in &self.captures {
        let path = canvas::Path::new(|path| {
          path.move_to(pos_to_point(chain[0]));
          for &pos in chain.iter().skip(1) {
            path.line_to(pos_to_point(pos));
          }
        });

        let mut color = color(*player);
        color.a = 0.5;

        frame.fill(&path, color);
      }

      if let Some(&pos) = self.field.points_seq().last() {
        let last_point = canvas::Path::new(|path| path.circle(pos_to_point(pos), point_radius * 1.5));

        let color = color(self.field.cell(pos).get_player());

        frame.stroke(
          &last_point,
          canvas::Stroke {
            width: 2.0,
            color,
            ..canvas::Stroke::default()
          },
        );
      }
    });

    let mut frame = canvas::Frame::new(bounds.size());

    if let Some(point) = cursor.position().and_then(|cursor_position| {
      let point = cursor_position - shift;
      if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
        let point = point - cursor_shift;
        let x = (point.x / step_x).round() as u32;
        let y = (point.y / step_y).round() as u32;
        let pos = self.field.to_pos(x, y);
        if self.field.is_putting_allowed(pos) {
          Some(xy_to_point(x, y))
        } else {
          None
        }
      } else {
        None
      }
    }) {
      let cursor_point = canvas::Path::new(|path| path.circle(point, point_radius));

      let mut color = color(self.player);
      color.a = 0.5;

      frame.fill(&cursor_point, color);
    }

    vec![field, frame.into_geometry()]
  }
}
<|endoftext|>


<commit_before>//! Elements of the WebAssembly binary format.

use crate::rust::{fmt, vec::Vec, format, string::String};
use crate::io;

macro_rules! buffered_read {
	($buffer_size: expr, $length: expr, $reader: expr) => {
		{
			let mut vec_buf = Vec::new();
			let mut total_read = 0;
			let mut buf = [0u8; $buffer_size];
			while total_read < $length {
				let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read };
				$reader.read(&mut buf[0..next_to_read])?;
				vec_buf.extend_from_slice(&buf[0..next_to_read]);
				total_read += next_to_read;
			}
			vec_buf
		}
	}
}

mod primitives;
mod module;
mod section;
mod types;
mod import_entry;
mod export_entry;
mod global_entry;
mod ops;
mod func;
mod segment;
mod index_map;
mod name_section;
mod reloc_section;

pub use self::module::{Module, peek_size, ImportCountType};
pub use self::section::{
	Section, FunctionSection, CodeSection, MemorySection, DataSection,
	ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection,
	TableSection, CustomSection,
};
pub use self::import_entry::{ImportEntry, ResizableLimits, MemoryType, TableType, GlobalType, External};
pub use self::export_entry::{ExportEntry, Internal};
pub use self::global_entry::GlobalEntry;
pub use self::primitives::{
	VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64,
	Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter,
};
pub use self::types::{Type, ValueType, BlockType, FunctionType, TableElementType};
pub use self::ops::{Instruction, Instructions, InitExpr, opcodes, BrTableData};

#[cfg(feature="atomics")]
pub use self::ops::AtomicsInstruction;

#[cfg(feature="simd")]
pub use self::ops::SimdInstruction;

#[cfg(feature="sign_ext")]
pub use self::ops::SignExtInstruction;

#[cfg(feature="bulk")]
pub use self::ops::BulkInstruction;

#[cfg(any(feature="simd", feature="atomics"))]
pub use self::ops::MemArg;

pub use self::func::{Func, FuncBody, Local};
pub use self::segment::{ElementSegment, DataSegment};
pub use self::index_map::IndexMap;
pub use self::name_section::{
	NameMap, NameSection, ModuleNameSubsection, FunctionNameSubsection,
	LocalNameSubsection,
};
pub use self::reloc_section::{
	RelocSection, RelocationEntry,
};

/// Deserialization from serial i/o.
pub trait Deserialize : Sized {
	/// Serialization error produced by deserialization routine.
	type Error: From<io::Error>;
	/// Deserialize type from serial i/o
	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
}

/// Serialization to serial i/o. Takes self by value to consume less memory
/// (parity-wasm IR is being partially freed by filling the result buffer).
pub trait Serialize {
	/// Serialization error produced by serialization routine.
	type Error: From<io::Error>;
	/// Serialize type to serial i/o
	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
}

/// Deserialization/serialization error
#[derive(Debug, Clone)]
pub enum Error {
	/// Unexpected end of input.
	UnexpectedEof,
	/// Invalid magic.
	InvalidMagic,
	/// Unsupported version.
	UnsupportedVersion(u32),
	/// Inconsistence between declared and actual length.
	InconsistentLength {
		/// Expected length of the definition.
		expected: usize,
		/// Actual length of the definition.
		actual: usize
	},
	/// Other static error.
	Other(&'static str),
	/// Other allocated error.
	HeapOther(String),
	/// Invalid/unknown value type declaration.
	UnknownValueType(i8),
	/// Invalid/unknown table element type declaration.
	UnknownTableElementType(i8),
	/// Non-utf8 string.
	NonUtf8String,
	/// Unknown external kind code.
	UnknownExternalKind(u8),
	/// Unknown internal kind code.
	UnknownInternalKind(u8),
	/// Unknown opcode encountered.
	UnknownOpcode(u8),
	#[cfg(feature="simd")]
	/// Unknown SIMD opcode encountered.
	UnknownSimdOpcode(u32),
	/// Invalid VarUint1 value.
	InvalidVarUint1(u8),
	/// Invalid VarInt32 value.
	InvalidVarInt32,
	/// Invalid VarInt64 value.
	InvalidVarInt64,
	/// Invalid VarUint32 value.
	InvalidVarUint32,
	/// Invalid VarUint64 value.
	InvalidVarUint64,
	/// Inconsistent metadata.
	InconsistentMetadata,
	/// Invalid section id.
	InvalidSectionId(u8),
	/// Sections are out of order.
	SectionsOutOfOrder,
	/// Duplicated sections.
	DuplicatedSections(u8),
	/// Invalid memory reference (should be 0).
	InvalidMemoryReference(u8),
	/// Invalid table reference (should be 0).
	InvalidTableReference(u8),
	/// Invalid value used for flags in limits type.
	InvalidLimitsFlags(u8),
	/// Unknown function form (should be 0x60).
	UnknownFunctionForm(u8),
	/// Invalid varint7 (should be in -64..63 range).
	InvalidVarInt7(u8),
	/// Number of function body entries and signatures does not match.
	InconsistentCode,
	/// Only flags 0, 1, and 2 are accepted on segments.
	InvalidSegmentFlags(u32),
	/// Sum of counts of locals is greater than 2^32.
	TooManyLocals,
	/// Duplicated name subsections.
	DuplicatedNameSubsections(u8),
	/// Unknown name subsection type.
	UnknownNameSubsectionType(u8),
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Error::UnexpectedEof => write!(f, "Unexpected end of input"),
			Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
			Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
			Error::InconsistentLength { expected, actual } => {
				write!(f, "Expected length {}, found {}", expected, actual)
			}
			Error::Other(msg) => write!(f, "{}", msg),
			Error::HeapOther(ref msg) => write!(f, "{}", msg),
			Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
			Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
			Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
			Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
			Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
			Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
			#[cfg(feature="simd")]
			Error::UnknownSimdOpcode(opcode) => write!(f, "Unknown SIMD opcode {}", opcode),
			Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
			Error::InvalidVarInt7(val) => write!(f, "Not a signed 7-bit integer: {}", val),
			Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
			Error::InvalidVarUint32 => write!(f, "Not an unsigned 32-bit integer"),
			Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
			Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"),
			Error::InconsistentMetadata =>  write!(f, "Inconsistent metadata"),
			Error::InvalidSectionId(ref id) =>  write!(f, "Invalid section id: {}", id),
			Error::SectionsOutOfOrder =>  write!(f, "Sections out of order"),
			Error::DuplicatedSections(ref id) =>  write!(f, "Duplicated sections ({})", id),
			Error::InvalidMemoryReference(ref mem_ref) =>  write!(f, "Invalid memory reference ({})", mem_ref),
			Error::InvalidTableReference(ref table_ref) =>  write!(f, "Invalid table reference ({})", table_ref),
			Error::InvalidLimitsFlags(ref flags) =>  write!(f, "Invalid limits flags ({})", flags),
			Error::UnknownFunctionForm(ref form) =>  write!(f, "Unknown function form ({})", form),
			Error::InconsistentCode =>  write!(f, "Number of function body entries and signatures does not match"),
			Error::InvalidSegmentFlags(n) =>  write!(f, "Invalid segment flags: {}", n),
			Error::TooManyLocals => write!(f, "Too many locals"),
			Error::DuplicatedNameSubsections(n) =>  write!(f, "Duplicated name subsections: {}", n),
			Error::UnknownNameSubsectionType(n) => write!(f, "Unknown subsection type: {}", n),
		}
	}
}

#[cfg(feature = "std")]
impl ::std::error::Error for Error {
	fn description(&self) -> &str {
		match *self {
			Error::UnexpectedEof => "Unexpected end of input",
			Error::InvalidMagic => "Invalid magic number at start of file",
			Error::UnsupportedVersion(_) => "Unsupported wasm version",
			Error::InconsistentLength { .. } => "Inconsistent length",
			Error::Other(msg) => msg,
			Error::HeapOther(ref msg) => &msg[..],
			Error::UnknownValueType(_) => "Invalid or unknown value type",
			Error::UnknownTableElementType(_) => "Unknown table element type",
			Error::NonUtf8String => "Non-UTF-8 string",
			Error::UnknownExternalKind(_) => "Unknown external kind",
			Error::UnknownInternalKind(_) => "Unknown internal kind",
			Error::UnknownOpcode(_) => "Unknown opcode",
			#[cfg(feature="simd")]
			Error::UnknownSimdOpcode(_) => "Unknown SIMD opcode",
			Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
			Error::InvalidVarInt32 => "Not a signed 32-bit integer",
			Error::InvalidVarInt7(_) => "Not a signed 7-bit integer",
			Error::InvalidVarUint32 => "Not an unsigned 32-bit integer",
			Error::InvalidVarInt64 => "Not a signed 64-bit integer",
			Error::InvalidVarUint64 => "Not an unsigned 64-bit integer",
			Error::InconsistentMetadata => "Inconsistent metadata",
			Error::InvalidSectionId(_) =>  "Invalid section id",
			Error::SectionsOutOfOrder =>  "Sections out of order",
			Error::DuplicatedSections(_) =>  "Duplicated section",
			Error::InvalidMemoryReference(_) =>  "Invalid memory reference",
			Error::InvalidTableReference(_) =>  "Invalid table reference",
			Error::InvalidLimitsFlags(_) => "Invalid limits flags",
			Error::UnknownFunctionForm(_) =>  "Unknown function form",
			Error::InconsistentCode =>  "Number of function body entries and signatures does not match",
			Error::InvalidSegmentFlags(_) =>  "Invalid segment flags",
			Error::TooManyLocals => "Too many locals",
			Error::DuplicatedNameSubsections(_) =>  "Duplicated name subsections",
			Error::UnknownNameSubsectionType(_) => "Unknown name subsections type",
		}
	}
}

impl From<io::Error> for Error {
	fn from(err: io::Error) -> Self {
		Error::HeapOther(format!("I/O Error: {:?}", err))
	}
}

/// Unparsed part of the module/section.
pub struct Unparsed(pub Vec<u8>);

impl Deserialize for Unparsed {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let len = VarUint32::deserialize(reader)?.into();
		let mut vec = vec![0u8; len];
		reader.read(&mut vec[..])?;
		Ok(Unparsed(vec))
	}
}

impl From<Unparsed> for Vec<u8> {
	fn from(u: Unparsed) -> Vec<u8> {
		u.0
	}
}

/// Deserialize deserializable type from buffer.
pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> {
	let mut reader = io::Cursor::new(contents);
	let result = T::deserialize(&mut reader)?;
	if reader.position() != contents.len() {
		// It's a TrailingData, since if there is not enough data then
		// UnexpectedEof must have been returned earlier in T::deserialize.
		return Err(io::Error::TrailingData.into())
	}
	Ok(result)
}

/// Create buffer with serialized value.
pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
	let mut buf = Vec::new();
	val.serialize(&mut buf)?;
	Ok(buf)
}

/// Deserialize module from the file.
#[cfg(feature = "std")]
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
	let mut f = ::std::fs::File::open(p)
		.map_err(|e| Error::HeapOther(format!("Can't read from the file: {:?}", e)))?;

	Module::deserialize(&mut f)
}

/// Serialize module to the file
#[cfg(feature = "std")]
pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error> {
	let mut io = ::std::fs::File::create(p)
		.map_err(|e|
			Error::HeapOther(format!("Can't create the file: {:?}", e))
		)?;

	module.serialize(&mut io)?;
	Ok(())
}
<commit_msg>Add from trait for errors returned by parse_names/parse_reloc<commit_after>//! Elements of the WebAssembly binary format.

use crate::rust::{fmt, vec::Vec, format, string::String};
use crate::io;

macro_rules! buffered_read {
	($buffer_size: expr, $length: expr, $reader: expr) => {
		{
			let mut vec_buf = Vec::new();
			let mut total_read = 0;
			let mut buf = [0u8; $buffer_size];
			while total_read < $length {
				let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read };
				$reader.read(&mut buf[0..next_to_read])?;
				vec_buf.extend_from_slice(&buf[0..next_to_read]);
				total_read += next_to_read;
			}
			vec_buf
		}
	}
}

mod primitives;
mod module;
mod section;
mod types;
mod import_entry;
mod export_entry;
mod global_entry;
mod ops;
mod func;
mod segment;
mod index_map;
mod name_section;
mod reloc_section;

pub use self::module::{Module, peek_size, ImportCountType};
pub use self::section::{
	Section, FunctionSection, CodeSection, MemorySection, DataSection,
	ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection,
	TableSection, CustomSection,
};
pub use self::import_entry::{ImportEntry, ResizableLimits, MemoryType, TableType, GlobalType, External};
pub use self::export_entry::{ExportEntry, Internal};
pub use self::global_entry::GlobalEntry;
pub use self::primitives::{
	VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64,
	Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter,
};
pub use self::types::{Type, ValueType, BlockType, FunctionType, TableElementType};
pub use self::ops::{Instruction, Instructions, InitExpr, opcodes, BrTableData};

#[cfg(feature="atomics")]
pub use self::ops::AtomicsInstruction;

#[cfg(feature="simd")]
pub use self::ops::SimdInstruction;

#[cfg(feature="sign_ext")]
pub use self::ops::SignExtInstruction;

#[cfg(feature="bulk")]
pub use self::ops::BulkInstruction;

#[cfg(any(feature="simd", feature="atomics"))]
pub use self::ops::MemArg;

pub use self::func::{Func, FuncBody, Local};
pub use self::segment::{ElementSegment, DataSegment};
pub use self::index_map::IndexMap;
pub use self::name_section::{
	NameMap, NameSection, ModuleNameSubsection, FunctionNameSubsection,
	LocalNameSubsection,
};
pub use self::reloc_section::{
	RelocSection, RelocationEntry,
};

/// Deserialization from serial i/o.
pub trait Deserialize : Sized {
	/// Serialization error produced by deserialization routine.
	type Error: From<io::Error>;
	/// Deserialize type from serial i/o
	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
}

/// Serialization to serial i/o. Takes self by value to consume less memory
/// (parity-wasm IR is being partially freed by filling the result buffer).
pub trait Serialize {
	/// Serialization error produced by serialization routine.
	type Error: From<io::Error>;
	/// Serialize type to serial i/o
	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
}

/// Deserialization/serialization error
#[derive(Debug, Clone)]
pub enum Error {
	/// Unexpected end of input.
	UnexpectedEof,
	/// Invalid magic.
	InvalidMagic,
	/// Unsupported version.
	UnsupportedVersion(u32),
	/// Inconsistence between declared and actual length.
	InconsistentLength {
		/// Expected length of the definition.
		expected: usize,
		/// Actual length of the definition.
		actual: usize
	},
	/// Other static error.
	Other(&'static str),
	/// Other allocated error.
	HeapOther(String),
	/// Invalid/unknown value type declaration.
	UnknownValueType(i8),
	/// Invalid/unknown table element type declaration.
	UnknownTableElementType(i8),
	/// Non-utf8 string.
	NonUtf8String,
	/// Unknown external kind code.
	UnknownExternalKind(u8),
	/// Unknown internal kind code.
	UnknownInternalKind(u8),
	/// Unknown opcode encountered.
	UnknownOpcode(u8),
	#[cfg(feature="simd")]
	/// Unknown SIMD opcode encountered.
	UnknownSimdOpcode(u32),
	/// Invalid VarUint1 value.
	InvalidVarUint1(u8),
	/// Invalid VarInt32 value.
	InvalidVarInt32,
	/// Invalid VarInt64 value.
	InvalidVarInt64,
	/// Invalid VarUint32 value.
	InvalidVarUint32,
	/// Invalid VarUint64 value.
	InvalidVarUint64,
	/// Inconsistent metadata.
	InconsistentMetadata,
	/// Invalid section id.
	InvalidSectionId(u8),
	/// Sections are out of order.
	SectionsOutOfOrder,
	/// Duplicated sections.
	DuplicatedSections(u8),
	/// Invalid memory reference (should be 0).
	InvalidMemoryReference(u8),
	/// Invalid table reference (should be 0).
	InvalidTableReference(u8),
	/// Invalid value used for flags in limits type.
	InvalidLimitsFlags(u8),
	/// Unknown function form (should be 0x60).
	UnknownFunctionForm(u8),
	/// Invalid varint7 (should be in -64..63 range).
	InvalidVarInt7(u8),
	/// Number of function body entries and signatures does not match.
	InconsistentCode,
	/// Only flags 0, 1, and 2 are accepted on segments.
	InvalidSegmentFlags(u32),
	/// Sum of counts of locals is greater than 2^32.
	TooManyLocals,
	/// Duplicated name subsections.
	DuplicatedNameSubsections(u8),
	/// Unknown name subsection type.
	UnknownNameSubsectionType(u8),
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Error::UnexpectedEof => write!(f, "Unexpected end of input"),
			Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
			Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
			Error::InconsistentLength { expected, actual } => {
				write!(f, "Expected length {}, found {}", expected, actual)
			}
			Error::Other(msg) => write!(f, "{}", msg),
			Error::HeapOther(ref msg) => write!(f, "{}", msg),
			Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
			Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
			Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
			Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
			Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
			Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
			#[cfg(feature="simd")]
			Error::UnknownSimdOpcode(opcode) => write!(f, "Unknown SIMD opcode {}", opcode),
			Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
			Error::InvalidVarInt7(val) => write!(f, "Not a signed 7-bit integer: {}", val),
			Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
			Error::InvalidVarUint32 => write!(f, "Not an unsigned 32-bit integer"),
			Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
			Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"),
			Error::InconsistentMetadata =>  write!(f, "Inconsistent metadata"),
			Error::InvalidSectionId(ref id) =>  write!(f, "Invalid section id: {}", id),
			Error::SectionsOutOfOrder =>  write!(f, "Sections out of order"),
			Error::DuplicatedSections(ref id) =>  write!(f, "Duplicated sections ({})", id),
			Error::InvalidMemoryReference(ref mem_ref) =>  write!(f, "Invalid memory reference ({})", mem_ref),
			Error::InvalidTableReference(ref table_ref) =>  write!(f, "Invalid table reference ({})", table_ref),
			Error::InvalidLimitsFlags(ref flags) =>  write!(f, "Invalid limits flags ({})", flags),
			Error::UnknownFunctionForm(ref form) =>  write!(f, "Unknown function form ({})", form),
			Error::InconsistentCode =>  write!(f, "Number of function body entries and signatures does not match"),
			Error::InvalidSegmentFlags(n) =>  write!(f, "Invalid segment flags: {}", n),
			Error::TooManyLocals => write!(f, "Too many locals"),
			Error::DuplicatedNameSubsections(n) =>  write!(f, "Duplicated name subsections: {}", n),
			Error::UnknownNameSubsectionType(n) => write!(f, "Unknown subsection type: {}", n),
		}
	}
}

#[cfg(feature = "std")]
impl ::std::error::Error for Error {
	fn description(&self) -> &str {
		match *self {
			Error::UnexpectedEof => "Unexpected end of input",
			Error::InvalidMagic => "Invalid magic number at start of file",
			Error::UnsupportedVersion(_) => "Unsupported wasm version",
			Error::InconsistentLength { .. } => "Inconsistent length",
			Error::Other(msg) => msg,
			Error::HeapOther(ref msg) => &msg[..],
			Error::UnknownValueType(_) => "Invalid or unknown value type",
			Error::UnknownTableElementType(_) => "Unknown table element type",
			Error::NonUtf8String => "Non-UTF-8 string",
			Error::UnknownExternalKind(_) => "Unknown external kind",
			Error::UnknownInternalKind(_) => "Unknown internal kind",
			Error::UnknownOpcode(_) => "Unknown opcode",
			#[cfg(feature="simd")]
			Error::UnknownSimdOpcode(_) => "Unknown SIMD opcode",
			Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
			Error::InvalidVarInt32 => "Not a signed 32-bit integer",
			Error::InvalidVarInt7(_) => "Not a signed 7-bit integer",
			Error::InvalidVarUint32 => "Not an unsigned 32-bit integer",
			Error::InvalidVarInt64 => "Not a signed 64-bit integer",
			Error::InvalidVarUint64 => "Not an unsigned 64-bit integer",
			Error::InconsistentMetadata => "Inconsistent metadata",
			Error::InvalidSectionId(_) =>  "Invalid section id",
			Error::SectionsOutOfOrder =>  "Sections out of order",
			Error::DuplicatedSections(_) =>  "Duplicated section",
			Error::InvalidMemoryReference(_) =>  "Invalid memory reference",
			Error::InvalidTableReference(_) =>  "Invalid table reference",
			Error::InvalidLimitsFlags(_) => "Invalid limits flags",
			Error::UnknownFunctionForm(_) =>  "Unknown function form",
			Error::InconsistentCode =>  "Number of function body entries and signatures does not match",
			Error::InvalidSegmentFlags(_) =>  "Invalid segment flags",
			Error::TooManyLocals => "Too many locals",
			Error::DuplicatedNameSubsections(_) =>  "Duplicated name subsections",
			Error::UnknownNameSubsectionType(_) => "Unknown name subsections type",
		}
	}
}

impl From<io::Error> for Error {
	fn from(err: io::Error) -> Self {
		Error::HeapOther(format!("I/O Error: {:?}", err))
	}
}

// These are emitted by section parsers, such as `parse_names` and `parse_reloc`.
impl From<(Vec<(usize, Error)>, Module)> for Error {
	fn from(err: (Vec<(usize, Error)>, Module)) -> Self {
		let ret = err.0.iter()
			.fold(
				String::new(),
				|acc, item| acc + &format!("In section {}: {}\n", item.0, item.1)
			);
		Error::HeapOther(ret)
	}
}

/// Unparsed part of the module/section.
pub struct Unparsed(pub Vec<u8>);

impl Deserialize for Unparsed {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let len = VarUint32::deserialize(reader)?.into();
		let mut vec = vec![0u8; len];
		reader.read(&mut vec[..])?;
		Ok(Unparsed(vec))
	}
}

impl From<Unparsed> for Vec<u8> {
	fn from(u: Unparsed) -> Vec<u8> {
		u.0
	}
}

/// Deserialize deserializable type from buffer.
pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> {
	let mut reader = io::Cursor::new(contents);
	let result = T::deserialize(&mut reader)?;
	if reader.position() != contents.len() {
		// It's a TrailingData, since if there is not enough data then
		// UnexpectedEof must have been returned earlier in T::deserialize.
		return Err(io::Error::TrailingData.into())
	}
	Ok(result)
}

/// Create buffer with serialized value.
pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
	let mut buf = Vec::new();
	val.serialize(&mut buf)?;
	Ok(buf)
}

/// Deserialize module from the file.
#[cfg(feature = "std")]
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
	let mut f = ::std::fs::File::open(p)
		.map_err(|e| Error::HeapOther(format!("Can't read from the file: {:?}", e)))?;

	Module::deserialize(&mut f)
}

/// Serialize module to the file
#[cfg(feature = "std")]
pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error> {
	let mut io = ::std::fs::File::create(p)
		.map_err(|e|
			Error::HeapOther(format!("Can't create the file: {:?}", e))
		)?;

	module.serialize(&mut io)?;
	Ok(())
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package finding.", why),
    });
}

#[derive(Serialize, Deserialize)]
struct Package {
    name: String,
    version: String,
    crc32: String,
    url: String,
    dependencies: Vec<Package>
}

#[derive(Serialize, Deserialize)]
struct PackageList {
    packages: Vec<Package>,
    last_updated: Date
}

pub fn update_package() -> bool {

}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, &str> {
    let mut list = custom_try!(match File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = reader.read_to_string();
    let package_list: PackageList = custom_try!(serde_json::from_str(buffer));

    let filtered = package_list.packages.into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err("Package not found"),
        _ => Ok(filtered)
    }
}

<commit_msg>Fix typos<commit_after>use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package finding.", why),
    });
}

#[derive(Serialize, Deserialize)]
struct Package {
    name: String,
    version: String,
    crc32: String,
    url: String,
    dependencies: Vec<Package>
}

#[derive(Serialize, Deserialize)]
struct PackageList {
    packages: Vec<Package>,
    last_updated: Date
}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, &str> {
    let mut list = custom_try!(File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = reader.read_to_string();
    let package_list: PackageList = custom_try!(serde_json::from_str(buffer));

    let filtered = package_list.packages.into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err("Package not found"),
        _ => Ok(filtered)
    }
}

<|endoftext|>


<commit_before>//! Zero-capacity channel.
//!
//! This kind of channel is also known as *rendezvous* channel.

use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::mem::{self, ManuallyDrop};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Instant;

use parking_lot::Mutex;

use internal::channel::RecvNonblocking;
use internal::context;
use internal::select::{Operation, Select, SelectHandle, Token};
use internal::utils::Backoff;
use internal::waker::Waker;

/// A pointer to a packet.
pub type ZeroToken = usize;

/// A slot for passing one message from a sender to a receiver.
struct Packet<T> {
    /// Equals `true` if the packet is allocated on the stack.
    on_stack: bool,

    /// Equals `true` once the packet is ready for reading or writing.
    ready: AtomicBool,

    /// The message.
    msg: ManuallyDrop<UnsafeCell<T>>,
}

impl<T> Packet<T> {
    /// Creates an empty packet on the stack.
    fn empty_on_stack() -> Packet<T> {
        Packet {
            on_stack: true,
            ready: AtomicBool::new(false),
            msg: unsafe { ManuallyDrop::new(UnsafeCell::new(mem::uninitialized())) },
        }
    }

    /// Creates an empty packet on the heap.
    fn empty_on_heap() -> Box<Packet<T>> {
        Box::new(Packet {
            on_stack: false,
            ready: AtomicBool::new(false),
            msg: unsafe { ManuallyDrop::new(UnsafeCell::new(mem::uninitialized())) },
        })
    }

    /// Creates a packet on the stack, containing a message.
    fn message_on_stack(msg: T) -> Packet<T> {
        Packet {
            on_stack: true,
            ready: AtomicBool::new(false),
            msg: ManuallyDrop::new(UnsafeCell::new(msg)),
        }
    }

    /// Waits until the packet becomes ready for reading or writing.
    fn wait_ready(&self) {
        let backoff = &mut Backoff::new();
        while !self.ready.load(Ordering::Acquire) {
            backoff.step();
        }
    }
}

/// Inner representation of a zero-capacity channel.
struct Inner {
    /// Senders waiting to pair up with a receive operation.
    senders: Waker,

    /// Receivers waiting to pair up with a send operation.
    receivers: Waker,

    /// Equals `true` when the channel is closed.
    is_closed: bool,
}

/// Zero-capacity channel.
pub struct Channel<T> {
    /// Inner representation of the channel.
    inner: Mutex<Inner>,

    /// Indicates that dropping a `Channel<T>` may drop values of type `T`.
    _marker: PhantomData<T>,
}

impl<T> Channel<T> {
    /// Constructs a new zero-capacity channel.
    pub fn new() -> Self {
        Channel {
            inner: Mutex::new(Inner {
                senders: Waker::new(),
                receivers: Waker::new(),
                is_closed: false,
            }),
            _marker: PhantomData,
        }
    }

    /// Returns a receiver handle to the channel.
    pub fn receiver(&self) -> Receiver<T> {
        Receiver(self)
    }

    /// Returns a sender handle to the channel.
    pub fn sender(&self) -> Sender<T> {
        Sender(self)
    }

    /// Attempts to reserve a slot for sending a message.
    fn start_send(&self, token: &mut Token, short_pause: bool) -> bool {
        let oper = Operation::hook(token);

        {
            let mut inner = self.inner.lock();

            // If there's a waiting receiver, pair up with it.
            if let Some(operation) = inner.receivers.wake_one() {
                token.zero = operation.packet;
                return true;
            }

            if !short_pause {
                return false;
            }

            // Register this send operation so that another receiver can pair up with it.
            context::current_reset();
            let packet = Box::into_raw(Packet::<T>::empty_on_heap());
            inner.senders.register_with_packet(oper, packet as usize);
        }

        // Yield to give receivers a chance to pair up with this operation.
        thread::yield_now();

        let sel = match context::current_try_select(Select::Aborted) {
            Ok(()) => Select::Aborted,
            Err(s) => s,
        };

        match sel {
            Select::Waiting | Select::Closed => unreachable!(),
            Select::Aborted => {
                // Unregister and destroy the packet.
                let operation = self.inner.lock().senders.unregister(oper).unwrap();
                unsafe {
                    drop(Box::from_raw(operation.packet as *mut Packet<T>));
                }
                false
            },
            Select::Operation(_) => {
                // Success! A receiver has paired up with this operation.
                token.zero = context::current_wait_packet();
                true
            },
        }
    }

    /// Writes a message into the packet.
    pub unsafe fn write(&self, token: &mut Token, msg: T) {
        let packet = &*(token.zero as *const Packet<T>);
        packet.msg.get().write(msg);
        packet.ready.store(true, Ordering::Release);
    }

    /// Attempts to pair up with a sender.
    fn start_recv(&self, token: &mut Token, short_pause: bool) -> bool {
        let oper = Operation::hook(token);
        {
            let mut inner = self.inner.lock();

            // If there's a waiting sender, pair up with it.
            if let Some(operation) = inner.senders.wake_one() {
                token.zero = operation.packet;
                return true;
            } else if inner.is_closed {
                token.zero = 0;
                return true;
            }

            if !short_pause {
                return false;
            }

            // Register this receive operation so that another sender can pair up with it.
            context::current_reset();
            let packet = Box::into_raw(Packet::<T>::empty_on_heap());
            inner.receivers.register_with_packet(oper, packet as usize);
        }

        // Yield to give senders a chance to pair up with this operation.
        thread::yield_now();

        let sel = match context::current_try_select(Select::Aborted) {
            Ok(()) => Select::Aborted,
            Err(s) => s,
        };

        match sel {
            Select::Waiting => unreachable!(),
            Select::Aborted => {
                // Unregister and destroy the packet.
                let operation = self.inner.lock().receivers.unregister(oper).unwrap();
                unsafe {
                    drop(Box::from_raw(operation.packet as *mut Packet<T>));
                }
                false
            },
            Select::Closed => {
                // Unregister and destroy the packet.
                let operation = self.inner.lock().receivers.unregister(oper).unwrap();
                unsafe {
                    drop(Box::from_raw(operation.packet as *mut Packet<T>));
                }

                // All senders have just been dropped.
                token.zero = 0;
                true
            },
            Select::Operation(_) => {
                // Success! A sender has paired up with this operation.
                token.zero = context::current_wait_packet();
                true
            },
        }
    }

    /// Reads a message from the packet.
    pub unsafe fn read(&self, token: &mut Token) -> Option<T> {
        // If there is no packet, the channel is closed.
        if token.zero == 0 {
            return None;
        }

        let packet = &*(token.zero as *const Packet<T>);

        if packet.on_stack {
            // The message has been in the packet from the beginning, so there is no need to wait
            // for it. However, after reading the message, we need to set `ready` to `true` in
            // order to signal that the packet can be destroyed.
            let msg = packet.msg.get().read();
            packet.ready.store(true, Ordering::Release);
            Some(msg)
        } else {
            // Wait until the message becomes available, then read it and destroy the
            // heap-allocated packet.
            packet.wait_ready();
            let msg = packet.msg.get().read();
            drop(Box::from_raw(packet as *const Packet<T> as *mut Packet<T>));
            Some(msg)
        }
    }

    /// Sends a message into the channel.
    pub fn send(&self, msg: T) {
        let token = &mut Token::default();
        let oper = Operation::hook(token);
        let packet;
        {
            let mut inner = self.inner.lock();

            // If there's a waiting receiver, pair up with it.
            if let Some(operation) = inner.receivers.wake_one() {
                token.zero = operation.packet;
                drop(inner);
                unsafe { self.write(token, msg); }
                return;
            }

            // Prepare for blocking until a receiver wakes us up.
            context::current_reset();
            packet = Packet::message_on_stack(msg);
            inner.senders.register_with_packet(
                oper,
                &packet as *const Packet<T> as usize,
            );
        }

        // Block the current thread.
        let sel = context::current_wait_until(None);

        match sel {
            Select::Waiting | Select::Aborted | Select::Closed => unreachable!(),
            Select::Operation(_) => {
                // Wait until the message is read, then drop the packet.
                packet.wait_ready();
            },
        }
    }

    /// Receives a message from the channel.
    pub fn recv(&self) -> Option<T> {
        let token = &mut Token::default();
        let oper = Operation::hook(token);
        let packet;
        {
            let mut inner = self.inner.lock();

            // If there's a waiting sender, pair up with it.
            if let Some(operation) = inner.senders.wake_one() {
                token.zero = operation.packet;
                drop(inner);
                unsafe { return self.read(token); }
            }

            if inner.is_closed {
                return None;
            }

            // Prepare for blocking until a sender wakes us up.
            context::current_reset();
            packet = Packet::<T>::empty_on_stack();
            inner.receivers.register_with_packet(
                oper,
                &packet as *const Packet<T> as usize,
            );
        }

        // Block the current thread.
        let sel = context::current_wait_until(None);

        match sel {
            Select::Waiting | Select::Aborted => unreachable!(),
            Select::Closed => {
                self.inner.lock().receivers.unregister(oper).unwrap();
                None
            },
            Select::Operation(_) => {
                // Wait until the message is provided, then read it.
                packet.wait_ready();
                unsafe { Some(packet.msg.get().read()) }
            },
        }
    }

    /// Attempts to receive a message without blocking.
    pub fn recv_nonblocking(&self) -> RecvNonblocking<T> {
        let token = &mut Token::default();
        let mut inner = self.inner.lock();

        // If there's a waiting sender, pair up with it.
        if let Some(operation) = inner.senders.wake_one() {
            token.zero = operation.packet;
            drop(inner);

            match unsafe { self.read(token) } {
                None => RecvNonblocking::Closed,
                Some(msg) => RecvNonblocking::Message(msg),
            }
        } else if inner.is_closed {
            RecvNonblocking::Closed
        } else {
            RecvNonblocking::Empty
        }
    }

    /// Closes the channel and wakes up all blocked receivers.
    pub fn close(&self) -> bool {
        let mut inner = self.inner.lock();

        if inner.is_closed {
            false
        } else {
            inner.is_closed = true;
            inner.receivers.close();
            true
        }
    }

    /// Returns the current number of messages inside the channel.
    pub fn len(&self) -> usize {
        0
    }

    /// Returns the capacity of the channel.
    pub fn capacity(&self) -> Option<usize> {
        Some(0)
    }

    /// Returns `true` if the channel is empty.
    pub fn is_empty(&self) -> bool {
        true
    }

    /// Returns `true` if the channel is full.
    pub fn is_full(&self) -> bool {
        true
    }
}

/// Receiver handle to a channel.
pub struct Receiver<'a, T: 'a>(&'a Channel<T>);

/// Sender handle to a channel.
pub struct Sender<'a, T: 'a>(&'a Channel<T>);

impl<'a, T> SelectHandle for Receiver<'a, T> {
    fn try(&self, token: &mut Token) -> bool {
        self.0.start_recv(token, false)
    }

    fn retry(&self, token: &mut Token) -> bool {
        self.0.start_recv(token, true)
    }

    fn deadline(&self) -> Option<Instant> {
        None
    }

    fn register(&self, _token: &mut Token, oper: Operation) -> bool {
        let packet = Box::into_raw(Packet::<T>::empty_on_heap());

        let mut inner = self.0.inner.lock();
        inner.receivers.register_with_packet(oper, packet as usize);
        !inner.senders.can_wake_one() && !inner.is_closed
    }

    fn unregister(&self, oper: Operation) {
        if let Some(operation) = self.0.inner.lock().receivers.unregister(oper) {
            unsafe {
                drop(Box::from_raw(operation.packet as *mut Packet<T>));
            }
        }
    }

    fn accept(&self, token: &mut Token) -> bool {
        token.zero = context::current_wait_packet();
        true
    }
}

impl<'a, T> SelectHandle for Sender<'a, T> {
    fn try(&self, token: &mut Token) -> bool {
        self.0.start_send(token, false)
    }

    fn retry(&self, token: &mut Token) -> bool {
        self.0.start_send(token, true)
    }

    fn deadline(&self) -> Option<Instant> {
        None
    }

    fn register(&self, _token: &mut Token, oper: Operation) -> bool {
        let packet = Box::into_raw(Packet::<T>::empty_on_heap());

        let mut inner = self.0.inner.lock();
        inner.senders.register_with_packet(oper, packet as usize);
        !inner.receivers.can_wake_one()
    }

    fn unregister(&self, oper: Operation) {
        if let Some(operation) = self.0.inner.lock().senders.unregister(oper) {
            unsafe {
                drop(Box::from_raw(operation.packet as *mut Packet<T>));
            }
        }
    }

    fn accept(&self, token: &mut Token) -> bool {
        token.zero = context::current_wait_packet();
        true
    }
}
<commit_msg>Eliminate calls to mem::uninitialized<commit_after>//! Zero-capacity channel.
//!
//! This kind of channel is also known as *rendezvous* channel.

use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Instant;

use parking_lot::Mutex;

use internal::channel::RecvNonblocking;
use internal::context;
use internal::select::{Operation, Select, SelectHandle, Token};
use internal::utils::Backoff;
use internal::waker::Waker;

/// A pointer to a packet.
pub type ZeroToken = usize;

/// A slot for passing one message from a sender to a receiver.
struct Packet<T> {
    /// Equals `true` if the packet is allocated on the stack.
    on_stack: bool,

    /// Equals `true` once the packet is ready for reading or writing.
    ready: AtomicBool,

    /// The message.
    msg: UnsafeCell<Option<T>>,
}

impl<T> Packet<T> {
    /// Creates an empty packet on the stack.
    fn empty_on_stack() -> Packet<T> {
        Packet {
            on_stack: true,
            ready: AtomicBool::new(false),
            msg: UnsafeCell::new(None),
        }
    }

    /// Creates an empty packet on the heap.
    fn empty_on_heap() -> Box<Packet<T>> {
        Box::new(Packet {
            on_stack: false,
            ready: AtomicBool::new(false),
            msg: UnsafeCell::new(None),
        })
    }

    /// Creates a packet on the stack, containing a message.
    fn message_on_stack(msg: T) -> Packet<T> {
        Packet {
            on_stack: true,
            ready: AtomicBool::new(false),
            msg: UnsafeCell::new(Some(msg)),
        }
    }

    /// Waits until the packet becomes ready for reading or writing.
    fn wait_ready(&self) {
        let backoff = &mut Backoff::new();
        while !self.ready.load(Ordering::Acquire) {
            backoff.step();
        }
    }
}

/// Inner representation of a zero-capacity channel.
struct Inner {
    /// Senders waiting to pair up with a receive operation.
    senders: Waker,

    /// Receivers waiting to pair up with a send operation.
    receivers: Waker,

    /// Equals `true` when the channel is closed.
    is_closed: bool,
}

/// Zero-capacity channel.
pub struct Channel<T> {
    /// Inner representation of the channel.
    inner: Mutex<Inner>,

    /// Indicates that dropping a `Channel<T>` may drop values of type `T`.
    _marker: PhantomData<T>,
}

impl<T> Channel<T> {
    /// Constructs a new zero-capacity channel.
    pub fn new() -> Self {
        Channel {
            inner: Mutex::new(Inner {
                senders: Waker::new(),
                receivers: Waker::new(),
                is_closed: false,
            }),
            _marker: PhantomData,
        }
    }

    /// Returns a receiver handle to the channel.
    pub fn receiver(&self) -> Receiver<T> {
        Receiver(self)
    }

    /// Returns a sender handle to the channel.
    pub fn sender(&self) -> Sender<T> {
        Sender(self)
    }

    /// Attempts to reserve a slot for sending a message.
    fn start_send(&self, token: &mut Token, short_pause: bool) -> bool {
        let oper = Operation::hook(token);

        {
            let mut inner = self.inner.lock();

            // If there's a waiting receiver, pair up with it.
            if let Some(operation) = inner.receivers.wake_one() {
                token.zero = operation.packet;
                return true;
            }

            if !short_pause {
                return false;
            }

            // Register this send operation so that another receiver can pair up with it.
            context::current_reset();
            let packet = Box::into_raw(Packet::<T>::empty_on_heap());
            inner.senders.register_with_packet(oper, packet as usize);
        }

        // Yield to give receivers a chance to pair up with this operation.
        thread::yield_now();

        let sel = match context::current_try_select(Select::Aborted) {
            Ok(()) => Select::Aborted,
            Err(s) => s,
        };

        match sel {
            Select::Waiting | Select::Closed => unreachable!(),
            Select::Aborted => {
                // Unregister and destroy the packet.
                let operation = self.inner.lock().senders.unregister(oper).unwrap();
                unsafe {
                    drop(Box::from_raw(operation.packet as *mut Packet<T>));
                }
                false
            },
            Select::Operation(_) => {
                // Success! A receiver has paired up with this operation.
                token.zero = context::current_wait_packet();
                true
            },
        }
    }

    /// Writes a message into the packet.
    pub unsafe fn write(&self, token: &mut Token, msg: T) {
        let packet = &*(token.zero as *const Packet<T>);
        packet.msg.get().write(Some(msg));
        packet.ready.store(true, Ordering::Release);
    }

    /// Attempts to pair up with a sender.
    fn start_recv(&self, token: &mut Token, short_pause: bool) -> bool {
        let oper = Operation::hook(token);
        {
            let mut inner = self.inner.lock();

            // If there's a waiting sender, pair up with it.
            if let Some(operation) = inner.senders.wake_one() {
                token.zero = operation.packet;
                return true;
            } else if inner.is_closed {
                token.zero = 0;
                return true;
            }

            if !short_pause {
                return false;
            }

            // Register this receive operation so that another sender can pair up with it.
            context::current_reset();
            let packet = Box::into_raw(Packet::<T>::empty_on_heap());
            inner.receivers.register_with_packet(oper, packet as usize);
        }

        // Yield to give senders a chance to pair up with this operation.
        thread::yield_now();

        let sel = match context::current_try_select(Select::Aborted) {
            Ok(()) => Select::Aborted,
            Err(s) => s,
        };

        match sel {
            Select::Waiting => unreachable!(),
            Select::Aborted => {
                // Unregister and destroy the packet.
                let operation = self.inner.lock().receivers.unregister(oper).unwrap();
                unsafe {
                    drop(Box::from_raw(operation.packet as *mut Packet<T>));
                }
                false
            },
            Select::Closed => {
                // Unregister and destroy the packet.
                let operation = self.inner.lock().receivers.unregister(oper).unwrap();
                unsafe {
                    drop(Box::from_raw(operation.packet as *mut Packet<T>));
                }

                // All senders have just been dropped.
                token.zero = 0;
                true
            },
            Select::Operation(_) => {
                // Success! A sender has paired up with this operation.
                token.zero = context::current_wait_packet();
                true
            },
        }
    }

    /// Reads a message from the packet.
    pub unsafe fn read(&self, token: &mut Token) -> Option<T> {
        // If there is no packet, the channel is closed.
        if token.zero == 0 {
            return None;
        }

        let packet = &*(token.zero as *const Packet<T>);

        if packet.on_stack {
            // The message has been in the packet from the beginning, so there is no need to wait
            // for it. However, after reading the message, we need to set `ready` to `true` in
            // order to signal that the packet can be destroyed.
            let msg = packet.msg.get().replace(None).unwrap();
            packet.ready.store(true, Ordering::Release);
            Some(msg)
        } else {
            // Wait until the message becomes available, then read it and destroy the
            // heap-allocated packet.
            packet.wait_ready();
            let msg = packet.msg.get().replace(None).unwrap();
            drop(Box::from_raw(packet as *const Packet<T> as *mut Packet<T>));
            Some(msg)
        }
    }

    /// Sends a message into the channel.
    pub fn send(&self, msg: T) {
        let token = &mut Token::default();
        let oper = Operation::hook(token);
        let packet;
        {
            let mut inner = self.inner.lock();

            // If there's a waiting receiver, pair up with it.
            if let Some(operation) = inner.receivers.wake_one() {
                token.zero = operation.packet;
                drop(inner);
                unsafe { self.write(token, msg); }
                return;
            }

            // Prepare for blocking until a receiver wakes us up.
            context::current_reset();
            packet = Packet::message_on_stack(msg);
            inner.senders.register_with_packet(
                oper,
                &packet as *const Packet<T> as usize,
            );
        }

        // Block the current thread.
        let sel = context::current_wait_until(None);

        match sel {
            Select::Waiting | Select::Aborted | Select::Closed => unreachable!(),
            Select::Operation(_) => {
                // Wait until the message is read, then drop the packet.
                packet.wait_ready();
            },
        }
    }

    /// Receives a message from the channel.
    pub fn recv(&self) -> Option<T> {
        let token = &mut Token::default();
        let oper = Operation::hook(token);
        let packet;
        {
            let mut inner = self.inner.lock();

            // If there's a waiting sender, pair up with it.
            if let Some(operation) = inner.senders.wake_one() {
                token.zero = operation.packet;
                drop(inner);
                unsafe { return self.read(token); }
            }

            if inner.is_closed {
                return None;
            }

            // Prepare for blocking until a sender wakes us up.
            context::current_reset();
            packet = Packet::<T>::empty_on_stack();
            inner.receivers.register_with_packet(
                oper,
                &packet as *const Packet<T> as usize,
            );
        }

        // Block the current thread.
        let sel = context::current_wait_until(None);

        match sel {
            Select::Waiting | Select::Aborted => unreachable!(),
            Select::Closed => {
                self.inner.lock().receivers.unregister(oper).unwrap();
                None
            },
            Select::Operation(_) => {
                // Wait until the message is provided, then read it.
                packet.wait_ready();
                unsafe { Some(packet.msg.get().replace(None).unwrap()) }
            },
        }
    }

    /// Attempts to receive a message without blocking.
    pub fn recv_nonblocking(&self) -> RecvNonblocking<T> {
        let token = &mut Token::default();
        let mut inner = self.inner.lock();

        // If there's a waiting sender, pair up with it.
        if let Some(operation) = inner.senders.wake_one() {
            token.zero = operation.packet;
            drop(inner);

            match unsafe { self.read(token) } {
                None => RecvNonblocking::Closed,
                Some(msg) => RecvNonblocking::Message(msg),
            }
        } else if inner.is_closed {
            RecvNonblocking::Closed
        } else {
            RecvNonblocking::Empty
        }
    }

    /// Closes the channel and wakes up all blocked receivers.
    pub fn close(&self) -> bool {
        let mut inner = self.inner.lock();

        if inner.is_closed {
            false
        } else {
            inner.is_closed = true;
            inner.receivers.close();
            true
        }
    }

    /// Returns the current number of messages inside the channel.
    pub fn len(&self) -> usize {
        0
    }

    /// Returns the capacity of the channel.
    pub fn capacity(&self) -> Option<usize> {
        Some(0)
    }

    /// Returns `true` if the channel is empty.
    pub fn is_empty(&self) -> bool {
        true
    }

    /// Returns `true` if the channel is full.
    pub fn is_full(&self) -> bool {
        true
    }
}

/// Receiver handle to a channel.
pub struct Receiver<'a, T: 'a>(&'a Channel<T>);

/// Sender handle to a channel.
pub struct Sender<'a, T: 'a>(&'a Channel<T>);

impl<'a, T> SelectHandle for Receiver<'a, T> {
    fn try(&self, token: &mut Token) -> bool {
        self.0.start_recv(token, false)
    }

    fn retry(&self, token: &mut Token) -> bool {
        self.0.start_recv(token, true)
    }

    fn deadline(&self) -> Option<Instant> {
        None
    }

    fn register(&self, _token: &mut Token, oper: Operation) -> bool {
        let packet = Box::into_raw(Packet::<T>::empty_on_heap());

        let mut inner = self.0.inner.lock();
        inner.receivers.register_with_packet(oper, packet as usize);
        !inner.senders.can_wake_one() && !inner.is_closed
    }

    fn unregister(&self, oper: Operation) {
        if let Some(operation) = self.0.inner.lock().receivers.unregister(oper) {
            unsafe {
                drop(Box::from_raw(operation.packet as *mut Packet<T>));
            }
        }
    }

    fn accept(&self, token: &mut Token) -> bool {
        token.zero = context::current_wait_packet();
        true
    }
}

impl<'a, T> SelectHandle for Sender<'a, T> {
    fn try(&self, token: &mut Token) -> bool {
        self.0.start_send(token, false)
    }

    fn retry(&self, token: &mut Token) -> bool {
        self.0.start_send(token, true)
    }

    fn deadline(&self) -> Option<Instant> {
        None
    }

    fn register(&self, _token: &mut Token, oper: Operation) -> bool {
        let packet = Box::into_raw(Packet::<T>::empty_on_heap());

        let mut inner = self.0.inner.lock();
        inner.senders.register_with_packet(oper, packet as usize);
        !inner.receivers.can_wake_one()
    }

    fn unregister(&self, oper: Operation) {
        if let Some(operation) = self.0.inner.lock().senders.unregister(oper) {
            unsafe {
                drop(Box::from_raw(operation.packet as *mut Packet<T>));
            }
        }
    }

    fn accept(&self, token: &mut Token) -> bool {
        token.zero = context::current_wait_packet();
        true
    }
}
<|endoftext|>