<commit_before>//!`Router` takes care of routing incoming requests to handlers.
//!
//!```rust
//!use rustful::router::Router;
//!# use std::hashmap::HashMap;
//!
//!# fn about_us(_: ~HashMap<~str, &str>) -> ~str {~""}
//!# fn show_user(_: ~HashMap<~str, &str>) -> ~str {~""}
//!# fn show_product(_: ~HashMap<~str, &str>) -> ~str {~""}
//!let routes = [
//!	("about", about_us),
//!	("user/:user", show_user),
//!	("product/:name", show_product)
//!];
//!
//!let router = Router::from_vec(routes);
//!```
use std::hashmap::HashMap;

///A handler function for routing.
pub type HandlerFn = fn(~HashMap<~str, &str>) -> ~str;

///Takes care of routing requests to handlers.
///
///Paths can be static (`"path/to/handler"`) or variable (`"users/:group/:user"`).
///Variables (starting with `:`) will match whatever word the path contains at
///that point and it will be sent as a value to the handler function.
pub struct Router {
	priv handler: Option<HandlerFn>,
	priv static_routes: HashMap<~str, ~Router>,
	priv variable_route: Option<~Router>,
	priv variable_names: ~[~str],
	priv wildcard_route: Option<~Router>
}

impl Router {
	///Creates an empty `Router`.
	pub fn new() -> Router {
		Router {
			handler: None,
			static_routes: HashMap::new(),
			variable_route: None,
			variable_names: ~[],
			wildcard_route: None
		}
	}

	///Generates a `Router` tree from a set of handlers and paths.
	pub fn from_vec(routes: &[(&str, HandlerFn)]) -> Router {
		let mut root = Router::new();

		for &(path, handler) in routes.iter() {
			root.insert_handler(path, handler);
		}

		root
	}

	///Inserts a handler into the `Router` at a given path.
	pub fn insert_handler(&mut self, path: &str, handler: HandlerFn) {
		self.insert_handler_vec(path.split('/').collect::<~[&str]>(), ~[], handler);
	}

	//Same as `insert_handler`, but internal
	fn insert_handler_vec(&mut self, path: &[&str], variable_names: ~[~str], handler: HandlerFn) {
		let mut var_names = variable_names;

		match path {
			[piece] => {
				let next = self.find_or_insert_router(piece);
				if piece.len() > 0 && piece.char_at(0) == ':' {
					var_names.push(piece.slice(1, piece.len()).to_owned());
				}
				next.variable_names = var_names;
				next.handler = Some(handler);
			},
			[piece, ..rest] => {
				let next = self.find_or_insert_router(piece);
				if piece.len() > 0 && piece.char_at(0) == ':' {
					var_names.push(piece.slice(1, piece.len()).to_owned());
				}
				next.insert_handler_vec(rest, var_names, handler);
			},
			[] => {
				self.variable_names = var_names;
				self.handler = Some(handler);
			}
		}
	}

	//Tries to find a router matching the key or inserts a new one if none exists
	fn find_or_insert_router<'a>(&'a mut self, key: &str) -> &'a mut ~Router {
		if key.len() > 0 && key.char_at(0) == ':' {
			if self.variable_route.is_none() {
				self.variable_route = Some(~Router::new());
			}
			self.variable_route.as_mut::<'a>().unwrap()
		} else {
			self.static_routes.find_or_insert_with::<'a>(key.to_owned(), |_| {
				~Router::new()
			})
		}
	}

	///Executes a matching handler function and returns the result.
	pub fn route(&self, path: &str) -> Option<~str> {
		self.find(path.split('/').collect::<~[&str]>(), &[])
	}

	//Tries to find a matching handler and run it
	fn find(&self, path: &[&str], variables: &[&str]) -> Option<~str> {
		match path {
			[piece] => {
				self.match_static(piece, variables, |next, vars| { next.exec(vars) })
			},
			[piece, ..rest] => {
				self.match_static(piece, variables, |next, vars| { next.find(rest, vars) })
			},
			[] => {
				self.exec(variables)
			}
		}
	}

	//Tries to run a handler with a given set of variable values
	fn exec(&self, variables: &[&str]) -> Option<~str> {
		match self.handler {
			Some(handler) => {
				let mut variable_map = ~HashMap::new();
				for (key, &value) in self.variable_names.iter().zip(variables.iter()) {
					variable_map.insert(key.to_owned(), value);
				}
				Some(handler(variable_map))
			},
			None => None
		}
	}

	//Checks for a static route. Runs `action` if found, runs `match_variable` otherwhise
	fn match_static(&self, key: &str, variables: &[&str], action: |&~Router, &[&str]| -> Option<~str>) -> Option<~str> {
		match self.static_routes.find(&key.to_owned()) {
			Some(next) => {
				match action(next, variables) {
					None => self.match_variable(key, variables, action),
					result => result
				}
			},
			None => {
				self.match_variable(key, variables, action)
			}
		}
	}

	//Checks for a variable route. Runs `action` if found, runs `match_wildcard` otherwhise
	fn match_variable(&self, key: &str, variables: &[&str], action: |&~Router, &[&str]| -> Option<~str>) -> Option<~str> {
		match self.variable_route {
			Some(ref next) => {
				let mut new_variables = variables.to_owned();
				new_variables.push(key.clone());
				action(next, new_variables)
			},
			None => None //TODO: Wildcard
		}
	}
}

#[cfg(test)]
mod test {
	use extra::test::BenchHarness;
	use std::hashmap::HashMap;
	use super::Router;

	fn test_1(_: ~HashMap<~str, &str>) -> ~str {
		~"test 1"
	}

	fn test_2(_: ~HashMap<~str, &str>) -> ~str {
		~"test 2"
	}

	fn test_3(_: ~HashMap<~str, &str>) -> ~str {
		~"test 3"
	}

	fn test_var(variables: ~HashMap<~str, &str>) -> ~str {
		let keys = ~[~"a", ~"b", ~"c"];
		keys.iter().filter_map(|key| {
			match variables.find(key) {
				Some(value) => Some(value.to_owned()),
				None => None
			}
		}).collect::<~[~str]>().connect(", ")
	}

	#[test]
	fn one_static_route() {
		let routes = [("path/to/test1", test_1)];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to"), None);
		assert_eq!(router.route("path/to/test1/nothing"), None);
	}

	#[test]
	fn several_static_routes() {
		let routes = [
			("path/to/test1", test_1),
			("path/to/test/no2", test_2),
			("path/to/test1/no/test3", test_3)
		];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to/test/no2"), Some(~"test 2"));
		assert_eq!(router.route("path/to/test1/no/test3"), Some(~"test 3"));
		assert_eq!(router.route("path/to/test1/no"), None);
	}

	#[test]
	fn one_variable_route() {
		let routes = [("path/:a/test1", test_var)];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"to"));
		assert_eq!(router.route("path/to"), None);
		assert_eq!(router.route("path/to/test1/nothing"), None);
	}

	#[test]
	fn several_variable_routes() {
		let routes = [
			("path/to/test1", test_var),
			("path/:a/test/no2", test_var),
			("path/to/:b/:c/:a", test_var)
		];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~""));
		assert_eq!(router.route("path/to/test/no2"), Some(~"to"));
		assert_eq!(router.route("path/to/test1/no/test3"), Some(~"test3, test1, no"));
		assert_eq!(router.route("path/to/test1/no"), None);
	}

	#[bench]
	fn search_speed(b: &mut BenchHarness) {
		let routes = [
			("path/to/test1", test_1),
			("path/to/test/no2", test_1),
			("path/to/test1/no/test3", test_1),
			("path/to/other/test1", test_1),
			("path/to/test/no2/again", test_1),
			("other/path/to/test1/no/test3", test_1),
			("path/to/test1", test_1),
			("path/:a/test/no2", test_1),
			("path/to/:b/:c/:a", test_1)
		];

		let paths = [
			"path/to/test1",
			"path/to/test/no2",
			"path/to/test1/no/test3",
			"path/to/other/test1",
			"path/to/test/no2/again",
			"other/path/to/test1/no/test3",
			"path/a/test1",
			"path/a/test/no2",
			"path/to/b/c/a",
			"path/to/test1/no",
			"path/to",
			"path/to/test1/nothing/at/all"
		];

		let router = Router::from_vec(routes);
		let mut counter = 0;

		b.iter(|| {
			router.route(paths[counter]);
			counter = (counter + 1) % paths.len()
		});
	}
}<commit_msg>Implemented wildcards in router paths<commit_after>//!`Router` takes care of routing incoming requests to handlers.
//!
//!```rust
//!# use rustful::router::Router;
//!# use std::hashmap::HashMap;
//!# fn about_us(_: ~HashMap<~str, &str>) -> ~str {~""}
//!# fn show_user(_: ~HashMap<~str, &str>) -> ~str {~""}
//!# fn show_product(_: ~HashMap<~str, &str>) -> ~str {~""}
//!# fn show_welcome(_: ~HashMap<~str, &str>) -> ~str {~""}
//!let routes = [
//!	("about", about_us),
//!	("user/:user", show_user),
//!	("product/:name", show_product),
//!	("*", show_welcome)
//!];
//!
//!let router = Router::from_vec(routes);
//!```
use std::hashmap::HashMap;

///A handler function for routing.
pub type HandlerFn = fn(~HashMap<~str, &str>) -> ~str;

///Takes care of routing requests to handlers.
///
///Paths can be static (`"path/to/handler"`) or variable (`"users/:group/:user"`)
///and contain wildcards (`"path/*/handler/*"`).
///
///Variables (starting with `:`) will match whatever word the request path contains at
///that point and it will be sent as a value to the handler function.
///
///Wildcards (a single `*`) will consume the segments until the rest of the
///path gives a match.
///
///```
///pattern = "a/*/b"
///"a/c/b" -> match
///"a/c/d/b" -> match
///"a/b" -> no match
///"a/c/b/d" -> no match
///```
///
///```
///pattern = "a/b/*"
///"a/b/c" -> match
///"a/b/c/d" -> match
///"a/b" -> no match
///```
pub struct Router {
	priv handler: Option<HandlerFn>,
	priv static_routes: HashMap<~str, ~Router>,
	priv variable_route: Option<~Router>,
	priv variable_names: ~[~str],
	priv wildcard_route: Option<~Router>
}

impl Router {
	///Creates an empty `Router`.
	pub fn new() -> Router {
		Router {
			handler: None,
			static_routes: HashMap::new(),
			variable_route: None,
			variable_names: ~[],
			wildcard_route: None
		}
	}

	///Generates a `Router` tree from a set of handlers and paths.
	pub fn from_vec(routes: &[(&str, HandlerFn)]) -> Router {
		let mut root = Router::new();

		for &(path, handler) in routes.iter() {
			root.insert_handler(path, handler);
		}

		root
	}

	///Inserts a handler into the `Router` at a given path.
	pub fn insert_handler(&mut self, path: &str, handler: HandlerFn) {
		self.insert_handler_vec(path.split('/').collect::<~[&str]>(), ~[], handler);
	}

	//Same as `insert_handler`, but internal
	fn insert_handler_vec(&mut self, path: &[&str], variable_names: ~[~str], handler: HandlerFn) {
		let mut var_names = variable_names;

		match path {
			[piece] => {
				let next = self.find_or_insert_router(piece);
				if piece.len() > 0 && piece.char_at(0) == ':' {
					var_names.push(piece.slice(1, piece.len()).to_owned());
				}
				next.variable_names = var_names;
				next.handler = Some(handler);
			},
			[piece, ..rest] => {
				let next = self.find_or_insert_router(piece);
				if piece.len() > 0 && piece.char_at(0) == ':' {
					var_names.push(piece.slice(1, piece.len()).to_owned());
				}
				next.insert_handler_vec(rest, var_names, handler);
			},
			[] => {
				self.variable_names = var_names;
				self.handler = Some(handler);
			}
		}
	}

	//Tries to find a router matching the key or inserts a new one if none exists
	fn find_or_insert_router<'a>(&'a mut self, key: &str) -> &'a mut ~Router {
		if key == "*" {
			if self.wildcard_route.is_none() {
				self.wildcard_route = Some(~Router::new());
			}
			self.wildcard_route.as_mut::<'a>().unwrap()
		} else if key.len() > 0 && key.char_at(0) == ':' {
			if self.variable_route.is_none() {
				self.variable_route = Some(~Router::new());
			}
			self.variable_route.as_mut::<'a>().unwrap()
		} else {
			self.static_routes.find_or_insert_with::<'a>(key.to_owned(), |_| {
				~Router::new()
			})
		}
	}

	///Executes a matching handler function and returns the result.
	pub fn route(&self, path: &str) -> Option<~str> {
		self.find(path.split('/').collect::<~[&str]>(), &[])
	}

	//Tries to find a matching handler and run it
	fn find(&self, path: &[&str], variables: &[&str]) -> Option<~str> {
		match path {
			[piece] => {
				self.match_static(piece, &[], variables, |next, _, vars| { next.exec(vars) })
			},
			[piece, ..rest] => {
				self.match_static(piece, rest, variables, |next, path, vars| { next.find(path, vars) })
			},
			[] => {
				self.exec(variables)
			}
		}
	}

	//Tries to run a handler with a given set of variable values
	fn exec(&self, variables: &[&str]) -> Option<~str> {
		match self.handler {
			Some(handler) => {
				let mut variable_map = ~HashMap::new();
				for (key, &value) in self.variable_names.iter().zip(variables.iter()) {
					variable_map.insert(key.to_owned(), value);
				}
				Some(handler(variable_map))
			},
			None => None
		}
	}

	//Checks for a static route. Runs `action` if found, runs `match_variable` otherwhise
	fn match_static(&self, key: &str, rest: &[&str], variables: &[&str], action: |&~Router, &[&str], &[&str]| -> Option<~str>) -> Option<~str> {
		match self.static_routes.find(&key.to_owned()) {
			Some(next) => {
				match action(next, rest, variables) {
					None => self.match_variable(key, rest, variables, action),
					result => result
				}
			},
			None => self.match_variable(key, rest, variables, action)
		}
	}

	//Checks for a variable route. Runs `action` if found, runs `match_wildcard` otherwhise
	fn match_variable(&self, key: &str, rest: &[&str], variables: &[&str], action: |&~Router, &[&str], &[&str]| -> Option<~str>) -> Option<~str> {
		match self.variable_route {
			Some(ref next) => {
				let mut new_variables = variables.to_owned();
				new_variables.push(key.clone());

				match action(next, rest, new_variables) {
					None => self.match_wildcard(rest, variables, action),
					result => result
				}
			},
			None => self.match_wildcard(rest, variables, action)
		}
	}

	//Checks for a wildcard route. Runs `action` if found, returns `None` otherwhise
	fn match_wildcard(&self, rest: &[&str], variables: &[&str], action: |&~Router, &[&str], &[&str]| -> Option<~str>) -> Option<~str> {
		match self.wildcard_route {
			Some(ref next) => {
				let mut path = rest;
				while path.len() > 0 {
					match action(next, path, variables) {
						None => path = path.slice(1, path.len()),
						result => return result
					}
				}

				action(next, path, variables)
			},
			None => None
		}
	}
}

#[cfg(test)]
mod test {
	use extra::test::BenchHarness;
	use std::hashmap::HashMap;
	use super::Router;

	fn test_1(_: ~HashMap<~str, &str>) -> ~str {
		~"test 1"
	}

	fn test_2(_: ~HashMap<~str, &str>) -> ~str {
		~"test 2"
	}

	fn test_3(_: ~HashMap<~str, &str>) -> ~str {
		~"test 3"
	}

	fn test_var(variables: ~HashMap<~str, &str>) -> ~str {
		let keys = ~[~"a", ~"b", ~"c"];
		keys.iter().filter_map(|key| {
			match variables.find(key) {
				Some(value) => Some(value.to_owned()),
				None => None
			}
		}).collect::<~[~str]>().connect(", ")
	}

	#[test]
	fn one_static_route() {
		let routes = [("path/to/test1", test_1)];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to"), None);
		assert_eq!(router.route("path/to/test1/nothing"), None);
	}

	#[test]
	fn several_static_routes() {
		let routes = [
			("path/to/test1", test_1),
			("path/to/test/no2", test_2),
			("path/to/test1/no/test3", test_3)
		];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to/test/no2"), Some(~"test 2"));
		assert_eq!(router.route("path/to/test1/no/test3"), Some(~"test 3"));
		assert_eq!(router.route("path/to/test1/no"), None);
	}

	#[test]
	fn one_variable_route() {
		let routes = [("path/:a/test1", test_var)];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"to"));
		assert_eq!(router.route("path/to"), None);
		assert_eq!(router.route("path/to/test1/nothing"), None);
	}

	#[test]
	fn several_variable_routes() {
		let routes = [
			("path/to/test1", test_var),
			("path/:a/test/no2", test_var),
			("path/to/:b/:c/:a", test_var)
		];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~""));
		assert_eq!(router.route("path/to/test/no2"), Some(~"to"));
		assert_eq!(router.route("path/to/test1/no/test3"), Some(~"test3, test1, no"));
		assert_eq!(router.route("path/to/test1/no"), None);
	}

	#[test]
	fn one_wildcard_end_route() {
		let routes = [("path/to/*", test_1)];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to/same/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to/the/same/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to"), None);
		assert_eq!(router.route("path"), None);
	}

	#[test]
	fn one_wildcard_middle_route() {
		let routes = [("path/*/test1", test_1)];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to/same/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to/the/same/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to"), None);
		assert_eq!(router.route("path"), None);
	}

	#[test]
	fn one_universal_wildcard_route() {
		let routes = [("*", test_1)];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to/same/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to/the/same/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/to"), Some(~"test 1"));
		assert_eq!(router.route("path"), Some(~"test 1"));
		assert_eq!(router.route(""), Some(~"test 1"));
	}

	#[test]
	fn several_wildcards_routes() {
		let routes = [
			("path/to/*", test_1),
			("path/*/test/no2", test_2),
			("path/to/*/*/*", test_3)
		];

		let router = Router::from_vec(routes);

		assert_eq!(router.route("path/to/test1"), Some(~"test 1"));
		assert_eq!(router.route("path/for/test/no2"), Some(~"test 2"));
		assert_eq!(router.route("path/to/test1/no/test3"), Some(~"test 3"));
		assert_eq!(router.route("path/to/test1/no/test3/again"), Some(~"test 3"));
		assert_eq!(router.route("path/to"), None);
	}

	#[bench]
	fn search_speed(b: &mut BenchHarness) {
		let routes = [
			("path/to/test1", test_1),
			("path/to/test/no2", test_1),
			("path/to/test1/no/test3", test_1),
			("path/to/other/test1", test_1),
			("path/to/test/no2/again", test_1),
			("other/path/to/test1/no/test3", test_1),
			("path/to/test1", test_1),
			("path/:a/test/no2", test_1),
			("path/to/:b/:c/:a", test_1),
			("path/to/*", test_1),
			("path/to/*/other", test_1)
		];

		let paths = [
			"path/to/test1",
			"path/to/test/no2",
			"path/to/test1/no/test3",
			"path/to/other/test1",
			"path/to/test/no2/again",
			"other/path/to/test1/no/test3",
			"path/a/test1",
			"path/a/test/no2",
			"path/to/b/c/a",
			"path/to/test1/no",
			"path/to",
			"path/to/test1/nothing/at/all"
		];

		let router = Router::from_vec(routes);
		let mut counter = 0;

		b.iter(|| {
			router.route(paths[counter]);
			counter = (counter + 1) % paths.len()
		});
	}

	#[bench]
	fn wildcard_speed(b: &mut BenchHarness) {
		let routes = [
			("*/to/*/*/a", test_1)
		];

		let paths = [
			"path/to/a",
			"path/to/test/a",
			"path/to/test1/no/a",
			"path/to/other/a",
			"path/to/test/no2/a",
			"other/path/to/test1/no/a",
			"path/a/a",
			"path/a/test/a",
			"path/to/b/c/a",
			"path/to/test1/a",
			"path/a",
			"path/to/test1/nothing/at/all/and/all/and/all/and/a"
		];

		let router = Router::from_vec(routes);
		let mut counter = 0;

		b.iter(|| {
			router.route(paths[counter]);
			counter = (counter + 1) % paths.len()
		});
	}
}<|endoftext|>


<commit_before>// Copyright 2015 Jerome Rasky <jerome@rasky.co>
//
// 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 expressed or implied. See the
// License for the specific language concerning governing permissions and
// limitations under the License.
use std::collections::{HashMap, BinaryHeap};
use std::cmp::Ordering;
use std::iter::FromIterator;
use std::sync::Arc;

use constants::*;

#[derive(PartialEq, Eq)]
enum CharClass {
    Whitespace,
    Numeric,
    Alphabetic,
    First,
    Other
}

#[derive(Debug)]
pub struct LineInfo {
    line: Arc<String>,
    char_map: HashMap<char, Vec<usize>>,
    heat_map: Vec<isize>,
    factor: isize
}

#[derive(Debug)]
pub struct LineMatch {
    score: isize,
    factor: isize,
    line: Arc<String>
}

#[derive(Debug)]
pub struct SearchBase {
    lines: Vec<LineInfo>
}

impl Ord for LineMatch {
    fn cmp(&self, other: &LineMatch) -> Ordering {
        match self.score.cmp(&other.score) {
            Ordering::Equal => self.factor.cmp(&other.factor),
            order => order
        }
    }
}

impl PartialOrd for LineMatch {
    fn partial_cmp(&self, other: &LineMatch) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for LineMatch {
    fn eq(&self, other: &LineMatch) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}

impl Eq for LineMatch {}

impl FromIterator<LineInfo> for SearchBase {
    fn from_iter<T: IntoIterator<Item=LineInfo>>(iterator: T) -> SearchBase {
        SearchBase {
            lines: Vec::from_iter(iterator)
        }
    }
}

impl SearchBase {
    pub fn query<T: AsRef<str>>(&self, query: T) -> Vec<Arc<String>> {
        if query.as_ref().is_empty() {
            // an empty query means don't match anything
            return vec![];
        }

        let mut matches: BinaryHeap<LineMatch> = BinaryHeap::with_capacity(MATCH_NUMBER);

        for item in self.lines.iter() {
            let score = match item.score(&query) {
                None => {
                    // non-matching line
                    continue;
                },
                Some(score) => {
                    score
                }
            };

            let match_item = LineMatch {
                score: -score,
                factor: -item.factor,
                line: item.line.clone()
            };

            if matches.len() < MATCH_NUMBER {
                matches.push(match_item);
            } else if &match_item < matches.peek().unwrap() {
                matches.push_pop(match_item);
            }
        }

        matches.into_sorted_vec().into_iter().map(|x| {x.line}).collect()
    }
}

impl LineInfo {
    pub fn new<T: Into<String>>(item: T, factor: isize) -> LineInfo {
        let mut map: HashMap<char, Vec<usize>> = HashMap::new();
        let mut heat = vec![];
        let line = Arc::new(item.into());

        let mut ws_score = 0isize;
        let mut cs_score = 0isize;
        let mut cur_class = CharClass::First;
        let mut cs_change = false;

        for (idx, c) in line.chars().enumerate() {
            if idx > MAX_LEN {
                break;
            }

            if !c.is_whitespace() {
                if cur_class == CharClass::First {
                    cs_score += FIRST_FACTOR;
                }
            }

            if c.is_whitespace() {
                cur_class = CharClass::Whitespace;
                ws_score = WHITESPACE_FACTOR;
            } else if c.is_numeric() {
                if cur_class != CharClass::Numeric {
                    cur_class = CharClass::Numeric;
                    if !cs_change {
                        cs_score += CLASS_FACTOR;
                        cs_change = true;
                    }
                } else {
                    cs_change = false;
                }
            } else if c.is_alphabetic() {
                if cur_class != CharClass::Alphabetic {
                    cur_class = CharClass::Alphabetic;
                    if !cs_change {
                        cs_score += CLASS_FACTOR;
                        cs_change = true;
                    }
                } else {
                    cs_change =  false;
                }
            } else {
                if cur_class != CharClass::Other {
                    cur_class = CharClass::Other;
                    if !cs_change {
                        cs_score += CLASS_FACTOR;
                        cs_change = true;
                    }
                } else {
                    cs_change = false;
                }
            }

            if cur_class != CharClass::Whitespace {
                map.entry(c).or_insert(Vec::default()).push(idx);
                if c.is_uppercase() {
                    for lc in c.to_lowercase() {
                        map.entry(lc).or_insert(Vec::default()).push(idx);
                    }
                }
            }

            heat.push(ws_score + cs_score);

            ws_score /= WHITESPACE_REDUCE;
            if !cs_change {
                cs_score /= CLASS_REDUCE;
            }
        }

        LineInfo {
            line: line,
            char_map: map,
            heat_map: heat,
            factor: factor
        }
    }

    fn get_positions(&self, item: char, after: Option<usize>) -> Option<Vec<usize>> {
        match after {
            None => self.char_map.get(&item).map(|list| {list.to_vec()}),
            Some(after) => {
                match self.char_map.get(&item) {
                    None => None,
                    Some(list) => match list.binary_search(&after) {
                        Ok(idx) if idx + 1 < list.len() => Some(list[idx + 1..].to_vec()),
                        Err(idx) if idx < list.len() => Some(list[idx..].to_vec()),
                        _ => None
                    }
                }
            }
        }
    }

    fn position_list<T: AsRef<str>>(&self, item: T) -> Option<Vec<Vec<usize>>> {
        let mut positions = vec![];
        let mut last = None;

        for c in item.as_ref().chars() {
            if c.is_whitespace() {
                // don't match whitespace
                continue;
            }

            match self.get_positions(c, last) {
                None => return None,
                Some(list) => {
                    last = match list.get(0) {
                        None => return None,
                        Some(idx) => Some(*idx)
                    };
                    positions.push(list);
                }
            }
        }

        Some(positions)
    }

    fn permute_positions(mut list: Vec<Vec<usize>>) -> Option<Vec<Vec<usize>>> {
        let mut result = vec![];

        debug!("Position list: {:?}", list);

        match list.pop() {
            None => return None,
            Some(item) => {
                for idx in item {
                    result.push(vec![idx]);
                }
            }
        }

        loop {
            match list.pop() {
                None => break,
                Some(base_list) => {
                    for list in result.iter_mut() {
                        let compare = *list.last().unwrap();
                        for item in base_list.iter().rev() {
                            if *item < compare {
                                list.push(*item);
                            }
                        }
                    }
                }
            }
        }

        if result.is_empty() {
            None
        } else {
            Some(result)
        }
    }

    fn score_position(&self, position: Vec<usize>) -> isize {
        let avg_dist: usize;

        debug!("Scoring position: {:?}", position);

        if position.len() < 2 {
            avg_dist = 0;
        } else {
            avg_dist = position.windows(2).map(|pair| {
                trace!("Window: {:?}", pair);
                pair[0] - pair[1]
            }).sum::<usize>() / position.len();
        }

        let heat_sum: isize = position.iter().map(|idx| {self.heat_map[*idx]}).sum();

        avg_dist as isize * DIST_WEIGHT + heat_sum * HEAT_WEIGHT + self.factor / FACTOR_REDUCE
    }

    fn best_position(&self, positions: Vec<Vec<usize>>) -> Option<isize> {
        positions.into_iter().map(|position| {self.score_position(position)}).max()
    }

    fn score<T: AsRef<str>>(&self, query: T) -> Option<isize> {
        self.position_list(query)
            .and_then(|positions| {LineInfo::permute_positions(positions)})
            .and_then(|positions| {self.best_position(positions)})
    }
}
<commit_msg>Use function instead of match statement<commit_after>// Copyright 2015 Jerome Rasky <jerome@rasky.co>
//
// 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 expressed or implied. See the
// License for the specific language concerning governing permissions and
// limitations under the License.
use std::collections::{HashMap, BinaryHeap};
use std::cmp::Ordering;
use std::iter::FromIterator;
use std::sync::Arc;

use constants::*;

#[derive(PartialEq, Eq)]
enum CharClass {
    Whitespace,
    Numeric,
    Alphabetic,
    First,
    Other
}

#[derive(Debug)]
pub struct LineInfo {
    line: Arc<String>,
    char_map: HashMap<char, Vec<usize>>,
    heat_map: Vec<isize>,
    factor: isize
}

#[derive(Debug)]
pub struct LineMatch {
    score: isize,
    factor: isize,
    line: Arc<String>
}

#[derive(Debug)]
pub struct SearchBase {
    lines: Vec<LineInfo>
}

impl Ord for LineMatch {
    fn cmp(&self, other: &LineMatch) -> Ordering {
        match self.score.cmp(&other.score) {
            Ordering::Equal => self.factor.cmp(&other.factor),
            order => order
        }
    }
}

impl PartialOrd for LineMatch {
    fn partial_cmp(&self, other: &LineMatch) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for LineMatch {
    fn eq(&self, other: &LineMatch) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}

impl Eq for LineMatch {}

impl FromIterator<LineInfo> for SearchBase {
    fn from_iter<T: IntoIterator<Item=LineInfo>>(iterator: T) -> SearchBase {
        SearchBase {
            lines: Vec::from_iter(iterator)
        }
    }
}

impl SearchBase {
    pub fn query<T: AsRef<str>>(&self, query: T) -> Vec<Arc<String>> {
        if query.as_ref().is_empty() {
            // an empty query means don't match anything
            return vec![];
        }

        let mut matches: BinaryHeap<LineMatch> = BinaryHeap::with_capacity(MATCH_NUMBER);

        for item in self.lines.iter() {
            let score = match item.score(&query) {
                None => {
                    // non-matching line
                    continue;
                },
                Some(score) => {
                    score
                }
            };

            let match_item = LineMatch {
                score: -score,
                factor: -item.factor,
                line: item.line.clone()
            };

            if matches.len() < MATCH_NUMBER {
                matches.push(match_item);
            } else if &match_item < matches.peek().unwrap() {
                matches.push_pop(match_item);
            }
        }

        matches.into_sorted_vec().into_iter().map(|x| {x.line}).collect()
    }
}

impl LineInfo {
    pub fn new<T: Into<String>>(item: T, factor: isize) -> LineInfo {
        let mut map: HashMap<char, Vec<usize>> = HashMap::new();
        let mut heat = vec![];
        let line = Arc::new(item.into());

        let mut ws_score = 0isize;
        let mut cs_score = 0isize;
        let mut cur_class = CharClass::First;
        let mut cs_change = false;

        for (idx, c) in line.chars().enumerate() {
            if idx > MAX_LEN {
                break;
            }

            if !c.is_whitespace() {
                if cur_class == CharClass::First {
                    cs_score += FIRST_FACTOR;
                }
            }

            if c.is_whitespace() {
                cur_class = CharClass::Whitespace;
                ws_score = WHITESPACE_FACTOR;
            } else if c.is_numeric() {
                if cur_class != CharClass::Numeric {
                    cur_class = CharClass::Numeric;
                    if !cs_change {
                        cs_score += CLASS_FACTOR;
                        cs_change = true;
                    }
                } else {
                    cs_change = false;
                }
            } else if c.is_alphabetic() {
                if cur_class != CharClass::Alphabetic {
                    cur_class = CharClass::Alphabetic;
                    if !cs_change {
                        cs_score += CLASS_FACTOR;
                        cs_change = true;
                    }
                } else {
                    cs_change =  false;
                }
            } else {
                if cur_class != CharClass::Other {
                    cur_class = CharClass::Other;
                    if !cs_change {
                        cs_score += CLASS_FACTOR;
                        cs_change = true;
                    }
                } else {
                    cs_change = false;
                }
            }

            if cur_class != CharClass::Whitespace {
                map.entry(c).or_insert(Vec::default()).push(idx);
                if c.is_uppercase() {
                    for lc in c.to_lowercase() {
                        map.entry(lc).or_insert(Vec::default()).push(idx);
                    }
                }
            }

            heat.push(ws_score + cs_score);

            ws_score /= WHITESPACE_REDUCE;
            if !cs_change {
                cs_score /= CLASS_REDUCE;
            }
        }

        LineInfo {
            line: line,
            char_map: map,
            heat_map: heat,
            factor: factor
        }
    }

    fn get_positions(&self, item: char, after: Option<usize>) -> Option<Vec<usize>> {
        match after {
            None => self.char_map.get(&item).map(|list| {list.to_vec()}),
            Some(after) => {
                self.char_map.get(&item).and_then(|list| {
                    match list.binary_search(&after) {
                        Ok(idx) if idx + 1 < list.len() => Some(list[idx + 1..].to_vec()),
                        Err(idx) if idx < list.len() => Some(list[idx..].to_vec()),
                        _ => None
                    }
                })
            }
        }
    }

    fn position_list<T: AsRef<str>>(&self, item: T) -> Option<Vec<Vec<usize>>> {
        let mut positions = vec![];
        let mut last = None;

        for c in item.as_ref().chars() {
            if c.is_whitespace() {
                // don't match whitespace
                continue;
            }

            match self.get_positions(c, last) {
                None => return None,
                Some(list) => {
                    last = match list.get(0) {
                        None => return None,
                        Some(idx) => Some(*idx)
                    };
                    positions.push(list);
                }
            }
        }

        Some(positions)
    }

    fn permute_positions(mut list: Vec<Vec<usize>>) -> Option<Vec<Vec<usize>>> {
        let mut result = vec![];

        debug!("Position list: {:?}", list);

        match list.pop() {
            None => return None,
            Some(item) => {
                for idx in item {
                    result.push(vec![idx]);
                }
            }
        }

        loop {
            match list.pop() {
                None => break,
                Some(base_list) => {
                    for list in result.iter_mut() {
                        let compare = *list.last().unwrap();
                        for item in base_list.iter().rev() {
                            if *item < compare {
                                list.push(*item);
                            }
                        }
                    }
                }
            }
        }

        if result.is_empty() {
            None
        } else {
            Some(result)
        }
    }

    fn score_position(&self, position: Vec<usize>) -> isize {
        let avg_dist: usize;

        debug!("Scoring position: {:?}", position);

        if position.len() < 2 {
            avg_dist = 0;
        } else {
            avg_dist = position.windows(2).map(|pair| {
                trace!("Window: {:?}", pair);
                pair[0] - pair[1]
            }).sum::<usize>() / position.len();
        }

        let heat_sum: isize = position.iter().map(|idx| {self.heat_map[*idx]}).sum();

        avg_dist as isize * DIST_WEIGHT + heat_sum * HEAT_WEIGHT + self.factor / FACTOR_REDUCE
    }

    fn best_position(&self, positions: Vec<Vec<usize>>) -> Option<isize> {
        positions.into_iter().map(|position| {self.score_position(position)}).max()
    }

    fn score<T: AsRef<str>>(&self, query: T) -> Option<isize> {
        self.position_list(query)
            .and_then(|positions| {LineInfo::permute_positions(positions)})
            .and_then(|positions| {self.best_position(positions)})
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::sync::mpsc;
use std::fmt;
use crate::types::{MaybeOwned, Storage, SharedSignal, SharedImpl};
use crate::stream::Stream;

use self::SigValue::*;

/// Represents a discrete value that changes over time.
///
/// Signals are usually constructed by stream operations and can be read using the `sample` or
/// `sample_with` methods. They update lazily when someone reads them.
#[derive(Clone, Debug)]
pub struct Signal<T>(SigValue<T>);

/// The content source of a signal.
#[derive(Clone)]
enum SigValue<T>
{
    /// A signal with constant value.
    Constant(T),
    /// A signal that generates it's values from a function.
    ///
    /// This is produced by `Signal::from_fn`
    Dynamic(Rc<dyn Fn() -> T>),
    /// A signal that contains shared data.
    ///
    /// This is mainly produced by stream methods or mapping other signals.
    Shared(Rc<dyn SharedSignal<T>>),
    /// A signal that contains a signal, and allows sampling the inner signal directly.
    ///
    /// This is produced by `Signal::switch`
    Nested(Rc<dyn Fn() -> Signal<T>>),
}

impl<T> Signal<T>
{
    /// Creates a signal with constant value.
    ///
    /// The value is assumed to be constant, so changing it while it's stored on the
    /// signal is a logic error and will cause unexpected results.
    pub fn constant(val: T) -> Self
    {
        Signal(Constant(val))
    }

    /// Creates a signal that samples it's values from an external source.
    ///
    /// The closure is meant to sample a continuous value from the real world,
    /// so the signal value is assumed to be always changing.
    pub fn from_fn<F>(f: F) -> Self
        where F: Fn() -> T + 'static
    {
        Signal(Dynamic(Rc::new(f)))
    }

    /// Creates a new shared signal.
    pub(crate) fn shared<S>(storage: S) -> Self
        where S: SharedSignal<T> + 'static
    {
        Signal(Shared(Rc::new(storage)))
    }

    /// Checks if the signal has changed since the last time it was sampled.
    pub fn has_changed(&self) -> bool
    {
        match self.0 {
            Constant(_) => false,
            Dynamic(_) | Nested(_) => true,
            Shared(ref s) => { s.update(); s.has_changed() },
        }
    }

    /// Moves the value out of the signal.
    ///
    /// To avoid leaving the internal storage empty (and causing panics), it must be filled with
    /// a default value. This marks the signal chain as changed, so most of time no one will
    /// notice anything.
    pub fn take(self) -> T
        where T: Default
    {
        match self.0
        {
            Constant(val) => val,
            Dynamic(f) => f(),
            Shared(s) => {
                s.update();
                let val = s.sample().take();
                s.get_storage().set(T::default());
                val
            }
            Nested(f) => f().take(),
        }
    }
}

impl<T: Clone> Signal<T>
{
    /// Sample by value.
    ///
    /// This will clone the content of the signal.
    pub fn sample(&self) -> T
    {
        match self.0
        {
            Constant(ref val) => T::clone(val),
            Dynamic(ref f) => f(),
            Shared(ref s) => { s.update(); s.sample().get() },
            Nested(ref f) => f().sample(),
        }
    }
}

impl<T: 'static> Signal<T>
{
    /// Maps a signal with the provided function.
    ///
    /// The closure is called only when the parent signal changes.
    pub fn map<F, R>(&self, f: F) -> Signal<R>
        where F: Fn(MaybeOwned<'_, T>) -> R + 'static,
        T: Clone, R: 'static
    {
        match self.0 {
            // constant signal: apply f once to produce another constant signal
            Constant(ref val) => {
                Signal::constant(f(MaybeOwned::Borrowed(val)))
            }
            // shared signal: apply f only when the parent signal has changed
            Shared(ref sig) => Signal::shared(SharedImpl{
                storage: Storage::inherit(sig.get_storage()),
                source: sig.clone(),
                f,
            }),
            // dynamic/nested signal: apply f unconditionally
            Dynamic(_) | Nested(_) => {
                let this = self.clone();
                Signal::from_fn(move || f(MaybeOwned::Owned(this.sample())))
            }
        }
    }

    /// Samples the value of this signal every time the trigger stream fires.
    pub fn snapshot<S, F, R>(&self, trigger: &Stream<S>, f: F) -> Stream<R>
        where F: Fn(MaybeOwned<'_, T>, MaybeOwned<'_, S>) -> R + 'static,
        T: Clone, S: 'static, R: 'static
    {
        let this = self.clone();
        trigger.map(move |b| f(MaybeOwned::Owned(this.sample()), b))
    }

    /// Creates a signal from a shared value.
    pub(crate) fn from_storage<P: 'static>(storage: Rc<SharedImpl<T, P, ()>>) -> Self
    {
        Signal(Shared(storage))
    }

    /// Stores the last value sent to a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and returns the last value seen.
    #[inline]
    pub fn from_channel(initial: T, rx: mpsc::Receiver<T>) -> Self
    {
        Self::fold_channel(initial, rx, |_, v| v)
    }

    /// Creates a signal that folds the values from a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and folds them using the current signal value as the
    /// initial accumulator state.
    pub fn fold_channel<V, F>(initial: T, rx: mpsc::Receiver<V>, f: F) -> Self
        where F: Fn(T, V) -> T + 'static,
        V: 'static
    {
        Signal::shared(SharedImpl{
            storage: Storage::new(initial),
            source: rx,
            f,
        })
    }
}

impl<T: Clone + 'static> Signal<Signal<T>>
{
    /// Creates a new signal that samples the inner value of a nested signal.
    pub fn switch(&self) -> Signal<T>
    {
        match self.0
        {
            // constant signal: just extract the inner signal
            Constant(ref sig) => Signal::clone(sig),
            // dynamic signal: re-label as nested
            Dynamic(ref f) => Signal(Nested(f.clone())),
            // shared signal: sample to extract the inner signal
            Shared(ref sig_) => {
                let sig = sig_.clone();
                Signal(Nested(Rc::new(move || { sig.update(); sig.sample().get() })))
            }
            // nested signal: remove one layer
            Nested(ref f_) => {
                let f = f_.clone();
                Signal(Nested(Rc::new(move || f().sample())))
            }
        }
    }
}

impl<T: Default> Default for Signal<T>
{
    /// Creates a constant signal with T's default value.
    #[inline]
    fn default() -> Self
    {
        Signal::constant(T::default())
    }
}

impl<T> From<T> for Signal<T>
{
    /// Creates a constant signal from T.
    #[inline]
    fn from(val: T) -> Self
    {
        Signal::constant(val)
    }
}

impl<T: fmt::Debug> fmt::Debug for SigValue<T>
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
    {
        match *self
        {
            Constant(ref val) => write!(f, "Constant({:?})", val),
            Dynamic(ref rf) => write!(f, "Dynamic(Fn@{:p})", rf),
            Shared(ref rs) => write!(f, "Shared(SharedSignal@{:p})", rs),
            Nested(ref rf) => write!(f, "Nested(Fn@{:p})", rf),
        }
    }
}

impl<T: fmt::Display + Clone> fmt::Display for Signal<T>
{
    /// Samples the signal and formats the value.
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
    {
        fmt::Display::fmt(&self.sample(), f)
    }
}

// A signal that contains only storage.

impl<T, S> SharedImpl<T, S, ()>
{
    pub fn new(initial: T, source: S) -> Self
    {
        SharedImpl{
            storage: Storage::new(initial),
            source,
            f: (),
        }
    }
}

impl<T, S> SharedSignal<T> for SharedImpl<T, S, ()>
{
    fn update(&self) {}

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn get_storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> &Storage<T>
    {
        &self.storage
    }
}

// A signal that maps a parent shared signal.

impl<T, P, F> SharedSignal<T> for SharedImpl<T, Rc<dyn SharedSignal<P>>, F>
    where F: Fn(MaybeOwned<'_, P>) -> T + 'static, P: Clone
{
    fn update(&self)
    {
        self.source.update()
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn get_storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> &Storage<T>
    {
        if self.has_changed()
        {
            let res = (self.f)(MaybeOwned::Owned(self.source.sample().get()));
            self.storage.set_local(res);
        }
        &self.storage
    }
}

// A signal that folds a channel.

impl<T, S, F> SharedSignal<T> for SharedImpl<T, mpsc::Receiver<S>, F>
    where F: Fn(T, S) -> T + 'static,
{
    fn update(&self)
    {
        if let Ok(first) = self.source.try_recv()
        {
            let acc = (self.f)(self.storage.take(), first);
            let new = self.source.try_iter().fold(acc, &self.f);
            self.storage.set(new);
        }
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn get_storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> &Storage<T>
    {
        self.update();
        self.storage.inc_local();
        &self.storage
    }
}

#[cfg(test)]
mod tests
{
    use super::*;
    use std::rc::Rc;
    use std::cell::Cell;
    use std::time::Instant;

    #[test]
    fn signal_basic()
    {
        let signal = Signal::constant(42);
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
        assert_eq!(plusone.sample(), 85);
    }

    #[test]
    fn signal_shared()
    {
        let st = Rc::new(SharedImpl::new(1, ()));
        let signal = Signal::from_storage(st.clone());
        let double = signal.map(|a| *a * 2);

        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        st.set(42);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
    }

    #[test]
    fn signal_dynamic()
    {
        let t = Instant::now();
        let signal = Signal::from_fn(move || t);
        assert_eq!(signal.sample(), t);

        let n = Rc::new(Cell::new(1));
        let cloned = n.clone();
        let signal = Signal::from_fn(move || cloned.get());
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        assert_eq!(plusone.sample(), 3);
        n.set(13);
        assert_eq!(signal.sample(), 13);
        assert_eq!(double.sample(), 26);
        assert_eq!(plusone.sample(), 27);
    }

    #[test]
    fn signal_take()
    {
        let signal = Signal::constant(42);
        assert_eq!(signal.take(), 42);

        let signal = Signal::from_fn(move || 33);
        assert_eq!(signal.clone().take(), 33);
        assert_eq!(signal.take(), 33);

        let st = Rc::new(SharedImpl::new(123, ()));
        let signal = Signal::from_storage(st.clone());
        assert_eq!(signal.clone().take(), 123);
        assert_eq!(signal.clone().take(), 0);
        st.set(13);
        assert_eq!(signal.take(), 13);
    }
}
<commit_msg>update doc comments<commit_after>use std::rc::Rc;
use std::sync::mpsc;
use std::fmt;
use crate::types::{MaybeOwned, Storage, SharedSignal, SharedImpl};
use crate::stream::Stream;

use self::SigValue::*;

/// Represents a discrete value that changes over time.
///
/// Signals are usually constructed by stream operations and can be read using the `sample` or
/// `take` methods. They update lazily when someone reads them.
#[derive(Clone, Debug)]
pub struct Signal<T>(SigValue<T>);

/// The content source of a signal.
#[derive(Clone)]
enum SigValue<T>
{
    /// A signal with constant value.
    Constant(T),
    /// A signal that generates it's values from a function.
    ///
    /// This is produced by `Signal::from_fn`
    Dynamic(Rc<dyn Fn() -> T>),
    /// A signal that contains shared data.
    ///
    /// This is mainly produced by stream methods or mapping other signals.
    Shared(Rc<dyn SharedSignal<T>>),
    /// A signal that contains a signal, and allows sampling the inner signal directly.
    ///
    /// This is produced by `Signal::switch`
    Nested(Rc<dyn Fn() -> Signal<T>>),
}

impl<T> Signal<T>
{
    /// Creates a signal with constant value.
    ///
    /// The value is assumed to be constant, so changing it while it's stored on the
    /// signal is a logic error and will cause unexpected results.
    pub fn constant(val: T) -> Self
    {
        Signal(Constant(val))
    }

    /// Creates a signal that samples it's values from an external source.
    ///
    /// The closure is meant to sample a continuous value from the real world,
    /// so the signal value is assumed to be always changing.
    pub fn from_fn<F>(f: F) -> Self
        where F: Fn() -> T + 'static
    {
        Signal(Dynamic(Rc::new(f)))
    }

    /// Creates a new shared signal.
    pub(crate) fn shared<S>(storage: S) -> Self
        where S: SharedSignal<T> + 'static
    {
        Signal(Shared(Rc::new(storage)))
    }

    /// Checks if the signal has changed since the last time it was sampled.
    pub fn has_changed(&self) -> bool
    {
        match self.0 {
            Constant(_) => false,
            Dynamic(_) | Nested(_) => true,
            Shared(ref s) => { s.update(); s.has_changed() },
        }
    }

    /// Moves the value out of the signal.
    ///
    /// To avoid leaving the internal storage empty (and causing panics), it must be filled with
    /// a default value. This marks the signal chain as changed, so most of time no one will
    /// notice anything.
    pub fn take(self) -> T
        where T: Default
    {
        match self.0
        {
            Constant(val) => val,
            Dynamic(f) => f(),
            Shared(s) => {
                s.update();
                let val = s.sample().take();
                s.get_storage().set(T::default());
                val
            }
            Nested(f) => f().take(),
        }
    }
}

impl<T: Clone> Signal<T>
{
    /// Samples the value of the signal.
    ///
    /// This will clone the value stored in the signal.
    pub fn sample(&self) -> T
    {
        match self.0
        {
            Constant(ref val) => T::clone(val),
            Dynamic(ref f) => f(),
            Shared(ref s) => { s.update(); s.sample().get() },
            Nested(ref f) => f().sample(),
        }
    }
}

impl<T: 'static> Signal<T>
{
    /// Maps a signal with the provided function.
    ///
    /// The closure is called only when the parent signal changes.
    pub fn map<F, R>(&self, f: F) -> Signal<R>
        where F: Fn(MaybeOwned<'_, T>) -> R + 'static,
        T: Clone, R: 'static
    {
        match self.0 {
            // constant signal: apply f once to produce another constant signal
            Constant(ref val) => {
                Signal::constant(f(MaybeOwned::Borrowed(val)))
            }
            // shared signal: apply f only when the parent signal has changed
            Shared(ref sig) => Signal::shared(SharedImpl{
                storage: Storage::inherit(sig.get_storage()),
                source: sig.clone(),
                f,
            }),
            // dynamic/nested signal: apply f unconditionally
            Dynamic(_) | Nested(_) => {
                let this = self.clone();
                Signal::from_fn(move || f(MaybeOwned::Owned(this.sample())))
            }
        }
    }

    /// Samples the value of this signal every time the trigger stream fires.
    pub fn snapshot<S, F, R>(&self, trigger: &Stream<S>, f: F) -> Stream<R>
        where F: Fn(MaybeOwned<'_, T>, MaybeOwned<'_, S>) -> R + 'static,
        T: Clone, S: 'static, R: 'static
    {
        let this = self.clone();
        trigger.map(move |b| f(MaybeOwned::Owned(this.sample()), b))
    }

    /// Creates a signal from a shared value.
    pub(crate) fn from_storage<P: 'static>(storage: Rc<SharedImpl<T, P, ()>>) -> Self
    {
        Signal(Shared(storage))
    }

    /// Stores the last value sent to a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and returns the last value seen.
    #[inline]
    pub fn from_channel(initial: T, rx: mpsc::Receiver<T>) -> Self
    {
        Self::fold_channel(initial, rx, |_, v| v)
    }

    /// Creates a signal that folds the values from a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and folds them using the current signal value as the
    /// initial accumulator state.
    pub fn fold_channel<V, F>(initial: T, rx: mpsc::Receiver<V>, f: F) -> Self
        where F: Fn(T, V) -> T + 'static,
        V: 'static
    {
        Signal::shared(SharedImpl{
            storage: Storage::new(initial),
            source: rx,
            f,
        })
    }
}

impl<T: Clone + 'static> Signal<Signal<T>>
{
    /// Creates a new signal that samples the inner value of a nested signal.
    pub fn switch(&self) -> Signal<T>
    {
        match self.0
        {
            // constant signal: just extract the inner signal
            Constant(ref sig) => Signal::clone(sig),
            // dynamic signal: re-label as nested
            Dynamic(ref f) => Signal(Nested(f.clone())),
            // shared signal: sample to extract the inner signal
            Shared(ref sig_) => {
                let sig = sig_.clone();
                Signal(Nested(Rc::new(move || { sig.update(); sig.sample().get() })))
            }
            // nested signal: remove one layer
            Nested(ref f_) => {
                let f = f_.clone();
                Signal(Nested(Rc::new(move || f().sample())))
            }
        }
    }
}

impl<T: Default> Default for Signal<T>
{
    /// Creates a constant signal with T's default value.
    #[inline]
    fn default() -> Self
    {
        Signal::constant(T::default())
    }
}

impl<T> From<T> for Signal<T>
{
    /// Creates a constant signal from T.
    #[inline]
    fn from(val: T) -> Self
    {
        Signal::constant(val)
    }
}

impl<T: fmt::Debug> fmt::Debug for SigValue<T>
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
    {
        match *self
        {
            Constant(ref val) => write!(f, "Constant({:?})", val),
            Dynamic(ref rf) => write!(f, "Dynamic(Fn@{:p})", rf),
            Shared(ref rs) => write!(f, "Shared(SharedSignal@{:p})", rs),
            Nested(ref rf) => write!(f, "Nested(Fn@{:p})", rf),
        }
    }
}

impl<T: fmt::Display + Clone> fmt::Display for Signal<T>
{
    /// Samples the signal and formats the value.
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
    {
        fmt::Display::fmt(&self.sample(), f)
    }
}

// A signal that contains only storage.

impl<T, S> SharedImpl<T, S, ()>
{
    pub fn new(initial: T, source: S) -> Self
    {
        SharedImpl{
            storage: Storage::new(initial),
            source,
            f: (),
        }
    }
}

impl<T, S> SharedSignal<T> for SharedImpl<T, S, ()>
{
    fn update(&self) {}

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn get_storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> &Storage<T>
    {
        &self.storage
    }
}

// A signal that maps a parent shared signal.

impl<T, P, F> SharedSignal<T> for SharedImpl<T, Rc<dyn SharedSignal<P>>, F>
    where F: Fn(MaybeOwned<'_, P>) -> T + 'static, P: Clone
{
    fn update(&self)
    {
        self.source.update()
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn get_storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> &Storage<T>
    {
        if self.has_changed()
        {
            let res = (self.f)(MaybeOwned::Owned(self.source.sample().get()));
            self.storage.set_local(res);
        }
        &self.storage
    }
}

// A signal that folds a channel.

impl<T, S, F> SharedSignal<T> for SharedImpl<T, mpsc::Receiver<S>, F>
    where F: Fn(T, S) -> T + 'static,
{
    fn update(&self)
    {
        if let Ok(first) = self.source.try_recv()
        {
            let acc = (self.f)(self.storage.take(), first);
            let new = self.source.try_iter().fold(acc, &self.f);
            self.storage.set(new);
        }
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn get_storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> &Storage<T>
    {
        self.update();
        self.storage.inc_local();
        &self.storage
    }
}

#[cfg(test)]
mod tests
{
    use super::*;
    use std::rc::Rc;
    use std::cell::Cell;
    use std::time::Instant;

    #[test]
    fn signal_basic()
    {
        let signal = Signal::constant(42);
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
        assert_eq!(plusone.sample(), 85);
    }

    #[test]
    fn signal_shared()
    {
        let st = Rc::new(SharedImpl::new(1, ()));
        let signal = Signal::from_storage(st.clone());
        let double = signal.map(|a| *a * 2);

        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        st.set(42);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
    }

    #[test]
    fn signal_dynamic()
    {
        let t = Instant::now();
        let signal = Signal::from_fn(move || t);
        assert_eq!(signal.sample(), t);

        let n = Rc::new(Cell::new(1));
        let cloned = n.clone();
        let signal = Signal::from_fn(move || cloned.get());
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        assert_eq!(plusone.sample(), 3);
        n.set(13);
        assert_eq!(signal.sample(), 13);
        assert_eq!(double.sample(), 26);
        assert_eq!(plusone.sample(), 27);
    }

    #[test]
    fn signal_take()
    {
        let signal = Signal::constant(42);
        assert_eq!(signal.take(), 42);

        let signal = Signal::from_fn(move || 33);
        assert_eq!(signal.clone().take(), 33);
        assert_eq!(signal.take(), 33);

        let st = Rc::new(SharedImpl::new(123, ()));
        let signal = Signal::from_storage(st.clone());
        assert_eq!(signal.clone().take(), 123);
        assert_eq!(signal.clone().take(), 0);
        st.set(13);
        assert_eq!(signal.take(), 13);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use ::Result;

use std::cmp;
use std::collections::hash_map;
use std::collections::HashMap;
use std::collections::BinaryHeap;
use std::ops::Deref;

#[derive(Default)]
pub struct Stream {
    recv: RecvBuf,
    send: SendBuf,

    pub tx_data: usize,
    pub max_tx_data: usize,

    pub rx_data: usize,
    pub max_rx_data: usize,
    pub new_max_rx_data: usize,
}

impl Stream {
    pub fn new(max_rx_data: usize, max_tx_data: usize) -> Stream {
        Stream {
            recv: RecvBuf::default(),
            send: SendBuf::default(),

            rx_data: 0,
            max_rx_data,
            new_max_rx_data: max_rx_data,

            tx_data: 0,
            max_tx_data,
        }
    }

    pub fn push_recv(&mut self, buf: RangeBuf) -> Result<()> {
        self.recv.push(buf)
    }

    pub fn pop_recv(&mut self) -> Result<RangeBuf> {
        self.recv.pop()
    }

    pub fn push_send(&mut self, data: &[u8], fin: bool) -> Result<()> {
        self.send.push_slice(data, fin)
    }

    pub fn pop_send(&mut self, max_len: usize) -> Result<RangeBuf> {
        self.send.pop(max_len)
    }

    pub fn resend(&mut self, buf: RangeBuf) -> Result<()> {
        self.send.push(buf)
    }

    pub fn readable(&self) -> bool {
        self.recv.ready()
    }

    pub fn writable(&self) -> bool {
        self.send.ready()
    }

    pub fn more_credit(&self) -> bool {
        // Send MAX_STREAM_DATA when the new limit is at least double the
        // amount of data that can be received before blocking.
        self.new_max_rx_data != self.max_rx_data &&
        self.new_max_rx_data / 2 > self.max_rx_data - self.rx_data
    }
}

pub fn is_local(id: u64, is_server: bool) -> bool {
    (id & 0x1) == (is_server as u64)
}

pub fn is_bidi(id: u64) -> bool {
    (id & 0x2) == 0
}

pub struct Readable<'a> {
    streams: hash_map::Iter<'a, u64, Stream>,
}

impl<'a> Readable<'a> {
    pub(crate) fn new(streams: &HashMap<u64, Stream>) -> Readable {
        Readable {
            streams: streams.iter(),
        }
    }
}

impl<'a> Iterator for Readable<'a> {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        for (id, s) in &mut self.streams {
            if s.readable() {
                return Some(*id);
            }
        }

        None
    }
}

#[derive(Default)]
struct RecvBuf {
    data: BinaryHeap<RangeBuf>,
    off: usize,
    len: usize,
}

impl RecvBuf {
    fn push(&mut self, buf: RangeBuf) -> Result<()> {
        // TODO: discard duplicated data (e.g. using RangeSet)
        self.len = cmp::max(self.len, buf.off + buf.len());

        self.data.push(buf);

        Ok(())
    }

    fn pop(&mut self) -> Result<RangeBuf> {
        let mut out = RangeBuf::default();

        while self.ready() {
            let mut buf = match self.data.pop() {
                Some(v) => v,
                None => break,
            };

            self.off += buf.len();
            self.len -= buf.len();

            out.fin = out.fin || buf.fin();

            out.data.append(&mut buf.data);
        }

        Ok(out)
    }

    fn ready(&self) -> bool {
        if self.len() == 0 {
            return false;
        }

        let buf = match self.data.peek() {
            Some(v) => v,
            None => return false,
        };

        buf.off == self.off
    }

    fn len(&self) -> usize {
        self.len
    }
}

#[derive(Default)]
struct SendBuf {
    data: BinaryHeap<RangeBuf>,
    off: usize,
    len: usize,
}

impl SendBuf {
    fn push_slice(&mut self, data: &[u8], fin: bool) -> Result<()> {
        let buf = RangeBuf::from(data, self.off, fin);
        self.push(buf)?;

        self.off += data.len();

        Ok(())
    }

    fn push(&mut self, buf: RangeBuf) -> Result<()> {
        self.off = cmp::min(self.off, buf.off());
        self.len += buf.len();

        self.data.push(buf);

        Ok(())
    }

    fn pop(&mut self, max_len: usize) -> Result<RangeBuf> {
        let mut out = RangeBuf::default();
        let mut out_len = max_len;

        while out_len > 0 && self.ready() {
            let mut buf = match self.data.pop() {
                Some(v) => v,
                None => break,
            };

            if buf.len() > out_len {
                let new_buf = RangeBuf {
                    data: buf.data.split_off(out_len),
                    off: buf.off + out_len,
                    fin: buf.fin,
                };

                buf.fin = false;

                self.data.push(new_buf);
            }

            if out.len() == 0 {
                out.off = buf.off;
            }

            self.len -= buf.len();

            out_len -= buf.len();

            out.fin = out.fin || buf.fin();

            out.data.append(&mut buf.data);
        }

        Ok(out)
    }

    fn ready(&self) -> bool {
        self.len() > 0
    }

    fn len(&self) -> usize {
        self.len
    }
}

#[derive(Debug, Default, Eq)]
pub struct RangeBuf {
    data: Vec<u8>,
    off: usize,
    fin: bool,
}

impl RangeBuf {
    pub fn from(buf: &[u8], off: usize, fin: bool) -> RangeBuf {
        RangeBuf {
            data: Vec::from(buf),
            off,
            fin,
        }
    }

    pub fn fin(&self) -> bool {
        self.fin
    }

    pub fn off(&self) -> usize {
        self.off
    }

    pub fn max_off(&self) -> usize {
        self.off() + self.len()
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }
}

impl Deref for RangeBuf {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.data
    }
}

impl Ord for RangeBuf {
    fn cmp(&self, other: &RangeBuf) -> cmp::Ordering {
        // Invert ordering to implement min-heap.
        self.off.cmp(&other.off).reverse()
    }
}

impl PartialOrd for RangeBuf {
    fn partial_cmp(&self, other: &RangeBuf) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for RangeBuf {
    fn eq(&self, other: &RangeBuf) -> bool {
        self.off == other.off
    }
}

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

    #[test]
    fn empty_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn ordered_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let first = RangeBuf::from(b"hello", 0, false);
        let second = RangeBuf::from(b"world", 5, false);
        let third = RangeBuf::from(b"something", 10, false);

        assert!(buf.push(second).is_ok());
        assert_eq!(buf.len(), 10);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);

        assert!(buf.push(third).is_ok());
        assert_eq!(buf.len(), 19);

        assert!(buf.push(first).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 19);
        assert_eq!(&read[..], b"helloworldsomething");
        assert_eq!(buf.len(), 0);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn incomplete_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let first = RangeBuf::from(b"something", 0, false);
        let second = RangeBuf::from(b"helloworld", 9, false);

        assert!(buf.push(second).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);

        assert!(buf.push(first).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 19);
        assert_eq!(&read[..], b"somethinghelloworld");
        assert_eq!(buf.len(), 0);
    }

    #[test]
    fn empty_write() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let write = buf.pop().unwrap();
        assert_eq!(write.len(), 0);
    }

    #[test]
    fn multi_write() {
        let mut buf = SendBuf::default();
        assert_eq!(buf.len(), 0);

        let first: [u8; 9] = *b"something";
        let second: [u8; 10] = *b"helloworld";

        assert!(buf.push_slice(&first, false).is_ok());
        assert_eq!(buf.len(), 9);

        assert!(buf.push_slice(&second, false).is_ok());
        assert_eq!(buf.len(), 19);

        let write = buf.pop(128).unwrap();
        assert_eq!(write.len(), 19);
        assert_eq!(&write[..], b"somethinghelloworld");
        assert_eq!(buf.len(), 0);
    }

    #[test]
    fn split_write() {
        let mut buf = SendBuf::default();
        assert_eq!(buf.len(), 0);

        let first: [u8; 9] = *b"something";
        let second: [u8; 10] = *b"helloworld";

        assert!(buf.push_slice(&first, false).is_ok());
        assert_eq!(buf.len(), 9);

        assert!(buf.push_slice(&second, true).is_ok());
        assert_eq!(buf.len(), 19);

        let write = buf.pop(10).unwrap();
        assert_eq!(write.off(), 0);
        assert_eq!(write.len(), 10);
        assert_eq!(&write[..], b"somethingh");
        assert_eq!(buf.len(), 9);

        let write = buf.pop(5).unwrap();
        assert_eq!(write.off(), 10);
        assert_eq!(write.len(), 5);
        assert_eq!(&write[..], b"ellow");
        assert_eq!(buf.len(), 4);

        let write = buf.pop(10).unwrap();
        assert_eq!(write.off(), 15);
        assert_eq!(write.len(), 4);
        assert_eq!(&write[..], b"orld");
        assert_eq!(buf.len(), 0);
    }
}
<commit_msg>stream: handle simple case of duplicated data<commit_after>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use ::Result;

use std::cmp;
use std::collections::hash_map;
use std::collections::HashMap;
use std::collections::BinaryHeap;
use std::ops::Deref;

#[derive(Default)]
pub struct Stream {
    recv: RecvBuf,
    send: SendBuf,

    pub tx_data: usize,
    pub max_tx_data: usize,

    pub rx_data: usize,
    pub max_rx_data: usize,
    pub new_max_rx_data: usize,
}

impl Stream {
    pub fn new(max_rx_data: usize, max_tx_data: usize) -> Stream {
        Stream {
            recv: RecvBuf::default(),
            send: SendBuf::default(),

            rx_data: 0,
            max_rx_data,
            new_max_rx_data: max_rx_data,

            tx_data: 0,
            max_tx_data,
        }
    }

    pub fn push_recv(&mut self, buf: RangeBuf) -> Result<()> {
        self.recv.push(buf)
    }

    pub fn pop_recv(&mut self) -> Result<RangeBuf> {
        self.recv.pop()
    }

    pub fn push_send(&mut self, data: &[u8], fin: bool) -> Result<()> {
        self.send.push_slice(data, fin)
    }

    pub fn pop_send(&mut self, max_len: usize) -> Result<RangeBuf> {
        self.send.pop(max_len)
    }

    pub fn resend(&mut self, buf: RangeBuf) -> Result<()> {
        self.send.push(buf)
    }

    pub fn readable(&self) -> bool {
        self.recv.ready()
    }

    pub fn writable(&self) -> bool {
        self.send.ready()
    }

    pub fn more_credit(&self) -> bool {
        // Send MAX_STREAM_DATA when the new limit is at least double the
        // amount of data that can be received before blocking.
        self.new_max_rx_data != self.max_rx_data &&
        self.new_max_rx_data / 2 > self.max_rx_data - self.rx_data
    }
}

pub fn is_local(id: u64, is_server: bool) -> bool {
    (id & 0x1) == (is_server as u64)
}

pub fn is_bidi(id: u64) -> bool {
    (id & 0x2) == 0
}

pub struct Readable<'a> {
    streams: hash_map::Iter<'a, u64, Stream>,
}

impl<'a> Readable<'a> {
    pub(crate) fn new(streams: &HashMap<u64, Stream>) -> Readable {
        Readable {
            streams: streams.iter(),
        }
    }
}

impl<'a> Iterator for Readable<'a> {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        for (id, s) in &mut self.streams {
            if s.readable() {
                return Some(*id);
            }
        }

        None
    }
}

#[derive(Default)]
struct RecvBuf {
    data: BinaryHeap<RangeBuf>,
    off: usize,
    len: usize,
}

impl RecvBuf {
    fn push(&mut self, buf: RangeBuf) -> Result<()> {
        // TODO: discard duplicated data (e.g. using RangeSet)
        if self.off >= buf.off() + buf.len() {
            // Data is fully duplicate.
            return Ok(());
        }

        self.len = cmp::max(self.len, buf.off + buf.len());

        self.data.push(buf);

        Ok(())
    }

    fn pop(&mut self) -> Result<RangeBuf> {
        let mut out = RangeBuf::default();

        while self.ready() {
            let mut buf = match self.data.pop() {
                Some(v) => v,
                None => break,
            };

            self.off += buf.len();
            self.len -= buf.len();

            out.fin = out.fin || buf.fin();

            out.data.append(&mut buf.data);
        }

        Ok(out)
    }

    fn ready(&self) -> bool {
        if self.len() == 0 {
            return false;
        }

        let buf = match self.data.peek() {
            Some(v) => v,
            None => return false,
        };

        buf.off == self.off
    }

    fn len(&self) -> usize {
        self.len
    }
}

#[derive(Default)]
struct SendBuf {
    data: BinaryHeap<RangeBuf>,
    off: usize,
    len: usize,
}

impl SendBuf {
    fn push_slice(&mut self, data: &[u8], fin: bool) -> Result<()> {
        let buf = RangeBuf::from(data, self.off, fin);
        self.push(buf)?;

        self.off += data.len();

        Ok(())
    }

    fn push(&mut self, buf: RangeBuf) -> Result<()> {
        self.off = cmp::min(self.off, buf.off());
        self.len += buf.len();

        self.data.push(buf);

        Ok(())
    }

    fn pop(&mut self, max_len: usize) -> Result<RangeBuf> {
        let mut out = RangeBuf::default();
        let mut out_len = max_len;

        while out_len > 0 && self.ready() {
            let mut buf = match self.data.pop() {
                Some(v) => v,
                None => break,
            };

            if buf.len() > out_len {
                let new_buf = RangeBuf {
                    data: buf.data.split_off(out_len),
                    off: buf.off + out_len,
                    fin: buf.fin,
                };

                buf.fin = false;

                self.data.push(new_buf);
            }

            if out.len() == 0 {
                out.off = buf.off;
            }

            self.len -= buf.len();

            out_len -= buf.len();

            out.fin = out.fin || buf.fin();

            out.data.append(&mut buf.data);
        }

        Ok(out)
    }

    fn ready(&self) -> bool {
        self.len() > 0
    }

    fn len(&self) -> usize {
        self.len
    }
}

#[derive(Debug, Default, Eq)]
pub struct RangeBuf {
    data: Vec<u8>,
    off: usize,
    fin: bool,
}

impl RangeBuf {
    pub fn from(buf: &[u8], off: usize, fin: bool) -> RangeBuf {
        RangeBuf {
            data: Vec::from(buf),
            off,
            fin,
        }
    }

    pub fn fin(&self) -> bool {
        self.fin
    }

    pub fn off(&self) -> usize {
        self.off
    }

    pub fn max_off(&self) -> usize {
        self.off() + self.len()
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }
}

impl Deref for RangeBuf {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.data
    }
}

impl Ord for RangeBuf {
    fn cmp(&self, other: &RangeBuf) -> cmp::Ordering {
        // Invert ordering to implement min-heap.
        self.off.cmp(&other.off).reverse()
    }
}

impl PartialOrd for RangeBuf {
    fn partial_cmp(&self, other: &RangeBuf) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for RangeBuf {
    fn eq(&self, other: &RangeBuf) -> bool {
        self.off == other.off
    }
}

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

    #[test]
    fn empty_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn ordered_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let first = RangeBuf::from(b"hello", 0, false);
        let second = RangeBuf::from(b"world", 5, false);
        let third = RangeBuf::from(b"something", 10, false);

        assert!(buf.push(second).is_ok());
        assert_eq!(buf.len(), 10);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);

        assert!(buf.push(third).is_ok());
        assert_eq!(buf.len(), 19);

        assert!(buf.push(first).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 19);
        assert_eq!(&read[..], b"helloworldsomething");
        assert_eq!(buf.len(), 0);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);
    }

    #[test]
    fn incomplete_read() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let first = RangeBuf::from(b"something", 0, false);
        let second = RangeBuf::from(b"helloworld", 9, false);

        assert!(buf.push(second).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 0);

        assert!(buf.push(first).is_ok());
        assert_eq!(buf.len(), 19);

        let read = buf.pop().unwrap();
        assert_eq!(read.len(), 19);
        assert_eq!(&read[..], b"somethinghelloworld");
        assert_eq!(buf.len(), 0);
    }

    #[test]
    fn empty_write() {
        let mut buf = RecvBuf::default();
        assert_eq!(buf.len(), 0);

        let write = buf.pop().unwrap();
        assert_eq!(write.len(), 0);
    }

    #[test]
    fn multi_write() {
        let mut buf = SendBuf::default();
        assert_eq!(buf.len(), 0);

        let first: [u8; 9] = *b"something";
        let second: [u8; 10] = *b"helloworld";

        assert!(buf.push_slice(&first, false).is_ok());
        assert_eq!(buf.len(), 9);

        assert!(buf.push_slice(&second, false).is_ok());
        assert_eq!(buf.len(), 19);

        let write = buf.pop(128).unwrap();
        assert_eq!(write.len(), 19);
        assert_eq!(&write[..], b"somethinghelloworld");
        assert_eq!(buf.len(), 0);
    }

    #[test]
    fn split_write() {
        let mut buf = SendBuf::default();
        assert_eq!(buf.len(), 0);

        let first: [u8; 9] = *b"something";
        let second: [u8; 10] = *b"helloworld";

        assert!(buf.push_slice(&first, false).is_ok());
        assert_eq!(buf.len(), 9);

        assert!(buf.push_slice(&second, true).is_ok());
        assert_eq!(buf.len(), 19);

        let write = buf.pop(10).unwrap();
        assert_eq!(write.off(), 0);
        assert_eq!(write.len(), 10);
        assert_eq!(&write[..], b"somethingh");
        assert_eq!(buf.len(), 9);

        let write = buf.pop(5).unwrap();
        assert_eq!(write.off(), 10);
        assert_eq!(write.len(), 5);
        assert_eq!(&write[..], b"ellow");
        assert_eq!(buf.len(), 4);

        let write = buf.pop(10).unwrap();
        assert_eq!(write.off(), 15);
        assert_eq!(write.len(), 4);
        assert_eq!(&write[..], b"orld");
        assert_eq!(buf.len(), 0);
    }
}
<|endoftext|>