<commit_before>use falcon_capstone::capstone;
use falcon_capstone::capstone::cs_x86_op;
use falcon_capstone::capstone_sys::{x86_op_type, x86_reg};
use error::*;
use il::*;
use il::Expression as Expr;
use translator::x86::x86register::{get_register, X86Register};

/// Mode used by translators to pick the correct registers/operations
#[derive(Clone, Debug)]
pub(crate) enum Mode {
    X86,
    Amd64
}

impl Mode {
    pub(crate) fn get_register(&self, capstone_id: x86_reg)
        -> Result<&'static X86Register> {

        get_register(self, capstone_id)
    }

    pub(crate) fn bits(&self) -> usize {
        match *self {
            Mode::X86 => 32,
            Mode::Amd64 => 64
        }
    }

    pub(crate) fn sp(&self) -> Scalar {
        match *self {
            Mode::X86 => scalar("esp", 32),
            Mode::Amd64 => scalar("rsp", 64)
        }
    }

    pub(crate) fn get_register_expression(
        &self,
        register: capstone::x86_reg,
        instruction: &capstone::Instr
    ) -> Result<Expression> {
        Ok(match register {
            x86_reg::X86_REG_RIP => expr_const(instruction.address, 64),
            _ => get_register(self, register)?.get()?
        })
    }

    /// Gets the value of an operand as an IL expression
    pub(crate) fn operand_value(
        &self,
        operand: &cs_x86_op,
        instruction: &capstone::Instr
    ) -> Result<Expression> {

        match operand.type_ {
            x86_op_type::X86_OP_INVALID => Err("Invalid operand".into()),
            x86_op_type::X86_OP_REG => {
                // Get the register value
                get_register(self, operand.reg())?.get()
            }
            x86_op_type::X86_OP_MEM => {
                let mem = operand.mem();
                let base_capstone_reg = capstone::x86_reg::from(mem.base);
                let index_capstone_reg = capstone::x86_reg::from(mem.index);

                let base = match base_capstone_reg {
                    x86_reg::X86_REG_INVALID => None,
                    reg => Some(self.get_register_expression(reg, instruction)?)
                };

                let index = match index_capstone_reg {
                    x86_reg::X86_REG_INVALID => None,
                    reg => Some(self.get_register_expression(reg, instruction)?)
                };

                let scale = Expr::constant(
                    Constant::new(mem.scale as i64 as u64, self.bits()));

                let si = match index {
                    Some(index) => Some(Expr::mul(index, scale)?),
                    None => None
                };

                // Handle base and scale/index
                let op : Option<Expression> = if base.is_some() {
                    if si.is_some() {
                        Some(Expr::add(base.unwrap(), si.unwrap())?)
                    }
                    else {
                        base
                    }
                }
                else if si.is_some() {
                    si
                }
                else {
                    None
                };

                // handle disp
                let op = if op.is_some() {
                    if mem.disp > 0 {
                        Expr::add(op.unwrap(),
                                  expr_const(mem.disp as u64, self.bits()))?
                    }
                    else if mem.disp < 0 {
                        Expr::sub(op.unwrap(),
                                  expr_const(mem.disp.abs() as u64, self.bits()))?
                    }
                    else {
                        op.unwrap()
                    }
                }
                else {
                    expr_const(mem.disp as u64, self.bits())
                };

                match x86_reg::from(mem.segment) {
                    x86_reg::X86_REG_INVALID =>
                        Ok(op),
                    x86_reg::X86_REG_CS |
                    x86_reg::X86_REG_DS |
                    x86_reg::X86_REG_ES |
                    x86_reg::X86_REG_FS |
                    x86_reg::X86_REG_GS |
                    x86_reg::X86_REG_SS => {
                        let segment_register =
                            self.get_register(x86_reg::from(mem.segment))?
                            .get()?;
                        Ok(Expr::add(segment_register, op)?)
                    },
                    _ => bail!("invalid segment register")
                }
            },
            x86_op_type::X86_OP_IMM => {
                Ok(expr_const(operand.imm() as u64, operand.size as usize * 8))
            }
            x86_op_type::X86_OP_FP => Err("Unhandled operand".into()),
        }
    }

    /// Gets the value of an operand as an IL expression, performing any required loads as needed.
    pub fn operand_load(
        &self,
        block: &mut Block,
        operand: &cs_x86_op,
        instruction: &capstone::Instr
    ) -> Result<Expression> {

        let op = self.operand_value(operand, instruction)?;

        if operand.type_ == x86_op_type::X86_OP_MEM {
            let temp = block.temp(operand.size as usize * 8);
            block.load(temp.clone(), op);
            return Ok(temp.into());
        }
        Ok(op)
    }

    /// Stores a value in an operand, performing any stores as necessary.
    pub fn operand_store(
        &self,
        mut block: &mut Block,
        operand: &cs_x86_op,
        value: Expression,
        instruction: &capstone::Instr
    ) -> Result<()> {

        match operand.type_ {
            x86_op_type::X86_OP_INVALID =>
                Err("operand_store called on invalid operand".into()),
            x86_op_type::X86_OP_IMM =>
                Err("operand_store called on immediate operand".into()),
            x86_op_type::X86_OP_REG => {
                let dst_register = self.get_register(operand.reg())?;
                dst_register.set(&mut block, value)
            },
            x86_op_type::X86_OP_MEM => {
                let address = self.operand_value(operand, instruction)?;
                block.store(address, value);
                Ok(())
            },
            x86_op_type::X86_OP_FP => {
                Err("operand_store called on fp operand".into())
            }
        }
    }

    /// Convenience function to pop a value off the stack
    pub fn pop_value(&self, block: &mut Block, bits: usize)
        -> Result<Expression> {

        let temp = block.temp(bits);

        block.load(temp.clone(), self.sp().into());
        block.assign(
            self.sp(),
            Expr::add(self.sp().into(), expr_const((bits / 8) as u64, self.bits()))?
        );

        Ok(temp.into())
    }

    /// Convenience function to push a value onto the stack
    pub fn push_value(&self, block: &mut Block, value: Expression)
        -> Result<()> {

        block.assign(
            self.sp(),
            Expr::sub(self.sp().into(),
                      expr_const((value.bits() / 8) as u64, self.bits()))?
        );
        block.store(self.sp().into(), value);
        Ok(())
    }
}<commit_msg>less ambiguous push for x86<commit_after>use falcon_capstone::capstone;
use falcon_capstone::capstone::cs_x86_op;
use falcon_capstone::capstone_sys::{x86_op_type, x86_reg};
use error::*;
use il::*;
use il::Expression as Expr;
use translator::x86::x86register::{get_register, X86Register};

/// Mode used by translators to pick the correct registers/operations
#[derive(Clone, Debug)]
pub(crate) enum Mode {
    X86,
    Amd64
}

impl Mode {
    pub(crate) fn get_register(&self, capstone_id: x86_reg)
        -> Result<&'static X86Register> {

        get_register(self, capstone_id)
    }

    pub(crate) fn bits(&self) -> usize {
        match *self {
            Mode::X86 => 32,
            Mode::Amd64 => 64
        }
    }

    pub(crate) fn sp(&self) -> Scalar {
        match *self {
            Mode::X86 => scalar("esp", 32),
            Mode::Amd64 => scalar("rsp", 64)
        }
    }

    pub(crate) fn get_register_expression(
        &self,
        register: capstone::x86_reg,
        instruction: &capstone::Instr
    ) -> Result<Expression> {
        Ok(match register {
            x86_reg::X86_REG_RIP => expr_const(instruction.address, 64),
            _ => get_register(self, register)?.get()?
        })
    }

    /// Gets the value of an operand as an IL expression
    pub(crate) fn operand_value(
        &self,
        operand: &cs_x86_op,
        instruction: &capstone::Instr
    ) -> Result<Expression> {

        match operand.type_ {
            x86_op_type::X86_OP_INVALID => Err("Invalid operand".into()),
            x86_op_type::X86_OP_REG => {
                // Get the register value
                get_register(self, operand.reg())?.get()
            }
            x86_op_type::X86_OP_MEM => {
                let mem = operand.mem();
                let base_capstone_reg = capstone::x86_reg::from(mem.base);
                let index_capstone_reg = capstone::x86_reg::from(mem.index);

                let base = match base_capstone_reg {
                    x86_reg::X86_REG_INVALID => None,
                    reg => Some(self.get_register_expression(reg, instruction)?)
                };

                let index = match index_capstone_reg {
                    x86_reg::X86_REG_INVALID => None,
                    reg => Some(self.get_register_expression(reg, instruction)?)
                };

                let scale = Expr::constant(
                    Constant::new(mem.scale as i64 as u64, self.bits()));

                let si = match index {
                    Some(index) => Some(Expr::mul(index, scale)?),
                    None => None
                };

                // Handle base and scale/index
                let op : Option<Expression> = if base.is_some() {
                    if si.is_some() {
                        Some(Expr::add(base.unwrap(), si.unwrap())?)
                    }
                    else {
                        base
                    }
                }
                else if si.is_some() {
                    si
                }
                else {
                    None
                };

                // handle disp
                let op = if op.is_some() {
                    if mem.disp > 0 {
                        Expr::add(op.unwrap(),
                                  expr_const(mem.disp as u64, self.bits()))?
                    }
                    else if mem.disp < 0 {
                        Expr::sub(op.unwrap(),
                                  expr_const(mem.disp.abs() as u64, self.bits()))?
                    }
                    else {
                        op.unwrap()
                    }
                }
                else {
                    expr_const(mem.disp as u64, self.bits())
                };

                match x86_reg::from(mem.segment) {
                    x86_reg::X86_REG_INVALID =>
                        Ok(op),
                    x86_reg::X86_REG_CS |
                    x86_reg::X86_REG_DS |
                    x86_reg::X86_REG_ES |
                    x86_reg::X86_REG_FS |
                    x86_reg::X86_REG_GS |
                    x86_reg::X86_REG_SS => {
                        let segment_register =
                            self.get_register(x86_reg::from(mem.segment))?
                            .get()?;
                        Ok(Expr::add(segment_register, op)?)
                    },
                    _ => bail!("invalid segment register")
                }
            },
            x86_op_type::X86_OP_IMM => {
                Ok(expr_const(operand.imm() as u64, operand.size as usize * 8))
            }
            x86_op_type::X86_OP_FP => Err("Unhandled operand".into()),
        }
    }

    /// Gets the value of an operand as an IL expression, performing any required loads as needed.
    pub fn operand_load(
        &self,
        block: &mut Block,
        operand: &cs_x86_op,
        instruction: &capstone::Instr
    ) -> Result<Expression> {

        let op = self.operand_value(operand, instruction)?;

        if operand.type_ == x86_op_type::X86_OP_MEM {
            let temp = block.temp(operand.size as usize * 8);
            block.load(temp.clone(), op);
            return Ok(temp.into());
        }
        Ok(op)
    }

    /// Stores a value in an operand, performing any stores as necessary.
    pub fn operand_store(
        &self,
        mut block: &mut Block,
        operand: &cs_x86_op,
        value: Expression,
        instruction: &capstone::Instr
    ) -> Result<()> {

        match operand.type_ {
            x86_op_type::X86_OP_INVALID =>
                Err("operand_store called on invalid operand".into()),
            x86_op_type::X86_OP_IMM =>
                Err("operand_store called on immediate operand".into()),
            x86_op_type::X86_OP_REG => {
                let dst_register = self.get_register(operand.reg())?;
                dst_register.set(&mut block, value)
            },
            x86_op_type::X86_OP_MEM => {
                let address = self.operand_value(operand, instruction)?;
                block.store(address, value);
                Ok(())
            },
            x86_op_type::X86_OP_FP => {
                Err("operand_store called on fp operand".into())
            }
        }
    }

    /// Convenience function to pop a value off the stack
    pub fn pop_value(&self, block: &mut Block, bits: usize)
        -> Result<Expression> {

        let temp = block.temp(bits);

        block.load(temp.clone(), self.sp().into());
        block.assign(
            self.sp(),
            Expr::add(self.sp().into(), expr_const((bits / 8) as u64, self.bits()))?
        );

        Ok(temp.into())
    }

    /// Convenience function to push a value onto the stack
    pub fn push_value(&self, block: &mut Block, value: Expression)
        -> Result<()> {

        match self {
            Mode::X86 =>
                block.assign(self.sp(), Expr::sub(self.sp().into(), expr_const(4, 32))?),
            Mode::Amd64 =>
                block.assign(self.sp(), Expr::sub(self.sp().into(), expr_const(8, 32))?)
        };

        block.store(self.sp().into(), value);
        Ok(())
    }
}<|endoftext|>


<commit_before>
use std::ops::Fn;
use regex::{Captures, Regex};

/// A Parser is designed to take an input type and turn part of it into an
/// output type.  Probably in every real-life scenario, the input type is a
/// slice of some type.  Thus a parser returns an output type along with another
/// input type, which for slices would be the rest of the data.
pub trait Parser<'a, I, O> {

  fn parse(&self, data: I) -> ParseResult<'a, I, O>;

}

pub type ParseResult<'a, I:'a, O> = Result<(O, I), String>;

pub fn literal<'a, T:'a + Eq + Clone>(literal: T) -> LiteralParser<'a, T>{
  LiteralParser{literal: literal}
}

/// A parser that consumes one item in a slice and only returns ok if it equals
/// the given literal
pub struct LiteralParser<'a, T:'a + Eq + Clone> {
  pub literal: T,
}

impl<'a, T: 'a + Eq + Clone> Parser<'a,  &'a [T], T> for LiteralParser<'a, T> {
  fn parse(&self, data: &'a[T]) -> ParseResult<'a, &'a[T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), data.slice_from(1)))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

/// A string Parser that attempts to consume the given regex
pub struct RegexLiteralParser<'a> {
  pub regex: Regex,
}

impl<'a> Parser<'a, &'a str, ()> for RegexLiteralParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, ()> {
    self.regex.find(data).map(|(_, e)| ((), data.slice_from(e))).ok_or(format!("regex literal match fail"))
  }
}

pub struct RegexCapturesParser<'a> {
  pub regex: Regex,
}
impl<'a> Parser<'a, &'a str, Captures<'a>> for RegexCapturesParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, Captures<'a>> {
    match self.regex.captures(data) {
      Some(caps) => match caps.pos(0) {
        Some((_, e)) => Ok((caps, data.slice_from(e))),
        None => Err(format!("No Match"))
      },
      None => Err(format!("No Match"))
    }
  }
}

/// A slice Parser that matches against the first item in the slice
pub struct MatchParser<'a, I, O> {
  pub matcher: Box< Fn<(&'a I,), Result<O, String>> +'a>
}
impl<'a, I: Clone, O> Parser<'a, &'a [I], O> for MatchParser<'a, I, O> {
  fn parse(&self, data: &'a[I]) -> ParseResult<'a, &'a[I], O> {
    if data.len() < 1 {
      Err(format!("Unexpected End!"))
    } else {
      self.matcher.call((&data[0],)).map(|res| (res, data.slice_from(1)))
    }
  }
}

/// A Parser that will keep repeating the given parser until it returns an
/// error.  The accumulated results are returned.
pub struct RepParser<'a, I, O, P: Parser<'a, I, O>>{
  pub parser: P
}

impl<'a, I: Clone, O, P: Parser<'a, I, O>> Parser<'a, I, Vec<O>> for RepParser<'a, I, O, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

/// A Parser that will repeatedly parse `rep` and `sep` in sequence until `sep`
/// returns an error.  The accumulated `rep` results are returned.  If `rep`
/// returns an error at any time, the error is escelated.
pub struct RepSepParser<'a, I, O, U, A: Parser<'a, I, O>, B: Parser<'a, I, U>> {
  pub rep: A,
  pub sep: B,
  pub min_reps: uint,
}
impl<'a, I: Clone, O, U, A: Parser<'a, I, O>, B: Parser<'a, I, U>> Parser<'a, I, Vec<O>> for RepSepParser<'a, I, O, U, A, B> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.rep.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          match self.sep.parse(rest.clone()) {
            Ok((_, rest2)) => {
              remain = rest2
            }
            Err(_) => {
              if v.len() < self.min_reps {
                return Err(format!("Not enough reps: required {}, got {}", self.min_reps, v.len()))
              } else {
                return Ok((v, rest))
              }
            }
          }
        }
        Err(err) => {
          return Err(format!("Error on rep: {}", err));
        }
      }
    }
    unreachable!()
  }
}

/// A Parser that will combine two parsers into a tuple of results.  If either
/// parser returns an error, the error is escelated (ie partial successes are
/// not returned)
pub struct DualParser<'a, I, A, B, X: Parser<'a, I, A>, Y: Parser<'a, I, B>> {
  pub first: X,
  pub second: Y,
}

impl <'a, I, A, B, X: Parser<'a, I, A>, Y: Parser<'a, I, B>> Parser<'a, I, (A,B)> for DualParser<'a, I, A, B, X, Y> {
  fn parse(&self, data: I) -> ParseResult<'a, I, (A, B)> {
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

//memoization coming sooooon
pub struct LazyParser<'a, I, O> {
  pub generator: Box<Fn() -> Box<Parser<'a, I, O> + 'a> + 'a>
}
impl<'a, I, O> Parser<'a, I, O> for LazyParser<'a, I, O> {
  fn parse(&self, input: I) -> ParseResult<'a, I, O> {
    self.generator.call(()).parse(input)
  }
}

/// A parser that will attempt to parse using parser `a`, and then `b` if
/// the first fails.  The contained parsers are lazy so that we can support recursive
/// grammars.
///
/// In general, the "greedier" parser should be `a`.
pub struct OrParser<'a, I, O, A: Parser<'a, I, O>, B: Parser<'a, I, O>> {
  pub a: A,
  pub b: B,
}

impl<'a, I: Clone, O, A: Parser<'a, I, O>, B: Parser<'a, I, O>> Parser<'a, I, O> for OrParser<'a, I, O, A, B> {
  fn parse(&self, data: I) -> ParseResult<'a, I, O> {
    match self.a.parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.b.parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

/// A Parser that can map the successful result of a parser to another type
pub struct MapParser<'a, I, O, U, P: Parser<'a, I, O>> {
  pub parser: P,
  pub mapper: Box<Fn<(O,), U> + 'a>, //this has to be a &Fn and not a regular lambda since it must be immutable
}
impl<'a, I, O, U, P: Parser<'a, I, O>> Parser<'a, I, U> for MapParser<'a, I, O, U, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, U> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper.call((output,)), input)))
  }
}

/// A Parser that will attempt to use a parser, returning an option of the contained parser's result
pub struct OptionParser<'a, I, O, P: Parser<'a, I, O>> {
  pub parser: P
}
impl<'a, I: Clone, O, P: Parser<'a, I, O>> Parser<'a, I, Option<O>> for OptionParser<'a, I, O, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Option<O>> {
    match self.parser.parse(data.clone()) {
      Ok((result, rest))  => Ok((Some(result), rest)),
      Err(_)              => Ok((None, data)),
    }
  }
}

<commit_msg>remove unnecessary unreachable!()<commit_after>
use std::ops::Fn;
use regex::{Captures, Regex};

/// A Parser is designed to take an input type and turn part of it into an
/// output type.  Probably in every real-life scenario, the input type is a
/// slice of some type.  Thus a parser returns an output type along with another
/// input type, which for slices would be the rest of the data.
pub trait Parser<'a, I, O> {

  fn parse(&self, data: I) -> ParseResult<'a, I, O>;

}

pub type ParseResult<'a, I:'a, O> = Result<(O, I), String>;

pub fn literal<'a, T:'a + Eq + Clone>(literal: T) -> LiteralParser<'a, T>{
  LiteralParser{literal: literal}
}

/// A parser that consumes one item in a slice and only returns ok if it equals
/// the given literal
pub struct LiteralParser<'a, T:'a + Eq + Clone> {
  pub literal: T,
}

impl<'a, T: 'a + Eq + Clone> Parser<'a,  &'a [T], T> for LiteralParser<'a, T> {
  fn parse(&self, data: &'a[T]) -> ParseResult<'a, &'a[T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), data.slice_from(1)))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

/// A string Parser that attempts to consume the given regex
pub struct RegexLiteralParser<'a> {
  pub regex: Regex,
}

impl<'a> Parser<'a, &'a str, ()> for RegexLiteralParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, ()> {
    self.regex.find(data).map(|(_, e)| ((), data.slice_from(e))).ok_or(format!("regex literal match fail"))
  }
}

pub struct RegexCapturesParser<'a> {
  pub regex: Regex,
}
impl<'a> Parser<'a, &'a str, Captures<'a>> for RegexCapturesParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, Captures<'a>> {
    match self.regex.captures(data) {
      Some(caps) => match caps.pos(0) {
        Some((_, e)) => Ok((caps, data.slice_from(e))),
        None => Err(format!("No Match"))
      },
      None => Err(format!("No Match"))
    }
  }
}

/// A slice Parser that matches against the first item in the slice
pub struct MatchParser<'a, I, O> {
  pub matcher: Box< Fn<(&'a I,), Result<O, String>> +'a>
}
impl<'a, I: Clone, O> Parser<'a, &'a [I], O> for MatchParser<'a, I, O> {
  fn parse(&self, data: &'a[I]) -> ParseResult<'a, &'a[I], O> {
    if data.len() < 1 {
      Err(format!("Unexpected End!"))
    } else {
      self.matcher.call((&data[0],)).map(|res| (res, data.slice_from(1)))
    }
  }
}

/// A Parser that will keep repeating the given parser until it returns an
/// error.  The accumulated results are returned.
pub struct RepParser<'a, I, O, P: Parser<'a, I, O>>{
  pub parser: P
}

impl<'a, I: Clone, O, P: Parser<'a, I, O>> Parser<'a, I, Vec<O>> for RepParser<'a, I, O, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

/// A Parser that will repeatedly parse `rep` and `sep` in sequence until `sep`
/// returns an error.  The accumulated `rep` results are returned.  If `rep`
/// returns an error at any time, the error is escelated.
pub struct RepSepParser<'a, I, O, U, A: Parser<'a, I, O>, B: Parser<'a, I, U>> {
  pub rep: A,
  pub sep: B,
  pub min_reps: uint,
}
impl<'a, I: Clone, O, U, A: Parser<'a, I, O>, B: Parser<'a, I, U>> Parser<'a, I, Vec<O>> for RepSepParser<'a, I, O, U, A, B> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.rep.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          match self.sep.parse(rest.clone()) {
            Ok((_, rest2)) => {
              remain = rest2
            }
            Err(_) => {
              if v.len() < self.min_reps {
                return Err(format!("Not enough reps: required {}, got {}", self.min_reps, v.len()))
              } else {
                return Ok((v, rest))
              }
            }
          }
        }
        Err(err) => {
          return Err(format!("Error on rep: {}", err));
        }
      }
    }
  }
}

/// A Parser that will combine two parsers into a tuple of results.  If either
/// parser returns an error, the error is escelated (ie partial successes are
/// not returned)
pub struct DualParser<'a, I, A, B, X: Parser<'a, I, A>, Y: Parser<'a, I, B>> {
  pub first: X,
  pub second: Y,
}

impl <'a, I, A, B, X: Parser<'a, I, A>, Y: Parser<'a, I, B>> Parser<'a, I, (A,B)> for DualParser<'a, I, A, B, X, Y> {
  fn parse(&self, data: I) -> ParseResult<'a, I, (A, B)> {
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

//memoization coming sooooon
pub struct LazyParser<'a, I, O> {
  pub generator: Box<Fn() -> Box<Parser<'a, I, O> + 'a> + 'a>
}
impl<'a, I, O> Parser<'a, I, O> for LazyParser<'a, I, O> {
  fn parse(&self, input: I) -> ParseResult<'a, I, O> {
    self.generator.call(()).parse(input)
  }
}

/// A parser that will attempt to parse using parser `a`, and then `b` if
/// the first fails.  The contained parsers are lazy so that we can support recursive
/// grammars.
///
/// In general, the "greedier" parser should be `a`.
pub struct OrParser<'a, I, O, A: Parser<'a, I, O>, B: Parser<'a, I, O>> {
  pub a: A,
  pub b: B,
}

impl<'a, I: Clone, O, A: Parser<'a, I, O>, B: Parser<'a, I, O>> Parser<'a, I, O> for OrParser<'a, I, O, A, B> {
  fn parse(&self, data: I) -> ParseResult<'a, I, O> {
    match self.a.parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.b.parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

/// A Parser that can map the successful result of a parser to another type
pub struct MapParser<'a, I, O, U, P: Parser<'a, I, O>> {
  pub parser: P,
  pub mapper: Box<Fn<(O,), U> + 'a>, //this has to be a &Fn and not a regular lambda since it must be immutable
}
impl<'a, I, O, U, P: Parser<'a, I, O>> Parser<'a, I, U> for MapParser<'a, I, O, U, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, U> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper.call((output,)), input)))
  }
}

/// A Parser that will attempt to use a parser, returning an option of the contained parser's result
pub struct OptionParser<'a, I, O, P: Parser<'a, I, O>> {
  pub parser: P
}
impl<'a, I: Clone, O, P: Parser<'a, I, O>> Parser<'a, I, Option<O>> for OptionParser<'a, I, O, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Option<O>> {
    match self.parser.parse(data.clone()) {
      Ok((result, rest))  => Ok((Some(result), rest)),
      Err(_)              => Ok((None, data)),
    }
  }
}

<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// 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.

//! aws ec2 metadata fetcher
//!
use errors::*;
use metadata::Metadata;
use retry;

#[cfg(test)]
mod mock_tests;
#[cfg(test)]
use self::mock_tests::URL;

#[cfg(not(test))]
const URL: &'static str = "http://169.254.169.254/2009-04-04";

fn url_for_key(key: &str) -> String {
    format!("{}/{}", URL, key)
}

#[allow(non_snake_case)]
#[derive(Debug, Deserialize)]
struct InstanceIdDoc {
    region: String,
}

pub fn fetch_metadata() -> Result<Metadata> {
    let client = retry::Client::new()
        .chain_err(|| "ec2: failed to create http client")?
        .return_on_404(true);

    let instance_id: Option<String> = client.get(retry::Raw, url_for_key("meta-data/instance-id")).send()?;
    let public: Option<String> = client.get(retry::Raw, url_for_key("meta-data/public-ipv4")).send()?;
    let local: Option<String> = client.get(retry::Raw, url_for_key("meta-data/local-ipv4")).send()?;
    let hostname: Option<String> = client.get(retry::Raw, url_for_key("meta-data/hostname")).send()?;
    let availability_zone: Option<String> = client.get(retry::Raw, url_for_key("meta-data/placement/availability-zone")).send()?;
    let region: Option<String> = client.get(retry::Json, url_for_key("dynamic/instance-identity/document")).send()?
        .map(|instance_id_doc: InstanceIdDoc| instance_id_doc.region);

    let ssh_keys: Vec<String> = fetch_ssh_keys(&client)?;

    Ok(Metadata::builder()
        .add_attribute_if_exists("EC2_REGION".to_owned(), region)
        .add_attribute_if_exists("EC2_INSTANCE_ID".to_owned(), instance_id)
        .add_attribute_if_exists("EC2_IPV4_PUBLIC".to_owned(), public)
        .add_attribute_if_exists("EC2_IPV4_LOCAL".to_owned(), local)
        .add_attribute_if_exists("EC2_HOSTNAME".to_owned(), hostname.clone())
        .add_attribute_if_exists("EC2_AVAILABILITY_ZONE".to_owned(), availability_zone)
        .set_hostname_if_exists(hostname)
        .add_ssh_keys(ssh_keys)?
        .build())
}

fn fetch_ssh_keys(client: &retry::Client) -> Result<Vec<String>> {
    let keydata: Option<String> = client.get(retry::Raw, url_for_key("meta-data/public-keys")).send()?;
    match keydata {
        Some(s) => {
            let mut res = Ok(Vec::new());
            for keyname in s.split_whitespace() {
                let tokens: Vec<&str> = keyname.split('=').collect();
                if tokens.len() != 2 {
                    res = Err("malformed public key".into());
                    break;
                }
                let ssh_key: String = client.get(retry::Raw, url_for_key(&format!("meta-data/public-keys/{}/openssh-key", tokens[0]))).send()?
                    .ok_or("missing ssh key")?;
                if let Ok(keys) = res.as_mut() {
                    keys.push(ssh_key);
                }
            }
            res
        }
        None => {
            Ok(Vec::new())
        }
    }
}
<commit_msg>providers/ec2: refactor fetch_ssh_keys<commit_after>// Copyright 2017 CoreOS, Inc.
//
// 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.

//! aws ec2 metadata fetcher
//!
use errors::*;
use metadata::Metadata;
use retry;

#[cfg(test)]
mod mock_tests;
#[cfg(test)]
use self::mock_tests::URL;

#[cfg(not(test))]
const URL: &'static str = "http://169.254.169.254/2009-04-04";

fn url_for_key(key: &str) -> String {
    format!("{}/{}", URL, key)
}

#[allow(non_snake_case)]
#[derive(Debug, Deserialize)]
struct InstanceIdDoc {
    region: String,
}

pub fn fetch_metadata() -> Result<Metadata> {
    let client = retry::Client::new()
        .chain_err(|| "ec2: failed to create http client")?
        .return_on_404(true);

    let instance_id: Option<String> = client.get(retry::Raw, url_for_key("meta-data/instance-id")).send()?;
    let public: Option<String> = client.get(retry::Raw, url_for_key("meta-data/public-ipv4")).send()?;
    let local: Option<String> = client.get(retry::Raw, url_for_key("meta-data/local-ipv4")).send()?;
    let hostname: Option<String> = client.get(retry::Raw, url_for_key("meta-data/hostname")).send()?;
    let availability_zone: Option<String> = client.get(retry::Raw, url_for_key("meta-data/placement/availability-zone")).send()?;
    let region: Option<String> = client.get(retry::Json, url_for_key("dynamic/instance-identity/document")).send()?
        .map(|instance_id_doc: InstanceIdDoc| instance_id_doc.region);

    let ssh_keys: Vec<String> = fetch_ssh_keys(&client)?;

    Ok(Metadata::builder()
        .add_attribute_if_exists("EC2_REGION".to_owned(), region)
        .add_attribute_if_exists("EC2_INSTANCE_ID".to_owned(), instance_id)
        .add_attribute_if_exists("EC2_IPV4_PUBLIC".to_owned(), public)
        .add_attribute_if_exists("EC2_IPV4_LOCAL".to_owned(), local)
        .add_attribute_if_exists("EC2_HOSTNAME".to_owned(), hostname.clone())
        .add_attribute_if_exists("EC2_AVAILABILITY_ZONE".to_owned(), availability_zone)
        .set_hostname_if_exists(hostname)
        .add_ssh_keys(ssh_keys)?
        .build())
}

fn fetch_ssh_keys(client: &retry::Client) -> Result<Vec<String>> {
    let keydata: Option<String> = client.get(retry::Raw, url_for_key("meta-data/public-keys")).send()?;
    let mut keys = Vec::new();
    if let Some(keys_list) = keydata {
        for l in keys_list.lines() {
            let tokens: Vec<&str> = l.split('=').collect();
            if tokens.len() != 2 {
                return Err("error parsing keyID".into());
            }
            let key: String = client.get(retry::Raw, url_for_key(&format!("meta-data/public-keys/{}/openssh-key", tokens[0]))).send()?
                    .ok_or("missing ssh key")?;
            keys.push(key)
        }
    }
    Ok(keys)
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// 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.

//! google compute engine metadata fetcher

use std::collections::HashMap;

use openssh_keys::PublicKey;
use update_ssh_keys::AuthorizedKeyEntry;

use errors::*;
use network;
use providers::MetadataProvider;
use retry;

header! {(MetadataFlavor, "Metadata-Flavor") => [String]}
const GOOGLE: &str = "Google";

#[derive(Clone, Debug)]
pub struct GceProvider {
    client: retry::Client,
}

impl GceProvider {
    pub fn new() -> Result<GceProvider> {
        let client = retry::Client::new()?
            .header(MetadataFlavor(GOOGLE.to_owned()))
            .return_on_404(true);

        Ok(GceProvider { client })
    }

    fn endpoint_for(name: &str) -> String {
        format!("http://metadata.google.internal/computeMetadata/v1/{}", name)
    }

    fn fetch_all_ssh_keys(&self) -> Result<Vec<String>> {
        let keys = self.fetch_ssh_keys("instance/attributes/sshKeys")?;
        if !keys.is_empty() {
            return Ok(keys);
        }
        let mut keys = self.fetch_ssh_keys("instance/attributes/ssh-keys")?;

        let block_project_keys: Option<String> = self.client
            .clone()
            .get(retry::Raw, GceProvider::endpoint_for("instance/attributes/block-project-ssh-keys"))
            .send()?;

        if block_project_keys == Some("true".to_owned()) {
            return Ok(keys);
        }

        keys.append(&mut self.fetch_ssh_keys("project/attributes/sshKeys")?);

        Ok(keys)
    }

    fn fetch_ssh_keys(&self, key: &str) -> Result<Vec<String>> {
        let key_data: Option<String> = self.client.get(retry::Raw, GceProvider::endpoint_for(key)).send()?;
        if let Some(key_data) = key_data {
            let mut keys = Vec::new();
            for l in key_data.lines() {
                if l.is_empty() {
                    continue
                }
                let mut l = l.to_owned();
                let index = l.find(':')
                    .ok_or("character ':' not found in line in key data")?;
                keys.push(l.split_off(index+1));
            }
            Ok(keys)
        } else {
            // The user must have not provided any keys
            Ok(Vec::new())
        }
    }
}

impl MetadataProvider for GceProvider {
    fn attributes(&self) -> Result<HashMap<String, String>> {
        let mut out = HashMap::with_capacity(3);

        let add_value = |map: &mut HashMap<_, _>, key: &str, name| -> Result<()> {
            let value: Option<String> = self.client.get(retry::Raw, GceProvider::endpoint_for(name)).send()?;

            if let Some(value) = value {
                if !value.is_empty() {
                    map.insert(key.to_string(), value);
                }
            }

            Ok(())
        };

        add_value(&mut out, "GCE_HOSTNAME", "instance/hostname")?;
        add_value(&mut out, "GCE_IP_EXTERNAL_0", "instance/network-interfaces/0/access-configs/0/external-ip")?;
        add_value(&mut out, "GCE_IP_LOCAL_0", "instance/network-interfaces/0/ip")?;

        Ok(out)
    }

    fn hostname(&self) -> Result<Option<String>> {
        self.client.get(retry::Raw, GceProvider::endpoint_for("instance/hostname")).send()
    }

    fn ssh_keys(&self) -> Result<Vec<AuthorizedKeyEntry>> {
        let mut out = Vec::new();

        for key in &self.fetch_all_ssh_keys()? {
            let key = PublicKey::parse(&key)?;
            out.push(AuthorizedKeyEntry::Valid{key});
        }

        Ok(out)
    }

    fn networks(&self) -> Result<Vec<network::Interface>> {
        Ok(vec![])
    }

    fn network_devices(&self) -> Result<Vec<network::Device>> {
        Ok(vec![])
    }
}
<commit_msg>providers/gcp: scrape new endpoint for ssh keys<commit_after>// Copyright 2017 CoreOS, Inc.
//
// 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.

//! google compute engine metadata fetcher

use std::collections::HashMap;

use openssh_keys::PublicKey;
use update_ssh_keys::AuthorizedKeyEntry;

use errors::*;
use network;
use providers::MetadataProvider;
use retry;

header! {(MetadataFlavor, "Metadata-Flavor") => [String]}
const GOOGLE: &str = "Google";

#[derive(Clone, Debug)]
pub struct GceProvider {
    client: retry::Client,
}

impl GceProvider {
    pub fn new() -> Result<GceProvider> {
        let client = retry::Client::new()?
            .header(MetadataFlavor(GOOGLE.to_owned()))
            .return_on_404(true);

        Ok(GceProvider { client })
    }

    fn endpoint_for(name: &str) -> String {
        format!("http://metadata.google.internal/computeMetadata/v1/{}", name)
    }

    fn fetch_all_ssh_keys(&self) -> Result<Vec<String>> {
        // The Google metadata API has a total of 4 endpoints to retrieve SSH keys from:
        // First, there are instance-level and project-level SSH keys.
        // Additionally, there are two attributes on both levels where these are stored, one called
        // `sshKeys`, and one called `ssh-keys`. The former is considered deprecated on both levels
        // but it can still be found in some setups, therefore we have to handle that.
        // https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys

        // Instance-level, old endpoint
        // If there are any of these, don't do anything else.
        let keys = self.fetch_ssh_keys("instance/attributes/sshKeys")?;
        if !keys.is_empty() {
            return Ok(keys);
        }
        // Instance-level, new endpoint
        let mut keys = self.fetch_ssh_keys("instance/attributes/ssh-keys")?;

        let block_project_keys: Option<String> = self.client
            .clone()
            .get(retry::Raw, GceProvider::endpoint_for("instance/attributes/block-project-ssh-keys"))
            .send()?;

        if block_project_keys == Some("true".to_owned()) {
            return Ok(keys);
        }

        // Project-level, old endpoint
        keys.append(&mut self.fetch_ssh_keys("project/attributes/sshKeys")?);
        // Project-level, new endpoint
        keys.append(&mut self.fetch_ssh_keys("project/attributes/ssh-keys")?);

        Ok(keys)
    }

    fn fetch_ssh_keys(&self, key: &str) -> Result<Vec<String>> {
        let key_data: Option<String> = self.client.get(retry::Raw, GceProvider::endpoint_for(key)).send()?;
        if let Some(key_data) = key_data {
            let mut keys = Vec::new();
            for l in key_data.lines() {
                if l.is_empty() {
                    continue
                }
                let mut l = l.to_owned();
                let index = l.find(':')
                    .ok_or("character ':' not found in line in key data")?;
                keys.push(l.split_off(index+1));
            }
            Ok(keys)
        } else {
            // The user must have not provided any keys
            Ok(Vec::new())
        }
    }
}

impl MetadataProvider for GceProvider {
    fn attributes(&self) -> Result<HashMap<String, String>> {
        let mut out = HashMap::with_capacity(3);

        let add_value = |map: &mut HashMap<_, _>, key: &str, name| -> Result<()> {
            let value: Option<String> = self.client.get(retry::Raw, GceProvider::endpoint_for(name)).send()?;

            if let Some(value) = value {
                if !value.is_empty() {
                    map.insert(key.to_string(), value);
                }
            }

            Ok(())
        };

        add_value(&mut out, "GCE_HOSTNAME", "instance/hostname")?;
        add_value(&mut out, "GCE_IP_EXTERNAL_0", "instance/network-interfaces/0/access-configs/0/external-ip")?;
        add_value(&mut out, "GCE_IP_LOCAL_0", "instance/network-interfaces/0/ip")?;

        Ok(out)
    }

    fn hostname(&self) -> Result<Option<String>> {
        self.client.get(retry::Raw, GceProvider::endpoint_for("instance/hostname")).send()
    }

    fn ssh_keys(&self) -> Result<Vec<AuthorizedKeyEntry>> {
        let mut out = Vec::new();

        for key in &self.fetch_all_ssh_keys()? {
            let key = PublicKey::parse(&key)?;
            out.push(AuthorizedKeyEntry::Valid{key});
        }

        Ok(out)
    }

    fn networks(&self) -> Result<Vec<network::Interface>> {
        Ok(vec![])
    }

    fn network_devices(&self) -> Result<Vec<network::Device>> {
        Ok(vec![])
    }
}
<|endoftext|>


<commit_before>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

pub trait PrettyPrint {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> ();
    fn pretty_print(&self) -> String {
        let mut pretty_printed = String::new();
        &self.pretty_print_into(&mut pretty_printed);
        pretty_printed
    }
}

impl PrettyPrint for Expr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &Expr::Literal(ref l) => l.pretty_print_into(pretty_printed),
            &Expr::Unary(ref u) => u.pretty_print_into(pretty_printed),
            &Expr::Binary(ref b) => b.pretty_print_into(pretty_printed),
            &Expr::Grouping(ref g) => g.pretty_print_into(pretty_printed),
        }
    }
}

impl PrettyPrint for UnaryOperator {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &UnaryOperator::Bang => pretty_printed.push_str("!"),
            &UnaryOperator::Minus => pretty_printed.push_str("-"),
        }
    }
}

impl PrettyPrint for BinaryOperator {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &BinaryOperator::Minus => pretty_printed.push_str("-"),
            &BinaryOperator::Plus => pretty_printed.push_str("+"),
            &BinaryOperator::Slash => pretty_printed.push_str("/"),
            &BinaryOperator::Star => pretty_printed.push_str("*"),
            &BinaryOperator::Equal => pretty_printed.push_str("=="),
            &BinaryOperator::NotEqual => pretty_printed.push_str("!="),
            &BinaryOperator::Less => pretty_printed.push_str("<"),
            &BinaryOperator::LessEqual => pretty_printed.push_str("<="),
            &BinaryOperator::Greater => pretty_printed.push_str(">"),
            &BinaryOperator::GreaterEqual => pretty_printed.push_str(">="),
        }
    }
}

impl PrettyPrint for Literal {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match self {
            &Literal::NilLiteral => pretty_printed.push_str("null"),
            &Literal::BoolLiteral(ref b) => pretty_printed.push_str(&b.to_string()),
            &Literal::StringLiteral(ref s) => pretty_printed.push_str(s),
            &Literal::NumberLiteral(n) => pretty_printed.push_str(&n.to_string()),
        }
    }
}

impl PrettyPrint for Grouping {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(group ");
        &self.expr.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

impl PrettyPrint for UnaryExpr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(");
        &self.operator.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        &self.right.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

impl PrettyPrint for BinaryExpr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(");
        &self.operator.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        &self.left.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        &self.right.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let string = String::from("abc");
        let expr = Expr::Literal(Literal::StringLiteral(string.clone()));
        assert_eq!(string, expr.pretty_print());
    }

    #[test]
    fn complex_expression() {
        let subexpr1 = UnaryExpr {
            operator: UnaryOperator::Minus,
            right: Expr::Literal(Literal::NumberLiteral(123f64)),
        };
        let subexpr2 = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        let binary_expr = BinaryExpr {
            left: Expr::Unary(Box::new(subexpr1)),
            operator: BinaryOperator::Star,
            right: Expr::Grouping(Box::new(subexpr2)),
        };
        let expr = Expr::Binary(Box::new(binary_expr));
        assert_eq!("(* (- 123) (group 45.67))", &expr.pretty_print());
    }
}
<commit_msg>[clippy] removed uselss &<commit_after>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

pub trait PrettyPrint {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> ();
    fn pretty_print(&self) -> String {
        let mut pretty_printed = String::new();
        self.pretty_print_into(&mut pretty_printed);
        pretty_printed
    }
}

impl PrettyPrint for Expr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match *self {
            Expr::Literal(ref l) => l.pretty_print_into(pretty_printed),
            Expr::Unary(ref u) => u.pretty_print_into(pretty_printed),
            Expr::Binary(ref b) => b.pretty_print_into(pretty_printed),
            Expr::Grouping(ref g) => g.pretty_print_into(pretty_printed),
        }
    }
}

impl PrettyPrint for UnaryOperator {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match *self {
            UnaryOperator::Bang => pretty_printed.push_str("!"),
            UnaryOperator::Minus => pretty_printed.push_str("-"),
        }
    }
}

impl PrettyPrint for BinaryOperator {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match *self {
            BinaryOperator::Minus => pretty_printed.push_str("-"),
            BinaryOperator::Plus => pretty_printed.push_str("+"),
            BinaryOperator::Slash => pretty_printed.push_str("/"),
            BinaryOperator::Star => pretty_printed.push_str("*"),
            BinaryOperator::Equal => pretty_printed.push_str("=="),
            BinaryOperator::NotEqual => pretty_printed.push_str("!="),
            BinaryOperator::Less => pretty_printed.push_str("<"),
            BinaryOperator::LessEqual => pretty_printed.push_str("<="),
            BinaryOperator::Greater => pretty_printed.push_str(">"),
            BinaryOperator::GreaterEqual => pretty_printed.push_str(">="),
        }
    }
}

impl PrettyPrint for Literal {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        match *self {
            Literal::NilLiteral => pretty_printed.push_str("null"),
            Literal::BoolLiteral(ref b) => pretty_printed.push_str(&b.to_string()),
            Literal::StringLiteral(ref s) => pretty_printed.push_str(s),
            Literal::NumberLiteral(n) => pretty_printed.push_str(&n.to_string()),
        }
    }
}

impl PrettyPrint for Grouping {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(group ");
        self.expr.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

impl PrettyPrint for UnaryExpr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(");
        self.operator.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        self.right.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

impl PrettyPrint for BinaryExpr {
    fn pretty_print_into(&self, pretty_printed: &mut String) -> () {
        pretty_printed.push_str("(");
        self.operator.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        self.left.pretty_print_into(pretty_printed);
        pretty_printed.push_str(" ");
        self.right.pretty_print_into(pretty_printed);
        pretty_printed.push_str(")");
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let string = String::from("abc");
        let expr = Expr::Literal(Literal::StringLiteral(string.clone()));
        assert_eq!(string, expr.pretty_print());
    }

    #[test]
    fn complex_expression() {
        let subexpr1 = UnaryExpr {
            operator: UnaryOperator::Minus,
            right: Expr::Literal(Literal::NumberLiteral(123f64)),
        };
        let subexpr2 = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        let binary_expr = BinaryExpr {
            left: Expr::Unary(Box::new(subexpr1)),
            operator: BinaryOperator::Star,
            right: Expr::Grouping(Box::new(subexpr2)),
        };
        let expr = Expr::Binary(Box::new(binary_expr));
        assert_eq!("(* (- 123) (group 45.67))", &expr.pretty_print());
    }
}
<|endoftext|>


<commit_before>use serialize::json;
use serialize::json::{Json};
use serialize::json::ToJson;

use mutable_json::MutableJson;
use helpers::{object_from_list, next_index, create_array, push_item_to_array};

fn merge_object_and_array(to: &mut Json, from: &Json) -> Option<Json> {
    let tree = to.as_object_mut().unwrap();
    let vec = from.as_list().unwrap();
    let index = next_index(tree);

    for (idx, item) in vec.iter().enumerate() {
        tree.insert((index + idx).to_string(), item.clone());
    }

    None
}

fn merge_object_and_merger(to: &mut Json, from: &Json) -> Option<Json> {

    let to_tree = to.as_object_mut().unwrap();
    let from_tree = from.as_object().unwrap();

    let to_index = from_tree.find(&"__idx".to_string()).unwrap().as_u64().unwrap().to_string();
    let source_obj = from_tree.find(&"__object".to_string()).unwrap();
    let has_dest_obj = {
        match to_tree.find(&to_index) {
            Some(&json::Object(_)) => true,
            Some(&json::List(_)) => true,
            Some(_) => false,
            None => false
        }
    };

    if has_dest_obj {
        let merge_result = merge(to_tree.find_mut(&to_index).unwrap(), source_obj);
        match merge_result {
            Some(result) => { to_tree.insert(to_index, result); },
            None => ()
        }
    } else {
        to_tree.insert(to_index, source_obj.clone());
    }

    None
}

fn merge_object_and_object(to: &mut Json, from: &Json) -> Option<Json> {
    let to_tree = to.as_object_mut().unwrap();
    let from_tree = from.as_object().unwrap();

    for (key, value) in from_tree.iter() {
        let has_dest_obj = {
            match to_tree.find(key) {
                Some(_) => true,
                None => false
            }
        };

        if has_dest_obj {
            let merge_result = merge(to_tree.find_mut(key).unwrap(), value);
            match merge_result {
                Some(result) => { to_tree.insert(key.to_string(), result); },
                None => ()
            }
        } else {
            let value = if is_merger(value) {
                let mut list = create_array();
                merge(&mut list, value).unwrap_or(list)
            } else {
                value.clone()
            };
            to_tree.insert(key.to_string(), value);
        }

    }

    None
}

fn merge_list_and_list(to: &mut Json, from: &Json) -> Option<Json> {
    let to_vec = to.as_list_mut().unwrap();
    let from_vec = from.as_list().unwrap();

    for value in from_vec.iter() {
        to_vec.push(value.clone());
    }

    None
}

fn merge_list_and_merger(to: &mut Json, from: &Json) -> Option<Json> {

    let to_vec = to.as_list_mut().unwrap();

    let from_tree = from.as_object().unwrap();
    let to_index = from_tree.find(&"__idx".to_string()).unwrap().as_u64().unwrap() as uint;
    let source_obj = from_tree.find(&"__object".to_string()).unwrap();

    if to_index < to_vec.len() {
        // merge existing item
        let merge_result = merge(&mut to_vec[to_index], source_obj);
        match merge_result {
            Some(result) => {
                to_vec.remove(to_index);
                to_vec.insert(to_index, result);
            },
            None => ()
        }
        None
    } else if to_index == to_vec.len() {
        to_vec.insert(to_index, source_obj.clone());
        None
    } else {
        let mut new_obj = object_from_list(&to_vec.to_json());
        merge_object_and_merger(&mut new_obj, from);
        return Some(new_obj);
    }
}

fn is_merger(obj: &Json) -> bool {
    if !obj.is_object() {
        return false;
    }

    let tree = obj.as_object().unwrap();
    let idx = tree.find(&"__idx".to_string());
    match idx {
        Some(idx) => idx.is_number(),
        None => false
    }
}

fn merge_list_and_object(to: &mut Json, from: &Json) -> Option<Json> {
    let mut to_tree = object_from_list(to);
    merge(&mut to_tree, from);
    Some(to_tree)
}

fn merge_string_and_json(to: &mut Json, from: &Json) -> Option<Json> {
    let mut list = create_array();
    push_item_to_array(&mut list, to.clone());
    push_item_to_array(&mut list, from.clone());

    Some(list)
}

fn merge_list_and_string(to: &mut Json, from: &Json) -> Option<Json> {
    push_item_to_array(to, from.clone());
    None
}

pub fn merge(to: &mut Json, from: &Json) -> Option<Json> {

    match to {
        &json::Object(_) => {
            match from {
                &json::List(_) => merge_object_and_array(to, from),
                &json::Object(_) if is_merger(from) => merge_object_and_merger(to, from),
                &json::Object(_) => merge_object_and_object(to, from),
                &json::String(_) => return Some(from.clone()),
                _ => panic!("Unknown merge")
            }
        }
        &json::List(_) => {
            match from {
                &json::List(_) => merge_list_and_list(to, from),
                &json::Object(_) if is_merger(from) => merge_list_and_merger(to, from),
                &json::Object(_) => merge_list_and_object(to, from),
                &json::String(_) => merge_list_and_string(to, from),
                _ => panic!("Unknown merge")
            }
        },
        &json::String(_) => {
            return merge_string_and_json(to, from)
        }
        _ => panic!("Unknown merge")
    }

} <commit_msg>refactor: rustup<commit_after>use serialize::json;
use serialize::json::{Json};
use serialize::json::ToJson;

use mutable_json::MutableJson;
use helpers::{object_from_list, next_index, create_array, push_item_to_array};

fn merge_object_and_array(to: &mut Json, from: &Json) -> Option<Json> {
    let tree = to.as_object_mut().unwrap();
    let vec = from.as_list().unwrap();
    let index = next_index(tree);

    for (idx, item) in vec.iter().enumerate() {
        tree.insert((index + idx).to_string(), item.clone());
    }

    None
}

fn merge_object_and_merger(to: &mut Json, from: &Json) -> Option<Json> {

    let to_tree = to.as_object_mut().unwrap();
    let from_tree = from.as_object().unwrap();

    let to_index = from_tree.get(&"__idx".to_string()).unwrap().as_u64().unwrap().to_string();
    let source_obj = from_tree.get(&"__object".to_string()).unwrap();
    let has_dest_obj = {
        match to_tree.get(&to_index) {
            Some(&json::Object(_)) => true,
            Some(&json::List(_)) => true,
            Some(_) => false,
            None => false
        }
    };

    if has_dest_obj {
        let merge_result = merge(to_tree.get_mut(&to_index).unwrap(), source_obj);
        match merge_result {
            Some(result) => { to_tree.insert(to_index, result); },
            None => ()
        }
    } else {
        to_tree.insert(to_index, source_obj.clone());
    }

    None
}

fn merge_object_and_object(to: &mut Json, from: &Json) -> Option<Json> {
    let to_tree = to.as_object_mut().unwrap();
    let from_tree = from.as_object().unwrap();

    for (key, value) in from_tree.iter() {
        let has_dest_obj = {
            match to_tree.get(key) {
                Some(_) => true,
                None => false
            }
        };

        if has_dest_obj {
            let merge_result = merge(to_tree.get_mut(key).unwrap(), value);
            match merge_result {
                Some(result) => { to_tree.insert(key.to_string(), result); },
                None => ()
            }
        } else {
            let value = if is_merger(value) {
                let mut list = create_array();
                merge(&mut list, value).unwrap_or(list)
            } else {
                value.clone()
            };
            to_tree.insert(key.to_string(), value);
        }

    }

    None
}

fn merge_list_and_list(to: &mut Json, from: &Json) -> Option<Json> {
    let to_vec = to.as_list_mut().unwrap();
    let from_vec = from.as_list().unwrap();

    for value in from_vec.iter() {
        to_vec.push(value.clone());
    }

    None
}

fn merge_list_and_merger(to: &mut Json, from: &Json) -> Option<Json> {

    let to_vec = to.as_list_mut().unwrap();

    let from_tree = from.as_object().unwrap();
    let to_index = from_tree.get(&"__idx".to_string()).unwrap().as_u64().unwrap() as uint;
    let source_obj = from_tree.get(&"__object".to_string()).unwrap();

    if to_index < to_vec.len() {
        // merge existing item
        let merge_result = merge(&mut to_vec[to_index], source_obj);
        match merge_result {
            Some(result) => {
                to_vec.remove(to_index);
                to_vec.insert(to_index, result);
            },
            None => ()
        }
        None
    } else if to_index == to_vec.len() {
        to_vec.insert(to_index, source_obj.clone());
        None
    } else {
        let mut new_obj = object_from_list(&to_vec.to_json());
        merge_object_and_merger(&mut new_obj, from);
        return Some(new_obj);
    }
}

fn is_merger(obj: &Json) -> bool {
    if !obj.is_object() {
        return false;
    }

    let tree = obj.as_object().unwrap();
    let idx = tree.get(&"__idx".to_string());
    match idx {
        Some(idx) => idx.is_number(),
        None => false
    }
}

fn merge_list_and_object(to: &mut Json, from: &Json) -> Option<Json> {
    let mut to_tree = object_from_list(to);
    merge(&mut to_tree, from);
    Some(to_tree)
}

fn merge_string_and_json(to: &mut Json, from: &Json) -> Option<Json> {
    let mut list = create_array();
    push_item_to_array(&mut list, to.clone());
    push_item_to_array(&mut list, from.clone());

    Some(list)
}

fn merge_list_and_string(to: &mut Json, from: &Json) -> Option<Json> {
    push_item_to_array(to, from.clone());
    None
}

pub fn merge(to: &mut Json, from: &Json) -> Option<Json> {

    match to {
        &json::Object(_) => {
            match from {
                &json::List(_) => merge_object_and_array(to, from),
                &json::Object(_) if is_merger(from) => merge_object_and_merger(to, from),
                &json::Object(_) => merge_object_and_object(to, from),
                &json::String(_) => return Some(from.clone()),
                _ => panic!("Unknown merge")
            }
        }
        &json::List(_) => {
            match from {
                &json::List(_) => merge_list_and_list(to, from),
                &json::Object(_) if is_merger(from) => merge_list_and_merger(to, from),
                &json::Object(_) => merge_list_and_object(to, from),
                &json::String(_) => merge_list_and_string(to, from),
                _ => panic!("Unknown merge")
            }
        },
        &json::String(_) => {
            return merge_string_and_json(to, from)
        }
        _ => panic!("Unknown merge")
    }

} <|endoftext|>


<commit_before>use std::ptr;
use glib::Error;
use glib::object::{Object, Upcast, Wrapper, Ref};
use glib::types::{StaticType, Type};
use glib::translate::*;
use glib::glib_container::GlibContainer;
use secret_service::SecretService;
use secret_item::SecretItem;
use SecretResult;
use ffi;

/// SecretCollection represents a collection of secret items stored in the Secret Service.
/// A collection can be in a locked or unlocked state. Use `Lock::lock()` or `Lock::unlock()` to lock or unlock the collection.
/// Use `get_items()` to lookup the items in the collection. There may not be any items exposed when the collection is locked.
pub struct SecretCollection(Ref);

impl SecretCollection {

    /// Lookup which collection is assigned to this alias.
    /// Aliases help determine well known collections, such as 'default'.
    /// Returns the collection, or NULL if none assigned to the alias.
    pub fn for_alias(alias: &str) -> SecretResult<SecretCollection>{
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_collection_for_alias_sync(ptr::null_mut(), alias.to_glib_none().0, SECRET_COLLECTION_LOAD_ITEMS, ptr::null_mut(), &mut err)};
        if err.is_null(){
            Ok(unsafe { from_glib_full(ptr) })
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Create a new collection in the secret service.
    /// If you specify an alias and a collection with that alias already exists, then a new collection will not be created. The previous one will be returned instead.
    /// Returns the created Collection.
    pub fn create(label: &str, alias: Option<&str>) -> SecretResult<SecretCollection> {
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_collection_create_sync(ptr::null_mut(), label.to_glib_none().0, alias.to_glib_none().0, 0, ptr::null_mut(), &mut err)};
        if err.is_null(){
            Ok(unsafe { from_glib_full(ptr) })
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Get the created date and time of the collection.
    /// The return value is the number of seconds since the unix epoch, January 1st 1970.
    pub fn get_created(&self) -> u64 {
        unsafe {ffi::secret_collection_get_created(self.to_glib_none().0)}
    }

    /// Get the modified date and time of the collection.
    /// The return value is the number of seconds since the unix epoch, January 1st 1970.
    pub fn get_modified(&self) -> u64 {
        unsafe {ffi::secret_collection_get_modified(self.to_glib_none().0)}
    }

    /// Get the Secret Service object that this collection was created with.
    pub fn get_service(&self) -> SecretService { //TODO find out if this can return null
        unsafe {
            let ptr = ffi::secret_collection_get_service(self.to_glib_none().0);
            from_glib_none(ptr)
        }
    }

    /// Get if the items are currently loaded. Use `load_items()` to load them.
    pub fn are_items_loaded(&self) -> bool {
        let flags = unsafe {ffi::secret_collection_get_flags(self.to_glib_none().0)};
        flags & SECRET_COLLECTION_LOAD_ITEMS != 0
    }

    /// Get the label of this collection.
    pub fn get_label(&self) -> String {
        unsafe{
            let ptr = ffi::secret_collection_get_label(self.to_glib_none().0);
            from_glib_full(ptr)
        }
    }

    /// Get the SecretItems of the collection
    pub fn get_items(&self) -> Vec<SecretItem> {
        unsafe {
            let glist = ffi::secret_collection_get_items(self.to_glib_none().0);
            Vec::from_glib_full(glist)
        }
    }

    /// Ensure that the SecretCollection proxy has loaded all the items present in the Secret Service.
    pub fn load_items(&self) -> SecretResult<()>{
        unsafe {
            let mut err = ptr::null_mut();
            ffi::secret_collection_load_items_sync(self.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    //TODO set_alias from ss
}

impl StaticType for SecretCollection {
    fn static_type() -> Type{
        unsafe { from_glib(ffi::secret_collection_get_type()) }
    }
}

unsafe impl Upcast<Object> for SecretCollection { }

impl Wrapper for SecretCollection {
    type GlibType = ffi::SecretCollection;
    unsafe fn wrap(r: Ref) -> Self{
        SecretCollection(r)
    }

    fn as_ref(&self) -> &Ref{
        &self.0
    }

    fn unwrap(self) -> Ref{
        self.0
    }
}

#[allow(dead_code)]
const SECRET_COLLECTION_NONE: i32        = 0;
const SECRET_COLLECTION_LOAD_ITEMS: i32  = 1 << 1;
<commit_msg>Implement set_alias for SecretCollection<commit_after>use std::ptr;
use glib::Error;
use glib::object::{Object, Upcast, Wrapper, Ref};
use glib::types::{StaticType, Type};
use glib::translate::*;
use glib::glib_container::GlibContainer;
use secret_service::SecretService;
use secret_item::SecretItem;
use SecretResult;
use ffi;

/// SecretCollection represents a collection of secret items stored in the Secret Service.
/// A collection can be in a locked or unlocked state. Use `Lock::lock()` or `Lock::unlock()` to lock or unlock the collection.
/// Use `get_items()` to lookup the items in the collection. There may not be any items exposed when the collection is locked.
pub struct SecretCollection(Ref);

impl SecretCollection {

    /// Lookup which collection is assigned to this alias.
    /// Aliases help determine well known collections, such as 'default'.
    /// Returns the collection, or NULL if none assigned to the alias.
    pub fn for_alias(alias: &str) -> SecretResult<SecretCollection>{
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_collection_for_alias_sync(ptr::null_mut(), alias.to_glib_none().0, SECRET_COLLECTION_LOAD_ITEMS, ptr::null_mut(), &mut err)};
        if err.is_null(){
            Ok(unsafe { from_glib_full(ptr) })
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Create a new collection in the secret service.
    /// If you specify an alias and a collection with that alias already exists, then a new collection will not be created. The previous one will be returned instead.
    /// Returns the created Collection.
    pub fn create(label: &str, alias: Option<&str>) -> SecretResult<SecretCollection> {
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_collection_create_sync(ptr::null_mut(), label.to_glib_none().0, alias.to_glib_none().0, 0, ptr::null_mut(), &mut err)};
        if err.is_null(){
            Ok(unsafe { from_glib_full(ptr) })
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Get the created date and time of the collection.
    /// The return value is the number of seconds since the unix epoch, January 1st 1970.
    pub fn get_created(&self) -> u64 {
        unsafe {ffi::secret_collection_get_created(self.to_glib_none().0)}
    }

    /// Get the modified date and time of the collection.
    /// The return value is the number of seconds since the unix epoch, January 1st 1970.
    pub fn get_modified(&self) -> u64 {
        unsafe {ffi::secret_collection_get_modified(self.to_glib_none().0)}
    }

    /// Get the Secret Service object that this collection was created with.
    pub fn get_service(&self) -> SecretService { //TODO find out if this can return null
        unsafe {
            let ptr = ffi::secret_collection_get_service(self.to_glib_none().0);
            from_glib_none(ptr)
        }
    }

    /// Get if the items are currently loaded. Use `load_items()` to load them.
    pub fn are_items_loaded(&self) -> bool {
        let flags = unsafe {ffi::secret_collection_get_flags(self.to_glib_none().0)};
        flags & SECRET_COLLECTION_LOAD_ITEMS != 0
    }

    /// Get the label of this collection.
    pub fn get_label(&self) -> String {
        unsafe{
            let ptr = ffi::secret_collection_get_label(self.to_glib_none().0);
            from_glib_full(ptr)
        }
    }

    /// Get the SecretItems of the collection
    pub fn get_items(&self) -> Vec<SecretItem> {
        unsafe {
            let glist = ffi::secret_collection_get_items(self.to_glib_none().0);
            Vec::from_glib_full(glist)
        }
    }

    /// Ensure that the SecretCollection proxy has loaded all the items present in the Secret Service.
    pub fn load_items(&self) -> SecretResult<()>{
        unsafe {
            let mut err = ptr::null_mut();
            ffi::secret_collection_load_items_sync(self.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    /// Assign the collection to this alias. Aliases help determine well known collections, such as 'default'.
    pub fn set_alias(&self, alias: &str) -> SecretResult<()>{
        unsafe {
            let mut err = ptr::null_mut();
            ffi::secret_service_set_alias_sync(ptr::null_mut(), alias.to_glib_none().0, self.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }
}

impl StaticType for SecretCollection {
    fn static_type() -> Type{
        unsafe { from_glib(ffi::secret_collection_get_type()) }
    }
}

unsafe impl Upcast<Object> for SecretCollection { }

impl Wrapper for SecretCollection {
    type GlibType = ffi::SecretCollection;
    unsafe fn wrap(r: Ref) -> Self{
        SecretCollection(r)
    }

    fn as_ref(&self) -> &Ref{
        &self.0
    }

    fn unwrap(self) -> Ref{
        self.0
    }
}

#[allow(dead_code)]
const SECRET_COLLECTION_NONE: i32        = 0;
const SECRET_COLLECTION_LOAD_ITEMS: i32  = 1 << 1;
<|endoftext|>


<commit_before>use libc::{c_ulong, c_int};
use {Errno, Result, NixPath};

bitflags!(
    flags MsFlags: c_ulong {
        const MS_RDONLY      = 1 << 0,  // Mount read-only
        const MS_NOSUID      = 1 << 1,  // Ignore suid and sgid bits
        const MS_NODEV       = 1 << 2,  // Disallow access to device special files
        const MS_NOEXEC      = 1 << 3,  // Disallow program execution
        const MS_SYNCHRONOUS = 1 << 4,  // Writes are synced at once
        const MS_REMOUNT     = 1 << 5,  // Alter flags of a mounted FS
        const MS_MANDLOCK    = 1 << 6,  // Allow mandatory locks on a FS
        const MS_DIRSYNC     = 1 << 7,  // Directory modifications are synchronous
        const MS_NOATIME     = 1 << 10, // Do not update access times
        const MS_NODIRATIME  = 1 << 11, // Do not update directory access times
        const MS_BIND        = 1 << 12, // Linux 2.4.0 - Bind directory at different place
        const MS_MOVE        = 1 << 13,
        const MS_REC         = 1 << 14,
        const MS_VERBOSE     = 1 << 15, // Deprecated
        const MS_SILENT      = 1 << 15,
        const MS_POSIXACL    = 1 << 16,
        const MS_UNBINDABLE  = 1 << 17,
        const MS_PRIVATE     = 1 << 18,
        const MS_SLAVE       = 1 << 19,
        const MS_SHARED      = 1 << 20,
        const MS_RELATIME    = 1 << 21,
        const MS_KERNMOUNT   = 1 << 22,
        const MS_I_VERSION   = 1 << 23,
        const MS_STRICTATIME = 1 << 24,
        const MS_NOSEC       = 1 << 28,
        const MS_BORN        = 1 << 29,
        const MS_ACTIVE      = 1 << 30,
        const MS_NOUSER      = 1 << 31,
        const MS_RMT_MASK    = MS_RDONLY.bits
                              | MS_SYNCHRONOUS.bits
                              | MS_MANDLOCK.bits
                              | MS_I_VERSION.bits,
        const MS_MGC_VAL     = 0xC0ED0000,
        const MS_MGC_MSK     = 0xffff0000
    }
);

bitflags!(
    flags MntFlags: c_int {
        const MNT_FORCE   = 1 << 0,
        const MNT_DETACH  = 1 << 1,
        const MNT_EXPIRE  = 1 << 2
    }
);

mod ffi {
    use libc::{c_char, c_int, c_ulong, c_void};

    extern {
        pub fn mount(
                source: *const c_char,
                target: *const c_char,
                fstype: *const c_char,
                flags: c_ulong,
                data: *const c_void) -> c_int;

        pub fn umount(target: *const c_char) -> c_int;

        pub fn umount2(target: *const c_char, flags: c_int) -> c_int;
    }
}

pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
        source: Option<&P1>,
        target: &P2,
        fstype: Option<&P3>,
        flags: MsFlags,
        data: Option<&P4>) -> Result<()> {
    use libc;

    let res = try!(try!(try!(try!(
        source.with_nix_path(|source| {
            target.with_nix_path(|target| {
                fstype.with_nix_path(|fstype| {
                    data.with_nix_path(|data| {
                        unsafe {
                            ffi::mount(source.as_ptr(),
                                       target.as_ptr(),
                                       fstype.as_ptr(),
                                       flags.bits,
                                       data.as_ptr() as *const libc::c_void)
                        }
                    })
                })
            })
        })))));

    Errno::result(res).map(drop)
}

pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
    let res = try!(target.with_nix_path(|cstr| {
        unsafe { ffi::umount(cstr.as_ptr()) }
    }));

    Errno::result(res).map(drop)
}

pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> {
    let res = try!(target.with_nix_path(|cstr| {
        unsafe { ffi::umount2(cstr.as_ptr(), flags.bits) }
    }));

    Errno::result(res).map(drop)
}
<commit_msg>Auto merge of #356 - brianp:mount-libc, r=posborne<commit_after>use libc::{c_ulong, c_int};
use libc;
use {Errno, Result, NixPath};

bitflags!(
    flags MsFlags: c_ulong {
        const MS_RDONLY      = 1 << 0,  // Mount read-only
        const MS_NOSUID      = 1 << 1,  // Ignore suid and sgid bits
        const MS_NODEV       = 1 << 2,  // Disallow access to device special files
        const MS_NOEXEC      = 1 << 3,  // Disallow program execution
        const MS_SYNCHRONOUS = 1 << 4,  // Writes are synced at once
        const MS_REMOUNT     = 1 << 5,  // Alter flags of a mounted FS
        const MS_MANDLOCK    = 1 << 6,  // Allow mandatory locks on a FS
        const MS_DIRSYNC     = 1 << 7,  // Directory modifications are synchronous
        const MS_NOATIME     = 1 << 10, // Do not update access times
        const MS_NODIRATIME  = 1 << 11, // Do not update directory access times
        const MS_BIND        = 1 << 12, // Linux 2.4.0 - Bind directory at different place
        const MS_MOVE        = 1 << 13,
        const MS_REC         = 1 << 14,
        const MS_VERBOSE     = 1 << 15, // Deprecated
        const MS_SILENT      = 1 << 15,
        const MS_POSIXACL    = 1 << 16,
        const MS_UNBINDABLE  = 1 << 17,
        const MS_PRIVATE     = 1 << 18,
        const MS_SLAVE       = 1 << 19,
        const MS_SHARED      = 1 << 20,
        const MS_RELATIME    = 1 << 21,
        const MS_KERNMOUNT   = 1 << 22,
        const MS_I_VERSION   = 1 << 23,
        const MS_STRICTATIME = 1 << 24,
        const MS_NOSEC       = 1 << 28,
        const MS_BORN        = 1 << 29,
        const MS_ACTIVE      = 1 << 30,
        const MS_NOUSER      = 1 << 31,
        const MS_RMT_MASK    = MS_RDONLY.bits
                              | MS_SYNCHRONOUS.bits
                              | MS_MANDLOCK.bits
                              | MS_I_VERSION.bits,
        const MS_MGC_VAL     = 0xC0ED0000,
        const MS_MGC_MSK     = 0xffff0000
    }
);

bitflags!(
    flags MntFlags: c_int {
        const MNT_FORCE   = 1 << 0,
        const MNT_DETACH  = 1 << 1,
        const MNT_EXPIRE  = 1 << 2
    }
);

pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
        source: Option<&P1>,
        target: &P2,
        fstype: Option<&P3>,
        flags: MsFlags,
        data: Option<&P4>) -> Result<()> {
    use libc;

    let res = try!(try!(try!(try!(
        source.with_nix_path(|source| {
            target.with_nix_path(|target| {
                fstype.with_nix_path(|fstype| {
                    data.with_nix_path(|data| {
                        unsafe {
                            libc::mount(source.as_ptr(),
                                       target.as_ptr(),
                                       fstype.as_ptr(),
                                       flags.bits,
                                       data.as_ptr() as *const libc::c_void)
                        }
                    })
                })
            })
        })))));

    Errno::result(res).map(drop)
}

pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
    let res = try!(target.with_nix_path(|cstr| {
        unsafe { libc::umount(cstr.as_ptr()) }
    }));

    Errno::result(res).map(drop)
}

pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> {
    let res = try!(target.with_nix_path(|cstr| {
        unsafe { libc::umount2(cstr.as_ptr(), flags.bits) }
    }));

    Errno::result(res).map(drop)
}
<|endoftext|>