<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

extern crate chrono;
extern crate clap;

extern crate fc_util;
extern crate jailer;

fn main() -> jailer::Result<()> {
    jailer::run(
        jailer::clap_app().get_matches(),
        (chrono::Utc::now().timestamp_nanos() / 1000) as u64,
        fc_util::now_cputime_us(),
    )
}
<commit_msg>jailer: handle internal errors<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

extern crate chrono;
extern crate clap;

extern crate fc_util;
extern crate jailer;

fn main() {
    match jailer::run(
        jailer::clap_app().get_matches(),
        (chrono::Utc::now().timestamp_nanos() / 1000) as u64,
        fc_util::now_cputime_us(),
    ) {
        Ok(()) => (),
        Err(error) => eprintln!("Jailer error: {}", error),
    }
}
<|endoftext|>


<commit_before>use block::{BlockEntry, Block};
use sys;

use std::mem::{align_of, size_of};
use std::{ops, ptr, slice, cmp};
use std::ptr::Unique;

pub struct BlockList {
    cap: usize,
    len: usize,
    ptr: Unique<BlockEntry>,
}

fn aligner(ptr: *mut u8, align: usize) -> usize {
    align - ptr as usize % align
}

fn canonicalize_brk(size: usize) -> usize {
    const BRK_MULTIPLIER: usize = 1;
    const BRK_MIN: usize = 200;
    const BRK_MIN_EXTRA: usize = 500;

    cmp::max(BRK_MIN, size + cmp::min(BRK_MULTIPLIER * size, BRK_MIN_EXTRA))
}

impl BlockList {
    pub fn alloc(&mut self, size: usize, align: usize) -> Unique<u8> {
        let mut ins = None;

        for (n, i) in self.iter_mut().enumerate() {
            let aligner = aligner(*i.ptr, align);

            if i.size - aligner >= size {
                // Set the excessive space as free.
                ins = Some((n, Block {
                    size: i.size - aligner - size,
                    ptr: unsafe { Unique::new((*i.ptr as usize + aligner + size) as *mut _) },
                }));

                // Leave the stub behind.
                if aligner == 0 {
                    i.free = false;
                } else {
                    i.size = aligner;
                }
            }
        }

        if let Some((n, b)) = ins {
            let res = unsafe {
                Unique::new((*b.ptr as usize - size) as *mut _)
            };

            if b.size != 0 {
                self.insert(n, b.into());
            }

            res
        } else {
            // No fitting block found. Allocate a new block.
            self.alloc_new(size, align)
        }
    }

    fn push(&mut self, block: BlockEntry) {
        let len = self.len;
        self.reserve(len + 1);

        unsafe {
            ptr::write((*self.ptr as usize + self.len * size_of::<Block>()) as *mut _, block);
        }
    }

    fn search(&mut self, block: &Block) -> Result<usize, usize> {
        self.binary_search_by(|x| (**x).cmp(block))
    }

    fn alloc_new(&mut self, size: usize, align: usize) -> Unique<u8> {
        // Calculate the canonical size (extra space is allocated to limit the number of system calls).
        let can_size = canonicalize_brk(size);
        // Get the previous segment end.
        let seg_end = sys::segment_end().unwrap_or_else(|x| x.handle());
        // Use SYSBRK to allocate extra data segment.
        let ptr = sys::inc_brk(can_size + aligner(seg_end, align)).unwrap_or_else(|x| x.handle());

        let res = unsafe {
            Unique::new((*ptr as usize + align) as *mut _)
        };
        let extra = unsafe {
            Unique::new((*res as usize + size) as *mut _)
        };

        // Add it to the list. This will not change the order, since the pointer is higher than all
        // the previous blocks.
        self.push(Block {
            size: align,
            ptr: ptr,
        }.into());

        // Add the extra space allocated.
        self.push(Block {
            size: can_size - size,
            ptr: extra,
        }.into());

        res
    }

    fn realloc_inplace(&mut self, ind: usize, old_size: usize, size: usize) -> Result<(), ()> {
        if ind == self.len - 1 { return Err(()) }

        let additional = old_size - size;

        if old_size + self[ind + 1].size >= size {
            // Leave the excessive space.
            self[ind + 1].ptr = unsafe {
                Unique::new((*self[ind + 1].ptr as usize + additional) as *mut _)
            };
            self[ind + 1].size -= additional;

            // Set the excessive block as free if it is empty.
            if self[ind + 1].size == 0 {
                self[ind + 1].free = false;
            }

            Ok(())
        } else {
            Err(())
        }
    }

    pub fn realloc(&mut self, block: Block, new_size: usize, align: usize) -> Unique<u8> {
        let ind = self.find(&block);

        if self.realloc_inplace(ind, block.size, new_size).is_ok() {
            block.ptr
        } else {
            // Reallocation cannot be done inplace.

            // Allocate a new block with the same size.
            let ptr = self.alloc(new_size, align);

            // Copy the old data to the new location.
            unsafe { ptr::copy(*block.ptr, *ptr, block.size); }

            // Free the old block.
            self.free(block);

            ptr
        }
    }

    fn reserve(&mut self, needed: usize) {
        if needed > self.cap {
            // Reallocate the block list.
            self.ptr = unsafe {
                let block = Block {
                    ptr: Unique::new(*self.ptr as *mut _),
                    size: self.cap,
                };

                Unique::new(*self.realloc(block, needed * 2, align_of::<Block>()) as *mut _)
            };
            // Update the capacity.
            self.cap = needed * 2;
        }
    }

    fn find(&mut self, block: &Block) -> usize {
        match self.search(block) {
            Ok(x) => x,
            Err(x) => x,
        }
    }

    pub fn free(&mut self, block: Block) {
        let ind = self.find(&block);

        // Try to merge left.
        if ind != 0 && self[ind - 1].left_to(&block) {
            self[ind - 1].size += block.size;
        // Try to merge right.
        } else if ind < self.len - 1 && self[ind].left_to(&block) {
            self[ind].size += block.size;
        } else {
            self.insert(ind, block.into());
        }
    }

    fn insert(&mut self, ind: usize, block: BlockEntry) {
        let len = self.len;

        // Find the next gap, where a used block were.
        let n = self.iter()
            .skip(ind)
            .enumerate()
            .filter(|&(_, x)| x.free)
            .next().map(|x| x.0)
            .unwrap_or_else(|| {
                // No gap was found, so we need to reserve space for new elements.
                self.reserve(len + 1);
                ind
            });

        // Memmove the blocks to close in that gap.
        unsafe {
            ptr::copy(self[ind..].as_ptr(), self[ind + 1..].as_mut_ptr(), self.len - n);
        }

        // Place the block left to the moved line.
        self[ind] = block;
        self.len += 1;
    }
}

impl ops::Deref for BlockList {
    type Target = [BlockEntry];

    fn deref(&self) -> &[BlockEntry] {
        unsafe {
            slice::from_raw_parts(*self.ptr as *const _, self.len)
        }
    }
}
impl ops::DerefMut for BlockList {
    fn deref_mut(&mut self) -> &mut [BlockEntry] {
        unsafe {
            slice::from_raw_parts_mut(*self.ptr, self.len)
        }
    }
}
<commit_msg>RL search<commit_after>use block::{BlockEntry, Block};
use sys;

use std::mem::{align_of, size_of};
use std::{ops, ptr, slice, cmp};
use std::ptr::Unique;

pub struct BlockList {
    cap: usize,
    len: usize,
    ptr: Unique<BlockEntry>,
}

fn aligner(ptr: *mut u8, align: usize) -> usize {
    align - ptr as usize % align
}

fn canonicalize_brk(size: usize) -> usize {
    const BRK_MULTIPLIER: usize = 1;
    const BRK_MIN: usize = 200;
    const BRK_MIN_EXTRA: usize = 500;

    cmp::max(BRK_MIN, size + cmp::min(BRK_MULTIPLIER * size, BRK_MIN_EXTRA))
}

impl BlockList {
    pub fn alloc(&mut self, size: usize, align: usize) -> Unique<u8> {
        let mut ins = None;

        // We run right-to-left, since new blocks tend to get added to the right.
        for (n, i) in self.iter_mut().enumerate().rev() {
            let aligner = aligner(*i.ptr, align);

            if i.size - aligner >= size {
                // Set the excessive space as free.
                ins = Some((n, Block {
                    size: i.size - aligner - size,
                    ptr: unsafe { Unique::new((*i.ptr as usize + aligner + size) as *mut _) },
                }));

                // Leave the stub behind.
                if aligner == 0 {
                    i.free = false;
                } else {
                    i.size = aligner;
                }
            }
        }

        if let Some((n, b)) = ins {
            let res = unsafe {
                Unique::new((*b.ptr as usize - size) as *mut _)
            };

            if b.size != 0 {
                self.insert(n, b.into());
            }

            res
        } else {
            // No fitting block found. Allocate a new block.
            self.alloc_new(size, align)
        }
    }

    fn push(&mut self, block: BlockEntry) {
        let len = self.len;
        self.reserve(len + 1);

        unsafe {
            ptr::write((*self.ptr as usize + self.len * size_of::<Block>()) as *mut _, block);
        }
    }

    fn search(&mut self, block: &Block) -> Result<usize, usize> {
        self.binary_search_by(|x| (**x).cmp(block))
    }

    fn alloc_new(&mut self, size: usize, align: usize) -> Unique<u8> {
        // Calculate the canonical size (extra space is allocated to limit the number of system calls).
        let can_size = canonicalize_brk(size);
        // Get the previous segment end.
        let seg_end = sys::segment_end().unwrap_or_else(|x| x.handle());
        // Use SYSBRK to allocate extra data segment.
        let ptr = sys::inc_brk(can_size + aligner(seg_end, align)).unwrap_or_else(|x| x.handle());

        let res = unsafe {
            Unique::new((*ptr as usize + align) as *mut _)
        };
        let extra = unsafe {
            Unique::new((*res as usize + size) as *mut _)
        };

        // Add it to the list. This will not change the order, since the pointer is higher than all
        // the previous blocks.
        self.push(Block {
            size: align,
            ptr: ptr,
        }.into());

        // Add the extra space allocated.
        self.push(Block {
            size: can_size - size,
            ptr: extra,
        }.into());

        res
    }

    fn realloc_inplace(&mut self, ind: usize, old_size: usize, size: usize) -> Result<(), ()> {
        if ind == self.len - 1 { return Err(()) }

        let additional = old_size - size;

        if old_size + self[ind + 1].size >= size {
            // Leave the excessive space.
            self[ind + 1].ptr = unsafe {
                Unique::new((*self[ind + 1].ptr as usize + additional) as *mut _)
            };
            self[ind + 1].size -= additional;

            // Set the excessive block as free if it is empty.
            if self[ind + 1].size == 0 {
                self[ind + 1].free = false;
            }

            Ok(())
        } else {
            Err(())
        }
    }

    pub fn realloc(&mut self, block: Block, new_size: usize, align: usize) -> Unique<u8> {
        let ind = self.find(&block);

        if self.realloc_inplace(ind, block.size, new_size).is_ok() {
            block.ptr
        } else {
            // Reallocation cannot be done inplace.

            // Allocate a new block with the same size.
            let ptr = self.alloc(new_size, align);

            // Copy the old data to the new location.
            unsafe { ptr::copy(*block.ptr, *ptr, block.size); }

            // Free the old block.
            self.free(block);

            ptr
        }
    }

    fn reserve(&mut self, needed: usize) {
        if needed > self.cap {
            // Reallocate the block list.
            self.ptr = unsafe {
                let block = Block {
                    ptr: Unique::new(*self.ptr as *mut _),
                    size: self.cap,
                };

                Unique::new(*self.realloc(block, needed * 2, align_of::<Block>()) as *mut _)
            };
            // Update the capacity.
            self.cap = needed * 2;
        }
    }

    fn find(&mut self, block: &Block) -> usize {
        match self.search(block) {
            Ok(x) => x,
            Err(x) => x,
        }
    }

    pub fn free(&mut self, block: Block) {
        let ind = self.find(&block);

        // Try to merge left.
        if ind != 0 && self[ind - 1].left_to(&block) {
            self[ind - 1].size += block.size;
        // Try to merge right.
        } else if ind < self.len - 1 && self[ind].left_to(&block) {
            self[ind].size += block.size;
        } else {
            self.insert(ind, block.into());
        }
    }

    fn insert(&mut self, ind: usize, block: BlockEntry) {
        let len = self.len;

        // Find the next gap, where a used block were.
        let n = self.iter()
            .skip(ind)
            .enumerate()
            .filter(|&(_, x)| x.free)
            .next().map(|x| x.0)
            .unwrap_or_else(|| {
                // No gap was found, so we need to reserve space for new elements.
                self.reserve(len + 1);
                ind
            });

        // Memmove the blocks to close in that gap.
        unsafe {
            ptr::copy(self[ind..].as_ptr(), self[ind + 1..].as_mut_ptr(), self.len - n);
        }

        // Place the block left to the moved line.
        self[ind] = block;
        self.len += 1;
    }
}

impl ops::Deref for BlockList {
    type Target = [BlockEntry];

    fn deref(&self) -> &[BlockEntry] {
        unsafe {
            slice::from_raw_parts(*self.ptr as *const _, self.len)
        }
    }
}
impl ops::DerefMut for BlockList {
    fn deref_mut(&mut self) -> &mut [BlockEntry] {
        unsafe {
            slice::from_raw_parts_mut(*self.ptr, self.len)
        }
    }
}
<|endoftext|>


<commit_before>//! choice combinators

#[macro_use]
mod macros;

use error::ErrorKind;
use error::ParseError;
use internal::{Err, IResult};

pub fn or<I: Clone, O, E: ParseError<I>, F, G>(f: F, g: G) -> impl Fn(I) -> IResult<I, O, E>
where
  F: Fn(I) -> IResult<I, O, E>,
  G: Fn(I) -> IResult<I, O, E>,
{
  move |i: I| match f(i.clone()) {
    Err(Err::Error(e)) => g(i).map_err(|e2| match e2 {
      Err::Error(e2) => Err::Error(e.or(e2)),
      e2 => e2,
    }),
    res => res,
  }
}

pub trait Alt<I, O, E> {
  fn choice(&self, input: I) -> IResult<I, O, E>;
}

macro_rules! tuple_choice(
  ($first:ident $second:ident $($id: ident)+) => (
    tuple_choice!(__impl $first $second; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident $($id: ident)+) => (
    tuple_choice_impl!($($current)*);

    tuple_choice!(__impl $($current)* $head; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident) => (
    tuple_choice_impl!($($current)*);
    tuple_choice_impl!($($current)* $head);
  );
);

macro_rules! tuple_choice_impl(
  ($($id:ident)+) => (
    impl<
      Input: Clone, Output, Error: ParseError<Input>,
      $($id: Fn(Input) -> IResult<Input, Output, Error>),+
    > Alt<Input, Output, Error> for ( $($id),+ ) {

      fn choice(&self, input: Input) -> IResult<Input, Output, Error> {
        let mut err = None;
        tuple_choice_inner!(0, self, input, err, $($id)+);

        Err(Err::Error(Error::append(input, ErrorKind::Alt, err.unwrap())))
      }
    }
  );
);

macro_rules! tuple_choice_inner(
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => (
    match $self.$it($input.clone()) {
      Err(Err::Error(e)) => {
        if $err.is_none() {
          $err = Some(e);
        } else {
          $err = Some($err.unwrap().or(e));
        }
        succ!($it, tuple_choice_inner!($self, $input, $err, $($id)+))
      },
      res => return res,
    }
  );
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => (
    match $self.$it($input.clone()) {
      Err(Err::Error(e)) => {
        if $err.is_none() {
          $err = Some(e);
        } else {
          $err = Some($err.unwrap().or(e));
        }
      },
      res => return res,
    }
  );
);

tuple_choice!(A B C D E F G H I J K L M N O P Q R S T U);

pub fn alt<I: Clone, O, E: ParseError<I>, List: Alt<I, O, E>>(l: List) -> impl Fn(I) -> IResult<I, O, E> {
  move |i: I| l.choice(i)
}

pub trait Permutation<I, O, E> {
  fn permutation(&self, input: I) -> IResult<I, O, E>;
}

macro_rules! permutation_trait(
  ($name1:ident $ty1:ident, $name2:ident $ty2:ident) => (
    permutation_trait_impl!($name1 $ty1, $name2 $ty2);
  );
  ($name1:ident $ty1:ident, $name2: ident $ty2:ident, $($name:ident $ty:ident),*) => (
    permutation_trait!(__impl $name1 $ty1, $name2 $ty2; $($name $ty),*);
  );
  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident, $($name2:ident $ty2:ident),*) => (
    permutation_trait_impl!($($name $ty),+);
    permutation_trait!(__impl $($name $ty),+ , $name1 $ty1; $($name2 $ty2),*);
  );
  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident) => (
    permutation_trait_impl!($($name $ty),+);
    permutation_trait_impl!($($name $ty),+, $name1 $ty1);
  );
);

macro_rules! permutation_trait_impl(
  ($($name:ident $ty: ident),+) => (
    impl<
      Input: Clone, $($ty),+ , Error: ParseError<Input>,
      $($name: Fn(Input) -> IResult<Input, $ty, Error>),+
    > Permutation<Input, ( $($ty),+ ), Error> for ( $($name),+ ) {

      fn permutation(&self, mut input: Input) -> IResult<Input, ( $($ty),+ ), Error> {
        let mut res = permutation_init!((), $($name),+);

        loop {
          let mut all_done = true;
          permutation_trait_inner!(0, self, input, res, all_done, $($name)+);

          //if we reach that part, it means none of the parsers were able to read anything
          if !all_done {
            //FIXME: should wrap the error returned by the child parser
            return Err(Err::Error(error_position!(input, ErrorKind::Permutation)));
          }
          break;
        }

        if let Some(unwrapped_res) = { permutation_trait_unwrap!(0, (), res, $($name),+) } {
          Ok((input, unwrapped_res))
        } else {
          Err(Err::Error(error_position!(input, ErrorKind::Permutation)))
        }
      }
    }
  );
);

macro_rules! permutation_trait_inner(
  ($it:tt, $self:expr, $input:ident, $res:expr, $all_done:expr, $head:ident $($id:ident)+) => ({
    if $res.$it.is_none() {
      match $self.$it($input.clone()) {
        Ok((i,o))     => {
          $input = i;
          $res.$it = Some(o);
          continue;
        },
        Err(Err::Error(_)) => {
          $all_done = false;
        },
        Err(e) => {
          return Err(e);
        }
      };
    }
    succ!($it, permutation_trait_inner!($self, $input, $res, $all_done, $($id)*));
  });
  ($it:tt, $self:expr, $input:ident, $res:expr, $all_done:expr, $head:ident) => ({
    if $res.$it.is_none() {
      match $self.$it($input.clone()) {
        Ok((i,o))     => {
          $input = i;
          $res.$it = Some(o);
          continue;
        },
        Err(Err::Error(_)) => {
          $all_done = false;
        },
        Err(e) => {
          return Err(e);
        }
      };
    }
  });
);

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! permutation_trait_unwrap (
  ($it:tt,  (), $res:ident, $e:ident, $($name:ident),+) => ({
    let res = $res.$it;
    if res.is_some() {
      succ!($it, permutation_trait_unwrap!((res.unwrap()), $res, $($name),+))
    } else {
      $crate::lib::std::option::Option::None
    }
  });

  ($it:tt, ($($parsed:expr),*), $res:ident, $e:ident, $($name:ident),+) => ({
    let res = $res.$it;
    if res.is_some() {
      succ!($it, permutation_trait_unwrap!(($($parsed),* , res.unwrap()), $res, $($name),+))
    } else {
      $crate::lib::std::option::Option::None
    }
  });

  ($it:tt, ($($parsed:expr),*), $res:ident, $name:ident) => ({
    let res = $res.$it;
    if res.is_some() {
      $crate::lib::std::option::Option::Some(($($parsed),* , res.unwrap() ))
    } else {
      $crate::lib::std::option::Option::None
    }
  });

);

permutation_trait!(FnA A, FnB B, FnC C, FnD D, FnE E, FnF F, FnG G, FnH H, FnI I, FnJ J, FnK K, FnL L, FnM M, FnN N, FnO O, FnP P, FnQ Q, FnR R, FnS S, FnT T, FnU U);

pub fn permutation<I: Clone, O, E: ParseError<I>, List: Permutation<I, O, E>>(l: List) -> impl Fn(I) -> IResult<I, O, E> {
  move |i: I| l.permutation(i)
}
<commit_msg>reorganize code in the branch module<commit_after>//! choice combinators

#[macro_use]
mod macros;

use error::ErrorKind;
use error::ParseError;
use internal::{Err, IResult};

pub fn or<I: Clone, O, E: ParseError<I>, F, G>(f: F, g: G) -> impl Fn(I) -> IResult<I, O, E>
where
  F: Fn(I) -> IResult<I, O, E>,
  G: Fn(I) -> IResult<I, O, E>,
{
  move |i: I| match f(i.clone()) {
    Err(Err::Error(e)) => g(i).map_err(|e2| match e2 {
      Err::Error(e2) => Err::Error(e.or(e2)),
      e2 => e2,
    }),
    res => res,
  }
}

/// helper trait for arguments to [alt]
pub trait Alt<I, O, E> {
  fn choice(&self, input: I) -> IResult<I, O, E>;
}

pub fn alt<I: Clone, O, E: ParseError<I>, List: Alt<I, O, E>>(l: List) -> impl Fn(I) -> IResult<I, O, E> {
  move |i: I| l.choice(i)
}

/// helper trait for arguments to [permutation]
pub trait Permutation<I, O, E> {
  fn permutation(&self, input: I) -> IResult<I, O, E>;
}

pub fn permutation<I: Clone, O, E: ParseError<I>, List: Permutation<I, O, E>>(l: List) -> impl Fn(I) -> IResult<I, O, E> {
  move |i: I| l.permutation(i)
}

macro_rules! alt_trait(
  ($first:ident $second:ident $($id: ident)+) => (
    alt_trait!(__impl $first $second; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident $($id: ident)+) => (
    alt_trait_impl!($($current)*);

    alt_trait!(__impl $($current)* $head; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident) => (
    alt_trait_impl!($($current)*);
    alt_trait_impl!($($current)* $head);
  );
);

macro_rules! alt_trait_impl(
  ($($id:ident)+) => (
    impl<
      Input: Clone, Output, Error: ParseError<Input>,
      $($id: Fn(Input) -> IResult<Input, Output, Error>),+
    > Alt<Input, Output, Error> for ( $($id),+ ) {

      fn choice(&self, input: Input) -> IResult<Input, Output, Error> {
        let mut err = None;
        alt_trait_inner!(0, self, input, err, $($id)+);

        Err(Err::Error(Error::append(input, ErrorKind::Alt, err.unwrap())))
      }
    }
  );
);

macro_rules! alt_trait_inner(
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => (
    match $self.$it($input.clone()) {
      Err(Err::Error(e)) => {
        if $err.is_none() {
          $err = Some(e);
        } else {
          $err = Some($err.unwrap().or(e));
        }
        succ!($it, alt_trait_inner!($self, $input, $err, $($id)+))
      },
      res => return res,
    }
  );
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => (
    match $self.$it($input.clone()) {
      Err(Err::Error(e)) => {
        if $err.is_none() {
          $err = Some(e);
        } else {
          $err = Some($err.unwrap().or(e));
        }
      },
      res => return res,
    }
  );
);

alt_trait!(A B C D E F G H I J K L M N O P Q R S T U);

macro_rules! permutation_trait(
  ($name1:ident $ty1:ident, $name2:ident $ty2:ident) => (
    permutation_trait_impl!($name1 $ty1, $name2 $ty2);
  );
  ($name1:ident $ty1:ident, $name2: ident $ty2:ident, $($name:ident $ty:ident),*) => (
    permutation_trait!(__impl $name1 $ty1, $name2 $ty2; $($name $ty),*);
  );
  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident, $($name2:ident $ty2:ident),*) => (
    permutation_trait_impl!($($name $ty),+);
    permutation_trait!(__impl $($name $ty),+ , $name1 $ty1; $($name2 $ty2),*);
  );
  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident) => (
    permutation_trait_impl!($($name $ty),+);
    permutation_trait_impl!($($name $ty),+, $name1 $ty1);
  );
);

macro_rules! permutation_trait_impl(
  ($($name:ident $ty: ident),+) => (
    impl<
      Input: Clone, $($ty),+ , Error: ParseError<Input>,
      $($name: Fn(Input) -> IResult<Input, $ty, Error>),+
    > Permutation<Input, ( $($ty),+ ), Error> for ( $($name),+ ) {

      fn permutation(&self, mut input: Input) -> IResult<Input, ( $($ty),+ ), Error> {
        let mut res = permutation_init!((), $($name),+);

        loop {
          let mut all_done = true;
          permutation_trait_inner!(0, self, input, res, all_done, $($name)+);

          //if we reach that part, it means none of the parsers were able to read anything
          if !all_done {
            //FIXME: should wrap the error returned by the child parser
            return Err(Err::Error(error_position!(input, ErrorKind::Permutation)));
          }
          break;
        }

        if let Some(unwrapped_res) = { permutation_trait_unwrap!(0, (), res, $($name),+) } {
          Ok((input, unwrapped_res))
        } else {
          Err(Err::Error(error_position!(input, ErrorKind::Permutation)))
        }
      }
    }
  );
);

macro_rules! permutation_trait_inner(
  ($it:tt, $self:expr, $input:ident, $res:expr, $all_done:expr, $head:ident $($id:ident)+) => ({
    if $res.$it.is_none() {
      match $self.$it($input.clone()) {
        Ok((i,o))     => {
          $input = i;
          $res.$it = Some(o);
          continue;
        },
        Err(Err::Error(_)) => {
          $all_done = false;
        },
        Err(e) => {
          return Err(e);
        }
      };
    }
    succ!($it, permutation_trait_inner!($self, $input, $res, $all_done, $($id)*));
  });
  ($it:tt, $self:expr, $input:ident, $res:expr, $all_done:expr, $head:ident) => ({
    if $res.$it.is_none() {
      match $self.$it($input.clone()) {
        Ok((i,o))     => {
          $input = i;
          $res.$it = Some(o);
          continue;
        },
        Err(Err::Error(_)) => {
          $all_done = false;
        },
        Err(e) => {
          return Err(e);
        }
      };
    }
  });
);

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! permutation_trait_unwrap (
  ($it:tt,  (), $res:ident, $e:ident, $($name:ident),+) => ({
    let res = $res.$it;
    if res.is_some() {
      succ!($it, permutation_trait_unwrap!((res.unwrap()), $res, $($name),+))
    } else {
      $crate::lib::std::option::Option::None
    }
  });

  ($it:tt, ($($parsed:expr),*), $res:ident, $e:ident, $($name:ident),+) => ({
    let res = $res.$it;
    if res.is_some() {
      succ!($it, permutation_trait_unwrap!(($($parsed),* , res.unwrap()), $res, $($name),+))
    } else {
      $crate::lib::std::option::Option::None
    }
  });

  ($it:tt, ($($parsed:expr),*), $res:ident, $name:ident) => ({
    let res = $res.$it;
    if res.is_some() {
      $crate::lib::std::option::Option::Some(($($parsed),* , res.unwrap() ))
    } else {
      $crate::lib::std::option::Option::None
    }
  });

);

permutation_trait!(FnA A, FnB B, FnC C, FnD D, FnE E, FnF F, FnG G, FnH H, FnI I, FnJ J, FnK K, FnL L, FnM M, FnN N, FnO O, FnP P, FnQ Q, FnR R, FnS S, FnT T, FnU U);
<|endoftext|>


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

use eyre::{bail, Result};
use futures::stream::{FuturesUnordered, StreamExt};
use graph::{Graph, Plan};
use graph_triples::Resource;
use kernels::{KernelSelector, KernelSpace};
use node_address::{Address, AddressMap};
use node_patch::{diff, mutate, Patch};
use stencila_schema::{CodeChunk, CodeExecutableExecuteStatus, CodeExpression, Node};
use tokio::sync::{mpsc::UnboundedSender, RwLock};

use crate::{
    compile_no_walk,
    utils::{resource_to_node, send_patches},
    Executable,
};

/// Execute a [`Plan`] on a [`Node`]
///
/// Uses a `RwLock` for `root` and `address_map` so that read locks can be held for as short as
/// time as possible (i.e. not while waiting for execution of tasks, which is what would
/// happen if held by the caller).
///
/// # Arguments
///
/// - `plan`: The plan to be executed
///
/// - `root`: The root node to execute the plan on (takes a read lock)
///
/// - `address_map`: The [`AddressMap`] map for the `root` node (used to locate code nodes
///                  included in the plan within the `root` node; takes a read lock)
///
/// - `patch_sender`: A [`Patch`] channel sender to send patches describing the changes to
///                   executed nodes
///
/// - `kernel_space`: The [`KernelSpace`] within which to execute the plan
///
pub async fn execute(
    plan: &Plan,
    root: &Arc<RwLock<Node>>,
    address_map: &Arc<RwLock<AddressMap>>,
    graph: &Arc<RwLock<Graph>>,
    patch_sender: &UnboundedSender<Patch>,
    kernel_space: Option<Arc<KernelSpace>>,
) -> Result<()> {
    let kernel_space = kernel_space.unwrap_or_default();

    // Obtain locks
    let root_guard = root.read().await;
    let address_map_guard = address_map.read().await;

    // Get a snapshot of all nodes involved in the plan at the start
    // Also get their `execute_status` so it can be restored at the end if needs be.
    let mut nodes: BTreeMap<Resource, _> = plan
        .stages
        .iter()
        .flat_map(|stage| stage.steps.iter())
        .filter_map(|step| {
            let resource_info = step.resource_info.clone();
            let resource = &resource_info.resource;
            match resource_to_node(resource, &root_guard, &address_map_guard) {
                Ok((node, node_id, node_address)) => {
                    let execution_status = get_execute_status(&node);
                    Some((
                        resource.clone(),
                        (resource_info, node_id, node_address, node, execution_status),
                    ))
                }
                Err(error) => {
                    tracing::warn!("While executing plan: {}", error);
                    None
                }
            }
        })
        .collect();

    // Release locks
    drop(root_guard);
    drop(address_map_guard);

    // Set the `execute_status` of all nodes to `Scheduled` or `ScheduledPreviouslyFailed`
    // and send the resulting patch
    send_patches(
        patch_sender,
        nodes
            .values_mut()
            .map(|(_, node_id, node_address, node, ..)| {
                set_execute_status_scheduled(node_id, node_address, node)
            })
            .collect(),
    );

    // For each stage in plan...
    let stage_count = plan.stages.len();
    let mut dependencies_failed = false;
    for (stage_index, stage) in plan.stages.iter().enumerate() {
        tracing::debug!("Starting stage {}/{}", stage_index + 1, stage_count);

        // Before running the steps in this stage, check that all their dependencies have succeeded
        // and stop if they have not
        dependencies_failed = stage
            .steps
            .iter()
            .flat_map(|step| step.resource_info.dependencies.iter().flatten())
            .filter_map(|dependency| nodes.get(dependency))
            .map(|tuple| get_execute_status(&tuple.3))
            .any(|status| !matches!(status, Some(CodeExecutableExecuteStatus::Succeeded)));
        if dependencies_failed {
            break;
        }

        // Create a kernel task for each step in this stage
        let step_count = stage.steps.len();
        let mut patches = Vec::with_capacity(step_count);
        let mut futures = Vec::with_capacity(step_count);
        for (step_index, step) in stage.steps.iter().enumerate() {
            // Get the node
            let (_, node_id, node_address, mut node, ..) = nodes
                .get(&step.resource_info.resource)
                .expect("Node for resource should be in nodes")
                .clone();

            // Set the `execute_status` of the node to `Running` or `RunningPreviouslyFailed`
            // and send the resulting patch
            patches.push(set_execute_status_running(
                &node_id,
                &node_address,
                &mut node,
            ));

            // Create clones of variables needed to execute the task
            let kernel_space = kernel_space.clone();
            let kernel_selector = KernelSelector::new(step.kernel_name.clone(), None, None);
            let mut resource_info = step.resource_info.clone();
            let is_fork = step.is_fork;

            // Create a future for the task that will be spawned later
            let future = async move {
                tracing::debug!(
                    "Starting step {}/{} of stage {}/{}",
                    step_index + 1,
                    step_count,
                    stage_index + 1,
                    stage_count
                );

                // Create a mutable draft of the node and execute it in the kernel space
                let mut draft = node.clone();
                match draft
                    .execute(&kernel_space, &kernel_selector, &resource_info, is_fork)
                    .await
                {
                    Ok(_) => {
                        // Update the resource to indicate that the resource was executed
                        let execute_status = match &draft {
                            Node::CodeChunk(CodeChunk { execute_status, .. })
                            | Node::CodeExpression(CodeExpression { execute_status, .. }) => {
                                execute_status.clone()
                            }
                            _ => None,
                        };
                        resource_info.did_execute(execute_status);

                        // Generate a patch for the differences resulting from execution
                        let mut patch = diff(&node, &draft);
                        patch.address = Some(node_address.clone());
                        patch.target = Some(node_id.clone());

                        Ok((step_index, resource_info, draft, patch))
                    }
                    Err(error) => bail!(error),
                }
            };
            futures.push(future);
        }
        send_patches(patch_sender, patches);

        // Spawn all tasks in the stage and wait for each to finish, sending on the resultant `Patch`
        // for application and publishing (if it is not empty)
        // TODO: Replace `FuturesUnordered` with `TaskSet`. See https://news.ycombinator.com/item?id=29912386
        let mut results = futures
            .into_iter()
            .map(tokio::spawn)
            .collect::<FuturesUnordered<_>>();
        while let Some(result) = results.next().await {
            let (step_index, resource_info, node, patch) = result??;

            tracing::debug!(
                "Finished step {}/{} of stage {}/{}",
                step_index + 1,
                step_count,
                stage_index + 1,
                stage_count
            );

            // Send the patch reflecting the changed state of the executed node
            if !patch.is_empty() {
                if let Err(error) = patch_sender.send(patch) {
                    tracing::debug!(
                        "When sending patch for step {} of stage {}: {}",
                        step_index + 1,
                        stage_index + 1,
                        error
                    );
                }
            }

            nodes
                .entry(resource_info.resource.clone())
                .and_modify(|info| info.3 = node);

            // Update the graph with new resource info
            graph.write().await.update_resource_info(resource_info)?;

            // Then do a recompile, using the graph, so that node properties such as
            // `code_dependencies` and `code_dependents` get updated with the new execution status
            // of nodes.
            compile_no_walk(root, address_map, graph, patch_sender).await?;
        }

        tracing::debug!("Finished stage {}/{}", stage_index + 1, stage_count);
    }

    // For nodes that were scheduled but never got to run because dependencies did not succeed,
    // restore their previous execution status
    if dependencies_failed {
        send_patches(
            patch_sender,
            nodes
                .values_mut()
                .map(|(_, node_id, node_address, node, execute_status)| {
                    restore_previous_execute_status(node_id, node_address, node, execute_status)
                })
                .collect(),
        );
    }

    Ok(())
}

fn get_execute_status(node: &Node) -> Option<CodeExecutableExecuteStatus> {
    match node {
        Node::CodeChunk(CodeChunk { execute_status, .. })
        | Node::CodeExpression(CodeExpression { execute_status, .. }) => execute_status.clone(),
        _ => None,
    }
}

fn set_execute_status_scheduled(node_id: &str, node_address: &Address, node: &mut Node) -> Patch {
    mutate(
        node,
        Some(node_id.to_string()),
        Some(node_address.clone()),
        &|node: &mut Node| match node {
            Node::CodeChunk(CodeChunk { execute_status, .. })
            | Node::CodeExpression(CodeExpression { execute_status, .. }) => {
                *execute_status = Some(match execute_status {
                    Some(CodeExecutableExecuteStatus::Failed) => {
                        CodeExecutableExecuteStatus::ScheduledPreviouslyFailed
                    }
                    _ => CodeExecutableExecuteStatus::Scheduled,
                });
            }
            _ => {}
        },
    )
}

fn set_execute_status_running(node_id: &str, node_address: &Address, node: &mut Node) -> Patch {
    mutate(
        node,
        Some(node_id.to_string()),
        Some(node_address.clone()),
        &|node: &mut Node| match node {
            Node::CodeChunk(CodeChunk { execute_status, .. })
            | Node::CodeExpression(CodeExpression { execute_status, .. }) => {
                *execute_status = Some(match execute_status {
                    Some(CodeExecutableExecuteStatus::Failed)
                    | Some(CodeExecutableExecuteStatus::ScheduledPreviouslyFailed) => {
                        CodeExecutableExecuteStatus::RunningPreviouslyFailed
                    }
                    _ => CodeExecutableExecuteStatus::Running,
                });
            }
            _ => {}
        },
    )
}

fn restore_previous_execute_status(
    node_id: &str,
    node_address: &Address,
    node: &mut Node,
    previous_execute_status: &Option<CodeExecutableExecuteStatus>,
) -> Patch {
    mutate(
        node,
        Some(node_id.to_string()),
        Some(node_address.clone()),
        &|node: &mut Node| match node {
            Node::CodeChunk(CodeChunk { execute_status, .. })
            | Node::CodeExpression(CodeExpression { execute_status, .. }) => {
                if matches!(
                    execute_status,
                    Some(CodeExecutableExecuteStatus::Scheduled)
                        | Some(CodeExecutableExecuteStatus::ScheduledPreviouslyFailed)
                ) {
                    *execute_status = previous_execute_status.clone();
                }
            }
            _ => {}
        },
    )
}
<commit_msg>fix(Node execution): Fix assesment of early stopping of stages<commit_after>use std::{
    collections::{BTreeMap, BTreeSet},
    sync::Arc,
};

use eyre::{bail, Result};
use futures::stream::{FuturesUnordered, StreamExt};
use graph::{Graph, Plan};
use graph_triples::Resource;
use kernels::{KernelSelector, KernelSpace};
use node_address::{Address, AddressMap};
use node_patch::{diff, mutate, Patch};
use stencila_schema::{CodeChunk, CodeExecutableExecuteStatus, CodeExpression, Node};
use tokio::sync::{mpsc::UnboundedSender, RwLock};

use crate::{
    compile_no_walk,
    utils::{resource_to_node, send_patches},
    Executable,
};

/// Execute a [`Plan`] on a [`Node`]
///
/// Uses a `RwLock` for `root` and `address_map` so that read locks can be held for as short as
/// time as possible (i.e. not while waiting for execution of tasks, which is what would
/// happen if held by the caller).
///
/// # Arguments
///
/// - `plan`: The plan to be executed
///
/// - `root`: The root node to execute the plan on (takes a read lock)
///
/// - `address_map`: The [`AddressMap`] map for the `root` node (used to locate code nodes
///                  included in the plan within the `root` node; takes a read lock)
///
/// - `patch_sender`: A [`Patch`] channel sender to send patches describing the changes to
///                   executed nodes
///
/// - `kernel_space`: The [`KernelSpace`] within which to execute the plan
///
pub async fn execute(
    plan: &Plan,
    root: &Arc<RwLock<Node>>,
    address_map: &Arc<RwLock<AddressMap>>,
    graph: &Arc<RwLock<Graph>>,
    patch_sender: &UnboundedSender<Patch>,
    kernel_space: Option<Arc<KernelSpace>>,
) -> Result<()> {
    let kernel_space = kernel_space.unwrap_or_default();

    // Obtain locks
    let root_guard = root.read().await;
    let address_map_guard = address_map.read().await;

    // Get a snapshot of all nodes involved in the plan at the start
    // Also get their `execute_status` so it can be restored at the end if needs be.
    let mut nodes: BTreeMap<Resource, _> = plan
        .stages
        .iter()
        .flat_map(|stage| stage.steps.iter())
        .filter_map(|step| {
            let resource_info = step.resource_info.clone();
            let resource = &resource_info.resource;
            match resource_to_node(resource, &root_guard, &address_map_guard) {
                Ok((node, node_id, node_address)) => {
                    let execution_status = get_execute_status(&node);
                    Some((
                        resource.clone(),
                        (resource_info, node_id, node_address, node, execution_status),
                    ))
                }
                Err(error) => {
                    tracing::warn!("While executing plan: {}", error);
                    None
                }
            }
        })
        .collect();

    // Release locks
    drop(root_guard);
    drop(address_map_guard);

    // Set the `execute_status` of all nodes to `Scheduled` or `ScheduledPreviouslyFailed`
    // and send the resulting patch
    send_patches(
        patch_sender,
        nodes
            .values_mut()
            .map(|(_, node_id, node_address, node, ..)| {
                set_execute_status_scheduled(node_id, node_address, node)
            })
            .collect(),
    );

    // For each stage in plan...
    let stage_count = plan.stages.len();
    let mut dependencies_failed = false;
    for (stage_index, stage) in plan.stages.iter().enumerate() {
        // Before running the steps in this stage, check that all their dependencies have succeeded
        // and stop if they have not. Collects to a `BTreeSet` to generate unique set (some steps in
        // the stage may have the shared dependencies)
        dependencies_failed = stage
            .steps
            .iter()
            .flat_map(|step| step.resource_info.dependencies.iter().flatten())
            .collect::<BTreeSet<&Resource>>()
            .iter()
            .filter_map(|dependency| nodes.get(dependency))
            .map(|tuple| (&tuple.1, get_execute_status(&tuple.3)))
            .any(|(node_id, status)| {
                tracing::trace!(
                    "Status of dependency of stage {}/{} `{}`: {:?}",
                    stage_index + 1,
                    stage_count,
                    node_id,
                    status
                );
                matches!(
                    status,
                    None | Some(CodeExecutableExecuteStatus::Failed)
                        | Some(CodeExecutableExecuteStatus::Cancelled)
                )
            });
        if dependencies_failed {
            tracing::debug!(
                "Stopping before stage {}/{}: some dependencies failed or were cancelled",
                stage_index + 1,
                stage_count
            );
            break;
        } else {
            tracing::debug!("Starting stage {}/{}", stage_index + 1, stage_count);
        }

        // Create a kernel task for each step in this stage
        let step_count = stage.steps.len();
        let mut patches = Vec::with_capacity(step_count);
        let mut futures = Vec::with_capacity(step_count);
        for (step_index, step) in stage.steps.iter().enumerate() {
            // Get the node
            let (_, node_id, node_address, mut node, ..) = nodes
                .get(&step.resource_info.resource)
                .expect("Node for resource should be in nodes")
                .clone();

            // Set the `execute_status` of the node to `Running` or `RunningPreviouslyFailed`
            // and send the resulting patch
            patches.push(set_execute_status_running(
                &node_id,
                &node_address,
                &mut node,
            ));

            // Create clones of variables needed to execute the task
            let kernel_space = kernel_space.clone();
            let kernel_selector = KernelSelector::new(step.kernel_name.clone(), None, None);
            let mut resource_info = step.resource_info.clone();
            let is_fork = step.is_fork;

            // Create a future for the task that will be spawned later
            let future = async move {
                tracing::debug!(
                    "Starting step {}/{} of stage {}/{}",
                    step_index + 1,
                    step_count,
                    stage_index + 1,
                    stage_count
                );

                // Create a mutable draft of the node and execute it in the kernel space
                let mut draft = node.clone();
                match draft
                    .execute(&kernel_space, &kernel_selector, &resource_info, is_fork)
                    .await
                {
                    Ok(_) => {
                        // Update the resource to indicate that the resource was executed
                        let execute_status = match &draft {
                            Node::CodeChunk(CodeChunk { execute_status, .. })
                            | Node::CodeExpression(CodeExpression { execute_status, .. }) => {
                                execute_status.clone()
                            }
                            _ => None,
                        };
                        resource_info.did_execute(execute_status);

                        // Generate a patch for the differences resulting from execution
                        let mut patch = diff(&node, &draft);
                        patch.address = Some(node_address.clone());
                        patch.target = Some(node_id.clone());

                        Ok((step_index, resource_info, draft, patch))
                    }
                    Err(error) => bail!(error),
                }
            };
            futures.push(future);
        }
        send_patches(patch_sender, patches);

        // Spawn all tasks in the stage and wait for each to finish, sending on the resultant `Patch`
        // for application and publishing (if it is not empty)
        // TODO: Replace `FuturesUnordered` with `TaskSet`. See https://news.ycombinator.com/item?id=29912386
        let mut results = futures
            .into_iter()
            .map(tokio::spawn)
            .collect::<FuturesUnordered<_>>();
        while let Some(result) = results.next().await {
            let (step_index, resource_info, node, patch) = result??;

            tracing::debug!(
                "Finished step {}/{} of stage {}/{}",
                step_index + 1,
                step_count,
                stage_index + 1,
                stage_count
            );

            // Send the patch reflecting the changed state of the executed node
            if !patch.is_empty() {
                if let Err(error) = patch_sender.send(patch) {
                    tracing::debug!(
                        "When sending patch for step {} of stage {}: {}",
                        step_index + 1,
                        stage_index + 1,
                        error
                    );
                }
            }

            nodes
                .entry(resource_info.resource.clone())
                .and_modify(|info| info.3 = node);

            // Update the graph with new resource info
            graph.write().await.update_resource_info(resource_info)?;

            // Then do a recompile, using the graph, so that node properties such as
            // `code_dependencies` and `code_dependents` get updated with the new execution status
            // of nodes.
            compile_no_walk(root, address_map, graph, patch_sender).await?;
        }

        tracing::debug!("Finished stage {}/{}", stage_index + 1, stage_count);
    }

    // For nodes that were scheduled but never got to run because dependencies did not succeed,
    // restore their previous execution status
    if dependencies_failed {
        send_patches(
            patch_sender,
            nodes
                .values_mut()
                .map(|(_, node_id, node_address, node, execute_status)| {
                    restore_previous_execute_status(node_id, node_address, node, execute_status)
                })
                .collect(),
        );
    }

    Ok(())
}

fn get_execute_status(node: &Node) -> Option<CodeExecutableExecuteStatus> {
    match node {
        Node::CodeChunk(CodeChunk { execute_status, .. })
        | Node::CodeExpression(CodeExpression { execute_status, .. }) => execute_status.clone(),
        // At present, assumes the execution of parameters always succeeds
        Node::Parameter(..) => Some(CodeExecutableExecuteStatus::Succeeded),
        _ => None,
    }
}

fn set_execute_status_scheduled(node_id: &str, node_address: &Address, node: &mut Node) -> Patch {
    mutate(
        node,
        Some(node_id.to_string()),
        Some(node_address.clone()),
        &|node: &mut Node| match node {
            Node::CodeChunk(CodeChunk { execute_status, .. })
            | Node::CodeExpression(CodeExpression { execute_status, .. }) => {
                *execute_status = Some(match execute_status {
                    Some(CodeExecutableExecuteStatus::Failed) => {
                        CodeExecutableExecuteStatus::ScheduledPreviouslyFailed
                    }
                    _ => CodeExecutableExecuteStatus::Scheduled,
                });
            }
            _ => {}
        },
    )
}

fn set_execute_status_running(node_id: &str, node_address: &Address, node: &mut Node) -> Patch {
    mutate(
        node,
        Some(node_id.to_string()),
        Some(node_address.clone()),
        &|node: &mut Node| match node {
            Node::CodeChunk(CodeChunk { execute_status, .. })
            | Node::CodeExpression(CodeExpression { execute_status, .. }) => {
                *execute_status = Some(match execute_status {
                    Some(CodeExecutableExecuteStatus::Failed)
                    | Some(CodeExecutableExecuteStatus::ScheduledPreviouslyFailed) => {
                        CodeExecutableExecuteStatus::RunningPreviouslyFailed
                    }
                    _ => CodeExecutableExecuteStatus::Running,
                });
            }
            _ => {}
        },
    )
}

fn restore_previous_execute_status(
    node_id: &str,
    node_address: &Address,
    node: &mut Node,
    previous_execute_status: &Option<CodeExecutableExecuteStatus>,
) -> Patch {
    mutate(
        node,
        Some(node_id.to_string()),
        Some(node_address.clone()),
        &|node: &mut Node| match node {
            Node::CodeChunk(CodeChunk { execute_status, .. })
            | Node::CodeExpression(CodeExpression { execute_status, .. }) => {
                if matches!(
                    execute_status,
                    Some(CodeExecutableExecuteStatus::Scheduled)
                        | Some(CodeExecutableExecuteStatus::ScheduledPreviouslyFailed)
                ) {
                    *execute_status = previous_execute_status.clone();
                }
            }
            _ => {}
        },
    )
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::file::{FileHeaderSpec, FileHeaderData, FileData};

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
}

impl ParserError {
    fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
        }
    }

    fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None
        }
    }
}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser : Sized {
    fn new(spec: &FileHeaderSpec) -> Self;
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

pub trait FileDataParser<FD: FileData + Sized> : Sized {
    fn new() -> Self;
    fn read(&self, string: Option<String>) -> Result<FD, ParserError>;
    fn write(&self, data: &FD) -> Result<String, ParserError>;
}

type TextTpl = (Option<String>, Option<String>);

pub struct Parser<HP, DP>
{
    headerp : HP,
    datap : DP,
}

impl<HP, DP> Parser<HP, DP> where
    HP: FileHeaderParser,
{

    fn new(headerp: HP, datap: DP) -> Parser<HP, DP> {
        Parser {
            headerp: headerp,
            datap: datap,
        }
    }

    pub fn read<FD>(&self, s: String) -> Result<(FileHeaderData, FD), ParserError>
        where FD: FileData + Sized,
              DP: FileDataParser<FD>
    {
        let divided = self.divide_text(&s);

        if divided.is_err() {
            return Err(divided.err().unwrap());
        }

        let (header, data) = divided.ok().unwrap();

        let h_parseres = try!(self.headerp.read(header));
        let d_parseres = try!(self.datap.read(data));

        Ok((h_parseres, d_parseres))
    }

    fn write<FD>(&self, tpl : (FileHeaderData, FD)) -> Result<String, ParserError>
        where FD: FileData + Sized,
              DP: FileDataParser<FD>
    {
        let (header, data) = tpl;
        let h_text = self.headerp.write(&header);
        let d_text = self.datap.write(&data);

        if h_text.is_err() {
            return Err(h_text.err().unwrap());
        }

        if d_text.is_err() {
            return Err(d_text.err().unwrap());
        }

        Ok(h_text.ok().unwrap() + &d_text.ok().unwrap()[..])
    }

    fn divide_text(&self, text: &String) -> Result<TextTpl, ParserError> {
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));
        Ok((header, content))
    }

}

<commit_msg>Minify Parser.write()<commit_after>use regex::Regex;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::file::{FileHeaderSpec, FileHeaderData, FileData};

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
}

impl ParserError {
    fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
        }
    }

    fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None
        }
    }
}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser : Sized {
    fn new(spec: &FileHeaderSpec) -> Self;
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

pub trait FileDataParser<FD: FileData + Sized> : Sized {
    fn new() -> Self;
    fn read(&self, string: Option<String>) -> Result<FD, ParserError>;
    fn write(&self, data: &FD) -> Result<String, ParserError>;
}

type TextTpl = (Option<String>, Option<String>);

pub struct Parser<HP, DP>
{
    headerp : HP,
    datap : DP,
}

impl<HP, DP> Parser<HP, DP> where
    HP: FileHeaderParser,
{

    fn new(headerp: HP, datap: DP) -> Parser<HP, DP> {
        Parser {
            headerp: headerp,
            datap: datap,
        }
    }

    pub fn read<FD>(&self, s: String) -> Result<(FileHeaderData, FD), ParserError>
        where FD: FileData + Sized,
              DP: FileDataParser<FD>
    {
        let divided = self.divide_text(&s);

        if divided.is_err() {
            return Err(divided.err().unwrap());
        }

        let (header, data) = divided.ok().unwrap();

        let h_parseres = try!(self.headerp.read(header));
        let d_parseres = try!(self.datap.read(data));

        Ok((h_parseres, d_parseres))
    }

    fn write<FD>(&self, tpl : (FileHeaderData, FD)) -> Result<String, ParserError>
        where FD: FileData + Sized,
              DP: FileDataParser<FD>
    {
        let (header, data) = tpl;
        let h_text = try!(self.headerp.write(&header));
        let d_text = try!(self.datap.write(&data));

        Ok(h_text + &d_text[..])
    }

    fn divide_text(&self, text: &String) -> Result<TextTpl, ParserError> {
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));
        Ok((header, content))
    }

}

<|endoftext|>


<commit_before>use scaly::memory::page::Page;
use scaly::memory::page::PAGE_SIZE;
use std::alloc::alloc;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::null_mut;

const STACK_BUCKET_PAGES: usize = 0x100;

pub struct Region<'a> {
    page: &'a mut Page,
}

impl<'a> Region<'a> {
    pub fn create_from_page(page: &Page) -> Region<'a> {
        let our_page_address = StackBucket::new_page(page);
        Region {
            page: unsafe { &mut *(our_page_address as *mut Page) },
        }
    }
    pub fn create(region: &Region<'a>) -> Region<'a> {
        Region::create_from_page(region.page)
    }
}

impl<'a> Drop for Region<'a> {
    fn drop(&mut self) {
        self.page.deallocate_extensions();
    }
}

pub enum Bucket {
    Stack(StackBucket),
    Heap(HeapBucket),
}

pub struct HeapBucket {
    map: usize,
}

pub struct StackBucket {
    next_bucket: *mut StackBucket,
}

impl StackBucket {
    pub fn new_page(page: &Page) -> *mut Page {
        let page_address = page as *const Page as usize;
        let stack_bucket_page_address = page_address & !(PAGE_SIZE * STACK_BUCKET_PAGES - 1);
        let overflowed_page_address = stack_bucket_page_address + PAGE_SIZE * STACK_BUCKET_PAGES;
        let our_page_address = page_address + PAGE_SIZE;
        if overflowed_page_address == our_page_address {
            let stack_bucket = (stack_bucket_page_address + size_of::<Page>()) as *mut StackBucket;
            unsafe { (*stack_bucket).get_page_from_next_bucket() }
        } else {
            our_page_address as *mut Page
        }
    }

    fn get_page_from_next_bucket(self: &mut StackBucket) -> *mut Page {
        if self.next_bucket == null_mut() {
            self.next_bucket = StackBucket::create();
        }
        Page::get_page(self.next_bucket as usize)
    }

    fn create() -> *mut StackBucket {
        unsafe {
            let memory = alloc(Layout::from_size_align_unchecked(
                PAGE_SIZE * STACK_BUCKET_PAGES,
                PAGE_SIZE * STACK_BUCKET_PAGES,
            ));
            if memory == null_mut() {
                panic!("Unable to crete a new stack bucket: Out of memory.");
            }
            let page = &mut *(memory as *mut Page);
            page.reset();
            let bucket = page.allocate(StackBucket {
                next_bucket: null_mut(),
            });
            bucket
        }
    }

    pub fn deallocate(&self) {
        let mut bucket = self as *const StackBucket;
        unsafe {
            while !(*bucket).next_bucket.is_null() {
                let next_bucket = (*bucket).next_bucket;
                let page = Page::get_page(bucket as usize);
                dealloc(
                    page as *mut u8,
                    Layout::from_size_align_unchecked(
                        PAGE_SIZE * STACK_BUCKET_PAGES,
                        PAGE_SIZE * STACK_BUCKET_PAGES,
                    ),
                );

                bucket = next_bucket;
            }
        }
    }
}

impl Drop for StackBucket {
    fn drop(&mut self) {
        self.deallocate();
    }
}

#[test]
fn test_region() {
    unsafe {
        let root_stack_bucket = StackBucket::create();
        let r1 = Region::create_from_page(&*Page::get_page(root_stack_bucket as usize));
        {
            let r2 = Region::create(&r1);
            {
                let _ = Region::create(&r2);
            }
        }
        (*root_stack_bucket).deallocate();
    }
    unsafe {
        let root_stack_bucket = StackBucket::create();

        let mut r = Region::create_from_page(&*Page::get_page(root_stack_bucket as usize));
        for _ in 1..STACK_BUCKET_PAGES * 2 {
            r = Region::create(&r);
        }

        (*root_stack_bucket).deallocate();
    }
}
<commit_msg>Began Pool<commit_after>use scaly::memory::page::Page;
use scaly::memory::page::PAGE_SIZE;
use std::alloc::alloc;
use std::alloc::alloc_zeroed;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::null_mut;

const STACK_BUCKET_PAGES: usize = 0x100;

pub struct Region<'a> {
    page: &'a mut Page,
}

impl<'a> Region<'a> {
    pub fn create_from_page(page: &Page) -> Region<'a> {
        let our_page_address = StackBucket::new_page(page);
        Region {
            page: unsafe { &mut *(our_page_address as *mut Page) },
        }
    }
    pub fn create(region: &Region<'a>) -> Region<'a> {
        Region::create_from_page(region.page)
    }
}

impl<'a> Drop for Region<'a> {
    fn drop(&mut self) {
        self.page.deallocate_extensions();
    }
}

pub enum Bucket {
    Stack(StackBucket),
    Heap(HeapBucket),
}

pub struct HeapBucket {
    map: usize,
}

pub struct Pool {
    root_map: usize,
    maps: *mut usize,
    pointers: *mut HeapBucket,
}

const MAPS_SIZE: usize = size_of::<usize>() * 8 * size_of::<usize>();
const POINTERS_SIZE: usize = MAPS_SIZE * 8 * size_of::<usize>();

impl Pool {
    pub fn create() -> Pool {
        unsafe {
            let maps_memory = alloc_zeroed(Layout::from_size_align_unchecked(MAPS_SIZE, PAGE_SIZE));
            if maps_memory == null_mut() {
                panic!("Unable to allocate maps memory: Out of memory.");
            }
            let pointers_memory =
                alloc_zeroed(Layout::from_size_align_unchecked(POINTERS_SIZE, PAGE_SIZE));
            if pointers_memory == null_mut() {
                panic!("Unable to allocate maps memory: Out of memory.");
            }
            Pool {
                root_map: 0,
                maps: maps_memory as *mut usize,
                pointers: pointers_memory as *mut HeapBucket,
            }
        }
    }
}

impl Drop for Pool {
    fn drop(&mut self) {
        if self.root_map != 0 {
            panic!("Pool is not empty!")
        }
        unsafe {
            dealloc(
                self.maps as *mut u8,
                Layout::from_size_align_unchecked(MAPS_SIZE, PAGE_SIZE),
            );
            dealloc(
                self.pointers as *mut u8,
                Layout::from_size_align_unchecked(POINTERS_SIZE, PAGE_SIZE),
            );
        }
    }
}

pub struct StackBucket {
    next_bucket: *mut StackBucket,
}

impl StackBucket {
    pub fn new_page(page: &Page) -> *mut Page {
        let page_address = page as *const Page as usize;
        let stack_bucket_page_address = page_address & !(PAGE_SIZE * STACK_BUCKET_PAGES - 1);
        let overflowed_page_address = stack_bucket_page_address + PAGE_SIZE * STACK_BUCKET_PAGES;
        let our_page_address = page_address + PAGE_SIZE;
        if overflowed_page_address == our_page_address {
            let stack_bucket = (stack_bucket_page_address + size_of::<Page>()) as *mut StackBucket;
            unsafe { (*stack_bucket).get_page_from_next_bucket() }
        } else {
            our_page_address as *mut Page
        }
    }

    fn get_page_from_next_bucket(self: &mut StackBucket) -> *mut Page {
        if self.next_bucket == null_mut() {
            self.next_bucket = StackBucket::create();
        }
        Page::get_page(self.next_bucket as usize)
    }

    fn create() -> *mut StackBucket {
        unsafe {
            let memory = alloc(Layout::from_size_align_unchecked(
                PAGE_SIZE * STACK_BUCKET_PAGES,
                PAGE_SIZE * STACK_BUCKET_PAGES,
            ));
            if memory == null_mut() {
                panic!("Unable to crete a new stack bucket: Out of memory.");
            }
            let page = &mut *(memory as *mut Page);
            page.reset();
            let bucket = page.allocate(StackBucket {
                next_bucket: null_mut(),
            });
            bucket
        }
    }

    pub fn deallocate(&self) {
        let mut bucket = self as *const StackBucket;
        unsafe {
            while !(*bucket).next_bucket.is_null() {
                let next_bucket = (*bucket).next_bucket;
                let page = Page::get_page(bucket as usize);
                dealloc(
                    page as *mut u8,
                    Layout::from_size_align_unchecked(
                        PAGE_SIZE * STACK_BUCKET_PAGES,
                        PAGE_SIZE * STACK_BUCKET_PAGES,
                    ),
                );

                bucket = next_bucket;
            }
        }
    }
}

impl Drop for StackBucket {
    fn drop(&mut self) {
        self.deallocate();
    }
}

#[test]
fn test_region() {
    unsafe {
        let root_stack_bucket = StackBucket::create();
        let r1 = Region::create_from_page(&*Page::get_page(root_stack_bucket as usize));
        {
            let r2 = Region::create(&r1);
            {
                let _ = Region::create(&r2);
            }
        }
        (*root_stack_bucket).deallocate();
    }
    unsafe {
        let root_stack_bucket = StackBucket::create();

        let mut r = Region::create_from_page(&*Page::get_page(root_stack_bucket as usize));
        for _ in 1..STACK_BUCKET_PAGES * 2 {
            r = Region::create(&r);
        }

        (*root_stack_bucket).deallocate();
    }
}
<|endoftext|>


<commit_before>use cgmath::{Point, Point3, Vector3, Aabb3};
use rand;
use rand::distributions::IndependentSample;
use std::convert::AsRef;
use std::f64;
use std::f32::consts::PI;
use std::ops::DerefMut;
use std::sync::mpsc::channel;
use std::time::Duration;
use thread_scoped;

use common::communicate::{ClientToServer, ServerToClient};
use common::entity;
use common::serialize;
use common::serialize::Copyable;
use common::socket::SendSocket;

use player::Player;
use server::{Client, Server};
use terrain;
use voxel;
use update_gaia::{ServerToGaia, LoadReason};

fn center(bounds: &Aabb3<f32>) -> Point3<f32> {
  bounds.min.add_v(&bounds.max.to_vec()).mul_s(1.0 / 2.0)
}

fn cast(
  server: &Server,
  player_id: entity::EntityId,
) -> Option<voxel::Bounds> {
  let ray;
  {
    let players = server.players.lock().unwrap();
    let player = players.get(&player_id).unwrap();
    ray = player.forward_ray();
  }

  let terrain_loader = server.terrain_loader.lock().unwrap();
  terrain_loader.terrain.voxels.cast_ray(
    &ray,
    &mut |bounds, voxel| {
      match voxel {
        &terrain::voxel::T::Volume(voxel::Material::Empty) => None,
        _ => Some(bounds),
      }
    }
  )
}

#[inline]
pub fn apply_client_update<UpdateGaia>(
  server: &Server,
  update_gaia: &mut UpdateGaia,
  update: ClientToServer,
) where
  UpdateGaia: FnMut(ServerToGaia),
{
  match update {
    ClientToServer::Init(client_url) => {
      info!("Sending to {}.", client_url);

      let (to_client_send, to_client_recv) = channel();
      let client_thread = unsafe {
        thread_scoped::scoped(move || {
          let mut socket = SendSocket::new(client_url.as_ref(), Some(Duration::from_secs(30)));
          while let Some(msg) = to_client_recv.recv().unwrap() {
            // TODO: Don't do this allocation on every packet!
            let msg = serialize::encode(&msg).unwrap();
            socket.write(msg.as_ref());
          }
        })
      };

      let client_id = server.client_allocator.lock().unwrap().allocate();
      to_client_send.send(Some(ServerToClient::LeaseId(Copyable(client_id)))).unwrap();

      let client =
        Client {
          sender: to_client_send,
          thread: client_thread,
        };
      server.clients.lock().unwrap().insert(client_id, client);
    },
    ClientToServer::Ping(Copyable(client_id)) => {
      server.clients.lock().unwrap()
        .get(&client_id)
        .unwrap()
        .sender
        .send(Some(ServerToClient::Ping(Copyable(()))))
        .unwrap();
    },
    ClientToServer::AddPlayer(Copyable(client_id)) => {
      let mut player =
        Player::new(
          server.id_allocator.lock().unwrap().allocate(),
          &server.owner_allocator,
        );

      // TODO: shift upward until outside terrain
      let min = Point3::new(0.0, 64.0, 4.0);
      let max = min.add_v(&Vector3::new(1.0, 2.0, 1.0));
      let bounds = Aabb3::new(min, max);
      server.physics.lock().unwrap().insert_misc(player.entity_id, bounds.clone());

      player.position = center(&bounds);
      player.rotate_lateral(PI / 2.0);

      let id = player.entity_id;
      let pos = player.position;

      server.players.lock().unwrap().insert(id, player);

      let clients = server.clients.lock().unwrap();
      let client = clients.get(&client_id).unwrap();
      client.sender.send(
        Some(ServerToClient::PlayerAdded(Copyable(id), Copyable(pos)))
      ).unwrap();
    },
    ClientToServer::StartJump(Copyable(player_id)) => {
      let mut players = server.players.lock().unwrap();
      let player = players.get_mut(&player_id).unwrap();
      if !player.is_jumping {
        player.is_jumping = true;
        // this 0.3 is duplicated in a few places
        player.accel.y = player.accel.y + 0.3;
      }
    },
    ClientToServer::StopJump(Copyable(player_id)) => {
      let mut players = server.players.lock().unwrap();
      let player = players.get_mut(&player_id).unwrap();
      if player.is_jumping {
        player.is_jumping = false;
        // this 0.3 is duplicated in a few places
        player.accel.y = player.accel.y - 0.3;
      }
    },
    ClientToServer::Walk(Copyable(player_id), Copyable(v)) => {
      let mut players = server.players.lock().unwrap();
      let mut player = players.get_mut(&player_id).unwrap();
      player.walk(v);
    },
    ClientToServer::RotatePlayer(Copyable(player_id), Copyable(v)) => {
      let mut players = server.players.lock().unwrap();
      let mut player = players.get_mut(&player_id).unwrap();
      player.rotate_lateral(v.x);
      player.rotate_vertical(v.y);
    },
    ClientToServer::RequestBlock(Copyable(client_id), Copyable(position), Copyable(lod)) => {
      update_gaia(ServerToGaia::Load(position, lod, LoadReason::ForClient(client_id)));
    },
    ClientToServer::Add(Copyable(player_id)) => {
      let bounds = cast(server, player_id);

      bounds.map(|bounds| {
        let mut rng = server.rng.lock().unwrap();
        let rng = rng.deref_mut();

        let trunk_radius =
          rand::distributions::normal::Normal::new(2.0, 0.5)
          .ind_sample(rng);
        let trunk_radius =
          f64::max(1.0, f64::min(3.0, trunk_radius));

        let trunk_height =
          rand::distributions::normal::Normal::new(8.0 * trunk_radius, 2.0 * trunk_radius)
          .ind_sample(rng);
        let trunk_height =
          f64::max(4.0 * trunk_radius, f64::min(12.0 * trunk_radius, trunk_height));

        let leaf_radius =
          rand::distributions::normal::Normal::new(4.0 * trunk_radius, trunk_radius)
          .ind_sample(rng);
        let leaf_radius =
          f64::max(2.0 * trunk_radius, f64::min(6.0 * trunk_radius, leaf_radius));

        let (low, high) = bounds.corners();
        let mut bottom = low.add_v(&high.to_vec()).div_s(2.0);
        bottom.y = high.y;
        let brush =
          terrain::voxel::brush::tree::T {
            bottom: bottom,
            trunk_height: trunk_height as f32,
            trunk_radius: trunk_radius as f32,
            leaf_radius: leaf_radius as f32,
          };
        update_gaia(ServerToGaia::AddTree(brush));
      });
    },
    ClientToServer::Remove(Copyable(player_id)) => {
      let bounds = cast(server, player_id);

      bounds.map(|bounds| {
        debug!("bounds {:?}", bounds);
        let center = bounds.center();
        let r = 8.0;
        let brush =
          terrain::voxel::brush::sphere::T {
            center: center,
            radius: r,
            material: voxel::Material::Empty,
          };
        update_gaia(ServerToGaia::RemoveSphere(brush));
      });
    },
  };
}
<commit_msg>place trees a little lower<commit_after>use cgmath::{Point, Point3, Vector3, Aabb3};
use rand;
use rand::distributions::IndependentSample;
use std::convert::AsRef;
use std::f64;
use std::f32::consts::PI;
use std::ops::DerefMut;
use std::sync::mpsc::channel;
use std::time::Duration;
use thread_scoped;

use common::communicate::{ClientToServer, ServerToClient};
use common::entity;
use common::serialize;
use common::serialize::Copyable;
use common::socket::SendSocket;

use player::Player;
use server::{Client, Server};
use terrain;
use voxel;
use update_gaia::{ServerToGaia, LoadReason};

fn center(bounds: &Aabb3<f32>) -> Point3<f32> {
  bounds.min.add_v(&bounds.max.to_vec()).mul_s(1.0 / 2.0)
}

fn cast(
  server: &Server,
  player_id: entity::EntityId,
) -> Option<voxel::Bounds> {
  let ray;
  {
    let players = server.players.lock().unwrap();
    let player = players.get(&player_id).unwrap();
    ray = player.forward_ray();
  }

  let terrain_loader = server.terrain_loader.lock().unwrap();
  terrain_loader.terrain.voxels.cast_ray(
    &ray,
    &mut |bounds, voxel| {
      match voxel {
        &terrain::voxel::T::Volume(voxel::Material::Empty) => None,
        _ => Some(bounds),
      }
    }
  )
}

#[inline]
pub fn apply_client_update<UpdateGaia>(
  server: &Server,
  update_gaia: &mut UpdateGaia,
  update: ClientToServer,
) where
  UpdateGaia: FnMut(ServerToGaia),
{
  match update {
    ClientToServer::Init(client_url) => {
      info!("Sending to {}.", client_url);

      let (to_client_send, to_client_recv) = channel();
      let client_thread = unsafe {
        thread_scoped::scoped(move || {
          let mut socket = SendSocket::new(client_url.as_ref(), Some(Duration::from_secs(30)));
          while let Some(msg) = to_client_recv.recv().unwrap() {
            // TODO: Don't do this allocation on every packet!
            let msg = serialize::encode(&msg).unwrap();
            socket.write(msg.as_ref());
          }
        })
      };

      let client_id = server.client_allocator.lock().unwrap().allocate();
      to_client_send.send(Some(ServerToClient::LeaseId(Copyable(client_id)))).unwrap();

      let client =
        Client {
          sender: to_client_send,
          thread: client_thread,
        };
      server.clients.lock().unwrap().insert(client_id, client);
    },
    ClientToServer::Ping(Copyable(client_id)) => {
      server.clients.lock().unwrap()
        .get(&client_id)
        .unwrap()
        .sender
        .send(Some(ServerToClient::Ping(Copyable(()))))
        .unwrap();
    },
    ClientToServer::AddPlayer(Copyable(client_id)) => {
      let mut player =
        Player::new(
          server.id_allocator.lock().unwrap().allocate(),
          &server.owner_allocator,
        );

      // TODO: shift upward until outside terrain
      let min = Point3::new(0.0, 64.0, 4.0);
      let max = min.add_v(&Vector3::new(1.0, 2.0, 1.0));
      let bounds = Aabb3::new(min, max);
      server.physics.lock().unwrap().insert_misc(player.entity_id, bounds.clone());

      player.position = center(&bounds);
      player.rotate_lateral(PI / 2.0);

      let id = player.entity_id;
      let pos = player.position;

      server.players.lock().unwrap().insert(id, player);

      let clients = server.clients.lock().unwrap();
      let client = clients.get(&client_id).unwrap();
      client.sender.send(
        Some(ServerToClient::PlayerAdded(Copyable(id), Copyable(pos)))
      ).unwrap();
    },
    ClientToServer::StartJump(Copyable(player_id)) => {
      let mut players = server.players.lock().unwrap();
      let player = players.get_mut(&player_id).unwrap();
      if !player.is_jumping {
        player.is_jumping = true;
        // this 0.3 is duplicated in a few places
        player.accel.y = player.accel.y + 0.3;
      }
    },
    ClientToServer::StopJump(Copyable(player_id)) => {
      let mut players = server.players.lock().unwrap();
      let player = players.get_mut(&player_id).unwrap();
      if player.is_jumping {
        player.is_jumping = false;
        // this 0.3 is duplicated in a few places
        player.accel.y = player.accel.y - 0.3;
      }
    },
    ClientToServer::Walk(Copyable(player_id), Copyable(v)) => {
      let mut players = server.players.lock().unwrap();
      let mut player = players.get_mut(&player_id).unwrap();
      player.walk(v);
    },
    ClientToServer::RotatePlayer(Copyable(player_id), Copyable(v)) => {
      let mut players = server.players.lock().unwrap();
      let mut player = players.get_mut(&player_id).unwrap();
      player.rotate_lateral(v.x);
      player.rotate_vertical(v.y);
    },
    ClientToServer::RequestBlock(Copyable(client_id), Copyable(position), Copyable(lod)) => {
      update_gaia(ServerToGaia::Load(position, lod, LoadReason::ForClient(client_id)));
    },
    ClientToServer::Add(Copyable(player_id)) => {
      let bounds = cast(server, player_id);

      bounds.map(|bounds| {
        let mut rng = server.rng.lock().unwrap();
        let rng = rng.deref_mut();

        let trunk_radius =
          rand::distributions::normal::Normal::new(2.0, 0.5)
          .ind_sample(rng);
        let trunk_radius =
          f64::max(1.0, f64::min(3.0, trunk_radius));

        let trunk_height =
          rand::distributions::normal::Normal::new(8.0 * trunk_radius, 2.0 * trunk_radius)
          .ind_sample(rng);
        let trunk_height =
          f64::max(4.0 * trunk_radius, f64::min(12.0 * trunk_radius, trunk_height));

        let leaf_radius =
          rand::distributions::normal::Normal::new(4.0 * trunk_radius, trunk_radius)
          .ind_sample(rng);
        let leaf_radius =
          f64::max(2.0 * trunk_radius, f64::min(6.0 * trunk_radius, leaf_radius));

        let (low, high) = bounds.corners();
        let mut bottom = low.add_v(&high.to_vec()).div_s(2.0);
        bottom.y = low.y;
        let brush =
          terrain::voxel::brush::tree::T {
            bottom: bottom,
            trunk_height: trunk_height as f32,
            trunk_radius: trunk_radius as f32,
            leaf_radius: leaf_radius as f32,
          };
        update_gaia(ServerToGaia::AddTree(brush));
      });
    },
    ClientToServer::Remove(Copyable(player_id)) => {
      let bounds = cast(server, player_id);

      bounds.map(|bounds| {
        debug!("bounds {:?}", bounds);
        let center = bounds.center();
        let r = 8.0;
        let brush =
          terrain::voxel::brush::sphere::T {
            center: center,
            radius: r,
            material: voxel::Material::Empty,
          };
        update_gaia(ServerToGaia::RemoveSphere(brush));
      });
    },
  };
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Method %>

// CSS Basic User Interface Module Level 1
// https://drafts.csswg.org/css-ui-3/
<% data.new_style_struct("UI", inherited=False, gecko_name="UIReset") %>

// TODO spec says that UAs should not support this
// we should probably remove from gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=1328331)
${helpers.single_keyword("ime-mode", "normal auto active disabled inactive",
                         products="gecko", gecko_ffi_name="mIMEMode",
                         animatable=False,
                         spec="https://drafts.csswg.org/css-ui/#input-method-editor")}

${helpers.single_keyword("-moz-user-select", "auto text none all", products="gecko",
                         alias="-webkit-user-select",
                         gecko_ffi_name="mUserSelect",
                         gecko_enum_prefix="StyleUserSelect",
                         gecko_inexhaustive=True,
                         animatable=False,
                         spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select")}
<commit_msg>Implement -moz-window-dragging<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Method %>

// CSS Basic User Interface Module Level 1
// https://drafts.csswg.org/css-ui-3/
<% data.new_style_struct("UI", inherited=False, gecko_name="UIReset") %>

// TODO spec says that UAs should not support this
// we should probably remove from gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=1328331)
${helpers.single_keyword("ime-mode", "normal auto active disabled inactive",
                         products="gecko", gecko_ffi_name="mIMEMode",
                         animatable=False,
                         spec="https://drafts.csswg.org/css-ui/#input-method-editor")}

${helpers.single_keyword("-moz-user-select", "auto text none all", products="gecko",
                         alias="-webkit-user-select",
                         gecko_ffi_name="mUserSelect",
                         gecko_enum_prefix="StyleUserSelect",
                         gecko_inexhaustive=True,
                         animatable=False,
                         spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select")}

${helpers.single_keyword("-moz-window-dragging", "default drag no-drag", products="gecko",
                         gecko_ffi_name="mWindowDragging",
                         gecko_enum_prefix="StyleWindowDragging",
                         animatable=False,
                         spec="None (Nonstandard Firefox-only property)")}
<|endoftext|>


<commit_before>pub trait InterruptController
{
    fn reset_external_devices(&mut self); // triggered by RESET instruction
    fn highest_priority(&self) -> u8;
    fn acknowledge_interrupt(&mut self, priority: u8) -> Option<u8>;
}

#[allow(dead_code)]
pub const UNINITIALIZED_INTERRUPT: u8 = 0x0F;
pub const SPURIOUS_INTERRUPT: u8 = 0x18;
const AUTOVECTOR_BASE: u8 = 0x18;

pub struct AutoInterruptController {
    level: u8
}
impl AutoInterruptController {
    pub fn new() -> AutoInterruptController {
        AutoInterruptController { level: 0 }
    }

    pub fn request_interrupt(&mut self, irq: u8) -> u8
    {
        assert!(irq > 0 && irq < 8);
        self.level |= 1 << irq - 1;
        self.level
    }
}
impl InterruptController for AutoInterruptController {
    fn reset_external_devices(&mut self)
    {
        // not a required effect of the RESET instruction, but assuming that
        // any external devices reset, also reset their
        // interrupt request state
        self.level = 0;
    }

    fn highest_priority(&self) -> u8 {
        (8 - self.level.leading_zeros()) as u8
    }

    fn acknowledge_interrupt(&mut self, priority: u8) -> Option<u8> {
        self.level &= !(1 << priority - 1);
        Some(AUTOVECTOR_BASE + priority)
    }
}

#[cfg(test)]
mod tests {
    use super::{InterruptController, AutoInterruptController,
        AUTOVECTOR_BASE};

    #[test]
    fn keeps_track_of_priority() {
        let mut ctrl = AutoInterruptController { level: 0 };
        ctrl.request_interrupt(2);
        ctrl.request_interrupt(5);
        assert_eq!(5, ctrl.highest_priority());
    }
    #[test]
    fn auto_resets_on_ack() {
        let mut ctrl = AutoInterruptController { level: 0 };
        ctrl.request_interrupt(2);
        ctrl.request_interrupt(5);
        assert_eq!(Some(AUTOVECTOR_BASE + 5), ctrl.acknowledge_interrupt(5));
        assert_eq!(2, ctrl.highest_priority());
    }
    #[test]
    fn resets_irq_level_on_external_device_reset() {
        let mut ctrl = AutoInterruptController { level: 0 };
        ctrl.request_interrupt(2);
        ctrl.request_interrupt(5);
        ctrl.reset_external_devices();
        assert_eq!(0, ctrl.highest_priority());
    }
}<commit_msg>Derive Default for AutoInterruptController<commit_after>pub trait InterruptController
{
    fn reset_external_devices(&mut self); // triggered by RESET instruction
    fn highest_priority(&self) -> u8;
    fn acknowledge_interrupt(&mut self, priority: u8) -> Option<u8>;
}

#[allow(dead_code)]
pub const UNINITIALIZED_INTERRUPT: u8 = 0x0F;
pub const SPURIOUS_INTERRUPT: u8 = 0x18;
const AUTOVECTOR_BASE: u8 = 0x18;

#[derive(Default)]
pub struct AutoInterruptController {
    level: u8
}
impl AutoInterruptController {
    pub fn new() -> AutoInterruptController {
        AutoInterruptController { level: 0 }
    }

    pub fn request_interrupt(&mut self, irq: u8) -> u8
    {
        assert!(irq > 0 && irq < 8);
        self.level |= 1 << irq - 1;
        self.level
    }
}
impl InterruptController for AutoInterruptController {
    fn reset_external_devices(&mut self)
    {
        // not a required effect of the RESET instruction, but assuming that
        // any external devices reset, also reset their
        // interrupt request state
        self.level = 0;
    }

    fn highest_priority(&self) -> u8 {
        (8 - self.level.leading_zeros()) as u8
    }

    fn acknowledge_interrupt(&mut self, priority: u8) -> Option<u8> {
        self.level &= !(1 << priority - 1);
        Some(AUTOVECTOR_BASE + priority)
    }
}

#[cfg(test)]
mod tests {
    use super::{InterruptController, AutoInterruptController,
        AUTOVECTOR_BASE};

    #[test]
    fn keeps_track_of_priority() {
        let mut ctrl = AutoInterruptController { level: 0 };
        ctrl.request_interrupt(2);
        ctrl.request_interrupt(5);
        assert_eq!(5, ctrl.highest_priority());
    }
    #[test]
    fn auto_resets_on_ack() {
        let mut ctrl = AutoInterruptController { level: 0 };
        ctrl.request_interrupt(2);
        ctrl.request_interrupt(5);
        assert_eq!(Some(AUTOVECTOR_BASE + 5), ctrl.acknowledge_interrupt(5));
        assert_eq!(2, ctrl.highest_priority());
    }
    #[test]
    fn resets_irq_level_on_external_device_reset() {
        let mut ctrl = AutoInterruptController { level: 0 };
        ctrl.request_interrupt(2);
        ctrl.request_interrupt(5);
        ctrl.reset_external_devices();
        assert_eq!(0, ctrl.highest_priority());
    }
}<|endoftext|>


<commit_before>use master_smasher::drawable::{Asset, Drawable};
use master_smasher::shape::{Circle, Intersect};
use super::world_assets::WorldAssets;
use super::collidable::Collidable;
use super::level_data::{PlanetData, PlanetKind};

use glm::{self, GenNum};
use glm::ext::normalize_to;
use num_traits::Zero;

use std::cmp;
use std::time::Duration;

struct Ring {
    radius: f64,
    strength: f64,
    asset: Asset,
    zoom: f64,
}

impl Ring {
    pub fn new(radius: f64, strength: f64, asset: Asset) -> Self {
        Ring {
            radius: radius,
            strength: strength,
            asset: asset,
            zoom: 1.,
        }
    }

    pub fn animate(&mut self, delta: Duration) {
        const K: f64 = 0.166;
        let moving_radius = self.asset.dims().x as f64 * self.zoom / 2.;
        let pull = glm::length(self.pull_vector(glm::dvec2(moving_radius, 0.), 0.));
        let time = delta.as_secs() as f64 + delta.subsec_nanos() as f64 / 1000000000.;
        self.zoom *= 1. / 2_f64.powf(K * pull * time);
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        let mut moving = self.asset.clone();
        moving.zoom(glm::DVec2::from_s(self.zoom));
        vec![Drawable::Asset(self.asset), Drawable::Asset(moving)]
    }

    pub fn pull_vector(&self, dist: glm::DVec2, radius: f64) -> glm::DVec2 {
        let len = glm::length(dist);
        if len > (self.radius + radius) {
            glm::DVec2::zero()
        } else {
            let force = self.strength / (len.powf(0.8));
            normalize_to(dist, force)
        }
    }
}

pub struct Planet {
    body: Circle,
    asset: Asset,
    ring: Option<Ring>,
}

impl Planet {
    pub fn new(data: &PlanetData, textures: &WorldAssets) -> Self {
        let (asset, ring) = Self::load_assets(data, textures);
        let dims = asset.dims();
        let radius = cmp::min(dims.x, dims.y) as f64 / 2.;
        let center = glm::dvec2(data.x as f64, data.y as f64);
        let body = Circle {
            center: center,
            radius: radius,
        };

        Planet {
            body: body,
            asset: asset,
            ring: ring,
        }
    }

    pub fn animate(&mut self, delta: Duration) {
        if let Some(ref mut r) = self.ring {
            if r.asset.dims().x as f64 * r.zoom / 2. < self.body.radius {
                r.zoom = 1.;
            }
            r.animate(delta)
        }
    }

    pub fn pull_vector(&self, point: glm::DVec2, radius: f64) -> glm::DVec2 {
        self.ring.as_ref().map_or(glm::DVec2::zero(),
                                  |r| r.pull_vector(self.body.center - point, radius))
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        let mut drawables = self.ring.as_ref().map_or(vec![], |r| r.drawables());
        drawables.push(Drawable::Asset(self.asset));
        drawables
    }

    fn load_assets(data: &PlanetData, textures: &WorldAssets) -> (Asset, Option<Ring>) {
        let center = glm::ivec2(data.x, data.y);
        let (planet, ring) = match data.kind {
            PlanetKind::RED { ring, strength } => {
                (textures.red_planet, Some((textures.red_ring, ring, strength)))
            }
            PlanetKind::BLUE { ring, strength } => {
                (textures.blue_planet, Some((textures.blue_ring, ring, strength)))
            }
            PlanetKind::WHITE { ring, strength } => {
                (textures.white_planet, Some((textures.white_ring, ring, strength)))
            }
            PlanetKind::DEAD => (textures.dead_planet, None),
        };

        let planet = Asset::from_texture(&planet, center);
        let ring = ring.map(|(t, r, s)| {
            let dims = glm::UVec2::from_s((r * 2.) as u32);
            let asset = Asset::centered_on(t.id, center, dims);
            Ring::new(r, s, asset)
        });

        (planet, ring)
    }
}

impl<I: Intersect<Circle>> Collidable<Circle, I> for Planet {
    fn collides(&self, shape: &I) -> bool {
        shape.intersects(&self.body)
    }
}
<commit_msg>one less magic number<commit_after>use master_smasher::drawable::{Asset, Drawable};
use master_smasher::shape::{Circle, Intersect};
use super::world_assets::WorldAssets;
use super::collidable::Collidable;
use super::level_data::{PlanetData, PlanetKind};

use glm::{self, GenNum};
use glm::ext::normalize_to;
use num_traits::Zero;

use std::cmp;
use std::time::Duration;

struct Ring {
    radius: f64,
    strength: f64,
    asset: Asset,
    zoom: f64,
}

impl Ring {
    pub fn new(radius: f64, strength: f64, asset: Asset) -> Self {
        Ring {
            radius: radius,
            strength: strength,
            asset: asset,
            zoom: 1.,
        }
    }

    pub fn animate(&mut self, delta: Duration) {
        const K: f64 = 0.166;
        const NANO_IN_SEC: f64 = 1000000000.;
        let moving_radius = self.asset.dims().x as f64 * self.zoom / 2.;
        let pull = glm::length(self.pull_vector(glm::dvec2(moving_radius, 0.), 0.));
        let time = delta.as_secs() as f64 + delta.subsec_nanos() as f64 / NANO_IN_SEC;
        self.zoom *= 1. / 2_f64.powf(K * pull * time);
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        let mut moving = self.asset.clone();
        moving.zoom(glm::DVec2::from_s(self.zoom));
        vec![Drawable::Asset(self.asset), Drawable::Asset(moving)]
    }

    pub fn pull_vector(&self, dist: glm::DVec2, radius: f64) -> glm::DVec2 {
        let len = glm::length(dist);
        if len > (self.radius + radius) {
            glm::DVec2::zero()
        } else {
            let force = self.strength / (len.powf(0.8));
            normalize_to(dist, force)
        }
    }
}

pub struct Planet {
    body: Circle,
    asset: Asset,
    ring: Option<Ring>,
}

impl Planet {
    pub fn new(data: &PlanetData, textures: &WorldAssets) -> Self {
        let (asset, ring) = Self::load_assets(data, textures);
        let dims = asset.dims();
        let radius = cmp::min(dims.x, dims.y) as f64 / 2.;
        let center = glm::dvec2(data.x as f64, data.y as f64);
        let body = Circle {
            center: center,
            radius: radius,
        };

        Planet {
            body: body,
            asset: asset,
            ring: ring,
        }
    }

    pub fn animate(&mut self, delta: Duration) {
        if let Some(ref mut r) = self.ring {
            if r.asset.dims().x as f64 * r.zoom / 2. < self.body.radius {
                r.zoom = 1.;
            }
            r.animate(delta)
        }
    }

    pub fn pull_vector(&self, point: glm::DVec2, radius: f64) -> glm::DVec2 {
        self.ring.as_ref().map_or(glm::DVec2::zero(),
                                  |r| r.pull_vector(self.body.center - point, radius))
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        let mut drawables = self.ring.as_ref().map_or(vec![], |r| r.drawables());
        drawables.push(Drawable::Asset(self.asset));
        drawables
    }

    fn load_assets(data: &PlanetData, textures: &WorldAssets) -> (Asset, Option<Ring>) {
        let center = glm::ivec2(data.x, data.y);
        let (planet, ring) = match data.kind {
            PlanetKind::RED { ring, strength } => {
                (textures.red_planet, Some((textures.red_ring, ring, strength)))
            }
            PlanetKind::BLUE { ring, strength } => {
                (textures.blue_planet, Some((textures.blue_ring, ring, strength)))
            }
            PlanetKind::WHITE { ring, strength } => {
                (textures.white_planet, Some((textures.white_ring, ring, strength)))
            }
            PlanetKind::DEAD => (textures.dead_planet, None),
        };

        let planet = Asset::from_texture(&planet, center);
        let ring = ring.map(|(t, r, s)| {
            let dims = glm::UVec2::from_s((r * 2.) as u32);
            let asset = Asset::centered_on(t.id, center, dims);
            Ring::new(r, s, asset)
        });

        (planet, ring)
    }
}

impl<I: Intersect<Circle>> Collidable<Circle, I> for Planet {
    fn collides(&self, shape: &I) -> bool {
        shape.intersects(&self.body)
    }
}
<|endoftext|>