<commit_before>//! Utility module for lexer implementations,
//! providing types to help manage states and tokens.

use std::str::Chars;
use super::token::Token;
use super::token::Category;

/// A recursive function type used by lexers to manage their state.
/// Based on Rob Pike's "Lexical Scanning in Go" talk, these functions are
/// invoked in a call/return loop (letting the current function determine
/// the next) until a `None` value is returned, after which lexing is complete.
///
/// See the `lexers` module for examples.
pub struct StateFunction(pub fn(&mut Tokenizer) -> Option<StateFunction>);

/// The Tokenizer type is used to produce and store tokens for lexers.
pub struct Tokenizer<'a> {
    data: Chars<'a>,
    current_token: String,
    tokens: Vec<Token>,
    pub states: Vec<StateFunction>,
}

/// Initializes a new tokenizer with the given data.
///
/// # Examples
///
/// ```
/// let tokenizer = luthor::tokenizer::new("luthor");
/// ```
pub fn new(data: &str) -> Tokenizer {
    Tokenizer{
      data: data.chars(),
      current_token: String::new(),
      tokens: vec![],
      states: vec![]
    }
}

impl<'a> Tokenizer<'a> {
    /// Returns a copy of the tokens processed to date.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// tokenizer.tokens();
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        self.tokens.clone()
    }

    /// Moves to the next character in the data.
    /// Does nothing if there is no more data to process.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Ensure that we're at the first character.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    ///
    /// // Consume the first character.
    /// tokenizer.advance();
    ///
    /// // Ensure that we're at the next character.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'u');
    /// ```
    pub fn advance(&mut self) {
        match self.data.next() {
            Some(c) => self.current_token.push(c),
            None => ()
        }
    }

    /// Returns the character at the current position,
    /// unless all of the data has been processed.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("l");
    ///
    /// // Ensure that the current character is correct.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    ///
    /// // Consume the last bit of data.
    /// tokenizer.advance();
    ///
    /// // Ensure that there is no current character.
    /// assert_eq!(tokenizer.current_char(), None);
    /// ```
    pub fn current_char(&self) -> Option<char> {
        match self.data.clone().peekable().peek() {
            Some(c) => Some(c.clone()),
            None => None
        }
    }

    /// Whether or not the remaining data starts with the specified prefix.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let tokenizer = luthor::tokenizer::new("lex");
    ///
    /// assert!(tokenizer.has_prefix("le"));
    /// ```
    pub fn has_prefix(&self, prefix: &str) -> bool {
        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let mut data_iter = self.data.clone();

        // Check that the subject is a prefix, character by character.
        // This is much faster than building a string of equal length from
        // self.data and deferring to a straight string comparison using ==.
        prefix.chars().all(|c| {
            match data_iter.next() {
                Some(d) => c == d,
                None => false
            }
        })
    }

    /// Whether or not the remaining data starts with the specified lexeme.
    /// Ensures that the specified lexeme is not just a prefix by checking that
    /// the data that follows it is a newline, space, comma, or nothing at all.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("lex\nluthor lib,rary");
    ///
    /// // Prefixes don't count.
    /// assert!(!tokenizer.starts_with_lexeme("le"));
    ///
    /// // Newlines delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("lex"));
    ///
    /// // Consume 4 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(4, Category::Text);
    ///
    /// // Spaces delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("luthor"));
    ///
    /// // Consume 7 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(7, Category::Text);
    ///
    /// // Commas delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("lib"));
    ///
    /// // Consume 4 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(4, Category::Text);
    ///
    /// // End of string delineates lexemes.
    /// assert!(tokenizer.starts_with_lexeme("rary"));
    /// ```
    pub fn starts_with_lexeme(&self, lexeme: &str) -> bool {
        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let data_iter = self.data.clone();

        self.has_prefix(lexeme) && match data_iter.skip(lexeme.len()).next() {
            Some(' ') | Some('\n') | Some(',') => true,
            None => true,
            _ => false
        }
    }

    /// Creates and stores a token with the given category containing any
    /// data processed using `advance` since the last call to this method.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Consume two characters and then tokenize them.
    /// tokenizer.advance();
    /// tokenizer.advance();
    /// tokenizer.tokenize(Category::Text);
    ///
    /// // Ensure that we have a correctly-categorized token.
    /// assert_eq!(tokenizer.tokens()[0].lexeme, "lu");
    /// ```
    pub fn tokenize(&mut self, category: Category) {
        if !self.current_token.is_empty() {
            let token = Token{
                lexeme: self.current_token.clone(),
                category: category,
            };
            self.tokens.push(token);
            self.current_token = String::new();
        }
    }

    /// Creates and stores a token with the given category and the
    /// next `amount` characters of the data. Before doing this, it
    /// tokenizes any previously processed characters with the generic
    /// `Category::Text` category.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Consume one character, and then tokenize the next 5.
    /// tokenizer.advance();
    /// tokenizer.tokenize_next(5, Category::Keyword);
    ///
    /// // Ensure that we have two properly-categorized tokens.
    /// assert_eq!(
    ///     tokenizer.tokens()[0],
    ///     Token{ lexeme: "l".to_string(), category: Category::Text }
    /// );
    /// assert_eq!(
    ///     tokenizer.tokens()[1],
    ///     Token{ lexeme: "uthor".to_string(), category: Category::Keyword }
    /// );
    /// ```
    pub fn tokenize_next(&mut self, amount: usize, category: Category) {
        // If there's any data that has yet
        // to be tokenized, take care of that.
        self.tokenize(Category::Text);

        // Mark the next series of characters.
        for _ in 0..amount { self.advance(); }

        // Tokenize the marked characters.
        self.tokenize(category);
    }

    /// Consumes consecutive whitespace characters as a single token.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// let mut tokenizer = luthor::tokenizer::new("  \nluthor");
    /// tokenizer.consume_whitespace();
    ///
    /// assert_eq!(
    ///     tokenizer.tokens()[0],
    ///     Token{ lexeme: "  \n".to_string(), category: Category::Whitespace }
    /// );
    /// ```
    pub fn consume_whitespace(&mut self) {
        // If there's any data that has yet
        // to be tokenized, take care of that.
        self.tokenize(Category::Text);

        loop {
            match self.current_char() {
                Some(' ') | Some('\n') => self.advance(),
                _ => {
                    self.tokenize(Category::Whitespace);
                    break
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::super::token::Token;
    use super::super::token::Category;

    #[test]
    fn current_char_returns_the_char_at_head() {
        let data = "él";
        let tokenizer = new(data);

        assert_eq!(tokenizer.current_char().unwrap(), 'é');
    }

    #[test]
    fn current_char_returns_none_if_at_the_end() {
        let data = "él";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();

        assert_eq!(tokenizer.current_char(), None);
    }

    #[test]
    fn tokenize_creates_the_correct_token() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize(Category::Text);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_does_nothing_if_range_is_empty() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.tokenize(Category::Text);

        assert_eq!(tokenizer.tokens.len(), 0);
    }

    #[test]
    fn tokenize_next_tokenizes_previous_data_as_text() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(1, Category::Keyword);

        let token = tokenizer.tokens.remove(0);
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_tokenizes_next_x_chars() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(5, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_takes_at_most_what_is_left() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(15, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }
}
<commit_msg>Prevent consume_whitespace from doing anything if none is found.<commit_after>//! Utility module for lexer implementations,
//! providing types to help manage states and tokens.

use std::str::Chars;
use super::token::Token;
use super::token::Category;

/// A recursive function type used by lexers to manage their state.
/// Based on Rob Pike's "Lexical Scanning in Go" talk, these functions are
/// invoked in a call/return loop (letting the current function determine
/// the next) until a `None` value is returned, after which lexing is complete.
///
/// See the `lexers` module for examples.
pub struct StateFunction(pub fn(&mut Tokenizer) -> Option<StateFunction>);

/// The Tokenizer type is used to produce and store tokens for lexers.
pub struct Tokenizer<'a> {
    data: Chars<'a>,
    current_token: String,
    tokens: Vec<Token>,
    pub states: Vec<StateFunction>,
}

/// Initializes a new tokenizer with the given data.
///
/// # Examples
///
/// ```
/// let tokenizer = luthor::tokenizer::new("luthor");
/// ```
pub fn new(data: &str) -> Tokenizer {
    Tokenizer{
      data: data.chars(),
      current_token: String::new(),
      tokens: vec![],
      states: vec![]
    }
}

impl<'a> Tokenizer<'a> {
    /// Returns a copy of the tokens processed to date.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// tokenizer.tokens();
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        self.tokens.clone()
    }

    /// Moves to the next character in the data.
    /// Does nothing if there is no more data to process.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Ensure that we're at the first character.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    ///
    /// // Consume the first character.
    /// tokenizer.advance();
    ///
    /// // Ensure that we're at the next character.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'u');
    /// ```
    pub fn advance(&mut self) {
        match self.data.next() {
            Some(c) => self.current_token.push(c),
            None => ()
        }
    }

    /// Returns the character at the current position,
    /// unless all of the data has been processed.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("l");
    ///
    /// // Ensure that the current character is correct.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    ///
    /// // Consume the last bit of data.
    /// tokenizer.advance();
    ///
    /// // Ensure that there is no current character.
    /// assert_eq!(tokenizer.current_char(), None);
    /// ```
    pub fn current_char(&self) -> Option<char> {
        match self.data.clone().peekable().peek() {
            Some(c) => Some(c.clone()),
            None => None
        }
    }

    /// Whether or not the remaining data starts with the specified prefix.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let tokenizer = luthor::tokenizer::new("lex");
    ///
    /// assert!(tokenizer.has_prefix("le"));
    /// ```
    pub fn has_prefix(&self, prefix: &str) -> bool {
        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let mut data_iter = self.data.clone();

        // Check that the subject is a prefix, character by character.
        // This is much faster than building a string of equal length from
        // self.data and deferring to a straight string comparison using ==.
        prefix.chars().all(|c| {
            match data_iter.next() {
                Some(d) => c == d,
                None => false
            }
        })
    }

    /// Whether or not the remaining data starts with the specified lexeme.
    /// Ensures that the specified lexeme is not just a prefix by checking that
    /// the data that follows it is a newline, space, comma, or nothing at all.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("lex\nluthor lib,rary");
    ///
    /// // Prefixes don't count.
    /// assert!(!tokenizer.starts_with_lexeme("le"));
    ///
    /// // Newlines delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("lex"));
    ///
    /// // Consume 4 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(4, Category::Text);
    ///
    /// // Spaces delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("luthor"));
    ///
    /// // Consume 7 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(7, Category::Text);
    ///
    /// // Commas delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("lib"));
    ///
    /// // Consume 4 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(4, Category::Text);
    ///
    /// // End of string delineates lexemes.
    /// assert!(tokenizer.starts_with_lexeme("rary"));
    /// ```
    pub fn starts_with_lexeme(&self, lexeme: &str) -> bool {
        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let data_iter = self.data.clone();

        self.has_prefix(lexeme) && match data_iter.skip(lexeme.len()).next() {
            Some(' ') | Some('\n') | Some(',') => true,
            None => true,
            _ => false
        }
    }

    /// Creates and stores a token with the given category containing any
    /// data processed using `advance` since the last call to this method.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Consume two characters and then tokenize them.
    /// tokenizer.advance();
    /// tokenizer.advance();
    /// tokenizer.tokenize(Category::Text);
    ///
    /// // Ensure that we have a correctly-categorized token.
    /// assert_eq!(tokenizer.tokens()[0].lexeme, "lu");
    /// ```
    pub fn tokenize(&mut self, category: Category) {
        if !self.current_token.is_empty() {
            let token = Token{
                lexeme: self.current_token.clone(),
                category: category,
            };
            self.tokens.push(token);
            self.current_token = String::new();
        }
    }

    /// Creates and stores a token with the given category and the
    /// next `amount` characters of the data. Before doing this, it
    /// tokenizes any previously processed characters with the generic
    /// `Category::Text` category.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Consume one character, and then tokenize the next 5.
    /// tokenizer.advance();
    /// tokenizer.tokenize_next(5, Category::Keyword);
    ///
    /// // Ensure that we have two properly-categorized tokens.
    /// assert_eq!(
    ///     tokenizer.tokens()[0],
    ///     Token{ lexeme: "l".to_string(), category: Category::Text }
    /// );
    /// assert_eq!(
    ///     tokenizer.tokens()[1],
    ///     Token{ lexeme: "uthor".to_string(), category: Category::Keyword }
    /// );
    /// ```
    pub fn tokenize_next(&mut self, amount: usize, category: Category) {
        // If there's any data that has yet
        // to be tokenized, take care of that.
        self.tokenize(Category::Text);

        // Mark the next series of characters.
        for _ in 0..amount { self.advance(); }

        // Tokenize the marked characters.
        self.tokenize(category);
    }

    /// Consumes consecutive whitespace characters as a single token.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// let mut tokenizer = luthor::tokenizer::new("  \nluthor");
    /// tokenizer.consume_whitespace();
    ///
    /// assert_eq!(
    ///     tokenizer.tokens()[0],
    ///     Token{ lexeme: "  \n".to_string(), category: Category::Whitespace }
    /// );
    /// ```
    pub fn consume_whitespace(&mut self) {
        let mut found_whitespace = false;
        loop {
            match self.current_char() {
                Some(' ') | Some('\n') => {
                    if !found_whitespace {
                        self.tokenize(Category::Text);
                        found_whitespace = true;
                    }

                    self.advance();
                },
                _ => {
                    if found_whitespace {
                        self.tokenize(Category::Whitespace);
                    }
                    return
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::super::token::Token;
    use super::super::token::Category;

    #[test]
    fn current_char_returns_the_char_at_head() {
        let data = "él";
        let tokenizer = new(data);

        assert_eq!(tokenizer.current_char().unwrap(), 'é');
    }

    #[test]
    fn current_char_returns_none_if_at_the_end() {
        let data = "él";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();

        assert_eq!(tokenizer.current_char(), None);
    }

    #[test]
    fn tokenize_creates_the_correct_token() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize(Category::Text);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_does_nothing_if_range_is_empty() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.tokenize(Category::Text);

        assert_eq!(tokenizer.tokens.len(), 0);
    }

    #[test]
    fn tokenize_next_tokenizes_previous_data_as_text() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(1, Category::Keyword);

        let token = tokenizer.tokens.remove(0);
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_tokenizes_next_x_chars() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(5, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_takes_at_most_what_is_left() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(15, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn consume_whitespace_handles_preexisting_noncategorized_chars() {
        let data = "e  ";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.consume_whitespace();

        assert_eq!(
            tokenizer.tokens()[0],
            Token{ lexeme: "e".to_string(), category: Category::Text }
        );
        assert_eq!(
            tokenizer.tokens()[1],
            Token{ lexeme: "  ".to_string(), category: Category::Whitespace }
        );
    }
}
<|endoftext|>


<commit_before>use nalgebra::{ToHomogeneous, Unit, UnitQuaternion, Quaternion};
use serde::{Deserialize, Deserializer, Error, Serialize, Serializer};
use serde::de::{MapVisitor, Visitor};
use std::default::Default;

use luminance::linear::M44;
use luminance::shader::program::UniformUpdate;
use luminance_gl::gl33::Uniform;

pub use nalgebra::{Matrix4, Vector3};

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
  pub translation: Translation,
  pub orientation: Orientation,
  pub scale: Scale
}

impl Transform {
  pub fn new(translation: Translation, orientation: Orientation, scale: Scale) -> Self {
    Transform {
      translation: translation,
      orientation: orientation,
      scale: scale
    }
  }

  pub fn repos(self, pos: Position) -> Self {
    Transform { translation: pos, .. self }
  }

  pub fn translate(self, t: Translation) -> Self {
    Transform { translation: self.translation + t, .. self }
  }

  pub fn reorient(self, axis: Axis, phi: f32) -> Self {
    Transform { orientation: UnitQuaternion::from_axisangle(Unit::new(&axis), phi), .. self }
  }

  pub fn orient(self, axis: Axis, phi: f32) -> Self {
    Transform { orientation: UnitQuaternion::from_axisangle(Unit::new(&axis), phi) * self.orientation, .. self }
  }

  pub fn uni_scale(self, scale: f32) -> Self {
    Transform { scale: Scale { x: scale, y: scale, z: scale }, .. self }
  }

  pub fn rescale(self, scale: Scale) -> Self {
    Transform { scale: scale, .. self }
  }

  pub fn scale(self, scale: Scale) -> Self {
    let new_scale = Scale {
      x: self.scale.x * scale.x,
      y: self.scale.y * scale.y,
      z: self.scale.z * scale.z,
    };

    Transform { scale: new_scale, .. self }
  }

  pub fn to_inst_mat(&self) -> Matrix4<f32> {
    translation_matrix(self.translation) * self.scale.to_mat() * self.orientation.to_rotation_matrix().to_homogeneous()
  }

  pub fn to_view_mat(&self) -> Matrix4<f32> {
    self.orientation.to_rotation_matrix().to_homogeneous() * translation_matrix(self.translation) * self.scale.to_mat()
  }

  pub fn as_inst_uniform<'a>(u: Uniform<M44>) -> UniformUpdate<'a, Self> {
    let u: UniformUpdate<M44> = u.into();
    u.contramap(|transform: Transform| { *transform.to_inst_mat().as_ref() })
  }

  pub fn as_view_uniform<'a>(u: Uniform<M44>) -> UniformUpdate<'a, Self> {
    let u: UniformUpdate<M44> = u.into();
    u.contramap(|transform: Transform| { *transform.to_view_mat().as_ref() })
  }
}

impl Default for Transform {
  fn default() -> Self {
    Transform {
      translation: Vector3::new(0., 0., 0.),
      orientation: UnitQuaternion::from_unit_value_unchecked(Quaternion::from_parts(1., Vector3::new(0., 0., 0.))),
      scale: Scale::default()
    }
  }
}

impl Serialize for Transform {
  fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
    let mut struct_st = try!(serializer.serialize_struct("Transform", 3));

    try!(serializer.serialize_struct_elt(&mut struct_st, "translation", self.translation.as_ref()));
    try!(serializer.serialize_struct_elt(&mut struct_st, "orientation", self.orientation.as_ref().as_ref()));
    let scale = [self.scale.x, self.scale.y, self.scale.z];
    try!(serializer.serialize_struct_elt(&mut struct_st, "scale", scale));

    serializer.serialize_struct_end(struct_st)
  }
}

impl Deserialize for Transform {
  fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
    enum Field { Translation, Orientation, Scale };

    impl Deserialize for Field {
      fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error> where D: Deserializer {
        struct FieldVisitor;

        impl Visitor for FieldVisitor {
          type Value = Field;

          fn visit_str<E>(&mut self, value: &str) -> Result<Field, E> where E: Error {
            match value {
              "translation" => Ok(Field::Translation),
              "orientation" => Ok(Field::Orientation),
              "scale" => Ok(Field::Scale),
              _ => Err(Error::unknown_field(value))
            }
          }
        }

        deserializer.deserialize_struct_field(FieldVisitor)
      }
    }

    struct TransformVisitor;

    impl Visitor for TransformVisitor {
      type Value = Transform;

      fn visit_map<V>(&mut self, mut visitor: V) -> Result<Self::Value, V::Error> where V: MapVisitor {
        let mut translation: Option<[f32; 3]> = None;
        let mut orientation: Option<[f32; 4]> = None;
        let mut scale: Option<[f32; 3]> = None;

        while let Some(key) = try!(visitor.visit_key::<Field>()) {
          match key {
            Field::Translation => {
              if translation.is_some() {
                return Err(<V::Error as Error>::duplicate_field("translation"));
              }

              translation = Some(try!(visitor.visit_value()));
            },
            Field::Orientation => {
              if orientation.is_some() {
                return Err(<V::Error as Error>::duplicate_field("orientation"));
              }

              orientation = Some(try!(visitor.visit_value()));
            },
            Field::Scale => {
              if scale.is_some() {
                return Err(<V::Error as Error>::duplicate_field("scale"));
              }

              scale = Some(try!(visitor.visit_value()));
            }
          }
        }

        try!(visitor.end());

        let translation = match translation {
          Some(a) => a,
          None => try!(visitor.missing_field("translation"))
        };

        let orientation = match orientation {
          Some(a) => a,
          None => try!(visitor.missing_field("orientation")),
        };

        let scale = match scale {
          Some(a) => a,
          None => try!(visitor.missing_field("scale"))
        };

        Ok(Transform::new(Translation::from(&translation), Orientation::new(&Quaternion::from(&orientation)), Scale::from(&scale)))
      }
    }

    const FIELDS: &'static [&'static str] = &["translation", "orientation", "scale"];
    deserializer.deserialize_struct("Transform", FIELDS, TransformVisitor)
  }
}

pub type Translation = Vector3<f32>;
pub type Axis = Vector3<f32>;
pub type Position = Vector3<f32>;
pub type Orientation = UnitQuaternion<f32>;

pub const X_AXIS: Axis = Axis { x: 1., y: 0., z: 0. };
pub const Y_AXIS: Axis = Axis { x: 0., y: 1., z: 0. };
pub const Z_AXIS: Axis = Axis { x: 0., y: 0., z: 1. };

/// Arbritrary scale.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Scale {
  pub x: f32,
  pub y: f32,
  pub z: f32
}

impl Scale {
  pub fn new(x: f32, y: f32, z: f32) -> Self {
    Scale {
      x: x,
      y: y,
      z: z
    }
  }

  pub fn uni(x: f32) -> Self {
    Scale {
      x: x,
      y: x,
      z: x
    }
  }

  pub fn to_mat(&self) -> Matrix4<f32> {
    Matrix4::new(
      self.x,     0.,     0., 0.,
          0., self.y,     0., 0.,
          0.,     0., self.z, 0.,
          0.,     0.,     0., 1.
    )
  }
}

impl Default for Scale {
  fn default() -> Self { Scale::new(1., 1., 1.) }
}

impl<'a> From<&'a [f32; 3]> for Scale {
  fn from(slice: &[f32; 3]) -> Self {
    Scale {
      x: slice[0],
      y: slice[1],
      z: slice[2]
    }
  }
}

fn translation_matrix(v: Translation) -> Matrix4<f32> {
  Matrix4::new(
    1., 0., 0., v.x,
    0., 1., 0., v.y,
    0., 0., 1., v.z,
    0., 0., 0.,  1.,
  )
}
<commit_msg>Scale From stuff.<commit_after>use nalgebra::{ToHomogeneous, Unit, UnitQuaternion, Quaternion};
use serde::{Deserialize, Deserializer, Error, Serialize, Serializer};
use serde::de::{MapVisitor, Visitor};
use std::default::Default;

use luminance::linear::M44;
use luminance::shader::program::UniformUpdate;
use luminance_gl::gl33::Uniform;

pub use nalgebra::{Matrix4, Vector3};

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
  pub translation: Translation,
  pub orientation: Orientation,
  pub scale: Scale
}

impl Transform {
  pub fn new(translation: Translation, orientation: Orientation, scale: Scale) -> Self {
    Transform {
      translation: translation,
      orientation: orientation,
      scale: scale
    }
  }

  pub fn repos(self, pos: Position) -> Self {
    Transform { translation: pos, .. self }
  }

  pub fn translate(self, t: Translation) -> Self {
    Transform { translation: self.translation + t, .. self }
  }

  pub fn reorient(self, axis: Axis, phi: f32) -> Self {
    Transform { orientation: UnitQuaternion::from_axisangle(Unit::new(&axis), phi), .. self }
  }

  pub fn orient(self, axis: Axis, phi: f32) -> Self {
    Transform { orientation: UnitQuaternion::from_axisangle(Unit::new(&axis), phi) * self.orientation, .. self }
  }

  pub fn uni_scale(self, scale: f32) -> Self {
    Transform { scale: Scale { x: scale, y: scale, z: scale }, .. self }
  }

  pub fn rescale(self, scale: Scale) -> Self {
    Transform { scale: scale, .. self }
  }

  pub fn scale(self, scale: Scale) -> Self {
    let new_scale = Scale {
      x: self.scale.x * scale.x,
      y: self.scale.y * scale.y,
      z: self.scale.z * scale.z,
    };

    Transform { scale: new_scale, .. self }
  }

  pub fn to_inst_mat(&self) -> Matrix4<f32> {
    translation_matrix(self.translation) * self.scale.to_mat() * self.orientation.to_rotation_matrix().to_homogeneous()
  }

  pub fn to_view_mat(&self) -> Matrix4<f32> {
    self.orientation.to_rotation_matrix().to_homogeneous() * translation_matrix(self.translation) * self.scale.to_mat()
  }

  pub fn as_inst_uniform<'a>(u: Uniform<M44>) -> UniformUpdate<'a, Self> {
    let u: UniformUpdate<M44> = u.into();
    u.contramap(|transform: Transform| { *transform.to_inst_mat().as_ref() })
  }

  pub fn as_view_uniform<'a>(u: Uniform<M44>) -> UniformUpdate<'a, Self> {
    let u: UniformUpdate<M44> = u.into();
    u.contramap(|transform: Transform| { *transform.to_view_mat().as_ref() })
  }
}

impl Default for Transform {
  fn default() -> Self {
    Transform {
      translation: Vector3::new(0., 0., 0.),
      orientation: UnitQuaternion::from_unit_value_unchecked(Quaternion::from_parts(1., Vector3::new(0., 0., 0.))),
      scale: Scale::default()
    }
  }
}

impl Serialize for Transform {
  fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
    let mut struct_st = try!(serializer.serialize_struct("Transform", 3));

    try!(serializer.serialize_struct_elt(&mut struct_st, "translation", self.translation.as_ref()));
    try!(serializer.serialize_struct_elt(&mut struct_st, "orientation", self.orientation.as_ref().as_ref()));
    let scale = [self.scale.x, self.scale.y, self.scale.z];
    try!(serializer.serialize_struct_elt(&mut struct_st, "scale", scale));

    serializer.serialize_struct_end(struct_st)
  }
}

impl Deserialize for Transform {
  fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
    enum Field { Translation, Orientation, Scale };

    impl Deserialize for Field {
      fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error> where D: Deserializer {
        struct FieldVisitor;

        impl Visitor for FieldVisitor {
          type Value = Field;

          fn visit_str<E>(&mut self, value: &str) -> Result<Field, E> where E: Error {
            match value {
              "translation" => Ok(Field::Translation),
              "orientation" => Ok(Field::Orientation),
              "scale" => Ok(Field::Scale),
              _ => Err(Error::unknown_field(value))
            }
          }
        }

        deserializer.deserialize_struct_field(FieldVisitor)
      }
    }

    struct TransformVisitor;

    impl Visitor for TransformVisitor {
      type Value = Transform;

      fn visit_map<V>(&mut self, mut visitor: V) -> Result<Self::Value, V::Error> where V: MapVisitor {
        let mut translation: Option<[f32; 3]> = None;
        let mut orientation: Option<[f32; 4]> = None;
        let mut scale: Option<[f32; 3]> = None;

        while let Some(key) = try!(visitor.visit_key::<Field>()) {
          match key {
            Field::Translation => {
              if translation.is_some() {
                return Err(<V::Error as Error>::duplicate_field("translation"));
              }

              translation = Some(try!(visitor.visit_value()));
            },
            Field::Orientation => {
              if orientation.is_some() {
                return Err(<V::Error as Error>::duplicate_field("orientation"));
              }

              orientation = Some(try!(visitor.visit_value()));
            },
            Field::Scale => {
              if scale.is_some() {
                return Err(<V::Error as Error>::duplicate_field("scale"));
              }

              scale = Some(try!(visitor.visit_value()));
            }
          }
        }

        try!(visitor.end());

        let translation = match translation {
          Some(a) => a,
          None => try!(visitor.missing_field("translation"))
        };

        let orientation = match orientation {
          Some(a) => a,
          None => try!(visitor.missing_field("orientation")),
        };

        let scale = match scale {
          Some(a) => a,
          None => try!(visitor.missing_field("scale"))
        };

        Ok(Transform::new(Translation::from(&translation), Orientation::new(&Quaternion::from(&orientation)), Scale::from(&scale)))
      }
    }

    const FIELDS: &'static [&'static str] = &["translation", "orientation", "scale"];
    deserializer.deserialize_struct("Transform", FIELDS, TransformVisitor)
  }
}

pub type Translation = Vector3<f32>;
pub type Axis = Vector3<f32>;
pub type Position = Vector3<f32>;
pub type Orientation = UnitQuaternion<f32>;

pub const X_AXIS: Axis = Axis { x: 1., y: 0., z: 0. };
pub const Y_AXIS: Axis = Axis { x: 0., y: 1., z: 0. };
pub const Z_AXIS: Axis = Axis { x: 0., y: 0., z: 1. };

/// Arbritrary scale.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Scale {
  pub x: f32,
  pub y: f32,
  pub z: f32
}

impl Scale {
  pub fn new(x: f32, y: f32, z: f32) -> Self {
    Scale {
      x: x,
      y: y,
      z: z
    }
  }

  pub fn uni(x: f32) -> Self {
    Scale {
      x: x,
      y: x,
      z: x
    }
  }

  pub fn to_mat(&self) -> Matrix4<f32> {
    Matrix4::new(
      self.x,     0.,     0., 0.,
          0., self.y,     0., 0.,
          0.,     0., self.z, 0.,
          0.,     0.,     0., 1.
    )
  }
}

impl Default for Scale {
  fn default() -> Self { Scale::new(1., 1., 1.) }
}

impl<'a> From<&'a [f32; 3]> for Scale {
  fn from(slice: &[f32; 3]) -> Self {
    Scale {
      x: slice[0],
      y: slice[1],
      z: slice[2]
    }
  }
}

impl<'a> From<&'a Scale> for [f32; 3] {
  fn from(scale: &Scale) -> Self {
    [scale.x, scale.y, scale.z]
  }
}

fn translation_matrix(v: Translation) -> Matrix4<f32> {
  Matrix4::new(
    1., 0., 0., v.x,
    0., 1., 0., v.y,
    0., 0., 1., v.z,
    0., 0., 0.,  1.,
  )
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Read, Write};
use std::net;
use std::net::TcpStream;

#[derive(Debug)]
pub struct Transport {
    tcp: TcpStream
}

impl Transport {
    pub fn new(addr: &str) -> io::Result<Transport> {
        return net::TcpStream::connect(addr)
            .map(|socket| Transport {
                tcp: socket
            });
    }

    /// In opposite to `TcpStream`'s `try_clone` this method
    /// creates absolutely new connection - it gets an address
    /// of a peer from `Transport` and creates a new encrypted
    /// transport with new TCP stream under hood.
    pub fn try_clone(&self) -> io::Result<Transport> {
        let addr = try!(self.tcp.peer_addr());

        net::TcpStream::connect(addr)
            .map(|socket| Transport {
                tcp: socket
            })
    }

    pub fn close(&mut self, close: net::Shutdown) -> io::Result<()> {
        return self.tcp.shutdown(close);
    }
}

impl Read for Transport {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        return self.tcp.read(buf);
    }
}

impl Write for Transport {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        return self.tcp.write(buf);
    }

    fn flush(&mut self) -> io::Result<()> {
        return self.tcp.flush();
    }
}
<commit_msg>trying to fit in<commit_after>use std::io;
use std::io::{Read, Write};
use std::net;
use std::net::TcpStream;
#[cfg(feature = "ssl")]
use openssl::ssl::{SslStream, SslConnector,HandshakeError};

pub  trait  CDRSTransport{

    fn try_clone(&self) -> io::Result<Self>;
    fn close(&mut self, close: net::Shutdown) -> io::Result<()>;
}

impl CDRSTransport  for Transport {

    /// In opposite to `TcpStream`'s `try_clone` this method
    /// creates absolutely new connection - it gets an address
    /// of a peer from `Transport` and creates a new encrypted
    /// transport with new TCP stream under hood.
    fn try_clone(&self) -> io::Result<Transport> {
        let addr = try!( self.tcp.peer_addr());

        net::TcpStream::connect(addr)
        .map( | socket | Transport {
        tcp: socket
        })
    }

     fn close(&mut self, close: net::Shutdown) -> io::Result<()> {
            return self.tcp.shutdown(close);
    }

}

#[derive(Debug)]
pub struct Transport {
    tcp: TcpStream
}

impl Transport {
    pub fn new(addr: &str) -> io::Result<Transport> {
        return net::TcpStream::connect(addr)
            .map(|socket| Transport {
                tcp: socket
            });
    }

}

impl Read for Transport {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        return self.tcp.read(buf);
    }
}

impl Write for Transport {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        return self.tcp.write(buf);
    }

    fn flush(&mut self) -> io::Result<()> {
        return self.tcp.flush();
    }
}
/*************************************/
/** TLS**/
/**************************************/
#[cfg(feature = "ssl")]
impl CDRSTransport for TransportTls{

    /// In opposite to `TcpStream`'s `try_clone` this method
    /// creates absolutely new connection - it gets an address
    /// of a peer from `TransportTls` and creates a new encrypted
    /// connection with a new TCP stream under hood.
     fn try_clone(&self) -> io::Result<TransportTls> {
        let addr = try!(self.ssl.get_ref().peer_addr());
        let ip_string = format!("{}", addr.ip());

        let res =  net::TcpStream::connect(addr)
            .map(|socket|
                     self.connector.connect(ip_string.as_str(), socket)
                         .map(|sslsocket| TransportTls {ssl: sslsocket, connector: self.connector.clone()}));

        res.and_then(|res| {
            res.map(|n: TransportTls| n ).map_err(|e| io::Error::new(io::ErrorKind::Other,e))
        })
    }

     fn close(&mut self, _close: net::Shutdown) -> io::Result<()> {
        return self.ssl.shutdown().map_err(|e| io::Error::new(io::ErrorKind::Other,e)).and_then(|_| Ok(()));
    }
}
#[cfg(feature = "ssl")]
pub struct TransportTls {
    ssl: SslStream<TcpStream>,
    connector: SslConnector
}
#[cfg(feature = "ssl")]
impl TransportTls {

    pub fn new(addr: &str, connector: & SslConnector) -> io::Result<TransportTls> {
        let a: Vec<&str> = addr.split(':').collect();
        let res =  net::TcpStream::connect(addr)
            .map(|socket|
                     connector.connect(a[0], socket)
                         .map(|sslsocket|
                                  TransportTls {
                                      ssl: sslsocket,
                                      connector: connector.clone()
                                  }
                         )
            );

        res.and_then(|res| {
            // transform `Ok(Result<TransportTls,HandshakeError<net::TcpStream>>)` into `Ok(Result<TransportTls, io::Error>)`
            res
                // transform n to TransportTls
                .map(|n: TransportTls| n )
                // transform `HandshakeError` into `'io::Error`
                .map_err(|e| io::Error::new(io::ErrorKind::Other,e))

        })
    }

}
#[cfg(feature = "ssl")]
impl Read for TransportTls {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        return self.ssl.read(buf);
    }
}
#[cfg(feature = "ssl")]
impl Write for TransportTls {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        return self.ssl.write(buf);
    }

    fn flush(&mut self) -> io::Result<()> {
        return self.ssl.flush();
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;
use std::mem::replace;

use adapton_syntax::* ;
use adapton_sigs::* ;

pub trait ListT<A:Adapton,Hd> : Debug+Hash+PartialEq+Eq+Clone {
    type List : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::List ;
    fn cons (&mut A, Hd, Self::List) -> Self::List ;
    fn rc   (&mut A, Rc<Self::List>) -> Self::List ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Self::List) -> Self::List ;
    fn art  (&mut A, Art<Self::List,A::Loc>) -> Self::List ;

    fn elim<Res,Nil,Cons,Name> (&mut A, &Self::List, Nil, Cons, Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Self::List) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Self::List) -> Res ;

    // Derived from `cons` and `nil` above:
    fn singleton (st:&mut A, hd:Hd) -> Self::List {
        let nil = Self::nil(st);
        Self::cons(st, hd, nil)
    }

    // Derived from `elim` above:
    fn is_empty (st:&mut A, list:&Self::List) -> bool {
        Self::elim(st, &list,
                   |_|       true,
                   |_,_,_|   false,
                   |st,_,tl| Self::is_empty(st,tl))
    }
}

pub trait TreeT<A:Adapton,Leaf,Bin:Hash> : Debug+Hash+PartialEq+Eq+Clone {
    type Tree : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::Tree ;
    fn leaf (&mut A, Leaf) -> Self::Tree ;
    fn bin  (&mut A, Bin, Self::Tree, Self::Tree) -> Self::Tree ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Self::Tree, Self::Tree) -> Self::Tree ;
    fn art  (&mut A, Art<Self::Tree,A::Loc>) -> Self::Tree ;

    fn fold<Res,LeafC,BinC,NameC> (&mut A, Self::Tree, Res, LeafC, BinC, NameC) -> Res
        where LeafC:Fn(&mut A, Res, &Leaf    ) -> Res
        ,      BinC:Fn(&mut A, Res, &Bin     ) -> Res
        ,     NameC:Fn(&mut A, Res, &A::Name ) -> Res
        ;

    fn fold_up<Res,LeafC,BinC,NameC> (&mut A, Self::Tree, LeafC, BinC, NameC) -> Res
        where LeafC:Fn(&mut A, &Leaf              ) -> Res
        ,      BinC:Fn(&mut A, &Bin,     Res, Res ) -> Res
        ,     NameC:Fn(&mut A, &A::Name, Res, Res ) -> Res
        ;

    // TODO: Add derived operations (max, min, sum, etc.) for fold_up.
}

#[derive(Debug,PartialEq,Eq,Hash,Clone)]
enum List<A:Adapton,Hd> {
    Nil,
    Cons(Hd,      Box<List<A,Hd>>),
    Rc(           Rc<List<A,Hd>>),
    Name(A::Name, Box<List<A,Hd>>),
    Art(          Art<List<A,Hd>, A::Loc>),
}

// TODO: Why Does Adapton have to implement all of these?
//       It's not actually *contained* within the List structure; it cannot be ecountered there.
//       It's only ever present in a negative position (as a function parameter).
impl<A:Adapton+Debug+Hash+PartialEq+Eq+Clone,Hd:Debug+Hash+PartialEq+Eq+Clone> ListT<A,Hd> for List<A,Hd> {
    type List = List<A,Hd>;

    fn nil  (_:&mut A)                             -> Self::List { List::Nil }
    fn cons (_:&mut A, hd:Hd, tl:Self::List)       -> Self::List { List::Cons(hd,Box::new(tl)) }
    fn name (_:&mut A, nm:A::Name, tl:Self::List)  -> Self::List { List::Name(nm, Box::new(tl)) }
    fn rc   (_:&mut A, rc:Rc<List<A,Hd>>)          -> Self::List { List::Rc(rc) }
    fn art  (_:&mut A, art:Art<List<A,Hd>,A::Loc>) -> Self::List { List::Art(art) }

    fn elim<Res,Nil,Cons,Name> (st:&mut A, list:&Self::List, nilf:Nil, consf:Cons, namef:Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Self::List) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Self::List) -> Res
    {
        match *list {
            List::Nil => nilf(st),
            List::Cons(ref hd, ref tl) => consf(st, hd, &*tl),
            List::Name(ref nm, ref tl) => namef(st, nm, &*tl),
            List::Rc(ref rc) => Self::elim(st, &*rc, nilf, consf, namef),
            List::Art(ref art) => {
                let list = st.force(art);
                Self::elim(st, &list, nilf, consf, namef)
            }
        }
    }
}

// https://doc.rust-lang.org/book/macros.html
//
// macro_rules! o_O {
//     (
//         $(
//             $x:expr; [ $( $y:expr ),* ]
//          );*
//     ) => {
//         &[ $($( $x + $y ),*),* ]
//     }
// }
//
// fn main() {
//     let a: &[i32]
//         = o_O!(10; [1, 2, 3];
//                20; [4, 5, 6]);
//
//     assert_eq!(a, [11, 12, 13, 24, 25, 26]);
// }

// TODO: Need to gensym a variable for each argument below:
//
// macro_rules! thunk {
//     ( $f:ident , $st:expr , $( $arg:expr ),* ) => {
//         let fval = Rc::new(Box::new(
//             |st, args|{
//                 let ($( $arg ),*) = args ;
//                 f( st, $( $arg ),* )
//             })) ;
//         ($st).thunk (ArtId::Eager, prog_pt!(f), fval, $( $arg ),* )
//     }}

fn tree_of_list_rec_memo <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32) ->
    (T::Tree, L::List)
{
    let t = st.thunk (ArtId::Eager,
                      prog_pt!(tree_of_list_rec),
                      Rc::new(Box::new(|st, args|{
                          let (list, left_tree, left_tree_lev, parent_lev) = args ;
                          tree_of_list_rec::<A,X,T,L>
                              (st, list, left_tree, left_tree_lev, parent_lev)
                      })),
                      (list, left_tree, left_tree_lev, parent_lev)
                      ) ;
    st.force( &t )
}

fn tree_of_list_rec <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32)
     -> (T::Tree, L::List)
{
    L::elim (
        st, &list,
        /* Nil */  |st| ( T::nil(st), L::nil(st) ),
        /* Cons */ |st, hd, rest| {
            let lev_hd = (1 + (my_hash(hd).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_hd && lev_hd <= parent_lev {
                let nil = T::nil(st) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( st, rest, &nil, 0 as u32, lev_hd ) ;
                let tree = T::bin ( st, hd.clone(), left_tree.clone(), right_tree ) ;
                tree_of_list_rec::<A,X,T,L> ( st, &rest, &tree, lev_hd, parent_lev )
            }
            else {
                let rest = L::cons(st, hd.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }},
        /* Name */ |st, nm, rest| {
            let lev_nm = (1 + 64 + (my_hash(nm).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_nm && lev_nm <= parent_lev {
                let nil = T::nil(st) ;
                let (right_tree, rest) = tree_of_list_rec_memo::<A,X,T,L> ( st, rest, &nil, 0 as u32, lev_nm ) ;
                // TODO: Place left_ and right_ trees into articulations (not Boxes), named by name.
                let tree = T::name( st, nm.clone(), left_tree.clone(), right_tree ) ;
                tree_of_list_rec_memo::<A,X,T,L> ( st, &rest, &tree, lev_nm, parent_lev )
            }
            else {
                let rest = L::name(st, nm.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }}
        )
}

pub fn tree_of_list <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, list:&L::List) -> T::Tree
{
    let nil = T::nil(st) ;
    let (tree, rest) = tree_of_list_rec::<A,X,T,L> (st, list, &nil, 0 as u32, u32::max_value()) ;
    assert!( L::is_empty( st, &rest ) );
    tree
}

pub fn list_merge<A:Adapton,X:Ord+Clone,L:ListT<A,X>>
    (st:&mut A,
     xo:Option<&X>, // for 3-way merge on (xo.unwrap(), hd(l1), hd(l2)).
     n1:Option<&A::Name>, l1:&L::List,
     n2:Option<&A::Name>, l2:&L::List  ) -> L::List
{
    L::elim(st, l1,
            |_| l2.clone(),
            |st,h1,t1|
            L::elim(st, l2,
                    |st| L::nil(st),
                    |st, h2, t2|
                    if match xo {
                        None => false,
                        Some(x) => ( x <= h1 && x <= h2 ) }
                    {
                        let rest = list_merge::<A,X,L>(st, None, n1, l1, n2, l2);
                        L::cons(st, xo.unwrap().clone(), rest)
                    }
                    else if h1 <= h2 {
                        //TODO: Nominal memoization with n1:
                        let rest = list_merge::<A,X,L>(st, xo, None, t1, n2, l2);
                        L::cons(st, (*h1).clone(), rest)
                    }
                    else {
                        //TODO: Nominal memoization with n2:
                        let rest = list_merge::<A,X,L>(st, xo, n1, l1, None, t2);
                        L::cons(st, (*h2).clone(), rest)
                    },
                    |st, m2, t2| list_merge::<A,X,L>(st, xo, n1, l1, Some(m2), t2)
                    ),
            |st,n1,t1| list_merge::<A,X,L>(st, xo, Some(n1), t1, n2, l2)
            )
}

pub fn list_merge_sort<A:Adapton,X:Ord+Hash+Clone,L:ListT<A,X>,T:TreeT<A,X,X>>
    (st:&mut A, list:&L::List) -> L::List
{
    let tree = tree_of_list::<A,X,T,L>(st, list);
    T::fold_up (st, tree,
                |st, x| // Nil:
                L::singleton(st, x.clone()),
                |st, x, left, right| // Bin:
                list_merge::<A,X,L>(st, Some(x), None, &left, None, &right),
                |st, _, left, right| // Name:
                list_merge::<A,X,L>(st, None, None, &left, None, &right)
                )
}
<commit_msg>Tech debt<commit_after>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;
use std::mem::replace;

use adapton_syntax::* ;
use adapton_sigs::* ;

pub trait ListT<A:Adapton,Hd> : Debug+Hash+PartialEq+Eq+Clone {
    type List : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::List ;
    fn cons (&mut A, Hd, Self::List) -> Self::List ;
    fn rc   (&mut A, Rc<Self::List>) -> Self::List ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Self::List) -> Self::List ;
    fn art  (&mut A, Art<Self::List,A::Loc>) -> Self::List ;

    fn elim<Res,Nil,Cons,Name> (&mut A, &Self::List, Nil, Cons, Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Self::List) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Self::List) -> Res ;

    // Derived from `cons` and `nil` above:
    fn singleton (st:&mut A, hd:Hd) -> Self::List {
        let nil = Self::nil(st);
        Self::cons(st, hd, nil)
    }

    // Derived from `elim` above:
    fn is_empty (st:&mut A, list:&Self::List) -> bool {
        Self::elim(st, &list,
                   |_|       true,
                   |_,_,_|   false,
                   |st,_,tl| Self::is_empty(st,tl))
    }
}

pub trait TreeT<A:Adapton,Leaf,Bin:Hash> : Debug+Hash+PartialEq+Eq+Clone {
    type Tree : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::Tree ;
    fn leaf (&mut A, Leaf) -> Self::Tree ;
    fn bin  (&mut A, Bin, Self::Tree, Self::Tree) -> Self::Tree ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Self::Tree, Self::Tree) -> Self::Tree ;
    fn art  (&mut A, Art<Self::Tree,A::Loc>) -> Self::Tree ;

    fn elim<Res,NilC,LeafC,BinC,NameC> (&mut A, &Self::Tree, NilC, LeafC, BinC, NameC) -> Res
        where NilC  : Fn(&mut A) -> Res
        ,     LeafC : Fn(&mut A, &Leaf) -> Res
        ,     BinC  : Fn(&mut A, &Bin,  &Self::Tree, &Self::Tree) -> Res
        ,     NameC : Fn(&mut A, &Name, &Self::Tree, &Self:Tree) -> Res
        ;

    fn fold<Res,LeafC,BinC,NameC> (&mut A, Self::Tree, Res, LeafC, BinC, NameC) -> Res
        where LeafC:Fn(&mut A, Res, &Leaf    ) -> Res
        ,      BinC:Fn(&mut A, Res, &Bin     ) -> Res
        ,     NameC:Fn(&mut A, Res, &A::Name ) -> Res
        ;

    fn fold_up<Res,LeafC,BinC,NameC> (&mut A, Self::Tree, LeafC, BinC, NameC) -> Res
        where LeafC:Fn(&mut A, &Leaf              ) -> Res
        ,      BinC:Fn(&mut A, &Bin,     Res, Res ) -> Res
        ,     NameC:Fn(&mut A, &A::Name, Res, Res ) -> Res
        ;

    // TODO: Add derived operations (max, min, sum, etc.) for fold_up.
}

#[derive(Debug,PartialEq,Eq,Hash,Clone)]
enum List<A:Adapton,Hd> {
    Nil,
    Cons(Hd,      Box<List<A,Hd>>),
    Rc(           Rc<List<A,Hd>>),
    Name(A::Name, Box<List<A,Hd>>),
    Art(          Art<List<A,Hd>, A::Loc>),
}

// TODO: Why Does Adapton have to implement all of these?
//       It's not actually *contained* within the List structure; it cannot be ecountered there.
//       It's only ever present in a negative position (as a function parameter).
impl<A:Adapton+Debug+Hash+PartialEq+Eq+Clone,Hd:Debug+Hash+PartialEq+Eq+Clone> ListT<A,Hd> for List<A,Hd> {
    type List = List<A,Hd>;

    fn nil  (_:&mut A)                             -> Self::List { List::Nil }
    fn cons (_:&mut A, hd:Hd, tl:Self::List)       -> Self::List { List::Cons(hd,Box::new(tl)) }
    fn name (_:&mut A, nm:A::Name, tl:Self::List)  -> Self::List { List::Name(nm, Box::new(tl)) }
    fn rc   (_:&mut A, rc:Rc<List<A,Hd>>)          -> Self::List { List::Rc(rc) }
    fn art  (_:&mut A, art:Art<List<A,Hd>,A::Loc>) -> Self::List { List::Art(art) }

    fn elim<Res,Nil,Cons,Name> (st:&mut A, list:&Self::List, nilf:Nil, consf:Cons, namef:Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Self::List) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Self::List) -> Res
    {
        match *list {
            List::Nil => nilf(st),
            List::Cons(ref hd, ref tl) => consf(st, hd, &*tl),
            List::Name(ref nm, ref tl) => namef(st, nm, &*tl),
            List::Rc(ref rc) => Self::elim(st, &*rc, nilf, consf, namef),
            List::Art(ref art) => {
                let list = st.force(art);
                Self::elim(st, &list, nilf, consf, namef)
            }
        }
    }
}

// https://doc.rust-lang.org/book/macros.html
//
// macro_rules! o_O {
//     (
//         $(
//             $x:expr; [ $( $y:expr ),* ]
//          );*
//     ) => {
//         &[ $($( $x + $y ),*),* ]
//     }
// }
//
// fn main() {
//     let a: &[i32]
//         = o_O!(10; [1, 2, 3];
//                20; [4, 5, 6]);
//
//     assert_eq!(a, [11, 12, 13, 24, 25, 26]);
// }

// TODO: Need to gensym a variable for each argument below:
//
// macro_rules! thunk {
//     ( $f:ident , $st:expr , $( $arg:expr ),* ) => {
//         let fval = Rc::new(Box::new(
//             |st, args|{
//                 let ($( $arg ),*) = args ;
//                 f( st, $( $arg ),* )
//             })) ;
//         ($st).thunk (ArtId::Eager, prog_pt!(f), fval, $( $arg ),* )
//     }}

fn tree_of_list_rec_memo <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32) ->
    (T::Tree, L::List)
{
    let t = st.thunk (ArtId::Eager,
                      prog_pt!(tree_of_list_rec),
                      Rc::new(Box::new(|st, args|{
                          let (list, left_tree, left_tree_lev, parent_lev) = args ;
                          tree_of_list_rec::<A,X,T,L>
                              (st, list, left_tree, left_tree_lev, parent_lev)
                      })),
                      (list, left_tree, left_tree_lev, parent_lev)
                      ) ;
    st.force( &t )
}

fn tree_of_list_rec <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32)
     -> (T::Tree, L::List)
{
    L::elim (
        st, &list,
        /* Nil */  |st| ( T::nil(st), L::nil(st) ),
        /* Cons */ |st, hd, rest| {
            let lev_hd = (1 + (my_hash(hd).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_hd && lev_hd <= parent_lev {
                let nil = T::nil(st) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( st, rest, &nil, 0 as u32, lev_hd ) ;
                let tree = T::bin ( st, hd.clone(), left_tree.clone(), right_tree ) ;
                tree_of_list_rec::<A,X,T,L> ( st, &rest, &tree, lev_hd, parent_lev )
            }
            else {
                let rest = L::cons(st, hd.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }},
        /* Name */ |st, nm, rest| {
            let lev_nm = (1 + 64 + (my_hash(nm).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_nm && lev_nm <= parent_lev {
                let nil = T::nil(st) ;
                let (right_tree, rest) = tree_of_list_rec_memo::<A,X,T,L> ( st, rest, &nil, 0 as u32, lev_nm ) ;
                // TODO: Place left_ and right_ trees into articulations (not Boxes), named by name.
                let tree = T::name( st, nm.clone(), left_tree.clone(), right_tree ) ;
                tree_of_list_rec_memo::<A,X,T,L> ( st, &rest, &tree, lev_nm, parent_lev )
            }
            else {
                let rest = L::name(st, nm.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }}
        )
}

pub fn tree_of_list <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, list:&L::List) -> T::Tree
{
    let nil = T::nil(st) ;
    let (tree, rest) = tree_of_list_rec::<A,X,T,L> (st, list, &nil, 0 as u32, u32::max_value()) ;
    assert!( L::is_empty( st, &rest ) );
    tree
}

pub fn list_merge<A:Adapton,X:Ord+Clone,L:ListT<A,X>>
    (st:&mut A,
     xo:Option<&X>, // for 3-way merge on (xo.unwrap(), hd(l1), hd(l2)).
     n1:Option<&A::Name>, l1:&L::List,
     n2:Option<&A::Name>, l2:&L::List  ) -> L::List
{
    L::elim(st, l1,
            |_| l2.clone(),
            |st,h1,t1|
            L::elim(st, l2,
                    |st| L::nil(st),
                    |st, h2, t2|
                    if match xo {
                        None => false,
                        Some(x) => ( x <= h1 && x <= h2 ) }
                    {
                        let rest = list_merge::<A,X,L>(st, None, n1, l1, n2, l2);
                        L::cons(st, xo.unwrap().clone(), rest)
                    }
                    else if h1 <= h2 {
                        //TODO: Nominal memoization with n1:
                        let rest = list_merge::<A,X,L>(st, xo, None, t1, n2, l2);
                        L::cons(st, (*h1).clone(), rest)
                    }
                    else {
                        //TODO: Nominal memoization with n2:
                        let rest = list_merge::<A,X,L>(st, xo, n1, l1, None, t2);
                        L::cons(st, (*h2).clone(), rest)
                    },
                    |st, m2, t2| list_merge::<A,X,L>(st, xo, n1, l1, Some(m2), t2)
                    ),
            |st,n1,t1| list_merge::<A,X,L>(st, xo, Some(n1), t1, n2, l2)
            )
}

pub fn list_merge_sort<A:Adapton,X:Ord+Hash+Clone,L:ListT<A,X>,T:TreeT<A,X,X>>
    (st:&mut A, list:&L::List) -> L::List
{
    let tree = tree_of_list::<A,X,T,L>(st, list);
    T::fold_up (st, tree,
                |st, x| // Nil:
                L::singleton(st, x.clone()),
                |st, x, left, right| // Bin:
                list_merge::<A,X,L>(st, Some(x), None, &left, None, &right),
                |st, _, left, right| // Name:
                list_merge::<A,X,L>(st, None, None, &left, None, &right)
                )
}
<|endoftext|>


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

//! Bindings for executing child processes

use prelude::*;

use libc;
use rt::io;
use rt::io::io_error;
use rt::local::Local;
use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory};

pub struct Process {
    priv handle: ~RtioProcessObject,
    io: ~[Option<io::PipeStream>],
}

/// This configuration describes how a new process should be spawned. This is
/// translated to libuv's own configuration
pub struct ProcessConfig<'self> {
    /// Path to the program to run
    program: &'self str,

    /// Arguments to pass to the program (doesn't include the program itself)
    args: &'self [~str],

    /// Optional environment to specify for the program. If this is None, then
    /// it will inherit the current process's environment.
    env: Option<&'self [(~str, ~str)]>,

    /// Optional working directory for the new process. If this is None, then
    /// the current directory of the running process is inherited.
    cwd: Option<&'self str>,

    /// Any number of streams/file descriptors/pipes may be attached to this
    /// process. This list enumerates the file descriptors and such for the
    /// process to be spawned, and the file descriptors inherited will start at
    /// 0 and go to the length of this array.
    ///
    /// Standard file descriptors are:
    ///
    ///     0 - stdin
    ///     1 - stdout
    ///     2 - stderr
    io: ~[StdioContainer]
}

/// Describes what to do with a standard io stream for a child process.
pub enum StdioContainer {
    /// This stream will be ignored. This is the equivalent of attaching the
    /// stream to `/dev/null`
    Ignored,

    /// The specified file descriptor is inherited for the stream which it is
    /// specified for.
    InheritFd(libc::c_int),

    // XXX: these two shouldn't have libuv-specific implementation details

    /// The specified libuv stream is inherited for the corresponding file
    /// descriptor it is assigned to.
    // XXX: this needs to be thought out more.
    //InheritStream(uv::net::StreamWatcher),

    /// Creates a pipe for the specified file descriptor which will be directed
    /// into the previously-initialized pipe passed in.
    ///
    /// The first boolean argument is whether the pipe is readable, and the
    /// second is whether it is writable. These properties are from the view of
    /// the *child* process, not the parent process.
    CreatePipe(io::UnboundPipeStream,
               bool /* readable */,
               bool /* writable */),
}

impl Process {
    /// Creates a new pipe initialized, but not bound to any particular
    /// source/destination
    pub fn new(config: ProcessConfig) -> Option<Process> {
        let process = unsafe {
            let io: *mut IoFactoryObject = Local::unsafe_borrow();
            (*io).spawn(config)
        };
        match process {
            Ok((p, io)) => Some(Process{
                handle: p,
                io: io.move_iter().map(|p|
                    p.map_move(|p| io::PipeStream::bind(p))
                ).collect()
            }),
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                None
            }
        }
    }

    /// Returns the process id of this child process
    pub fn id(&self) -> libc::pid_t { self.handle.id() }

    /// Sends the specified signal to the child process, returning whether the
    /// signal could be delivered or not.
    ///
    /// Note that this is purely a wrapper around libuv's `uv_process_kill`
    /// function.
    ///
    /// If the signal delivery fails, then the `io_error` condition is raised on
    pub fn signal(&mut self, signal: int) {
        match self.handle.kill(signal) {
            Ok(()) => {}
            Err(err) => {
                io_error::cond.raise(err)
            }
        }
    }

    /// Wait for the child to exit completely, returning the status that it
    /// exited with. This function will continue to have the same return value
    /// after it has been called at least once.
    pub fn wait(&mut self) -> int { self.handle.wait() }
}

impl Drop for Process {
    fn drop(&mut self) {
        // Close all I/O before exiting to ensure that the child doesn't wait
        // forever to print some text or something similar.
        for _ in range(0, self.io.len()) {
            self.io.pop();
        }

        self.wait();
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use super::*;

    use rt::io::{Reader, Writer};
    use rt::io::pipe::*;
    use str;

    #[test]
    #[cfg(unix, not(android))]
    fn smoke() {
        let io = ~[];
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"true"],
            env: None,
            cwd: None,
            io: io,
        };
        let p = Process::new(args);
        assert!(p.is_some());
        let mut p = p.unwrap();
        assert_eq!(p.wait(), 0);
    }

    #[test]
    #[cfg(unix, not(android))]
    fn smoke_failure() {
        let io = ~[];
        let args = ProcessConfig {
            program: "if-this-is-a-binary-then-the-world-has-ended",
            args: [],
            env: None,
            cwd: None,
            io: io,
        };
        let p = Process::new(args);
        assert!(p.is_some());
        let mut p = p.unwrap();
        assert!(p.wait() != 0);
    }

    #[test]
    #[cfg(unix, not(android))]
    fn exit_reported_right() {
        let io = ~[];
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"exit 1"],
            env: None,
            cwd: None,
            io: io,
        };
        let p = Process::new(args);
        assert!(p.is_some());
        let mut p = p.unwrap();
        assert_eq!(p.wait(), 1);
    }

    fn read_all(input: &mut Reader) -> ~str {
        let mut ret = ~"";
        let mut buf = [0, ..1024];
        loop {
            match input.read(buf) {
                None | Some(0) => { break }
                Some(n) => { ret = ret + str::from_utf8(buf.slice_to(n)); }
            }
        }
        return ret;
    }

    fn run_output(args: ProcessConfig) -> ~str {
        let p = Process::new(args);
        assert!(p.is_some());
        let mut p = p.unwrap();
        assert!(p.io[0].is_none());
        assert!(p.io[1].is_some());
        let ret = read_all(p.io[1].get_mut_ref() as &mut Reader);
        assert_eq!(p.wait(), 0);
        return ret;
    }

    #[test]
    #[cfg(unix, not(android))]
    fn stdout_works() {
        let pipe = PipeStream::new().unwrap();
        let io = ~[Ignored, CreatePipe(pipe, false, true)];
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"echo foobar"],
            env: None,
            cwd: None,
            io: io,
        };
        assert_eq!(run_output(args), ~"foobar\n");
    }

    #[test]
    #[cfg(unix, not(android))]
    fn set_cwd_works() {
        let pipe = PipeStream::new().unwrap();
        let io = ~[Ignored, CreatePipe(pipe, false, true)];
        let cwd = Some("/");
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"pwd"],
            env: None,
            cwd: cwd,
            io: io,
        };
        assert_eq!(run_output(args), ~"/\n");
    }

    #[test]
    #[cfg(unix, not(android))]
    fn stdin_works() {
        let input = PipeStream::new().unwrap();
        let output = PipeStream::new().unwrap();
        let io = ~[CreatePipe(input, true, false),
                   CreatePipe(output, false, true)];
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"read line; echo $line"],
            env: None,
            cwd: None,
            io: io,
        };
        let mut p = Process::new(args).expect("didn't create a proces?!");
        p.io[0].get_mut_ref().write("foobar".as_bytes());
        p.io[0] = None; // close stdin;
        let out = read_all(p.io[1].get_mut_ref() as &mut Reader);
        assert_eq!(p.wait(), 0);
        assert_eq!(out, ~"foobar\n");
    }
}
<commit_msg>Ignore io::process tests<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Bindings for executing child processes

use prelude::*;

use libc;
use rt::io;
use rt::io::io_error;
use rt::local::Local;
use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory};

pub struct Process {
    priv handle: ~RtioProcessObject,
    io: ~[Option<io::PipeStream>],
}

/// This configuration describes how a new process should be spawned. This is
/// translated to libuv's own configuration
pub struct ProcessConfig<'self> {
    /// Path to the program to run
    program: &'self str,

    /// Arguments to pass to the program (doesn't include the program itself)
    args: &'self [~str],

    /// Optional environment to specify for the program. If this is None, then
    /// it will inherit the current process's environment.
    env: Option<&'self [(~str, ~str)]>,

    /// Optional working directory for the new process. If this is None, then
    /// the current directory of the running process is inherited.
    cwd: Option<&'self str>,

    /// Any number of streams/file descriptors/pipes may be attached to this
    /// process. This list enumerates the file descriptors and such for the
    /// process to be spawned, and the file descriptors inherited will start at
    /// 0 and go to the length of this array.
    ///
    /// Standard file descriptors are:
    ///
    ///     0 - stdin
    ///     1 - stdout
    ///     2 - stderr
    io: ~[StdioContainer]
}

/// Describes what to do with a standard io stream for a child process.
pub enum StdioContainer {
    /// This stream will be ignored. This is the equivalent of attaching the
    /// stream to `/dev/null`
    Ignored,

    /// The specified file descriptor is inherited for the stream which it is
    /// specified for.
    InheritFd(libc::c_int),

    // XXX: these two shouldn't have libuv-specific implementation details

    /// The specified libuv stream is inherited for the corresponding file
    /// descriptor it is assigned to.
    // XXX: this needs to be thought out more.
    //InheritStream(uv::net::StreamWatcher),

    /// Creates a pipe for the specified file descriptor which will be directed
    /// into the previously-initialized pipe passed in.
    ///
    /// The first boolean argument is whether the pipe is readable, and the
    /// second is whether it is writable. These properties are from the view of
    /// the *child* process, not the parent process.
    CreatePipe(io::UnboundPipeStream,
               bool /* readable */,
               bool /* writable */),
}

impl Process {
    /// Creates a new pipe initialized, but not bound to any particular
    /// source/destination
    pub fn new(config: ProcessConfig) -> Option<Process> {
        let process = unsafe {
            let io: *mut IoFactoryObject = Local::unsafe_borrow();
            (*io).spawn(config)
        };
        match process {
            Ok((p, io)) => Some(Process{
                handle: p,
                io: io.move_iter().map(|p|
                    p.map_move(|p| io::PipeStream::bind(p))
                ).collect()
            }),
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                None
            }
        }
    }

    /// Returns the process id of this child process
    pub fn id(&self) -> libc::pid_t { self.handle.id() }

    /// Sends the specified signal to the child process, returning whether the
    /// signal could be delivered or not.
    ///
    /// Note that this is purely a wrapper around libuv's `uv_process_kill`
    /// function.
    ///
    /// If the signal delivery fails, then the `io_error` condition is raised on
    pub fn signal(&mut self, signal: int) {
        match self.handle.kill(signal) {
            Ok(()) => {}
            Err(err) => {
                io_error::cond.raise(err)
            }
        }
    }

    /// Wait for the child to exit completely, returning the status that it
    /// exited with. This function will continue to have the same return value
    /// after it has been called at least once.
    pub fn wait(&mut self) -> int { self.handle.wait() }
}

impl Drop for Process {
    fn drop(&mut self) {
        // Close all I/O before exiting to ensure that the child doesn't wait
        // forever to print some text or something similar.
        for _ in range(0, self.io.len()) {
            self.io.pop();
        }

        self.wait();
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use super::*;

    use rt::io::{Reader, Writer};
    use rt::io::pipe::*;
    use str;

    #[test]
    #[cfg(unix, not(android))]
    #[ignore] // FIXME(#9341)
    fn smoke() {
        let io = ~[];
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"true"],
            env: None,
            cwd: None,
            io: io,
        };
        let p = Process::new(args);
        assert!(p.is_some());
        let mut p = p.unwrap();
        assert_eq!(p.wait(), 0);
    }

    #[test]
    #[cfg(unix, not(android))]
    #[ignore] // FIXME(#9341)
    fn smoke_failure() {
        let io = ~[];
        let args = ProcessConfig {
            program: "if-this-is-a-binary-then-the-world-has-ended",
            args: [],
            env: None,
            cwd: None,
            io: io,
        };
        let p = Process::new(args);
        assert!(p.is_some());
        let mut p = p.unwrap();
        assert!(p.wait() != 0);
    }

    #[test]
    #[cfg(unix, not(android))]
    #[ignore] // FIXME(#9341)
    fn exit_reported_right() {
        let io = ~[];
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"exit 1"],
            env: None,
            cwd: None,
            io: io,
        };
        let p = Process::new(args);
        assert!(p.is_some());
        let mut p = p.unwrap();
        assert_eq!(p.wait(), 1);
    }

    fn read_all(input: &mut Reader) -> ~str {
        let mut ret = ~"";
        let mut buf = [0, ..1024];
        loop {
            match input.read(buf) {
                None | Some(0) => { break }
                Some(n) => { ret = ret + str::from_utf8(buf.slice_to(n)); }
            }
        }
        return ret;
    }

    fn run_output(args: ProcessConfig) -> ~str {
        let p = Process::new(args);
        assert!(p.is_some());
        let mut p = p.unwrap();
        assert!(p.io[0].is_none());
        assert!(p.io[1].is_some());
        let ret = read_all(p.io[1].get_mut_ref() as &mut Reader);
        assert_eq!(p.wait(), 0);
        return ret;
    }

    #[test]
    #[cfg(unix, not(android))]
    #[ignore] // FIXME(#9341)
    fn stdout_works() {
        let pipe = PipeStream::new().unwrap();
        let io = ~[Ignored, CreatePipe(pipe, false, true)];
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"echo foobar"],
            env: None,
            cwd: None,
            io: io,
        };
        assert_eq!(run_output(args), ~"foobar\n");
    }

    #[test]
    #[cfg(unix, not(android))]
    #[ignore] // FIXME(#9341)
    fn set_cwd_works() {
        let pipe = PipeStream::new().unwrap();
        let io = ~[Ignored, CreatePipe(pipe, false, true)];
        let cwd = Some("/");
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"pwd"],
            env: None,
            cwd: cwd,
            io: io,
        };
        assert_eq!(run_output(args), ~"/\n");
    }

    #[test]
    #[cfg(unix, not(android))]
    #[ignore] // FIXME(#9341)
    fn stdin_works() {
        let input = PipeStream::new().unwrap();
        let output = PipeStream::new().unwrap();
        let io = ~[CreatePipe(input, true, false),
                   CreatePipe(output, false, true)];
        let args = ProcessConfig {
            program: "/bin/sh",
            args: [~"-c", ~"read line; echo $line"],
            env: None,
            cwd: None,
            io: io,
        };
        let mut p = Process::new(args).expect("didn't create a proces?!");
        p.io[0].get_mut_ref().write("foobar".as_bytes());
        p.io[0] = None; // close stdin;
        let out = read_all(p.io[1].get_mut_ref() as &mut Reader);
        assert_eq!(p.wait(), 0);
        assert_eq!(out, ~"foobar\n");
    }
}
<|endoftext|>


<commit_before>use crate::mem;
use crate::slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
                                             mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    return v
}

#[cfg(all(unix,
          not(target_os = "ios"),
          not(target_os = "openbsd"),
          not(target_os = "freebsd"),
          not(target_os = "fuchsia")))]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        use crate::sync::atomic::{AtomicBool, Ordering};
        use crate::sys::os::errno;

        static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
        if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
            return false;
        }

        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::ENOSYS {
                    GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
                    return false;
                } else if err == libc::EAGAIN {
                    return false;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
        true
    }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy. The
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around. The PRNG of /dev/urandom will still be used but over a
        // possibly predictable entropy pool.
        if getrandom_fill_bytes(v) {
            return;
        }

        // getrandom failed because it is permanently or temporarily (because
        // of missing entropy) unavailable. Open /dev/urandom, read from it,
        // and close it again.
        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom")
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use crate::sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe {
                libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
            };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    use crate::io;
    use crate::ptr;
    use libc::{c_int, size_t};

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t,
                              bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe {
            SecRandomCopyBytes(kSecRandomDefault,
                               v.len(),
                               v.as_mut_ptr())
        };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}",
                   io::Error::last_os_error());
        }
    }
}

#[cfg(target_os = "freebsd")]
mod imp {
    use crate::ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
                             s.as_mut_ptr() as *mut _, &mut s_len,
                             ptr::null(), 0)
            };
            if ret == -1 || s_len != s.len() {
                panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                       ret, s.len(), s_len);
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern {
        fn zx_cprng_draw(buffer: *mut u8, len: usize);
    }

    pub fn fill_bytes(v: &mut [u8]) {
        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
    }
}
<commit_msg>Auto merge of #59879 - ebarnard:patch-1, r=alexcrichton<commit_after>use crate::mem;
use crate::slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
                                             mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    return v
}

#[cfg(all(unix,
          not(target_os = "ios"),
          not(target_os = "openbsd"),
          not(target_os = "freebsd"),
          not(target_os = "fuchsia")))]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        use crate::sync::atomic::{AtomicBool, Ordering};
        use crate::sys::os::errno;

        static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
        if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
            return false;
        }

        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::ENOSYS {
                    GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
                    return false;
                } else if err == libc::EAGAIN {
                    return false;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
        true
    }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy. The
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around. The PRNG of /dev/urandom will still be used but over a
        // possibly predictable entropy pool.
        if getrandom_fill_bytes(v) {
            return;
        }

        // getrandom failed because it is permanently or temporarily (because
        // of missing entropy) unavailable. Open /dev/urandom, read from it,
        // and close it again.
        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom")
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use crate::sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe {
                libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
            };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
// from `/dev/random` and which runs on its own thread accessed via GCD.
// This seems needlessly heavyweight for the purposes of generating two u64s
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
#[cfg(target_os = "ios")]
mod imp {
    use crate::io;
    use crate::ptr;
    use libc::{c_int, size_t};

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t,
                              bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe {
            SecRandomCopyBytes(kSecRandomDefault,
                               v.len(),
                               v.as_mut_ptr())
        };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}",
                   io::Error::last_os_error());
        }
    }
}

#[cfg(target_os = "freebsd")]
mod imp {
    use crate::ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
                             s.as_mut_ptr() as *mut _, &mut s_len,
                             ptr::null(), 0)
            };
            if ret == -1 || s_len != s.len() {
                panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                       ret, s.len(), s_len);
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern {
        fn zx_cprng_draw(buffer: *mut u8, len: usize);
    }

    pub fn fill_bytes(v: &mut [u8]) {
        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
    }
}
<|endoftext|>