<commit_before>#![feature(question_mark)]

extern crate difference;
extern crate getopts;
extern crate test_util;
extern crate parser2;

use std::env;
use std::fmt;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use difference::{diff, print_diff};
use getopts::{Matches, Options};

use parser2::ast_printer::{self, NoAnn};
use parser2::codemap::CodeMap;
use parser2::error_handler::{DiagnosticBuilder};
use parser2::lexer::{StringReader};
use parser2::parser::{ParseSess, Parser};

use test_util::file as test;

fn print_usage(program: &str, opts: &Options) {
  let brief = format!("Usage: {} TEST_DIR [options]", program);
  print!("{}", opts.usage(&brief));
}

fn list_files(dir: &Path, extention: &str) -> io::Result<Vec<PathBuf>> {
  Ok(test::list_files(dir)?
    .map(|e| e.ok().unwrap().path())
    .filter(|p| p.extension().unwrap().to_str().unwrap() == extention)
    .collect::<Vec<PathBuf>>())

}

fn extract_test_name<'a>(file_name: &'a Path) -> &'a str{
  file_name.file_stem().unwrap().to_str().unwrap()
}

impl<'a> fmt::Display for OsStrDisplay<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.s.unwrap().to_str().unwrap())
  }
}

struct OsStrDisplay<'a> {
  s: Option<&'a OsStr>
}

fn display<'a>(s: Option<&'a OsStr>) -> OsStrDisplay {
  OsStrDisplay {s: s}
}

fn test_parser_succ(basedir: &Path, tmpdir: &Path, stop_if_error: bool) -> PResult<()> {
  // for each file in dir
  //   parser source file into AST
  //   transform AST to source via pretty printer
  //   read a expected result from a file
  //   compare a pretty printed result with a expected result
  // end for

  let mut succ_dir = PathBuf::from(basedir);
  succ_dir.push("success");
  let succ_dir = succ_dir.as_path();

  let mut succ_res_dir = PathBuf::from(tmpdir);
  succ_res_dir.push("success");
  let succ_res_dir = succ_res_dir.as_path();

  for p in list_files(succ_dir, "fl")? {

    let fpath = p.as_path();
    let test_name = extract_test_name(fpath);

    // convert source into ast, and then generates a source code from ast.
    let pp = src_to_pp(fpath).ok().unwrap();

    let mut res_path = PathBuf::from(succ_res_dir);
    res_path.push(format!("{}.{}", test_name, "result"));
    let mut result_file = File::create(&res_path)?;
    result_file.write_all(pp.as_bytes())?;
    result_file.sync_all()?;

    let mut expected_path = PathBuf::from(succ_dir);
    expected_path.push(format!("{}.{}", test_name, "result"));
    let expected = test::file_to_string(expected_path.as_path())?;

    print!("Testing {} ... ", display(fpath.file_name()));

    let (dist, _) = diff(&pp, &expected, "");

    if dist > 0 {
      println!(" Failed, difference:");
      print_diff(&expected, &pp, "");
      if stop_if_error {
        return Err(PTestError::TestFailure);
      }
      println!("");
    } else {
      println!(" Ok")
    }
  }

  Ok(())
}

pub type PResult<T> = Result<T, PTestError>;

pub enum PTestError {
  ParseError(DiagnosticBuilder),
  TestFailure,
  IOError(io::Error)
}

impl From<DiagnosticBuilder> for PTestError {
  fn from(err: DiagnosticBuilder) -> PTestError {
    PTestError::ParseError(err)
  }
}

impl From<io::Error> for PTestError {
  fn from(err: io::Error) -> PTestError {
    PTestError::IOError(err)
  }
}

pub type TResult<T> = Result<T, PTestError>;

fn src_to_pp(src_path: &Path) -> TResult<String> {
  assert!(src_path.is_absolute(),
    "A source path must be absolute path, but it is {}.", src_path.to_str().unwrap());

  let sess: ParseSess = ParseSess::new();
  let codemap = CodeMap::new();
  let filemap = codemap.load_file(src_path)?;

  let reader = StringReader::new(&sess.span_diagnostic, filemap);
  let mut parser = Parser::new(&sess, Box::new(reader));
  let package = parser.parse_package()?;

  let rdr: Vec<u8> = test::file_to_string(src_path).unwrap().into();
  let mut rdr = &*rdr;
  let mut out = Vec::new();

  {
    let writer: &mut Write = &mut out;
    let no_ann = NoAnn;

    ast_printer::print_package(&codemap,
                               &sess.span_diagnostic,
                               &package,
                               "test".to_string(),
                               &mut rdr,
                               Box::new(writer),
                               &no_ann,
                               false)?;
  }

  Ok(String::from_utf8(out).expect("from_utf8 conversion error..."))
}

#[allow(unused_variables)]
fn test_parser_fail(basedir: &Path, tmpdir: &Path, stop_if_err: bool) -> PResult<()> {
  println!("test_parser_fail!");

  Ok(())
}

fn setup_opts() -> Options {
  let mut opts = Options::new();
  opts.optflag("h", "help", "print this help menu")
      .optflag("", "parser-success", "Test parsing success")
      .optflag("", "parser-fail", "Test parsing failures");

  opts
}

fn parse_opts(opts: &Options, args: &Vec<String>) -> Matches {
  match opts.parse(&args[1..]) {
    Ok(m) => m,
    Err(e) => {
      println!("{}", e);
      std::process::exit(1);
    }
  }
}

fn program_name() -> String {
  return env::args().nth(0).unwrap();
}

fn may_print_usage_and_exit(m: &Matches, opts: &Options) {
  let program = program_name();
  if m.opt_present("h") {
    print_usage(&program, opts);
    std::process::exit(0);
  }
}

fn absolute_path(path: &str) -> PathBuf {
  let p = PathBuf::from(path);
  if p.is_absolute() {
    p
  } else {
    let mut cur_dir = PathBuf::from(std::env::current_dir().unwrap());
    cur_dir.push(p);
    cur_dir
  }
}

fn check_args_or_exit(m: &Matches, opts: &Options) -> (PathBuf, PathBuf) {
  if m.free.len() == 2 {

    let dirs = (absolute_path(&m.free[0]), absolute_path(&m.free[1]));
    if !dirs.0.exists() {
      println!("The base directory '{}' does not exists.", dirs.0.display());
      print_usage(&program_name(), opts);
      std::process::exit(1);
    }
    return dirs;
  } else {
    print_usage(&program_name(), opts);
    std::process::exit(1);
  }
}

fn setup_tmpdir(tmpdir: &Path) {
  mkdir(tmpdir);

  let mut succ_result = PathBuf::from(tmpdir);
  succ_result.push("success");
  mkdir(succ_result.as_path());
}

fn mkdir(path: &Path) {
  if !path.exists() {
    match fs::create_dir(path) {
      Ok(_) => {},
      Err(why) => {
        println!("! {:?}", why.kind());
        std::process::exit(1);
      }
    }
  }
}

pub type Phase = Box<Fn(&Path, &Path, bool) -> PResult<()>>;

fn setup_phases() -> Vec<(&'static str, Phase)> {
  vec![
    ("parser-success", Box::new(test_parser_succ)),
    ("parser-fail",    Box::new(test_parser_fail))
  ]
}

fn run_phases(data_dir: &Path, tmp_dir: &Path,
              m: &Matches,
              phases: &Vec<(&'static str, Phase)>)
              -> PResult<()> {

  for p in phases.iter() {
    if m.opt_present(p.0) {
      p.1(data_dir, tmp_dir, false)?
    }
  }

  Ok(())
}

fn display_info(basedir: &Path) {
  println!("Running tests on {}...", basedir.display());
}

pub fn main() {
  let args: Vec<String> = env::args().collect();
  let opts = setup_opts();
  let matches = parse_opts(&opts, &args);
  let (basedir, tmpdir) = check_args_or_exit(&matches, &opts);
  let phases = setup_phases();

  setup_tmpdir(&tmpdir);
  display_info(basedir.as_path());
  may_print_usage_and_exit(&matches, &opts);
  run_phases(basedir.as_path(), tmpdir.as_path(), &matches, &phases).ok().unwrap();

  std::process::exit(0);
}<commit_msg>Refactor parser-tests.<commit_after>#![feature(question_mark)]

extern crate difference;
extern crate getopts;
extern crate test_util;
extern crate parser2;

use std::env;
use std::fmt;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use difference::{diff, print_diff};
use getopts::{Matches, Options};

use parser2::ast_printer::{self, NoAnn};
use parser2::codemap::CodeMap;
use parser2::error_handler::{DiagnosticBuilder};
use parser2::lexer::{StringReader};
use parser2::parser::{ParseSess, Parser};

use test_util::file as test;

fn print_usage(program: &str, opts: &Options) {
  let brief = format!("Usage: {} TEST_DIR [options]", program);
  print!("{}", opts.usage(&brief));
}

fn list_files(dir: &Path, extention: &str) -> io::Result<Vec<PathBuf>> {
  Ok(test::list_files(dir)?
    .map(|e| e.ok().unwrap().path())
    .filter(|p| p.extension().unwrap().to_str().unwrap() == extention)
    .collect::<Vec<PathBuf>>())

}

fn extract_test_name<'a>(file_name: &'a Path) -> &'a str{
  file_name.file_stem().unwrap().to_str().unwrap()
}

impl<'a> fmt::Display for OsStrDisplay<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.s.unwrap().to_str().unwrap())
  }
}

struct OsStrDisplay<'a> {
  s: Option<&'a OsStr>
}

fn display<'a>(s: Option<&'a OsStr>) -> OsStrDisplay {
  OsStrDisplay {s: s}
}

pub type AssertFn = Fn(i32, &str, &str, bool) -> TResult<()>;

pub type ExecFn = Fn(&Path) -> TResult<String>;

fn test_base(basedir: &Path, tmpdir: &Path,
             stop_if_err: bool,
             exec_fn: &ExecFn, assert_fn: &AssertFn)
             -> TResult<()> {

  let mut succ_dir = PathBuf::from(basedir);
  succ_dir.push("success");
  let succ_dir = succ_dir.as_path();

  let mut succ_res_dir = PathBuf::from(tmpdir);
  succ_res_dir.push("success");
  let succ_res_dir = succ_res_dir.as_path();

  for p in list_files(succ_dir, "fl")? {
    let fpath = p.as_path();
    let test_name = extract_test_name(fpath);

    // convert source into ast, and then generates a source code from ast.
    let result = exec_fn(fpath)?;

    let mut res_path = PathBuf::from(succ_res_dir);
    res_path.push(format!("{}.{}", test_name, "result"));
    let mut result_file = File::create(&res_path)?;
    result_file.write_all(result.as_bytes())?;
    result_file.sync_all()?;

    let mut expected_path = PathBuf::from(succ_dir);
    expected_path.push(format!("{}.{}", test_name, "result"));
    let expected = test::file_to_string(expected_path.as_path())?;

    print!("Testing {} ... ", display(fpath.file_name()));

    let (dist, _) = diff(&result, &expected, "");
    assert_fn(dist, &expected, &result, stop_if_err)?
  }

  Ok(())
}

fn test_parser_succ(basedir: &Path, tmpdir: &Path, stop_if_err: bool) -> TResult<()> {

  let succ_fn = |edit_dist: i32, expected: &str, result: &str, stop_if_err: bool|
    -> TResult<()> {

    if edit_dist > 0 {
      println!(" Failed, difference:");
      print_diff(expected, result, "");
      if stop_if_err {
        return Err(PTestError::TestFailure);
      }
      println!("");
    } else {
      println!(" Ok")
    }

    Ok(())
  };

  test_base(basedir, tmpdir, stop_if_err, &src_to_pp, &succ_fn)
}

pub enum PTestError {
  ParseError(DiagnosticBuilder),
  TestFailure,
  IOError(io::Error)
}

impl From<DiagnosticBuilder> for PTestError {
  fn from(err: DiagnosticBuilder) -> PTestError {
    PTestError::ParseError(err)
  }
}

impl From<io::Error> for PTestError {
  fn from(err: io::Error) -> PTestError {
    PTestError::IOError(err)
  }
}

pub type TResult<T> = Result<T, PTestError>;

fn src_to_pp(src_path: &Path) -> TResult<String> {
  assert!(src_path.is_absolute(),
    "A source path must be absolute path, but it is {}.", src_path.to_str().unwrap());

  let sess: ParseSess = ParseSess::new();
  let codemap = CodeMap::new();
  let filemap = codemap.load_file(src_path)?;

  let reader = StringReader::new(&sess.span_diagnostic, filemap);
  let mut parser = Parser::new(&sess, Box::new(reader));
  let package = parser.parse_package()?;

  let rdr: Vec<u8> = test::file_to_string(src_path).unwrap().into();
  let mut rdr = &*rdr;
  let mut out = Vec::new();

  {
    let writer: &mut Write = &mut out;
    let no_ann = NoAnn;

    ast_printer::print_package(&codemap,
                               &sess.span_diagnostic,
                               &package,
                               "test".to_string(),
                               &mut rdr,
                               Box::new(writer),
                               &no_ann,
                               false)?;
  }

  Ok(String::from_utf8(out).expect("from_utf8 conversion error..."))
}

#[allow(unused_variables)]
fn test_parser_fail(basedir: &Path, tmpdir: &Path, stop_if_err: bool) -> TResult<()> {
  println!("test_parser_fail!");

  Ok(())
}

fn setup_opts() -> Options {
  let mut opts = Options::new();
  opts.optflag("h", "help", "print this help menu")
      .optflag("", "parser-success", "Test parsing success")
      .optflag("", "parser-fail", "Test parsing failures");

  opts
}

fn parse_opts(opts: &Options, args: &Vec<String>) -> Matches {
  match opts.parse(&args[1..]) {
    Ok(m) => m,
    Err(e) => {
      println!("{}", e);
      std::process::exit(1);
    }
  }
}

fn program_name() -> String {
  return env::args().nth(0).unwrap();
}

fn may_print_usage_and_exit(m: &Matches, opts: &Options) {
  let program = program_name();
  if m.opt_present("h") {
    print_usage(&program, opts);
    std::process::exit(0);
  }
}

fn absolute_path(path: &str) -> PathBuf {
  let p = PathBuf::from(path);
  if p.is_absolute() {
    p
  } else {
    let mut cur_dir = PathBuf::from(std::env::current_dir().unwrap());
    cur_dir.push(p);
    cur_dir
  }
}

fn check_args_or_exit(m: &Matches, opts: &Options) -> (PathBuf, PathBuf) {
  if m.free.len() == 2 {

    let dirs = (absolute_path(&m.free[0]), absolute_path(&m.free[1]));
    if !dirs.0.exists() {
      println!("The base directory '{}' does not exists.", dirs.0.display());
      print_usage(&program_name(), opts);
      std::process::exit(1);
    }
    return dirs;
  } else {
    print_usage(&program_name(), opts);
    std::process::exit(1);
  }
}

fn setup_tmpdir(tmpdir: &Path) {
  mkdir(tmpdir);

  let mut succ_result = PathBuf::from(tmpdir);
  succ_result.push("success");
  mkdir(succ_result.as_path());
}

fn mkdir(path: &Path) {
  if !path.exists() {
    match fs::create_dir(path) {
      Ok(_) => {},
      Err(why) => {
        println!("! {:?}", why.kind());
        std::process::exit(1);
      }
    }
  }
}

pub type Phase = Box<Fn(&Path, &Path, bool) -> TResult<()>>;

fn setup_phases() -> Vec<(&'static str, Phase)> {
  vec![
    ("parser-success", Box::new(test_parser_succ)),
    ("parser-fail",    Box::new(test_parser_fail))
  ]
}

fn run_phases(data_dir: &Path, tmp_dir: &Path,
              m: &Matches,
              phases: &Vec<(&'static str, Phase)>)
              -> TResult<()> {

  for p in phases.iter() {
    if m.opt_present(p.0) {
      p.1(data_dir, tmp_dir, false)?
    }
  }

  Ok(())
}

fn display_info(basedir: &Path) {
  println!("Running tests on {}...", basedir.display());
}

pub fn main() {
  let args: Vec<String> = env::args().collect();
  let opts = setup_opts();
  let matches = parse_opts(&opts, &args);
  let (basedir, tmpdir) = check_args_or_exit(&matches, &opts);
  let phases = setup_phases();

  setup_tmpdir(&tmpdir);
  display_info(basedir.as_path());
  may_print_usage_and_exit(&matches, &opts);
  run_phases(basedir.as_path(), tmpdir.as_path(), &matches, &phases).ok().unwrap();

  std::process::exit(0);
}<|endoftext|>


<commit_before>use std::fs::{File};
use std::io;
use std::path::{Path, PathBuf};
use std::sync::{Arc};
use std::str::from_utf8;

use futures::{Future};
use futures::future::{ok};
use mime_guess::guess_mime_type;
use mime::{TopLevel, Mime};
use tk_http::server::Error;
use tk_http::Status;
use tk_sendfile::{FileOpener, IntoFileOpener, FileReader};

use config::static_files::{VersionChars, VersionedStatic};
use default_error_page::{error_page};
use incoming::{Input, Request, Reply, Transport};
use incoming::reply;
use handlers::files::FileError;
use handlers::files::decode::decode_component;
use handlers::files::pools::get_pool;
use handlers::files::normal;

quick_error! {
    #[derive(Debug, Copy, Clone)]
    pub enum VersionError {
        NoVersion
        BadVersion  // length or chars
        InvalidPath
        NoFile
    }
}

#[cfg(unix)]
struct PathOpen {
    version_path: Result<PathBuf, VersionError>,
    plain_path: Option<PathBuf>,
    settings: Arc<VersionedStatic>,
    file: Option<(File, u64, Mime)>,
}

#[cfg(windows)]
struct PathOpen {
    version_path: Option<PathBuf>,
    plain_path: Option<PathBuf>,
    settings: Arc<VersionedStatic>,
    file: Option<(Mutex<File>, u64, Mime)>,
}

#[cfg(unix)]
fn wrap_file(file: File) -> File {
    file
}

#[cfg(windows)]
fn wrap_file(file: File) -> Mutex<File> {
    Mutex::new(file)
}

fn find_param<'x>(query: &'x str, arg: &str) -> Option<&'x str> {
    for pair in query.split('&') {
        if pair.starts_with(arg) && pair.len() > arg.len()
            && pair[arg.len()..].starts_with("=")
        {
            return Some(&pair[arg.len()+1..]);
        }
    }
    return None;
}

fn path(settings: &VersionedStatic, inp: &Input)
    -> Result<PathBuf, VersionError>
{
    let path = inp.headers.path().unwrap_or("/");
    let path = match path.find(|c| c == '#') {
        Some(idx) => &path[..idx],
        None => path
    };
    let query = path.find(|c| c == '?').ok_or(VersionError::NoVersion)?;
    let (path, query) = path.split_at(query);
    let version = find_param(&query[1..], &settings.version_arg)
        .ok_or(VersionError::NoVersion)?;

    if version.len() != settings.version_len {
        return Err(VersionError::BadVersion);
    }
    match settings.version_chars {
        VersionChars::lowercase_hex => {
            for &c in version.as_bytes() {
                if c < b'0' || (c > b'9' && c < b'a') || c > b'z' {
                    return Err(VersionError::BadVersion);
                }
            }
        }
    }

    let file_name = match path.rfind('/') {
        Some(idx) => &path[idx+1..],
        None => path,
    };
    let mut buf = Vec::with_capacity(
        settings.version_len*2 + 1 + file_name.len());
    let mut offset = 0;
    for &chunk in &settings.version_split {
        buf.extend(version[offset..offset+chunk as usize].as_bytes());
        buf.push(b'/');
        offset += chunk as usize;
    }
    buf.pop();
    buf.push(b'-');
    decode_component(&mut buf, file_name)
        .map_err(|_| VersionError::InvalidPath)?;

    // only valid utf-8 supported so far
    let utf8 = from_utf8(&buf).map_err(|_| VersionError::InvalidPath)?;
    Ok(settings.versioned_root.join(utf8))
}

pub fn serve_versioned<S: Transport>(settings: &Arc<VersionedStatic>,
    mut inp: Input)
    -> Request<S>
{
    let path = path(settings, &inp);
    let npath = normal::path(&settings.fallback, &inp).ok();
    inp.debug.set_fs_path( // TODO(tailhook)
        &path.as_ref().ok().map(|x| -> &Path { x.as_ref() })
        .or(npath.as_ref().map(|x| -> &Path { x.as_ref() }))
        .unwrap_or(&Path::new("")));
    let pool = get_pool(&inp.runtime, &settings.pool);
    let settings = settings.clone();
    if path.is_err() && npath.is_none() {
        inp.debug.set_deny(path.unwrap_err().to_header_string());
        return reply(inp, move |e| {
            Box::new(error_page(Status::NotFound, e))
        });
    }
    reply(inp, move |mut e| {
        Box::new(pool.open(PathOpen::new(path, npath, &settings))
            .then(move |res| match res {
                Ok(file) => {
                    e.status(Status::Ok);
                    e.add_length(file.size());
                    if !settings.overrides_content_type {
                        let mime = file.get_inner().get_mime();
                        match (&mime.0, &settings.text_charset) {
                            (&TopLevel::Text, &Some(ref enc)) => {
                                e.format_header("Content-Type", format_args!(
                                    "{}/{}; charset={}", mime.0, mime.1, enc));
                            }
                            _ => {
                                e.format_header("Content-Type", mime);
                            }
                        }
                    }
                    e.add_extra_headers(&settings.extra_headers);
                    if e.done_headers() {
                        Box::new(e.raw_body()
                            .and_then(|raw_body| file.write_into(raw_body))
                            .map(|raw_body| raw_body.done())
                            .map_err(FileError::Sendfile)
                            .map_err(Error::custom))
                        as Reply<_>
                    } else {
                        Box::new(ok(e.done()))
                    }
                }
                Err(ref err) if err.kind() == io::ErrorKind::NotFound => {
                    Box::new(error_page(Status::NotFound, e))
                }
                // One of the known `Other` issues is when path refers to
                // a directory rather than regular file
                Err(ref err) if err.kind() == io::ErrorKind::Other => {
                    Box::new(error_page(Status::Forbidden, e))
                }
                // TODO(tailhook) find out if we want to expose other
                // errors, for example "Permission denied" and "is a directory"
                Err(_) => {
                    Box::new(error_page(Status::InternalServerError, e))
                }
            }))
    })
}

impl PathOpen {
    fn new(vpath: Result<PathBuf, VersionError>, npath: Option<PathBuf>,
        settings: &Arc<VersionedStatic>)
        -> PathOpen
    {
        PathOpen {
            version_path: vpath,
            plain_path: npath,
            settings: settings.clone(),
            file: None,
        }
    }
    fn get_mime(&self) -> &Mime {
        self.file.as_ref()
            .map(|&(_, _, ref m)| m)
            .unwrap()
    }
}

impl FileOpener for PathOpen {
    fn open(&mut self) -> Result<(&FileReader, u64), io::Error> {
        use self::VersionError::*;
        use config::static_files::FallbackMode::*;
        if self.file.is_none() {
            let vers = match self.version_path.as_ref().map(|x| File::open(&x))
            {
                Ok(Ok(file)) => Ok(file),
                Ok(Err(ref e)) if e.kind() == io::ErrorKind::NotFound => {
                    Err(NoFile)
                }
                Ok(Err(e)) => {
                    debug!("Error opening version: {}", e);
                    return Err(e);
                }
                Err(&e) => Err(e),
            };
            println!("Version {:?}, plainp {:?}, {:?}",
                vers, self.plain_path, self.settings.fallback_to_plain);
            let file = match (vers, &self.plain_path,
                              self.settings.fallback_to_plain)
            {
                (Ok(x), _, _) => x,
                (Err(_), &Some(ref pp), always)
                | (Err(NoFile), &Some(ref pp), no_file)
                | (Err(BadVersion), &Some(ref pp), no_file)
                | (Err(InvalidPath), &Some(ref pp), no_file)
                | (Err(NoVersion), &Some(ref pp), no_file)
                | (Err(BadVersion), &Some(ref pp), bad_version)
                | (Err(NoVersion), &Some(ref pp), bad_version)
                | (Err(NoVersion), &Some(ref pp), no_version)
                => {
                    File::open(pp)?
                }
                (Err(_), _, _) => {
                    return Err(io::ErrorKind::NotFound.into());
                }
            };
            let meta = file.metadata()?;
            if meta.is_dir() {
                return Err(io::ErrorKind::Other.into());
            } else {
                let mime = guess_mime_type(
                    &self.version_path.as_ref().ok()
                    .unwrap_or(self.plain_path.as_ref().unwrap()));
                self.file = Some((wrap_file(file), meta.len(), mime));
            }
        }
        Ok(self.file.as_ref()
            .map(|&(ref f, s, _)| (f as &FileReader, s)).unwrap())
    }
}

impl IntoFileOpener for PathOpen {
    type Opener = PathOpen;
    fn into_file_opener(self) -> Self::Opener {
        self
    }
}

impl VersionError {
    fn to_header_string(&self) -> &'static str {
        match *self {
            VersionError::NoVersion => "no-version",
            VersionError::BadVersion => "bad-version",
            VersionError::InvalidPath => "invalid-path",
            VersionError::NoFile => "no-file",
        }
    }
}
<commit_msg>Removes debugging print<commit_after>use std::fs::{File};
use std::io;
use std::path::{Path, PathBuf};
use std::sync::{Arc};
use std::str::from_utf8;

use futures::{Future};
use futures::future::{ok};
use mime_guess::guess_mime_type;
use mime::{TopLevel, Mime};
use tk_http::server::Error;
use tk_http::Status;
use tk_sendfile::{FileOpener, IntoFileOpener, FileReader};

use config::static_files::{VersionChars, VersionedStatic};
use default_error_page::{error_page};
use incoming::{Input, Request, Reply, Transport};
use incoming::reply;
use handlers::files::FileError;
use handlers::files::decode::decode_component;
use handlers::files::pools::get_pool;
use handlers::files::normal;

quick_error! {
    #[derive(Debug, Copy, Clone)]
    pub enum VersionError {
        NoVersion
        BadVersion  // length or chars
        InvalidPath
        NoFile
    }
}

#[cfg(unix)]
struct PathOpen {
    version_path: Result<PathBuf, VersionError>,
    plain_path: Option<PathBuf>,
    settings: Arc<VersionedStatic>,
    file: Option<(File, u64, Mime)>,
}

#[cfg(windows)]
struct PathOpen {
    version_path: Option<PathBuf>,
    plain_path: Option<PathBuf>,
    settings: Arc<VersionedStatic>,
    file: Option<(Mutex<File>, u64, Mime)>,
}

#[cfg(unix)]
fn wrap_file(file: File) -> File {
    file
}

#[cfg(windows)]
fn wrap_file(file: File) -> Mutex<File> {
    Mutex::new(file)
}

fn find_param<'x>(query: &'x str, arg: &str) -> Option<&'x str> {
    for pair in query.split('&') {
        if pair.starts_with(arg) && pair.len() > arg.len()
            && pair[arg.len()..].starts_with("=")
        {
            return Some(&pair[arg.len()+1..]);
        }
    }
    return None;
}

fn path(settings: &VersionedStatic, inp: &Input)
    -> Result<PathBuf, VersionError>
{
    let path = inp.headers.path().unwrap_or("/");
    let path = match path.find(|c| c == '#') {
        Some(idx) => &path[..idx],
        None => path
    };
    let query = path.find(|c| c == '?').ok_or(VersionError::NoVersion)?;
    let (path, query) = path.split_at(query);
    let version = find_param(&query[1..], &settings.version_arg)
        .ok_or(VersionError::NoVersion)?;

    if version.len() != settings.version_len {
        return Err(VersionError::BadVersion);
    }
    match settings.version_chars {
        VersionChars::lowercase_hex => {
            for &c in version.as_bytes() {
                if c < b'0' || (c > b'9' && c < b'a') || c > b'z' {
                    return Err(VersionError::BadVersion);
                }
            }
        }
    }

    let file_name = match path.rfind('/') {
        Some(idx) => &path[idx+1..],
        None => path,
    };
    let mut buf = Vec::with_capacity(
        settings.version_len*2 + 1 + file_name.len());
    let mut offset = 0;
    for &chunk in &settings.version_split {
        buf.extend(version[offset..offset+chunk as usize].as_bytes());
        buf.push(b'/');
        offset += chunk as usize;
    }
    buf.pop();
    buf.push(b'-');
    decode_component(&mut buf, file_name)
        .map_err(|_| VersionError::InvalidPath)?;

    // only valid utf-8 supported so far
    let utf8 = from_utf8(&buf).map_err(|_| VersionError::InvalidPath)?;
    Ok(settings.versioned_root.join(utf8))
}

pub fn serve_versioned<S: Transport>(settings: &Arc<VersionedStatic>,
    mut inp: Input)
    -> Request<S>
{
    let path = path(settings, &inp);
    let npath = normal::path(&settings.fallback, &inp).ok();
    inp.debug.set_fs_path( // TODO(tailhook)
        &path.as_ref().ok().map(|x| -> &Path { x.as_ref() })
        .or(npath.as_ref().map(|x| -> &Path { x.as_ref() }))
        .unwrap_or(&Path::new("")));
    let pool = get_pool(&inp.runtime, &settings.pool);
    let settings = settings.clone();
    if path.is_err() && npath.is_none() {
        inp.debug.set_deny(path.unwrap_err().to_header_string());
        return reply(inp, move |e| {
            Box::new(error_page(Status::NotFound, e))
        });
    }
    reply(inp, move |mut e| {
        Box::new(pool.open(PathOpen::new(path, npath, &settings))
            .then(move |res| match res {
                Ok(file) => {
                    e.status(Status::Ok);
                    e.add_length(file.size());
                    if !settings.overrides_content_type {
                        let mime = file.get_inner().get_mime();
                        match (&mime.0, &settings.text_charset) {
                            (&TopLevel::Text, &Some(ref enc)) => {
                                e.format_header("Content-Type", format_args!(
                                    "{}/{}; charset={}", mime.0, mime.1, enc));
                            }
                            _ => {
                                e.format_header("Content-Type", mime);
                            }
                        }
                    }
                    e.add_extra_headers(&settings.extra_headers);
                    if e.done_headers() {
                        Box::new(e.raw_body()
                            .and_then(|raw_body| file.write_into(raw_body))
                            .map(|raw_body| raw_body.done())
                            .map_err(FileError::Sendfile)
                            .map_err(Error::custom))
                        as Reply<_>
                    } else {
                        Box::new(ok(e.done()))
                    }
                }
                Err(ref err) if err.kind() == io::ErrorKind::NotFound => {
                    Box::new(error_page(Status::NotFound, e))
                }
                // One of the known `Other` issues is when path refers to
                // a directory rather than regular file
                Err(ref err) if err.kind() == io::ErrorKind::Other => {
                    Box::new(error_page(Status::Forbidden, e))
                }
                // TODO(tailhook) find out if we want to expose other
                // errors, for example "Permission denied" and "is a directory"
                Err(_) => {
                    Box::new(error_page(Status::InternalServerError, e))
                }
            }))
    })
}

impl PathOpen {
    fn new(vpath: Result<PathBuf, VersionError>, npath: Option<PathBuf>,
        settings: &Arc<VersionedStatic>)
        -> PathOpen
    {
        PathOpen {
            version_path: vpath,
            plain_path: npath,
            settings: settings.clone(),
            file: None,
        }
    }
    fn get_mime(&self) -> &Mime {
        self.file.as_ref()
            .map(|&(_, _, ref m)| m)
            .unwrap()
    }
}

impl FileOpener for PathOpen {
    fn open(&mut self) -> Result<(&FileReader, u64), io::Error> {
        use self::VersionError::*;
        use config::static_files::FallbackMode::*;
        if self.file.is_none() {
            let vers = match self.version_path.as_ref().map(|x| File::open(&x))
            {
                Ok(Ok(file)) => Ok(file),
                Ok(Err(ref e)) if e.kind() == io::ErrorKind::NotFound => {
                    Err(NoFile)
                }
                Ok(Err(e)) => {
                    debug!("Error opening version: {}", e);
                    return Err(e);
                }
                Err(&e) => Err(e),
            };
            let file = match (vers, &self.plain_path,
                              self.settings.fallback_to_plain)
            {
                (Ok(x), _, _) => x,
                (Err(_), &Some(ref pp), always)
                | (Err(NoFile), &Some(ref pp), no_file)
                | (Err(BadVersion), &Some(ref pp), no_file)
                | (Err(InvalidPath), &Some(ref pp), no_file)
                | (Err(NoVersion), &Some(ref pp), no_file)
                | (Err(BadVersion), &Some(ref pp), bad_version)
                | (Err(NoVersion), &Some(ref pp), bad_version)
                | (Err(NoVersion), &Some(ref pp), no_version)
                => {
                    File::open(pp)?
                }
                (Err(_), _, _) => {
                    return Err(io::ErrorKind::NotFound.into());
                }
            };
            let meta = file.metadata()?;
            if meta.is_dir() {
                return Err(io::ErrorKind::Other.into());
            } else {
                let mime = guess_mime_type(
                    &self.version_path.as_ref().ok()
                    .unwrap_or(self.plain_path.as_ref().unwrap()));
                self.file = Some((wrap_file(file), meta.len(), mime));
            }
        }
        Ok(self.file.as_ref()
            .map(|&(ref f, s, _)| (f as &FileReader, s)).unwrap())
    }
}

impl IntoFileOpener for PathOpen {
    type Opener = PathOpen;
    fn into_file_opener(self) -> Self::Opener {
        self
    }
}

impl VersionError {
    fn to_header_string(&self) -> &'static str {
        match *self {
            VersionError::NoVersion => "no-version",
            VersionError::BadVersion => "bad-version",
            VersionError::InvalidPath => "invalid-path",
            VersionError::NoFile => "no-file",
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A centralized set of stylesheets for a document.

use dom::TElement;
use invalidation::stylesheets::StylesheetInvalidationSet;
use media_queries::Device;
use shared_lock::SharedRwLockReadGuard;
use std::slice;
use stylesheets::{Origin, OriginSet, StylesheetInDocument};

/// Entry for a StylesheetSet. We don't bother creating a constructor, because
/// there's no sensible defaults for the member variables.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct StylesheetSetEntry<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    sheet: S,
}

/// A iterator over the stylesheets of a list of entries in the StylesheetSet.
#[derive(Clone)]
pub struct StylesheetIterator<'a, S>(slice::Iter<'a, StylesheetSetEntry<S>>)
where
    S: StylesheetInDocument + PartialEq + 'static;

impl<'a, S> Iterator for StylesheetIterator<'a, S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    type Item = &'a S;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|entry| &entry.sheet)
    }
}

/// The set of stylesheets effective for a given document.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct StylesheetSet<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// The actual list of all the stylesheets that apply to the given document,
    /// each stylesheet associated with a unique ID.
    ///
    /// This is only a list of top-level stylesheets, and as such it doesn't
    /// include recursive `@import` rules.
    entries: Vec<StylesheetSetEntry<S>>,

    /// The invalidations for stylesheets added or removed from this document.
    invalidations: StylesheetInvalidationSet,

    /// The origins whose stylesheets have changed so far.
    origins_dirty: OriginSet,

    /// Has author style been disabled?
    author_style_disabled: bool,
}

impl<S> StylesheetSet<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// Create a new empty StylesheetSet.
    pub fn new() -> Self {
        StylesheetSet {
            entries: vec![],
            invalidations: StylesheetInvalidationSet::new(),
            origins_dirty: OriginSet::empty(),
            author_style_disabled: false,
        }
    }

    /// Returns the number of stylesheets in the set.
    pub fn len(&self) -> usize {
        self.entries.len()
    }

    /// Returns the number of stylesheets in the set.
    pub fn get(&self, index: usize) -> Option<&S> {
        self.entries.get(index).map(|s| &s.sheet)
    }

    /// Returns whether author styles have been disabled for the current
    /// stylesheet set.
    pub fn author_style_disabled(&self) -> bool {
        self.author_style_disabled
    }

    fn remove_stylesheet_if_present(&mut self, sheet: &S) {
        self.entries.retain(|entry| entry.sheet != *sheet);
    }

    fn collect_invalidations_for(
        &mut self,
        device: Option<&Device>,
        sheet: &S,
        guard: &SharedRwLockReadGuard,
    ) {
        if let Some(device) = device {
            self.invalidations.collect_invalidations_for(device, sheet, guard);
        }
        self.origins_dirty |= sheet.contents(guard).origin;
    }

    /// Appends a new stylesheet to the current set.
    ///
    /// No device implies not computing invalidations.
    pub fn append_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard
    ) {
        debug!("StylesheetSet::append_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);
        self.entries.push(StylesheetSetEntry { sheet });
    }

    /// Prepend a new stylesheet to the current set.
    pub fn prepend_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard
    ) {
        debug!("StylesheetSet::prepend_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);
        self.entries.insert(0, StylesheetSetEntry { sheet });
    }

    /// Insert a given stylesheet before another stylesheet in the document.
    pub fn insert_stylesheet_before(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        before_sheet: S,
        guard: &SharedRwLockReadGuard,
    ) {
        debug!("StylesheetSet::insert_stylesheet_before");
        self.remove_stylesheet_if_present(&sheet);
        let index = self.entries.iter().position(|entry| {
            entry.sheet == before_sheet
        }).expect("`before_sheet` stylesheet not found");
        self.collect_invalidations_for(device, &sheet, guard);
        self.entries.insert(index, StylesheetSetEntry { sheet });
    }

    /// Remove a given stylesheet from the set.
    pub fn remove_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard,
    ) {
        debug!("StylesheetSet::remove_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);
    }

    /// Notes that the author style has been disabled for this document.
    pub fn set_author_style_disabled(&mut self, disabled: bool) {
        debug!("StylesheetSet::set_author_style_disabled");
        if self.author_style_disabled == disabled {
            return;
        }
        self.author_style_disabled = disabled;
        self.invalidations.invalidate_fully();
        self.origins_dirty |= Origin::Author;
    }

    /// Returns whether the given set has changed from the last flush.
    pub fn has_changed(&self) -> bool {
        !self.origins_dirty.is_empty()
    }

    /// Flush the current set, unmarking it as dirty, and returns the damaged
    /// origins, and whether any elements were invalidated.
    pub fn flush<E>(
        &mut self,
        document_element: Option<E>,
    ) -> (OriginSet, bool)
    where
        E: TElement,
    {
        use std::mem;

        debug!("StylesheetSet::flush");

        let have_invalidations = self.invalidations.flush(document_element);
        let origins = mem::replace(&mut self.origins_dirty, OriginSet::empty());

        (origins, have_invalidations)
    }

    /// Flush stylesheets, but without running any of the invalidation passes.
    #[cfg(feature = "servo")]
    pub fn flush_without_invalidation(&mut self) -> OriginSet {
        use std::mem;

        debug!("StylesheetSet::flush_without_invalidation");

        self.invalidations.clear();
        mem::replace(&mut self.origins_dirty, OriginSet::empty())
    }

    /// Returns an iterator over the current list of stylesheets.
    pub fn iter(&self) -> StylesheetIterator<S> {
        StylesheetIterator(self.entries.iter())
    }

    /// Mark the stylesheets for the specified origin as dirty, because
    /// something external may have invalidated it.
    pub fn force_dirty(&mut self, origins: OriginSet) {
        self.invalidations.invalidate_fully();
        self.origins_dirty |= origins;
    }
}
<commit_msg>style: Add a no-op constructor of StyleSheetEntry, in preparation for more changes.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A centralized set of stylesheets for a document.

use dom::TElement;
use invalidation::stylesheets::StylesheetInvalidationSet;
use media_queries::Device;
use shared_lock::SharedRwLockReadGuard;
use std::slice;
use stylesheets::{Origin, OriginSet, StylesheetInDocument};

/// Entry for a StylesheetSet. We don't bother creating a constructor, because
/// there's no sensible defaults for the member variables.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
struct StylesheetSetEntry<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    sheet: S,
}

impl<S> StylesheetSetEntry<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    fn new(sheet: S) -> Self {
        Self { sheet }
    }
}

/// A iterator over the stylesheets of a list of entries in the StylesheetSet.
#[derive(Clone)]
pub struct StylesheetIterator<'a, S>(slice::Iter<'a, StylesheetSetEntry<S>>)
where
    S: StylesheetInDocument + PartialEq + 'static;

impl<'a, S> Iterator for StylesheetIterator<'a, S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    type Item = &'a S;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|entry| &entry.sheet)
    }
}

/// The set of stylesheets effective for a given document.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct StylesheetSet<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// The actual list of all the stylesheets that apply to the given document,
    /// each stylesheet associated with a unique ID.
    ///
    /// This is only a list of top-level stylesheets, and as such it doesn't
    /// include recursive `@import` rules.
    entries: Vec<StylesheetSetEntry<S>>,

    /// The invalidations for stylesheets added or removed from this document.
    invalidations: StylesheetInvalidationSet,

    /// The origins whose stylesheets have changed so far.
    origins_dirty: OriginSet,

    /// Has author style been disabled?
    author_style_disabled: bool,
}

impl<S> StylesheetSet<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// Create a new empty StylesheetSet.
    pub fn new() -> Self {
        StylesheetSet {
            entries: vec![],
            invalidations: StylesheetInvalidationSet::new(),
            origins_dirty: OriginSet::empty(),
            author_style_disabled: false,
        }
    }

    /// Returns the number of stylesheets in the set.
    pub fn len(&self) -> usize {
        self.entries.len()
    }

    /// Returns the number of stylesheets in the set.
    pub fn get(&self, index: usize) -> Option<&S> {
        self.entries.get(index).map(|s| &s.sheet)
    }

    /// Returns whether author styles have been disabled for the current
    /// stylesheet set.
    pub fn author_style_disabled(&self) -> bool {
        self.author_style_disabled
    }

    fn remove_stylesheet_if_present(&mut self, sheet: &S) {
        self.entries.retain(|entry| entry.sheet != *sheet);
    }

    fn collect_invalidations_for(
        &mut self,
        device: Option<&Device>,
        sheet: &S,
        guard: &SharedRwLockReadGuard,
    ) {
        if let Some(device) = device {
            self.invalidations.collect_invalidations_for(device, sheet, guard);
        }
        self.origins_dirty |= sheet.contents(guard).origin;
    }

    /// Appends a new stylesheet to the current set.
    ///
    /// No device implies not computing invalidations.
    pub fn append_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard
    ) {
        debug!("StylesheetSet::append_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);
        self.entries.push(StylesheetSetEntry::new(sheet));
    }

    /// Prepend a new stylesheet to the current set.
    pub fn prepend_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard
    ) {
        debug!("StylesheetSet::prepend_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);
        self.entries.insert(0, StylesheetSetEntry::new(sheet));
    }

    /// Insert a given stylesheet before another stylesheet in the document.
    pub fn insert_stylesheet_before(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        before_sheet: S,
        guard: &SharedRwLockReadGuard,
    ) {
        debug!("StylesheetSet::insert_stylesheet_before");
        self.remove_stylesheet_if_present(&sheet);
        let index = self.entries.iter().position(|entry| {
            entry.sheet == before_sheet
        }).expect("`before_sheet` stylesheet not found");
        self.collect_invalidations_for(device, &sheet, guard);
        self.entries.insert(index, StylesheetSetEntry::new(sheet));
    }

    /// Remove a given stylesheet from the set.
    pub fn remove_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard,
    ) {
        debug!("StylesheetSet::remove_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);
    }

    /// Notes that the author style has been disabled for this document.
    pub fn set_author_style_disabled(&mut self, disabled: bool) {
        debug!("StylesheetSet::set_author_style_disabled");
        if self.author_style_disabled == disabled {
            return;
        }
        self.author_style_disabled = disabled;
        self.invalidations.invalidate_fully();
        self.origins_dirty |= Origin::Author;
    }

    /// Returns whether the given set has changed from the last flush.
    pub fn has_changed(&self) -> bool {
        !self.origins_dirty.is_empty()
    }

    /// Flush the current set, unmarking it as dirty, and returns the damaged
    /// origins, and whether any elements were invalidated.
    pub fn flush<E>(
        &mut self,
        document_element: Option<E>,
    ) -> (OriginSet, bool)
    where
        E: TElement,
    {
        use std::mem;

        debug!("StylesheetSet::flush");

        let have_invalidations = self.invalidations.flush(document_element);
        let origins = mem::replace(&mut self.origins_dirty, OriginSet::empty());

        (origins, have_invalidations)
    }

    /// Flush stylesheets, but without running any of the invalidation passes.
    #[cfg(feature = "servo")]
    pub fn flush_without_invalidation(&mut self) -> OriginSet {
        use std::mem;

        debug!("StylesheetSet::flush_without_invalidation");

        self.invalidations.clear();
        mem::replace(&mut self.origins_dirty, OriginSet::empty())
    }

    /// Returns an iterator over the current list of stylesheets.
    pub fn iter(&self) -> StylesheetIterator<S> {
        StylesheetIterator(self.entries.iter())
    }

    /// Mark the stylesheets for the specified origin as dirty, because
    /// something external may have invalidated it.
    pub fn force_dirty(&mut self, origins: OriginSet) {
        self.invalidations.invalidate_fully();
        self.origins_dirty |= origins;
    }
}
<|endoftext|>


<commit_before>use std::iter;

// FIXME: only supports extended-ASCII
/// searches for the pattern in the input text using the
/// KMP algorithm.
pub struct KMP<'a> {
    r: usize,
    dfa: Vec<Vec<usize>>,
    pat: &'a str
}

impl<'a> KMP<'a> {
    // create the DFA from a string pattern
    pub fn new<'b>(pat: &'b str) -> KMP<'b> {
        let r = 256;
        let mut ret = KMP {
            r: r,
            dfa: Vec::new(),
            pat: pat
        };
        ret.build_dfa();
        ret
    }

    fn build_dfa(&mut self) {
        let m = self.pat.len();
        let r = self.r;
        let mut dfa = iter::repeat(iter::repeat(0).take(m).collect::<Vec<usize>>())
            .take(r).collect::<Vec<Vec<usize>>>();
        dfa[self.pat.char_at(0) as usize][0] = 1;
        let mut x = 0;
        for j in 1 .. m {
            for c in 0 .. r {
                dfa[c][j] = dfa[c][x]; // copy mismatch cases
            }
            dfa[self.pat.char_at(j) as usize][j] = j+1; // set match case
            x = dfa[self.pat.char_at(j) as usize][x];   // update restart state
        }
        self.dfa = dfa;
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let m = self.pat.len();
        let n = txt.len();
        let mut i = 0;
        let mut j = 0;
        while i < n && j < m {
            j = self.dfa[txt.char_at(i) as usize][j];
            i += 1;
        }
        if j == m {
            Some(i-m)
        } else {
            None
        }
    }
}

#[test]
fn test_kmp() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let kmp = KMP::new(pat);
    assert!(kmp.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(kmp.search("zzzzz"), None);
}

/// searches for the pattern in the input text using the
/// bad-character rule part of the Boyer-Moore algorithm.
pub struct BoyerMoore<'a> {
    r: usize,
    right: Vec<isize>,
    pat: &'a str
}

impl<'a> BoyerMoore<'a> {
     pub fn new<'b>(pat: &'b str) -> BoyerMoore<'b> {
         let r = 256;
         let mut ret = BoyerMoore {
             r: r,
             right: Vec::new(),
             pat: pat
         };
         ret.init();
         ret
     }

    fn init(&mut self) {
        let r = self.r;
        self.right = iter::repeat(-1).take(r).collect();
        for j in 0 .. self.pat.len() {
            self.right[self.pat.char_at(j) as usize] = j as isize;
        }
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let m = self.pat.len();
        let n = txt.len();
        if n < m {
            return None;
        }
        let mut skip;
        let mut i = 0;
        while i <= n-m {
            skip = 0;
            for j in (0 .. m).rev() {
                if self.pat.char_at(j) != txt.char_at(i+j) {
                    skip = j as isize - self.right[txt.char_at(i+j) as usize];
                    if skip < 1 {
                        skip = 1;
                    }
                    break;
                }
            }
            if skip == 0 {
                return Some(i);
            }
            i += skip as usize;
        }
        return None;
    }
}

#[test]
fn test_boyer_moore() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let bm = BoyerMoore::new(pat);
    assert!(bm.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(bm.search("zzzzz"), None);
}

pub struct RabinKarp<'a> {
    pat: &'a str,
    pat_hash: usize,
    m: usize,
    r: usize,
    q: usize,
    rm: usize,                    // R^(M-1) % Q
}

impl<'a> RabinKarp<'a> {
    pub fn new<'b>(pat: &'b str) -> RabinKarp<'b> {
        let mut ret = RabinKarp {
            pat: pat,
            pat_hash: 0,
            m: pat.len(),
            r: 256,
            q: RabinKarp::long_random_prime(),
            rm: 1
        };
        ret.init();
        ret
    }

    fn init(&mut self) {
        let r = self.r;
        let q = self.q;
        for _ in 1 .. self.m {
            self.rm = (r * self.rm) % q;
        }
        self.pat_hash = self.hash(self.pat, self.m);
    }

    fn hash(&self, key: &str, m: usize) -> usize {
        let r = self.r;
        let q = self.q;
        let mut h = 0;
        for j in 0 .. m {
            h = (r * h + key.char_at(j) as usize) % q
        }
        h
    }

    fn check(&self, txt: &str, i: usize) -> bool {
        for j in 0 .. self.m {
            if self.pat.char_at(j) != txt.char_at(i+j) {
                return false;
            }
        }
        true
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let n = txt.len();
        if n < self.m {
            return None;
        }

        let mut txt_hash = self.hash(txt, self.m);

        // check for match at offset 0
        if self.pat_hash == txt_hash && self.check(txt, 0) {
            return Some(0);
        }

        // check for hash match
        for i in self.m .. n {
            txt_hash = (txt_hash + self.q - self.rm * txt.char_at(i-self.m) as usize % self.q) % self.q;
            txt_hash = (txt_hash * self.r + txt.char_at(i) as usize) % self.q;

            let offset = i - self.m + 1;
            if self.pat_hash == txt_hash && self.check(txt, offset) {
                return Some(offset);
            }
        }
        None
    }

    fn long_random_prime() -> usize {
        // TODO: max bits 31, use random prime generator
        5800079
    }
}

#[test]
fn test_rabin_karp() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let bm = RabinKarp::new(pat);
    assert!(bm.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(bm.search("zzzzz"), None);
}
<commit_msg>substring_search: implement search_monte_carlo() for RabinKarp<commit_after>use std::iter;

// FIXME: only supports extended-ASCII
/// searches for the pattern in the input text using the
/// KMP algorithm.
pub struct KMP<'a> {
    r: usize,
    dfa: Vec<Vec<usize>>,
    pat: &'a str
}

impl<'a> KMP<'a> {
    // create the DFA from a string pattern
    pub fn new<'b>(pat: &'b str) -> KMP<'b> {
        let r = 256;
        let mut ret = KMP {
            r: r,
            dfa: Vec::new(),
            pat: pat
        };
        ret.build_dfa();
        ret
    }

    fn build_dfa(&mut self) {
        let m = self.pat.len();
        let r = self.r;
        let mut dfa = iter::repeat(iter::repeat(0).take(m).collect::<Vec<usize>>())
            .take(r).collect::<Vec<Vec<usize>>>();
        dfa[self.pat.char_at(0) as usize][0] = 1;
        let mut x = 0;
        for j in 1 .. m {
            for c in 0 .. r {
                dfa[c][j] = dfa[c][x]; // copy mismatch cases
            }
            dfa[self.pat.char_at(j) as usize][j] = j+1; // set match case
            x = dfa[self.pat.char_at(j) as usize][x];   // update restart state
        }
        self.dfa = dfa;
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let m = self.pat.len();
        let n = txt.len();
        let mut i = 0;
        let mut j = 0;
        while i < n && j < m {
            j = self.dfa[txt.char_at(i) as usize][j];
            i += 1;
        }
        if j == m {
            Some(i-m)
        } else {
            None
        }
    }
}

#[test]
fn test_kmp() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let kmp = KMP::new(pat);
    assert!(kmp.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(kmp.search("zzzzz"), None);
}

/// searches for the pattern in the input text using the
/// bad-character rule part of the Boyer-Moore algorithm.
pub struct BoyerMoore<'a> {
    r: usize,
    right: Vec<isize>,
    pat: &'a str
}

impl<'a> BoyerMoore<'a> {
     pub fn new<'b>(pat: &'b str) -> BoyerMoore<'b> {
         let r = 256;
         let mut ret = BoyerMoore {
             r: r,
             right: Vec::new(),
             pat: pat
         };
         ret.init();
         ret
     }

    fn init(&mut self) {
        let r = self.r;
        self.right = iter::repeat(-1).take(r).collect();
        for j in 0 .. self.pat.len() {
            self.right[self.pat.char_at(j) as usize] = j as isize;
        }
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let m = self.pat.len();
        let n = txt.len();
        if n < m {
            return None;
        }
        let mut skip;
        let mut i = 0;
        while i <= n-m {
            skip = 0;
            for j in (0 .. m).rev() {
                if self.pat.char_at(j) != txt.char_at(i+j) {
                    skip = j as isize - self.right[txt.char_at(i+j) as usize];
                    if skip < 1 {
                        skip = 1;
                    }
                    break;
                }
            }
            if skip == 0 {
                return Some(i);
            }
            i += skip as usize;
        }
        return None;
    }
}

#[test]
fn test_boyer_moore() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let bm = BoyerMoore::new(pat);
    assert!(bm.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(bm.search("zzzzz"), None);
}

pub struct RabinKarp<'a> {
    pat: &'a str,
    pat_hash: usize,
    m: usize,
    r: usize,
    q: usize,
    rm: usize,                    // R^(M-1) % Q
}

impl<'a> RabinKarp<'a> {
    pub fn new<'b>(pat: &'b str) -> RabinKarp<'b> {
        let mut ret = RabinKarp {
            pat: pat,
            pat_hash: 0,
            m: pat.len(),
            r: 256,
            q: RabinKarp::long_random_prime(),
            rm: 1
        };
        ret.init();
        ret
    }

    fn init(&mut self) {
        let r = self.r;
        let q = self.q;
        for _ in 1 .. self.m {
            self.rm = (r * self.rm) % q;
        }
        self.pat_hash = self.hash(self.pat, self.m);
    }

    fn hash(&self, key: &str, m: usize) -> usize {
        let r = self.r;
        let q = self.q;
        let mut h = 0;
        for j in 0 .. m {
            h = (r * h + key.char_at(j) as usize) % q
        }
        h
    }

    fn check(&self, txt: &str, i: usize) -> bool {
        for j in 0 .. self.m {
            if self.pat.char_at(j) != txt.char_at(i+j) {
                return false;
            }
        }
        true
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let n = txt.len();
        if n < self.m {
            return None;
        }

        let mut txt_hash = self.hash(txt, self.m);

        // check for match at offset 0
        if self.pat_hash == txt_hash && self.check(txt, 0) {
            return Some(0);
        }

        // check for hash match
        for i in self.m .. n {
            txt_hash = (txt_hash + self.q - self.rm * txt.char_at(i-self.m) as usize % self.q) % self.q;
            txt_hash = (txt_hash * self.r + txt.char_at(i) as usize) % self.q;

            let offset = i - self.m + 1;
            if self.pat_hash == txt_hash && self.check(txt, offset) {
                return Some(offset);
            }
        }
        None
    }

    pub fn search_monte_carlo(&self, txt: &str) -> Option<usize> {
        if txt.len() < self.m {
            return None;
        }
        let mut txt_hash = self.hash(txt, self.m);
        if self.pat_hash == txt_hash && self.check(txt, 0) {
            return Some(0);
        }
        for i in self.m .. txt.len() {
            txt_hash = (txt_hash + self.q - self.rm * txt.char_at(i-self.m) as usize % self.q) % self.q;
            txt_hash = (txt_hash * self.r + txt.char_at(i) as usize) % self.q;

            let offset = i - self.m + 1;
            if self.pat_hash == txt_hash { // diffs here
                return Some(offset);
            }
        }
        None
    }

    fn long_random_prime() -> usize {
        // TODO: max bits 31, use random prime generator
        5800079
    }
}

#[test]
fn test_rabin_karp() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let bm = RabinKarp::new(pat);
    assert!(bm.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert!(bm.search_monte_carlo(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(bm.search("zzzzz"), None);
}
<|endoftext|>


<commit_before>#![cfg_attr(rustfmt, rustfmt_skip)] // https://github.com/rust-lang-nursery/rustfmt/issues/2755

#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_operator_body {
    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = ReturnBasedOnArgs,
        ty_params = ($($ty_param:ident,)+),
        field_names = $field_names:tt,
        backend_ty_params = $backend_ty_params:tt,
        backend_ty = $backend_ty:ty,
    ) => {
        __diesel_operator_body! {
            notation = $notation,
            struct_name = $name,
            operator = $operator,
            return_ty = ST,
            ty_params = ($($ty_param,)+),
            field_names = $field_names,
            backend_ty_params = $backend_ty_params,
            backend_ty = $backend_ty,
            expression_ty_params = (ST,),
            expression_bounds = ($($ty_param: $crate::expression::Expression<SqlType = ST>,)+),
        }
    };

    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = $return_ty:ty,
        ty_params = ($($ty_param:ident,)+),
        field_names = $field_names:tt,
        backend_ty_params = $backend_ty_params:tt,
        backend_ty = $backend_ty:ty,
    ) => {
        __diesel_operator_body! {
            notation = $notation,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = ($($ty_param,)+),
            field_names = $field_names,
            backend_ty_params = $backend_ty_params,
            backend_ty = $backend_ty,
            expression_ty_params = (),
            expression_bounds = ($($ty_param: $crate::expression::Expression,)+),
        }
    };

    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = $return_ty:ty,
        ty_params = ($($ty_param:ident,)+),
        field_names = ($($field_name:ident,)+),
        backend_ty_params = ($($backend_ty_param:ident,)*),
        backend_ty = $backend_ty:ty,
        expression_ty_params = ($($expression_ty_params:ident,)*),
        expression_bounds = ($($expression_bounds:tt)*),
    ) => {
        #[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, NonAggregate)]
        #[doc(hidden)]
        pub struct $name<$($ty_param,)+> {
            $(pub(crate) $field_name: $ty_param,)+
        }

        impl<$($ty_param,)+> $name<$($ty_param,)+> {
            pub fn new($($field_name: $ty_param,)+) -> Self {
                $name { $($field_name,)+ }
            }
        }

        impl_selectable_expression!($name<$($ty_param),+>);

        impl<$($ty_param,)+ $($expression_ty_params,)*> $crate::expression::Expression for $name<$($ty_param,)+> where
            $($expression_bounds)*
        {
            type SqlType = $return_ty;
        }

        impl<$($ty_param,)+ $($backend_ty_param,)*> $crate::query_builder::QueryFragment<$backend_ty>
            for $name<$($ty_param,)+> where
                $($ty_param: $crate::query_builder::QueryFragment<$backend_ty>,)+
                $($backend_ty_param: $crate::backend::Backend,)*
        {
            fn walk_ast(&self, mut out: $crate::query_builder::AstPass<$backend_ty>) -> $crate::result::QueryResult<()> {
                __diesel_operator_to_sql!(
                    notation = $notation,
                    operator_expr = out.push_sql($operator),
                    field_exprs = ($(self.$field_name.walk_ast(out.reborrow())?),+),
                );
                Ok(())
            }
        }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_operator_to_sql {
    (
        notation = infix,
        operator_expr = $op:expr,
        field_exprs = ($left:expr, $right:expr),
    ) => {
        $left;
        $op;
        $right;
    };

    (
        notation = postfix,
        operator_expr = $op:expr,
        field_exprs = ($expr:expr),
    ) => {
        $expr;
        $op;
    };

    (
        notation = prefix,
        operator_expr = $op:expr,
        field_exprs = ($expr:expr),
    ) => {
        $op;
        $expr;
    };
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// This will create a new type with the given name. It will implement all
/// methods needed to be used as an expression in Diesel, placing the given
/// SQL between the two elements. The third argument specifies the SQL type
/// that the operator returns. If it is not given, the type will be assumed
/// to be `Bool`.
///
/// If the operator is specific to a single backend, you can specify this by
/// adding `backend: Pg` or similar as the last argument.
///
/// It should be noted that the generated impls will not constrain the SQL
/// types of the arguments. You should ensure that they are of the right
/// type in your function which constructs the operator.
///
/// Typically you would not expose the type that this generates directly. You'd
/// expose a function (or trait) used to construct the expression, and a helper
/// type which represents the return type of that function. See the source of
/// `diesel::expression::expression_methods` and
/// `diesel::expression::helper_types` for real world examples of this.
///
/// # Examples
///
/// # Possible invocations
///
/// ```ignore
/// // The SQL type will be boolean. The backend will not be constrained
/// infix_operator!(Matches, " @@ ");
///
/// // Queries which try to execute `Contains` on a backend other than Pg
/// // will fail to compile
/// infix_operator!(Contains, " @> ", backend: Pg);
///
/// // The type of `Concat` will be `TsVector` rather than Bool
/// infix_operator!(Concat, " || ", TsVector);
///
/// // It is perfectly fine to have multiple operators with the same SQL.
/// // Diesel will ensure that the queries are always unambiguous in which
/// // operator applies
/// infix_operator!(Or, " || ", TsQuery);
///
/// // Specifying both the return types and the backend
/// infix_operator!(And, " && ", TsQuery, backend: Pg);
/// ```
///
/// ## Example usage
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// #
/// # fn main() {
/// #     use schema::users::dsl::*;
/// #     let connection = establish_connection();
/// infix_operator!(MyEq, " = ");
///
/// use diesel::expression::AsExpression;
///
/// // Normally you would put this on a trait instead
/// fn my_eq<T, U>(left: T, right: U) -> MyEq<T, U::Expression> where
///     T: Expression,
///     U: AsExpression<T::SqlType>,
/// {
///     MyEq::new(left, right.as_expression())
/// }
///
/// let users_with_name = users.select(id).filter(my_eq(name, "Sean"));
///
/// assert_eq!(Ok(1), users_with_name.first(&connection));
/// # }
/// ```
#[macro_export]
macro_rules! infix_operator {
    ($name:ident, $operator:expr) => {
        infix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        infix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $($return_ty:tt)::*) => {
        __diesel_operator_body!(
            notation = infix,
            struct_name = $name,
            operator = $operator,
            return_ty = $($return_ty)::*,
            ty_params = (T, U,),
            field_names = (left, right,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = infix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (T, U,),
            field_names = (left, right,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::infix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
macro_rules! diesel_infix_operator {
    ($($args:tt)*) => {
        infix_operator!($($args)*);
    }
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// Similar to [`infix_operator!`], but the generated type will only take
/// a single argument rather than two. The operator SQL will be placed after
/// the single argument. See [`infix_operator!`] for example usage.
///
/// [`infix_operator!`]: macro.infix_operator.html
#[macro_export]
macro_rules! postfix_operator {
    ($name:ident, $operator:expr) => {
        postfix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        postfix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $return_ty:ty) => {
        __diesel_operator_body!(
            notation = postfix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = postfix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::postfix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
macro_rules! diesel_postfix_operator {
    ($($args:tt)*) => {
        postfix_operator!($($args)*);
    }
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// Similar to [`infix_operator!`], but the generated type will only take
/// a single argument rather than two. The operator SQL will be placed before
/// the single argument. See [`infix_operator!`] for example usage.
///
/// [`infix_operator!`]: macro.infix_operator.html
#[macro_export]
macro_rules! prefix_operator {
    ($name:ident, $operator:expr) => {
        prefix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        prefix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $return_ty:ty) => {
        __diesel_operator_body!(
            notation = prefix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = prefix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::prefix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
macro_rules! diesel_prefix_operator {
    ($($args:tt)*) => {
        prefix_operator!($($args)*);
    }
}

infix_operator!(Concat, " || ", ReturnBasedOnArgs);
infix_operator!(And, " AND ");
infix_operator!(Between, " BETWEEN ");
infix_operator!(Escape, " ESCAPE ");
infix_operator!(Eq, " = ");
infix_operator!(Gt, " > ");
infix_operator!(GtEq, " >= ");
infix_operator!(Like, " LIKE ");
infix_operator!(Lt, " < ");
infix_operator!(LtEq, " <= ");
infix_operator!(NotBetween, " NOT BETWEEN ");
infix_operator!(NotEq, " != ");
infix_operator!(NotLike, " NOT LIKE ");
infix_operator!(Or, " OR ");

postfix_operator!(IsNull, " IS NULL");
postfix_operator!(IsNotNull, " IS NOT NULL");
postfix_operator!(Asc, " ASC", ());
postfix_operator!(Desc, " DESC", ());

prefix_operator!(Not, "NOT ");

use insertable::{ColumnInsertValue, Insertable};
use query_builder::ValuesClause;
use query_source::Column;

impl<T, U> Insertable<T::Table> for Eq<T, U>
where
    T: Column,
{
    type Values = ValuesClause<ColumnInsertValue<T, U>, T::Table>;

    fn values(self) -> Self::Values {
        ValuesClause::new(ColumnInsertValue::Expression(self.left, self.right))
    }
}

impl<'a, T, Tab, U> Insertable<Tab> for &'a Eq<T, U>
where
    T: Copy,
    Eq<T, &'a U>: Insertable<Tab>,
{
    type Values = <Eq<T, &'a U> as Insertable<Tab>>::Values;

    fn values(self) -> Self::Values {
        Eq::new(self.left, &self.right).values()
    }
}
<commit_msg>Update diesel/src/expression/operators.rs<commit_after>#![cfg_attr(rustfmt, rustfmt_skip)] // https://github.com/rust-lang-nursery/rustfmt/issues/2755

#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_operator_body {
    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = ReturnBasedOnArgs,
        ty_params = ($($ty_param:ident,)+),
        field_names = $field_names:tt,
        backend_ty_params = $backend_ty_params:tt,
        backend_ty = $backend_ty:ty,
    ) => {
        __diesel_operator_body! {
            notation = $notation,
            struct_name = $name,
            operator = $operator,
            return_ty = ST,
            ty_params = ($($ty_param,)+),
            field_names = $field_names,
            backend_ty_params = $backend_ty_params,
            backend_ty = $backend_ty,
            expression_ty_params = (ST,),
            expression_bounds = ($($ty_param: $crate::expression::Expression<SqlType = ST>,)+),
        }
    };

    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = $return_ty:ty,
        ty_params = ($($ty_param:ident,)+),
        field_names = $field_names:tt,
        backend_ty_params = $backend_ty_params:tt,
        backend_ty = $backend_ty:ty,
    ) => {
        __diesel_operator_body! {
            notation = $notation,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = ($($ty_param,)+),
            field_names = $field_names,
            backend_ty_params = $backend_ty_params,
            backend_ty = $backend_ty,
            expression_ty_params = (),
            expression_bounds = ($($ty_param: $crate::expression::Expression,)+),
        }
    };

    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = $return_ty:ty,
        ty_params = ($($ty_param:ident,)+),
        field_names = ($($field_name:ident,)+),
        backend_ty_params = ($($backend_ty_param:ident,)*),
        backend_ty = $backend_ty:ty,
        expression_ty_params = ($($expression_ty_params:ident,)*),
        expression_bounds = ($($expression_bounds:tt)*),
    ) => {
        #[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, NonAggregate)]
        #[doc(hidden)]
        pub struct $name<$($ty_param,)+> {
            $(pub(crate) $field_name: $ty_param,)+
        }

        impl<$($ty_param,)+> $name<$($ty_param,)+> {
            pub fn new($($field_name: $ty_param,)+) -> Self {
                $name { $($field_name,)+ }
            }
        }

        impl_selectable_expression!($name<$($ty_param),+>);

        impl<$($ty_param,)+ $($expression_ty_params,)*> $crate::expression::Expression for $name<$($ty_param,)+> where
            $($expression_bounds)*
        {
            type SqlType = $return_ty;
        }

        impl<$($ty_param,)+ $($backend_ty_param,)*> $crate::query_builder::QueryFragment<$backend_ty>
            for $name<$($ty_param,)+> where
                $($ty_param: $crate::query_builder::QueryFragment<$backend_ty>,)+
                $($backend_ty_param: $crate::backend::Backend,)*
        {
            fn walk_ast(&self, mut out: $crate::query_builder::AstPass<$backend_ty>) -> $crate::result::QueryResult<()> {
                __diesel_operator_to_sql!(
                    notation = $notation,
                    operator_expr = out.push_sql($operator),
                    field_exprs = ($(self.$field_name.walk_ast(out.reborrow())?),+),
                );
                Ok(())
            }
        }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_operator_to_sql {
    (
        notation = infix,
        operator_expr = $op:expr,
        field_exprs = ($left:expr, $right:expr),
    ) => {
        $left;
        $op;
        $right;
    };

    (
        notation = postfix,
        operator_expr = $op:expr,
        field_exprs = ($expr:expr),
    ) => {
        $expr;
        $op;
    };

    (
        notation = prefix,
        operator_expr = $op:expr,
        field_exprs = ($expr:expr),
    ) => {
        $op;
        $expr;
    };
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// This will create a new type with the given name. It will implement all
/// methods needed to be used as an expression in Diesel, placing the given
/// SQL between the two elements. The third argument specifies the SQL type
/// that the operator returns. If it is not given, the type will be assumed
/// to be `Bool`.
///
/// If the operator is specific to a single backend, you can specify this by
/// adding `backend: Pg` or similar as the last argument.
///
/// It should be noted that the generated impls will not constrain the SQL
/// types of the arguments. You should ensure that they are of the right
/// type in your function which constructs the operator.
///
/// Typically you would not expose the type that this generates directly. You'd
/// expose a function (or trait) used to construct the expression, and a helper
/// type which represents the return type of that function. See the source of
/// `diesel::expression::expression_methods` and
/// `diesel::expression::helper_types` for real world examples of this.
///
/// # Examples
///
/// # Possible invocations
///
/// ```ignore
/// // The SQL type will be boolean. The backend will not be constrained
/// infix_operator!(Matches, " @@ ");
///
/// // Queries which try to execute `Contains` on a backend other than Pg
/// // will fail to compile
/// infix_operator!(Contains, " @> ", backend: Pg);
///
/// // The type of `Concat` will be `TsVector` rather than Bool
/// infix_operator!(Concat, " || ", TsVector);
///
/// // It is perfectly fine to have multiple operators with the same SQL.
/// // Diesel will ensure that the queries are always unambiguous in which
/// // operator applies
/// infix_operator!(Or, " || ", TsQuery);
///
/// // Specifying both the return types and the backend
/// infix_operator!(And, " && ", TsQuery, backend: Pg);
/// ```
///
/// ## Example usage
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// #
/// # fn main() {
/// #     use schema::users::dsl::*;
/// #     let connection = establish_connection();
/// infix_operator!(MyEq, " = ");
///
/// use diesel::expression::AsExpression;
///
/// // Normally you would put this on a trait instead
/// fn my_eq<T, U>(left: T, right: U) -> MyEq<T, U::Expression> where
///     T: Expression,
///     U: AsExpression<T::SqlType>,
/// {
///     MyEq::new(left, right.as_expression())
/// }
///
/// let users_with_name = users.select(id).filter(my_eq(name, "Sean"));
///
/// assert_eq!(Ok(1), users_with_name.first(&connection));
/// # }
/// ```
#[macro_export]
macro_rules! infix_operator {
    ($name:ident, $operator:expr) => {
        infix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        infix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $($return_ty:tt)::*) => {
        __diesel_operator_body!(
            notation = infix,
            struct_name = $name,
            operator = $operator,
            return_ty = $($return_ty)::*,
            ty_params = (T, U,),
            field_names = (left, right,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = infix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (T, U,),
            field_names = (left, right,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::infix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
#[doc(hidden)]
macro_rules! diesel_infix_operator {
    ($($args:tt)*) => {
        infix_operator!($($args)*);
    }
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// Similar to [`infix_operator!`], but the generated type will only take
/// a single argument rather than two. The operator SQL will be placed after
/// the single argument. See [`infix_operator!`] for example usage.
///
/// [`infix_operator!`]: macro.infix_operator.html
#[macro_export]
macro_rules! postfix_operator {
    ($name:ident, $operator:expr) => {
        postfix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        postfix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $return_ty:ty) => {
        __diesel_operator_body!(
            notation = postfix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = postfix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::postfix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
macro_rules! diesel_postfix_operator {
    ($($args:tt)*) => {
        postfix_operator!($($args)*);
    }
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// Similar to [`infix_operator!`], but the generated type will only take
/// a single argument rather than two. The operator SQL will be placed before
/// the single argument. See [`infix_operator!`] for example usage.
///
/// [`infix_operator!`]: macro.infix_operator.html
#[macro_export]
macro_rules! prefix_operator {
    ($name:ident, $operator:expr) => {
        prefix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        prefix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $return_ty:ty) => {
        __diesel_operator_body!(
            notation = prefix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = prefix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::prefix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
macro_rules! diesel_prefix_operator {
    ($($args:tt)*) => {
        prefix_operator!($($args)*);
    }
}

infix_operator!(Concat, " || ", ReturnBasedOnArgs);
infix_operator!(And, " AND ");
infix_operator!(Between, " BETWEEN ");
infix_operator!(Escape, " ESCAPE ");
infix_operator!(Eq, " = ");
infix_operator!(Gt, " > ");
infix_operator!(GtEq, " >= ");
infix_operator!(Like, " LIKE ");
infix_operator!(Lt, " < ");
infix_operator!(LtEq, " <= ");
infix_operator!(NotBetween, " NOT BETWEEN ");
infix_operator!(NotEq, " != ");
infix_operator!(NotLike, " NOT LIKE ");
infix_operator!(Or, " OR ");

postfix_operator!(IsNull, " IS NULL");
postfix_operator!(IsNotNull, " IS NOT NULL");
postfix_operator!(Asc, " ASC", ());
postfix_operator!(Desc, " DESC", ());

prefix_operator!(Not, "NOT ");

use insertable::{ColumnInsertValue, Insertable};
use query_builder::ValuesClause;
use query_source::Column;

impl<T, U> Insertable<T::Table> for Eq<T, U>
where
    T: Column,
{
    type Values = ValuesClause<ColumnInsertValue<T, U>, T::Table>;

    fn values(self) -> Self::Values {
        ValuesClause::new(ColumnInsertValue::Expression(self.left, self.right))
    }
}

impl<'a, T, Tab, U> Insertable<Tab> for &'a Eq<T, U>
where
    T: Copy,
    Eq<T, &'a U>: Insertable<Tab>,
{
    type Values = <Eq<T, &'a U> as Insertable<Tab>>::Values;

    fn values(self) -> Self::Values {
        Eq::new(self.left, &self.right).values()
    }
}
<|endoftext|>


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

mod node;
pub mod map;
pub mod set;

trait Recover<Q: ?Sized> {
    type Key;

    fn get(&self, key: &Q) -> Option<&Self::Key>;
    fn take(&mut self, key: &Q) -> Option<Self::Key>;
    fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
}
<commit_msg>hide docs for private `collections::btree::Recover` trait<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

mod node;
pub mod map;
pub mod set;

#[doc(hidden)]
trait Recover<Q: ?Sized> {
    type Key;

    fn get(&self, key: &Q) -> Option<&Self::Key>;
    fn take(&mut self, key: &Q) -> Option<Self::Key>;
    fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
}
<|endoftext|>


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

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::{c_int, c_char};
use std::ffi::CString;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

pub fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        static POISONED: AtomicBool = AtomicBool::new(false);
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features must be known to LLVM or the feature
// detection code will walk past the end of the feature array,
// leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"];

const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                 "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                 "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
                                                 "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0",
                                                     "power8-altivec\0", "power9-altivec\0",
                                                     "power8-vector\0", "power9-vector\0",
                                                     "vsx\0"];

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess);

    let whitelist = match &*sess.target.target.arch {
        "arm" | "aarch64" => ARM_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    };

    let mut features = Vec::new();
    for feat in whitelist {
        assert_eq!(feat.chars().last(), Some('\0'));
        if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } {
            features.push(Symbol::intern(&feat[..feat.len() - 1]));
        }
    }
    features
}

pub fn print_version() {
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub fn print(req: PrintRequest, sess: &Session) {
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}

pub fn enable_llvm_debug() {
    unsafe { llvm::LLVMRustSetDebug(1); }
}
<commit_msg>introduce a whitelist for aarch64<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::{c_int, c_char};
use std::ffi::CString;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

pub fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        static POISONED: AtomicBool = AtomicBool::new(false);
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features must be known to LLVM or the feature
// detection code will walk past the end of the feature array,
// leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"];

const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0"];

const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                 "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                 "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
                                                 "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0",
                                                     "power8-altivec\0", "power9-altivec\0",
                                                     "power8-vector\0", "power9-vector\0",
                                                     "vsx\0"];

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess);

    let whitelist = match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    };

    let mut features = Vec::new();
    for feat in whitelist {
        assert_eq!(feat.chars().last(), Some('\0'));
        if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } {
            features.push(Symbol::intern(&feat[..feat.len() - 1]));
        }
    }
    features
}

pub fn print_version() {
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub fn print(req: PrintRequest, sess: &Session) {
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}

pub fn enable_llvm_debug() {
    unsafe { llvm::LLVMRustSetDebug(1); }
}
<|endoftext|>