<commit_before>/*!
  This module provides the syntax extension `iterator!()` that enables mapping, filtering and
  nesting of iterators using a comprehension syntax as well as the associated types `Prepend1`…
  `Prependn` which return the elements of an iterator in the last position of a 1…n element tuple,
  the preceding positions being constant.
*/

#[feature(macro_rules,phase)];

#[crate_id = "iteratorcomprehensions#0.1"];
#[crate_type = "lib"];

#[cfg(not(test))]
pub use prepend::{prepend1,Prepend1,prepend2,Prepend2};

/**
  Contains the macros that implement the comprehension syntax.
*/
#[cfg(not(test))]
pub mod macros {
  /**
    The `iterator!()` macro implements the following comprehension syntax:

    ```notrust
    iterator!(
      map_expr for var_1 in gen_expr_1 [if filter_expr_1]
      [… for var_n in gen_expr_n [if filter_expr]]
    )
    ```

    * `var_1`… `var_n` identify the iteration variables associated with each of the nested
      iterators.
    * `gen_expr_1`… `gen_expr_n` are expressions that evaluate to an `Iterator`. `gen_expr_i` can
      refer to all "outer" iteration variables `var_1`… `var_(i-1)`.
    * `map_expr` is an expression that constructs the elements of the iterator comprehension from
      the iteration variables.
    * `filter_expr_1`… `filter_expr_n` are expressions that evaluate to a boolean which filters
      the iterator elements based on the "outer" iteration variables.

    `iterator!()` evaluates to an expression which itself implements the `Iterator` trait.

    The expression

    ```notrust
    iterator!(
      (i, j) for i in range(0,3) for j in range(0, i + 1) if (i + j) % 2 == 0
    )
    ```
    evaluates to an iterator that contains the elements

    ```notrust
    (0,0), (1,1), (2,0), (2,2)
    ```
  */
  #[macro_export]
  macro_rules! iterator(
    (
      $map:expr
      for $var:ident in $gen:expr
      $(if $filter:expr)*
    ) => (
      $gen
      $(.filter_map(|$var| { if $filter { Some($var) } else { None } }))*
      .map(|$var| { $map })
    );
    (
      $map:expr
      for $var1:ident in $gen1:expr
      $(if $filter1:expr)*
      for $var2:ident in $gen2:expr
      $(if $filter2:expr)*
    ) => (
      $gen1
      $(.filter_map(|$var1| { if $filter1 { Some($var1) } else { None } }))*
      .flat_map(|$var1| { iteratorcomprehensions::prepend1($var1, $gen2) })
      $(.filter_map(|($var1, $var2)| { if $filter2 { Some(($var1, $var2)) } else { None } }))*
      .map(|($var1, $var2)| { $map })
    );
    (
      $map:expr
      for $var1:ident in $gen1:expr
      $(if $filter1:expr)*
      for $var2:ident in $gen2:expr
      $(if $filter2:expr)*
      for $var3:ident in $gen3:expr
      $(if $filter3:expr)*
    ) => (
      $gen1
      $(.filter_map(|$var1| { if $filter1 { Some($var1) } else { None } }))*
      .flat_map(|$var1| { iteratorcomprehensions::prepend1($var1, $gen2) })
      $(.filter_map(|($var1, $var2)| { if $filter2 { Some(($var1, $var2)) } else { None } }))*
      .flat_map(|($var1, $var2)| { iteratorcomprehensions::prepend2($var1, $var2, $gen3) })
      $(.filter_map(
        |($var1, $var2, $var3)| { if $filter3 { Some(($var1, $var2, $var3)) } else { None } }
      ))*
      .map(|($var1, $var2, $var3)| { $map })
    );
  )
}

/**
  Contains the types `Prepend1`… `Prependn` as well as the convenience functions `prepend1`… `prependn`.
*/
#[cfg(not(test))]
pub mod prepend {
  /**
    Maps each element `i` in `iter` to the tuple `(val1, i)`.
  */
  pub struct Prepend1<T1, T, It> {
    iter: It,
    val1: T1
  }

  impl<T1: Clone, T, It: Iterator<T>> Prepend1<T1, T, It> {
    #[inline]
    fn new(v1: T1, it: It) -> Prepend1<T1, T, It> {
      Prepend1 { iter: it, val1: v1 }
    }
  }

  impl<T1: Clone, T, It: Iterator<T>> Iterator<(T1, T)> for Prepend1<T1, T, It> {
    #[inline]
    fn next(&mut self) -> Option<(T1, T)> {
      self.iter.next().map(|val| (self.val1.clone(), val))
    }
  }

  /**
    Constructs a new `Prepend1`.
  */
  #[inline]
  pub fn prepend1<T1: Clone, T, It: Iterator<T>>(v1: T1, it: It) -> Prepend1<T1, T, It> {
    Prepend1::new(v1, it)
  }

  /**
    Maps each element `i` in `iter` to the tuple `(val1, val2, i)`.
  */
  pub struct Prepend2<T1, T2, T, It> {
    iter: It,
    val1: T1,
    val2: T2
  }

  impl<T1: Clone, T2: Clone, T, It: Iterator<T>> Prepend2<T1, T2, T, It> {
    #[inline]
    fn new(v1: T1, v2: T2, it: It) -> Prepend2<T1, T2, T, It> {
      Prepend2 { iter: it, val1: v1, val2: v2 }
    }
  }

  impl<T1: Clone, T2: Clone, T, It: Iterator<T>> Iterator<(T1, T2, T)> for Prepend2<T1, T2, T, It> {
    #[inline]
    fn next(&mut self) -> Option<(T1, T2, T)> {
      self.iter.next().map(|val| (self.val1.clone(), self.val2.clone(), val))
    }
  }

  /**
    Constructs a new `Prepend2`.
  */
  #[inline]
  pub fn prepend2<T1: Clone, T2: Clone, T, It: Iterator<T>>(v1: T1, v2: T2, it: It)
  -> Prepend2<T1, T2, T, It> {
    Prepend2::new(v1, v2, it)
  }
}

#[cfg(test)]
mod tests {
  #[phase(syntax,link)]
  extern crate iteratorcomprehensions;

  #[test]
  fn iterator1_test() {
    let xs: ~[int] = iterator!( i for i in range(0, 3) ).collect();
    assert_eq!(xs, ~[0, 1, 2]);
  }

  #[test]
  fn iterator1_map_test() {
    let xs: ~[int] = iterator!( i + 1 for i in range(0, 3) ).collect();
    assert_eq!(xs, ~[1, 2, 3]);
  }

  #[test]
  fn iterator1_filter_test() {
    let xs: ~[int] = iterator!( i for i in range(0, 3) if i % 2 == 1 ).collect();
    assert_eq!(xs, ~[1]);
  }

  #[test]
  fn iterator1_filter_map_test() {
    let xs: ~[int] = iterator!( i * 2 for i in range(0, 3) if i % 2 == 1 ).collect();
    assert_eq!(xs, ~[2]);
  }

  #[test]
  fn iterator2_map_test() {
    let xs: ~[int] = iterator!( i * j for i in range(1, 3) for j in range(2, 4) ).collect();
    assert_eq!(xs, ~[2, 3, 4, 6]);
  }

  #[test]
  fn iterator2_filter_map_test() {
    let xs: ~[int] = iterator!(
      i / j for i in range(6, 9) for j in range(1, 4) if i % j == 0
    ).collect();
    assert_eq!(xs, ~[6, 3, 2, 7, 8, 4]);
  }

  #[test]
  fn iterator2_example_test() {
    let xs: ~[(int,int)] = iterator!(
      (i,j) for i in range(0,3) for j in range(0, i + 1) if (i + j) % 2 == 0
    ).collect();
    assert_eq!(xs, ~[(0,0), (1,1), (2,0), (2,2)]);
  }

  #[test]
  fn iterator3_map_test() {
    let xs: ~[int] = iterator!(
      i * j * k for i in range(1, 3) for j in range(2, 4) for k in range(3, 5)
    ).collect();
    assert_eq!(xs, ~[6, 8, 9, 12, 12, 16, 18, 24]);
  }

  #[test]
  fn iterator3_filter_map_test() {
    let xs: ~[int] = iterator!(
      i + j + k for i in range(0, 10) for j in range(0, 10) for k in range(0, 10)
      if i == 1 && j == 1 && k == 1
    ).collect();
    assert_eq!(xs, ~[3]);
  }

  #[test]
  fn iterator3_empty_test() {
    let xs: ~[int] = iterator!(
      i * j * k for i in range(0, 2) for j in range(0, i) for k in range(0, 1)
    ).collect();
    assert_eq!(xs, ~[0]);
  }
}
<commit_msg>use .filter() instead of .filter_map()<commit_after>/*!
  This module provides the syntax extension `iterator!()` that enables mapping, filtering and
  nesting of iterators using a comprehension syntax as well as the associated types `Prepend1`…
  `Prependn` which return the elements of an iterator in the last position of a 1…n element tuple,
  the preceding positions being constant.
*/

#[feature(macro_rules,phase)];

#[crate_id = "iteratorcomprehensions#0.1"];
#[crate_type = "lib"];

#[cfg(not(test))]
pub use prepend::{prepend1,Prepend1,prepend2,Prepend2};

/**
  Contains the macros that implement the comprehension syntax.
*/
#[cfg(not(test))]
pub mod macros {
  /**
    The `iterator!()` macro implements the following comprehension syntax:

    ```notrust
    iterator!(
      map_expr for var_1 in gen_expr_1 [if filter_expr_1]
      [… for var_n in gen_expr_n [if filter_expr]]
    )
    ```

    * `var_1`… `var_n` identify the iteration variables associated with each of the nested
      iterators.
    * `gen_expr_1`… `gen_expr_n` are expressions that evaluate to an `Iterator`. `gen_expr_i` can
      refer to all "outer" iteration variables `var_1`… `var_(i-1)`.
    * `map_expr` is an expression that constructs the elements of the iterator comprehension from
      the iteration variables.
    * `filter_expr_1`… `filter_expr_n` are expressions that evaluate to a boolean which filters
      the iterator elements based on the "outer" iteration variables.

    `iterator!()` evaluates to an expression which itself implements the `Iterator` trait.

    The expression

    ```notrust
    iterator!(
      (i, j) for i in range(0,3) for j in range(0, i + 1) if (i + j) % 2 == 0
    )
    ```
    evaluates to an iterator that contains the elements

    ```notrust
    (0,0), (1,1), (2,0), (2,2)
    ```
  */
  #[macro_export]
  macro_rules! iterator(
    (
      $map:expr
      for $var:ident in $gen:expr
      $(if $filter:expr)*
    ) => (
      $gen
      $(.filter(|&$var| { $filter }))*
      .map(|$var| { $map })
    );
    (
      $map:expr
      for $var1:ident in $gen1:expr
      $(if $filter1:expr)*
      for $var2:ident in $gen2:expr
      $(if $filter2:expr)*
    ) => (
      $gen1
      $(.filter(|&$var1| { $filter1 }))*
      .flat_map(|$var1| { iteratorcomprehensions::prepend1($var1, $gen2) })
      $(.filter(|&($var1, $var2)| { $filter2 }))*
      .map(|($var1, $var2)| { $map })
    );
    (
      $map:expr
      for $var1:ident in $gen1:expr
      $(if $filter1:expr)*
      for $var2:ident in $gen2:expr
      $(if $filter2:expr)*
      for $var3:ident in $gen3:expr
      $(if $filter3:expr)*
    ) => (
      $gen1
      $(.filter(|&$var1| { $filter1 }))*
      .flat_map(|$var1| { iteratorcomprehensions::prepend1($var1, $gen2) })
      $(.filter(|&($var1, $var2)| { $filter2 }))*
      .flat_map(|($var1, $var2)| { iteratorcomprehensions::prepend2($var1, $var2, $gen3) })
      $(.filter(|&($var1, $var2, $var3)| { $filter3 }))*
      .map(|($var1, $var2, $var3)| { $map })
    );
  )
}

/**
  Contains the types `Prepend1`… `Prependn` as well as the convenience functions `prepend1`… `prependn`.
*/
#[cfg(not(test))]
pub mod prepend {
  /**
    Maps each element `i` in `iter` to the tuple `(val1, i)`.
  */
  pub struct Prepend1<T1, T, It> {
    iter: It,
    val1: T1
  }

  impl<T1: Clone, T, It: Iterator<T>> Prepend1<T1, T, It> {
    #[inline]
    fn new(v1: T1, it: It) -> Prepend1<T1, T, It> {
      Prepend1 { iter: it, val1: v1 }
    }
  }

  impl<T1: Clone, T, It: Iterator<T>> Iterator<(T1, T)> for Prepend1<T1, T, It> {
    #[inline]
    fn next(&mut self) -> Option<(T1, T)> {
      self.iter.next().map(|val| (self.val1.clone(), val))
    }
  }

  /**
    Constructs a new `Prepend1`.
  */
  #[inline]
  pub fn prepend1<T1: Clone, T, It: Iterator<T>>(v1: T1, it: It) -> Prepend1<T1, T, It> {
    Prepend1::new(v1, it)
  }

  /**
    Maps each element `i` in `iter` to the tuple `(val1, val2, i)`.
  */
  pub struct Prepend2<T1, T2, T, It> {
    iter: It,
    val1: T1,
    val2: T2
  }

  impl<T1: Clone, T2: Clone, T, It: Iterator<T>> Prepend2<T1, T2, T, It> {
    #[inline]
    fn new(v1: T1, v2: T2, it: It) -> Prepend2<T1, T2, T, It> {
      Prepend2 { iter: it, val1: v1, val2: v2 }
    }
  }

  impl<T1: Clone, T2: Clone, T, It: Iterator<T>> Iterator<(T1, T2, T)> for Prepend2<T1, T2, T, It> {
    #[inline]
    fn next(&mut self) -> Option<(T1, T2, T)> {
      self.iter.next().map(|val| (self.val1.clone(), self.val2.clone(), val))
    }
  }

  /**
    Constructs a new `Prepend2`.
  */
  #[inline]
  pub fn prepend2<T1: Clone, T2: Clone, T, It: Iterator<T>>(v1: T1, v2: T2, it: It)
  -> Prepend2<T1, T2, T, It> {
    Prepend2::new(v1, v2, it)
  }
}

#[cfg(test)]
mod tests {
  #[phase(syntax,link)]
  extern crate iteratorcomprehensions;

  #[test]
  fn iterator1_test() {
    let xs: ~[int] = iterator!( i for i in range(0, 3) ).collect();
    assert_eq!(xs, ~[0, 1, 2]);
  }

  #[test]
  fn iterator1_map_test() {
    let xs: ~[int] = iterator!( i + 1 for i in range(0, 3) ).collect();
    assert_eq!(xs, ~[1, 2, 3]);
  }

  #[test]
  fn iterator1_filter_test() {
    let xs: ~[int] = iterator!( i for i in range(0, 3) if i % 2 == 1 ).collect();
    assert_eq!(xs, ~[1]);
  }

  #[test]
  fn iterator1_filter_map_test() {
    let xs: ~[int] = iterator!( i * 2 for i in range(0, 3) if i % 2 == 1 ).collect();
    assert_eq!(xs, ~[2]);
  }

  #[test]
  fn iterator2_map_test() {
    let xs: ~[int] = iterator!( i * j for i in range(1, 3) for j in range(2, 4) ).collect();
    assert_eq!(xs, ~[2, 3, 4, 6]);
  }

  #[test]
  fn iterator2_filter_map_test() {
    let xs: ~[int] = iterator!(
      i / j for i in range(6, 9) for j in range(1, 4) if i % j == 0
    ).collect();
    assert_eq!(xs, ~[6, 3, 2, 7, 8, 4]);
  }

  #[test]
  fn iterator2_example_test() {
    let xs: ~[(int,int)] = iterator!(
      (i,j) for i in range(0,3) for j in range(0, i + 1) if (i + j) % 2 == 0
    ).collect();
    assert_eq!(xs, ~[(0,0), (1,1), (2,0), (2,2)]);
  }

  #[test]
  fn iterator3_map_test() {
    let xs: ~[int] = iterator!(
      i * j * k for i in range(1, 3) for j in range(2, 4) for k in range(3, 5)
    ).collect();
    assert_eq!(xs, ~[6, 8, 9, 12, 12, 16, 18, 24]);
  }

  #[test]
  fn iterator3_filter_map_test() {
    let xs: ~[int] = iterator!(
      i + j + k for i in range(0, 10) for j in range(0, 10) for k in range(0, 10)
      if i == 1 && j == 1 && k == 1
    ).collect();
    assert_eq!(xs, ~[3]);
  }

  #[test]
  fn iterator3_empty_test() {
    let xs: ~[int] = iterator!(
      i * j * k for i in range(0, 2) for j in range(0, i) for k in range(0, 1)
    ).collect();
    assert_eq!(xs, ~[0]);
  }
}
<|endoftext|>


<commit_before>use decoders::Image;
use imageops::fcol;

pub fn whitebalance(img: &Image, buf: &mut Vec<f32>) {
  // Set green multiplier as 1.0
  let unity: f32 = img.wb_coeffs[1];
  let mul = img.wb_coeffs.iter().map(|x| if x.is_nan() { 1.0 } else { x / unity }).collect::<Vec<f32>>();

  for row in 0..img.height {
    for col in 0..img.width {
      let pos = row*img.width + col;
      let color = fcol(img, row, col);
      buf[pos] = (buf[pos] * mul[color]).min(1.0);
    }
  }
}
<commit_msg>whitebalance: cleanup loops with proper iterators<commit_after>use decoders::Image;
use imageops::fcol;

pub fn whitebalance(img: &Image, buf: &mut Vec<f32>) {
  // Set green multiplier as 1.0
  let unity: f32 = img.wb_coeffs[1];
  let mul = img.wb_coeffs.iter().map(|x| if x.is_nan() { 1.0 } else { x / unity }).collect::<Vec<f32>>();

  for (row,line) in buf.chunks_mut(img.width).enumerate() {
    for (col,pix) in line.chunks_mut(1).enumerate() {
      let color = fcol(img, row, col);
      pix[0] = (pix[0] * mul[color]).min(1.0);
    }
  }
}
<|endoftext|>


<commit_before>use itertools::zip;
use std::collections::BTreeMap;
use std::path;
use lib::collections::*;
use lib::front::*;
use lib::front::ast::*;
use lib::front::substitution::*;

/// If `var` is an instantiation of a polymorphic value and monomorphization
/// does not already exist for this instantiation type, generate a
/// monomorphization and return the monomorphisized definition
fn monomorphize_def_of_inst<'src>(
    var: &mut Variable<'src>,
    env: &mut ScopeStack<&str, Binding<'src>>,
) -> Option<(Vec<Type<'src>>, Expr<'src>)> {
    if let Type::App(ref f, ref mut ts) = var.typ {
        // In application of poly function to poly args, any type can be used
        // for the args during codegen, with the constraint that a Num arg must
        // be numeric. As such, default args of (application of poly function to poly args)
        // to Int64
        *ts = ts.iter()
            .map(|t| {
                if !t.is_monomorphic() {
                    Type::Const("Int64", None)
                } else {
                    t.clone()
                }
            })
            .collect::<Vec<_>>();
        if let TypeFunc::Poly(ref p) = **f {
            // An application of a polytype =>
            //   it's an instantiation to generate monomorphization for
            let b = env.get(var.ident.s).unwrap();
            if !b.mono_insts.contains_key(&*ts) {
                // The monomorphization does not already exist
                let mut s = zip(&p.params, &*ts)
                    .map(|((&param_v, _), t)| (param_v, t.clone()))
                    .collect();
                let mut def_mono = b.val.clone();
                subst_expr(&mut def_mono, &mut s);
                return Some((ts.clone(), def_mono));
            }
        }
    } else if !var.typ.is_monomorphic() {
        // If, in a monomorphic instantiation, the variable can be of any type:
        // consistently default to generating it as Int64
        var.typ = Type::Const("Int64", None)
    }
    // Either definition is already monomorphic to begin with,
    // or it is polymorphic, but monomorphization has already been generated
    None
}

fn monomorphize_defs_of_insts_in_match<'src>(
    m: &mut Match<'src>,
    env: &mut ScopeStack<&'src str, Binding<'src>>,
) {
    // TODO: This is probably wrong. I have no idea what to put here.
    // I kinda forgot how exactly this whole process worked, and I'm
    // tired and confused.
    for case in &mut m.cases {
        monomorphize_defs_of_insts_in_expr(&mut case.body, env)
    }
}

/// Monomorphize definitions for monomorphic instantiations of variables in `expr`
fn monomorphize_defs_of_insts_in_expr<'src>(
    e: &mut Expr<'src>,
    env: &mut ScopeStack<&'src str, Binding<'src>>,
) {
    let canon = e.get_type().canonicalize();
    if !canon.is_monomorphic() {
        e.pos().error(&format!(
            "Could not deduce {} from use of expression. Type was not monomorphic at compile time.",
            canon
        ));
        note("Try adding a type annotation to choose which specific instance of the type to use.");
        exit()
    }
    match *e {
        Expr::Variable(ref mut var) => {
            if let Some((arg_ts, mut def_mono)) = monomorphize_def_of_inst(var, env) {
                // Insert dummy monomorphization as a tag to show that monomorphization
                // already has been done, but we still need `def_mono` to continue
                // our recursive monomorphization
                {
                    let dummy_expr = Expr::Nil(Nil {
                        pos: SrcPos::new_pos(path::Path::new(""), "", 0),
                    });
                    let b = env.get_mut(var.ident.s).unwrap();
                    b.mono_insts.insert(arg_ts.clone(), dummy_expr);
                }

                // Recursively generate monomorphizations for now-monomorphic
                // instantiations in `def_mono`
                let h = env.get_height(var.ident.s).unwrap();
                let above = env.split_off(h + 1);
                monomorphize_defs_of_insts_in_expr(&mut def_mono, env);
                env.extend(above);

                let b = env.get_mut(var.ident.s).unwrap();
                *b.mono_insts.get_mut(&arg_ts).unwrap() = def_mono;
            }
        }
        Expr::App(ref mut app) => {
            monomorphize_defs_of_insts_in_expr(&mut app.func, env);
            monomorphize_defs_of_insts_in_expr(&mut app.arg, env);
        }
        Expr::If(ref mut cond) => {
            monomorphize_defs_of_insts_in_expr(&mut cond.predicate, env);
            monomorphize_defs_of_insts_in_expr(&mut cond.consequent, env);
            monomorphize_defs_of_insts_in_expr(&mut cond.alternative, env);
        }
        Expr::Lambda(ref mut lam) => {
            monomorphize_defs_of_insts_in_expr(&mut lam.body, env);
        }
        Expr::Let(box ref mut l) => {
            monomorphize_defs_of_insts_in_let(&mut l.bindings, &mut l.body, env)
        }
        Expr::TypeAscript(_) => unreachable!(),
        Expr::Cons(ref mut cons) => {
            monomorphize_defs_of_insts_in_expr(&mut cons.car, env);
            monomorphize_defs_of_insts_in_expr(&mut cons.cdr, env);
        }
        Expr::Car(ref mut c) => {
            monomorphize_defs_of_insts_in_expr(&mut c.expr, env);
        }
        Expr::Cdr(ref mut c) => {
            monomorphize_defs_of_insts_in_expr(&mut c.expr, env);
        }
        Expr::Cast(ref mut c) => {
            monomorphize_defs_of_insts_in_expr(&mut c.expr, env);
        }
        Expr::New(ref mut n) => for member in &mut n.members {
            monomorphize_defs_of_insts_in_expr(member, env)
        },
        Expr::Match(ref mut m) => monomorphize_defs_of_insts_in_match(m, env),
        Expr::Nil(_) | Expr::NumLit(_) | Expr::StrLit(_) | Expr::Bool(_) => (),
    }
}

/// Monomorphize definitions for monomorphic instantiations of variables in `bindings`
fn monomorphize_defs_of_insts_in_let<'src>(
    bindings: &mut TopologicallyOrderedDependencyGroups<'src>,
    body: &mut Expr<'src>,
    env: &mut ScopeStack<&'src str, Binding<'src>>,
) {
    let mut monos = BTreeMap::new();
    let mut bindings_flat_map = BTreeMap::new();
    for b in bindings.bindings() {
        if b.sig.is_monomorphic() {
            monos.insert(b.ident.s, b.val.clone());
        }
        bindings_flat_map.insert(b.ident.s, b.clone());
    }
    env.push(bindings_flat_map);

    for (_, mut def) in &mut monos {
        monomorphize_defs_of_insts_in_expr(&mut def, env);
    }
    monomorphize_defs_of_insts_in_expr(body, env);

    for b in bindings.bindings_mut() {
        if let Some(upd_def) = monos.remove(b.ident.s) {
            b.val = upd_def;
        } else if let Some(upd_bnd) = env.remove(b.ident.s) {
            *b = upd_bnd
        }
    }
    env.pop().unwrap();
}

/// Monomorphize definitions for monomorphic instantiations of variables in `bindings`
pub fn monomorphize_defs_of_insts<'src>(globals: &mut TopologicallyOrderedDependencyGroups<'src>) {
    let mut dummy_body = Expr::Nil(Nil {
        pos: SrcPos::new_pos(path::Path::new(""), "", 0),
    });
    monomorphize_defs_of_insts_in_let(globals, &mut dummy_body, &mut ScopeStack::new());
}
<commit_msg>Fix Match.expr not monomorphized<commit_after>use itertools::zip;
use std::collections::BTreeMap;
use std::path;
use lib::collections::*;
use lib::front::*;
use lib::front::ast::*;
use lib::front::substitution::*;

/// If `var` is an instantiation of a polymorphic value and monomorphization
/// does not already exist for this instantiation type, generate a
/// monomorphization and return the monomorphisized definition
fn monomorphize_def_of_inst<'src>(
    var: &mut Variable<'src>,
    env: &mut ScopeStack<&str, Binding<'src>>,
) -> Option<(Vec<Type<'src>>, Expr<'src>)> {
    if let Type::App(ref f, ref mut ts) = var.typ {
        // In application of poly function to poly args, any type can be used
        // for the args during codegen, with the constraint that a Num arg must
        // be numeric. As such, default args of (application of poly function to poly args)
        // to Int64
        *ts = ts.iter()
            .map(|t| {
                if !t.is_monomorphic() {
                    Type::Const("Int64", None)
                } else {
                    t.clone()
                }
            })
            .collect::<Vec<_>>();
        if let TypeFunc::Poly(ref p) = **f {
            // An application of a polytype =>
            //   it's an instantiation to generate monomorphization for
            let b = env.get(var.ident.s).unwrap();
            if !b.mono_insts.contains_key(&*ts) {
                // The monomorphization does not already exist
                let mut s = zip(&p.params, &*ts)
                    .map(|((&param_v, _), t)| (param_v, t.clone()))
                    .collect();
                let mut def_mono = b.val.clone();
                subst_expr(&mut def_mono, &mut s);
                return Some((ts.clone(), def_mono));
            }
        }
    } else if !var.typ.is_monomorphic() {
        // If, in a monomorphic instantiation, the variable can be of any type:
        // consistently default to generating it as Int64
        var.typ = Type::Const("Int64", None)
    }
    // Either definition is already monomorphic to begin with,
    // or it is polymorphic, but monomorphization has already been generated
    None
}

fn monomorphize_defs_of_insts_in_match<'src>(
    m: &mut Match<'src>,
    env: &mut ScopeStack<&'src str, Binding<'src>>,
) {
    monomorphize_defs_of_insts_in_expr(&mut m.expr, env);
    // TODO: This is probably wrong. I have no idea what to put here.
    // I kinda forgot how exactly this whole process worked, and I'm
    // tired and confused.
    for case in &mut m.cases {
        monomorphize_defs_of_insts_in_expr(&mut case.body, env)
    }
}

/// Monomorphize definitions for monomorphic instantiations of variables in `expr`
fn monomorphize_defs_of_insts_in_expr<'src>(
    e: &mut Expr<'src>,
    env: &mut ScopeStack<&'src str, Binding<'src>>,
) {
    let canon = e.get_type().canonicalize();
    if !canon.is_monomorphic() {
        e.pos().error(&format!(
            "Could not deduce {} from use of expression. Type was not monomorphic at compile time.",
            canon
        ));
        note("Try adding a type annotation to choose which specific instance of the type to use.");
        exit()
    }
    match *e {
        Expr::Variable(ref mut var) => {
            if let Some((arg_ts, mut def_mono)) = monomorphize_def_of_inst(var, env) {
                // Insert dummy monomorphization as a tag to show that monomorphization
                // already has been done, but we still need `def_mono` to continue
                // our recursive monomorphization
                {
                    let dummy_expr = Expr::Nil(Nil {
                        pos: SrcPos::new_pos(path::Path::new(""), "", 0),
                    });
                    let b = env.get_mut(var.ident.s).unwrap();
                    b.mono_insts.insert(arg_ts.clone(), dummy_expr);
                }

                // Recursively generate monomorphizations for now-monomorphic
                // instantiations in `def_mono`
                let h = env.get_height(var.ident.s).unwrap();
                let above = env.split_off(h + 1);
                monomorphize_defs_of_insts_in_expr(&mut def_mono, env);
                env.extend(above);

                let b = env.get_mut(var.ident.s).unwrap();
                *b.mono_insts.get_mut(&arg_ts).unwrap() = def_mono;
            }
        }
        Expr::App(ref mut app) => {
            monomorphize_defs_of_insts_in_expr(&mut app.func, env);
            monomorphize_defs_of_insts_in_expr(&mut app.arg, env);
        }
        Expr::If(ref mut cond) => {
            monomorphize_defs_of_insts_in_expr(&mut cond.predicate, env);
            monomorphize_defs_of_insts_in_expr(&mut cond.consequent, env);
            monomorphize_defs_of_insts_in_expr(&mut cond.alternative, env);
        }
        Expr::Lambda(ref mut lam) => {
            monomorphize_defs_of_insts_in_expr(&mut lam.body, env);
        }
        Expr::Let(box ref mut l) => {
            monomorphize_defs_of_insts_in_let(&mut l.bindings, &mut l.body, env)
        }
        Expr::TypeAscript(_) => unreachable!(),
        Expr::Cons(ref mut cons) => {
            monomorphize_defs_of_insts_in_expr(&mut cons.car, env);
            monomorphize_defs_of_insts_in_expr(&mut cons.cdr, env);
        }
        Expr::Car(ref mut c) => {
            monomorphize_defs_of_insts_in_expr(&mut c.expr, env);
        }
        Expr::Cdr(ref mut c) => {
            monomorphize_defs_of_insts_in_expr(&mut c.expr, env);
        }
        Expr::Cast(ref mut c) => {
            monomorphize_defs_of_insts_in_expr(&mut c.expr, env);
        }
        Expr::New(ref mut n) => for member in &mut n.members {
            monomorphize_defs_of_insts_in_expr(member, env)
        },
        Expr::Match(ref mut m) => monomorphize_defs_of_insts_in_match(m, env),
        Expr::Nil(_) | Expr::NumLit(_) | Expr::StrLit(_) | Expr::Bool(_) => (),
    }
}

/// Monomorphize definitions for monomorphic instantiations of variables in `bindings`
fn monomorphize_defs_of_insts_in_let<'src>(
    bindings: &mut TopologicallyOrderedDependencyGroups<'src>,
    body: &mut Expr<'src>,
    env: &mut ScopeStack<&'src str, Binding<'src>>,
) {
    let mut monos = BTreeMap::new();
    let mut bindings_flat_map = BTreeMap::new();
    for b in bindings.bindings() {
        if b.sig.is_monomorphic() {
            monos.insert(b.ident.s, b.val.clone());
        }
        bindings_flat_map.insert(b.ident.s, b.clone());
    }
    env.push(bindings_flat_map);

    for (_, mut def) in &mut monos {
        monomorphize_defs_of_insts_in_expr(&mut def, env);
    }
    monomorphize_defs_of_insts_in_expr(body, env);

    for b in bindings.bindings_mut() {
        if let Some(upd_def) = monos.remove(b.ident.s) {
            b.val = upd_def;
        } else if let Some(upd_bnd) = env.remove(b.ident.s) {
            *b = upd_bnd
        }
    }
    env.pop().unwrap();
}

/// Monomorphize definitions for monomorphic instantiations of variables in `bindings`
pub fn monomorphize_defs_of_insts<'src>(globals: &mut TopologicallyOrderedDependencyGroups<'src>) {
    let mut dummy_body = Expr::Nil(Nil {
        pos: SrcPos::new_pos(path::Path::new(""), "", 0),
    });
    monomorphize_defs_of_insts_in_let(globals, &mut dummy_body, &mut ScopeStack::new());
}
<|endoftext|>


<commit_before>use std::cmp::min;
use std::f64;

use markup5ever::{expanded_name, local_name, namespace_url, ns};
use nalgebra::{DMatrix, Dynamic, VecStorage};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers::{NumberOptionalNumber, ParseValue};
use crate::property_bag::PropertyBag;
use crate::rect::IRect;
use crate::surface_utils::{
    shared_surface::{BlurDirection, Horizontal, SharedImageSurface, Vertical},
    EdgeMode,
};

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, PrimitiveWithInput};

/// The maximum gaussian blur kernel size.
///
/// The value of 500 is used in webkit.
const MAXIMUM_KERNEL_SIZE: usize = 500;

/// The `feGaussianBlur` filter primitive.
pub struct FeGaussianBlur {
    base: PrimitiveWithInput,
    std_deviation: (f64, f64),
}

impl Default for FeGaussianBlur {
    /// Constructs a new `GaussianBlur` with empty properties.
    #[inline]
    fn default() -> FeGaussianBlur {
        FeGaussianBlur {
            base: PrimitiveWithInput::new::<Self>(),
            std_deviation: (0.0, 0.0),
        }
    }
}

impl NodeTrait for FeGaussianBlur {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "stdDeviation") => {
                    let NumberOptionalNumber(x, y) =
                        attr.parse_and_validate(value, |v: NumberOptionalNumber<f64>| {
                            if v.0 >= 0.0 && v.1 >= 0.0 {
                                Ok(v)
                            } else {
                                Err(ValueErrorKind::value_error("values can't be negative"))
                            }
                        })?;

                    self.std_deviation = (x, y);
                }
                _ => (),
            }
        }

        Ok(())
    }
}

/// Computes a gaussian kernel line for the given standard deviation.
fn gaussian_kernel(std_deviation: f64) -> Vec<f64> {
    assert!(std_deviation > 0.0);

    // Make sure there aren't any infinities.
    let maximal_deviation = (MAXIMUM_KERNEL_SIZE / 2) as f64 / 3.0;

    // Values further away than std_deviation * 3 are too small to contribute anything meaningful.
    let radius = ((std_deviation.min(maximal_deviation) * 3.0) + 0.5) as usize;
    // Clamp the radius rather than diameter because `MAXIMUM_KERNEL_SIZE` might be even and we
    // want an odd-sized kernel.
    let radius = min(radius, (MAXIMUM_KERNEL_SIZE - 1) / 2);
    let diameter = radius * 2 + 1;

    let mut kernel = Vec::with_capacity(diameter);

    let gauss_point = |x: f64| (-x.powi(2) / (2.0 * std_deviation.powi(2))).exp();

    // Fill the matrix by doing numerical integration approximation from -2*std_dev to 2*std_dev,
    // sampling 50 points per pixel. We do the bottom half, mirror it to the top half, then compute
    // the center point. Otherwise asymmetric quantization errors will occur. The formula to
    // integrate is e^-(x^2/2s^2).
    for i in 0..diameter / 2 {
        let base_x = (diameter / 2 + 1 - i) as f64 - 0.5;

        let mut sum = 0.0;
        for j in 1..=50 {
            let r = base_x + 0.02 * f64::from(j);
            sum += gauss_point(r);
        }

        kernel.push(sum / 50.0);
    }

    // We'll compute the middle point later.
    kernel.push(0.0);

    // Mirror the bottom half to the top half.
    for i in 0..diameter / 2 {
        let x = kernel[diameter / 2 - 1 - i];
        kernel.push(x);
    }

    // Find center val -- calculate an odd number of quanta to make it symmetric, even if the
    // center point is weighted slightly higher than others.
    let mut sum = 0.0;
    for j in 0..=50 {
        let r = -0.5 + 0.02 * f64::from(j);
        sum += gauss_point(r);
    }
    kernel[diameter / 2] = sum / 51.0;

    // Normalize the distribution by scaling the total sum to 1.
    let sum = kernel.iter().sum::<f64>();
    kernel.iter_mut().for_each(|x| *x /= sum);

    kernel
}

/// Returns a size of the box blur kernel to approximate the gaussian blur.
fn box_blur_kernel_size(std_deviation: f64) -> usize {
    let d = (std_deviation * 3.0 * (2.0 * f64::consts::PI).sqrt() / 4.0 + 0.5).floor();
    let d = d.min(MAXIMUM_KERNEL_SIZE as f64);
    d as usize
}

/// Applies three box blurs to approximate the gaussian blur.
///
/// This is intended to be used in two steps, horizontal and vertical.
fn three_box_blurs<B: BlurDirection>(
    surface: &SharedImageSurface,
    bounds: IRect,
    std_deviation: f64,
) -> Result<SharedImageSurface, FilterError> {
    let d = box_blur_kernel_size(std_deviation);
    if d == 0 {
        return Ok(surface.clone());
    }

    let surface = if d % 2 == 1 {
        // Odd kernel sizes just get three successive box blurs.
        let mut surface = surface.clone();

        for _ in 0..3 {
            surface = surface.box_blur::<B>(bounds, d, d / 2)?;
        }

        surface
    } else {
        // Even kernel sizes have a more interesting scheme.
        let surface = surface.box_blur::<B>(bounds, d, d / 2)?;
        let surface = surface.box_blur::<B>(bounds, d, d / 2 - 1)?;

        let d = d + 1;
        surface.box_blur::<B>(bounds, d, d / 2)?
    };

    Ok(surface)
}

/// Applies the gaussian blur.
///
/// This is intended to be used in two steps, horizontal and vertical.
fn gaussian_blur(
    input_surface: &SharedImageSurface,
    bounds: IRect,
    std_deviation: f64,
    vertical: bool,
) -> Result<SharedImageSurface, FilterError> {
    let kernel = gaussian_kernel(std_deviation);
    let (rows, cols) = if vertical {
        (kernel.len(), 1)
    } else {
        (1, kernel.len())
    };
    let kernel = DMatrix::from_data(VecStorage::new(
        Dynamic::new(rows),
        Dynamic::new(cols),
        kernel,
    ));

    Ok(input_surface.convolve(
        bounds,
        ((cols / 2) as i32, (rows / 2) as i32),
        &kernel,
        EdgeMode::None,
    )?)
}

impl FilterEffect for FeGaussianBlur {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);

        let (std_x, std_y) = self.std_deviation;
        let (std_x, std_y) = ctx.paffine().transform_distance(std_x, std_y);

        // The deviation can become negative here due to the transform.
        let std_x = std_x.abs();
        let std_y = std_y.abs();

        // Performance TODO: gaussian blur is frequently used for shadows, operating on SourceAlpha
        // (so the image is alpha-only). We can use this to not waste time processing the other
        // channels.

        // Horizontal convolution.
        let horiz_result_surface = if std_x != 0.0 {
            // The spec says for deviation >= 2.0 three box blurs can be used as an optimization.
            if std_x >= 2.0 {
                three_box_blurs::<Horizontal>(input.surface(), bounds, std_x)?
            } else {
                gaussian_blur(input.surface(), bounds, std_x, false)?
            }
        } else {
            input.surface().clone()
        };

        // Vertical convolution.
        let output_surface = if std_y != 0.0 {
            // The spec says for deviation >= 2.0 three box blurs can be used as an optimization.
            if std_y >= 2.0 {
                three_box_blurs::<Vertical>(&horiz_result_surface, bounds, std_y)?
            } else {
                gaussian_blur(&horiz_result_surface, bounds, std_y, true)?
            }
        } else {
            horiz_result_surface
        };

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: output_surface,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        true
    }
}
<commit_msg>gaussian_blur: shorten code<commit_after>use std::cmp::min;
use std::f64;

use markup5ever::{expanded_name, local_name, namespace_url, ns};
use nalgebra::{DMatrix, Dynamic, VecStorage};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers::{NumberOptionalNumber, ParseValue};
use crate::property_bag::PropertyBag;
use crate::rect::IRect;
use crate::surface_utils::{
    shared_surface::{BlurDirection, Horizontal, SharedImageSurface, Vertical},
    EdgeMode,
};

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, PrimitiveWithInput};

/// The maximum gaussian blur kernel size.
///
/// The value of 500 is used in webkit.
const MAXIMUM_KERNEL_SIZE: usize = 500;

/// The `feGaussianBlur` filter primitive.
pub struct FeGaussianBlur {
    base: PrimitiveWithInput,
    std_deviation: (f64, f64),
}

impl Default for FeGaussianBlur {
    /// Constructs a new `GaussianBlur` with empty properties.
    #[inline]
    fn default() -> FeGaussianBlur {
        FeGaussianBlur {
            base: PrimitiveWithInput::new::<Self>(),
            std_deviation: (0.0, 0.0),
        }
    }
}

impl NodeTrait for FeGaussianBlur {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "stdDeviation") => {
                    let NumberOptionalNumber(x, y) =
                        attr.parse_and_validate(value, |v: NumberOptionalNumber<f64>| {
                            if v.0 >= 0.0 && v.1 >= 0.0 {
                                Ok(v)
                            } else {
                                Err(ValueErrorKind::value_error("values can't be negative"))
                            }
                        })?;

                    self.std_deviation = (x, y);
                }
                _ => (),
            }
        }

        Ok(())
    }
}

/// Computes a gaussian kernel line for the given standard deviation.
fn gaussian_kernel(std_deviation: f64) -> Vec<f64> {
    assert!(std_deviation > 0.0);

    // Make sure there aren't any infinities.
    let maximal_deviation = (MAXIMUM_KERNEL_SIZE / 2) as f64 / 3.0;

    // Values further away than std_deviation * 3 are too small to contribute anything meaningful.
    let radius = ((std_deviation.min(maximal_deviation) * 3.0) + 0.5) as usize;
    // Clamp the radius rather than diameter because `MAXIMUM_KERNEL_SIZE` might be even and we
    // want an odd-sized kernel.
    let radius = min(radius, (MAXIMUM_KERNEL_SIZE - 1) / 2);
    let diameter = radius * 2 + 1;

    let mut kernel = Vec::with_capacity(diameter);

    let gauss_point = |x: f64| (-x.powi(2) / (2.0 * std_deviation.powi(2))).exp();

    // Fill the matrix by doing numerical integration approximation from -2*std_dev to 2*std_dev,
    // sampling 50 points per pixel. We do the bottom half, mirror it to the top half, then compute
    // the center point. Otherwise asymmetric quantization errors will occur. The formula to
    // integrate is e^-(x^2/2s^2).
    for i in 0..diameter / 2 {
        let base_x = (diameter / 2 + 1 - i) as f64 - 0.5;

        let mut sum = 0.0;
        for j in 1..=50 {
            let r = base_x + 0.02 * f64::from(j);
            sum += gauss_point(r);
        }

        kernel.push(sum / 50.0);
    }

    // We'll compute the middle point later.
    kernel.push(0.0);

    // Mirror the bottom half to the top half.
    for i in 0..diameter / 2 {
        let x = kernel[diameter / 2 - 1 - i];
        kernel.push(x);
    }

    // Find center val -- calculate an odd number of quanta to make it symmetric, even if the
    // center point is weighted slightly higher than others.
    let mut sum = 0.0;
    for j in 0..=50 {
        let r = -0.5 + 0.02 * f64::from(j);
        sum += gauss_point(r);
    }
    kernel[diameter / 2] = sum / 51.0;

    // Normalize the distribution by scaling the total sum to 1.
    let sum = kernel.iter().sum::<f64>();
    kernel.iter_mut().for_each(|x| *x /= sum);

    kernel
}

/// Returns a size of the box blur kernel to approximate the gaussian blur.
fn box_blur_kernel_size(std_deviation: f64) -> usize {
    let d = (std_deviation * 3.0 * (2.0 * f64::consts::PI).sqrt() / 4.0 + 0.5).floor();
    let d = d.min(MAXIMUM_KERNEL_SIZE as f64);
    d as usize
}

/// Applies three box blurs to approximate the gaussian blur.
///
/// This is intended to be used in two steps, horizontal and vertical.
fn three_box_blurs<B: BlurDirection>(
    surface: &SharedImageSurface,
    bounds: IRect,
    std_deviation: f64,
) -> Result<SharedImageSurface, FilterError> {
    let d = box_blur_kernel_size(std_deviation);
    if d == 0 {
        return Ok(surface.clone());
    }

    let surface = if d % 2 == 1 {
        // Odd kernel sizes just get three successive box blurs.
        let mut surface = surface.clone();

        for _ in 0..3 {
            surface = surface.box_blur::<B>(bounds, d, d / 2)?;
        }

        surface
    } else {
        // Even kernel sizes have a more interesting scheme.
        let surface = surface.box_blur::<B>(bounds, d, d / 2)?;
        let surface = surface.box_blur::<B>(bounds, d, d / 2 - 1)?;

        let d = d + 1;
        surface.box_blur::<B>(bounds, d, d / 2)?
    };

    Ok(surface)
}

/// Applies the gaussian blur.
///
/// This is intended to be used in two steps, horizontal and vertical.
fn gaussian_blur(
    input_surface: &SharedImageSurface,
    bounds: IRect,
    std_deviation: f64,
    vertical: bool,
) -> Result<SharedImageSurface, FilterError> {
    let kernel = gaussian_kernel(std_deviation);
    let (rows, cols) = if vertical {
        (kernel.len(), 1)
    } else {
        (1, kernel.len())
    };
    let kernel = DMatrix::from_data(VecStorage::new(
        Dynamic::new(rows),
        Dynamic::new(cols),
        kernel,
    ));

    Ok(input_surface.convolve(
        bounds,
        ((cols / 2) as i32, (rows / 2) as i32),
        &kernel,
        EdgeMode::None,
    )?)
}

impl FilterEffect for FeGaussianBlur {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);

        let (std_x, std_y) = self.std_deviation;
        let (std_x, std_y) = ctx.paffine().transform_distance(std_x, std_y);

        // The deviation can become negative here due to the transform.
        let std_x = std_x.abs();
        let std_y = std_y.abs();

        // Performance TODO: gaussian blur is frequently used for shadows, operating on SourceAlpha
        // (so the image is alpha-only). We can use this to not waste time processing the other
        // channels.

        // Horizontal convolution.
        let horiz_result_surface = if std_x >= 2.0 {
            // The spec says for deviation >= 2.0 three box blurs can be used as an optimization.
            three_box_blurs::<Horizontal>(input.surface(), bounds, std_x)?
        } else if std_x != 0.0 {
            gaussian_blur(input.surface(), bounds, std_x, false)?
        } else {
            input.surface().clone()
        };

        // Vertical convolution.
        let output_surface = if std_y >= 2.0 {
            // The spec says for deviation >= 2.0 three box blurs can be used as an optimization.
            three_box_blurs::<Vertical>(&horiz_result_surface, bounds, std_y)?
        } else if std_y != 0.0 {
            gaussian_blur(&horiz_result_surface, bounds, std_y, true)?
        } else {
            horiz_result_surface
        };

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: output_surface,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        true
    }
}
<|endoftext|>


<commit_before>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;
use std::vec::Vec;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Binary(Vec<u8>),
    Empty
}

enum Opcode {
    EmptyOp = 0x0,
    TextOp = 0x1,
    BinaryOp = 0x2,
    CloseOp = 0x8,
}

struct Message {
    payload: Payload,
    opcode: Opcode,
    fin: u8
 }

impl Message {

    fn from_payload (payload: Payload, fin: u8) -> Message {
        let opcode: Opcode = match payload {
            Payload::Text(_) => Opcode::TextOp,
            Payload::Binary(_) => Opcode::BinaryOp,
            Payload::Empty => Opcode::EmptyOp
        };
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn continue_from_payload (payload: Payload) -> Message {
        let opcode = Opcode::EmptyOp;
        let fin = 0x0;
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn send (&self,
            mut stream: &mut BufferedStream<TcpStream>) {
        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Binary(ref s) => s.as_slice(),
            Payload::Empty => "".as_bytes(),
        };

        let length = msg.len() as u8;

        println!("fin: {}, msg: {}, opcode: {}", self.fin, msg, self.opcode as u8);

        stream.write_u8(self.fin | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();
        stream.flush();
    }

    fn from_buffer (buf: &[u8]) {
        let fin = buf[0] & 0b1000_0000;
        let rsv = buf[0] & 0b0111_0000;
        let opc = buf[0] & 0b0000_1111;
        let msk = buf[0] & 0b0000_0001;
        let len = (buf[1] & 0b0111_1111) as uint;
        let mskkey = buf.slice(2, 6);

        let mut msg = Vec::new();
        for ii in range(0u, len) {
            let ch = mskkey[ii % 4] ^ buf[6 + ii];
            msg.push(ch);
        }

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, msg {}, \nbuf {}",
            fin, rsv, msk, opc, len, mskkey, String::from_utf8(msg),  buf.as_slice());
    }

    fn from_stream(mut stream: &mut BufferedStream<TcpStream>) {
        println!("read first byte");
        let cur_byte: u8 = stream.read_byte().unwrap();
        println!("end read first byte");
        let fin = cur_byte & 0b1000_0000;
        let rsv = cur_byte & 0b0111_0000;
        let opc = cur_byte & 0b0000_1111;
        let msk = cur_byte & 0b0000_0001;

        let cur_byte = stream.read_byte().unwrap();
        let len = (cur_byte & 0b0111_1111) as uint;

        let mskkey = stream.read_exact(4).unwrap();

        let mut msg = Vec::new();
        for ii in range(0u, len) {
            let cur_byte = stream.read_byte().unwrap();
            let ch = mskkey[ii % 4] ^ cur_byte;
            msg.push(ch);
        }

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, msg {}",
            fin, rsv, msk, opc, len, mskkey, String::from_utf8(msg));

    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    // from rfc6455 [page 6]
    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             mut headers: Vec<ClientHeader>) {

    let payload = Payload::Text("text ".to_string());
    let msg = Message::from_payload(payload, 0b0000_0000);
    msg.send(&mut stream);

    let payload = Payload::Text("here".to_string());
    let msg = Message::continue_from_payload(payload);
    let mut stream2 = stream;
    msg.send(&mut stream2);

    let payload = Payload::Empty;
    let msg = Message::from_payload(payload, 0b1000_0000);
    let mut stream3 = stream2;
    msg.send(&mut stream3);

    println!("done sending");

    /*
    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);
    */

    let mut stream4 = stream3;
    Message::from_stream(&mut stream4);

    let mut stream5 = stream4;
    Message::from_stream(&mut stream5);

    /*
    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);
    */

    /*
    let mut stream4 = stream3;
    let mut buf = [0, ..100];
    match stream4.read(&mut buf) {
        Ok(nread) => println!("Read {} bytes", nread),
        Err(e) => println!("error reading: {}", e)
    }

    Message::from_buffer(&buf);

     */

}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("./html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("./html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.as_bytes()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.as_bytes()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<commit_msg>echo back a message<commit_after>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;
use std::vec::Vec;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Binary(Vec<u8>),
    Empty
}

enum Opcode {
    EmptyOp = 0x0,
    TextOp = 0x1,
    BinaryOp = 0x2,
    CloseOp = 0x8,
}

struct Message {
    payload: Payload,
    opcode: Opcode,
    fin: u8
 }

impl Message {

    fn from_payload (payload: Payload, fin: u8) -> Message {
        let opcode: Opcode = match payload {
            Payload::Text(_) => Opcode::TextOp,
            Payload::Binary(_) => Opcode::BinaryOp,
            Payload::Empty => Opcode::EmptyOp
        };
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn continue_from_payload (payload: Payload) -> Message {
        let opcode = Opcode::EmptyOp;
        let fin = 0x0;
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn send (&self,
            mut stream: &mut BufferedStream<TcpStream>) {
        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Binary(ref s) => s.as_slice(),
            Payload::Empty => "".as_bytes(),
        };

        let length = msg.len() as u8;

        println!("fin: {}, msg: {}, opcode: {}", self.fin, msg, self.opcode as u8);

        stream.write_u8(self.fin | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();
        stream.flush();
    }

    fn from_buffer (buf: &[u8]) {
        let fin = buf[0] & 0b1000_0000;
        let rsv = buf[0] & 0b0111_0000;
        let opc = buf[0] & 0b0000_1111;
        let msk = buf[0] & 0b0000_0001;
        let len = (buf[1] & 0b0111_1111) as uint;
        let mskkey = buf.slice(2, 6);

        let mut msg = Vec::new();
        for ii in range(0u, len) {
            let ch = mskkey[ii % 4] ^ buf[6 + ii];
            msg.push(ch);
        }

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, msg {}, \nbuf {}",
            fin, rsv, msk, opc, len, mskkey, String::from_utf8(msg),  buf.as_slice());
    }

    fn from_stream(mut stream: &mut BufferedStream<TcpStream>) -> Message {
        let cur_byte: u8 = stream.read_byte().unwrap();

        let fin = cur_byte & 0b1000_0000;
        let rsv = cur_byte & 0b0111_0000;
        let opc = cur_byte & 0b0000_1111;
        let msk = cur_byte & 0b0000_0001;

        let cur_byte: u8 = stream.read_byte().unwrap();
        let len = (cur_byte & 0b0111_1111) as uint;

        let mskkey = stream.read_exact(4).unwrap();

        let mut msg = Vec::new();
        for ii in range(0u, len) {
            let cur_byte: u8 = stream.read_byte().unwrap();
            let ch = mskkey[ii % 4] ^ cur_byte;
            msg.push(ch);
        }

        let utf8_msg = match String::from_utf8(msg) {
            Ok(m) => m,
            Err(_) => panic!("I don't know how to ut8 that")
        };

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, msg {}",
            fin, rsv, msk, opc, len, mskkey, utf8_msg);

        let payload = Payload::Text(utf8_msg);
        return Message::from_payload(payload, fin);
    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    // from rfc6455 [page 6]
    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             mut headers: Vec<ClientHeader>) {

    let payload = Payload::Text("text ".to_string());
    let msg = Message::from_payload(payload, 0b0000_0000);
    msg.send(&mut stream);

    let payload = Payload::Text("here".to_string());
    let msg = Message::continue_from_payload(payload);
    let mut stream2 = stream;
    msg.send(&mut stream2);

    let payload = Payload::Empty;
    let msg = Message::from_payload(payload, 0b1000_0000);
    let mut stream3 = stream2;
    msg.send(&mut stream3);

    println!("done sending");

    /*
    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);
    */

    let mut stream4 = stream3;
    Message::from_stream(&mut stream4);

    let mut stream5 = stream4;
    let echo_msg = Message::from_stream(&mut stream5);

    echo_msg.send(&mut stream5);

    /*
    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);
    */

    /*
    let mut stream4 = stream3;
    let mut buf = [0, ..100];
    match stream4.read(&mut buf) {
        Ok(nread) => println!("Read {} bytes", nread),
        Err(e) => println!("error reading: {}", e)
    }

    Message::from_buffer(&buf);

     */

}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("./html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("./html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.as_bytes()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.as_bytes()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::{Diagnostic, DiagnosticsResult, Location, NamedItem, WithLocation};
use graphql_ir::{
    Condition, FragmentSpread, InlineFragment, LinkedField, OperationDefinition, Program,
    ScalarField, Selection, Transformed, Transformer, ValidationMessage,
};
use intern::string_key::{Intern, StringKey};
use lazy_static::lazy_static;
use schema::{FieldID, Schema};
use std::sync::Arc;

lazy_static! {
    static ref ASSIGNABLE_DIRECTIVE: StringKey = "assignable".intern();
    static ref UPDATABLE_DIRECTIVE: StringKey = "updatable".intern();
}

pub fn transform_assignable_fragment_spreads(program: &Program) -> DiagnosticsResult<Program> {
    let mut transform = AssignableFragmentSpread {
        program,
        errors: Default::default(),
        path: vec![],
    };

    let next_program = transform
        .transform_program(program)
        .replace_or_else(|| program.clone());

    if transform.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transform.errors)
    }
}

struct AssignableFragmentSpread<'s> {
    program: &'s Program,
    errors: Vec<Diagnostic>,
    path: Vec<PathSegment>,
}

impl<'s> AssignableFragmentSpread<'s> {
    /// 1. Validate that the assignable fragment does not have @skip/@defer, and
    /// is not within an inline fragment with directives, and is nested in a linked field
    /// 2. Mark the enclosing linked field as containing an assignable fragment spread.
    /// This later results in an __id (clientid_field) selection being added to the linked
    /// field.
    fn validate_nesting_and_mark_enclosing_linked_field(
        &mut self,
        fragment_spread: &FragmentSpread,
    ) {
        let mut directly_in_condition = None;
        let mut in_linked_field = false;
        let mut in_inline_fragment = false;

        for (index, item) in self.path.iter_mut().rev().enumerate() {
            match item {
                PathSegment::Condition(c) => {
                    // We can encounter a condition (before a linked field) in two ways:
                    // Directly on the assignable fragment spread: ... Assignable_foo @skip
                    // or
                    // As a directive on an inline fragment ... @skip { ...Assignable_foo }
                    if index == 0 {
                        directly_in_condition = Some(*c);
                    }
                }
                PathSegment::LinkedField {
                    encountered_assignable_fragment_spread,
                } => {
                    in_linked_field = true;
                    *encountered_assignable_fragment_spread = true;
                    break;
                }
                PathSegment::InlineFragment => {
                    in_inline_fragment = true;
                }
            }
        }

        if let Some(condition_directive_name) = directly_in_condition {
            self.errors.push(Diagnostic::error(
                ValidationMessage::AssignableFragmentSpreadNoOtherDirectives {
                    disallowed_directive_name: condition_directive_name.intern(),
                },
                fragment_spread.fragment.location,
            ));
        }
        if in_inline_fragment {
            self.errors.push(Diagnostic::error(
                ValidationMessage::AssignableFragmentSpreadNotWithinInlineFragment,
                fragment_spread.fragment.location,
            ));
        }
        if !in_linked_field {
            self.errors.push(Diagnostic::error(
                ValidationMessage::AssignableNoTopLevelFragmentSpreads,
                fragment_spread.fragment.location,
            ));
        }
    }
}

#[derive(Debug)]
enum PathSegment {
    Condition(&'static str),
    LinkedField {
        encountered_assignable_fragment_spread: bool,
    },
    InlineFragment,
}

impl<'s> Transformer for AssignableFragmentSpread<'s> {
    const NAME: &'static str = "RequiredDirectiveTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        if operation.directives.named(*UPDATABLE_DIRECTIVE).is_some() {
            Transformed::Keep
        } else {
            self.default_transform_operation(operation)
        }
    }

    fn transform_fragment_spread(
        &mut self,
        fragment_spread: &FragmentSpread,
    ) -> Transformed<Selection> {
        // When we encounter a spread of an assignable fragment, we
        // return the current fragment spread and a peer inline fragment of the form
        // ... on FragmentType { __isFragmentName: __typename }
        // However, because we are returning Transformed<Selection>, i.e. a single selection, we
        // instead return
        // ... on FragmentType { ...ExistingFragmentSpread, __isFragmentName }
        let fragment_definition = self
            .program
            .fragment(fragment_spread.fragment.item)
            .expect("Expected fragment to exist.");

        if fragment_definition
            .directives
            .named(*ASSIGNABLE_DIRECTIVE)
            .is_none()
        {
            return Transformed::Keep;
        }

        self.validate_nesting_and_mark_enclosing_linked_field(fragment_spread);

        // Assignable fragments cannot have directives, but we error only on the first one
        if let Some(directive) = fragment_spread.directives.first() {
            self.errors.push(Diagnostic::error(
                ValidationMessage::AssignableFragmentSpreadNoOtherDirectives {
                    disallowed_directive_name: directive.name.item,
                },
                directive.name.location,
            ));
        }

        if fragment_definition.type_condition.is_abstract_type() {
            let new_inline_fragment = Selection::InlineFragment(Arc::new(InlineFragment {
                type_condition: Some(fragment_definition.type_condition),
                directives: vec![],
                selections: vec![
                    Selection::FragmentSpread(Arc::new(fragment_spread.clone())),
                    // This is the "abstract fragment spread marker"
                    Selection::ScalarField(Arc::new(ScalarField {
                        alias: Some(WithLocation {
                            location: Location::generated(),
                            item: format!("__is{}", fragment_spread.fragment.item.lookup())
                                .intern(),
                        }),
                        definition: WithLocation {
                            location: Location::generated(),
                            item: self.program.schema.typename_field(),
                        },
                        arguments: vec![],
                        directives: vec![],
                    })),
                ],
            }));
            Transformed::Replace(new_inline_fragment)
        } else {
            Transformed::Keep
        }
    }

    fn transform_linked_field(&mut self, linked_field: &LinkedField) -> Transformed<Selection> {
        self.path.push(PathSegment::LinkedField {
            encountered_assignable_fragment_spread: false,
        });
        let response = self.default_transform_linked_field(linked_field);
        let encountered_assignable_fragment_spread = if let PathSegment::LinkedField {
            encountered_assignable_fragment_spread,
        } =
            self.path.pop().expect("path should be empty")
        {
            encountered_assignable_fragment_spread
        } else {
            panic!("Unexpected non-linked field");
        };

        match response {
            Transformed::Delete => panic!("Unexpected Transformed::Delete"),
            Transformed::Keep => {
                if encountered_assignable_fragment_spread {
                    get_transformed_linked_field(linked_field, self.program.schema.clientid_field())
                } else {
                    Transformed::Keep
                }
            }
            Transformed::Replace(selection) => {
                if encountered_assignable_fragment_spread {
                    let linked_field = match selection {
                        Selection::LinkedField(l) => l,
                        _ => panic!("Unexpected non-linked field"),
                    };
                    get_transformed_linked_field(
                        &linked_field,
                        self.program.schema.clientid_field(),
                    )
                } else {
                    Transformed::Replace(selection)
                }
            }
        }
    }

    fn transform_condition(&mut self, condition: &Condition) -> Transformed<Selection> {
        self.path
            .push(PathSegment::Condition(condition.directive_name()));
        let response = self.default_transform_condition(condition);
        self.path.pop().expect("path should not be empty");
        response
    }

    fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed<Selection> {
        self.path.push(PathSegment::InlineFragment);
        let response = self.default_transform_inline_fragment(fragment);
        self.path.pop().expect("path should not be empty");
        response
    }
}

fn get_transformed_linked_field(
    linked_field: &LinkedField,
    additional_field: FieldID,
) -> Transformed<Selection> {
    let mut selections = linked_field.selections.clone();
    selections.push(Selection::ScalarField(Arc::new(ScalarField {
        alias: None,
        definition: WithLocation {
            location: Location::generated(),
            item: additional_field,
        },
        arguments: vec![],
        directives: vec![],
    })));
    Transformed::Replace(Selection::LinkedField(Arc::new(LinkedField {
        selections,
        directives: linked_field.directives.clone(),
        alias: linked_field.alias,
        definition: linked_field.definition,
        arguments: linked_field.arguments.clone(),
    })))
}
<commit_msg>Update transform's NAME field to be accurate<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::{Diagnostic, DiagnosticsResult, Location, NamedItem, WithLocation};
use graphql_ir::{
    Condition, FragmentSpread, InlineFragment, LinkedField, OperationDefinition, Program,
    ScalarField, Selection, Transformed, Transformer, ValidationMessage,
};
use intern::string_key::{Intern, StringKey};
use lazy_static::lazy_static;
use schema::{FieldID, Schema};
use std::sync::Arc;

lazy_static! {
    static ref ASSIGNABLE_DIRECTIVE: StringKey = "assignable".intern();
    static ref UPDATABLE_DIRECTIVE: StringKey = "updatable".intern();
}

pub fn transform_assignable_fragment_spreads(program: &Program) -> DiagnosticsResult<Program> {
    let mut transform = AssignableFragmentSpread {
        program,
        errors: Default::default(),
        path: vec![],
    };

    let next_program = transform
        .transform_program(program)
        .replace_or_else(|| program.clone());

    if transform.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transform.errors)
    }
}

struct AssignableFragmentSpread<'s> {
    program: &'s Program,
    errors: Vec<Diagnostic>,
    path: Vec<PathSegment>,
}

impl<'s> AssignableFragmentSpread<'s> {
    /// 1. Validate that the assignable fragment does not have @skip/@defer, and
    /// is not within an inline fragment with directives, and is nested in a linked field
    /// 2. Mark the enclosing linked field as containing an assignable fragment spread.
    /// This later results in an __id (clientid_field) selection being added to the linked
    /// field.
    fn validate_nesting_and_mark_enclosing_linked_field(
        &mut self,
        fragment_spread: &FragmentSpread,
    ) {
        let mut directly_in_condition = None;
        let mut in_linked_field = false;
        let mut in_inline_fragment = false;

        for (index, item) in self.path.iter_mut().rev().enumerate() {
            match item {
                PathSegment::Condition(c) => {
                    // We can encounter a condition (before a linked field) in two ways:
                    // Directly on the assignable fragment spread: ... Assignable_foo @skip
                    // or
                    // As a directive on an inline fragment ... @skip { ...Assignable_foo }
                    if index == 0 {
                        directly_in_condition = Some(*c);
                    }
                }
                PathSegment::LinkedField {
                    encountered_assignable_fragment_spread,
                } => {
                    in_linked_field = true;
                    *encountered_assignable_fragment_spread = true;
                    break;
                }
                PathSegment::InlineFragment => {
                    in_inline_fragment = true;
                }
            }
        }

        if let Some(condition_directive_name) = directly_in_condition {
            self.errors.push(Diagnostic::error(
                ValidationMessage::AssignableFragmentSpreadNoOtherDirectives {
                    disallowed_directive_name: condition_directive_name.intern(),
                },
                fragment_spread.fragment.location,
            ));
        }
        if in_inline_fragment {
            self.errors.push(Diagnostic::error(
                ValidationMessage::AssignableFragmentSpreadNotWithinInlineFragment,
                fragment_spread.fragment.location,
            ));
        }
        if !in_linked_field {
            self.errors.push(Diagnostic::error(
                ValidationMessage::AssignableNoTopLevelFragmentSpreads,
                fragment_spread.fragment.location,
            ));
        }
    }
}

#[derive(Debug)]
enum PathSegment {
    Condition(&'static str),
    LinkedField {
        encountered_assignable_fragment_spread: bool,
    },
    InlineFragment,
}

impl<'s> Transformer for AssignableFragmentSpread<'s> {
    const NAME: &'static str = "AssignableFragmentTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        if operation.directives.named(*UPDATABLE_DIRECTIVE).is_some() {
            Transformed::Keep
        } else {
            self.default_transform_operation(operation)
        }
    }

    fn transform_fragment_spread(
        &mut self,
        fragment_spread: &FragmentSpread,
    ) -> Transformed<Selection> {
        // When we encounter a spread of an assignable fragment, we
        // return the current fragment spread and a peer inline fragment of the form
        // ... on FragmentType { __isFragmentName: __typename }
        // However, because we are returning Transformed<Selection>, i.e. a single selection, we
        // instead return
        // ... on FragmentType { ...ExistingFragmentSpread, __isFragmentName }
        let fragment_definition = self
            .program
            .fragment(fragment_spread.fragment.item)
            .expect("Expected fragment to exist.");

        if fragment_definition
            .directives
            .named(*ASSIGNABLE_DIRECTIVE)
            .is_none()
        {
            return Transformed::Keep;
        }

        self.validate_nesting_and_mark_enclosing_linked_field(fragment_spread);

        // Assignable fragments cannot have directives, but we error only on the first one
        if let Some(directive) = fragment_spread.directives.first() {
            self.errors.push(Diagnostic::error(
                ValidationMessage::AssignableFragmentSpreadNoOtherDirectives {
                    disallowed_directive_name: directive.name.item,
                },
                directive.name.location,
            ));
        }

        if fragment_definition.type_condition.is_abstract_type() {
            let new_inline_fragment = Selection::InlineFragment(Arc::new(InlineFragment {
                type_condition: Some(fragment_definition.type_condition),
                directives: vec![],
                selections: vec![
                    Selection::FragmentSpread(Arc::new(fragment_spread.clone())),
                    // This is the "abstract fragment spread marker"
                    Selection::ScalarField(Arc::new(ScalarField {
                        alias: Some(WithLocation {
                            location: Location::generated(),
                            item: format!("__is{}", fragment_spread.fragment.item.lookup())
                                .intern(),
                        }),
                        definition: WithLocation {
                            location: Location::generated(),
                            item: self.program.schema.typename_field(),
                        },
                        arguments: vec![],
                        directives: vec![],
                    })),
                ],
            }));
            Transformed::Replace(new_inline_fragment)
        } else {
            Transformed::Keep
        }
    }

    fn transform_linked_field(&mut self, linked_field: &LinkedField) -> Transformed<Selection> {
        self.path.push(PathSegment::LinkedField {
            encountered_assignable_fragment_spread: false,
        });
        let response = self.default_transform_linked_field(linked_field);
        let encountered_assignable_fragment_spread = if let PathSegment::LinkedField {
            encountered_assignable_fragment_spread,
        } =
            self.path.pop().expect("path should be empty")
        {
            encountered_assignable_fragment_spread
        } else {
            panic!("Unexpected non-linked field");
        };

        match response {
            Transformed::Delete => panic!("Unexpected Transformed::Delete"),
            Transformed::Keep => {
                if encountered_assignable_fragment_spread {
                    get_transformed_linked_field(linked_field, self.program.schema.clientid_field())
                } else {
                    Transformed::Keep
                }
            }
            Transformed::Replace(selection) => {
                if encountered_assignable_fragment_spread {
                    let linked_field = match selection {
                        Selection::LinkedField(l) => l,
                        _ => panic!("Unexpected non-linked field"),
                    };
                    get_transformed_linked_field(
                        &linked_field,
                        self.program.schema.clientid_field(),
                    )
                } else {
                    Transformed::Replace(selection)
                }
            }
        }
    }

    fn transform_condition(&mut self, condition: &Condition) -> Transformed<Selection> {
        self.path
            .push(PathSegment::Condition(condition.directive_name()));
        let response = self.default_transform_condition(condition);
        self.path.pop().expect("path should not be empty");
        response
    }

    fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed<Selection> {
        self.path.push(PathSegment::InlineFragment);
        let response = self.default_transform_inline_fragment(fragment);
        self.path.pop().expect("path should not be empty");
        response
    }
}

fn get_transformed_linked_field(
    linked_field: &LinkedField,
    additional_field: FieldID,
) -> Transformed<Selection> {
    let mut selections = linked_field.selections.clone();
    selections.push(Selection::ScalarField(Arc::new(ScalarField {
        alias: None,
        definition: WithLocation {
            location: Location::generated(),
            item: additional_field,
        },
        arguments: vec![],
        directives: vec![],
    })));
    Transformed::Replace(Selection::LinkedField(Arc::new(LinkedField {
        selections,
        directives: linked_field.directives.clone(),
        alias: linked_field.alias,
        definition: linked_field.definition,
        arguments: linked_field.arguments.clone(),
    })))
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! # pest. The Elegant Parser
//!
//! pest is a general purpose parser written in Rust with a focus on accessibility, correctness,
//! and performance. It uses parsing expression grammars (or [PEG]) as input, which are similar in
//! spirit to regular expressions, but which offer the enhanced expressivity needed to parse
//! complex languages.
//!
//! [PEG]: https://en.wikipedia.org/wiki/Parsing_expression_grammar
//!
//! ## Getting started
//!
//! The recommended way to start parsing with pest is to read the official [book].
//!
//! Other helpful resources:
//!
//! * API reference on [docs.rs]
//! * play with grammars and share them on our [fiddle]
//! * leave feedback, ask questions, or greet us on [Gitter]
//!
//! [book]: https://pest-parser.github.io/book
//! [docs.rs]: https://docs.rs/pest
//! [fiddle]: https://pest-parser.github.io/#editor
//! [Gitter]: https://gitter.im/dragostis/pest
//!
//! ## Usage
//!
//! The core of pest is the trait [`Parser`], which provides an interface to the parsing
//! functionality.
//!
//! The accompanying crate `pest_derive` can automatically generate a [`Parser`] from a PEG
//! grammar. Using `pest_derive` is highly encouraged, but it is also possible to implement
//! [`Parser`] manually if required.
//!
//! ## `.pest` files
//!
//! Grammar definitions reside in custom `.pest` files located in the crate `src` directory.
//! Parsers are automatically generated from these files using `#[derive(Parser)]` and a special
//! `#[grammar = "..."]` attribute on a dummy struct.
//!
//! ```ignore
//! #[derive(Parser)]
//! #[grammar = "path/to/my_grammar.pest"] // relative to src
//! struct MyParser;
//! ```
//!
//! The syntax of `.pest` files is documented in the [`pest_derive` crate].
//!
//! [`Parser`]: trait.Parser.html
//! [`pest_derive` crate]: https://docs.rs/pest_derive/

#![doc(html_root_url = "https://docs.rs/pest")]

extern crate ucd_trie;

pub use parser::Parser;
pub use parser_state::{state, Atomicity, Lookahead, MatchDir, ParseResult, ParserState};
pub use position::Position;
pub use span::Span;
use std::fmt::Debug;
use std::hash::Hash;
pub use token::Token;

pub mod error;
pub mod iterators;
mod macros;
mod parser;
mod parser_state;
mod position;
pub mod prec_climber;
mod span;
mod stack;
mod token;
#[doc(hidden)]
pub mod unicode;

/// A trait which parser rules must implement.
///
/// This trait is set up so that any struct that implements all of its required traits will
/// automatically implement this trait as well.
///
/// This is essentially a [trait alias](https://github.com/rust-lang/rfcs/pull/1733). When trait
/// aliases are implemented, this may be replaced by one.
pub trait RuleType: Copy + Debug + Eq + Hash + Ord {}

impl<T: Copy + Debug + Eq + Hash + Ord> RuleType for T {}
<commit_msg>export Lines<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! # pest. The Elegant Parser
//!
//! pest is a general purpose parser written in Rust with a focus on accessibility, correctness,
//! and performance. It uses parsing expression grammars (or [PEG]) as input, which are similar in
//! spirit to regular expressions, but which offer the enhanced expressivity needed to parse
//! complex languages.
//!
//! [PEG]: https://en.wikipedia.org/wiki/Parsing_expression_grammar
//!
//! ## Getting started
//!
//! The recommended way to start parsing with pest is to read the official [book].
//!
//! Other helpful resources:
//!
//! * API reference on [docs.rs]
//! * play with grammars and share them on our [fiddle]
//! * leave feedback, ask questions, or greet us on [Gitter]
//!
//! [book]: https://pest-parser.github.io/book
//! [docs.rs]: https://docs.rs/pest
//! [fiddle]: https://pest-parser.github.io/#editor
//! [Gitter]: https://gitter.im/dragostis/pest
//!
//! ## Usage
//!
//! The core of pest is the trait [`Parser`], which provides an interface to the parsing
//! functionality.
//!
//! The accompanying crate `pest_derive` can automatically generate a [`Parser`] from a PEG
//! grammar. Using `pest_derive` is highly encouraged, but it is also possible to implement
//! [`Parser`] manually if required.
//!
//! ## `.pest` files
//!
//! Grammar definitions reside in custom `.pest` files located in the crate `src` directory.
//! Parsers are automatically generated from these files using `#[derive(Parser)]` and a special
//! `#[grammar = "..."]` attribute on a dummy struct.
//!
//! ```ignore
//! #[derive(Parser)]
//! #[grammar = "path/to/my_grammar.pest"] // relative to src
//! struct MyParser;
//! ```
//!
//! The syntax of `.pest` files is documented in the [`pest_derive` crate].
//!
//! [`Parser`]: trait.Parser.html
//! [`pest_derive` crate]: https://docs.rs/pest_derive/

#![doc(html_root_url = "https://docs.rs/pest")]

extern crate ucd_trie;

pub use parser::Parser;
pub use parser_state::{state, Atomicity, Lookahead, MatchDir, ParseResult, ParserState};
pub use position::Position;
pub use span::{Span, Lines};
use std::fmt::Debug;
use std::hash::Hash;
pub use token::Token;

pub mod error;
pub mod iterators;
mod macros;
mod parser;
mod parser_state;
mod position;
pub mod prec_climber;
mod span;
mod stack;
mod token;
#[doc(hidden)]
pub mod unicode;

/// A trait which parser rules must implement.
///
/// This trait is set up so that any struct that implements all of its required traits will
/// automatically implement this trait as well.
///
/// This is essentially a [trait alias](https://github.com/rust-lang/rfcs/pull/1733). When trait
/// aliases are implemented, this may be replaced by one.
pub trait RuleType: Copy + Debug + Eq + Hash + Ord {}

impl<T: Copy + Debug + Eq + Hash + Ord> RuleType for T {}
<|endoftext|>