<commit_before>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
extern crate rustc_serialize;
extern crate hyper;
extern crate mio;
extern crate env_logger;
extern crate openssl;
#[macro_use]
extern crate log;
mod irc;
mod matrix;
mod bridge;
mod ssl;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt};
use std::thread;
use bridge::Bridge;
use std::env;
use std::path::Path;
use openssl::ssl::{SslContext, SslMethod};
use openssl::x509::X509FileType;
use irc::streams::{Server, AsEvented};

struct IrcHandler {
    server: Box<Server>,
    url: String
}

impl Handler for IrcHandler {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, _event_loop: &mut EventLoop<IrcHandler>, token: Token, _: EventSet) {
        match token {
            SERVER => {
                match self.server.accept() {
                    Some(client) => {
                        let mut bridge = Bridge::new(client, self.url.trim());
                        thread::spawn(move||{
                            bridge.run()
                        });
                    },
                    None => ()
                }
            },
            _ => unreachable!("Got a really weird token in the server event loop!")
        }
    }
}

const SERVER: Token = Token(0);

fn main() {
    env_logger::init().unwrap();
    let addr = "127.0.0.1:8001".parse().unwrap();
    let url =  env::args().nth(1).unwrap();
    let use_ssl = false;
    let server: Box<Server> = if use_ssl {
        let mut ssl = SslContext::new(SslMethod::Sslv23).expect("SSL setup failed");
        ssl.set_certificate_file(Path::new("pto.crt"), X509FileType::PEM).expect("Could not load pto.crt");
        ssl.set_private_key_file(Path::new("pto.key"), X509FileType::PEM).expect("Could not load pto.key");
        Box::new(ssl::SslServer::new(&addr, ssl))
    } else {
        Box::new(ssl::TcpServer::new(&addr))
    };
    info!("Listening on 127.0.0.1:8001");
    let mut events = EventLoop::new().unwrap();
    events.register(server.as_evented(), SERVER, EventSet::all(), PollOpt::edge()).unwrap();
    events.run(&mut IrcHandler{
        server: server,
        url: url
    }).unwrap();
}
<commit_msg>main: warn about SSL being disabled<commit_after>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
extern crate rustc_serialize;
extern crate hyper;
extern crate mio;
extern crate env_logger;
extern crate openssl;
#[macro_use]
extern crate log;
mod irc;
mod matrix;
mod bridge;
mod ssl;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt};
use std::thread;
use bridge::Bridge;
use std::env;
use std::path::Path;
use openssl::ssl::{SslContext, SslMethod};
use openssl::x509::X509FileType;
use irc::streams::{Server, AsEvented};

struct IrcHandler {
    server: Box<Server>,
    url: String
}

impl Handler for IrcHandler {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, _event_loop: &mut EventLoop<IrcHandler>, token: Token, _: EventSet) {
        match token {
            SERVER => {
                match self.server.accept() {
                    Some(client) => {
                        let mut bridge = Bridge::new(client, self.url.trim());
                        thread::spawn(move||{
                            bridge.run()
                        });
                    },
                    None => ()
                }
            },
            _ => unreachable!("Got a really weird token in the server event loop!")
        }
    }
}

const SERVER: Token = Token(0);

fn main() {
    env_logger::init().unwrap();
    let addr = "127.0.0.1:8001".parse().unwrap();
    let url =  env::args().nth(1).unwrap();
    let use_ssl = false;
    let server: Box<Server> = if use_ssl {
        let mut ssl = SslContext::new(SslMethod::Sslv23).expect("SSL setup failed");
        ssl.set_certificate_file(Path::new("pto.crt"), X509FileType::PEM).expect("Could not load pto.crt");
        ssl.set_private_key_file(Path::new("pto.key"), X509FileType::PEM).expect("Could not load pto.key");
        Box::new(ssl::SslServer::new(&addr, ssl))
    } else {
        warn!("SSL IS DISABLED!! IRC LOGINS ARE IN THE CLEAR AND UNENCRYPTED");
        Box::new(ssl::TcpServer::new(&addr))
    };
    info!("Listening on 127.0.0.1:8001");
    let mut events = EventLoop::new().unwrap();
    events.register(server.as_evented(), SERVER, EventSet::all(), PollOpt::edge()).unwrap();
    events.run(&mut IrcHandler{
        server: server,
        url: url
    }).unwrap();
}
<|endoftext|>


<commit_before>extern crate count;

extern crate clap;
extern crate walkdir;
extern crate itertools;

use clap::{Arg, App, AppSettings};
use walkdir::WalkDir;

use std::collections::HashMap;
use std::collections::hash_map::Entry;

use count as c;

fn main() {

    let matches = App::new("count")
        .global_settings(&[AppSettings::ColoredHelp])
        .version("0.1")
        .author("Curtis Gagliardi <curtis@curtis.io>")
        .about("counts things quickly hopefully")
        .arg(Arg::with_name("exclude")
            .required(false)
            .long("exclude")
            .value_name("FILES/DIRS")
            .takes_value(true)
            .value_delimiter(",")
            .help("comma separated list of files/directories to ignore"))
        .arg(Arg::with_name("target")
            .required(true)
            .help("The file or directory to count lines in/of"))
        .get_matches();

    let filepaths = matches.values_of("target").unwrap();
    let mut counts: Vec<(c::Lang, String, c::Count)> = Vec::new();
    let mut files_processed = 0;
    for filepath in filepaths {
        for entry in WalkDir::new(filepath) {
            let entry = entry.unwrap();
            if entry.file_type().is_file() {
                let path = entry.path().to_str().unwrap();
                let lang = c::lang_from_ext(path);
                if lang != c::Lang::Unrecognized {
                    let count = c::count(path);
                    counts.push((lang, String::from(path), count));
                }
            }
        }
    }

    let mut lang_counts_by_file: HashMap<c::Lang, Vec<(String, c::Count)>> = HashMap::new();
    for (lang, filepath, count) in counts {
        match lang_counts_by_file.entry(lang) {
            Entry::Occupied(mut lang_counts_by_file) => {
                lang_counts_by_file.get_mut().push((filepath, count))
            }
            Entry::Vacant(lang_counts_by_file) => {
                lang_counts_by_file.insert(vec![(filepath, count)]);
            }
        };
    }

    let mut lang_totals: HashMap<c::Lang, c::LangTotal> = HashMap::new();
    for (lang, count_vec) in lang_counts_by_file {
        // TODO(cgag): use a fold
        let mut lang_total: c::Count = Default::default();
        for &(_, ref count) in count_vec.iter() {
            lang_total.merge(count);
        }
        lang_totals.insert(lang,
                           c::LangTotal {
                               files: count_vec.len() as u32,
                               count: lang_total,
                           });
    }

    println!("-------------------------------------------------------------------------------");
    println!(" {0: <12} {1: >12} {2: >12} {3: >12} {4: >12} {5: >12}",
             "Language",
             "Files",
             "Lines",
             "Blank",
             "Comment",
             "Code");
    println!("-------------------------------------------------------------------------------");

    let mut totals_by_lang = lang_totals.iter().collect::<Vec<(&c::Lang, &c::LangTotal)>>();
    totals_by_lang.sort_by(|&(lang1, total1), &(lang2, total2)| lang2.to_s().cmp(lang1.to_s()));

    for &(lang, total) in &totals_by_lang {
        println!(" {0: <12} {1: >12} {2: >12} {3: >12} {4: >12} {5: >12}",
                 lang,
                 total.files,
                 total.count.lines,
                 total.count.blank,
                 total.count.comment,
                 total.count.code);
    }

    let mut totals = c::LangTotal {
        files: 0,
        count: Default::default(),
    };
    for &(_, ref total) in &totals_by_lang {
        totals.files += total.files;
        totals.count.code += total.count.code;
        totals.count.blank += total.count.blank;
        totals.count.comment += total.count.comment;
        totals.count.lines += total.count.lines;
    }

    println!("-------------------------------------------------------------------------------");
    println!(" {0: <12} {1: >12} {2: >12} {3: >12} {4: >12} {5: >12}",
             "Total",
             totals.files,
             totals.count.lines,
             totals.count.blank,
             totals.count.comment,
             totals.count.code);
    println!("-------------------------------------------------------------------------------");
}
<commit_msg>alternative counting with map/filter, probably not worth it<commit_after>extern crate count;

extern crate clap;
extern crate walkdir;
extern crate itertools;

use clap::{Arg, App, AppSettings};
use walkdir::WalkDir;

use std::collections::HashMap;
use std::collections::hash_map::Entry;

use count as c;

fn main() {

    let matches = App::new("count")
        .global_settings(&[AppSettings::ColoredHelp])
        .version("0.1")
        .author("Curtis Gagliardi <curtis@curtis.io>")
        .about("counts things quickly hopefully")
        .arg(Arg::with_name("exclude")
            .required(false)
            .long("exclude")
            .value_name("FILES/DIRS")
            .takes_value(true)
            .value_delimiter(",")
            .help("comma separated list of files/directories to ignore"))
        .arg(Arg::with_name("target")
            .required(true)
            .help("The file or directory to count lines in/of"))
        .get_matches();

    let filepaths = matches.values_of("target").unwrap();
    // let mut counts = filepaths.flat_map(|p| {
    //         WalkDir::new(p)
    //             .into_iter()
    //             .map(|entry| entry.unwrap())
    //             .filter(|entry| entry.file_type().is_file())
    //             .map(|file_entry| String::from(file_entry.path().to_str().unwrap()))
    //             .map(|path| (c::lang_from_ext(&path), path))
    //             .filter(|&(lang, _)| lang != c::Lang::Unrecognized)
    //             .map(|(lang, path)| (lang, path.clone(), c::count(&path)))
    //     })
    //     .collect::<Vec<_>>();

    let mut counts: Vec<(c::Lang, String, c::Count)> = Vec::new();
    for filepath in filepaths {
        for entry in WalkDir::new(filepath) {
            let entry = entry.unwrap();
            if entry.file_type().is_file() {
                let path = entry.path().to_str().unwrap();
                let lang = c::lang_from_ext(path);
                if lang != c::Lang::Unrecognized {
                    let count = c::count(path);
                    counts.push((lang, String::from(path), count));
                }
            }
        }
    }

    let mut lang_counts_by_file: HashMap<c::Lang, Vec<(String, c::Count)>> = HashMap::new();
    for (lang, filepath, count) in counts {
        match lang_counts_by_file.entry(lang) {
            Entry::Occupied(mut lang_counts_by_file) => {
                lang_counts_by_file.get_mut().push((filepath, count))
            }
            Entry::Vacant(lang_counts_by_file) => {
                lang_counts_by_file.insert(vec![(filepath, count)]);
            }
        };
    }

    let mut lang_totals: HashMap<c::Lang, c::LangTotal> = HashMap::new();
    for (lang, count_vec) in lang_counts_by_file {
        // TODO(cgag): use a fold
        let mut lang_total: c::Count = Default::default();
        for &(_, ref count) in count_vec.iter() {
            lang_total.merge(count);
        }
        lang_totals.insert(lang,
                           c::LangTotal {
                               files: count_vec.len() as u32,
                               count: lang_total,
                           });
    }

    println!("-------------------------------------------------------------------------------");
    println!(" {0: <12} {1: >12} {2: >12} {3: >12} {4: >12} {5: >12}",
             "Language",
             "Files",
             "Lines",
             "Blank",
             "Comment",
             "Code");
    println!("-------------------------------------------------------------------------------");

    let mut totals_by_lang = lang_totals.iter().collect::<Vec<(&c::Lang, &c::LangTotal)>>();
    totals_by_lang.sort_by(|&(lang1, total1), &(lang2, total2)| lang2.to_s().cmp(lang1.to_s()));

    for &(lang, total) in &totals_by_lang {
        println!(" {0: <12} {1: >12} {2: >12} {3: >12} {4: >12} {5: >12}",
                 lang,
                 total.files,
                 total.count.lines,
                 total.count.blank,
                 total.count.comment,
                 total.count.code);
    }

    let mut totals = c::LangTotal {
        files: 0,
        count: Default::default(),
    };
    for &(_, ref total) in &totals_by_lang {
        totals.files += total.files;
        totals.count.code += total.count.code;
        totals.count.blank += total.count.blank;
        totals.count.comment += total.count.comment;
        totals.count.lines += total.count.lines;
    }

    println!("-------------------------------------------------------------------------------");
    println!(" {0: <12} {1: >12} {2: >12} {3: >12} {4: >12} {5: >12}",
             "Total",
             totals.files,
             totals.count.lines,
             totals.count.blank,
             totals.count.comment,
             totals.count.code);
    println!("-------------------------------------------------------------------------------");
}
<|endoftext|>


<commit_before>use direction::{Direction, NUM_DIRECTIONS};

#[derive(Debug, Copy, Clone)]
pub struct Room<T: Copy, C: Copy> {
  exits: [Option<T>; NUM_DIRECTIONS],
  pub name: &'static str,
  pub description: &'static str,
  pub contents: Option<C>,
}

impl<T: Copy, C: Copy> Room<T, C> {
  pub fn new() -> Self {
    Self {
      exits: [None; NUM_DIRECTIONS],
      name: "",
      description: "",
      contents: None,
    }
  }

  pub fn get_exit(self, d: Direction) -> Option<T> {
    self.exits[d as usize]
  }

  pub fn set_exit(&mut self, d: Direction, r: T) -> &mut Self {
    self.exits[d as usize] = Some(r);
    self
  }

  pub fn describe(&mut self, name: &'static str, desc: &'static str) -> &mut Self {
    self.name = name;
    self.description = desc;
    self
  }
}
<commit_msg>Assert that set_exit() is only called on exits that are currently None.<commit_after>use direction::{Direction, NUM_DIRECTIONS};

#[derive(Debug, Copy, Clone)]
pub struct Room<T: Copy, C: Copy> {
  exits: [Option<T>; NUM_DIRECTIONS],
  pub name: &'static str,
  pub description: &'static str,
  pub contents: Option<C>,
}

impl<T: Copy, C: Copy> Room<T, C> {
  pub fn new() -> Self {
    Self {
      exits: [None; NUM_DIRECTIONS],
      name: "",
      description: "",
      contents: None,
    }
  }

  pub fn get_exit(self, d: Direction) -> Option<T> {
    self.exits[d as usize]
  }

  pub fn set_exit(&mut self, d: Direction, r: T) -> &mut Self {
    assert!(self.exits[d as usize].is_none());
    self.exits[d as usize] = Some(r);
    self
  }

  pub fn describe(&mut self, name: &'static str, desc: &'static str) -> &mut Self {
    self.name = name;
    self.description = desc;
    self
  }
}
<|endoftext|>


<commit_before>use std::io::fs;
use std::path::posix::Path;
use std::os::homedir;
use std::io::fs::PathExtensions;
#[cfg(test)] use test_helper::{cleanup_dir,random_name};

static MUXED_NAME_STR: &'static str = "muxed";

/// Create the muxed directory and return the path if creation is successful.
pub fn create_muxed_dir(path: &Path) -> Path {
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create muxed directory: {}", path.filename())
    }

    path.clone()
}

/// Return the users current homedir as a string.
pub fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

pub fn muxed_dir() -> Path {
    let path = muxed_path();
    match path.exists() {
        true  => path,
        false => create_muxed_dir(&path)
    }
}

#[cfg(test)] pub fn muxed_path() -> Path {
    Path::new(format!("/tmp/.{}/", &MUXED_NAME_STR.to_string()))
}

#[cfg(not_test)] pub fn muxed_path() -> Path {
    Path::new(format!("{}/.{}/", root::homedir_string(), &MUXED_NAME_STR.to_string()))
}

#[test]
fn creates_muxed_dir() {
    let muxed_path = &muxed_path();
    create_muxed_dir(muxed_path);
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}

#[test]
fn muxed_dir_creates_dir() {
    let muxed_path = &muxed_dir();
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}

//#[test]
//fn muxed_dir_finds_existing_dir() {
//    let muxed_path = &muxed_path();
//    create_muxed_dir(muxed_path);
//    assert_eq!(muxed_path.as_str().unwrap(), muxed_dir().as_str().unwrap());
//    cleanup_dir(muxed_path);
//}
<commit_msg>Update Syntax & Don't decalre un-needed scope.<commit_after>use std::io::fs;
use std::path::posix::Path;
use std::os::homedir;
use std::io::fs::PathExtensions;
#[cfg(test)] use test_helper::{cleanup_dir,random_name};

static MUXED_NAME_STR: &'static str = "muxed";

/// Create the muxed directory and return the path if creation is successful.
pub fn create_muxed_dir(path: &Path) -> Path {
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create muxed directory: {}", path.filename())
    }

    path.clone()
}

/// Return the users current homedir as a string.
pub fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

pub fn muxed_dir() -> Path {
    let path = muxed_path();
    match path.exists() {
        true  => path,
        false => create_muxed_dir(&path)
    }
}

#[cfg(test)] pub fn muxed_path() -> Path {
    Path::new(format!("/tmp/.{}/", &MUXED_NAME_STR.to_string()))
}

#[cfg(not(test))] pub fn muxed_path() -> Path {
    Path::new(format!("{}/.{}/", homedir_string(), &MUXED_NAME_STR.to_string()))
}

#[test]
fn creates_muxed_dir() {
    let muxed_path = &muxed_path();
    create_muxed_dir(muxed_path);
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}

#[test]
fn muxed_dir_creates_dir() {
    let muxed_path = &muxed_dir();
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}

//#[test]
//fn muxed_dir_finds_existing_dir() {
//    let muxed_path = &muxed_path();
//    create_muxed_dir(muxed_path);
//    assert_eq!(muxed_path.as_str().unwrap(), muxed_dir().as_str().unwrap());
//    cleanup_dir(muxed_path);
//}
<|endoftext|>


<commit_before>#![ allow (unused_parens) ]

use std::fs;
use std::fs::DirEntry;
use std::io;
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use std::rc::Rc;

use output::Output;

use arguments::*;
use misc::*;
use storage::*;

fn scan_directory_internal (
	arguments: & Arguments,
	output: & mut Output,
	directory: Rc <PathBuf>,
	root_path: Rc <PathBuf>,
	in_iterator: & mut FileDatabaseIntoIterator,
	out_database: & mut FileDatabase,
	progress: & mut u64,
) -> Result <(), String> {

	let directory =
		directory.as_ref ();

	let entry_results: Vec <io::Result <DirEntry>> =
		try! (

		io_result (
			fs::read_dir (
				directory),
		).map_err (
			|error|

			format! (
				"Error reading directory: {:?}: {}",
				directory,
				error)

		)

	).collect ();

	let mut entries: Vec <DirEntry> =
		Vec::new ();

	for entry_result in entry_results.into_iter () {

		entries.push (
			try! (

			io_result (
				entry_result,
			).map_err (
				|error|

				format! (
					"Error reading entry: {}",
					error)

			)

		));

	}

	entries.sort_by_key (
		|entry|

		entry.file_name ()

	);

	let mut entry_iterator =
		entries.into_iter ().peekable ();

	loop {

		{

			let entry_next =
				entry_iterator.peek ();

			if entry_next.is_none () {
				break;
			}

		}

		let entry =
			entry_iterator.next ().unwrap ();

		let entry_path =
			Rc::new (
				entry.path ());

		loop {

			let exists = {

				let in_next_option =
					in_iterator.peek ();

				if in_next_option.is_none () {
					break;
				}

				let in_next =
					in_next_option.unwrap ();

				let in_next_path =
					in_next.path.clone ();

				if in_next_path >= entry_path {
					break;
				}

				in_next_path.exists ()

			};

			if exists {

				out_database.insert_direct (
					in_iterator.next ().unwrap ());

			} else {

				in_iterator.next ();

			}

		}

		let metadata =
			try! (

			fs::symlink_metadata (
				entry.path (),
			).map_err (
				|error|

				format! (
					"Error reading metadata for: {:?}: {}",
					entry.path (),
					error)

			)

		);

		let file_type =
			metadata.file_type ();

		if (

			file_type.is_symlink ()

			|| metadata.len () == 0

		) {

			// ignore

		} else if file_type.is_dir () {

			try! (
				scan_directory_internal (
					arguments,
					output,
					entry_path,
					root_path.clone (),
					in_iterator,
					out_database,
					progress));

		} else if file_type.is_file () {

			let exists = {

				let in_next_option =
					in_iterator.peek ();

				if in_next_option.is_some () {

					let in_next =
						in_next_option.unwrap ();

					let in_next_path =
						in_next.path.clone ();

					in_next_path == entry_path

				} else {

					false

				}

			};

			if exists {

				let existing_file_data =
					in_iterator.next ().unwrap ();

				let changed = (

					metadata.len () !=
						existing_file_data.size

				||

					metadata.mtime () !=
						existing_file_data.mtime

				);

				if changed {

					out_database.insert_update_metadata (
						& existing_file_data,
						root_path.clone (),
						& metadata,
					);

				} else {

					out_database.insert_direct (
						existing_file_data)

				}

			} else {

				out_database.insert_new (
					Rc::new (
						entry.path ()),
					root_path.clone (),
					& metadata,
				);

			}

		} else {

			stderrln! (
				"Ignoring unknown filetype: {:?}: {:?}",
				file_type,
				entry.path ());

		};

		if * progress % 0x1000 == 0 {

			output.status (
				& format! (
					"Scanning filesystem... {:?}",
					entry.path ()));

		}

		* progress += 1;

	}

	Ok (())

}

pub fn scan_directories (
	arguments: & Arguments,
	output: & mut Output,
	previous_database: FileDatabase,
) -> Result <FileDatabase, String> {

	let mut new_database: FileDatabase =
		FileDatabase::new ();

	let mut progress: u64 = 0;

	let previous_database_iterator =
		previous_database.into_iter ();

	let mut previous_database_iterator =
		previous_database_iterator.peekable ();

	for root_path in & arguments.root_paths {

		let root_path =
			new_database.get_path (
				root_path.clone ());

		loop {

			{

				let existing_file_data_option =
					previous_database_iterator.peek ();

				if existing_file_data_option.is_none () {
					break;
				}

				let existing_file_data =
					existing_file_data_option.unwrap ();

				let existing_file_path =
					& existing_file_data.path;

				if * existing_file_path >= root_path {
					break;
				}

			}

			new_database.insert_direct (
				previous_database_iterator.next ().unwrap ());

		}

		try! (
			scan_directory_internal (
				arguments,
				output,
				root_path.clone (),
				root_path.clone (),
				& mut previous_database_iterator,
				& mut new_database,
				& mut progress));

	}

	for existing_file_data_ref in previous_database_iterator {

		new_database.insert_direct (
			existing_file_data_ref.clone ());

	}

	output.clear_status ();

	output.message (
		& format! (
			"Scanned {} files",
			progress));

	output.message (
		& format! (
			"Total {} files in database",
			new_database.len ()));

	Ok (new_database)

}

// ex: noet ts=4 filetype=rust
<commit_msg>only scan one device/subvolume<commit_after>#![ allow (unused_parens) ]

use std::fs;
use std::fs::DirEntry;
use std::io;
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use std::rc::Rc;

use output::Output;

use arguments::*;
use misc::*;
use storage::*;

fn scan_directory_internal (
	arguments: & Arguments,
	output: & mut Output,
	directory: Rc <PathBuf>,
	root_path: Rc <PathBuf>,
	device_id: u64,
	in_iterator: & mut FileDatabaseIntoIterator,
	out_database: & mut FileDatabase,
	progress: & mut u64,
) -> Result <(), String> {

	let directory =
		directory.as_ref ();

	let entry_results: Vec <io::Result <DirEntry>> =
		try! (

		io_result (
			fs::read_dir (
				directory),
		).map_err (
			|error|

			format! (
				"Error reading directory: {:?}: {}",
				directory,
				error)

		)

	).collect ();

	let mut entries: Vec <DirEntry> =
		Vec::new ();

	for entry_result in entry_results.into_iter () {

		entries.push (
			try! (

			io_result (
				entry_result,
			).map_err (
				|error|

				format! (
					"Error reading entry: {}",
					error)

			)

		));

	}

	entries.sort_by_key (
		|entry|

		entry.file_name ()

	);

	let mut entry_iterator =
		entries.into_iter ().peekable ();

	loop {

		{

			let entry_next =
				entry_iterator.peek ();

			if entry_next.is_none () {
				break;
			}

		}

		let entry =
			entry_iterator.next ().unwrap ();

		let entry_path =
			Rc::new (
				entry.path ());

		loop {

			let exists = {

				let in_next_option =
					in_iterator.peek ();

				if in_next_option.is_none () {
					break;
				}

				let in_next =
					in_next_option.unwrap ();

				let in_next_path =
					in_next.path.clone ();

				if in_next_path >= entry_path {
					break;
				}

				in_next_path.exists ()

			};

			if exists {

				out_database.insert_direct (
					in_iterator.next ().unwrap ());

			} else {

				in_iterator.next ();

			}

		}

		let metadata =
			try! (

			fs::symlink_metadata (
				entry.path (),
			).map_err (
				|error|

				format! (
					"Error reading metadata for: {:?}: {}",
					entry.path (),
					error)

			)

		);

		let file_type =
			metadata.file_type ();

		if (

			file_type.is_symlink ()

			|| metadata.dev () != device_id

		) {

			// ignore

		} else if file_type.is_dir () {

			try! (
				scan_directory_internal (
					arguments,
					output,
					entry_path,
					root_path.clone (),
					device_id,
					in_iterator,
					out_database,
					progress));

		} else if file_type.is_file () {

			let exists = {

				let in_next_option =
					in_iterator.peek ();

				if in_next_option.is_some () {

					let in_next =
						in_next_option.unwrap ();

					let in_next_path =
						in_next.path.clone ();

					in_next_path == entry_path

				} else {

					false

				}

			};

			if exists {

				let existing_file_data =
					in_iterator.next ().unwrap ();

				let changed = (

					metadata.len () !=
						existing_file_data.size

				||

					metadata.mtime () !=
						existing_file_data.mtime

				);

				if changed {

					out_database.insert_update_metadata (
						& existing_file_data,
						root_path.clone (),
						& metadata,
					);

				} else {

					out_database.insert_direct (
						existing_file_data)

				}

			} else {

				out_database.insert_new (
					Rc::new (
						entry.path ()),
					root_path.clone (),
					& metadata,
				);

			}

		} else {

			stderrln! (
				"Ignoring unknown filetype: {:?}: {:?}",
				file_type,
				entry.path ());

		};

		if * progress % 0x1000 == 0 {

			output.status (
				& format! (
					"Scanning filesystem... {:?}",
					entry.path ()));

		}

		* progress += 1;

	}

	Ok (())

}

pub fn scan_directories (
	arguments: & Arguments,
	output: & mut Output,
	previous_database: FileDatabase,
) -> Result <FileDatabase, String> {

	let mut new_database: FileDatabase =
		FileDatabase::new ();

	let mut progress: u64 = 0;

	let previous_database_iterator =
		previous_database.into_iter ();

	let mut previous_database_iterator =
		previous_database_iterator.peekable ();

	for root_path in & arguments.root_paths {

		let root_path =
			new_database.get_path (
				root_path.clone ());

		let metadata =
			try! (

			fs::symlink_metadata (
				root_path.as_ref (),
			).map_err (
				|error|

				format! (
					"Error reading metadata for: {:?}: {}",
					root_path.as_ref (),
					error)

			)

		);

		loop {

			{

				let existing_file_data_option =
					previous_database_iterator.peek ();

				if existing_file_data_option.is_none () {
					break;
				}

				let existing_file_data =
					existing_file_data_option.unwrap ();

				let existing_file_path =
					& existing_file_data.path;

				if * existing_file_path >= root_path {
					break;
				}

			}

			new_database.insert_direct (
				previous_database_iterator.next ().unwrap ());

		}

		try! (
			scan_directory_internal (
				arguments,
				output,
				root_path.clone (),
				root_path.clone (),
				metadata.dev (),
				& mut previous_database_iterator,
				& mut new_database,
				& mut progress));

	}

	for existing_file_data_ref in previous_database_iterator {

		new_database.insert_direct (
			existing_file_data_ref.clone ());

	}

	output.clear_status ();

	output.message (
		& format! (
			"Scanned {} files",
			progress));

	output.message (
		& format! (
			"Total {} files in database",
			new_database.len ()));

	Ok (new_database)

}

// ex: noet ts=4 filetype=rust
<|endoftext|>


<commit_before>// (c) 2016-2017 Productize SPRL <joost@productize.be>

use std::fmt;
use std::result;
use std::str::FromStr;
use std::mem;

use Result;

/// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    /// convert self into a Sexp
    fn into_sexp(&self) -> Sexp;
}

impl Into<Sexp> for Vec<Sexp> {
    fn into(self:Vec<Sexp>) -> Sexp {
        Sexp::List(self)
    }
}

impl Into<Sexp> for String {
    fn into(self:String) -> Sexp {
        Sexp::String(self)
    }
}

impl<'a> From<&'a str> for Sexp {
    fn from(t:&str) -> Sexp {
        Sexp::String(t.into())
    }
}

impl Into<Sexp> for i64 {
    fn into(self:i64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl Into<Sexp> for f64 {
    fn into(self:f64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl<'a> From<(&'a str, Sexp)> for Sexp {
    fn from(kv:(&str, Sexp)) -> Sexp {
        let (name,value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(value);
        v.into()
    }
}

impl<'a, T:fmt::Display> From<(&'a str, &'a T)> for Sexp {
    fn from(kv:(&str, &T)) -> Sexp {
        let (name,value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }
}

/// a symbolic-expression
/// Can be a string or a list or nothing
#[derive(Debug, Clone, PartialEq)]
pub enum Sexp {
    /// plain String symbolic-expression
    String(String),
    /// list symbolic-expression
    List(Vec<Sexp>),
    /// empty, trivial symbolic-expression
    Empty,
}

// Following the KiCad file formats specification chapter 4.4 - Identifiers and Strings:
// A string may not contain an actual newline or carriage return,
// but it may use an escape sequence to encode a // newline, such as \n.
// If a string has any of the following conditions, then it must be quoted
// with a leading and trailing double quote
// character, otherwise it is acceptable to not quote the string:
// 1. has one or more of the following 4 separator bytes: ASCII space,
// tab, '(', or ')'.
// 2. has one or more of the following bytes: '%', '{', or '}'.
// 3. has a length of zero bytes, and you need a place holder for the field,
//  then use "".
// 4. includes a byte of '-', and this byte is not in the first position of
// the string.
//

// Joost remark: kicad no longer seems to follow Rule 4.
// so we don't either

/// encode a string according to the guidelines given by Kicad
pub fn encode_string(s: &str) -> String {
    // fn rule_4(s:&str) -> bool {
    // s.contains('-') && s.len() > 1 && s.as_bytes()[0] != 45
    // }
    if s.contains('(') || s.contains(' ') || s.contains(')') || s.contains('\t') ||
       s.contains('{') || s.contains('}') || s.contains('}') || s.contains('%') ||
       s.is_empty()
    // || rule_4(s)
    {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

impl Sexp {
    /// create an empty symbolic-expression
    #[deprecated(since="4.0.0", note="please use `Sexp::default()` instead")]
    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

    /// create a String type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_string<T>(s: T) -> Sexp
        where T: fmt::Display
    {
        format!("{}", s).into()
    }

    /// create a list type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_list(v: Vec<Sexp>) -> Sexp {
        Sexp::List(v)
    }

    /// create an empty list type symbolic-expression
    pub fn start(name:&str) -> Sexp {
        let mut v = vec![];
        v.push(Sexp::String(name.into()));
        Sexp::List(v)
    }

    /// push an element in a list
    pub fn push<T:Into<Sexp>>(&mut self, element:T) {
        match *self {
            Sexp::List(ref mut v) => {
                v.push(element.into())
            }
            _ => {
                panic!("Only use push on lists!")
            }
        }
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, the remainder is filled in via the provided
    /// fill function
    pub fn new_named_list<F>(name: &str, fill: F) -> Sexp
        where F: Fn(&mut Vec<Sexp>)
    {
        let mut v = vec![];
        v.push(name.into());
        fill(&mut v);
        Sexp::List(v)
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_named<T>(name: &str, value: T) -> Sexp
        where T: fmt::Display
    {
        let mut v = vec![];
        v.push(format!("{}", name).into());
        v.push(format!("{}", value).into());
        v.into()
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, and the second is another symbolic-expression
    /// created via the IntoSexp trait
    pub fn new_named_sexp<T>(name: &str, value: &T) -> Sexp
        where T: IntoSexp
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(value.into_sexp());
        Sexp::List(v)
    }

    /// if the expression is a list, take out the list and swap it with Empty
    pub fn take_list(&mut self) -> Result<Vec<Sexp>> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::List(v) => Ok(v),
            _ => Err(format!("Not a list: {}", e).into()),
        }
    }

    /// if the expression is a string, take it out and swap it with Empty
    pub fn take_string(&mut self) -> Result<String> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::String(s) => Ok(s),
            _ => Err(format!("Not a string: {}", e).into()),
        }
    }

    /// create a symbolic-expression via the IntoSexp trait
    pub fn from<T: IntoSexp>(t: &T) -> Sexp {
        t.into_sexp()
    }

    /// access the symbolic-expression as if it is a List
    pub fn list(&self) -> Result<&Vec<Sexp>> {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self).into()),
        }
    }

    /// access the symbolic-expression as if it is a String
    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self).into()),
        }
    }

    /// is this expression a string
    pub fn is_string(&self) -> bool {
        match *self {
            Sexp::String(_) => true,
            _ => false,
        }
    }

    /// is this expression a list
    pub fn is_list(&self) -> bool {
        match *self {
            Sexp::List(_) => true,
            _ => false,
        }
    }

    /// access the symbolic-expression as if it is a String
    /// that is a f64
    pub fn f(&self) -> Result<f64> {
        let s = self.string()?;
        let f = f64::from_str(s)?;
        Ok(f)
    }

    /// access the symbolic-expression as if it is a String
    /// that is an i64
    pub fn i(&self) -> Result<i64> {
        let s = self.string()?;
        let i = i64::from_str(s)?;
        Ok(i)
    }

    /// access the symbolic-expression as if it is a List
    /// assuming the first element is a String and return that
    pub fn list_name(&self) -> Result<&String> {
        let l = self.list()?;
        let l = &l[..];
        let a = l[0].string()?;
        Ok(a)
    }

    /// access the symbolic-expression as if it is a named List
    /// where the name is provided and returns the remaining elements
    /// after the name as a slice
    pub fn slice_atom(&self, s: &str) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list {} doesn't start with {}, but with {}", self, s, st).into());
        };
        Ok(&v[1..])
    }

    /// access the symbolic-expression as if it is a named List
    /// with two elements where the name is provided and returns
    /// the next element in the list
    pub fn named_value(&self, s: &str) -> Result<&Sexp> {
        let v = self.list()?;
        if v.len() != 2 {
            return Err(format!("list {} is not a named_value", s).into());
        }
        let l = self.slice_atom(s)?;
        Ok(&l[0])
    }

    /// as named_value but converted to i64
    pub fn named_value_i(&self, s: &str) -> Result<i64> {
        self.named_value(s)?.i()
    }

    /// as named_value but converted to f64
    pub fn named_value_f(&self, s: &str) -> Result<f64> {
        self.named_value(s)?.f()
    }

    /// as named_value but converted to String
    pub fn named_value_string(&self, s: &str) -> Result<&String> {
        self.named_value(s)?.string()
    }

    /// get the symbolic-expression as a list which starts
    /// with a string that indicates the name and has num more
    /// elements, returns those elements
    pub fn slice_atom_num(&self, s: &str, num: usize) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st).into());
        };
        if v.len() != (num + 1) {
            return Err(format!("list ({}) doesn't have {} elements but {}",
                                     s,
                                     num,
                                     v.len() - 1).into());
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => write!(f, "{}", encode_string(s)),
            Sexp::List(ref v) => {
                write!(f, "(")?;
                let l = v.len();
                for (i, x) in v.iter().enumerate() {
                    if i < l - 1 {
                        write!(f, "{} ", x)?;
                    } else {
                        write!(f, "{}", x)?;
                    }
                }
                write!(f, ")")
            }
            Sexp::Empty => Ok(()),
        }
    }
}

impl Default for Sexp {
    fn default() -> Sexp {
        Sexp::Empty
    }
}
<commit_msg>from &String<commit_after>// (c) 2016-2017 Productize SPRL <joost@productize.be>

use std::fmt;
use std::result;
use std::str::FromStr;
use std::mem;

use Result;

/// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    /// convert self into a Sexp
    fn into_sexp(&self) -> Sexp;
}

impl Into<Sexp> for Vec<Sexp> {
    fn into(self:Vec<Sexp>) -> Sexp {
        Sexp::List(self)
    }
}

impl Into<Sexp> for String {
    fn into(self:String) -> Sexp {
        Sexp::String(self)
    }
}

impl<'a> From<&'a str> for Sexp {
    fn from(t:&str) -> Sexp {
        Sexp::String(t.into())
    }
}

impl<'a> From<&'a String> for Sexp {
    fn from(t:&String) -> Sexp {
        Sexp::String(t.clone())
    }
}

impl Into<Sexp> for i64 {
    fn into(self:i64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl Into<Sexp> for f64 {
    fn into(self:f64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl<'a> From<(&'a str, Sexp)> for Sexp {
    fn from(kv:(&str, Sexp)) -> Sexp {
        let (name,value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(value);
        v.into()
    }
}

impl<'a, T:fmt::Display> From<(&'a str, &'a T)> for Sexp {
    fn from(kv:(&str, &T)) -> Sexp {
        let (name,value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }
}

/// a symbolic-expression
/// Can be a string or a list or nothing
#[derive(Debug, Clone, PartialEq)]
pub enum Sexp {
    /// plain String symbolic-expression
    String(String),
    /// list symbolic-expression
    List(Vec<Sexp>),
    /// empty, trivial symbolic-expression
    Empty,
}

// Following the KiCad file formats specification chapter 4.4 - Identifiers and Strings:
// A string may not contain an actual newline or carriage return,
// but it may use an escape sequence to encode a // newline, such as \n.
// If a string has any of the following conditions, then it must be quoted
// with a leading and trailing double quote
// character, otherwise it is acceptable to not quote the string:
// 1. has one or more of the following 4 separator bytes: ASCII space,
// tab, '(', or ')'.
// 2. has one or more of the following bytes: '%', '{', or '}'.
// 3. has a length of zero bytes, and you need a place holder for the field,
//  then use "".
// 4. includes a byte of '-', and this byte is not in the first position of
// the string.
//

// Joost remark: kicad no longer seems to follow Rule 4.
// so we don't either

/// encode a string according to the guidelines given by Kicad
pub fn encode_string(s: &str) -> String {
    // fn rule_4(s:&str) -> bool {
    // s.contains('-') && s.len() > 1 && s.as_bytes()[0] != 45
    // }
    if s.contains('(') || s.contains(' ') || s.contains(')') || s.contains('\t') ||
       s.contains('{') || s.contains('}') || s.contains('}') || s.contains('%') ||
       s.is_empty()
    // || rule_4(s)
    {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

impl Sexp {
    /// create an empty symbolic-expression
    #[deprecated(since="4.0.0", note="please use `Sexp::default()` instead")]
    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

    /// create a String type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_string<T>(s: T) -> Sexp
        where T: fmt::Display
    {
        format!("{}", s).into()
    }

    /// create a list type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_list(v: Vec<Sexp>) -> Sexp {
        Sexp::List(v)
    }

    /// create an empty list type symbolic-expression
    pub fn start(name:&str) -> Sexp {
        let mut v = vec![];
        v.push(Sexp::String(name.into()));
        Sexp::List(v)
    }

    /// push an element in a list
    pub fn push<T:Into<Sexp>>(&mut self, element:T) {
        match *self {
            Sexp::List(ref mut v) => {
                v.push(element.into())
            }
            _ => {
                panic!("Only use push on lists!")
            }
        }
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, the remainder is filled in via the provided
    /// fill function
    pub fn new_named_list<F>(name: &str, fill: F) -> Sexp
        where F: Fn(&mut Vec<Sexp>)
    {
        let mut v = vec![];
        v.push(name.into());
        fill(&mut v);
        Sexp::List(v)
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_named<T>(name: &str, value: T) -> Sexp
        where T: fmt::Display
    {
        let mut v = vec![];
        v.push(format!("{}", name).into());
        v.push(format!("{}", value).into());
        v.into()
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, and the second is another symbolic-expression
    /// created via the IntoSexp trait
    pub fn new_named_sexp<T>(name: &str, value: &T) -> Sexp
        where T: IntoSexp
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(value.into_sexp());
        Sexp::List(v)
    }

    /// if the expression is a list, take out the list and swap it with Empty
    pub fn take_list(&mut self) -> Result<Vec<Sexp>> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::List(v) => Ok(v),
            _ => Err(format!("Not a list: {}", e).into()),
        }
    }

    /// if the expression is a string, take it out and swap it with Empty
    pub fn take_string(&mut self) -> Result<String> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::String(s) => Ok(s),
            _ => Err(format!("Not a string: {}", e).into()),
        }
    }

    /// create a symbolic-expression via the IntoSexp trait
    pub fn from<T: IntoSexp>(t: &T) -> Sexp {
        t.into_sexp()
    }

    /// access the symbolic-expression as if it is a List
    pub fn list(&self) -> Result<&Vec<Sexp>> {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self).into()),
        }
    }

    /// access the symbolic-expression as if it is a String
    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self).into()),
        }
    }

    /// is this expression a string
    pub fn is_string(&self) -> bool {
        match *self {
            Sexp::String(_) => true,
            _ => false,
        }
    }

    /// is this expression a list
    pub fn is_list(&self) -> bool {
        match *self {
            Sexp::List(_) => true,
            _ => false,
        }
    }

    /// access the symbolic-expression as if it is a String
    /// that is a f64
    pub fn f(&self) -> Result<f64> {
        let s = self.string()?;
        let f = f64::from_str(s)?;
        Ok(f)
    }

    /// access the symbolic-expression as if it is a String
    /// that is an i64
    pub fn i(&self) -> Result<i64> {
        let s = self.string()?;
        let i = i64::from_str(s)?;
        Ok(i)
    }

    /// access the symbolic-expression as if it is a List
    /// assuming the first element is a String and return that
    pub fn list_name(&self) -> Result<&String> {
        let l = self.list()?;
        let l = &l[..];
        let a = l[0].string()?;
        Ok(a)
    }

    /// access the symbolic-expression as if it is a named List
    /// where the name is provided and returns the remaining elements
    /// after the name as a slice
    pub fn slice_atom(&self, s: &str) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list {} doesn't start with {}, but with {}", self, s, st).into());
        };
        Ok(&v[1..])
    }

    /// access the symbolic-expression as if it is a named List
    /// with two elements where the name is provided and returns
    /// the next element in the list
    pub fn named_value(&self, s: &str) -> Result<&Sexp> {
        let v = self.list()?;
        if v.len() != 2 {
            return Err(format!("list {} is not a named_value", s).into());
        }
        let l = self.slice_atom(s)?;
        Ok(&l[0])
    }

    /// as named_value but converted to i64
    pub fn named_value_i(&self, s: &str) -> Result<i64> {
        self.named_value(s)?.i()
    }

    /// as named_value but converted to f64
    pub fn named_value_f(&self, s: &str) -> Result<f64> {
        self.named_value(s)?.f()
    }

    /// as named_value but converted to String
    pub fn named_value_string(&self, s: &str) -> Result<&String> {
        self.named_value(s)?.string()
    }

    /// get the symbolic-expression as a list which starts
    /// with a string that indicates the name and has num more
    /// elements, returns those elements
    pub fn slice_atom_num(&self, s: &str, num: usize) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st).into());
        };
        if v.len() != (num + 1) {
            return Err(format!("list ({}) doesn't have {} elements but {}",
                                     s,
                                     num,
                                     v.len() - 1).into());
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => write!(f, "{}", encode_string(s)),
            Sexp::List(ref v) => {
                write!(f, "(")?;
                let l = v.len();
                for (i, x) in v.iter().enumerate() {
                    if i < l - 1 {
                        write!(f, "{} ", x)?;
                    } else {
                        write!(f, "{}", x)?;
                    }
                }
                write!(f, ")")
            }
            Sexp::Empty => Ok(()),
        }
    }
}

impl Default for Sexp {
    fn default() -> Sexp {
        Sexp::Empty
    }
}
<|endoftext|>


<commit_before>use std::{fmt, mem};
use std::rc::Rc;
use std::cell::RefCell;

use futures::{Async, Future, Poll};
use futures::task::{Task as FutureTask, current as current_task};

use route::{Reply, ReplyItem};
use body::{Body, BodyStream, Binary};
use context::Frame;
use h1writer::{Writer, WriterState};
use error::{Error, UnexpectedTaskFrame};
use pipeline::MiddlewaresResponse;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;

#[derive(PartialEq, Debug)]
enum TaskRunningState {
    Paused,
    Running,
    Done,
}

impl TaskRunningState {
    fn is_done(&self) -> bool {
        *self == TaskRunningState::Done
    }
    fn pause(&mut self) {
        if *self != TaskRunningState::Done {
            *self = TaskRunningState::Paused
        }
    }
    fn resume(&mut self) {
        if *self != TaskRunningState::Done {
            *self = TaskRunningState::Running
        }
    }
}

enum ResponseState {
    Reading,
    Ready(HttpResponse),
    Middlewares(MiddlewaresResponse),
    Prepared(Option<HttpResponse>),
}

enum IOState {
    Response,
    Payload(BodyStream),
    Context,
    Done,
}

enum TaskStream {
    None,
    Context(Box<IoContext>),
    Response(Box<Future<Item=HttpResponse, Error=Error>>),
}

impl IOState {
    fn is_done(&self) -> bool {
        match *self {
            IOState::Done => true,
            _ => false
        }
    }
}

impl ResponseState {
    fn is_reading(&self) -> bool {
        match *self {
            ResponseState::Reading => true,
            _ => false
        }
    }
}

impl fmt::Debug for ResponseState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResponseState::Reading => write!(f, "ResponseState::Reading"),
            ResponseState::Ready(_) => write!(f, "ResponseState::Ready"),
            ResponseState::Middlewares(_) => write!(f, "ResponseState::Middlewares"),
            ResponseState::Prepared(_) => write!(f, "ResponseState::Prepared"),
        }
    }
}

impl fmt::Debug for IOState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IOState::Response => write!(f, "IOState::Response"),
            IOState::Payload(_) => write!(f, "IOState::Payload"),
            IOState::Context => write!(f, "IOState::Context"),
            IOState::Done => write!(f, "IOState::Done"),
        }
    }
}

pub(crate) trait IoContext: 'static {
    fn disconnected(&mut self);
    fn poll(&mut self) -> Poll<Option<Frame>, Error>;
}

/// Future that resolves when all buffered data get sent
#[doc(hidden)]
#[derive(Debug)]
pub struct DrainFut {
    drained: bool,
    task: Option<FutureTask>,
}

impl Default for DrainFut {

    fn default() -> DrainFut {
        DrainFut {
            drained: false,
            task: None,
        }
    }
}

impl DrainFut {

    fn set(&mut self) {
        self.drained = true;
        if let Some(task) = self.task.take() {
            task.notify()
        }
    }
}

impl Future for DrainFut {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        if self.drained {
            Ok(Async::Ready(()))
        } else {
            self.task = Some(current_task());
            Ok(Async::NotReady)
        }
    }
}

pub(crate) struct Task {
    running: TaskRunningState,
    response: ResponseState,
    iostate: IOState,
    stream: TaskStream,
    drain: Vec<Rc<RefCell<DrainFut>>>,
    middlewares: Option<MiddlewaresResponse>,
}

impl Task {

    pub(crate) fn new(reply: Reply) -> Task {
        match reply.into() {
            ReplyItem::Message(msg) => {
                Task::from_response(msg)
            },
            ReplyItem::Actor(ctx) => {
                Task { running: TaskRunningState::Running,
                       response: ResponseState::Reading,
                       iostate: IOState::Response,
                       drain: Vec::new(),
                       stream: TaskStream::Context(ctx),
                       middlewares: None }
            }
            ReplyItem::Future(fut) => {
                Task { running: TaskRunningState::Running,
                       response: ResponseState::Reading,
                       iostate: IOState::Response,
                       drain: Vec::new(),
                       stream: TaskStream::Response(fut),
                       middlewares: None }
            }
        }
    }

    pub(crate) fn from_response<R: Into<HttpResponse>>(response: R) -> Task {
        Task { running: TaskRunningState::Running,
               response: ResponseState::Ready(response.into()),
               iostate: IOState::Response,
               drain: Vec::new(),
               stream: TaskStream::None,
               middlewares: None }
    }

    pub(crate) fn from_error<E: Into<Error>>(err: E) -> Task {
        Task::from_response(err.into())
    }

    pub(crate) fn response(&mut self) -> HttpResponse {
        match self.response {
            ResponseState::Prepared(ref mut state) => state.take().unwrap(),
            _ => panic!("Internal state is broken"),
        }
    }

    pub(crate) fn set_middlewares(&mut self, middlewares: MiddlewaresResponse) {
        self.middlewares = Some(middlewares)
    }

    pub(crate) fn disconnected(&mut self) {
        if let TaskStream::Context(ref mut ctx) = self.stream {
            ctx.disconnected();
        }
    }

    pub(crate) fn poll_io<T>(&mut self, io: &mut T, req: &mut HttpRequest) -> Poll<bool, Error>
        where T: Writer
    {
        trace!("POLL-IO frames resp: {:?}, io: {:?}, running: {:?}",
               self.response, self.iostate, self.running);

        if self.iostate.is_done() {  // response is completed
            return Ok(Async::Ready(self.running.is_done()));
        } else if self.drain.is_empty() && self.running != TaskRunningState::Paused {
            // if task is paused, write buffer is probably full

            loop {
                let result = match mem::replace(&mut self.iostate, IOState::Done) {
                    IOState::Response => {
                        match self.poll_response(req) {
                            Ok(Async::Ready(mut resp)) => {
                                let result = io.start(req, &mut resp)?;

                                match resp.replace_body(Body::Empty) {
                                    Body::Streaming(stream) | Body::Upgrade(stream) =>
                                        self.iostate = IOState::Payload(stream),
                                    Body::StreamingContext | Body::UpgradeContext =>
                                        self.iostate = IOState::Context,
                                    _ => (),
                                }
                                self.response = ResponseState::Prepared(Some(resp));
                                result
                            },
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Response;
                                return Ok(Async::NotReady)
                            }
                            Err(err) => {
                                let mut resp = err.into();
                                let result = io.start(req, &mut resp)?;

                                match resp.replace_body(Body::Empty) {
                                    Body::Streaming(stream) | Body::Upgrade(stream) =>
                                        self.iostate = IOState::Payload(stream),
                                    _ => (),
                                }
                                self.response = ResponseState::Prepared(Some(resp));
                                result
                            }
                        }
                    },
                    IOState::Payload(mut body) => {
                        // always poll stream
                        if self.running == TaskRunningState::Running {
                            match self.poll()? {
                                Async::Ready(_) =>
                                    self.running = TaskRunningState::Done,
                                Async::NotReady => (),
                            }
                        }

                        match body.poll() {
                            Ok(Async::Ready(None)) => {
                                self.iostate = IOState::Done;
                                io.write_eof()?;
                                break
                            },
                            Ok(Async::Ready(Some(chunk))) => {
                                self.iostate = IOState::Payload(body);
                                io.write(chunk.as_ref())?
                            }
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Payload(body);
                                break
                            },
                            Err(err) => return Err(err),
                        }
                    }
                    IOState::Context => {
                        match self.poll_context() {
                            Ok(Async::Ready(None)) => {
                                self.iostate = IOState::Done;
                                self.running = TaskRunningState::Done;
                                io.write_eof()?;
                                break
                            },
                            Ok(Async::Ready(Some(chunk))) => {
                                self.iostate = IOState::Context;
                                io.write(chunk.as_ref())?
                            }
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Context;
                                break
                            }
                            Err(err) => return Err(err),
                        }
                    }
                    IOState::Done => break,
                };

                match result {
                    WriterState::Pause => {
                        self.running.pause();
                        break
                    }
                    WriterState::Done =>
                        self.running.resume(),
                }
            }
        }

        // flush io
        match io.poll_complete() {
            Ok(Async::Ready(_)) => self.running.resume(),
            Ok(Async::NotReady) => return Ok(Async::NotReady),
            Err(err) => {
                debug!("Error sending data: {}", err);
                return Err(err.into())
            }
        }

        // drain futures
        if !self.drain.is_empty() {
            for fut in &mut self.drain {
                fut.borrow_mut().set()
            }
            self.drain.clear();
        }

        // response is completed
        if self.iostate.is_done() {
            if let ResponseState::Prepared(Some(ref mut resp)) = self.response {
                resp.set_response_size(io.written())
            }
            Ok(Async::Ready(self.running.is_done()))
        } else {
            Ok(Async::NotReady)
        }
    }

    pub(crate) fn poll_response(&mut self, req: &mut HttpRequest) -> Poll<HttpResponse, Error> {
        loop {
            let state = mem::replace(&mut self.response, ResponseState::Prepared(None));
            match state {
                ResponseState::Ready(response) => {
                    // run middlewares
                    if let Some(mut middlewares) = self.middlewares.take() {
                        match middlewares.response(req, response) {
                            Ok(Some(response)) =>
                                return Ok(Async::Ready(response)),
                            Ok(None) => {
                                // middlewares need to run some futures
                                self.response = ResponseState::Middlewares(middlewares);
                                continue
                            }
                            Err(err) => return Err(err),
                        }
                    } else {
                        return Ok(Async::Ready(response))
                    }
                }
                ResponseState::Middlewares(mut middlewares) => {
                    // process middlewares
                    match middlewares.poll(req) {
                        Ok(Async::NotReady) => {
                            self.response = ResponseState::Middlewares(middlewares);
                            return Ok(Async::NotReady)
                        },
                        Ok(Async::Ready(response)) =>
                            return Ok(Async::Ready(response)),
                        Err(err) =>
                            return Err(err),
                    }
                }
                _ => (),
            }
            self.response = state;

            match mem::replace(&mut self.stream, TaskStream::None) {
                TaskStream::None =>
                    return Ok(Async::NotReady),
                TaskStream::Context(mut context) => {
                    loop {
                        match context.poll() {
                            Ok(Async::Ready(Some(frame))) => {
                                match frame {
                                    Frame::Message(msg) => {
                                        if !self.response.is_reading() {
                                            error!("Unexpected message frame {:?}", msg);
                                            return Err(UnexpectedTaskFrame.into())
                                        }
                                        self.stream = TaskStream::Context(context);
                                        self.response = ResponseState::Ready(msg);
                                        break
                                    },
                                    Frame::Payload(_) => (),
                                    Frame::Drain(fut) => {
                                        self.drain.push(fut);
                                        self.stream = TaskStream::Context(context);
                                        break
                                    }
                                }
                            },
                            Ok(Async::Ready(None)) => {
                                error!("Unexpected eof");
                                return Err(UnexpectedTaskFrame.into())
                            },
                            Ok(Async::NotReady) => {
                                self.stream = TaskStream::Context(context);
                                return Ok(Async::NotReady)
                            },
                            Err(err) =>
                                return Err(err),
                        }
                    }
                },
                TaskStream::Response(mut fut) => {
                    match fut.poll() {
                        Ok(Async::NotReady) => {
                            self.stream = TaskStream::Response(fut);
                            return Ok(Async::NotReady);
                        },
                        Ok(Async::Ready(response)) => {
                            self.response = ResponseState::Ready(response);
                        }
                        Err(err) =>
                            return Err(err)
                    }
                }
            }
        }
    }

    pub(crate) fn poll(&mut self) -> Poll<(), Error> {
        match self.stream {
            TaskStream::None | TaskStream::Response(_) =>
                Ok(Async::Ready(())),
            TaskStream::Context(ref mut context) => {
                loop {
                    match context.poll() {
                        Ok(Async::Ready(Some(_))) => (),
                        Ok(Async::Ready(None)) =>
                            return Ok(Async::Ready(())),
                        Ok(Async::NotReady) =>
                            return Ok(Async::NotReady),
                        Err(err) =>
                            return Err(err),
                    }
                }
            },
        }
    }

    fn poll_context(&mut self) -> Poll<Option<Binary>, Error> {
        match self.stream {
            TaskStream::None | TaskStream::Response(_) =>
                Err(UnexpectedTaskFrame.into()),
            TaskStream::Context(ref mut context) => {
                match context.poll() {
                    Ok(Async::Ready(Some(frame))) => {
                        match frame {
                            Frame::Message(msg) => {
                                error!("Unexpected message frame {:?}", msg);
                                Err(UnexpectedTaskFrame.into())
                            },
                            Frame::Payload(payload) => {
                                Ok(Async::Ready(payload))
                            },
                            Frame::Drain(fut) => {
                                self.drain.push(fut);
                                Ok(Async::NotReady)
                            }
                        }
                    },
                    Ok(Async::Ready(None)) => Ok(Async::Ready(None)),
                    Ok(Async::NotReady) => Ok(Async::NotReady),
                    Err(err) => Err(err),
                }
            },
        }
    }
}
<commit_msg>simlify code<commit_after>use std::{fmt, mem};
use std::rc::Rc;
use std::cell::RefCell;

use futures::{Async, Future, Poll};
use futures::task::{Task as FutureTask, current as current_task};

use route::{Reply, ReplyItem};
use body::{Body, BodyStream, Binary};
use context::Frame;
use h1writer::{Writer, WriterState};
use error::{Error, UnexpectedTaskFrame};
use pipeline::MiddlewaresResponse;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;

#[derive(PartialEq, Debug)]
enum TaskRunningState {
    Paused,
    Running,
    Done,
}

impl TaskRunningState {
    fn is_done(&self) -> bool {
        *self == TaskRunningState::Done
    }
    fn pause(&mut self) {
        if *self != TaskRunningState::Done {
            *self = TaskRunningState::Paused
        }
    }
    fn resume(&mut self) {
        if *self != TaskRunningState::Done {
            *self = TaskRunningState::Running
        }
    }
}

enum ResponseState {
    Reading,
    Ready(HttpResponse),
    Middlewares(MiddlewaresResponse),
    Prepared(Option<HttpResponse>),
}

enum IOState {
    Response,
    Payload(BodyStream),
    Context,
    Done,
}

enum TaskStream {
    None,
    Context(Box<IoContext>),
    Response(Box<Future<Item=HttpResponse, Error=Error>>),
}

impl IOState {
    fn is_done(&self) -> bool {
        match *self {
            IOState::Done => true,
            _ => false
        }
    }
}

impl ResponseState {
    fn is_reading(&self) -> bool {
        match *self {
            ResponseState::Reading => true,
            _ => false
        }
    }
}

impl fmt::Debug for ResponseState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResponseState::Reading => write!(f, "ResponseState::Reading"),
            ResponseState::Ready(_) => write!(f, "ResponseState::Ready"),
            ResponseState::Middlewares(_) => write!(f, "ResponseState::Middlewares"),
            ResponseState::Prepared(_) => write!(f, "ResponseState::Prepared"),
        }
    }
}

impl fmt::Debug for IOState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IOState::Response => write!(f, "IOState::Response"),
            IOState::Payload(_) => write!(f, "IOState::Payload"),
            IOState::Context => write!(f, "IOState::Context"),
            IOState::Done => write!(f, "IOState::Done"),
        }
    }
}

pub(crate) trait IoContext: 'static {
    fn disconnected(&mut self);
    fn poll(&mut self) -> Poll<Option<Frame>, Error>;
}

/// Future that resolves when all buffered data get sent
#[doc(hidden)]
#[derive(Debug)]
pub struct DrainFut {
    drained: bool,
    task: Option<FutureTask>,
}

impl Default for DrainFut {

    fn default() -> DrainFut {
        DrainFut {
            drained: false,
            task: None,
        }
    }
}

impl DrainFut {

    fn set(&mut self) {
        self.drained = true;
        if let Some(task) = self.task.take() {
            task.notify()
        }
    }
}

impl Future for DrainFut {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        if self.drained {
            Ok(Async::Ready(()))
        } else {
            self.task = Some(current_task());
            Ok(Async::NotReady)
        }
    }
}

pub(crate) struct Task {
    running: TaskRunningState,
    response: ResponseState,
    iostate: IOState,
    stream: TaskStream,
    drain: Vec<Rc<RefCell<DrainFut>>>,
    middlewares: Option<MiddlewaresResponse>,
}

impl Task {

    pub(crate) fn new(reply: Reply) -> Task {
        match reply.into() {
            ReplyItem::Message(msg) => {
                Task::from_response(msg)
            },
            ReplyItem::Actor(ctx) => {
                Task { running: TaskRunningState::Running,
                       response: ResponseState::Reading,
                       iostate: IOState::Response,
                       drain: Vec::new(),
                       stream: TaskStream::Context(ctx),
                       middlewares: None }
            }
            ReplyItem::Future(fut) => {
                Task { running: TaskRunningState::Running,
                       response: ResponseState::Reading,
                       iostate: IOState::Response,
                       drain: Vec::new(),
                       stream: TaskStream::Response(fut),
                       middlewares: None }
            }
        }
    }

    pub(crate) fn from_response<R: Into<HttpResponse>>(response: R) -> Task {
        Task { running: TaskRunningState::Running,
               response: ResponseState::Ready(response.into()),
               iostate: IOState::Response,
               drain: Vec::new(),
               stream: TaskStream::None,
               middlewares: None }
    }

    pub(crate) fn from_error<E: Into<Error>>(err: E) -> Task {
        Task::from_response(err.into())
    }

    pub(crate) fn response(&mut self) -> HttpResponse {
        match self.response {
            ResponseState::Prepared(ref mut state) => state.take().unwrap(),
            _ => panic!("Internal state is broken"),
        }
    }

    pub(crate) fn set_middlewares(&mut self, middlewares: MiddlewaresResponse) {
        self.middlewares = Some(middlewares)
    }

    pub(crate) fn disconnected(&mut self) {
        if let TaskStream::Context(ref mut ctx) = self.stream {
            ctx.disconnected();
        }
    }

    pub(crate) fn poll_io<T>(&mut self, io: &mut T, req: &mut HttpRequest) -> Poll<bool, Error>
        where T: Writer
    {
        trace!("POLL-IO frames resp: {:?}, io: {:?}, running: {:?}",
               self.response, self.iostate, self.running);

        if self.iostate.is_done() {  // response is completed
            return Ok(Async::Ready(self.running.is_done()));
        } else if self.drain.is_empty() && self.running != TaskRunningState::Paused {
            // if task is paused, write buffer is probably full

            loop {
                let result = match mem::replace(&mut self.iostate, IOState::Done) {
                    IOState::Response => {
                        match self.poll_response(req) {
                            Ok(Async::Ready(mut resp)) => {
                                let result = io.start(req, &mut resp)?;

                                match resp.replace_body(Body::Empty) {
                                    Body::Streaming(stream) | Body::Upgrade(stream) =>
                                        self.iostate = IOState::Payload(stream),
                                    Body::StreamingContext | Body::UpgradeContext =>
                                        self.iostate = IOState::Context,
                                    _ => (),
                                }
                                self.response = ResponseState::Prepared(Some(resp));
                                result
                            },
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Response;
                                return Ok(Async::NotReady)
                            }
                            Err(err) => {
                                let mut resp = err.into();
                                let result = io.start(req, &mut resp)?;

                                match resp.replace_body(Body::Empty) {
                                    Body::Streaming(stream) | Body::Upgrade(stream) =>
                                        self.iostate = IOState::Payload(stream),
                                    _ => (),
                                }
                                self.response = ResponseState::Prepared(Some(resp));
                                result
                            }
                        }
                    },
                    IOState::Payload(mut body) => {
                        // always poll stream
                        if self.running == TaskRunningState::Running {
                            match self.poll()? {
                                Async::Ready(_) =>
                                    self.running = TaskRunningState::Done,
                                Async::NotReady => (),
                            }
                        }

                        match body.poll() {
                            Ok(Async::Ready(None)) => {
                                self.iostate = IOState::Done;
                                io.write_eof()?;
                                break
                            },
                            Ok(Async::Ready(Some(chunk))) => {
                                self.iostate = IOState::Payload(body);
                                io.write(chunk.as_ref())?
                            }
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Payload(body);
                                break
                            },
                            Err(err) => return Err(err),
                        }
                    }
                    IOState::Context => {
                        match self.poll_context() {
                            Ok(Async::Ready(None)) => {
                                self.iostate = IOState::Done;
                                self.running = TaskRunningState::Done;
                                io.write_eof()?;
                                break
                            },
                            Ok(Async::Ready(Some(chunk))) => {
                                self.iostate = IOState::Context;
                                io.write(chunk.as_ref())?
                            }
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Context;
                                break
                            }
                            Err(err) => return Err(err),
                        }
                    }
                    IOState::Done => break,
                };

                match result {
                    WriterState::Pause => {
                        self.running.pause();
                        break
                    }
                    WriterState::Done =>
                        self.running.resume(),
                }
            }
        }

        // flush io
        match io.poll_complete() {
            Ok(Async::Ready(_)) => self.running.resume(),
            Ok(Async::NotReady) => return Ok(Async::NotReady),
            Err(err) => {
                debug!("Error sending data: {}", err);
                return Err(err.into())
            }
        }

        // drain futures
        if !self.drain.is_empty() {
            for fut in &mut self.drain {
                fut.borrow_mut().set()
            }
            self.drain.clear();
        }

        // response is completed
        if self.iostate.is_done() {
            if let ResponseState::Prepared(Some(ref mut resp)) = self.response {
                resp.set_response_size(io.written())
            }
            Ok(Async::Ready(self.running.is_done()))
        } else {
            Ok(Async::NotReady)
        }
    }

    pub(crate) fn poll_response(&mut self, req: &mut HttpRequest) -> Poll<HttpResponse, Error> {
        loop {
            let state = mem::replace(&mut self.response, ResponseState::Prepared(None));
            match state {
                ResponseState::Ready(response) => {
                    // run middlewares
                    if let Some(mut middlewares) = self.middlewares.take() {
                        match middlewares.response(req, response) {
                            Ok(Some(response)) =>
                                return Ok(Async::Ready(response)),
                            Ok(None) => {
                                // middlewares need to run some futures
                                self.response = ResponseState::Middlewares(middlewares);
                                continue
                            }
                            Err(err) => return Err(err),
                        }
                    } else {
                        return Ok(Async::Ready(response))
                    }
                }
                ResponseState::Middlewares(mut middlewares) => {
                    // process middlewares
                    match middlewares.poll(req) {
                        Ok(Async::NotReady) => {
                            self.response = ResponseState::Middlewares(middlewares);
                            return Ok(Async::NotReady)
                        },
                        Ok(Async::Ready(response)) =>
                            return Ok(Async::Ready(response)),
                        Err(err) =>
                            return Err(err),
                    }
                }
                _ => (),
            }
            self.response = state;

            match mem::replace(&mut self.stream, TaskStream::None) {
                TaskStream::None =>
                    return Ok(Async::NotReady),
                TaskStream::Context(mut context) => {
                    loop {
                        match context.poll() {
                            Ok(Async::Ready(Some(frame))) => {
                                match frame {
                                    Frame::Message(msg) => {
                                        if !self.response.is_reading() {
                                            error!("Unexpected message frame {:?}", msg);
                                            return Err(UnexpectedTaskFrame.into())
                                        }
                                        self.stream = TaskStream::Context(context);
                                        self.response = ResponseState::Ready(msg);
                                        break
                                    },
                                    Frame::Payload(_) | Frame::Drain(_) => (),
                                }
                            },
                            Ok(Async::Ready(None)) => {
                                error!("Unexpected eof");
                                return Err(UnexpectedTaskFrame.into())
                            },
                            Ok(Async::NotReady) => {
                                self.stream = TaskStream::Context(context);
                                return Ok(Async::NotReady)
                            },
                            Err(err) =>
                                return Err(err),
                        }
                    }
                },
                TaskStream::Response(mut fut) => {
                    match fut.poll() {
                        Ok(Async::NotReady) => {
                            self.stream = TaskStream::Response(fut);
                            return Ok(Async::NotReady);
                        },
                        Ok(Async::Ready(response)) => {
                            self.response = ResponseState::Ready(response);
                        }
                        Err(err) =>
                            return Err(err)
                    }
                }
            }
        }
    }

    pub(crate) fn poll(&mut self) -> Poll<(), Error> {
        match self.stream {
            TaskStream::None | TaskStream::Response(_) =>
                Ok(Async::Ready(())),
            TaskStream::Context(ref mut context) => {
                loop {
                    match context.poll() {
                        Ok(Async::Ready(Some(_))) => (),
                        Ok(Async::Ready(None)) =>
                            return Ok(Async::Ready(())),
                        Ok(Async::NotReady) =>
                            return Ok(Async::NotReady),
                        Err(err) =>
                            return Err(err),
                    }
                }
            },
        }
    }

    fn poll_context(&mut self) -> Poll<Option<Binary>, Error> {
        match self.stream {
            TaskStream::None | TaskStream::Response(_) =>
                Err(UnexpectedTaskFrame.into()),
            TaskStream::Context(ref mut context) => {
                match context.poll() {
                    Ok(Async::Ready(Some(frame))) => {
                        match frame {
                            Frame::Message(msg) => {
                                error!("Unexpected message frame {:?}", msg);
                                Err(UnexpectedTaskFrame.into())
                            },
                            Frame::Payload(payload) => {
                                Ok(Async::Ready(payload))
                            },
                            Frame::Drain(fut) => {
                                self.drain.push(fut);
                                Ok(Async::NotReady)
                            }
                        }
                    },
                    Ok(Async::Ready(None)) => Ok(Async::Ready(None)),
                    Ok(Async::NotReady) => Ok(Async::NotReady),
                    Err(err) => Err(err),
                }
            },
        }
    }
}
<|endoftext|>