<commit_before>use ascii::{AsAsciiStrError, AsciiChar, AsciiStr, ToAsciiChar, ToAsciiCharError};
use std::ascii::AsciiExt;
use std::borrow::{Borrow, BorrowMut};
use std::cmp::{Eq, PartialEq};
use std::convert::{AsRef, AsMut, From, Into};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::{fmt, mem, ptr, slice, str};
use ::{PascalStr, PASCAL_STRING_BUF_SIZE};

/// An owned `PascalString`. This string type stores its data the stack. It is always 256 bytes long, with
/// the first byte storing the length.
///
/// This string type uses Ascii encoding.
pub struct PascalString {
    /// The length of this string.
    len: u8,
    /// The characters of this string, encoded as an ascii array.
    chars: [AsciiChar; PASCAL_STRING_BUF_SIZE]
}

impl PascalString {
    /// Creates a new, empty `PascalString`.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Create a new `PascalString` using the contents of `bytes`.
    ///
    /// Returns an `Err` if `bytes` is longer than 255 characters, or it does not contain
    /// Ascii encoded characters.
    #[inline]
    pub fn from<B: AsRef<[u8]>>(bytes: B) -> Result<Self, PascalStringCreateError> {
        PascalString::_from(bytes.as_ref())
    }

    fn _from(bytes: &[u8]) -> Result<Self, PascalStringCreateError>  {
        let len = bytes.len();
        if len > PASCAL_STRING_BUF_SIZE {
            return Err(PascalStringCreateError::InputTooLong);
        }
        // Perform ascii check
        let ascii = try!(AsciiStr::from_ascii(bytes));

        let mut string = PascalString::new();
        string.len = len as u8;
        for i in 0..len {
            string[i] = ascii[i];
        }
        Ok(string)
    }

    /// Push an ascii convertible character onto this string.
    ///
    /// # Panics
    ///
    /// Panics if the string is full, of if the `character` is not a valid ascii character.
    #[inline]
    pub fn push<C: ToAsciiChar>(&mut self, character: C) {
        self.try_push(character).unwrap();
    }

    /// Attempt to push an ascii convertible character onto the end of this `PascalString`.
    ///
    /// Returns `Err(_)` if the character cannot be pushed because this `PascalString` is full, or if
    /// `character` is not a valid ascii character.
    #[inline]
    pub fn try_push<C: ToAsciiChar>(&mut self, character: C) -> Result<(), PascalStringAppendError> {
        self._try_push(try!(AsciiChar::from(character)))
    }

    fn _try_push(&mut self, ch: AsciiChar) -> Result<(), PascalStringAppendError> {
        if self.is_full() {
            return Err(PascalStringAppendError::AppendedStringTooLong)
        }
        self.len += 1;
        let idx = self.len - 1;
        self[idx] = ch;
        self.set_trailing_byte_to_null();
        Ok(())
    }

    /// Append a given string slice onto the end of this `PascalString`.
    ///
    /// # Panics
    ///
    /// Panics if the string cannot be pushed to because this `PascalString` is full.
    #[inline]
    pub fn push_str<S: AsRef<str>>(&mut self, s: S) {
        self.try_push_str(s).unwrap();
    }

    /// Attempt to append a given string slice onto the end of this `PascalString`.
    ///
    /// Returns `Err(_)` if the string cannot be pushed because this `PascalString` is full.
    #[inline]
    pub fn try_push_str<S: AsRef<str>>(&mut self, s: S) -> Result<(), PascalStringAppendError> {
        self._try_push_str(s.as_ref())
    }

    fn _try_push_str(&mut self, s: &str) -> Result<(), PascalStringAppendError> {
        unimplemented!()
    }

    /// Removes the last character from the string buffer and returns it.
    ///
    /// Returns `None` if this `PascalString` is empty.
    pub fn pop(&mut self) -> Option<AsciiChar> {
        if self.is_empty() {
            return None;
        }
        let c = self.chars[self.len as usize];
        self.len -= 1;
        self.set_trailing_byte_to_null();
        Some(c)
    }

    pub fn remove(&mut self, index: u8) -> AsciiChar {
        assert!(self.len < index);
        let len = self.len as usize;
        let index = index as isize;
        let c = self[len];
        // Shift everything to the right of the removed character to the left to cover up the hole
        // left.
        unsafe {
            let ptr = self.as_mut_ptr().offset(index);
            ptr::copy(ptr.offset(1), ptr, len - index.abs() as usize - 1);
        }
        self.len -= 1;
        self.set_trailing_byte_to_null();
        c
    }

    #[inline]
    pub fn insert<C: ToAsciiChar>(&mut self, ch: C, index: u8) {
        self._insert(AsciiChar::from(ch).unwrap(), index)
    }

    fn _insert(&mut self, ch: AsciiChar, index: u8) {
        assert!(self.len < index);
        assert!(!self.is_full());
        let len = self.len as usize;
        let index = index as isize;
        // Shift everything to the right of `index` 1 place to the right to make room for the
        // new character.
        unsafe {
            let ptr = self.as_mut_ptr().offset(index);
            ptr::copy(ptr, ptr.offset(1), len - index.abs() as usize - 1);
        }
        self[len] = ch;
        self.len += 1;
        self.set_trailing_byte_to_null();
    }

    /// Truncates this String, removing all contents.
    ///
    /// Does not zero the values of the string.
    #[inline]
    pub fn clear(&mut self) {
        self.len = 0;
        self.set_trailing_byte_to_null();
    }

    /// Consumes this `PascalString`, and returns its inner state as a `[u8; 256]`, where the first byte
    /// is the length.
    ///
    /// Note that if the string has been truncated, bytes beyond the end of the string will not have been
    /// zeroed.
    #[inline]
    pub fn to_array(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
        self.into()
    }

    /// Get a character in the string, without checking if the index is within the bounds of `len()`.
    ///
    /// This method cannot cause memory unsafety because of the size of `index`. However, it can give access
    /// to stale characters if `index` is greater than `len()`, and `len() < 255`.
    #[inline]
    pub fn get_unchecked(&self, index: u8) -> AsciiChar {
        self.chars[index as usize]
    }

    #[inline]
    fn set_trailing_byte_to_null(&mut self) {
        if !self.is_full() {
            self.chars[self.len as usize] = AsciiChar::Null;
        }
    }
}

impl Default for PascalString {
    #[inline]
    fn default() -> Self {
        PascalString {
            len: 0,
            chars: [AsciiChar::Null; PASCAL_STRING_BUF_SIZE]
        }
    }
}

impl Clone for PascalString {
    fn clone(&self) -> Self {
        let mut clone = PascalString::default();
        clone.len = self.len;
        unsafe {
            ptr::copy_nonoverlapping(&self.chars, &mut clone.chars, PASCAL_STRING_BUF_SIZE);
        }
        clone
    }
}

impl Eq for PascalString { }

impl PartialEq for PascalString {
    fn eq(&self, other: &PascalString) -> bool {
        if self.len != other.len {
            return false;
        }
        self.chars.iter().zip(other.chars.iter()).all(|(c0, c1)| c0 == c1)
    }
}

impl Hash for PascalString {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u8(self.len);
        state.write(self.as_ref());
    }
}

impl AsciiExt for PascalString {
    type Owned = Self;

    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Self::Owned {
        let mut upper = self.clone();
        upper.make_ascii_uppercase();
        upper
    }

    fn to_ascii_lowercase(&self) -> Self::Owned {
        let mut lower = self.clone();
        lower.make_ascii_lowercase();
        lower
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.chars().zip(other.chars()).all(|(c0, c1)| c0.eq_ignore_ascii_case(&c1))
    }

    #[inline]
    fn make_ascii_uppercase(&mut self) {
        for c in self.chars_mut() {
            c.make_ascii_uppercase();
        }
    }

    #[inline]
    fn make_ascii_lowercase(&mut self) {
        for c in self.chars_mut() {
            c.make_ascii_lowercase();
        }
    }
}

impl fmt::Debug for PascalString {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        write!(fmtr, "{}", self)
    }
}

impl fmt::Display for PascalString {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        fmtr.pad(self.as_ref())
    }
}

impl Deref for PascalString {
    type Target = PascalStr;
    fn deref(&self) -> &Self::Target {
        let ascii_str: &[AsciiChar] = self.as_ref();
        unsafe {
            mem::transmute(ascii_str)
        }
    }
}

impl DerefMut for PascalString {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let ascii_str: &mut [AsciiChar] = self.as_mut();
        unsafe {
            mem::transmute(ascii_str)
        }
    }
}

impl AsRef<PascalStr> for PascalString {
    fn as_ref(&self) -> &PascalStr {
        self.deref()
    }
}

impl AsRef<str> for PascalString {
    fn as_ref(&self) -> &str {
        let bytes: &[u8] = self.as_ref();
        str::from_utf8(bytes).unwrap()
    }
}

impl AsRef<[u8]> for PascalString {
    fn as_ref(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(self.chars.as_ptr() as *const u8, self.len as usize)
        }
    }
}

impl AsRef<AsciiStr> for PascalString {
    fn as_ref(&self) -> &AsciiStr {
        let bytes: &[u8] = self.as_ref();
        AsciiStr::from_ascii(bytes).unwrap()
    }
}

impl AsRef<[AsciiChar]> for PascalString {
    fn as_ref(&self) -> &[AsciiChar] {
        unsafe {
            slice::from_raw_parts(self.chars.as_ptr(), self.len as usize)
        }
    }
}

impl AsMut<[AsciiChar]> for PascalString {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        unsafe {
            slice::from_raw_parts_mut(self.chars.as_mut_ptr(), self.len as usize)
        }
    }
}

impl Borrow<PascalStr> for PascalString {
    #[inline]
    fn borrow(&self) -> &PascalStr {
        self.deref()
    }
}

impl BorrowMut<PascalStr> for PascalString {
    #[inline]
    fn borrow_mut(&mut self) -> &mut PascalStr {
        self.deref_mut()
    }
}

impl Borrow<str> for PascalString {
    #[inline]
    fn borrow(&self) -> &str {
        self.as_ref()
    }
}

impl Borrow<[u8]> for PascalString {
    #[inline]
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl Borrow<AsciiStr> for PascalString {
    #[inline]
    fn borrow(&self) -> &AsciiStr {
        self.as_ref()
    }
}

impl Borrow<[AsciiChar]> for PascalString {
    #[inline]
    fn borrow(&self) -> &[AsciiChar] {
        self.as_ref()
    }
}

impl BorrowMut<[AsciiChar]> for PascalString {
    #[inline]
    fn borrow_mut(&mut self) -> &mut [AsciiChar] {
        self.as_mut()
    }
}

impl Into<[u8; PASCAL_STRING_BUF_SIZE + 1]> for PascalString {
    fn into(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
        let mut array = [0u8; PASCAL_STRING_BUF_SIZE + 1];
        array[0] = self.len;
        unsafe {
            let chars_ptr = &self.chars as *const _ as *const [u8; PASCAL_STRING_BUF_SIZE];
            let array_ptr = (&mut array as *mut _).offset(1) as *mut [u8; PASCAL_STRING_BUF_SIZE];
            ptr::copy_nonoverlapping(chars_ptr, array_ptr, PASCAL_STRING_BUF_SIZE);
        }
        array
    }
}

impl Into<String> for PascalString {
    #[inline]
    fn into(self) -> String {
        String::from_utf8_lossy(self.as_ref()).into_owned()
    }
}

impl Into<Vec<u8>> for PascalString {
    fn into(self) -> Vec<u8> {
        let mut v = Vec::with_capacity(self.len());
        v.extend_from_slice(self.as_ref());
        v
    }
}

#[derive(Debug, PartialEq)]
pub enum PascalStringCreateError {
    InputTooLong,
    NotValidAscii(AsAsciiStrError)
}

impl From<AsAsciiStrError> for PascalStringCreateError {
    #[inline]
    fn from(e: AsAsciiStrError) -> Self {
        PascalStringCreateError::NotValidAscii(e)
    }
}

#[derive(Debug, PartialEq)]
pub enum PascalStringAppendError {
    AppendedStringTooLong,
    InvalidCharAppended(ToAsciiCharError),
    InvalidStringAppended(AsAsciiStrError)
}

impl From<ToAsciiCharError> for PascalStringAppendError {
    #[inline]
    fn from(e: ToAsciiCharError) -> Self {
        PascalStringAppendError::InvalidCharAppended(e)
    }
}

impl From<AsAsciiStrError> for PascalStringAppendError {
    #[inline]
    fn from(e: AsAsciiStrError) -> Self {
        PascalStringAppendError::InvalidStringAppended(e)
    }
}<commit_msg>Add PascalString::from_fixed_ascii_array, and improve error types.<commit_after>use ascii::{AsAsciiStrError, AsciiChar, AsciiStr, ToAsciiChar, ToAsciiCharError};
use std::ascii::AsciiExt;
use std::borrow::{Borrow, BorrowMut};
use std::cmp::{Eq, PartialEq};
use std::convert::{AsRef, AsMut, From, Into};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::{fmt, mem, ptr, slice, str};
use ::{PascalStr, PASCAL_STRING_BUF_SIZE};

/// An owned `PascalString`. This string type stores its data the stack. It is always 256 bytes long, with
/// the first byte storing the length.
///
/// This string type uses Ascii encoding.
pub struct PascalString {
    /// The length of this string.
    len: u8,
    /// The characters of this string, encoded as an ascii array.
    chars: [AsciiChar; PASCAL_STRING_BUF_SIZE]
}

impl PascalString {
    /// Creates a new, empty `PascalString`.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Create a new `PascalString` from its constituent parts: `string_len` and `char_array`.
    ///
    /// Returns an `Err` if `char_array` is not valid Ascii.
    #[inline]
    pub fn from_fixed_ascii_array<C>(string_len: u8, char_array: [C; 255]) -> Result<Self, PascalStringCreateError>
        where C: ToAsciiChar + Clone {
        let mut pstring = PascalString::new();
        pstring.len = string_len;
        for i in 0..(pstring.len as usize) {
            pstring[i] = try!(AsciiChar::from(char_array[i].clone()));
        }
        Ok(pstring)
    }

    /// Create a new `PascalString` using the contents of `bytes`.
    ///
    /// Returns an `Err` if `bytes` is longer than 255 characters, or it does not contain
    /// Ascii encoded characters.
    #[inline]
    pub fn from<B: AsRef<[u8]>>(bytes: B) -> Result<Self, PascalStringCreateError> {
        PascalString::_from(bytes.as_ref())
    }

    fn _from(bytes: &[u8]) -> Result<Self, PascalStringCreateError>  {
        let len = bytes.len();
        if len > PASCAL_STRING_BUF_SIZE {
            return Err(PascalStringCreateError::InputTooLong);
        }
        // Perform ascii check
        let ascii = try!(AsciiStr::from_ascii(bytes));

        let mut string = PascalString::new();
        string.len = len as u8;
        for i in 0..len {
            string[i] = ascii[i];
        }
        Ok(string)
    }

    /// Push an ascii convertible character onto this string.
    ///
    /// # Panics
    ///
    /// Panics if the string is full, of if the `character` is not a valid ascii character.
    #[inline]
    pub fn push<C: ToAsciiChar>(&mut self, character: C) {
        self.try_push(character).unwrap();
    }

    /// Attempt to push an ascii convertible character onto the end of this `PascalString`.
    ///
    /// Returns `Err(_)` if the character cannot be pushed because this `PascalString` is full, or if
    /// `character` is not a valid ascii character.
    #[inline]
    pub fn try_push<C: ToAsciiChar>(&mut self, character: C) -> Result<(), PascalStringAppendError> {
        self._try_push(try!(AsciiChar::from(character)))
    }

    fn _try_push(&mut self, ch: AsciiChar) -> Result<(), PascalStringAppendError> {
        if self.is_full() {
            return Err(PascalStringAppendError::AppendedStringTooLong)
        }
        self.len += 1;
        let idx = self.len - 1;
        self[idx] = ch;
        self.set_trailing_byte_to_null();
        Ok(())
    }

    /// Append a given string slice onto the end of this `PascalString`.
    ///
    /// # Panics
    ///
    /// Panics if the string cannot be pushed to because this `PascalString` is full.
    #[inline]
    pub fn push_str<S: AsRef<str>>(&mut self, s: S) {
        self.try_push_str(s).unwrap();
    }

    /// Attempt to append a given string slice onto the end of this `PascalString`.
    ///
    /// Returns `Err(_)` if the string cannot be pushed because this `PascalString` is full.
    #[inline]
    pub fn try_push_str<S: AsRef<str>>(&mut self, s: S) -> Result<(), PascalStringAppendError> {
        self._try_push_str(s.as_ref())
    }

    fn _try_push_str(&mut self, s: &str) -> Result<(), PascalStringAppendError> {
        unimplemented!()
    }

    /// Removes the last character from the string buffer and returns it.
    ///
    /// Returns `None` if this `PascalString` is empty.
    pub fn pop(&mut self) -> Option<AsciiChar> {
        if self.is_empty() {
            return None;
        }
        let c = self.chars[self.len as usize];
        self.len -= 1;
        self.set_trailing_byte_to_null();
        Some(c)
    }

    pub fn remove(&mut self, index: u8) -> AsciiChar {
        assert!(self.len < index);
        let len = self.len as usize;
        let index = index as isize;
        let c = self[len];
        // Shift everything to the right of the removed character to the left to cover up the hole
        // left.
        unsafe {
            let ptr = self.as_mut_ptr().offset(index);
            ptr::copy(ptr.offset(1), ptr, len - index.abs() as usize - 1);
        }
        self.len -= 1;
        self.set_trailing_byte_to_null();
        c
    }

    #[inline]
    pub fn insert<C: ToAsciiChar>(&mut self, ch: C, index: u8) {
        self._insert(AsciiChar::from(ch).unwrap(), index)
    }

    fn _insert(&mut self, ch: AsciiChar, index: u8) {
        assert!(self.len < index);
        assert!(!self.is_full());
        let len = self.len as usize;
        let index = index as isize;
        // Shift everything to the right of `index` 1 place to the right to make room for the
        // new character.
        unsafe {
            let ptr = self.as_mut_ptr().offset(index);
            ptr::copy(ptr, ptr.offset(1), len - index.abs() as usize - 1);
        }
        self[len] = ch;
        self.len += 1;
        self.set_trailing_byte_to_null();
    }

    /// Truncates this String, removing all contents.
    ///
    /// Does not zero the values of the string.
    #[inline]
    pub fn clear(&mut self) {
        self.len = 0;
        self.set_trailing_byte_to_null();
    }

    /// Consumes this `PascalString`, and returns its inner state as a `[u8; 256]`, where the first byte
    /// is the length.
    ///
    /// Note that if the string has been truncated, bytes beyond the end of the string will not have been
    /// zeroed.
    #[inline]
    pub fn to_array(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
        self.into()
    }

    /// Get a character in the string, without checking if the index is within the bounds of `len()`.
    ///
    /// This method cannot cause memory unsafety because of the size of `index`. However, it can give access
    /// to stale characters if `index` is greater than `len()`, and `len() < 255`.
    #[inline]
    pub fn get_unchecked(&self, index: u8) -> AsciiChar {
        self.chars[index as usize]
    }

    #[inline]
    fn set_trailing_byte_to_null(&mut self) {
        if !self.is_full() {
            self.chars[self.len as usize] = AsciiChar::Null;
        }
    }
}

impl Default for PascalString {
    #[inline]
    fn default() -> Self {
        PascalString {
            len: 0,
            chars: [AsciiChar::Null; PASCAL_STRING_BUF_SIZE]
        }
    }
}

impl Clone for PascalString {
    fn clone(&self) -> Self {
        let mut clone = PascalString::default();
        clone.len = self.len;
        unsafe {
            ptr::copy_nonoverlapping(&self.chars, &mut clone.chars, PASCAL_STRING_BUF_SIZE);
        }
        clone
    }
}

impl Eq for PascalString { }

impl PartialEq for PascalString {
    fn eq(&self, other: &PascalString) -> bool {
        if self.len != other.len {
            return false;
        }
        self.chars.iter().zip(other.chars.iter()).all(|(c0, c1)| c0 == c1)
    }
}

impl Hash for PascalString {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u8(self.len);
        state.write(self.as_ref());
    }
}

impl AsciiExt for PascalString {
    type Owned = Self;

    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Self::Owned {
        let mut upper = self.clone();
        upper.make_ascii_uppercase();
        upper
    }

    fn to_ascii_lowercase(&self) -> Self::Owned {
        let mut lower = self.clone();
        lower.make_ascii_lowercase();
        lower
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.chars().zip(other.chars()).all(|(c0, c1)| c0.eq_ignore_ascii_case(&c1))
    }

    #[inline]
    fn make_ascii_uppercase(&mut self) {
        for c in self.chars_mut() {
            c.make_ascii_uppercase();
        }
    }

    #[inline]
    fn make_ascii_lowercase(&mut self) {
        for c in self.chars_mut() {
            c.make_ascii_lowercase();
        }
    }
}

impl fmt::Debug for PascalString {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        write!(fmtr, "{}", self)
    }
}

impl fmt::Display for PascalString {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        fmtr.pad(self.as_ref())
    }
}

impl Deref for PascalString {
    type Target = PascalStr;
    fn deref(&self) -> &Self::Target {
        let ascii_str: &[AsciiChar] = self.as_ref();
        unsafe {
            mem::transmute(ascii_str)
        }
    }
}

impl DerefMut for PascalString {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let ascii_str: &mut [AsciiChar] = self.as_mut();
        unsafe {
            mem::transmute(ascii_str)
        }
    }
}

impl AsRef<PascalStr> for PascalString {
    fn as_ref(&self) -> &PascalStr {
        self.deref()
    }
}

impl AsRef<str> for PascalString {
    fn as_ref(&self) -> &str {
        let bytes: &[u8] = self.as_ref();
        str::from_utf8(bytes).unwrap()
    }
}

impl AsRef<[u8]> for PascalString {
    fn as_ref(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(self.chars.as_ptr() as *const u8, self.len as usize)
        }
    }
}

impl AsRef<AsciiStr> for PascalString {
    fn as_ref(&self) -> &AsciiStr {
        let bytes: &[u8] = self.as_ref();
        AsciiStr::from_ascii(bytes).unwrap()
    }
}

impl AsRef<[AsciiChar]> for PascalString {
    fn as_ref(&self) -> &[AsciiChar] {
        unsafe {
            slice::from_raw_parts(self.chars.as_ptr(), self.len as usize)
        }
    }
}

impl AsMut<[AsciiChar]> for PascalString {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        unsafe {
            slice::from_raw_parts_mut(self.chars.as_mut_ptr(), self.len as usize)
        }
    }
}

impl Borrow<PascalStr> for PascalString {
    #[inline]
    fn borrow(&self) -> &PascalStr {
        self.deref()
    }
}

impl BorrowMut<PascalStr> for PascalString {
    #[inline]
    fn borrow_mut(&mut self) -> &mut PascalStr {
        self.deref_mut()
    }
}

impl Borrow<str> for PascalString {
    #[inline]
    fn borrow(&self) -> &str {
        self.as_ref()
    }
}

impl Borrow<[u8]> for PascalString {
    #[inline]
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl Borrow<AsciiStr> for PascalString {
    #[inline]
    fn borrow(&self) -> &AsciiStr {
        self.as_ref()
    }
}

impl Borrow<[AsciiChar]> for PascalString {
    #[inline]
    fn borrow(&self) -> &[AsciiChar] {
        self.as_ref()
    }
}

impl BorrowMut<[AsciiChar]> for PascalString {
    #[inline]
    fn borrow_mut(&mut self) -> &mut [AsciiChar] {
        self.as_mut()
    }
}

impl Into<[u8; PASCAL_STRING_BUF_SIZE + 1]> for PascalString {
    fn into(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
        let mut array = [0u8; PASCAL_STRING_BUF_SIZE + 1];
        array[0] = self.len;
        unsafe {
            let chars_ptr = &self.chars as *const _ as *const [u8; PASCAL_STRING_BUF_SIZE];
            let array_ptr = (&mut array as *mut _).offset(1) as *mut [u8; PASCAL_STRING_BUF_SIZE];
            ptr::copy_nonoverlapping(chars_ptr, array_ptr, PASCAL_STRING_BUF_SIZE);
        }
        array
    }
}

impl Into<String> for PascalString {
    #[inline]
    fn into(self) -> String {
        String::from_utf8_lossy(self.as_ref()).into_owned()
    }
}

impl Into<Vec<u8>> for PascalString {
    fn into(self) -> Vec<u8> {
        let mut v = Vec::with_capacity(self.len());
        v.extend_from_slice(self.as_ref());
        v
    }
}

#[derive(Debug, PartialEq)]
pub enum PascalStringCreateError {
    InputTooLong,
    NotValidAscii(AsciiError)
}

impl<E: Into<AsciiError>> From<E> for PascalStringCreateError {
    #[inline]
    fn from(e: E) -> Self {
        PascalStringCreateError::NotValidAscii(e.into())
    }
}

#[derive(Debug, PartialEq)]
pub enum PascalStringAppendError {
    AppendedStringTooLong,
    InvalidCharAppended(ToAsciiCharError),
    InvalidStringAppended(AsAsciiStrError)
}

impl From<ToAsciiCharError> for PascalStringAppendError {
    #[inline]
    fn from(e: ToAsciiCharError) -> Self {
        PascalStringAppendError::InvalidCharAppended(e)
    }
}

impl From<AsAsciiStrError> for PascalStringAppendError {
    #[inline]
    fn from(e: AsAsciiStrError) -> Self {
        PascalStringAppendError::InvalidStringAppended(e)
    }
}

#[derive(Debug, PartialEq)]
pub enum AsciiError {
    Char(ToAsciiCharError),
    Str(AsAsciiStrError)
}

impl From<ToAsciiCharError> for AsciiError {
    #[inline]
    fn from(e: ToAsciiCharError) -> Self {
        AsciiError::Char(e)
    }
}

impl From<AsAsciiStrError> for AsciiError {
    #[inline]
    fn from(e: AsAsciiStrError) -> Self {
        AsciiError::Str(e)
    }
}
<|endoftext|>


<commit_before>//! Utility class to communicate between agents
//!
//! This class provides three structs : IP, Ports and IPSender.

extern crate capnp;
#[allow(unused_imports)]
use std::io::Read;

use result;
use result::Result;

use std::collections::HashMap;
use std::mem;

use std::sync::mpsc::{Sender, Receiver, SyncSender};
use std::sync::mpsc::sync_channel;

use scheduler::CompMsg;

/// Represent an IP
pub struct IP {
    /// The capn'p representation
    pub vec: Vec<u8>,
    /// is the action of the IP
    pub action: String,
    reader: Option<capnp::message::Reader<capnp::serialize::OwnedSegments>>,
    builder: Option<capnp::message::Builder<capnp::message::HeapAllocator>>,
}

impl IP {
    /// Return a new IP
    ///
    /// # Example
    /// ```rust,ignore
    /// let ip = IP::new();
    /// ```
    pub fn new() -> Self {
        IP { vec: vec![],
             action: String::new(),
             reader: None,
             builder: None,
        }
    }

    /// Return a capnp `Reader`
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let ip = an_initialized_ip;
    /// {
    ///     let reader: generic_text::Reader = try!(ip.read_schema());
    ///     let text = try!(reader.get_text());
    /// }
    /// ```
    pub fn read_schema<'a, T: capnp::traits::FromPointerReader<'a>>(&'a mut self) -> Result<T> {
        let msg = try!(capnp::serialize::read_message(&mut &self.vec[..], capnp::message::ReaderOptions::new()));
        self.reader = Some(msg);
        Ok(try!(self.reader.as_ref().unwrap().get_root()))
    }

    /// Return a capnp `Builder`
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let mut ip = IP::new();
    /// // Initialize the IP
    /// {
    ///     let mut builder: generic_text::Builder = ip.build_schema();
    ///     builder.set_text("Hello Fractalide!");
    /// }
    /// ```
    pub fn build_schema<'a, T: capnp::traits::FromPointerBuilder<'a>>(&'a mut self) -> T {
        let msg = capnp::message::Builder::new_default();
        self.builder = Some(msg);
        self.builder.as_mut().unwrap().init_root()
    }

    /// Return a capnp `Builder` from a capnp `Reader`
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let mut ip = an_initialized_ip;
    /// {
    ///     let mut builder = try!(edit_edge::<generic_text::Builder, generic_text::Reader>());
    ///     builder.set_text("Hello Fractalide!");
    /// }
    /// ```
    pub fn edit_schema<'a, T: capnp::traits::FromPointerBuilder<'a>,
                                 U: capnp::traits::FromPointerReader<'a> + capnp::traits::SetPointerBuilder<T>>
        (&'a mut self) -> Result<T> {
        let reader = try!(capnp::serialize::read_message(&mut &self.vec[..], capnp::message::ReaderOptions::new()));
        self.reader = Some(reader);
        let reader: U = try!(self.reader.as_ref().unwrap().get_root());

        let mut msg = capnp::message::Builder::new_default();
        try!(msg.set_root(reader));
        self.builder = Some(msg);
        Ok(try!(self.builder.as_mut().unwrap().get_root()))
    }

    /// Write a capnp `Builder` to a `Vec`
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let mut ip = an_initialized_ip;
    /// {
    ///     let mut builder = try!(edit_edge::<generic_text::Builder, generic_text::Reader>());
    ///     builder.set_text("Hello Fractalide!");
    /// }
    /// try!(ip.before_send());
    /// ```
    pub fn before_send(&mut self) -> Result<()> {
        let mut build = mem::replace(&mut self.builder, None);
        if let Some(ref mut b) = build {
            self.vec.clear();
            try!(capnp::serialize::write_message(&mut self.vec, b))
        }
        Ok(())

    }
}

impl Clone for IP {
    fn clone(&self) -> Self {
        IP {
            vec: self.vec.clone(),
            action: self.action.clone(),
            reader: None,
            builder: None,
        }
    }
}

/// A wrapper around `SyncSender<IP>`
///
/// A specific `SyncSender` for the IP object. It also sends information to the scheduler.
#[derive(Clone)]
pub struct IPSender {
    /// The SyncSender, connected to a receiver in another agent
    pub sender: SyncSender<IP>,
    /// The name of the agent owning the receiver
    pub dest: String,
    /// A Sender to the scheduler, to signal that the receiver must be run
    pub sched: Sender<CompMsg>,
}

impl IPSender {
    /// Send an IP to the Receiver
    pub fn send(&self, mut ip: IP) -> Result<()> {
        try!(ip.before_send());
        try!(self.sender.send(ip));
        if self.dest != "" {
            try!(self.sched.send(CompMsg::Inc(self.dest.clone())));
        }
        Ok(())
    }
}

}

        } else {
        }
    }

        let (s, r) = sync_channel(25);
        let s = IPSender {
            sender: s,
        };
    }

    }

    }
}
<commit_msg>Add the struct IPReceiver<commit_after>//! Utility class to communicate between agents
//!
//! This class provides three structs : IP, Ports and IPSender.

extern crate capnp;
#[allow(unused_imports)]
use std::io::Read;

use result;
use result::Result;

use std::collections::HashMap;
use std::mem;

use std::sync::mpsc::{Sender, Receiver, SyncSender};
use std::sync::mpsc::sync_channel;

use scheduler::CompMsg;

/// Represent an IP
pub struct IP {
    /// The capn'p representation
    pub vec: Vec<u8>,
    /// is the action of the IP
    pub action: String,
    reader: Option<capnp::message::Reader<capnp::serialize::OwnedSegments>>,
    builder: Option<capnp::message::Builder<capnp::message::HeapAllocator>>,
}

impl IP {
    /// Return a new IP
    ///
    /// # Example
    /// ```rust,ignore
    /// let ip = IP::new();
    /// ```
    pub fn new() -> Self {
        IP { vec: vec![],
             action: String::new(),
             reader: None,
             builder: None,
        }
    }

    /// Return a capnp `Reader`
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let ip = an_initialized_ip;
    /// {
    ///     let reader: generic_text::Reader = try!(ip.read_schema());
    ///     let text = try!(reader.get_text());
    /// }
    /// ```
    pub fn read_schema<'a, T: capnp::traits::FromPointerReader<'a>>(&'a mut self) -> Result<T> {
        let msg = try!(capnp::serialize::read_message(&mut &self.vec[..], capnp::message::ReaderOptions::new()));
        self.reader = Some(msg);
        Ok(try!(self.reader.as_ref().unwrap().get_root()))
    }

    /// Return a capnp `Builder`
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let mut ip = IP::new();
    /// // Initialize the IP
    /// {
    ///     let mut builder: generic_text::Builder = ip.build_schema();
    ///     builder.set_text("Hello Fractalide!");
    /// }
    /// ```
    pub fn build_schema<'a, T: capnp::traits::FromPointerBuilder<'a>>(&'a mut self) -> T {
        let msg = capnp::message::Builder::new_default();
        self.builder = Some(msg);
        self.builder.as_mut().unwrap().init_root()
    }

    /// Return a capnp `Builder` from a capnp `Reader`
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let mut ip = an_initialized_ip;
    /// {
    ///     let mut builder = try!(edit_edge::<generic_text::Builder, generic_text::Reader>());
    ///     builder.set_text("Hello Fractalide!");
    /// }
    /// ```
    pub fn edit_schema<'a, T: capnp::traits::FromPointerBuilder<'a>,
                                 U: capnp::traits::FromPointerReader<'a> + capnp::traits::SetPointerBuilder<T>>
        (&'a mut self) -> Result<T> {
        let reader = try!(capnp::serialize::read_message(&mut &self.vec[..], capnp::message::ReaderOptions::new()));
        self.reader = Some(reader);
        let reader: U = try!(self.reader.as_ref().unwrap().get_root());

        let mut msg = capnp::message::Builder::new_default();
        try!(msg.set_root(reader));
        self.builder = Some(msg);
        Ok(try!(self.builder.as_mut().unwrap().get_root()))
    }

    /// Write a capnp `Builder` to a `Vec`
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// let mut ip = an_initialized_ip;
    /// {
    ///     let mut builder = try!(edit_edge::<generic_text::Builder, generic_text::Reader>());
    ///     builder.set_text("Hello Fractalide!");
    /// }
    /// try!(ip.before_send());
    /// ```
    pub fn before_send(&mut self) -> Result<()> {
        let mut build = mem::replace(&mut self.builder, None);
        if let Some(ref mut b) = build {
            self.vec.clear();
            try!(capnp::serialize::write_message(&mut self.vec, b))
        }
        Ok(())

    }
}

impl Clone for IP {
    fn clone(&self) -> Self {
        IP {
            vec: self.vec.clone(),
            action: self.action.clone(),
            reader: None,
            builder: None,
        }
    }
}

/// A wrapper around `SyncSender<IP>`
///
/// A specific `SyncSender` for the IP object. It also sends information to the scheduler.
#[derive(Clone)]
pub struct IPSender {
    /// The SyncSender, connected to a receiver in another agent
    pub sender: SyncSender<IP>,
    /// The name of the agent owning the receiver
    pub dest: String,
    /// A Sender to the scheduler, to signal that the receiver must be run
    pub sched: Sender<CompMsg>,
}

impl IPSender {
    /// Send an IP to the Receiver
    pub fn send(&self, mut ip: IP) -> Result<()> {
        try!(ip.before_send());
        try!(self.sender.send(ip));
        if self.dest != "" {
            try!(self.sched.send(CompMsg::Inc(self.dest.clone())));
        }
        Ok(())
    }
}

}

        } else {
        }
    }

pub struct IPReceiver {
    name: String,
    recv: Receiver<IP>,
    sched: Sender<CompMsg>,
    must_sched: bool,
}

impl IPReceiver {
    pub fn new(name: String, sched: Sender<CompMsg>, must_sched: bool) -> (IPReceiver, IPSender) {
        let (s, r) = sync_channel(25);
        let s = IPSender {
            sender: s,
            dest: if must_sched { name.clone() } else { "".into() },
            sched: sched.clone(),
        };
        let r = IPReceiver {
            recv: r,
            name: name,
            sched: sched,
            must_sched: must_sched,
        };
        (r, s)
    }

    pub fn recv(&self) -> Result<IP> {
        let ip = try!(self.recv.recv());
        if self.must_sched {
            try!(self.sched.send(CompMsg::Dec(self.name.clone())));
        }
        Ok(ip)
    }

    pub fn try_recv(&self) -> Result<IP> {
        let ip = self.recv.try_recv()?;
        if self.must_sched {
            try!(self.sched.send(CompMsg::Dec(self.name.clone())));
        }
        Ok(ip)
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) COMFOLLOW Chowner Passwd RFILE RFILE's derefer dgid duid

#[macro_use]
extern crate uucore;
pub use uucore::entries::{self, Group, Locate, Passwd};
use uucore::fs::resolve_relative_path;
use uucore::libc::{gid_t, uid_t};
use uucore::perms::{wrap_chown, Verbosity};

use clap::{crate_version, App, Arg};

use walkdir::WalkDir;

use std::fs::{self, Metadata};
use std::os::unix::fs::MetadataExt;

use std::convert::AsRef;
use std::path::Path;
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "change file owner and group";

pub mod options {
    pub mod verbosity {
        pub static CHANGES: &str = "changes";
        pub static QUIET: &str = "quiet";
        pub static SILENT: &str = "silent";
        pub static VERBOSE: &str = "verbose";
    }
    pub mod preserve_root {
        pub static PRESERVE: &str = "preserve-root";
        pub static NO_PRESERVE: &str = "no-preserve-root";
    }
    pub mod dereference {
        pub static DEREFERENCE: &str = "dereference";
        pub static NO_DEREFERENCE: &str = "no-dereference";
    }
    pub static FROM: &str = "from";
    pub static RECURSIVE: &str = "recursive";
    pub mod traverse {
        pub static TRAVERSE: &str = "H";
        pub static NO_TRAVERSE: &str = "P";
        pub static EVERY: &str = "L";
    }
    pub static REFERENCE: &str = "reference";
}

static ARG_OWNER: &str = "owner";
static ARG_FILES: &str = "files";

const FTS_COMFOLLOW: u8 = 1;
const FTS_PHYSICAL: u8 = 1 << 1;
const FTS_LOGICAL: u8 = 1 << 2;

fn get_usage() -> String {
    format!(
        "{0} [OPTION]... [OWNER][:[GROUP]] FILE...\n{0} [OPTION]... --reference=RFILE FILE...",
        executable!()
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let usage = get_usage();

    let matches = App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(options::verbosity::CHANGES)
                .short("c")
                .long(options::verbosity::CHANGES)
                .help("like verbose but report only when a change is made"),
        )
        .arg(Arg::with_name(options::dereference::DEREFERENCE).long(options::dereference::DEREFERENCE).help(
            "affect the referent of each symbolic link (this is the default), rather than the symbolic link itself",
        ))
        .arg(
            Arg::with_name(options::dereference::NO_DEREFERENCE)
                .short("h")
                .long(options::dereference::NO_DEREFERENCE)
                .help(
                    "affect symbolic links instead of any referenced file (useful only on systems that can change the ownership of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(options::FROM)
                .long(options::FROM)
                .help(
                    "change the owner and/or group of each file only if its current owner and/or group match those specified here. Either may be omitted, in which case a match is not required for the omitted attribute",
                )
                .value_name("CURRENT_OWNER:CURRENT_GROUP"),
        )
        .arg(
            Arg::with_name(options::preserve_root::PRESERVE)
                .long(options::preserve_root::PRESERVE)
                .help("fail to operate recursively on '/'"),
        )
        .arg(
            Arg::with_name(options::preserve_root::NO_PRESERVE)
                .long(options::preserve_root::NO_PRESERVE)
                .help("do not treat '/' specially (the default)"),
        )
        .arg(
            Arg::with_name(options::verbosity::QUIET)
                .long(options::verbosity::QUIET)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::with_name(options::RECURSIVE)
                .short("R")
                .long(options::RECURSIVE)
                .help("operate on files and directories recursively"),
        )
        .arg(
            Arg::with_name(options::REFERENCE)
                .long(options::REFERENCE)
                .help("use RFILE's owner and group rather than specifying OWNER:GROUP values")
                .value_name("RFILE")
                .min_values(1),
        )
        .arg(Arg::with_name(options::verbosity::SILENT).short("f").long(options::verbosity::SILENT))
        .arg(
            Arg::with_name(options::traverse::TRAVERSE)
                .short(options::traverse::TRAVERSE)
                .help("if a command line argument is a symbolic link to a directory, traverse it")
                .overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::with_name(options::traverse::EVERY)
                .short(options::traverse::EVERY)
                .help("traverse every symbolic link to a directory encountered")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::with_name(options::traverse::NO_TRAVERSE)
                .short(options::traverse::NO_TRAVERSE)
                .help("do not traverse any symbolic links (default)")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]),
        )
        .arg(
            Arg::with_name(options::verbosity::VERBOSE)
                .long(options::verbosity::VERBOSE)
                .help("output a diagnostic for every file processed"),
        )
        .arg(
            Arg::with_name(ARG_OWNER)
                .multiple(false)
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .required(true)
                .min_values(1),
        )
        .get_matches_from(args);

    /* First arg is the owner/group */
    let owner = matches.value_of(ARG_OWNER).unwrap();

    /* Then the list of files */
    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let preserve_root = matches.is_present(options::preserve_root::PRESERVE);

    let mut derefer = if matches.is_present(options::dereference::NO_DEREFERENCE) {
        1
    } else {
        0
    };

    let mut bit_flag = if matches.is_present(options::traverse::TRAVERSE) {
        FTS_COMFOLLOW | FTS_PHYSICAL
    } else if matches.is_present(options::traverse::EVERY) {
        FTS_LOGICAL
    } else {
        FTS_PHYSICAL
    };

    let recursive = matches.is_present(options::RECURSIVE);
    if recursive {
        if bit_flag == FTS_PHYSICAL {
            if derefer == 1 {
                show_error!("-R --dereference requires -H or -L");
                return 1;
            }
            derefer = 0;
        }
    } else {
        bit_flag = FTS_PHYSICAL;
    }

    let verbosity = if matches.is_present(options::verbosity::CHANGES) {
        Verbosity::Changes
    } else if matches.is_present(options::verbosity::SILENT)
        || matches.is_present(options::verbosity::QUIET)
    {
        Verbosity::Silent
    } else if matches.is_present(options::verbosity::VERBOSE) {
        Verbosity::Verbose
    } else {
        Verbosity::Normal
    };

    let filter = if let Some(spec) = matches.value_of(options::FROM) {
        match parse_spec(spec) {
            Ok((Some(uid), None)) => IfFrom::User(uid),
            Ok((None, Some(gid))) => IfFrom::Group(gid),
            Ok((Some(uid), Some(gid))) => IfFrom::UserGroup(uid, gid),
            Ok((None, None)) => IfFrom::All,
            Err(e) => {
                show_error!("{}", e);
                return 1;
            }
        }
    } else {
        IfFrom::All
    };

    let dest_uid: Option<u32>;
    let dest_gid: Option<u32>;
    if let Some(file) = matches.value_of(options::REFERENCE) {
        match fs::metadata(&file) {
            Ok(meta) => {
                dest_gid = Some(meta.gid());
                dest_uid = Some(meta.uid());
            }
            Err(e) => {
                show_error!("failed to get attributes of '{}': {}", file, e);
                return 1;
            }
        }
    } else {
        match parse_spec(owner) {
            Ok((u, g)) => {
                dest_uid = u;
                dest_gid = g;
            }
            Err(e) => {
                show_error!("{}", e);
                return 1;
            }
        }
    }
    let executor = Chowner {
        bit_flag,
        dest_uid,
        dest_gid,
        verbosity,
        recursive,
        dereference: derefer != 0,
        filter,
        preserve_root,
        files,
    };
    executor.exec()
}

fn parse_spec(spec: &str) -> Result<(Option<u32>, Option<u32>), String> {
    let args = spec.split_terminator(':').collect::<Vec<_>>();
    let usr_only = args.len() == 1 && !args[0].is_empty();
    let grp_only = args.len() == 2 && args[0].is_empty();
    let usr_grp = args.len() == 2 && !args[0].is_empty() && !args[1].is_empty();

    if usr_only {
        Ok((
            Some(match Passwd::locate(args[0]) {
                Ok(v) => v.uid(),
                _ => return Err(format!("invalid user: ‘{}’", spec)),
            }),
            None,
        ))
    } else if grp_only {
        Ok((
            None,
            Some(match Group::locate(args[1]) {
                Ok(v) => v.gid(),
                _ => return Err(format!("invalid group: ‘{}’", spec)),
            }),
        ))
    } else if usr_grp {
        Ok((
            Some(match Passwd::locate(args[0]) {
                Ok(v) => v.uid(),
                _ => return Err(format!("invalid user: ‘{}’", spec)),
            }),
            Some(match Group::locate(args[1]) {
                Ok(v) => v.gid(),
                _ => return Err(format!("invalid group: ‘{}’", spec)),
            }),
        ))
    } else {
        Ok((None, None))
    }
}

enum IfFrom {
    All,
    User(u32),
    Group(u32),
    UserGroup(u32, u32),
}

struct Chowner {
    dest_uid: Option<u32>,
    dest_gid: Option<u32>,
    bit_flag: u8,
    verbosity: Verbosity,
    filter: IfFrom,
    files: Vec<String>,
    recursive: bool,
    preserve_root: bool,
    dereference: bool,
}

macro_rules! unwrap {
    ($m:expr, $e:ident, $err:block) => {
        match $m {
            Ok(meta) => meta,
            Err($e) => $err,
        }
    };
}

impl Chowner {
    fn exec(&self) -> i32 {
        let mut ret = 0;
        for f in &self.files {
            ret |= self.traverse(f);
        }
        ret
    }

    fn traverse<P: AsRef<Path>>(&self, root: P) -> i32 {
        let follow_arg = self.dereference || self.bit_flag != FTS_PHYSICAL;
        let path = root.as_ref();
        let meta = match self.obtain_meta(path, follow_arg) {
            Some(m) => m,
            _ => return 1,
        };

        // Prohibit only if:
        // (--preserve-root and -R present) &&
        // (
        //     (argument is not symlink && resolved to be '/') ||
        //     (argument is symlink && should follow argument && resolved to be '/')
        // )
        if self.recursive && self.preserve_root {
            let may_exist = if follow_arg {
                path.canonicalize().ok()
            } else {
                let real = resolve_relative_path(path);
                if real.is_dir() {
                    Some(real.canonicalize().expect("failed to get real path"))
                } else {
                    Some(real.into_owned())
                }
            };

            if let Some(p) = may_exist {
                if p.parent().is_none() {
                    show_error!("it is dangerous to operate recursively on '/'");
                    show_error!("use --no-preserve-root to override this failsafe");
                    return 1;
                }
            }
        }

        let ret = if self.matched(meta.uid(), meta.gid()) {
            match wrap_chown(
                path,
                &meta,
                self.dest_uid,
                self.dest_gid,
                follow_arg,
                self.verbosity.clone(),
            ) {
                Ok(n) => {
                    if !n.is_empty() {
                        show_error!("{}", n);
                    }
                    0
                }
                Err(e) => {
                    if self.verbosity != Verbosity::Silent {
                        show_error!("{}", e);
                    }
                    1
                }
            }
        } else {
            0
        };

        if !self.recursive {
            ret
        } else {
            ret | self.dive_into(&root)
        }
    }

    fn dive_into<P: AsRef<Path>>(&self, root: P) -> i32 {
        let mut ret = 0;
        let root = root.as_ref();
        let follow = self.dereference || self.bit_flag & FTS_LOGICAL != 0;
        for entry in WalkDir::new(root).follow_links(follow).min_depth(1) {
            let entry = unwrap!(entry, e, {
                ret = 1;
                show_error!("{}", e);
                continue;
            });
            let path = entry.path();
            let meta = match self.obtain_meta(path, follow) {
                Some(m) => m,
                _ => {
                    ret = 1;
                    continue;
                }
            };

            if !self.matched(meta.uid(), meta.gid()) {
                continue;
            }

            ret = match wrap_chown(
                path,
                &meta,
                self.dest_uid,
                self.dest_gid,
                follow,
                self.verbosity.clone(),
            ) {
                Ok(n) => {
                    if !n.is_empty() {
                        show_error!("{}", n);
                    }
                    0
                }
                Err(e) => {
                    if self.verbosity != Verbosity::Silent {
                        show_error!("{}", e);
                    }
                    1
                }
            }
        }
        ret
    }

    fn obtain_meta<P: AsRef<Path>>(&self, path: P, follow: bool) -> Option<Metadata> {
        use self::Verbosity::*;
        let path = path.as_ref();
        let meta = if follow {
            unwrap!(path.metadata(), e, {
                match self.verbosity {
                    Silent => (),
                    _ => show_error!("cannot access '{}': {}", path.display(), e),
                }
                return None;
            })
        } else {
            unwrap!(path.symlink_metadata(), e, {
                match self.verbosity {
                    Silent => (),
                    _ => show_error!("cannot dereference '{}': {}", path.display(), e),
                }
                return None;
            })
        };
        Some(meta)
    }

    #[inline]
    fn matched(&self, uid: uid_t, gid: gid_t) -> bool {
        match self.filter {
            IfFrom::All => true,
            IfFrom::User(u) => u == uid,
            IfFrom::Group(g) => g == gid,
            IfFrom::UserGroup(u, g) => u == uid && g == gid,
        }
    }
}
<commit_msg>chown: clean up returning Err<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) COMFOLLOW Chowner Passwd RFILE RFILE's derefer dgid duid

#[macro_use]
extern crate uucore;
pub use uucore::entries::{self, Group, Locate, Passwd};
use uucore::fs::resolve_relative_path;
use uucore::libc::{gid_t, uid_t};
use uucore::perms::{wrap_chown, Verbosity};

use clap::{crate_version, App, Arg};

use walkdir::WalkDir;

use std::fs::{self, Metadata};
use std::os::unix::fs::MetadataExt;

use std::convert::AsRef;
use std::path::Path;
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "change file owner and group";

pub mod options {
    pub mod verbosity {
        pub static CHANGES: &str = "changes";
        pub static QUIET: &str = "quiet";
        pub static SILENT: &str = "silent";
        pub static VERBOSE: &str = "verbose";
    }
    pub mod preserve_root {
        pub static PRESERVE: &str = "preserve-root";
        pub static NO_PRESERVE: &str = "no-preserve-root";
    }
    pub mod dereference {
        pub static DEREFERENCE: &str = "dereference";
        pub static NO_DEREFERENCE: &str = "no-dereference";
    }
    pub static FROM: &str = "from";
    pub static RECURSIVE: &str = "recursive";
    pub mod traverse {
        pub static TRAVERSE: &str = "H";
        pub static NO_TRAVERSE: &str = "P";
        pub static EVERY: &str = "L";
    }
    pub static REFERENCE: &str = "reference";
}

static ARG_OWNER: &str = "owner";
static ARG_FILES: &str = "files";

const FTS_COMFOLLOW: u8 = 1;
const FTS_PHYSICAL: u8 = 1 << 1;
const FTS_LOGICAL: u8 = 1 << 2;

fn get_usage() -> String {
    format!(
        "{0} [OPTION]... [OWNER][:[GROUP]] FILE...\n{0} [OPTION]... --reference=RFILE FILE...",
        executable!()
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let usage = get_usage();

    let matches = App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(options::verbosity::CHANGES)
                .short("c")
                .long(options::verbosity::CHANGES)
                .help("like verbose but report only when a change is made"),
        )
        .arg(Arg::with_name(options::dereference::DEREFERENCE).long(options::dereference::DEREFERENCE).help(
            "affect the referent of each symbolic link (this is the default), rather than the symbolic link itself",
        ))
        .arg(
            Arg::with_name(options::dereference::NO_DEREFERENCE)
                .short("h")
                .long(options::dereference::NO_DEREFERENCE)
                .help(
                    "affect symbolic links instead of any referenced file (useful only on systems that can change the ownership of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(options::FROM)
                .long(options::FROM)
                .help(
                    "change the owner and/or group of each file only if its current owner and/or group match those specified here. Either may be omitted, in which case a match is not required for the omitted attribute",
                )
                .value_name("CURRENT_OWNER:CURRENT_GROUP"),
        )
        .arg(
            Arg::with_name(options::preserve_root::PRESERVE)
                .long(options::preserve_root::PRESERVE)
                .help("fail to operate recursively on '/'"),
        )
        .arg(
            Arg::with_name(options::preserve_root::NO_PRESERVE)
                .long(options::preserve_root::NO_PRESERVE)
                .help("do not treat '/' specially (the default)"),
        )
        .arg(
            Arg::with_name(options::verbosity::QUIET)
                .long(options::verbosity::QUIET)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::with_name(options::RECURSIVE)
                .short("R")
                .long(options::RECURSIVE)
                .help("operate on files and directories recursively"),
        )
        .arg(
            Arg::with_name(options::REFERENCE)
                .long(options::REFERENCE)
                .help("use RFILE's owner and group rather than specifying OWNER:GROUP values")
                .value_name("RFILE")
                .min_values(1),
        )
        .arg(Arg::with_name(options::verbosity::SILENT).short("f").long(options::verbosity::SILENT))
        .arg(
            Arg::with_name(options::traverse::TRAVERSE)
                .short(options::traverse::TRAVERSE)
                .help("if a command line argument is a symbolic link to a directory, traverse it")
                .overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::with_name(options::traverse::EVERY)
                .short(options::traverse::EVERY)
                .help("traverse every symbolic link to a directory encountered")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::with_name(options::traverse::NO_TRAVERSE)
                .short(options::traverse::NO_TRAVERSE)
                .help("do not traverse any symbolic links (default)")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]),
        )
        .arg(
            Arg::with_name(options::verbosity::VERBOSE)
                .long(options::verbosity::VERBOSE)
                .help("output a diagnostic for every file processed"),
        )
        .arg(
            Arg::with_name(ARG_OWNER)
                .multiple(false)
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .required(true)
                .min_values(1),
        )
        .get_matches_from(args);

    /* First arg is the owner/group */
    let owner = matches.value_of(ARG_OWNER).unwrap();

    /* Then the list of files */
    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let preserve_root = matches.is_present(options::preserve_root::PRESERVE);

    let mut derefer = if matches.is_present(options::dereference::NO_DEREFERENCE) {
        1
    } else {
        0
    };

    let mut bit_flag = if matches.is_present(options::traverse::TRAVERSE) {
        FTS_COMFOLLOW | FTS_PHYSICAL
    } else if matches.is_present(options::traverse::EVERY) {
        FTS_LOGICAL
    } else {
        FTS_PHYSICAL
    };

    let recursive = matches.is_present(options::RECURSIVE);
    if recursive {
        if bit_flag == FTS_PHYSICAL {
            if derefer == 1 {
                show_error!("-R --dereference requires -H or -L");
                return 1;
            }
            derefer = 0;
        }
    } else {
        bit_flag = FTS_PHYSICAL;
    }

    let verbosity = if matches.is_present(options::verbosity::CHANGES) {
        Verbosity::Changes
    } else if matches.is_present(options::verbosity::SILENT)
        || matches.is_present(options::verbosity::QUIET)
    {
        Verbosity::Silent
    } else if matches.is_present(options::verbosity::VERBOSE) {
        Verbosity::Verbose
    } else {
        Verbosity::Normal
    };

    let filter = if let Some(spec) = matches.value_of(options::FROM) {
        match parse_spec(spec) {
            Ok((Some(uid), None)) => IfFrom::User(uid),
            Ok((None, Some(gid))) => IfFrom::Group(gid),
            Ok((Some(uid), Some(gid))) => IfFrom::UserGroup(uid, gid),
            Ok((None, None)) => IfFrom::All,
            Err(e) => {
                show_error!("{}", e);
                return 1;
            }
        }
    } else {
        IfFrom::All
    };

    let dest_uid: Option<u32>;
    let dest_gid: Option<u32>;
    if let Some(file) = matches.value_of(options::REFERENCE) {
        match fs::metadata(&file) {
            Ok(meta) => {
                dest_gid = Some(meta.gid());
                dest_uid = Some(meta.uid());
            }
            Err(e) => {
                show_error!("failed to get attributes of '{}': {}", file, e);
                return 1;
            }
        }
    } else {
        match parse_spec(owner) {
            Ok((u, g)) => {
                dest_uid = u;
                dest_gid = g;
            }
            Err(e) => {
                show_error!("{}", e);
                return 1;
            }
        }
    }
    let executor = Chowner {
        bit_flag,
        dest_uid,
        dest_gid,
        verbosity,
        recursive,
        dereference: derefer != 0,
        filter,
        preserve_root,
        files,
    };
    executor.exec()
}

fn parse_spec(spec: &str) -> Result<(Option<u32>, Option<u32>), String> {
    let args = spec.split_terminator(':').collect::<Vec<_>>();
    let usr_only = args.len() == 1 && !args[0].is_empty();
    let grp_only = args.len() == 2 && args[0].is_empty();
    let usr_grp = args.len() == 2 && !args[0].is_empty() && !args[1].is_empty();

    let r = if usr_only {
        (
            Some(
                Passwd::locate(args[0])
                    .map_err(|_| format!("invalid user: ‘{}’", spec))?
                    .uid(),
            ),
            None,
        )
    } else if grp_only {
        (
            None,
            Some(
                Group::locate(args[1])
                    .map_err(|_| format!("invalid group: ‘{}’", spec))?
                    .gid(),
            ),
        )
    } else if usr_grp {
        (
            Some(
                Passwd::locate(args[0])
                    .map_err(|_| format!("invalid user: ‘{}’", spec))?
                    .uid(),
            ),
            Some(
                Group::locate(args[1])
                    .map_err(|_| format!("invalid group: ‘{}’", spec))?
                    .gid(),
            ),
        )
    } else {
        (None, None)
    };
    Ok(r)
}

enum IfFrom {
    All,
    User(u32),
    Group(u32),
    UserGroup(u32, u32),
}

struct Chowner {
    dest_uid: Option<u32>,
    dest_gid: Option<u32>,
    bit_flag: u8,
    verbosity: Verbosity,
    filter: IfFrom,
    files: Vec<String>,
    recursive: bool,
    preserve_root: bool,
    dereference: bool,
}

macro_rules! unwrap {
    ($m:expr, $e:ident, $err:block) => {
        match $m {
            Ok(meta) => meta,
            Err($e) => $err,
        }
    };
}

impl Chowner {
    fn exec(&self) -> i32 {
        let mut ret = 0;
        for f in &self.files {
            ret |= self.traverse(f);
        }
        ret
    }

    fn traverse<P: AsRef<Path>>(&self, root: P) -> i32 {
        let follow_arg = self.dereference || self.bit_flag != FTS_PHYSICAL;
        let path = root.as_ref();
        let meta = match self.obtain_meta(path, follow_arg) {
            Some(m) => m,
            _ => return 1,
        };

        // Prohibit only if:
        // (--preserve-root and -R present) &&
        // (
        //     (argument is not symlink && resolved to be '/') ||
        //     (argument is symlink && should follow argument && resolved to be '/')
        // )
        if self.recursive && self.preserve_root {
            let may_exist = if follow_arg {
                path.canonicalize().ok()
            } else {
                let real = resolve_relative_path(path);
                if real.is_dir() {
                    Some(real.canonicalize().expect("failed to get real path"))
                } else {
                    Some(real.into_owned())
                }
            };

            if let Some(p) = may_exist {
                if p.parent().is_none() {
                    show_error!("it is dangerous to operate recursively on '/'");
                    show_error!("use --no-preserve-root to override this failsafe");
                    return 1;
                }
            }
        }

        let ret = if self.matched(meta.uid(), meta.gid()) {
            match wrap_chown(
                path,
                &meta,
                self.dest_uid,
                self.dest_gid,
                follow_arg,
                self.verbosity.clone(),
            ) {
                Ok(n) => {
                    if !n.is_empty() {
                        show_error!("{}", n);
                    }
                    0
                }
                Err(e) => {
                    if self.verbosity != Verbosity::Silent {
                        show_error!("{}", e);
                    }
                    1
                }
            }
        } else {
            0
        };

        if !self.recursive {
            ret
        } else {
            ret | self.dive_into(&root)
        }
    }

    fn dive_into<P: AsRef<Path>>(&self, root: P) -> i32 {
        let mut ret = 0;
        let root = root.as_ref();
        let follow = self.dereference || self.bit_flag & FTS_LOGICAL != 0;
        for entry in WalkDir::new(root).follow_links(follow).min_depth(1) {
            let entry = unwrap!(entry, e, {
                ret = 1;
                show_error!("{}", e);
                continue;
            });
            let path = entry.path();
            let meta = match self.obtain_meta(path, follow) {
                Some(m) => m,
                _ => {
                    ret = 1;
                    continue;
                }
            };

            if !self.matched(meta.uid(), meta.gid()) {
                continue;
            }

            ret = match wrap_chown(
                path,
                &meta,
                self.dest_uid,
                self.dest_gid,
                follow,
                self.verbosity.clone(),
            ) {
                Ok(n) => {
                    if !n.is_empty() {
                        show_error!("{}", n);
                    }
                    0
                }
                Err(e) => {
                    if self.verbosity != Verbosity::Silent {
                        show_error!("{}", e);
                    }
                    1
                }
            }
        }
        ret
    }

    fn obtain_meta<P: AsRef<Path>>(&self, path: P, follow: bool) -> Option<Metadata> {
        use self::Verbosity::*;
        let path = path.as_ref();
        let meta = if follow {
            unwrap!(path.metadata(), e, {
                match self.verbosity {
                    Silent => (),
                    _ => show_error!("cannot access '{}': {}", path.display(), e),
                }
                return None;
            })
        } else {
            unwrap!(path.symlink_metadata(), e, {
                match self.verbosity {
                    Silent => (),
                    _ => show_error!("cannot dereference '{}': {}", path.display(), e),
                }
                return None;
            })
        };
        Some(meta)
    }

    #[inline]
    fn matched(&self, uid: uid_t, gid: gid_t) -> bool {
        match self.filter {
            IfFrom::All => true,
            IfFrom::User(u) => u == uid,
            IfFrom::Group(g) => g == gid,
            IfFrom::UserGroup(u, g) => u == uid && g == gid,
        }
    }
}
<|endoftext|>


<commit_before>use cgmath::{Aabb3, Point3};
use std::sync::Mutex;
use stopwatch;
use time;

use common::protocol;
use common::surroundings_loader;
use common::surroundings_loader::LoadType;
use common::voxel;

use block_position;
use client;
use lod;
use load_terrain;
use load_terrain::lod_index;
use record_book;
use server_update::apply_server_update;
use terrain_mesh;
use view_update::ClientToView;

const MAX_OUTSTANDING_TERRAIN_REQUESTS: u32 = 1 << 1;

pub fn update_thread<RecvServer, RecvVoxelUpdates, UpdateView0, UpdateView1, UpdateServer, EnqueueBlockUpdates>(
  quit: &Mutex<bool>,
  client: &client::T,
  recv_server: &mut RecvServer,
  recv_voxel_updates: &mut RecvVoxelUpdates,
  update_view0: &mut UpdateView0,
  update_view1: &mut UpdateView1,
  update_server: &mut UpdateServer,
  enqueue_block_updates: &mut EnqueueBlockUpdates,
) where
  RecvServer: FnMut() -> Option<protocol::ServerToClient>,
  RecvVoxelUpdates: FnMut() -> Option<(Option<u64>, Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason)>,
  UpdateView0: FnMut(ClientToView),
  UpdateView1: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
  EnqueueBlockUpdates: FnMut(Option<u64>, Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason),
{
  'update_loop: loop {
    let should_quit = *quit.lock().unwrap();
    if should_quit {
      break 'update_loop
    } else {
      stopwatch::time("update_iteration", || {
        stopwatch::time("process_server_updates", || {
          process_server_updates(client, recv_server, update_view0, update_server, enqueue_block_updates);
        });

        stopwatch::time("update_surroundings", || {
          update_surroundings(client, update_view1, update_server);
        });

        stopwatch::time("process_voxel_updates", || {
          process_voxel_updates(client, recv_voxel_updates, update_view1);
        });
      })
    }
  }
}

#[inline(never)]
fn update_surroundings<UpdateView, UpdateServer>(
  client: &client::T,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
) where
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
{
  let start = time::precise_time_ns();
  let mut i = 0;
  let load_position = {
    let load_position = *client.load_position.lock().unwrap();
    load_position.unwrap_or_else(|| *client.player_position.lock().unwrap())
  };
  let load_position = block_position::of_world_position(&load_position);
  let mut surroundings_loader = client.surroundings_loader.lock().unwrap();
  let mut updates = surroundings_loader.updates(load_position.as_pnt()) ;
  loop {
    if*client.outstanding_terrain_requests.lock().unwrap() >= MAX_OUTSTANDING_TERRAIN_REQUESTS {
      trace!("update loop breaking");
      break;
    }

    let block_position;
    let load_type;
    match updates.next() {
      None => break,
      Some((b, l)) => {
        block_position = block_position::of_pnt(&b);
        load_type = l;
      },
    }

    debug!("block surroundings");
    let distance =
      surroundings_loader::distance_between(
        load_position.as_pnt(),
        block_position.as_pnt(),
      );
    match load_type {
      LoadType::Load => {
        stopwatch::time("update_thread.load_block", || {
          let new_lod = lod_index(distance);
          let lod_change =
            client.loaded_blocks
            .lock().unwrap()
            .get(&block_position)
            .map(|&(_, lod)| lod != new_lod);
          if lod_change != Some(false) {
            load_or_request_chunk(client, update_server, update_view, block_position, new_lod);
          } else {
            debug!("Not re-loading {:?} at {:?}", block_position, new_lod);
          }
        })
      },
      LoadType::Update => {
        stopwatch::time("update_thread.update_block", || {
          let new_lod = lod_index(distance);
          let lod_change =
            client.loaded_blocks
            .lock().unwrap()
            .get(&block_position)
            .map(|&(_, lod)| new_lod < lod);
          if lod_change == Some(true) {
            load_or_request_chunk(client, update_server, update_view, block_position, new_lod);
          } else {
            trace!("Not updating {:?} at {:?}", block_position, new_lod);
          }
        })
      },
      LoadType::Unload => {
        stopwatch::time("update_thread.unload", || {
          // The block removal code is duplicated elsewhere.

          client.loaded_blocks
          .lock().unwrap()
            .remove(&block_position)
            // If it wasn't loaded, don't unload anything.
            .map(|(block, _)| {
              for id in &block.ids {
                update_view(ClientToView::RemoveTerrain(*id));
              }
            });
        })
      },
    };

    if i >= 10 {
      i -= 10;
      if time::precise_time_ns() - start >= 1_000_000 {
        break
      }
    }
    i += 1;
  }
}

fn load_or_request_chunk<UpdateServer, UpdateView>(
  client: &client::T,
  update_server: &mut UpdateServer,
  update_view: &mut UpdateView,
  block_position: block_position::T,
  lod: lod::T,
) where
  UpdateServer: FnMut(protocol::ClientToServer),
  UpdateView: FnMut(ClientToView),
{
  if load_terrain::all_voxels_loaded(&client.block_voxels_loaded.lock().unwrap(), block_position, lod) {
    load_terrain::load_block(
      client,
      update_view,
      &block_position,
      lod,
    );
  } else {
    let voxel_size = 1 << terrain_mesh::LG_SAMPLE_SIZE[lod.0 as usize];
    update_server(
      protocol::ClientToServer::RequestVoxels(
        time::precise_time_ns(),
        client.id,
        terrain_mesh::voxels_in(
          &Aabb3::new(
            Point3::new(
              (block_position.as_pnt().x << terrain_mesh::LG_WIDTH) - voxel_size,
              (block_position.as_pnt().y << terrain_mesh::LG_WIDTH) - voxel_size,
              (block_position.as_pnt().z << terrain_mesh::LG_WIDTH) - voxel_size,
            ),
            Point3::new(
              ((block_position.as_pnt().x + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
              ((block_position.as_pnt().y + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
              ((block_position.as_pnt().z + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
            ),
          ),
          terrain_mesh::LG_SAMPLE_SIZE[lod.0 as usize],
        ),
      )
    );
    *client.outstanding_terrain_requests.lock().unwrap() += 1;
  }
}

#[inline(never)]
fn process_voxel_updates<RecvVoxelUpdates, UpdateView>(
  client: &client::T,
  recv_voxel_updates: &mut RecvVoxelUpdates,
  update_view: &mut UpdateView,
) where
  RecvVoxelUpdates: FnMut() -> Option<(Option<u64>, Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason)>,
  UpdateView: FnMut(ClientToView),
{
  let start = time::precise_time_ns();
  while let Some((request_time, voxel_updates, reason)) = recv_voxel_updates() {
    let mut update_blocks = block_position::with_lod::set::new();
    let response_time = time::precise_time_ns();
    for (bounds, voxel) in voxel_updates {
      trace!("Got voxel at {:?}", bounds);
      load_terrain::load_voxel(
        client,
        voxel,
        &bounds,
        |block, lod| { update_blocks.insert((block, lod)); },
      );
    }

    let processed_time = time::precise_time_ns();

    for (block, lod) in update_blocks.into_iter() {
      load_terrain::load_block(
        client,
        update_view,
        &block,
        lod
      )
    }

    let block_loaded = time::precise_time_ns();

    match request_time {
      None => {},
      Some(request_time) => {
        record_book::thread_local::push_block_load(
          record_book::BlockLoad {
            requested_at: request_time,
            responded_at: response_time,
            processed_at: processed_time,
            loaded_at: block_loaded,
          }
        );
      },
    }

    match reason {
      protocol::VoxelReason::Updated => {},
      protocol::VoxelReason::Requested => {
        *client.outstanding_terrain_requests.lock().unwrap() -= 1;
        debug!("Outstanding terrain requests: {}", *client.outstanding_terrain_requests.lock().unwrap());
      },
    }

    if time::precise_time_ns() - start >= 1_000_000 {
      break
    }
  }
}

#[inline(never)]
fn process_server_updates<RecvServer, UpdateView, UpdateServer, EnqueueBlockUpdates>(
  client: &client::T,
  recv_server: &mut RecvServer,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
  enqueue_block_updates: &mut EnqueueBlockUpdates,
) where
  RecvServer: FnMut() -> Option<protocol::ServerToClient>,
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
  EnqueueBlockUpdates: FnMut(Option<u64>, Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason),
{
  let start = time::precise_time_ns();
  let mut i = 0;
  while let Some(up) = recv_server() {
    apply_server_update(
      client,
      update_view,
      update_server,
      enqueue_block_updates,
      up,
    );

    if i > 10 {
      i -= 10;
      if time::precise_time_ns() - start >= 1_000_000 {
        break
      }
    }
    i += 1;
  }
}
<commit_msg>revert<commit_after>use cgmath::{Aabb3, Point3};
use std::sync::Mutex;
use stopwatch;
use time;

use common::protocol;
use common::surroundings_loader;
use common::surroundings_loader::LoadType;
use common::voxel;

use block_position;
use client;
use lod;
use load_terrain;
use load_terrain::lod_index;
use record_book;
use server_update::apply_server_update;
use terrain_mesh;
use view_update::ClientToView;

const MAX_OUTSTANDING_TERRAIN_REQUESTS: u32 = 1;

pub fn update_thread<RecvServer, RecvVoxelUpdates, UpdateView0, UpdateView1, UpdateServer, EnqueueBlockUpdates>(
  quit: &Mutex<bool>,
  client: &client::T,
  recv_server: &mut RecvServer,
  recv_voxel_updates: &mut RecvVoxelUpdates,
  update_view0: &mut UpdateView0,
  update_view1: &mut UpdateView1,
  update_server: &mut UpdateServer,
  enqueue_block_updates: &mut EnqueueBlockUpdates,
) where
  RecvServer: FnMut() -> Option<protocol::ServerToClient>,
  RecvVoxelUpdates: FnMut() -> Option<(Option<u64>, Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason)>,
  UpdateView0: FnMut(ClientToView),
  UpdateView1: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
  EnqueueBlockUpdates: FnMut(Option<u64>, Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason),
{
  'update_loop: loop {
    let should_quit = *quit.lock().unwrap();
    if should_quit {
      break 'update_loop
    } else {
      stopwatch::time("update_iteration", || {
        stopwatch::time("process_server_updates", || {
          process_server_updates(client, recv_server, update_view0, update_server, enqueue_block_updates);
        });

        stopwatch::time("update_surroundings", || {
          update_surroundings(client, update_view1, update_server);
        });

        stopwatch::time("process_voxel_updates", || {
          process_voxel_updates(client, recv_voxel_updates, update_view1);
        });
      })
    }
  }
}

#[inline(never)]
fn update_surroundings<UpdateView, UpdateServer>(
  client: &client::T,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
) where
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
{
  let start = time::precise_time_ns();
  let mut i = 0;
  let load_position = {
    let load_position = *client.load_position.lock().unwrap();
    load_position.unwrap_or_else(|| *client.player_position.lock().unwrap())
  };
  let load_position = block_position::of_world_position(&load_position);
  let mut surroundings_loader = client.surroundings_loader.lock().unwrap();
  let mut updates = surroundings_loader.updates(load_position.as_pnt()) ;
  loop {
    if*client.outstanding_terrain_requests.lock().unwrap() >= MAX_OUTSTANDING_TERRAIN_REQUESTS {
      trace!("update loop breaking");
      break;
    }

    let block_position;
    let load_type;
    match updates.next() {
      None => break,
      Some((b, l)) => {
        block_position = block_position::of_pnt(&b);
        load_type = l;
      },
    }

    debug!("block surroundings");
    let distance =
      surroundings_loader::distance_between(
        load_position.as_pnt(),
        block_position.as_pnt(),
      );
    match load_type {
      LoadType::Load => {
        stopwatch::time("update_thread.load_block", || {
          let new_lod = lod_index(distance);
          let lod_change =
            client.loaded_blocks
            .lock().unwrap()
            .get(&block_position)
            .map(|&(_, lod)| lod != new_lod);
          if lod_change != Some(false) {
            load_or_request_chunk(client, update_server, update_view, block_position, new_lod);
          } else {
            debug!("Not re-loading {:?} at {:?}", block_position, new_lod);
          }
        })
      },
      LoadType::Update => {
        stopwatch::time("update_thread.update_block", || {
          let new_lod = lod_index(distance);
          let lod_change =
            client.loaded_blocks
            .lock().unwrap()
            .get(&block_position)
            .map(|&(_, lod)| new_lod < lod);
          if lod_change == Some(true) {
            load_or_request_chunk(client, update_server, update_view, block_position, new_lod);
          } else {
            trace!("Not updating {:?} at {:?}", block_position, new_lod);
          }
        })
      },
      LoadType::Unload => {
        stopwatch::time("update_thread.unload", || {
          // The block removal code is duplicated elsewhere.

          client.loaded_blocks
          .lock().unwrap()
            .remove(&block_position)
            // If it wasn't loaded, don't unload anything.
            .map(|(block, _)| {
              for id in &block.ids {
                update_view(ClientToView::RemoveTerrain(*id));
              }
            });
        })
      },
    };

    if i >= 10 {
      i -= 10;
      if time::precise_time_ns() - start >= 1_000_000 {
        break
      }
    }
    i += 1;
  }
}

fn load_or_request_chunk<UpdateServer, UpdateView>(
  client: &client::T,
  update_server: &mut UpdateServer,
  update_view: &mut UpdateView,
  block_position: block_position::T,
  lod: lod::T,
) where
  UpdateServer: FnMut(protocol::ClientToServer),
  UpdateView: FnMut(ClientToView),
{
  if load_terrain::all_voxels_loaded(&client.block_voxels_loaded.lock().unwrap(), block_position, lod) {
    load_terrain::load_block(
      client,
      update_view,
      &block_position,
      lod,
    );
  } else {
    let voxel_size = 1 << terrain_mesh::LG_SAMPLE_SIZE[lod.0 as usize];
    update_server(
      protocol::ClientToServer::RequestVoxels(
        time::precise_time_ns(),
        client.id,
        terrain_mesh::voxels_in(
          &Aabb3::new(
            Point3::new(
              (block_position.as_pnt().x << terrain_mesh::LG_WIDTH) - voxel_size,
              (block_position.as_pnt().y << terrain_mesh::LG_WIDTH) - voxel_size,
              (block_position.as_pnt().z << terrain_mesh::LG_WIDTH) - voxel_size,
            ),
            Point3::new(
              ((block_position.as_pnt().x + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
              ((block_position.as_pnt().y + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
              ((block_position.as_pnt().z + 1) << terrain_mesh::LG_WIDTH) + voxel_size,
            ),
          ),
          terrain_mesh::LG_SAMPLE_SIZE[lod.0 as usize],
        ),
      )
    );
    *client.outstanding_terrain_requests.lock().unwrap() += 1;
  }
}

#[inline(never)]
fn process_voxel_updates<RecvVoxelUpdates, UpdateView>(
  client: &client::T,
  recv_voxel_updates: &mut RecvVoxelUpdates,
  update_view: &mut UpdateView,
) where
  RecvVoxelUpdates: FnMut() -> Option<(Option<u64>, Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason)>,
  UpdateView: FnMut(ClientToView),
{
  let start = time::precise_time_ns();
  while let Some((request_time, voxel_updates, reason)) = recv_voxel_updates() {
    let mut update_blocks = block_position::with_lod::set::new();
    let response_time = time::precise_time_ns();
    for (bounds, voxel) in voxel_updates {
      trace!("Got voxel at {:?}", bounds);
      load_terrain::load_voxel(
        client,
        voxel,
        &bounds,
        |block, lod| { update_blocks.insert((block, lod)); },
      );
    }

    let processed_time = time::precise_time_ns();

    for (block, lod) in update_blocks.into_iter() {
      load_terrain::load_block(
        client,
        update_view,
        &block,
        lod
      )
    }

    let block_loaded = time::precise_time_ns();

    match request_time {
      None => {},
      Some(request_time) => {
        record_book::thread_local::push_block_load(
          record_book::BlockLoad {
            requested_at: request_time,
            responded_at: response_time,
            processed_at: processed_time,
            loaded_at: block_loaded,
          }
        );
      },
    }

    match reason {
      protocol::VoxelReason::Updated => {},
      protocol::VoxelReason::Requested => {
        *client.outstanding_terrain_requests.lock().unwrap() -= 1;
        debug!("Outstanding terrain requests: {}", *client.outstanding_terrain_requests.lock().unwrap());
      },
    }

    if time::precise_time_ns() - start >= 1_000_000 {
      break
    }
  }
}

#[inline(never)]
fn process_server_updates<RecvServer, UpdateView, UpdateServer, EnqueueBlockUpdates>(
  client: &client::T,
  recv_server: &mut RecvServer,
  update_view: &mut UpdateView,
  update_server: &mut UpdateServer,
  enqueue_block_updates: &mut EnqueueBlockUpdates,
) where
  RecvServer: FnMut() -> Option<protocol::ServerToClient>,
  UpdateView: FnMut(ClientToView),
  UpdateServer: FnMut(protocol::ClientToServer),
  EnqueueBlockUpdates: FnMut(Option<u64>, Vec<(voxel::bounds::T, voxel::T)>, protocol::VoxelReason),
{
  let start = time::precise_time_ns();
  let mut i = 0;
  while let Some(up) = recv_server() {
    apply_server_update(
      client,
      update_view,
      update_server,
      enqueue_block_updates,
      up,
    );

    if i > 10 {
      i -= 10;
      if time::precise_time_ns() - start >= 1_000_000 {
        break
      }
    }
    i += 1;
  }
}
<|endoftext|>


<commit_before>//! This module contains paths to types and functions Clippy needs to know about.

pub const BEGIN_PANIC: [&'static str; 3] = ["std", "rt", "begin_panic"];
pub const BINARY_HEAP: [&'static str; 3] = ["collections", "binary_heap", "BinaryHeap"];
pub const BOX: [&'static str; 3] = ["std", "boxed", "Box"];
pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"];
pub const BTREEMAP: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"];
pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"];
pub const BTREESET: [&'static str; 4] = ["collections", "btree", "set", "BTreeSet"];
pub const CLONE: [&'static str; 4] = ["core", "clone", "Clone", "clone"];
pub const CLONE_TRAIT: [&'static str; 3] = ["core", "clone", "Clone"];
pub const CMP_MAX: [&'static str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&'static str; 3] = ["core", "cmp", "min"];
pub const COW: [&'static str; 3] = ["collections", "borrow", "Cow"];
pub const CSTRING_NEW: [&'static str; 4] = ["std", "ffi", "CString", "new"];
pub const DEBUG_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"];
pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"];
pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Display", "fmt"];
pub const DROP: [&'static str; 3] = ["core", "mem", "drop"];
pub const FMT_ARGUMENTS_NEWV1: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"];
pub const FMT_ARGUMENTV1_NEW: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"];
pub const HASH: [&'static str; 2] = ["hash", "Hash"];
pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"];
pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"];
pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"];
pub const ITERATOR: [&'static str; 4] = ["core", "iter", "iterator", "Iterator"];
pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"];
pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"];
pub const OPTION: [&'static str; 3] = ["core", "option", "Option"];
pub const RANGE: [&'static str; 3] = ["core", "ops", "Range"];
pub const RANGE_FROM: [&'static str; 3] = ["core", "ops", "RangeFrom"];
pub const RANGE_FROM_STD: [&'static str; 3] = ["std", "ops", "RangeFrom"];
pub const RANGE_FULL: [&'static str; 3] = ["core", "ops", "RangeFull"];
pub const RANGE_FULL_STD: [&'static str; 3] = ["std", "ops", "RangeFull"];
pub const RANGE_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeInclusive"];
pub const RANGE_INCLUSIVE_NON_EMPTY: [&'static str; 4] = ["core", "ops", "RangeInclusive", "NonEmpty"];
pub const RANGE_INCLUSIVE_NON_EMPTY_STD: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"];
pub const RANGE_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeInclusive"];
pub const RANGE_STD: [&'static str; 3] = ["std", "ops", "Range"];
pub const RANGE_TO: [&'static str; 3] = ["core", "ops", "RangeTo"];
pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeToInclusive"];
pub const RANGE_TO_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeToInclusive"];
pub const RANGE_TO_STD: [&'static str; 3] = ["std", "ops", "RangeTo"];
pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"];
pub const REGEX_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
pub const REGEX_BYTES: [&'static str; 3] = ["regex", "re_bytes", "Regex"];
pub const REGEX_BYTES_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&'static str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&'static str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&'static str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&'static str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
pub const RESULT: [&'static str; 3] = ["core", "result", "Result"];
pub const STRING: [&'static str; 3] = ["collections", "string", "String"];
pub const SERDE_DE_VISITOR: [&'static str; 3] = ["serde", "de", "Visitor"];
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
pub const VEC: [&'static str; 3] = ["collections", "vec", "Vec"];
pub const VEC_DEQUE: [&'static str; 3] = ["collections", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&'static str; 3] = ["std", "vec", "from_elem"];
<commit_msg>"fallout"<commit_after>//! This module contains paths to types and functions Clippy needs to know about.

pub const BEGIN_PANIC: [&'static str; 3] = ["std", "rt", "begin_panic"];
pub const BINARY_HEAP: [&'static str; 3] = ["collections", "binary_heap", "BinaryHeap"];
pub const BOX: [&'static str; 3] = ["std", "boxed", "Box"];
pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"];
pub const BTREEMAP: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"];
pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"];
pub const BTREESET: [&'static str; 4] = ["collections", "btree", "set", "BTreeSet"];
pub const CLONE: [&'static str; 4] = ["core", "clone", "Clone", "clone"];
pub const CLONE_TRAIT: [&'static str; 3] = ["core", "clone", "Clone"];
pub const CMP_MAX: [&'static str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&'static str; 3] = ["core", "cmp", "min"];
pub const COW: [&'static str; 3] = ["collections", "borrow", "Cow"];
pub const CSTRING_NEW: [&'static str; 4] = ["std", "ffi", "CString", "new"];
pub const DEBUG_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"];
pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"];
pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Display", "fmt"];
pub const DROP: [&'static str; 3] = ["core", "mem", "drop"];
pub const FMT_ARGUMENTS_NEWV1: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"];
pub const FMT_ARGUMENTV1_NEW: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"];
pub const HASH: [&'static str; 2] = ["hash", "Hash"];
pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"];
pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"];
pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"];
pub const ITERATOR: [&'static str; 4] = ["core", "iter", "iterator", "Iterator"];
pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"];
pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"];
pub const OPTION: [&'static str; 3] = ["core", "option", "Option"];
pub const RANGE: [&'static str; 3] = ["core", "ops", "Range"];
pub const RANGE_FROM: [&'static str; 3] = ["core", "ops", "RangeFrom"];
pub const RANGE_FROM_STD: [&'static str; 3] = ["std", "ops", "RangeFrom"];
pub const RANGE_FULL: [&'static str; 3] = ["core", "ops", "RangeFull"];
pub const RANGE_FULL_STD: [&'static str; 3] = ["std", "ops", "RangeFull"];
pub const RANGE_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeInclusive"];
pub const RANGE_INCLUSIVE_NON_EMPTY: [&'static str; 4] = ["core", "ops", "RangeInclusive", "NonEmpty"];
pub const RANGE_INCLUSIVE_NON_EMPTY_STD: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"];
pub const RANGE_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeInclusive"];
pub const RANGE_STD: [&'static str; 3] = ["std", "ops", "Range"];
pub const RANGE_TO: [&'static str; 3] = ["core", "ops", "RangeTo"];
pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeToInclusive"];
pub const RANGE_TO_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeToInclusive"];
pub const RANGE_TO_STD: [&'static str; 3] = ["std", "ops", "RangeTo"];
pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"];
pub const REGEX_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
pub const REGEX_BYTES: [&'static str; 3] = ["regex", "re_bytes", "Regex"];
pub const REGEX_BYTES_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&'static str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&'static str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&'static str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&'static str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
pub const RESULT: [&'static str; 3] = ["core", "result", "Result"];
pub const SERDE_DE_VISITOR: [&'static str; 3] = ["serde", "de", "Visitor"];
pub const STRING: [&'static str; 3] = ["collections", "string", "String"];
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
pub const VEC: [&'static str; 3] = ["collections", "vec", "Vec"];
pub const VEC_DEQUE: [&'static str; 3] = ["collections", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&'static str; 3] = ["std", "vec", "from_elem"];
<|endoftext|>