<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rust::{ParserAttr, respan};
use rust::Token as rtok;
use rust::BinOpToken as rbtok;
use rust;
use std::str::Chars;
use std::iter::Peekable;

use front::ast::*;
use front::ast::Expression_::*;

pub struct Parser<'a>
{
  rp: rust::Parser<'a>,
  inner_attrs: Vec<rust::Attribute>,
  grammar_name: rust::Ident
}

impl<'a> Parser<'a>
{
  pub fn new(sess: &'a rust::ParseSess,
         cfg: rust::CrateConfig,
         tts: Vec<rust::TokenTree>,
         grammar_name: rust::Ident) -> Parser<'a>
  {
    Parser{
      rp: rust::new_parser_from_tts(sess, cfg, tts),
      inner_attrs: Vec::new(),
      grammar_name: grammar_name
    }
  }

  pub fn parse_grammar(&mut self) -> Grammar {
    let (rules, rust_items) = self.parse_blocks();
    Grammar{name: self.grammar_name, rules: rules, rust_items: rust_items, attributes: self.inner_attrs.to_vec()}
  }

  fn bump(&mut self) {
    self.rp.bump().unwrap()
  }

  fn parse_blocks(&mut self) -> (Vec<Rule>, Vec<RItem>) {
    let mut rules = vec![];
    let mut rust_items = vec![];
    while self.rp.token != rtok::Eof
    {
      // FIXME: #45
      if self.rp.token == rust::token::Pound {
        rules.push(self.parse_rule())
      }
      else {
        self.rp.parse_item().map_or_else(
          || rules.push(self.parse_rule()),
          |item| rust_items.push(item))
      }
    }
    (rules, rust_items)
  }

  fn parse_rule(&mut self) -> Rule {
    let outer_attrs = self.parse_attributes();
    let name = self.parse_rule_decl();
    self.rp.expect(&rtok::Eq).unwrap();
    let body = self.parse_rule_rhs(id_to_string(name.node).as_str());
    Rule{name: name, attributes: outer_attrs, def: body}
  }

  // Outer attributes are attached to the next item.
  // Inner attributes are attached to the englobing item.
  fn parse_attributes(&mut self) -> Vec<rust::Attribute> {
    let inners = self.rp.parse_inner_attributes();
    self.inner_attrs.push_all(inners.as_slice());
    self.rp.parse_outer_attributes()
  }

  fn parse_rule_decl(&mut self) -> rust::SpannedIdent {
    let sp = self.rp.span;
    respan(sp, self.rp.parse_ident().unwrap())
  }

  fn parse_rule_rhs(&mut self, rule_name: &str) -> Box<Expression> {
    self.parse_rule_choice(rule_name)
  }

  fn parse_rule_choice(&mut self, rule_name: &str) -> Box<Expression> {
    let lo = self.rp.span.lo;
    let mut choices = Vec::new();
    loop{
      let seq = self.parse_rule_seq(rule_name);
      choices.push(self.parse_semantic_action_or_ty(seq, rule_name));
      let token = self.rp.token.clone();
      match token {
        rtok::BinOp(rbtok::Slash) => self.bump(),
        _ => break
      }
    }
    let hi = self.rp.last_span.hi;
    if choices.len() == 1 {
      choices.pop().unwrap()
    } else {
      spanned_expr(lo, hi, Choice(choices))
    }
  }

  fn parse_semantic_action_or_ty(&mut self, expr: Box<Expression>, rule_name: &str) -> Box<Expression> {
    let token = self.rp.token.clone();
    match token {
      rtok::Gt => {
        self.bump();
        let fun_name = self.rp.parse_ident().unwrap();
        self.last_respan(SemanticAction(expr, fun_name))
      },
      rtok::RArrow => {
        self.bump();
        self.parse_type(expr, rule_name)
      }
      _ => expr
    }
  }

  // `()` or `(^)`
  fn parse_type(&mut self, mut expr: Box<Expression>, rule_name: &str) -> Box<Expression> {
    let token = self.rp.token.clone();
    match token {
      rtok::OpenDelim(rust::DelimToken::Paren) => {
        self.bump();
        let token = self.rp.token.clone();
        let mut ty = TypeAnnotation::Unit;
        if token == rtok::BinOp(rbtok::Caret) {
          self.bump();
          ty = TypeAnnotation::Invisible;
        }
        self.rp.expect(&rtok::CloseDelim(rust::DelimToken::Paren)).unwrap();
        expr.ty = Some(ty);
        expr
      }
      _ => {
        let span = self.rp.span;
        self.rp.span_err(
          span,
          format!("In rule {}: Unknown token after `->`. Use the arrow to annotate an expression with the unit type `()` or the invisible type `(^)`.",
            rule_name).as_str()
        );
        expr
      }
    }
  }

  fn parse_rule_seq(&mut self, rule_name: &str) -> Box<Expression> {
    let lo = self.rp.span.lo;
    let mut seq = Vec::new();
    while let Some(expr) = self.parse_rule_prefixed(rule_name) {
      seq.push(expr);
    }
    let hi = self.rp.last_span.hi;
    if seq.len() == 0 {
      self.rp.span_err(
        mk_sp(lo, hi),
        format!("In rule {}: must defined at least one expression.",
          rule_name).as_str());
    }
    spanned_expr(lo, hi, Sequence(seq))
  }

  fn parse_rule_prefixed(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    match token {
      rtok::Not => {
        self.parse_prefix(rule_name, |e| NotPredicate(e))
      }
      rtok::BinOp(rbtok::And) => {
        self.parse_prefix(rule_name, |e| AndPredicate(e))
      }
      _ => self.parse_rule_suffixed(rule_name)
    }
  }

  fn parse_prefix<F>(&mut self, rule_name: &str, make_prefix: F) -> Option<Box<Expression>>
   where F: Fn(Box<Expression>) -> ExpressionNode
  {
    let lo = self.rp.span.lo;
    self.bump();
    let expr = match self.parse_rule_suffixed(rule_name) {
      Some(expr) => expr,
      None => {
        let span = self.rp.span;
        self.rp.span_err(
          span,
          format!("In rule {}: A not predicate (`!expr`) is not followed by a \
            valid expression. Do not forget it must be in front of the expression.",
            rule_name).as_str()
        );
        return None
      }
    };
    let hi = self.rp.span.hi;
    Some(spanned_expr(lo, hi, make_prefix(expr)))
  }

  fn parse_rule_suffixed(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let lo = self.rp.span.lo;
    let expr = match self.parse_rule_atom(rule_name){
      Some(expr) => expr,
      None => return None
    };
    let hi = self.rp.span.hi;
    let token = self.rp.token.clone();
    match token {
      rtok::BinOp(rbtok::Star) => {
        self.bump();
        Some(spanned_expr(lo, hi, ZeroOrMore(expr)))
      },
      rtok::BinOp(rbtok::Plus) => {
        self.bump();
        Some(spanned_expr(lo, hi, OneOrMore(expr)))
      },
      rtok::Question => {
        self.bump();
        Some(spanned_expr(lo, hi, Optional(expr)))
      },
      _ => Some(expr)
    }
  }

  fn last_respan(&self, expr: ExpressionNode) -> Box<Expression> {
    respan_expr(self.rp.last_span, expr)
  }

  fn parse_rule_atom(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    if token.is_any_keyword() {
      return None
    }
    match token {
      rtok::Literal(rust::token::Lit::Str_(name),_) => {
        self.bump();
        Some(self.last_respan(StrLiteral(name_to_string(name))))
      },
      rtok::Dot => {
        self.bump();
        Some(self.last_respan(AnySingleChar))
      },
      rtok::OpenDelim(rust::DelimToken::Paren) => {
        self.bump();
        let res = self.parse_rule_rhs(rule_name);
        self.rp.expect(&rtok::CloseDelim(rust::DelimToken::Paren)).unwrap();
        Some(res)
      },
      rtok::Ident(id, _) => {
        if self.is_rule_lhs() { None }
        else {
          self.bump();
          Some(self.last_respan(NonTerminalSymbol(id)))
        }
      },
      rtok::OpenDelim(rust::DelimToken::Bracket) => {
        self.bump();
        let res = self.parse_char_class(rule_name);
        match self.rp.token {
          rtok::CloseDelim(rust::DelimToken::Bracket) => {
            self.bump();
            res
          },
          _ => {
            let span = self.rp.span;
            panic!(self.rp.span_fatal(
              span,
              format!("In rule {}: A character class must always be terminated by `]` \
                and can only contain a string literal (such as in `[\"a-z\"]`",
                rule_name).as_str()
            ));
          }
        }
      },
      _ => { None }
    }
  }

  fn parse_char_class(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    match token {
      rtok::Literal(rust::token::Lit::Str_(name),_) => {
        self.bump();
        let cooked_lit = rust::str_lit(name_to_string(name).as_str());
        self.parse_set_of_char_range(&cooked_lit, rule_name)
      },
      _ => {
        let span = self.rp.span;
        panic!(self.rp.span_fatal(
          span,
          format!("In rule {}: An expected character occurred in this character class. \
            `[` must only be followed by a string literal (such as in `[\"a-z\"]`",
            rule_name).as_str()
        ));
      }
    }
  }

  fn parse_set_of_char_range(&mut self, ranges: &String, rule_name: &str) -> Option<Box<Expression>> {
    let mut ranges = ranges.chars().peekable();
    let mut intervals = vec![];
    match ranges.peek() {
      Some(&sep) if sep == '-' => {
        intervals.push(CharacterInterval{lo: '-', hi: '-'});
        ranges.next();
      }
      _ => ()
    }
    loop {
      match self.parse_char_range(&mut ranges, rule_name) {
        Some(char_set) => intervals.push_all(char_set.as_slice()),
        None => break
      }
    }
    Some(respan_expr(self.rp.span, CharacterClass(CharacterClassExpr{intervals: intervals})))
  }

  fn parse_char_range<'b>(&mut self, ranges: &mut Peekable<Chars<'b>>, rule_name: &str) -> Option<Vec<CharacterInterval>> {
    let mut res = vec![];
    let separator_err = format!(
      "In rule {}: Unexpected separator `-`. Put it in the start or the end if you want \
      to accept it as a character in the set. Otherwise, you should only use it for \
      character intervals as in `[\"a-z\"]`.",
      rule_name);
    let span = self.rp.span;
    let lo = ranges.next();
    // Twisted logic due to the fact that `peek` borrows the ranges...
    let lo = {
      let next = ranges.peek();
      match (lo, next) {
        (Some('-'), Some(_)) => {
          self.rp.span_err(span, separator_err.as_str());
          return None
        },
        (Some(lo), Some(&sep)) if sep == '-' => {
          lo
        },
        (Some(lo), _) => {
          res.push(CharacterInterval{lo: lo, hi: lo}); // If lo == '-', it ends the class, allowed.
          return Some(res)
        }
        (None, _) => return None
      }
    };
    ranges.next();
    match ranges.next() {
      Some('-') => { self.rp.span_err(span, separator_err.as_str()); None }
      Some(hi) => {
        res.push(CharacterInterval{lo: lo, hi: hi});
        Some(res)
      }
      None => {
        res.push(CharacterInterval{lo:lo, hi:lo});
        res.push(CharacterInterval{lo:'-', hi: '-'});
        Some(res)
      }
    }
  }

  fn is_rule_lhs(&mut self) -> bool {
    self.rp.look_ahead(1, |t| match t { &rtok::Eq => true, _ => false})
  }
}
<commit_msg>[Front-end][Bug] No more attributes are expected on rules so the bug #45 is fixed for now. It closes #45.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rust::{ParserAttr, respan};
use rust::Token as rtok;
use rust::BinOpToken as rbtok;
use rust;
use std::str::Chars;
use std::iter::Peekable;

use front::ast::*;
use front::ast::Expression_::*;

pub struct Parser<'a>
{
  rp: rust::Parser<'a>,
  inner_attrs: Vec<rust::Attribute>,
  grammar_name: rust::Ident
}

impl<'a> Parser<'a>
{
  pub fn new(sess: &'a rust::ParseSess,
         cfg: rust::CrateConfig,
         tts: Vec<rust::TokenTree>,
         grammar_name: rust::Ident) -> Parser<'a>
  {
    Parser{
      rp: rust::new_parser_from_tts(sess, cfg, tts),
      inner_attrs: Vec::new(),
      grammar_name: grammar_name
    }
  }

  pub fn parse_grammar(&mut self) -> Grammar {
    let (rules, rust_items) = self.parse_blocks();
    Grammar{name: self.grammar_name, rules: rules, rust_items: rust_items, attributes: self.inner_attrs.to_vec()}
  }

  fn bump(&mut self) {
    self.rp.bump().unwrap()
  }

  fn parse_blocks(&mut self) -> (Vec<Rule>, Vec<RItem>) {
    let mut rules = vec![];
    let mut rust_items = vec![];
    while self.rp.token != rtok::Eof
    {
      self.rp.parse_item().map_or_else(
        || rules.push(self.parse_rule()),
        |item| rust_items.push(item))
    }
    (rules, rust_items)
  }

  fn parse_rule(&mut self) -> Rule {
    let outer_attrs = self.parse_attributes();
    let name = self.parse_rule_decl();
    self.rp.expect(&rtok::Eq).unwrap();
    let body = self.parse_rule_rhs(id_to_string(name.node).as_str());
    Rule{name: name, attributes: outer_attrs, def: body}
  }

  // Outer attributes are attached to the next item.
  // Inner attributes are attached to the englobing item.
  fn parse_attributes(&mut self) -> Vec<rust::Attribute> {
    let inners = self.rp.parse_inner_attributes();
    self.inner_attrs.push_all(inners.as_slice());
    self.rp.parse_outer_attributes()
  }

  fn parse_rule_decl(&mut self) -> rust::SpannedIdent {
    let sp = self.rp.span;
    respan(sp, self.rp.parse_ident().unwrap())
  }

  fn parse_rule_rhs(&mut self, rule_name: &str) -> Box<Expression> {
    self.parse_rule_choice(rule_name)
  }

  fn parse_rule_choice(&mut self, rule_name: &str) -> Box<Expression> {
    let lo = self.rp.span.lo;
    let mut choices = Vec::new();
    loop{
      let seq = self.parse_rule_seq(rule_name);
      choices.push(self.parse_semantic_action_or_ty(seq, rule_name));
      let token = self.rp.token.clone();
      match token {
        rtok::BinOp(rbtok::Slash) => self.bump(),
        _ => break
      }
    }
    let hi = self.rp.last_span.hi;
    if choices.len() == 1 {
      choices.pop().unwrap()
    } else {
      spanned_expr(lo, hi, Choice(choices))
    }
  }

  fn parse_semantic_action_or_ty(&mut self, expr: Box<Expression>, rule_name: &str) -> Box<Expression> {
    let token = self.rp.token.clone();
    match token {
      rtok::Gt => {
        self.bump();
        let fun_name = self.rp.parse_ident().unwrap();
        self.last_respan(SemanticAction(expr, fun_name))
      },
      rtok::RArrow => {
        self.bump();
        self.parse_type(expr, rule_name)
      }
      _ => expr
    }
  }

  // `()` or `(^)`
  fn parse_type(&mut self, mut expr: Box<Expression>, rule_name: &str) -> Box<Expression> {
    let token = self.rp.token.clone();
    match token {
      rtok::OpenDelim(rust::DelimToken::Paren) => {
        self.bump();
        let token = self.rp.token.clone();
        let mut ty = TypeAnnotation::Unit;
        if token == rtok::BinOp(rbtok::Caret) {
          self.bump();
          ty = TypeAnnotation::Invisible;
        }
        self.rp.expect(&rtok::CloseDelim(rust::DelimToken::Paren)).unwrap();
        expr.ty = Some(ty);
        expr
      }
      _ => {
        let span = self.rp.span;
        self.rp.span_err(
          span,
          format!("In rule {}: Unknown token after `->`. Use the arrow to annotate an expression with the unit type `()` or the invisible type `(^)`.",
            rule_name).as_str()
        );
        expr
      }
    }
  }

  fn parse_rule_seq(&mut self, rule_name: &str) -> Box<Expression> {
    let lo = self.rp.span.lo;
    let mut seq = Vec::new();
    while let Some(expr) = self.parse_rule_prefixed(rule_name) {
      seq.push(expr);
    }
    let hi = self.rp.last_span.hi;
    if seq.len() == 0 {
      self.rp.span_err(
        mk_sp(lo, hi),
        format!("In rule {}: must defined at least one expression.",
          rule_name).as_str());
    }
    spanned_expr(lo, hi, Sequence(seq))
  }

  fn parse_rule_prefixed(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    match token {
      rtok::Not => {
        self.parse_prefix(rule_name, |e| NotPredicate(e))
      }
      rtok::BinOp(rbtok::And) => {
        self.parse_prefix(rule_name, |e| AndPredicate(e))
      }
      _ => self.parse_rule_suffixed(rule_name)
    }
  }

  fn parse_prefix<F>(&mut self, rule_name: &str, make_prefix: F) -> Option<Box<Expression>>
   where F: Fn(Box<Expression>) -> ExpressionNode
  {
    let lo = self.rp.span.lo;
    self.bump();
    let expr = match self.parse_rule_suffixed(rule_name) {
      Some(expr) => expr,
      None => {
        let span = self.rp.span;
        self.rp.span_err(
          span,
          format!("In rule {}: A not predicate (`!expr`) is not followed by a \
            valid expression. Do not forget it must be in front of the expression.",
            rule_name).as_str()
        );
        return None
      }
    };
    let hi = self.rp.span.hi;
    Some(spanned_expr(lo, hi, make_prefix(expr)))
  }

  fn parse_rule_suffixed(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let lo = self.rp.span.lo;
    let expr = match self.parse_rule_atom(rule_name){
      Some(expr) => expr,
      None => return None
    };
    let hi = self.rp.span.hi;
    let token = self.rp.token.clone();
    match token {
      rtok::BinOp(rbtok::Star) => {
        self.bump();
        Some(spanned_expr(lo, hi, ZeroOrMore(expr)))
      },
      rtok::BinOp(rbtok::Plus) => {
        self.bump();
        Some(spanned_expr(lo, hi, OneOrMore(expr)))
      },
      rtok::Question => {
        self.bump();
        Some(spanned_expr(lo, hi, Optional(expr)))
      },
      _ => Some(expr)
    }
  }

  fn last_respan(&self, expr: ExpressionNode) -> Box<Expression> {
    respan_expr(self.rp.last_span, expr)
  }

  fn parse_rule_atom(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    if token.is_any_keyword() {
      return None
    }
    match token {
      rtok::Literal(rust::token::Lit::Str_(name),_) => {
        self.bump();
        Some(self.last_respan(StrLiteral(name_to_string(name))))
      },
      rtok::Dot => {
        self.bump();
        Some(self.last_respan(AnySingleChar))
      },
      rtok::OpenDelim(rust::DelimToken::Paren) => {
        self.bump();
        let res = self.parse_rule_rhs(rule_name);
        self.rp.expect(&rtok::CloseDelim(rust::DelimToken::Paren)).unwrap();
        Some(res)
      },
      rtok::Ident(id, _) => {
        if self.is_rule_lhs() { None }
        else {
          self.bump();
          Some(self.last_respan(NonTerminalSymbol(id)))
        }
      },
      rtok::OpenDelim(rust::DelimToken::Bracket) => {
        self.bump();
        let res = self.parse_char_class(rule_name);
        match self.rp.token {
          rtok::CloseDelim(rust::DelimToken::Bracket) => {
            self.bump();
            res
          },
          _ => {
            let span = self.rp.span;
            panic!(self.rp.span_fatal(
              span,
              format!("In rule {}: A character class must always be terminated by `]` \
                and can only contain a string literal (such as in `[\"a-z\"]`",
                rule_name).as_str()
            ));
          }
        }
      },
      _ => { None }
    }
  }

  fn parse_char_class(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    match token {
      rtok::Literal(rust::token::Lit::Str_(name),_) => {
        self.bump();
        let cooked_lit = rust::str_lit(name_to_string(name).as_str());
        self.parse_set_of_char_range(&cooked_lit, rule_name)
      },
      _ => {
        let span = self.rp.span;
        panic!(self.rp.span_fatal(
          span,
          format!("In rule {}: An expected character occurred in this character class. \
            `[` must only be followed by a string literal (such as in `[\"a-z\"]`",
            rule_name).as_str()
        ));
      }
    }
  }

  fn parse_set_of_char_range(&mut self, ranges: &String, rule_name: &str) -> Option<Box<Expression>> {
    let mut ranges = ranges.chars().peekable();
    let mut intervals = vec![];
    match ranges.peek() {
      Some(&sep) if sep == '-' => {
        intervals.push(CharacterInterval{lo: '-', hi: '-'});
        ranges.next();
      }
      _ => ()
    }
    loop {
      match self.parse_char_range(&mut ranges, rule_name) {
        Some(char_set) => intervals.push_all(char_set.as_slice()),
        None => break
      }
    }
    Some(respan_expr(self.rp.span, CharacterClass(CharacterClassExpr{intervals: intervals})))
  }

  fn parse_char_range<'b>(&mut self, ranges: &mut Peekable<Chars<'b>>, rule_name: &str) -> Option<Vec<CharacterInterval>> {
    let mut res = vec![];
    let separator_err = format!(
      "In rule {}: Unexpected separator `-`. Put it in the start or the end if you want \
      to accept it as a character in the set. Otherwise, you should only use it for \
      character intervals as in `[\"a-z\"]`.",
      rule_name);
    let span = self.rp.span;
    let lo = ranges.next();
    // Twisted logic due to the fact that `peek` borrows the ranges...
    let lo = {
      let next = ranges.peek();
      match (lo, next) {
        (Some('-'), Some(_)) => {
          self.rp.span_err(span, separator_err.as_str());
          return None
        },
        (Some(lo), Some(&sep)) if sep == '-' => {
          lo
        },
        (Some(lo), _) => {
          res.push(CharacterInterval{lo: lo, hi: lo}); // If lo == '-', it ends the class, allowed.
          return Some(res)
        }
        (None, _) => return None
      }
    };
    ranges.next();
    match ranges.next() {
      Some('-') => { self.rp.span_err(span, separator_err.as_str()); None }
      Some(hi) => {
        res.push(CharacterInterval{lo: lo, hi: hi});
        Some(res)
      }
      None => {
        res.push(CharacterInterval{lo:lo, hi:lo});
        res.push(CharacterInterval{lo:'-', hi: '-'});
        Some(res)
      }
    }
  }

  fn is_rule_lhs(&mut self) -> bool {
    self.rp.look_ahead(1, |t| match t { &rtok::Eq => true, _ => false})
  }
}
<|endoftext|>


<commit_before>//! Some stuff used by rustc that doesn't have many dependencies
//!
//! Originally extracted from rustc::back, which was nominally the
//! compiler 'backend', though LLVM is rustc's backend, so rustc_target
//! is really just odds-and-ends relating to code gen and linking.
//! This crate mostly exists to make rustc smaller, so we might put
//! more 'stuff' here in the future. It does not have a dependency on
//! LLVM.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(box_syntax)]
#![feature(bool_to_option)]
#![feature(nll)]

#[macro_use]
extern crate log;

pub mod abi;
pub mod spec;

/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in librustc.
pub trait HashStableContext {}
<commit_msg>Remove unused feature gate from librustc_target<commit_after>//! Some stuff used by rustc that doesn't have many dependencies
//!
//! Originally extracted from rustc::back, which was nominally the
//! compiler 'backend', though LLVM is rustc's backend, so rustc_target
//! is really just odds-and-ends relating to code gen and linking.
//! This crate mostly exists to make rustc smaller, so we might put
//! more 'stuff' here in the future. It does not have a dependency on
//! LLVM.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(bool_to_option)]
#![feature(nll)]

#[macro_use]
extern crate log;

pub mod abi;
pub mod spec;

/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in librustc.
pub trait HashStableContext {}
<|endoftext|>


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

use sync::{Mutex, Condvar};

/// A barrier enables multiple threads to synchronize the beginning
/// of some computation.
///
/// ```
/// use std::sync::{Arc, Barrier};
/// use std::thread;
///
/// let barrier = Arc::new(Barrier::new(10));
/// for _ in 0..10 {
///     let c = barrier.clone();
///     // The same messages will be printed together.
///     // You will NOT see any interleaving.
///     thread::spawn(move|| {
///         println!("before wait");
///         c.wait();
///         println!("after wait");
///     });
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Barrier {
    lock: Mutex<BarrierState>,
    cvar: Condvar,
    num_threads: usize,
}

// The inner state of a double barrier
struct BarrierState {
    count: usize,
    generation_id: usize,
}

/// A result returned from wait.
///
/// Currently this opaque structure only has one method, `.is_leader()`. Only
/// one thread will receive a result that will return `true` from this function.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BarrierWaitResult(bool);

impl Barrier {
    /// Creates a new barrier that can block a given number of threads.
    ///
    /// A barrier will block `n`-1 threads which call `wait` and then wake up
    /// all threads at once when the `n`th thread calls `wait`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new(n: usize) -> Barrier {
        Barrier {
            lock: Mutex::new(BarrierState {
                count: 0,
                generation_id: 0,
            }),
            cvar: Condvar::new(),
            num_threads: n,
        }
    }

    /// Blocks the current thread until all threads has rendezvoused here.
    ///
    /// Barriers are re-usable after all threads have rendezvoused once, and can
    /// be used continuously.
    ///
    /// A single (arbitrary) thread will receive a `BarrierWaitResult` that
    /// returns `true` from `is_leader` when returning from this function, and
    /// all other threads will receive a result that will return `false` from
    /// `is_leader`
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn wait(&self) -> BarrierWaitResult {
        let mut lock = self.lock.lock().unwrap();
        let local_gen = lock.generation_id;
        lock.count += 1;
        if lock.count < self.num_threads {
            // We need a while loop to guard against spurious wakeups.
            // http://en.wikipedia.org/wiki/Spurious_wakeup
            while local_gen == lock.generation_id &&
                  lock.count < self.num_threads {
                lock = self.cvar.wait(lock).unwrap();
            }
            BarrierWaitResult(false)
        } else {
            lock.count = 0;
            lock.generation_id += 1;
            self.cvar.notify_all();
            BarrierWaitResult(true)
        }
    }
}

impl BarrierWaitResult {
    /// Returns whether this thread from `wait` is the "leader thread".
    ///
    /// Only one thread will have `true` returned from their result, all other
    /// threads will have `false` returned.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn is_leader(&self) -> bool { self.0 }
}

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

    use sync::{Arc, Barrier};
    use sync::mpsc::{channel, TryRecvError};
    use thread;

    #[test]
    fn test_barrier() {
        const N: usize = 10;

        let barrier = Arc::new(Barrier::new(N));
        let (tx, rx) = channel();

        for _ in 0..N - 1 {
            let c = barrier.clone();
            let tx = tx.clone();
            thread::spawn(move|| {
                tx.send(c.wait().is_leader()).unwrap();
            });
        }

        // At this point, all spawned threads should be blocked,
        // so we shouldn't get anything from the port
        assert!(match rx.try_recv() {
            Err(TryRecvError::Empty) => true,
            _ => false,
        });

        let mut leader_found = barrier.wait().is_leader();

        // Now, the barrier is cleared and we should get data.
        for _ in 0..N - 1 {
            if rx.recv().unwrap() {
                assert!(!leader_found);
                leader_found = true;
            }
        }
        assert!(leader_found);
    }
}
<commit_msg>Rollup merge of #32507 - klingtnet:master, r=steveklabnik<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use sync::{Mutex, Condvar};

/// A barrier enables multiple threads to synchronize the beginning
/// of some computation.
///
/// ```
/// use std::sync::{Arc, Barrier};
/// use std::thread;
///
/// let mut handles = Vec::with_capacity(10);
/// let barrier = Arc::new(Barrier::new(10));
/// for _ in 0..10 {
///     let c = barrier.clone();
///     // The same messages will be printed together.
///     // You will NOT see any interleaving.
///     handles.push(thread::spawn(move|| {
///         println!("before wait");
///         c.wait();
///         println!("after wait");
///     }));
/// }
/// // Wait for other threads to finish.
/// for handle in handles {
///     handle.join().unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Barrier {
    lock: Mutex<BarrierState>,
    cvar: Condvar,
    num_threads: usize,
}

// The inner state of a double barrier
struct BarrierState {
    count: usize,
    generation_id: usize,
}

/// A result returned from wait.
///
/// Currently this opaque structure only has one method, `.is_leader()`. Only
/// one thread will receive a result that will return `true` from this function.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BarrierWaitResult(bool);

impl Barrier {
    /// Creates a new barrier that can block a given number of threads.
    ///
    /// A barrier will block `n`-1 threads which call `wait` and then wake up
    /// all threads at once when the `n`th thread calls `wait`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new(n: usize) -> Barrier {
        Barrier {
            lock: Mutex::new(BarrierState {
                count: 0,
                generation_id: 0,
            }),
            cvar: Condvar::new(),
            num_threads: n,
        }
    }

    /// Blocks the current thread until all threads has rendezvoused here.
    ///
    /// Barriers are re-usable after all threads have rendezvoused once, and can
    /// be used continuously.
    ///
    /// A single (arbitrary) thread will receive a `BarrierWaitResult` that
    /// returns `true` from `is_leader` when returning from this function, and
    /// all other threads will receive a result that will return `false` from
    /// `is_leader`
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn wait(&self) -> BarrierWaitResult {
        let mut lock = self.lock.lock().unwrap();
        let local_gen = lock.generation_id;
        lock.count += 1;
        if lock.count < self.num_threads {
            // We need a while loop to guard against spurious wakeups.
            // http://en.wikipedia.org/wiki/Spurious_wakeup
            while local_gen == lock.generation_id &&
                  lock.count < self.num_threads {
                lock = self.cvar.wait(lock).unwrap();
            }
            BarrierWaitResult(false)
        } else {
            lock.count = 0;
            lock.generation_id += 1;
            self.cvar.notify_all();
            BarrierWaitResult(true)
        }
    }
}

impl BarrierWaitResult {
    /// Returns whether this thread from `wait` is the "leader thread".
    ///
    /// Only one thread will have `true` returned from their result, all other
    /// threads will have `false` returned.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn is_leader(&self) -> bool { self.0 }
}

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

    use sync::{Arc, Barrier};
    use sync::mpsc::{channel, TryRecvError};
    use thread;

    #[test]
    fn test_barrier() {
        const N: usize = 10;

        let barrier = Arc::new(Barrier::new(N));
        let (tx, rx) = channel();

        for _ in 0..N - 1 {
            let c = barrier.clone();
            let tx = tx.clone();
            thread::spawn(move|| {
                tx.send(c.wait().is_leader()).unwrap();
            });
        }

        // At this point, all spawned threads should be blocked,
        // so we shouldn't get anything from the port
        assert!(match rx.try_recv() {
            Err(TryRecvError::Empty) => true,
            _ => false,
        });

        let mut leader_found = barrier.wait().is_leader();

        // Now, the barrier is cleared and we should get data.
        for _ in 0..N - 1 {
            if rx.recv().unwrap() {
                assert!(!leader_found);
                leader_found = true;
            }
        }
        assert!(leader_found);
    }
}
<|endoftext|>


<commit_before>use memory::Memory;
use std::vec::Vec;

/// Maps multiple `Memory`s into a single address space.
///
/// The `MappedMemory` allows to unify multiple `Memory`s in one address space.
/// A `Memory` is mounted at a certain address and is from now on responsible
/// for all reads and writes between that starting at that address (the “mount
/// point”) and ending where the mounted memory ends.
/// The read and write calls for the responsible `Memory` will be given an
/// address _relative_ to the mount point.
///
/// ```text
///                   Unmapped
///                <------------>
///       mem_a                   mem_b
/// |--------------|            |------|
///
/// |------------- mapped_mem ----------->
/// |              |            |      |
/// 0            0x100        0x200  0x280
/// ```
///
/// For example: `mapped_mem.get(0x208)` would yield the same value as
/// `mem_b.get(0x008)`.
///
/// For now, mounts resulting in overlapping areas don’t panic but yield
/// undefined behavior.
///
/// # Examples
/// ```
/// use osciemu::memory::{Memory, SliceMemory, MappedMemory};
///
/// // m1 =~ [1]
/// let mut m1 = SliceMemory::with_value(1, 1);
/// // m2 =~ [2, 2]
/// let mut m2 = SliceMemory::with_value(2, 2);
/// let mut mm = MappedMemory::new();
/// mm.mount(0, &mut m1);
/// mm.mount(2, &mut m2);
/// // Now mm =~ [1, _, 2, 2]
/// assert_eq!(mm.get(0), 1);
/// assert_eq!(mm.get(3), 2);
/// ```
///
/// # Panics
/// `MappedMemory` panics when an unmapped address is read or written.
///
/// # TODOs
/// - Handle overlapping mounts in lookup
/// - Handle if the last mount in the list is not necessarily the one
/// - responsible for the largest address.
pub struct MappedMemory<'a>(Vec<Entry<'a>>);

pub struct Entry<'a> {
    memory: &'a mut Memory,
    start_address: usize,
    size: usize,
}

impl<'a> MappedMemory<'a> {
    pub fn new() -> MappedMemory<'a> {
        MappedMemory(Vec::new())
    }

    /// Mounts a `Memory` at the given address.
    pub fn mount(&mut self, start: usize, memory: &'a mut Memory) {
        let size = memory.size();
        let new_entry = Entry {
            memory: memory,
            start_address: start,
            size: size,
        };
        let mut insert_idx = self.0.len();
        {
            let mut iter = self.0.iter().enumerate();
            loop {
                if let Some((idx, entry)) = iter.next() {
                    if entry.start_address >= new_entry.start_address {
                        insert_idx = idx - 1;
                        break;
                    }
                } else {
                    break;
                }
            }
        }
        self.0.insert(insert_idx, new_entry);
    }

    fn memory_at_addr(&self, addr: usize) -> Option<&Entry<'a>> {
        self.0
            .iter()
            .find(|entry| entry.start_address <= addr && entry.start_address + entry.size > addr)
    }

    fn memory_at_addr_mut(&mut self, addr: usize) -> Option<&mut Entry<'a>> {
        self.0
            .iter_mut()
            .find(|entry| entry.start_address <= addr && entry.start_address + entry.size > addr)
    }
}

impl<'a> Memory for MappedMemory<'a> {
    fn get(&self, addr: usize) -> u32 {
        self.memory_at_addr(addr)
            .map(|entry| entry.memory.get(addr - entry.start_address))
            .expect("Out of bounds")
    }

    fn set(&mut self, addr: usize, value: u32) {
        self.memory_at_addr_mut(addr)
            .map(|entry| entry.memory.set(addr - entry.start_address, value))
            .expect("Out of bounds")
    }

    fn size(&self) -> usize {
        self.0
            .last()
            .map_or(0, |entry| entry.size + entry.start_address as usize)
    }
}

#[cfg(test)]
mod test {
    use memory::Memory;
    use memory::SliceMemory;

    #[test]
    fn memory_at_addr() {
        let mut m1 = SliceMemory::with_value(1, 1);
        let mut m2 = SliceMemory::with_value(2, 2);
        let mut mm = super::MappedMemory::new();
        mm.mount(0, &mut m1);
        mm.mount(2, &mut m2);

        assert!(mm.memory_at_addr(0)
            .map_or(false, |entry| entry.memory.get(0) == 1));
        assert!(mm.memory_at_addr(1).is_none());
        assert!(mm.memory_at_addr(2)
            .map_or(false, |entry| entry.memory.get(0) == 2));
        assert!(mm.memory_at_addr(3)
            .map_or(false, |entry| entry.memory.get(0) == 2));
        assert!(mm.memory_at_addr(4).is_none());
    }

    #[test]
    fn get_and_set() {
        let mut m1 = SliceMemory::with_value(1, 1);
        let mut m2 = SliceMemory::with_value(2, 2);
        {
            let mut mm = super::MappedMemory::new();
            mm.mount(0, &mut m1);
            mm.mount(2, &mut m2);

            assert_eq!(mm.get(0), 1);
            assert_eq!(mm.get(2), 2);

            mm.set(0, 3);
            assert_eq!(mm.get(0), 3);
            mm.set(3, 0);
            assert_eq!(mm.get(3), 0);
        }
        assert_eq!(m1.get(0), 3);
        assert_eq!(m2.get(1), 0);
    }

    #[test]
    fn size() {
        let mut m1 = SliceMemory::with_value(1, 1);
        let mut m2 = SliceMemory::with_value(2, 2);
        let mut mm = super::MappedMemory::new();
        assert_eq!(mm.size(), 0);

        mm.mount(0, &mut m1);
        assert_eq!(mm.size(), 1);

        mm.mount(2, &mut m2);
        assert_eq!(mm.size(), 4);
    }
}
<commit_msg>feat(mappedmemory): Support overlapping mounts<commit_after>use memory::Memory;
use std::vec::Vec;

/// Maps multiple `Memory`s into a single address space.
///
/// The `MappedMemory` allows to unify multiple `Memory`s in one address space.
/// A `Memory` is mounted at a certain address and is from now on responsible
/// for all reads and writes between that starting at that address (the “mount
/// point”) and ending where the mounted memory ends.
/// The read and write calls for the responsible `Memory` will be given an
/// address _relative_ to the mount point.
///
/// ```text
///                   Unmapped
///                <-------->
///       mem_a                   mem_b
/// |--------------|            |------|
///                            NullMemory
///                         |--------------
/// |------------- mapped_mem ----------->
/// |              |            |      |
/// 0            0x100        0x200  0x280
/// ```
///
/// For example: `mapped_mem.get(0x208)` would yield the same value as
/// `mem_b.get(0x008)`.
///
/// # Examples
/// ```
/// use osciemu::memory::{Memory, SliceMemory, MappedMemory};
///
/// // m1 =~ [1]
/// let mut m1 = SliceMemory::with_value(1, 1);
/// // m2 =~ [2, 2]
/// let mut m2 = SliceMemory::with_value(2, 2);
/// let mut mm = MappedMemory::new();
/// mm.mount(0, &mut m1);
/// mm.mount(2, &mut m2);
/// // Now mm =~ [1, _, 2, 2]
/// assert_eq!(mm.get(0), 1);
/// assert_eq!(mm.get(3), 2);
/// ```
///
/// # Panics
/// `MappedMemory` panics when an unmapped address is read or written.
pub struct MappedMemory<'a>(Vec<Entry<'a>>);

pub struct Entry<'a> {
    memory: &'a mut Memory,
    start_address: usize,
    size: usize,
}

impl<'a> MappedMemory<'a> {
    pub fn new() -> MappedMemory<'a> {
        MappedMemory(Vec::new())
    }

    /// Mounts a `Memory` at the given address.
    pub fn mount(&mut self, start: usize, memory: &'a mut Memory) {
        let size = memory.size();
        let new_entry = Entry {
            memory: memory,
            start_address: start,
            size: size,
        };
        self.0.push(new_entry);
    }

    fn memory_at_addr(&self, addr: usize) -> Option<&Entry<'a>> {
        self.0
            .iter()
            .rev()
            .find(|entry| entry.start_address <= addr && entry.start_address + entry.size > addr)
    }

    fn memory_at_addr_mut(&mut self, addr: usize) -> Option<&mut Entry<'a>> {
        self.0
            .iter_mut()
            .rev()
            .find(|entry| entry.start_address <= addr && entry.start_address + entry.size > addr)
    }
}

impl<'a> Memory for MappedMemory<'a> {
    fn get(&self, addr: usize) -> u32 {
        self.memory_at_addr(addr)
            .map(|entry| entry.memory.get(addr - entry.start_address))
            .expect("Out of bounds")
    }

    fn set(&mut self, addr: usize, value: u32) {
        self.memory_at_addr_mut(addr)
            .map(|entry| entry.memory.set(addr - entry.start_address, value))
            .expect("Out of bounds")
    }

    fn size(&self) -> usize {
        self.0
            .iter()
            .map(|entry| entry.start_address + entry.size)
            .max().unwrap_or(0)
    }
}

#[cfg(test)]
mod test {
    use memory::{Memory, SliceMemory, NullMemory};

    #[test]
    fn memory_at_addr() {
        let mut m1 = SliceMemory::with_value(1, 1);
        let mut m2 = SliceMemory::with_value(2, 2);
        let mut mm = super::MappedMemory::new();
        mm.mount(0, &mut m1);
        mm.mount(2, &mut m2);

        assert!(mm.memory_at_addr(0)
            .map_or(false, |entry| entry.memory.get(0) == 1));
        assert!(mm.memory_at_addr(1).is_none());
        assert!(mm.memory_at_addr(2)
            .map_or(false, |entry| entry.memory.get(0) == 2));
        assert!(mm.memory_at_addr(3)
            .map_or(false, |entry| entry.memory.get(0) == 2));
        assert!(mm.memory_at_addr(4).is_none());
    }

    #[test]
    fn overlapping_mounts() {
        let mut m1 = NullMemory::new();
        let mut m2 = SliceMemory::with_value(2, 2);
        let mut m3 = SliceMemory::with_value(1, 3);
        let mut mm = super::MappedMemory::new();
        mm.mount(0, &mut m1);
        mm.mount(1, &mut m2);
        mm.mount(2, &mut m3);

        assert_eq!(mm.get(0), 0);
        assert_eq!(mm.get(1), 2);
        assert_eq!(mm.get(2), 3);
        assert_eq!(mm.get(3), 0);
    }

    #[test]
    fn get_and_set() {
        let mut m1 = SliceMemory::with_value(1, 1);
        let mut m2 = SliceMemory::with_value(2, 2);
        {
            let mut mm = super::MappedMemory::new();
            mm.mount(0, &mut m1);
            mm.mount(2, &mut m2);

            assert_eq!(mm.get(0), 1);
            assert_eq!(mm.get(2), 2);

            mm.set(0, 3);
            assert_eq!(mm.get(0), 3);
            mm.set(3, 0);
            assert_eq!(mm.get(3), 0);
        }
        assert_eq!(m1.get(0), 3);
        assert_eq!(m2.get(1), 0);
    }

    #[test]
    fn size() {
        let mut m1 = SliceMemory::with_value(1, 1);
        let mut m2 = SliceMemory::with_value(2, 2);
        let mut mm = super::MappedMemory::new();
        assert_eq!(mm.size(), 0);

        mm.mount(0, &mut m1);
        assert_eq!(mm.size(), 1);

        mm.mount(2, &mut m2);
        assert_eq!(mm.size(), 4);
    }

    #[test]
    fn size_with_overlap() {
        let mut m1 = SliceMemory::with_value(10, 1);
        let mut m2 = SliceMemory::with_value(2, 2);
        let mut m3 = SliceMemory::with_value(3, 3);
        let mut mm = super::MappedMemory::new();

        mm.mount(0, &mut m1);
        mm.mount(2, &mut m2);
        assert_eq!(mm.size(), 10);

        mm.mount(9, &mut m3);
        assert_eq!(mm.size(), 12);
    }
}
<|endoftext|>


<commit_before>use common::types::{
	Ty,
	bool_ty
};

use util::boxed::{
	ToBoxedVec,
	ToVec
};

#[derive(Clone)]
pub struct Expr (pub Ty, pub ExprKind);

impl Expr
{
	#[inline]
	pub fn ty(&self) -> &Ty
	{
		&self.0
	}

	#[inline]
	pub fn kind(&self) -> &ExprKind
	{
		&self.1
	}
}

/// Expression Specific Element
#[derive(Clone)]
pub enum ExprKind {
  // Unary Expressions
  Not      (Box<Expr>),
  IsNull   (Box<Expr>),
  IsNotNull(Box<Expr>),
  PlusSign (Box<Expr>),
  MinusSign(Box<Expr>),
  Cast     (Box<Expr>, Ty, Ty),

  // Binary Arithmetic Expressions
  And(Box<Expr>,Box<Expr>),
  Or(Box<Expr>,Box<Expr>),
  Cmp(CmpOp, Box<Expr>, Box<Expr>),
  Arithm(ArithmOp, Box<Expr>, Box<Expr>),

  // function and values
  Fn(FnDecl, Vec<Box<Expr>>),
  Field(String),
  Const(Literal),

  // condition
  Switch(Vec<Box<Expr>>, Box<Expr>), // multiple conditions, else return value
  Case  (Box<Expr>, Box<Expr>),      // condition, return value
}

/// Comparison Operator Type
#[derive(Clone, Copy)]
pub enum CmpOp {
  Eq,
  Ne,
  Lt,
  Le,
  Gt,
  Ge
}

/// Arithmetic Operator Type
#[derive(Clone, Copy)]
pub enum ArithmOp {
  Plus,
  Sub,
  Mul,
  Div,
  Rem,
}

/// Function Declaration
#[derive(Clone)]
pub struct FnDecl {
  signature: String,
  ret_ty: Ty
}

impl FnDecl
{
	pub fn ty(&self) -> &Ty
	{
		&self.ret_ty
	}
}

/// Representation for a single value
#[derive(Clone)]
pub enum Literal
{
  Bool(bool),
  I8(i8),
  I16(i16),
  I32(i32),
  I64(i64),
  F32(f32),
  F64(f64),
  String(String)
}

pub fn Not(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::Not(Box::new(c)))
}

pub fn IsNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

pub fn IsNotNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

pub fn Cast(c: Expr, from_ty: &Ty, to_ty: &Ty) -> Expr
{
	Expr(to_ty.clone(), ExprKind::Cast(Box::new(c), from_ty.clone(), to_ty.clone()))
}

pub fn PlusSign(c: Expr) -> Expr
{
	Expr(c.ty().	clone(), ExprKind::PlusSign(Box::new(c)))
}

pub fn MinusSign(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::MinusSign(Box::new(c)))
}

pub fn And(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::And(Box::new(l), Box::new(r)))
}

pub fn Or(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Or(Box::new(l), Box::new(r)))
}

pub fn Cmp(op: CmpOp, l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Cmp(op, Box::new(l), Box::new(r)))
}

pub fn Arithm(op: &ArithmOp, ret_type: &Ty, l: Expr, r: Expr) -> Expr
{
	Expr(ret_type.clone(), ExprKind::Arithm(*op, Box::new(l), Box::new(r)))
}

pub fn Func(decl: FnDecl, args: Vec<Expr>) -> Expr
{
	Expr(decl.ty().clone(), ExprKind::Fn(decl, args.to_boxed()))
}

pub fn Switch(cases: Vec<Expr>, default: Expr) -> Expr
{
	Expr(default.ty().clone(), ExprKind::Switch(cases.to_boxed(), Box::new(default)))
}

pub fn Case(cond: Expr, result: Expr) -> Expr
{
	Expr(result.ty().clone(), ExprKind::Case(Box::new(cond), Box::new(result)))
}

pub fn Const(value: Literal) -> Expr
{
	let ty = match value {
		Literal::Bool(_) => bool_ty(),
		_                => panic!("unsupported type")
	};

	Expr(ty, ExprKind::Const(value))
}

pub fn clone(e: &Box<Expr>) -> Expr
{
	*(e.clone())
}

pub mod optimizer
{
	pub use expr_optimizer::*;
}

pub mod visitor
{
	//! Visitor for Expr

	use common::types::Ty;
	use super::*;

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait SimpleVisitor: Sized
	{
	  fn accept(&mut self, e: &Expr)
	  {
	    accept_by_default(self, e);
	  }
	}

	pub fn accept_by_default<T>(v: &mut T, e: &Expr) where T: SimpleVisitor + Sized {
	  match *e.kind() {
	    ExprKind::Not      (ref c)       => v.accept(c),
	    ExprKind::IsNull   (ref c)       => v.accept(c),
	    ExprKind::IsNotNull(ref c)       => v.accept(c),
	    ExprKind::PlusSign (ref c)       => v.accept(c),
	    ExprKind::MinusSign(ref c)       => v.accept(c),
	    ExprKind::Cast     (ref c, _, _) => v.accept(c),

	    ExprKind::And      (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Or       (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Cmp      (_, ref l, ref r) => { v.accept(l); v.accept(r) },
	    ExprKind::Arithm   (_, ref l, ref r) => { v.accept(l); v.accept(r) },

	    ExprKind::Fn     (_, ref args)  => { for e in args.iter() { v.accept(e) } },
			ExprKind::Field  (_) 	          => {},
	    ExprKind::Const  (_)            => {}

	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },
	  }
	}

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait TransformVisitor: Sized
  {
	  fn transform(&self, e: &Expr) -> Expr
	  {
	    transform_by_default(self, e)
	  }
	}

	pub fn transform_by_default<T>(v: &T, e: &Expr) -> Expr
			where T: TransformVisitor + Sized
	{
		match *e.kind() {
	    ExprKind::Not      (ref c)               => Not      (v.transform(c)),
	    ExprKind::IsNull   (ref c)               => IsNull   (v.transform(c)),
	    ExprKind::IsNotNull(ref c)               => IsNotNull(v.transform(c)),
	    ExprKind::PlusSign (ref c)               => PlusSign (v.transform(c)),
	    ExprKind::MinusSign(ref c)               => MinusSign(v.transform(c)),
	    ExprKind::Cast     (ref c, ref f, ref t) => Cast     (v.transform(c), f, t),

	    ExprKind::And      (ref l, ref r)        => And(v.transform(l), v.transform(r)),
	    ExprKind::Or       (ref l, ref r)        => Or (v.transform(l), v.transform(r)),
	    ExprKind::Cmp      (ref o, ref l, ref r) => Cmp(*o, v.transform(l), v.transform(r)),
	    ExprKind::Arithm   (ref o, ref l, ref r) => Arithm(o, e.ty(), v.transform(l), v.transform(r)),

	    ExprKind::Fn       (ref f, ref args)     => {
	    	let rargs = args.iter().map(|arg| v.transform(arg)).collect::<Vec<Expr>>();
	    	Func(f.clone(), rargs)
    	},
			ExprKind::Field     (_) 	                => e.clone(),
	    ExprKind::Const     (_)                   => e.clone(),

	    ExprKind::Switch   (ref cases, ref default)  => {
	    	let rcases = cases.iter().map(|case| v.transform(case)).collect::<Vec<Expr>>();

	    	Switch(rcases, v.transform(default))
   	  }
	    ExprKind::Case      (ref l, ref r)        => Case(v.transform(l), v.transform(r)),
	  }
	}
}<commit_msg>Renamed SimpleVisitor in expr.rs to Visitor.<commit_after>use common::types::{
	Ty,
	bool_ty
};

use util::boxed::{
	ToBoxedVec,
	ToVec
};

#[derive(Clone)]
pub struct Expr (pub Ty, pub ExprKind);

impl Expr
{
	#[inline]
	pub fn ty(&self) -> &Ty
	{
		&self.0
	}

	#[inline]
	pub fn kind(&self) -> &ExprKind
	{
		&self.1
	}
}

/// Expression Specific Element
#[derive(Clone)]
pub enum ExprKind {
  // Unary Expressions
  Not      (Box<Expr>),
  IsNull   (Box<Expr>),
  IsNotNull(Box<Expr>),
  PlusSign (Box<Expr>),
  MinusSign(Box<Expr>),
  Cast     (Box<Expr>, Ty, Ty),

  // Binary Arithmetic Expressions
  And(Box<Expr>,Box<Expr>),
  Or(Box<Expr>,Box<Expr>),
  Cmp(CmpOp, Box<Expr>, Box<Expr>),
  Arithm(ArithmOp, Box<Expr>, Box<Expr>),

  // function and values
  Fn(FnDecl, Vec<Box<Expr>>),
  Field(String),
  Const(Literal),

  // condition
  Switch(Vec<Box<Expr>>, Box<Expr>), // multiple conditions, else return value
  Case  (Box<Expr>, Box<Expr>),      // condition, return value
}

/// Comparison Operator Type
#[derive(Clone, Copy)]
pub enum CmpOp {
  Eq,
  Ne,
  Lt,
  Le,
  Gt,
  Ge
}

/// Arithmetic Operator Type
#[derive(Clone, Copy)]
pub enum ArithmOp {
  Plus,
  Sub,
  Mul,
  Div,
  Rem,
}

/// Function Declaration
#[derive(Clone)]
pub struct FnDecl {
  signature: String,
  ret_ty: Ty
}

impl FnDecl
{
	pub fn ty(&self) -> &Ty
	{
		&self.ret_ty
	}
}

/// Representation for a single value
#[derive(Clone)]
pub enum Literal
{
  Bool(bool),
  I8(i8),
  I16(i16),
  I32(i32),
  I64(i64),
  F32(f32),
  F64(f64),
  String(String)
}

pub fn Not(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::Not(Box::new(c)))
}

pub fn IsNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

pub fn IsNotNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

pub fn Cast(c: Expr, from_ty: &Ty, to_ty: &Ty) -> Expr
{
	Expr(to_ty.clone(), ExprKind::Cast(Box::new(c), from_ty.clone(), to_ty.clone()))
}

pub fn PlusSign(c: Expr) -> Expr
{
	Expr(c.ty().	clone(), ExprKind::PlusSign(Box::new(c)))
}

pub fn MinusSign(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::MinusSign(Box::new(c)))
}

pub fn And(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::And(Box::new(l), Box::new(r)))
}

pub fn Or(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Or(Box::new(l), Box::new(r)))
}

pub fn Cmp(op: CmpOp, l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Cmp(op, Box::new(l), Box::new(r)))
}

pub fn Arithm(op: &ArithmOp, ret_type: &Ty, l: Expr, r: Expr) -> Expr
{
	Expr(ret_type.clone(), ExprKind::Arithm(*op, Box::new(l), Box::new(r)))
}

pub fn Func(decl: FnDecl, args: Vec<Expr>) -> Expr
{
	Expr(decl.ty().clone(), ExprKind::Fn(decl, args.to_boxed()))
}

pub fn Switch(cases: Vec<Expr>, default: Expr) -> Expr
{
	Expr(default.ty().clone(), ExprKind::Switch(cases.to_boxed(), Box::new(default)))
}

pub fn Case(cond: Expr, result: Expr) -> Expr
{
	Expr(result.ty().clone(), ExprKind::Case(Box::new(cond), Box::new(result)))
}

pub fn Const(value: Literal) -> Expr
{
	let ty = match value {
		Literal::Bool(_) => bool_ty(),
		_                => panic!("unsupported type")
	};

	Expr(ty, ExprKind::Const(value))
}

pub fn clone(e: &Box<Expr>) -> Expr
{
	*(e.clone())
}

pub mod optimizer
{
	pub use expr_optimizer::*;
}

pub mod visitor
{
	//! Visitor for Expr

	use common::types::Ty;
	use super::*;

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait Visitor: Sized
	{
	  fn accept(&mut self, e: &Expr)
	  {
	    accept_by_default(self, e);
	  }
	}

	pub fn accept_by_default<T>(v: &mut T, e: &Expr) where T: Visitor + Sized {
	  match *e.kind() {
	    ExprKind::Not      (ref c)       => v.accept(c),
	    ExprKind::IsNull   (ref c)       => v.accept(c),
	    ExprKind::IsNotNull(ref c)       => v.accept(c),
	    ExprKind::PlusSign (ref c)       => v.accept(c),
	    ExprKind::MinusSign(ref c)       => v.accept(c),
	    ExprKind::Cast     (ref c, _, _) => v.accept(c),

	    ExprKind::And      (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Or       (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Cmp      (_, ref l, ref r) => { v.accept(l); v.accept(r) },
	    ExprKind::Arithm   (_, ref l, ref r) => { v.accept(l); v.accept(r) },

	    ExprKind::Fn     (_, ref args)  => { for e in args.iter() { v.accept(e) } },
			ExprKind::Field  (_) 	          => {},
	    ExprKind::Const  (_)            => {}

	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },
	  }
	}

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait TransformVisitor: Sized
  {
	  fn transform(&self, e: &Expr) -> Expr
	  {
	    transform_by_default(self, e)
	  }
	}

	pub fn transform_by_default<T>(v: &T, e: &Expr) -> Expr
			where T: TransformVisitor + Sized
	{
		match *e.kind() {
	    ExprKind::Not      (ref c)               => Not      (v.transform(c)),
	    ExprKind::IsNull   (ref c)               => IsNull   (v.transform(c)),
	    ExprKind::IsNotNull(ref c)               => IsNotNull(v.transform(c)),
	    ExprKind::PlusSign (ref c)               => PlusSign (v.transform(c)),
	    ExprKind::MinusSign(ref c)               => MinusSign(v.transform(c)),
	    ExprKind::Cast     (ref c, ref f, ref t) => Cast     (v.transform(c), f, t),

	    ExprKind::And      (ref l, ref r)        => And(v.transform(l), v.transform(r)),
	    ExprKind::Or       (ref l, ref r)        => Or (v.transform(l), v.transform(r)),
	    ExprKind::Cmp      (ref o, ref l, ref r) => Cmp(*o, v.transform(l), v.transform(r)),
	    ExprKind::Arithm   (ref o, ref l, ref r) => Arithm(o, e.ty(), v.transform(l), v.transform(r)),

	    ExprKind::Fn       (ref f, ref args)     => {
	    	let rargs = args.iter().map(|arg| v.transform(arg)).collect::<Vec<Expr>>();
	    	Func(f.clone(), rargs)
    	},
			ExprKind::Field     (_) 	                => e.clone(),
	    ExprKind::Const     (_)                   => e.clone(),

	    ExprKind::Switch   (ref cases, ref default)  => {
	    	let rcases = cases.iter().map(|case| v.transform(case)).collect::<Vec<Expr>>();

	    	Switch(rcases, v.transform(default))
   	  }
	    ExprKind::Case      (ref l, ref r)        => Case(v.transform(l), v.transform(r)),
	  }
	}
}<|endoftext|>


<commit_before>#![feature(proc_macro)]
#[macro_use] extern crate clap;
#[macro_use] extern crate serde_derive;
extern crate mio;
extern crate mio_uds;
extern crate nix;
extern crate libc;
extern crate time;
extern crate toml;
extern crate serde;
extern crate serde_json;
extern crate sozu_lib as sozu;

mod config;
mod command;
mod messages;

use mio_uds::UnixStream;
use std::net::{UdpSocket,ToSocketAddrs};
use std::collections::HashMap;
use clap::{App,Arg,SubCommand};
use sozu::messages::Command;
use sozu::command::CommandChannel;

use command::{dump_state,save_state};
use messages::{ConfigCommand,ConfigMessage,ConfigMessageAnswer,ConfigMessageStatus};

fn main() {
  let matches = App::new("sozuctl")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .arg(Arg::with_name("config")
                            .short("c")
                            .long("config")
                            .value_name("FILE")
                            .help("Sets a custom config file")
                            .takes_value(true)
                            .required(true))
                        .subcommand(SubCommand::with_name("shutdown")
                                    .about("shuts down the proxy")
                                    .arg(Arg::with_name("hard").long("hard")
                                         .help("shuts down the proxy without waiting for connections to finish")))
                        .subcommand(SubCommand::with_name("state")
                                    .about("state management")
                                    .subcommand(SubCommand::with_name("save")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("load")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)))
                                    .subcommand(SubCommand::with_name("dump")))
                        .get_matches();

  if let Some(matches) = matches.subcommand_matches("worker") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let id  = matches.value_of("id").expect("needs a worker id");
    let tag = matches.value_of("tag").expect("needs a configuration tag");

    return;
  }

  let config_file = matches.value_of("config").expect("required config file");

  let config = config::Config::load_from_path(config_file).expect("could not parse configuration file");
  let stream = UnixStream::connect(config.command_socket).expect("could not connect to the command unix socket");
  let mut channel: CommandChannel<ConfigMessage,ConfigMessageAnswer> = CommandChannel::new(stream, 10000, 20000);
  channel.set_nonblocking(false);

  match matches.subcommand() {
    ("shutdown", Some(sub)) => {
      let hard_shutdown = sub.is_present("hard");
    },
    ("state", Some(sub))    => {
      match sub.subcommand() {
        ("save", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          save_state(&mut channel, file);
        },
        ("load", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
        },
        ("dump", _) => {
          dump_state(&mut channel);
        },
        _                   => println!("unknown state management command")
      }
    },
    _                => println!("unknown subcommand")
  }

}
<commit_msg>remove useless code<commit_after>#![feature(proc_macro)]
#[macro_use] extern crate clap;
#[macro_use] extern crate serde_derive;
extern crate mio;
extern crate mio_uds;
extern crate nix;
extern crate libc;
extern crate time;
extern crate toml;
extern crate serde;
extern crate serde_json;
extern crate sozu_lib as sozu;

mod config;
mod command;
mod messages;

use mio_uds::UnixStream;
use std::net::{UdpSocket,ToSocketAddrs};
use std::collections::HashMap;
use clap::{App,Arg,SubCommand};
use sozu::messages::Command;
use sozu::command::CommandChannel;

use command::{dump_state,save_state};
use messages::{ConfigCommand,ConfigMessage,ConfigMessageAnswer,ConfigMessageStatus};

fn main() {
  let matches = App::new("sozuctl")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .arg(Arg::with_name("config")
                            .short("c")
                            .long("config")
                            .value_name("FILE")
                            .help("Sets a custom config file")
                            .takes_value(true)
                            .required(true))
                        .subcommand(SubCommand::with_name("shutdown")
                                    .about("shuts down the proxy")
                                    .arg(Arg::with_name("hard").long("hard")
                                         .help("shuts down the proxy without waiting for connections to finish")))
                        .subcommand(SubCommand::with_name("state")
                                    .about("state management")
                                    .subcommand(SubCommand::with_name("save")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("load")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)))
                                    .subcommand(SubCommand::with_name("dump")))
                        .get_matches();

  let config_file = matches.value_of("config").expect("required config file");

  let config = config::Config::load_from_path(config_file).expect("could not parse configuration file");
  let stream = UnixStream::connect(config.command_socket).expect("could not connect to the command unix socket");
  let mut channel: CommandChannel<ConfigMessage,ConfigMessageAnswer> = CommandChannel::new(stream, 10000, 20000);
  channel.set_nonblocking(false);

  match matches.subcommand() {
    ("shutdown", Some(sub)) => {
      let hard_shutdown = sub.is_present("hard");
    },
    ("state", Some(sub))    => {
      match sub.subcommand() {
        ("save", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          save_state(&mut channel, file);
        },
        ("load", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
        },
        ("dump", _) => {
          dump_state(&mut channel);
        },
        _                   => println!("unknown state management command")
      }
    },
    _                => println!("unknown subcommand")
  }

}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! 64-bit Interrupt Descriptor Table implementation.
//!
//! Refer to section 6.10 of the _Intel® 64 and IA-32 Architectures
//! Software Developer’s Manual_ for more information.
use core::mem;
use spin::Mutex;
use super::cpu::pics;

#[path = "../x86_all/interrupts.rs"] mod interrupts_all;
pub use self::interrupts_all::*;

extern {
    /// Offset of the 64-bit GDT main code segment.
    /// Exported by `boot.asm`
    static gdt64_offset: u16;

    /// Array of interrupt handlers from ASM
    static int_handlers: [Option<unsafe extern "C" fn()>; IDT_ENTRIES];
}

/// Registers pushed to the stack when handling an interrupt.
#[repr(C, packed)]
struct Registers { rsi: u64
                 , rdi: u64
                 , r11: u64
                 , r10: u64
                 , r9:  u64
                 , r8:  u64
                 , rdx: u64
                 , rcx: u64
                 , rax: u64
                 , int_id:  u32
                 , __pad_1: u32
                 , err_no:  u32
                 , __pad_2: u32
                 }

impl Registers {
    // Transform this struct into an array of u64s
    // (if you would ever want to do this)
    pub unsafe fn to_array(&self) -> [u64; 11] {
        [ self.rsi, self.rdi, self.r11, self.r10, self.r9
        , self.r8,  self.rdx, self.rcx, self.rax
        , mem::transmute([self.__pad_1, self.int_id])
        , mem::transmute([self.__pad_2, self.err_no])
        ]
    }
}

fn handle_exception(r: &Registers) {
    panic!( "ERROR {}: {}"
          , r.err_no
          , EXCEPTIONS[r.int_id as usize] );
}

/// An IDT entry is called a gate.
///
/// Based on code from the OS Dev Wiki
/// http://wiki.osdev.org/Interrupt_Descriptor_Table#Structure
#[repr(C, packed)]
#[derive(Copy,Clone)]
struct Gate64 { /// bits 0 - 15 of the offset
              offset_lower: u16
            , /// code segment selector (GDT or LDT)
              selector: u16
            , /// always zero
              zero: u8
            , /// indicates the gate's type and attributes.
              /// the second half indicates the type:
              ///   + `0b1100`: Call gate
              ///   + `0b1110`: Interrupt gate
              ///   + `0b1111`: Trap Gate
              type_attr: u8
            , /// bits 16 - 31 of the offset
              offset_mid: u16
            , /// bits 32 - 63 of the offset
              offset_upper: u32
            , /// always zero (according to the spec, this is "reserved")
              reserved: u32
            }

impl Gate64 {
    /// Creates a new IDT gate marked as `absent`.
    ///
    /// This is basically just for filling the new IDT table
    /// with valid (but useless) gates upon init.
    const fn absent() -> Self {
        Gate64 { offset_lower: 0
               , selector: 0
               , zero: 0
               , type_attr: 0b0000_1110
               , offset_mid: 0
               , offset_upper: 0
               , reserved: 0
               }
    }
}

impl Gate for Gate64 {

    /// Creates a new IDT gate pointing at the given handler function.
    fn new(handler: Handler) -> Self {
        unsafe { // trust me on this.
                 // `mem::transmute()` is glorious black magic
            let (low, mid, high): (u16, u16, u32)
                = mem::transmute(handler);

            Gate64 { offset_lower: low
                   , selector: gdt64_offset
                   , zero: 0
                   , type_attr: 0b1000_1110
                   , offset_mid: mid
                   , offset_upper: high
                   , reserved: 0
                   }
        }
    }
}

struct Idt64([Gate64; IDT_ENTRIES]);

impl Idt for Idt64 {
    type Ptr = IdtPtr<Self>;

    /// Get the IDT pointer struct to pass to `lidt`
    fn get_ptr(&self) -> Self::Ptr {
        IdtPtr { limit: (mem::size_of::<Gate64>() * IDT_ENTRIES) as u16
               , base:  self as *const Idt64
               }
    }

    /// Add an entry for the given handler at the given index
    fn add_gate(&mut self, index: usize, handler: Handler) {
        self.0[index] = Gate64::new(handler)
    }

}

impl IdtPtrOps for IdtPtr<Idt64> {
    /// Load the IDT at the given location.
    /// This just calls `lidt`.
    unsafe fn load(&self) {
        asm!(  "lidt ($0)"
            :: "{rax}"(self)
            :: "volatile" );
    }
}

/// Global Interrupt Descriptor Table instance
/// Our global IDT.
static IDT: Mutex<Idt64>
    = Mutex::new(Idt64([Gate64::absent(); IDT_ENTRIES]));

pub fn initialize() {
    let mut idt = IDT.lock();

    // TODO: load interrupts into IDT

    unsafe {
        idt.get_ptr().load();    // Load the IDT pointer
        pics::initialize();      // initialize the PICs
        idt.enable_interrupts(); // enable interrupts
    }
}
<commit_msg>Fix static method reference in interrupts.rs<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! 64-bit Interrupt Descriptor Table implementation.
//!
//! Refer to section 6.10 of the _Intel® 64 and IA-32 Architectures
//! Software Developer’s Manual_ for more information.
use core::mem;
use spin::Mutex;
use super::cpu::pics;

#[path = "../x86_all/interrupts.rs"] mod interrupts_all;
pub use self::interrupts_all::*;

extern {
    /// Offset of the 64-bit GDT main code segment.
    /// Exported by `boot.asm`
    static gdt64_offset: u16;

    /// Array of interrupt handlers from ASM
    static int_handlers: [Option<unsafe extern "C" fn()>; IDT_ENTRIES];
}

/// Registers pushed to the stack when handling an interrupt.
#[repr(C, packed)]
struct Registers { rsi: u64
                 , rdi: u64
                 , r11: u64
                 , r10: u64
                 , r9:  u64
                 , r8:  u64
                 , rdx: u64
                 , rcx: u64
                 , rax: u64
                 , int_id:  u32
                 , __pad_1: u32
                 , err_no:  u32
                 , __pad_2: u32
                 }

impl Registers {
    // Transform this struct into an array of u64s
    // (if you would ever want to do this)
    pub unsafe fn to_array(&self) -> [u64; 11] {
        [ self.rsi, self.rdi, self.r11, self.r10, self.r9
        , self.r8,  self.rdx, self.rcx, self.rax
        , mem::transmute([self.__pad_1, self.int_id])
        , mem::transmute([self.__pad_2, self.err_no])
        ]
    }
}

fn handle_exception(r: &Registers) {
    panic!( "ERROR {}: {}"
          , r.err_no
          , EXCEPTIONS[r.int_id as usize] );
}

/// An IDT entry is called a gate.
///
/// Based on code from the OS Dev Wiki
/// http://wiki.osdev.org/Interrupt_Descriptor_Table#Structure
#[repr(C, packed)]
#[derive(Copy,Clone)]
struct Gate64 { /// bits 0 - 15 of the offset
              offset_lower: u16
            , /// code segment selector (GDT or LDT)
              selector: u16
            , /// always zero
              zero: u8
            , /// indicates the gate's type and attributes.
              /// the second half indicates the type:
              ///   + `0b1100`: Call gate
              ///   + `0b1110`: Interrupt gate
              ///   + `0b1111`: Trap Gate
              type_attr: u8
            , /// bits 16 - 31 of the offset
              offset_mid: u16
            , /// bits 32 - 63 of the offset
              offset_upper: u32
            , /// always zero (according to the spec, this is "reserved")
              reserved: u32
            }

impl Gate64 {
    /// Creates a new IDT gate marked as `absent`.
    ///
    /// This is basically just for filling the new IDT table
    /// with valid (but useless) gates upon init.
    const fn absent() -> Self {
        Gate64 { offset_lower: 0
               , selector: 0
               , zero: 0
               , type_attr: 0b0000_1110
               , offset_mid: 0
               , offset_upper: 0
               , reserved: 0
               }
    }
}

impl Gate for Gate64 {

    /// Creates a new IDT gate pointing at the given handler function.
    fn new(handler: Handler) -> Self {
        unsafe { // trust me on this.
                 // `mem::transmute()` is glorious black magic
            let (low, mid, high): (u16, u16, u32)
                = mem::transmute(handler);

            Gate64 { offset_lower: low
                   , selector: gdt64_offset
                   , zero: 0
                   , type_attr: 0b1000_1110
                   , offset_mid: mid
                   , offset_upper: high
                   , reserved: 0
                   }
        }
    }
}

struct Idt64([Gate64; IDT_ENTRIES]);

impl Idt for Idt64 {
    type Ptr = IdtPtr<Self>;

    /// Get the IDT pointer struct to pass to `lidt`
    fn get_ptr(&self) -> Self::Ptr {
        IdtPtr { limit: (mem::size_of::<Gate64>() * IDT_ENTRIES) as u16
               , base:  self as *const Idt64
               }
    }

    /// Add an entry for the given handler at the given index
    fn add_gate(&mut self, index: usize, handler: Handler) {
        self.0[index] = Gate64::new(handler)
    }

}

impl IdtPtrOps for IdtPtr<Idt64> {
    /// Load the IDT at the given location.
    /// This just calls `lidt`.
    unsafe fn load(&self) {
        asm!(  "lidt ($0)"
            :: "{rax}"(self)
            :: "volatile" );
    }
}

/// Global Interrupt Descriptor Table instance
/// Our global IDT.
static IDT: Mutex<Idt64>
    = Mutex::new(Idt64([Gate64::absent(); IDT_ENTRIES]));

pub fn initialize() {
    let mut idt = IDT.lock();

    // TODO: load interrupts into IDT

    unsafe {
        idt.get_ptr().load();       // Load the IDT pointer
        pics::initialize();         // initialize the PICs
        Idt64::enable_interrupts(); // enable interrupts
    }
}
<|endoftext|>


<commit_before>// Finger server in Rust

use std::io::net::ip::{SocketAddr,IpAddr};
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Acceptor,Listener,BufferedStream};
//use std::time::duration::Duration;
//use std::io::net::addrinfo;
//use std::io::IoError;

static PORT_NUM : u16 = 79;
static LOCAL_IP : &'static str = "127.0.0.1";

mod passwd;

//Login: phooky         			Name: Adam Mayer
//Directory: /home/phooky             	Shell: /bin/bash
//On since Thu Dec  4 15:46 (EST) on tty2     2 days 23 hours idle
//     (messages off)
//On since Sat Nov 29 14:01 (EST) on :0 from :0 (messages off)
//On since Tue Dec  2 14:28 (EST) on pts/3 from :0
//    5 days 1 hour idle
//On since Thu Dec  4 16:05 (EST) on pts/1 from :0
//    45 seconds idle
//No mail.
//No Plan.
fn format_verbose(e : & passwd::Entry, bstream : &mut BufferedStream<TcpStream> ) {
    writeln!(bstream,"Login: {: <33}Name: {: <33}",
             e.username,e.gecos.name);
    if e.gecos.location.len() > 0 ||
        e.gecos.telephone.len() > 0 {
        writeln!(bstream,"Office: {: <30}Telephone: {: <30}",
                 e.gecos.location, e.gecos.telephone);
    }
    writeln!(bstream,"Directory: {: <29}Shell: {: <33}",
             e.home,e.shell);
}

fn process_local(uname : &str, wflag : bool, bstream : &mut BufferedStream<TcpStream>) {
    match passwd::get_entry(String::from_str(uname)) {
        None => {writeln!(bstream,"{}: no such user.",uname);}
        Some(e) => {format_verbose(&e,bstream);}
    };
}

fn finger_remote(req:&str, remote_host:&str, wflag:bool, bstream : &mut BufferedStream<TcpStream>) {
    println!("Remote! {} at {}, {}",req,remote_host,wflag);
}

fn process_request(str : String, bstream : &mut BufferedStream<TcpStream>) {
    let mut s = str.as_slice().trim();
    let wflag = s.starts_with("/W");
    if wflag {
        s = s.slice_from(2).trim();
    }
    match s.rfind('@') {
        None => process_local(s,wflag,bstream),
        Some(x) => finger_remote(s.slice_to(x),s.slice_from(x+1),wflag,bstream),
    }
}

fn finger_client(mut stream: TcpStream) {
//    stream.set_read_timeout(None);
    let mut bstream : BufferedStream<TcpStream> = BufferedStream::new(stream);
    match bstream.read_line() {
        Ok(str) => process_request(str,&mut bstream),
        Err(e) => panic!("Read failed: {}",e.desc),
    }
}

fn main() {
    let ip_addr : IpAddr;
    match from_str::<IpAddr>(LOCAL_IP) {
        None => panic!("Can not parse local IP specification!"),
        Some(ip) => ip_addr = ip,
    }
    let mut tcp_listener =
        match TcpListener::bind(SocketAddr{ ip:ip_addr, port:PORT_NUM }) {
            Ok(l) => l,
            Err(..) => panic!("Cannot bind to port {}!",PORT_NUM),
        };
    let mut acceptor =
        match tcp_listener.listen() {
            Ok(a) => a,
            Err(..) => panic!("Can not listen on port {}!",PORT_NUM),
        };
    println!("Starting to listen on port {}...",PORT_NUM);
    for stream in acceptor.incoming() {
        match stream {
            Err(e) => println!("Incoming connection failed."),
            Ok(stream) => spawn( proc() { finger_client(stream) } ),
        }
    }
}
<commit_msg>added configuration (cmdline and config file) for fingerd<commit_after>// Finger server in Rust

extern crate getopts;
use getopts::{optopt,optflag,getopts,OptGroup,usage};
use std::os;
use std::io::net::ip::{SocketAddr,IpAddr};
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Acceptor,Listener,BufferedStream,BufferedReader};
use std::io::fs::File;
use std::path::posix::Path;

//use std::time::duration::Duration;
//use std::io::net::addrinfo;
//use std::io::IoError;

static PORT_NUM : u16 = 79;
static LOCAL_IP : &'static str = "127.0.0.1";

mod passwd;

struct FingerdConfig {
    local_ip : String,
    permit_redirects : bool,
}

fn parse_config(path : &str) -> FingerdConfig {
    let mut config = FingerdConfig { local_ip : String::from_str(LOCAL_IP),
                                    permit_redirects : false };
    let p = Path::new(path);
    match File::open(&p) {
        Ok(f) => {
            let mut br = BufferedReader::new(f);
            for line in br.lines() {
                let st = line.unwrap();
                let s = st.as_slice().trim();
                if s.len() == 0 || s.starts_with("#") {
                    continue;
                }
                let kv : Vec<&str> = s.split('=').map(|x| x.trim()).collect();
                if kv.len() < 2 {
                    panic!("Unparseable line {}",s);
                }
                println!("Key {} Value {}",kv[0],kv[1]);
            }
        }
        Err(..) => (),
    }
    config
}

//Login: phooky         			Name: Adam Mayer
//Directory: /home/phooky             	Shell: /bin/bash
//On since Thu Dec  4 15:46 (EST) on tty2     2 days 23 hours idle
//     (messages off)
//On since Sat Nov 29 14:01 (EST) on :0 from :0 (messages off)
//On since Tue Dec  2 14:28 (EST) on pts/3 from :0
//    5 days 1 hour idle
//On since Thu Dec  4 16:05 (EST) on pts/1 from :0
//    45 seconds idle
//No mail.
//No Plan.
fn format_verbose(e : & passwd::Entry, bstream : &mut BufferedStream<TcpStream> ) {
    writeln!(bstream,"Login: {: <33}Name: {: <33}",
             e.username,e.gecos.name);
    if e.gecos.location.len() > 0 ||
        e.gecos.telephone.len() > 0 {
        writeln!(bstream,"Office: {: <30}Telephone: {: <30}",
                 e.gecos.location, e.gecos.telephone);
    }
    writeln!(bstream,"Directory: {: <29}Shell: {: <33}",
             e.home,e.shell);
}

fn process_local(uname : &str, wflag : bool, bstream : &mut BufferedStream<TcpStream>) {
    match passwd::get_entry(String::from_str(uname)) {
        None => {writeln!(bstream,"{}: no such user.",uname);}
        Some(e) => {format_verbose(&e,bstream);}
    };
}

fn finger_remote(req:&str, remote_host:&str, wflag:bool, bstream : &mut BufferedStream<TcpStream>) {
    println!("Remote! {} at {}, {}",req,remote_host,wflag);
}

fn process_request(str : String, bstream : &mut BufferedStream<TcpStream>) {
    let mut s = str.as_slice().trim();
    let wflag = s.starts_with("/W");
    if wflag {
        s = s.slice_from(2).trim();
    }
    match s.rfind('@') {
        None => process_local(s,wflag,bstream),
        Some(x) => finger_remote(s.slice_to(x),s.slice_from(x+1),wflag,bstream),
    }
}

fn finger_client(mut stream: TcpStream) {
//    stream.set_read_timeout(None);
    let mut bstream : BufferedStream<TcpStream> = BufferedStream::new(stream);
    match bstream.read_line() {
        Ok(str) => process_request(str,&mut bstream),
        Err(e) => panic!("Read failed: {}",e.desc),
    }
}

fn main() {
    let opts = &[
        optopt("","ip","IP to host server on","IP_ADDR"),
        optopt("c","","Config file (defaults to /etc/fingerd.conf)",
               "CONFIG_PATH"),
        optflag("h","help","Show usage information"),
    ];
    let args : Vec<String> = os::args();
    let program = args[0].clone();
    let matches = match getopts(args.tail(),opts) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    if matches.opt_present("h") {
        println!("{}",usage("Finger protocol server",opts));
        return;
    }
    let config = match matches.opt_str("c") {
        Some(path) => parse_config(path.as_slice()),
        None => parse_config("/etc/fingerd.conf"),
    };
    let ip_addr : IpAddr;
    match from_str::<IpAddr>(config.local_ip.as_slice()) {
        None => panic!("Can not parse local IP specification!"),
        Some(ip) => ip_addr = ip,
    }
    let mut tcp_listener =
        match TcpListener::bind(SocketAddr{ ip:ip_addr, port:PORT_NUM }) {
            Ok(l) => l,
            Err(..) => panic!("Cannot bind to port {}!",PORT_NUM),
        };
    let mut acceptor =
        match tcp_listener.listen() {
            Ok(a) => a,
            Err(..) => panic!("Can not listen on port {}!",PORT_NUM),
        };
    println!("Starting to listen on port {}...",PORT_NUM);
    for stream in acceptor.incoming() {
        match stream {
            Err(e) => println!("Incoming connection failed."),
            Ok(stream) => spawn( proc() { finger_client(stream) } ),
        }
    }
}
<|endoftext|>


<commit_before>//! Types for the [`m.room.create`] event.
//!
//! [`m.room.create`]: https://spec.matrix.org/v1.1/client-server-api/#mroomcreate

use ruma_events_macros::EventContent;
use ruma_identifiers::{EventId, RoomId, RoomVersionId, UserId};
use ruma_serde::StringEnum;
use serde::{Deserialize, Serialize};

use crate::PrivOwnedStr;

/// The content of an `m.room.create` event.
///
/// This is the first event in a room and cannot be changed.
///
/// It acts as the root of all other events.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.create", kind = State)]
pub struct RoomCreateEventContent {
    /// The `user_id` of the room creator.
    ///
    /// This is set by the homeserver.
    #[ruma_event(skip_redaction)]
    pub creator: Box<UserId>,

    /// Whether or not this room's data should be transferred to other homeservers.
    #[serde(
        rename = "m.federate",
        default = "ruma_serde::default_true",
        skip_serializing_if = "ruma_serde::is_true"
    )]
    pub federate: bool,

    /// The version of the room.
    ///
    /// Defaults to `RoomVersionId::V1`.
    #[serde(default = "default_room_version_id")]
    pub room_version: RoomVersionId,

    /// A reference to the room this room replaces, if the previous room was upgraded.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub predecessor: Option<PreviousRoom>,

    /// The room type.
    ///
    /// This is currently only used for spaces.
    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
    pub room_type: Option<RoomType>,
}

impl RoomCreateEventContent {
    /// Creates a new `RoomCreateEventContent` with the given creator.
    pub fn new(creator: Box<UserId>) -> Self {
        Self {
            creator,
            federate: true,
            room_version: default_room_version_id(),
            predecessor: None,
            room_type: None,
        }
    }
}

/// An enum of possible room types.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[non_exhaustive]
pub enum RoomType {
    /// Defines the room as a space.
    #[ruma_enum(rename = "m.space")]
    Space,

    /// Defines the room as a custom type.
    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

impl RoomType {
    /// Creates a string slice from this `RoomType`.
    pub fn as_str(&self) -> &str {
        self.as_ref()
    }
}

/// A reference to an old room replaced during a room version upgrade.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct PreviousRoom {
    /// The ID of the old room.
    pub room_id: Box<RoomId>,

    /// The event ID of the last known event in the old room.
    pub event_id: Box<EventId>,
}

impl PreviousRoom {
    /// Creates a new `PreviousRoom` from the given room and event IDs.
    pub fn new(room_id: Box<RoomId>, event_id: Box<EventId>) -> Self {
        Self { room_id, event_id }
    }
}

/// Used to default the `room_version` field to room version 1.
fn default_room_version_id() -> RoomVersionId {
    RoomVersionId::V1
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use ruma_identifiers::{user_id, RoomVersionId};
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{RoomCreateEventContent, RoomType};

    #[test]
    fn serialization() {
        let content = RoomCreateEventContent {
            creator: user_id!("@carl:example.com").to_owned(),
            federate: false,
            room_version: RoomVersionId::V4,
            predecessor: None,
            room_type: None,
        };

        let json = json!({
            "creator": "@carl:example.com",
            "m.federate": false,
            "room_version": "4"
        });

        assert_eq!(to_json_value(&content).unwrap(), json);
    }

    #[test]
    fn space_serialization() {
        let content = RoomCreateEventContent {
            creator: user_id!("@carl:example.com").to_owned(),
            federate: false,
            room_version: RoomVersionId::V4,
            predecessor: None,
            room_type: Some(RoomType::Space),
        };

        let json = json!({
            "creator": "@carl:example.com",
            "m.federate": false,
            "room_version": "4",
            "type": "m.space"
        });

        assert_eq!(to_json_value(&content).unwrap(), json);
    }

    #[test]
    fn deserialization() {
        let json = json!({
            "creator": "@carl:example.com",
            "m.federate": true,
            "room_version": "4"
        });

        assert_matches!(
            from_json_value::<RoomCreateEventContent>(json).unwrap(),
            RoomCreateEventContent {
                creator,
                federate: true,
                room_version: RoomVersionId::V4,
                predecessor: None,
                room_type: None,
            } if creator == "@carl:example.com"
        );
    }

    #[cfg(feature = "unstable-pre-spec")]
    #[test]
    fn space_deserialization() {
        let json = json!({
            "creator": "@carl:example.com",
            "m.federate": true,
            "room_version": "4",
            "type": "m.space"
        });

        assert_matches!(
            from_json_value::<RoomCreateEventContent>(json).unwrap(),
            RoomCreateEventContent {
                creator,
                federate: true,
                room_version: RoomVersionId::V4,
                predecessor: None,
                room_type
            } if creator == "@carl:example.com" && room_type == Some(RoomType::Space)
        );
    }
}
<commit_msg>events: Move space deserialization test out of unstable-pre-spec<commit_after>//! Types for the [`m.room.create`] event.
//!
//! [`m.room.create`]: https://spec.matrix.org/v1.1/client-server-api/#mroomcreate

use ruma_events_macros::EventContent;
use ruma_identifiers::{EventId, RoomId, RoomVersionId, UserId};
use ruma_serde::StringEnum;
use serde::{Deserialize, Serialize};

use crate::PrivOwnedStr;

/// The content of an `m.room.create` event.
///
/// This is the first event in a room and cannot be changed.
///
/// It acts as the root of all other events.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.create", kind = State)]
pub struct RoomCreateEventContent {
    /// The `user_id` of the room creator.
    ///
    /// This is set by the homeserver.
    #[ruma_event(skip_redaction)]
    pub creator: Box<UserId>,

    /// Whether or not this room's data should be transferred to other homeservers.
    #[serde(
        rename = "m.federate",
        default = "ruma_serde::default_true",
        skip_serializing_if = "ruma_serde::is_true"
    )]
    pub federate: bool,

    /// The version of the room.
    ///
    /// Defaults to `RoomVersionId::V1`.
    #[serde(default = "default_room_version_id")]
    pub room_version: RoomVersionId,

    /// A reference to the room this room replaces, if the previous room was upgraded.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub predecessor: Option<PreviousRoom>,

    /// The room type.
    ///
    /// This is currently only used for spaces.
    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
    pub room_type: Option<RoomType>,
}

impl RoomCreateEventContent {
    /// Creates a new `RoomCreateEventContent` with the given creator.
    pub fn new(creator: Box<UserId>) -> Self {
        Self {
            creator,
            federate: true,
            room_version: default_room_version_id(),
            predecessor: None,
            room_type: None,
        }
    }
}

/// An enum of possible room types.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[non_exhaustive]
pub enum RoomType {
    /// Defines the room as a space.
    #[ruma_enum(rename = "m.space")]
    Space,

    /// Defines the room as a custom type.
    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

impl RoomType {
    /// Creates a string slice from this `RoomType`.
    pub fn as_str(&self) -> &str {
        self.as_ref()
    }
}

/// A reference to an old room replaced during a room version upgrade.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct PreviousRoom {
    /// The ID of the old room.
    pub room_id: Box<RoomId>,

    /// The event ID of the last known event in the old room.
    pub event_id: Box<EventId>,
}

impl PreviousRoom {
    /// Creates a new `PreviousRoom` from the given room and event IDs.
    pub fn new(room_id: Box<RoomId>, event_id: Box<EventId>) -> Self {
        Self { room_id, event_id }
    }
}

/// Used to default the `room_version` field to room version 1.
fn default_room_version_id() -> RoomVersionId {
    RoomVersionId::V1
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use ruma_identifiers::{user_id, RoomVersionId};
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{RoomCreateEventContent, RoomType};

    #[test]
    fn serialization() {
        let content = RoomCreateEventContent {
            creator: user_id!("@carl:example.com").to_owned(),
            federate: false,
            room_version: RoomVersionId::V4,
            predecessor: None,
            room_type: None,
        };

        let json = json!({
            "creator": "@carl:example.com",
            "m.federate": false,
            "room_version": "4"
        });

        assert_eq!(to_json_value(&content).unwrap(), json);
    }

    #[test]
    fn space_serialization() {
        let content = RoomCreateEventContent {
            creator: user_id!("@carl:example.com").to_owned(),
            federate: false,
            room_version: RoomVersionId::V4,
            predecessor: None,
            room_type: Some(RoomType::Space),
        };

        let json = json!({
            "creator": "@carl:example.com",
            "m.federate": false,
            "room_version": "4",
            "type": "m.space"
        });

        assert_eq!(to_json_value(&content).unwrap(), json);
    }

    #[test]
    fn deserialization() {
        let json = json!({
            "creator": "@carl:example.com",
            "m.federate": true,
            "room_version": "4"
        });

        assert_matches!(
            from_json_value::<RoomCreateEventContent>(json).unwrap(),
            RoomCreateEventContent {
                creator,
                federate: true,
                room_version: RoomVersionId::V4,
                predecessor: None,
                room_type: None,
            } if creator == "@carl:example.com"
        );
    }

    #[test]
    fn space_deserialization() {
        let json = json!({
            "creator": "@carl:example.com",
            "m.federate": true,
            "room_version": "4",
            "type": "m.space"
        });

        assert_matches!(
            from_json_value::<RoomCreateEventContent>(json).unwrap(),
            RoomCreateEventContent {
                creator,
                federate: true,
                room_version: RoomVersionId::V4,
                predecessor: None,
                room_type
            } if creator == "@carl:example.com" && room_type == Some(RoomType::Space)
        );
    }
}
<|endoftext|>