<commit_before>use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use std::{fs, io};

use toml::{Parser, Value};

use errors::*;

pub fn cp_r(src: &Path, dst: &Path) -> Result<()> {
    (|| -> io::Result<()> {
            for e in src.read_dir()? {
                let e = e?;
                let metadata = e.path().metadata()?;
                let f = e.file_name();
                let src = src.join(&f);
                let dst = dst.join(&f);

                if metadata.is_dir() {
                    fs::create_dir(&dst)?;
                    cp_r(
                        src.as_path(),
                        dst.as_path()
                    ).map_err(|e| io::Error::new(io::ErrorKind::Other, e.description()))?;
                } else {
                    fs::copy(src, dst)?;
                }
            }

            Ok(())
        })()
        .chain_err(|| {
            format!("copying files from `{}` to `{}` failed",
                    src.display(),
                    dst.display())
        })
}

pub fn mkdir(path: &Path) -> Result<()> {
    fs::create_dir(path)
        .chain_err(|| format!("couldn't create directory {}", path.display()))
}

/// Parses `path` as TOML
pub fn parse(path: &Path) -> Result<Value> {
    Ok(Value::Table(Parser::new(&read(path)?).parse()
        .ok_or_else(|| format!("{} is not valid TOML", path.display()))?))
}

pub fn read(path: &Path) -> Result<String> {
    let mut s = String::new();

    let p = path.display();
    File::open(path).chain_err(|| format!("couldn't open {}", p))?
        .read_to_string(&mut s)
        .chain_err(|| format!("couldn't read {}", p))?;

    Ok(s)
}

/// Search for `file` in `path` and its parent directories
pub fn search<'p>(mut path: &'p Path, file: &str) -> Option<&'p Path> {
    loop {
        if path.join(file).exists() {
            return Some(path);
        }

        if let Some(p) = path.parent() {
            path = p;
        } else {
            return None;
        }
    }
}

pub fn write(path: &Path, contents: &str) -> Result<()> {
    let p = path.display();
    File::create(path)
        .chain_err(|| format!("couldn't open {}", p))?
        .write_all(contents.as_bytes())
        .chain_err(|| format!("couldn't write to {}", p))
}
<commit_msg>Updated cp_r to use WalkDir instead of recursive functions<commit_after>use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use std::fs;

use toml::{Parser, Value};
use walkdir::WalkDir;

use errors::*;

pub fn cp_r(src: &Path, dst: &Path) -> Result<()> {
    for e in WalkDir::new(src) {
        let e = e.unwrap();
        let src_file = e.path();
        let relative_path = src_file.strip_prefix(src).unwrap();
        let dst_file = dst.join(relative_path);
        let metadata = e.metadata()
            .chain_err(|| {
                format!("Could not retrieve metadata of `{}`",
                e.path().display())
            })?;

        if metadata.is_dir() {
            // ensure the destination directory exists
            fs::create_dir_all(&dst_file)
                .chain_err(|| {
                    format!("Could not create directory `{}`",
                            dst_file.display())
                })?;
        } else {
            // else copy the file
            fs::copy(&src_file, &dst_file)
                .chain_err(|| {
                    format!("copying files from `{}` to `{}` failed",
                            src_file.display(),
                            dst_file.display())
                })?;
        };
    }

    Ok(())
}

pub fn mkdir(path: &Path) -> Result<()> {
    fs::create_dir(path)
        .chain_err(|| format!("couldn't create directory {}", path.display()))
}

/// Parses `path` as TOML
pub fn parse(path: &Path) -> Result<Value> {
    Ok(Value::Table(Parser::new(&read(path)?).parse()
        .ok_or_else(|| format!("{} is not valid TOML", path.display()))?))
}

pub fn read(path: &Path) -> Result<String> {
    let mut s = String::new();

    let p = path.display();
    File::open(path).chain_err(|| format!("couldn't open {}", p))?
        .read_to_string(&mut s)
        .chain_err(|| format!("couldn't read {}", p))?;

    Ok(s)
}

/// Search for `file` in `path` and its parent directories
pub fn search<'p>(mut path: &'p Path, file: &str) -> Option<&'p Path> {
    loop {
        if path.join(file).exists() {
            return Some(path);
        }

        if let Some(p) = path.parent() {
            path = p;
        } else {
            return None;
        }
    }
}

pub fn write(path: &Path, contents: &str) -> Result<()> {
    let p = path.display();
    File::create(path)
        .chain_err(|| format!("couldn't open {}", p))?
        .write_all(contents.as_bytes())
        .chain_err(|| format!("couldn't write to {}", p))
}
<|endoftext|>


<commit_before>pub fn trim_right<'a, 'b>(uri: &'a str, end: &'b str) -> &'a str {
    let n = uri.len();
    let p = end.len();

    if n >= p && &uri[(n - p)..n] == end {
        &uri[0..(n - p)]
    } else {
        uri
    }
}

pub fn trim_left<'a, 'b>(uri: &'a str, start: &'b str) -> &'a str {
    let n = uri.len();
    let p = start.len();

    if n >= p && &uri[0..p] == start {
        &uri[p..n]
    } else {
        uri
    }
}

pub fn add_right(uri: &str, end: &str) -> String {
    let n = uri.len();
    let p = end.len();

    if n >= p && &uri[(n - p)..n] == end {
        uri.to_string()
    } else {
        uri.to_string() + end
    }
}

pub fn add_https(uri: &str) -> String {
    let protocol = "https://";
    let other = "http://";
    let p = protocol.len();
    let o = other.len();
    let n = uri.len();

    if n < p || &uri[0..p] != protocol && &uri[0..o] != other {
        protocol.to_string() + uri
    } else {
        uri.to_string()
    }
}
//
// pub fn join(left: &str, right: &str, delim: &str) -> String {
//     trim_right(left, delim).to_string() + delim + trim_left(right, delim)
// }
<commit_msg>CoWed the util lib<commit_after>use std::borrow::Cow;

pub fn trim_right<'a, 'b>(uri: &'a str, end: &'b str) -> &'a str {
    let n = uri.len();
    let p = end.len();

    if n >= p && &uri[(n - p)..n] == end {
        &uri[0..(n - p)]
    } else {
        uri
    }
}

pub fn trim_left<'a, 'b>(uri: &'a str, start: &'b str) -> &'a str {
    let n = uri.len();
    let p = start.len();

    if n >= p && &uri[0..p] == start {
        &uri[p..n]
    } else {
        uri
    }
}

pub fn add_right<'l>(uri: &'l str, end: &str) -> Cow<'l, str> {
    let n = uri.len();
    let p = end.len();

    if n >= p && &uri[(n - p)..n] == end {
        Cow::Borrowed(uri)
    } else {
        Cow::Owned(uri.to_string() + end)
    }
}

pub fn add_https<'l>(uri: &'l str) -> Cow<'l, str> {
    let protocol = "https://";
    let other = "http://";
    let p = protocol.len();
    let o = other.len();
    let n = uri.len();

    if n < p || &uri[0..p] != protocol && &uri[0..o] != other {
        Cow::Owned(protocol.to_string() + uri)
    } else {
        Cow::Borrowed(uri)
    }
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(exit_status)]
#![feature(io)]
#![feature(os)]
#![feature(std_misc)]
extern crate octobuild;
extern crate tempdir;

use octobuild::common::BuildTask;
use octobuild::cache::Cache;
use octobuild::wincmd;
use octobuild::xg;
use octobuild::graph::{Graph, NodeIndex, Node, EdgeIndex, Edge};
use octobuild::vs::compiler::VsCompiler;
use octobuild::compiler::*;

use tempdir::TempDir;

use std::fs::File;
use std::env;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::io;
use std::iter::FromIterator;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread::Thread;

#[derive(Debug)]
struct TaskMessage {
	index: NodeIndex,
	task: BuildTask
}

#[derive(Debug)]
struct ResultMessage {
	index: NodeIndex,
	task: BuildTask,
	worker: usize,
	result: Result<OutputInfo, Error>
}

fn main() {
	println!("XGConsole:");
	let args = Vec::from_iter(env::args());
	for arg in args.iter() {
		println!("  {}", arg);
	}
	match execute(&args.as_slice()[1..]) {
		Ok(result) => {
			env::set_exit_status(match result {
				Some(r) => r,
				None => 500
			});
		}
		Err(e) => {
			println!("FATAL ERROR: {:?}", e);
			env::set_exit_status(500);
		}
	}
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
	let cache = Cache::new();
	let temp_dir = try! (TempDir::new("octobuild"));
	for arg in args.iter() {
		if arg.starts_with("/") {continue}

		let (tx_result, rx_result): (Sender<ResultMessage>, Receiver<ResultMessage>) = channel();
		let (tx_task, rx_task): (Sender<TaskMessage>, Receiver<TaskMessage>) = channel();

		create_threads(rx_task, tx_result, std::os::num_cpus(), |worker_id:usize| {
			let temp_path = temp_dir.path().to_path_buf();
			let temp_cache = cache.clone();
			move |task:TaskMessage| -> ResultMessage {
				execute_task(&temp_cache, &temp_path, worker_id, task)
			}
		});

		let path = Path::new(arg);
		let file = try! (File::open(&path));
		let graph = try! (xg::parser::parse(BufReader::new(file)));
		let validated_graph = try! (validate_graph(graph));
		match try! (execute_graph(&validated_graph, tx_task, rx_result)) {
			Some(v) if v == 0 => {}
			v => {return Ok(v)}
		}
	}
	cache.cleanup(16 * 1024 * 1024 * 1024);
	Ok(Some(0))
}

fn create_threads<R: 'static + Send, T: 'static + Send, Worker:'static + Fn(T) -> R + Send, Factory:Fn(usize) -> Worker>(rx_task: Receiver<T>, tx_result: Sender<R>, num_cpus: usize, factory: Factory) ->  Arc<Mutex<Receiver<T>>> {
	let mutex_rx_task = Arc::new(Mutex::new(rx_task));
	for cpu_id in range(0, num_cpus) {
		let local_rx_task = mutex_rx_task.clone();
		let local_tx_result = tx_result.clone();
		let worker = factory(cpu_id);
		Thread::spawn(move || {
			loop {
				let task: T;
				match local_rx_task.lock().unwrap().recv() {
					Ok(v) => {task = v;}
					Err(_) => {break;}
				}
				match local_tx_result.send(worker(task)) {
					Ok(_) => {}
					Err(_) => {break;}
				}
			}
		});
	}
	mutex_rx_task
}

fn validate_graph(graph: Graph<BuildTask, ()>) -> Result<Graph<BuildTask, ()>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	let mut queue:Vec<NodeIndex> = Vec::new();
	graph.each_node(|index: NodeIndex, _:&Node<BuildTask>|->bool {
		completed.push(false);
		queue.push(index);
		true
	});
	let mut count:usize = 0;
	let mut i:usize = 0;
	while i < queue.len() {
		let index = queue[i];
		if (!completed[index.node_id()]) && (is_ready(&graph, &completed, &index)) {
			completed[index.node_id()] = true;
			graph.each_incoming_edge(index, |_:EdgeIndex, edge:&Edge<()>| -> bool {
				queue.push(edge.source());
				true
			});
			count += 1;
			if count ==completed.len() {
				return Ok(graph);
			}
		}
		i = i + 1;
	}
	Err(Error::new(ErrorKind::InvalidInput, "Found cycles in build dependencies", None))
}

fn execute_task(cache: &Cache, temp_dir: &Path, worker: usize, message: TaskMessage) -> ResultMessage {
	let args = wincmd::expand_args(&message.task.args, &|name:&str|->Option<String>{env::var(name).ok()});
	let output = execute_compiler(cache, temp_dir, message.task.exec.as_slice(), &Path::new(&message.task.working_dir), args.as_slice());
	ResultMessage {
		index: message.index,
		task: message.task,
		worker: worker,
		result: output,
	}
}

fn execute_compiler(cache: &Cache, temp_dir: &Path, program: &str, cwd: &Path, args: &[String]) -> Result<OutputInfo, Error> {
	let command = CommandInfo {
		program: Path::new(program).to_path_buf(),
		current_dir: Some(cwd.to_path_buf()),
	};
	if Path::new(program).ends_with("cl.exe") {
		let compiler = VsCompiler::new(cache, temp_dir);
		compiler.compile(command, args)
	} else {
		command.to_command()
			.args(args.as_slice())
			.output()
			.map(|o| OutputInfo::new(o))
	}
}

fn execute_graph(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	// Run all tasks.
	let result = execute_until_failed(graph, tx_task, &rx_result);
	// Wait for in progress task completion.
	for _ in rx_result.iter() {
	}
	result
}

fn execute_until_failed(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: &Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	if !graph.each_node(|index: NodeIndex, node:&Node<BuildTask>|->bool {
		let mut has_edges = false;
		graph.each_outgoing_edge(index, |_:EdgeIndex, _:&Edge<()>| -> bool {
			has_edges = true;
			false
		});
		completed.push(false);
		if !has_edges {
			match tx_task.send(TaskMessage{
				index: index,
				task: node.data.clone(),
			}) {
				Ok(_) => true,
				Err(_) => false,
			}
		} else {
			true
		}
	}) {
		return Err(Error::new(ErrorKind::BrokenPipe, "Can't schedule root tasks", None));
	}

	let mut count:usize = 0;
	for message in rx_result.iter() {
		assert!(!completed[message.index.node_id()]);
		count += 1;
		println!("#{} {}/{}: {}", message.worker, count, completed.len(), message.task.title);
		let result = try! (message.result);
		try! (io::stdout().write_all(result.stdout.as_slice()));
		try! (io::stderr().write_all(result.stderr.as_slice()));
		if !result.success() {
			return Ok(result.status);
		}
		completed[message.index.node_id()] = true;
		if !graph.each_incoming_edge(message.index, |_:EdgeIndex, edge:&Edge<()>| -> bool {
			let source = edge.source();
			if !completed[source.node_id()] {
				if is_ready(graph, &completed, &source) {
					match tx_task.send(TaskMessage{
						index: source,
						task: graph.node(source).data.clone(),
					}) {
						Ok(_) => {},
						Err(_) => {return false;}
					}
				}
			}
			true
		}) {
			return Err(Error::new(ErrorKind::BrokenPipe, "Can't schedule child task", None));
		};
		if count == completed.len() {
			return Ok(Some(0));
		}
	}
	panic! ("Unexpected end of result pipe");
}

fn is_ready(graph: &Graph<BuildTask, ()>, completed: &Vec<bool>, source: &NodeIndex) -> bool {
	let mut ready = true;
		graph.each_outgoing_edge(*source, |_:EdgeIndex, deps:&Edge<()>| -> bool {
		if !completed[deps.target().node_id()]{
			ready = false;
			false
		} else {
			true
		}
	});
	ready
}
<commit_msg>Remove using of deprecated methods<commit_after>#![feature(core)]
#![feature(exit_status)]
#![feature(io)]
#![feature(os)]
extern crate octobuild;
extern crate tempdir;

use octobuild::common::BuildTask;
use octobuild::cache::Cache;
use octobuild::wincmd;
use octobuild::xg;
use octobuild::graph::{Graph, NodeIndex, Node, EdgeIndex, Edge};
use octobuild::vs::compiler::VsCompiler;
use octobuild::compiler::*;

use tempdir::TempDir;

use std::fs::File;
use std::env;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::io;
use std::iter::FromIterator;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread;

#[derive(Debug)]
struct TaskMessage {
	index: NodeIndex,
	task: BuildTask
}

#[derive(Debug)]
struct ResultMessage {
	index: NodeIndex,
	task: BuildTask,
	worker: usize,
	result: Result<OutputInfo, Error>
}

fn main() {
	println!("XGConsole:");
	let args = Vec::from_iter(env::args());
	for arg in args.iter() {
		println!("  {}", arg);
	}
	match execute(&args.as_slice()[1..]) {
		Ok(result) => {
			env::set_exit_status(match result {
				Some(r) => r,
				None => 500
			});
		}
		Err(e) => {
			println!("FATAL ERROR: {:?}", e);
			env::set_exit_status(500);
		}
	}
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
	let cache = Cache::new();
	let temp_dir = try! (TempDir::new("octobuild"));
	for arg in args.iter() {
		if arg.starts_with("/") {continue}

		let (tx_result, rx_result): (Sender<ResultMessage>, Receiver<ResultMessage>) = channel();
		let (tx_task, rx_task): (Sender<TaskMessage>, Receiver<TaskMessage>) = channel();

		create_threads(rx_task, tx_result, std::os::num_cpus(), |worker_id:usize| {
			let temp_path = temp_dir.path().to_path_buf();
			let temp_cache = cache.clone();
			move |task:TaskMessage| -> ResultMessage {
				execute_task(&temp_cache, &temp_path, worker_id, task)
			}
		});

		let path = Path::new(arg);
		let file = try! (File::open(&path));
		let graph = try! (xg::parser::parse(BufReader::new(file)));
		let validated_graph = try! (validate_graph(graph));
		match try! (execute_graph(&validated_graph, tx_task, rx_result)) {
			Some(v) if v == 0 => {}
			v => {return Ok(v)}
		}
	}
	cache.cleanup(16 * 1024 * 1024 * 1024);
	Ok(Some(0))
}

fn create_threads<R: 'static + Send, T: 'static + Send, Worker:'static + Fn(T) -> R + Send, Factory:Fn(usize) -> Worker>(rx_task: Receiver<T>, tx_result: Sender<R>, num_cpus: usize, factory: Factory) ->  Arc<Mutex<Receiver<T>>> {
	let mutex_rx_task = Arc::new(Mutex::new(rx_task));
	for cpu_id in range(0, num_cpus) {
		let local_rx_task = mutex_rx_task.clone();
		let local_tx_result = tx_result.clone();
		let worker = factory(cpu_id);
		thread::spawn(move || {
			loop {
				let task: T;
				match local_rx_task.lock().unwrap().recv() {
					Ok(v) => {task = v;}
					Err(_) => {break;}
				}
				match local_tx_result.send(worker(task)) {
					Ok(_) => {}
					Err(_) => {break;}
				}
			}
		});
	}
	mutex_rx_task
}

fn validate_graph(graph: Graph<BuildTask, ()>) -> Result<Graph<BuildTask, ()>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	let mut queue:Vec<NodeIndex> = Vec::new();
	graph.each_node(|index: NodeIndex, _:&Node<BuildTask>|->bool {
		completed.push(false);
		queue.push(index);
		true
	});
	let mut count:usize = 0;
	let mut i:usize = 0;
	while i < queue.len() {
		let index = queue[i];
		if (!completed[index.node_id()]) && (is_ready(&graph, &completed, &index)) {
			completed[index.node_id()] = true;
			graph.each_incoming_edge(index, |_:EdgeIndex, edge:&Edge<()>| -> bool {
				queue.push(edge.source());
				true
			});
			count += 1;
			if count ==completed.len() {
				return Ok(graph);
			}
		}
		i = i + 1;
	}
	Err(Error::new(ErrorKind::InvalidInput, "Found cycles in build dependencies", None))
}

fn execute_task(cache: &Cache, temp_dir: &Path, worker: usize, message: TaskMessage) -> ResultMessage {
	let args = wincmd::expand_args(&message.task.args, &|name:&str|->Option<String>{env::var(name).ok()});
	let output = execute_compiler(cache, temp_dir, message.task.exec.as_slice(), &Path::new(&message.task.working_dir), args.as_slice());
	ResultMessage {
		index: message.index,
		task: message.task,
		worker: worker,
		result: output,
	}
}

fn execute_compiler(cache: &Cache, temp_dir: &Path, program: &str, cwd: &Path, args: &[String]) -> Result<OutputInfo, Error> {
	let command = CommandInfo {
		program: Path::new(program).to_path_buf(),
		current_dir: Some(cwd.to_path_buf()),
	};
	if Path::new(program).ends_with("cl.exe") {
		let compiler = VsCompiler::new(cache, temp_dir);
		compiler.compile(command, args)
	} else {
		command.to_command()
			.args(args.as_slice())
			.output()
			.map(|o| OutputInfo::new(o))
	}
}

fn execute_graph(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	// Run all tasks.
	let result = execute_until_failed(graph, tx_task, &rx_result);
	// Wait for in progress task completion.
	for _ in rx_result.iter() {
	}
	result
}

fn execute_until_failed(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: &Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	if !graph.each_node(|index: NodeIndex, node:&Node<BuildTask>|->bool {
		let mut has_edges = false;
		graph.each_outgoing_edge(index, |_:EdgeIndex, _:&Edge<()>| -> bool {
			has_edges = true;
			false
		});
		completed.push(false);
		if !has_edges {
			match tx_task.send(TaskMessage{
				index: index,
				task: node.data.clone(),
			}) {
				Ok(_) => true,
				Err(_) => false,
			}
		} else {
			true
		}
	}) {
		return Err(Error::new(ErrorKind::BrokenPipe, "Can't schedule root tasks", None));
	}

	let mut count:usize = 0;
	for message in rx_result.iter() {
		assert!(!completed[message.index.node_id()]);
		count += 1;
		println!("#{} {}/{}: {}", message.worker, count, completed.len(), message.task.title);
		let result = try! (message.result);
		try! (io::stdout().write_all(result.stdout.as_slice()));
		try! (io::stderr().write_all(result.stderr.as_slice()));
		if !result.success() {
			return Ok(result.status);
		}
		completed[message.index.node_id()] = true;
		if !graph.each_incoming_edge(message.index, |_:EdgeIndex, edge:&Edge<()>| -> bool {
			let source = edge.source();
			if !completed[source.node_id()] {
				if is_ready(graph, &completed, &source) {
					match tx_task.send(TaskMessage{
						index: source,
						task: graph.node(source).data.clone(),
					}) {
						Ok(_) => {},
						Err(_) => {return false;}
					}
				}
			}
			true
		}) {
			return Err(Error::new(ErrorKind::BrokenPipe, "Can't schedule child task", None));
		};
		if count == completed.len() {
			return Ok(Some(0));
		}
	}
	panic! ("Unexpected end of result pipe");
}

fn is_ready(graph: &Graph<BuildTask, ()>, completed: &Vec<bool>, source: &NodeIndex) -> bool {
	let mut ready = true;
		graph.each_outgoing_edge(*source, |_:EdgeIndex, deps:&Edge<()>| -> bool {
		if !completed[deps.target().node_id()]{
			ready = false;
			false
		} else {
			true
		}
	});
	ready
}
<|endoftext|>


<commit_before>#[deriving(Show)]
struct Vec2<T> {
    x: T,
    y: T,
}

// The Add<T, U> trait overloads the + operator: (Self + T = U)
impl<
    // bound: T implements the Add trait
    T: Add<T, T>
> Add<Vec2<T>, Vec2<T>>
for Vec2<T> {
    // add() is a required method of the Add trait
    fn add(&self, rhs: &Vec2<T>) -> Vec2<T> {
        Vec2 {
            // x and y are of type T, and implement the add() method
            x: self.x.add(&rhs.x),
            y: self.x.add(&rhs.y),
        }
    }
}

// The Sub<T, U> trait overloads the + operator: (Self - T = U)
impl<
    // bound: T implements the Add trait
    T: Sub<T, T>
> Sub<Vec2<T>, Vec2<T>>
for Vec2<T> {
    // add() is a required method of the Add trait
    fn sub(&self, rhs: &Vec2<T>) -> Vec2<T> {
        Vec2 {
            // x and y are of type T, and implement the add() method
            x: self.x.sub(&rhs.x),
            y: self.x.sub(&rhs.y),
        }
    }
}

impl<
    // bound: T implements the Add trait and the Mul trait
    T: Add<T, T> + Mul<T, T>
> Vec2<T> {
    fn dot(&self, rhs: &Vec2<T>) -> T {
        self.x.mul(&rhs.x).add(&self.y.mul(&rhs.y))
    }
}

fn main() {
    let v1 = Vec2 { x: 1.0, y: 2.0 };
    let v2 = Vec2 { x: 2.0, y: 1.0 };

    println!("{} + {} = {}", v1, v2, v1 + v2);
    println!("{} - {} = {}", v1, v2, v1 - v2);
    println!("{} . {} = {}", v1, v2, v1.dot(&v2));
}
<commit_msg>update bounds.rs, fix comment<commit_after>#[deriving(Show)]
struct Vec2<T> {
    x: T,
    y: T,
}

// The Add<T, U> trait overloads the + operator: (Self + T = U)
impl<
    // bound: T implements the Add trait
    T: Add<T, T>
> Add<Vec2<T>, Vec2<T>>
for Vec2<T> {
    // add() is a required method of the Add trait
    fn add(&self, rhs: &Vec2<T>) -> Vec2<T> {
        Vec2 {
            // x and y are of type T, and implement the add() method
            x: self.x.add(&rhs.x),
            y: self.x.add(&rhs.y),
        }
    }
}

// The Sub<T, U> trait overloads the - operator: (Self - T = U)
impl<
    // bound: T implements the Sub trait
    T: Sub<T, T>
> Sub<Vec2<T>, Vec2<T>>
for Vec2<T> {
    // sub() is a required method of the Sub trait
    fn sub(&self, rhs: &Vec2<T>) -> Vec2<T> {
        Vec2 {
            // x and y are of type T, and implement the sub() method
            x: self.x.sub(&rhs.x),
            y: self.x.sub(&rhs.y),
        }
    }
}

impl<
    // bound: T implements the Add trait and the Mul trait
    T: Add<T, T> + Mul<T, T>
> Vec2<T> {
    fn dot(&self, rhs: &Vec2<T>) -> T {
        self.x.mul(&rhs.x).add(&self.y.mul(&rhs.y))
    }
}

fn main() {
    let v1 = Vec2 { x: 1.0, y: 2.0 };
    let v2 = Vec2 { x: 2.0, y: 1.0 };

    println!("{} + {} = {}", v1, v2, v1 + v2);
    println!("{} - {} = {}", v1, v2, v1 - v2);
    println!("{} . {} = {}", v1, v2, v1.dot(&v2));
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::old_io::{File, Open, Read, Write};
use std::old_io::IoError;
use std::old_io::IoResult;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;
use super::Cursor;

/// A UTF-8 buffer with bounds-checked cursor management and persistence.
pub struct Buffer {
    data: Rc<RefCell<GapBuffer>>,
    pub path: Option<Path>,
    pub cursor: Cursor,
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn data(&self) -> String {
        self.data.borrow().to_string()
    }

    /// Writes the contents of the buffer to its path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::old_io::{File, Open, Read};
    ///
    /// // Set up a buffer and point it to a path.
    /// let mut buffer = scribe::buffer::new();
    /// let write_path = Path::new("my_doc");
    /// buffer.path = Some(write_path.clone());
    ///
    /// // Put some data into the buffer and save it.
    /// buffer.insert("scribe");
    /// buffer.save();
    ///
    /// # let saved_data = File::open_mode(&write_path, Open, Read)
    /// #   .unwrap().read_to_string().unwrap();
    /// # assert_eq!(saved_data, "scribe");
    ///
    /// # std::old_io::fs::unlink(&write_path);
    /// ```
    pub fn save(&self) -> Option<IoError> {
        let path = match self.path.clone() {
            Some(p) => p,
            None => Path::new(""),
        };

        // Try to open and write to the file, returning any errors encountered.
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(error) => return Some(error),
        };

        // We use to_string here because we don't want to write the gap contents.
        match file.write(self.data().to_string().as_bytes()) {
            Ok(_) => (),
            Err(error) => return Some(error),
        }

        return None
    }

    /// Inserts `data` into the buffer at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn insert(&mut self, data: &str) {
        self.data.borrow_mut().insert(data, &self.cursor);
    }

    /// Deletes a character at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// buffer.delete();
    /// assert_eq!(buffer.data(), "cribe");
    /// ```
    pub fn delete(&mut self) {
        let mut end = self.cursor.clone();
        end.offset += 1;
        self.data.borrow_mut().delete(&Range{ start: *self.cursor, end: end});
    }
}

/// Creates a new empty buffer. The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::new();
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn new() -> Buffer {
    let data = Rc::new(RefCell::new(gap_buffer::new(String::new())));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    Buffer{ data: data.clone(), path: None, cursor: cursor }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
/// The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::from_file(&Path::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn from_file(path: &Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(path, Open, Read) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    let data = Rc::new(RefCell::new(gap_buffer::new(data)));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    // Create a new buffer using the loaded data, path, and other defaults.
    Ok(Buffer{ data: data.clone(), path: Some(path.clone()), cursor: cursor })
}
<commit_msg>Add an optional lexer field to the buffer type.<commit_after>extern crate luthor;

use std::rc::Rc;
use std::cell::RefCell;
use std::old_io::{File, Open, Read, Write};
use std::old_io::IoError;
use std::old_io::IoResult;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;
use super::Cursor;
use self::luthor::token::Token;

/// A UTF-8 buffer with bounds-checked cursor management and persistence.
pub struct Buffer {
    data: Rc<RefCell<GapBuffer>>,
    lexer: Option<fn(&str) -> Vec<Token>>,
    pub path: Option<Path>,
    pub cursor: Cursor,
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn data(&self) -> String {
        self.data.borrow().to_string()
    }

    /// Writes the contents of the buffer to its path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::old_io::{File, Open, Read};
    ///
    /// // Set up a buffer and point it to a path.
    /// let mut buffer = scribe::buffer::new();
    /// let write_path = Path::new("my_doc");
    /// buffer.path = Some(write_path.clone());
    ///
    /// // Put some data into the buffer and save it.
    /// buffer.insert("scribe");
    /// buffer.save();
    ///
    /// # let saved_data = File::open_mode(&write_path, Open, Read)
    /// #   .unwrap().read_to_string().unwrap();
    /// # assert_eq!(saved_data, "scribe");
    ///
    /// # std::old_io::fs::unlink(&write_path);
    /// ```
    pub fn save(&self) -> Option<IoError> {
        let path = match self.path.clone() {
            Some(p) => p,
            None => Path::new(""),
        };

        // Try to open and write to the file, returning any errors encountered.
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(error) => return Some(error),
        };

        // We use to_string here because we don't want to write the gap contents.
        match file.write(self.data().to_string().as_bytes()) {
            Ok(_) => (),
            Err(error) => return Some(error),
        }

        return None
    }

    /// Inserts `data` into the buffer at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn insert(&mut self, data: &str) {
        self.data.borrow_mut().insert(data, &self.cursor);
    }

    /// Deletes a character at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// buffer.delete();
    /// assert_eq!(buffer.data(), "cribe");
    /// ```
    pub fn delete(&mut self) {
        let mut end = self.cursor.clone();
        end.offset += 1;
        self.data.borrow_mut().delete(&Range{ start: *self.cursor, end: end});
    }
}

/// Creates a new empty buffer. The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::new();
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn new() -> Buffer {
    let data = Rc::new(RefCell::new(gap_buffer::new(String::new())));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    Buffer{ data: data.clone(), path: None, cursor: cursor, lexer: None }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
/// The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::from_file(&Path::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn from_file(path: &Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(path, Open, Read) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    let data = Rc::new(RefCell::new(gap_buffer::new(data)));
    let cursor = Cursor{ data: data.clone(), position: Position{ line: 0, offset: 0 }};

    // Create a new buffer using the loaded data, path, and other defaults.
    Ok(Buffer{ data: data.clone(), path: Some(path.clone()), cursor: cursor, lexer: None })
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::rc::Rc;
use std::cell::RefCell;
use super::Position;
use super::GapBuffer;

/// Read-only wrapper for a `Position`, to allow field level access to a
/// buffer's cursor while simultaneously enforcing bounds-checking when
/// updating its value.
pub struct Cursor {
    pub data: Rc<RefCell<GapBuffer>>,
    pub position: Position,
}

impl Deref for Cursor {
    type Target = Position;

    fn deref(&self) -> &Position {
        &self.position
    }
}

impl Cursor {
    /// Moves the cursor to the specified location. The location is
    /// bounds-checked against the data and the cursor will not be
    /// updated if it is out-of-bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// let in_bounds = scribe::buffer::Position{ line: 0, offset: 2 };
    /// let out_of_bounds = scribe::buffer::Position{ line: 2, offset: 2 };
    /// buffer.insert("scribe");
    ///
    /// buffer.cursor.move_to(in_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    ///
    /// buffer.cursor.move_to(out_of_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    /// ```
    pub fn move_to(&mut self, position: Position) -> bool {
        if self.data.borrow().in_bounds(&position) {
            self.position = position;
            return true
        }
        false
    }

    /// Decrements the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    ///
    /// TODO: Make this more efficient by checking the
    /// target line's existence and using its length.
    pub fn move_up(&mut self) {
        let mut moved = false;
        let mut offset = self.offset;
        let mut new_position: Position;

        while moved == false && offset >= 0 {
            new_position = Position{ line: self.line-1, offset: offset };
            moved = self.move_to(new_position);
            offset -= 1;
        }
    }

    /// Increments the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_down(&mut self) {
        let new_position = Position{ line: self.line+1, offset: self.offset };
        self.move_to(new_position);
    }

    /// Decrements the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_left(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset-1 };
        self.move_to(new_position);
    }

    /// Increments the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_right(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset+1 };
        self.move_to(new_position);
    }
}

#[cfg(test)]
mod tests {
    use super::Cursor;
    use super::super::gap_buffer;
    use super::super::Position;
    use std::rc::Rc;
    use std::cell::RefCell;

    #[test]
    fn move_up_goes_to_EOL_if_offset_would_be_out_of_range() {
        let mut buffer = Rc::new(RefCell::new(gap_buffer::new("This is a test.\nAnother line that is longer.".to_string())));
        let position = Position{ line: 1, offset: 20 };
        let mut cursor = Cursor{ data: buffer, position: position };
        cursor.move_up();
        assert_eq!(cursor.line, 0);
        assert_eq!(cursor.offset, 15);
    }
}
<commit_msg>Improve to-EOL upward movement efficiency.<commit_after>use std::ops::Deref;
use std::rc::Rc;
use std::cell::RefCell;
use super::Position;
use super::GapBuffer;

/// Read-only wrapper for a `Position`, to allow field level access to a
/// buffer's cursor while simultaneously enforcing bounds-checking when
/// updating its value.
pub struct Cursor {
    pub data: Rc<RefCell<GapBuffer>>,
    pub position: Position,
}

impl Deref for Cursor {
    type Target = Position;

    fn deref(&self) -> &Position {
        &self.position
    }
}

impl Cursor {
    /// Moves the cursor to the specified location. The location is
    /// bounds-checked against the data and the cursor will not be
    /// updated if it is out-of-bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// let in_bounds = scribe::buffer::Position{ line: 0, offset: 2 };
    /// let out_of_bounds = scribe::buffer::Position{ line: 2, offset: 2 };
    /// buffer.insert("scribe");
    ///
    /// buffer.cursor.move_to(in_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    ///
    /// buffer.cursor.move_to(out_of_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    /// ```
    pub fn move_to(&mut self, position: Position) -> bool {
        if self.data.borrow().in_bounds(&position) {
            self.position = position;
            return true
        }
        false
    }

    /// Decrements the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_up(&mut self) {
        let target_line = self.line-1;
        let mut new_position = Position{ line: target_line, offset: self.offset };

        // Try moving to the same offset on the line above, falling back to its EOL.
        if self.move_to(new_position) == false {
            let mut target_offset = 0;
            for (line_number, line) in self.data.borrow().to_string().lines().enumerate() {
                if line_number == target_line {
                    target_offset = line.len();
                }
            }
            self.move_to(Position{ line: target_line, offset: target_offset });
        }
    }

    /// Increments the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_down(&mut self) {
        let new_position = Position{ line: self.line+1, offset: self.offset };
        self.move_to(new_position);
    }

    /// Decrements the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_left(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset-1 };
        self.move_to(new_position);
    }

    /// Increments the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_right(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset+1 };
        self.move_to(new_position);
    }
}

#[cfg(test)]
mod tests {
    use super::Cursor;
    use super::super::gap_buffer;
    use super::super::Position;
    use std::rc::Rc;
    use std::cell::RefCell;

    #[test]
    fn move_up_goes_to_EOL_if_offset_would_be_out_of_range() {
        let mut buffer = Rc::new(RefCell::new(gap_buffer::new("This is a test.\nAnother line that is longer.".to_string())));
        let position = Position{ line: 1, offset: 20 };
        let mut cursor = Cursor{ data: buffer, position: position };
        cursor.move_up();
        assert_eq!(cursor.line, 0);
        assert_eq!(cursor.offset, 15);
    }
}
<|endoftext|>


<commit_before>use std::mem;

use bytes::{Bytes, BytesMut};
use futures::{Async, Poll};
use http::header::{self, HeaderName, HeaderValue};
use http::{HeaderMap, StatusCode, Version};
use httparse;

use error::{ParseError, PayloadError};

use server::h1decoder::{EncodingDecoder, HeaderIndex};
use server::IoStream;

use super::response::ClientMessage;
use super::ClientResponse;

const MAX_BUFFER_SIZE: usize = 131_072;
const MAX_HEADERS: usize = 96;

#[derive(Default)]
pub struct HttpResponseParser {
    decoder: Option<EncodingDecoder>,
}

#[derive(Debug, Fail)]
pub enum HttpResponseParserError {
    /// Server disconnected
    #[fail(display = "Server disconnected")]
    Disconnect,
    #[fail(display = "{}", _0)]
    Error(#[cause] ParseError),
}

impl HttpResponseParser {
    pub fn parse<T>(
        &mut self, io: &mut T, buf: &mut BytesMut,
    ) -> Poll<ClientResponse, HttpResponseParserError>
    where
        T: IoStream,
    {
        // if buf is empty parse_message will always return NotReady, let's avoid that
        if buf.is_empty() {
            match io.read_available(buf) {
                Ok(Async::Ready((true, true))) => (),
                Ok(Async::Ready((false, true))) => {
                    return Err(HttpResponseParserError::Disconnect)
                }
                Ok(Async::Ready((_, false))) => (),
                Ok(Async::NotReady) => return Ok(Async::NotReady),
                Err(err) => return Err(HttpResponseParserError::Error(err.into())),
            }
        }

        loop {
            match HttpResponseParser::parse_message(buf)
                .map_err(HttpResponseParserError::Error)?
            {
                Async::Ready((msg, decoder)) => {
                    self.decoder = decoder;
                    return Ok(Async::Ready(msg));
                }
                Async::NotReady => {
                    if buf.capacity() >= MAX_BUFFER_SIZE {
                        return Err(HttpResponseParserError::Error(ParseError::TooLarge));
                    }
                    match io.read_available(buf) {
                        Ok(Async::Ready((true, true))) => (),
                        Ok(Async::Ready((false, true))) => {
                            return Err(HttpResponseParserError::Disconnect)
                        }
                        Ok(Async::Ready((_, false))) => (),
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(err) => {
                            return Err(HttpResponseParserError::Error(err.into()))
                        }
                    }
                }
            }
        }
    }

    pub fn parse_payload<T>(
        &mut self, io: &mut T, buf: &mut BytesMut,
    ) -> Poll<Option<Bytes>, PayloadError>
    where
        T: IoStream,
    {
        if self.decoder.is_some() {
            loop {
                // read payload
                let (not_ready, stream_finished) = match io.read_available(buf) {
                    Ok(Async::Ready((_, true))) => (false, true),
                    Ok(Async::Ready((_, false))) => (false, false),
                    Ok(Async::NotReady) => (true, false),
                    Err(err) => return Err(err.into()),
                };

                match self.decoder.as_mut().unwrap().decode(buf) {
                    Ok(Async::Ready(Some(b))) => return Ok(Async::Ready(Some(b))),
                    Ok(Async::Ready(None)) => {
                        self.decoder.take();
                        return Ok(Async::Ready(None));
                    }
                    Ok(Async::NotReady) => {
                        if not_ready {
                            return Ok(Async::NotReady);
                        }
                        if stream_finished {
                            return Err(PayloadError::Incomplete);
                        }
                    }
                    Err(err) => return Err(err.into()),
                }
            }
        } else {
            Ok(Async::Ready(None))
        }
    }

    fn parse_message(
        buf: &mut BytesMut,
    ) -> Poll<(ClientResponse, Option<EncodingDecoder>), ParseError> {
        // Unsafe: we read only this data only after httparse parses headers into.
        // performance bump for pipeline benchmarks.
        let mut headers: [HeaderIndex; MAX_HEADERS] = unsafe { mem::uninitialized() };

        let (len, version, status, headers_len) = {
            let mut parsed: [httparse::Header; MAX_HEADERS] =
                unsafe { mem::uninitialized() };

            let mut resp = httparse::Response::new(&mut parsed);
            match resp.parse(buf)? {
                httparse::Status::Complete(len) => {
                    let version = if resp.version.unwrap_or(1) == 1 {
                        Version::HTTP_11
                    } else {
                        Version::HTTP_10
                    };
                    HeaderIndex::record(buf, resp.headers, &mut headers);
                    let status = StatusCode::from_u16(resp.code.unwrap())
                        .map_err(|_| ParseError::Status)?;

                    (len, version, status, resp.headers.len())
                }
                httparse::Status::Partial => return Ok(Async::NotReady),
            }
        };

        let slice = buf.split_to(len).freeze();

        // convert headers
        let mut hdrs = HeaderMap::new();
        for idx in headers[..headers_len].iter() {
            if let Ok(name) = HeaderName::from_bytes(&slice[idx.name.0..idx.name.1]) {
                // Unsafe: httparse check header value for valid utf-8
                let value = unsafe {
                    HeaderValue::from_shared_unchecked(
                        slice.slice(idx.value.0, idx.value.1),
                    )
                };
                hdrs.append(name, value);
            } else {
                return Err(ParseError::Header);
            }
        }

        let decoder = if status == StatusCode::SWITCHING_PROTOCOLS {
            Some(EncodingDecoder::eof())
        } else if let Some(len) = hdrs.get(header::CONTENT_LENGTH) {
            // Content-Length
            if let Ok(s) = len.to_str() {
                if let Ok(len) = s.parse::<u64>() {
                    Some(EncodingDecoder::length(len))
                } else {
                    debug!("illegal Content-Length: {:?}", len);
                    return Err(ParseError::Header);
                }
            } else {
                debug!("illegal Content-Length: {:?}", len);
                return Err(ParseError::Header);
            }
        } else if chunked(&hdrs)? {
            // Chunked encoding
            Some(EncodingDecoder::chunked())
        } else {
            None
        };

        if let Some(decoder) = decoder {
            Ok(Async::Ready((
                ClientResponse::new(ClientMessage {
                    status,
                    version,
                    headers: hdrs,
                    cookies: None,
                }),
                Some(decoder),
            )))
        } else {
            Ok(Async::Ready((
                ClientResponse::new(ClientMessage {
                    status,
                    version,
                    headers: hdrs,
                    cookies: None,
                }),
                None,
            )))
        }
    }
}

/// Check if request has chunked transfer encoding
pub fn chunked(headers: &HeaderMap) -> Result<bool, ParseError> {
    if let Some(encodings) = headers.get(header::TRANSFER_ENCODING) {
        if let Ok(s) = encodings.to_str() {
            Ok(s.to_lowercase().contains("chunked"))
        } else {
            Err(ParseError::Header)
        }
    } else {
        Ok(false)
    }
}
<commit_msg>Simplify buffer reading logic.  Remove duplicate code.<commit_after>use std::mem;

use bytes::{Bytes, BytesMut};
use futures::{Async, Poll};
use http::header::{self, HeaderName, HeaderValue};
use http::{HeaderMap, StatusCode, Version};
use httparse;

use error::{ParseError, PayloadError};

use server::h1decoder::{EncodingDecoder, HeaderIndex};
use server::IoStream;

use super::response::ClientMessage;
use super::ClientResponse;

const MAX_BUFFER_SIZE: usize = 131_072;
const MAX_HEADERS: usize = 96;

#[derive(Default)]
pub struct HttpResponseParser {
    decoder: Option<EncodingDecoder>,
}

#[derive(Debug, Fail)]
pub enum HttpResponseParserError {
    /// Server disconnected
    #[fail(display = "Server disconnected")]
    Disconnect,
    #[fail(display = "{}", _0)]
    Error(#[cause] ParseError),
}

impl HttpResponseParser {
    pub fn parse<T>(
        &mut self, io: &mut T, buf: &mut BytesMut,
    ) -> Poll<ClientResponse, HttpResponseParserError>
    where
        T: IoStream,
    {
        loop {
            match io.read_available(buf) {
                Ok(Async::Ready((false, true))) => {
                    return Err(HttpResponseParserError::Disconnect)
                }
                Ok(Async::Ready(_)) => (),
                Ok(Async::NotReady) => return Ok(Async::NotReady),
                Err(err) => {
                    return Err(HttpResponseParserError::Error(err.into()))
                }
            }
            match HttpResponseParser::parse_message(buf)
                .map_err(HttpResponseParserError::Error)?
            {
                Async::Ready((msg, decoder)) => {
                    self.decoder = decoder;
                    return Ok(Async::Ready(msg));
                }
                Async::NotReady => {
                    if buf.capacity() >= MAX_BUFFER_SIZE {
                        return Err(HttpResponseParserError::Error(ParseError::TooLarge));
                    }
                }
            }
        }
    }

    pub fn parse_payload<T>(
        &mut self, io: &mut T, buf: &mut BytesMut,
    ) -> Poll<Option<Bytes>, PayloadError>
    where
        T: IoStream,
    {
        if self.decoder.is_some() {
            loop {
                // read payload
                let (not_ready, stream_finished) = match io.read_available(buf) {
                    Ok(Async::Ready((_, true))) => (false, true),
                    Ok(Async::Ready((_, false))) => (false, false),
                    Ok(Async::NotReady) => (true, false),
                    Err(err) => return Err(err.into()),
                };

                match self.decoder.as_mut().unwrap().decode(buf) {
                    Ok(Async::Ready(Some(b))) => return Ok(Async::Ready(Some(b))),
                    Ok(Async::Ready(None)) => {
                        self.decoder.take();
                        return Ok(Async::Ready(None));
                    }
                    Ok(Async::NotReady) => {
                        if not_ready {
                            return Ok(Async::NotReady);
                        }
                        if stream_finished {
                            return Err(PayloadError::Incomplete);
                        }
                    }
                    Err(err) => return Err(err.into()),
                }
            }
        } else {
            Ok(Async::Ready(None))
        }
    }

    fn parse_message(
        buf: &mut BytesMut,
    ) -> Poll<(ClientResponse, Option<EncodingDecoder>), ParseError> {
        // Unsafe: we read only this data only after httparse parses headers into.
        // performance bump for pipeline benchmarks.
        let mut headers: [HeaderIndex; MAX_HEADERS] = unsafe { mem::uninitialized() };

        let (len, version, status, headers_len) = {
            let mut parsed: [httparse::Header; MAX_HEADERS] =
                unsafe { mem::uninitialized() };

            let mut resp = httparse::Response::new(&mut parsed);
            match resp.parse(buf)? {
                httparse::Status::Complete(len) => {
                    let version = if resp.version.unwrap_or(1) == 1 {
                        Version::HTTP_11
                    } else {
                        Version::HTTP_10
                    };
                    HeaderIndex::record(buf, resp.headers, &mut headers);
                    let status = StatusCode::from_u16(resp.code.unwrap())
                        .map_err(|_| ParseError::Status)?;

                    (len, version, status, resp.headers.len())
                }
                httparse::Status::Partial => return Ok(Async::NotReady),
            }
        };

        let slice = buf.split_to(len).freeze();

        // convert headers
        let mut hdrs = HeaderMap::new();
        for idx in headers[..headers_len].iter() {
            if let Ok(name) = HeaderName::from_bytes(&slice[idx.name.0..idx.name.1]) {
                // Unsafe: httparse check header value for valid utf-8
                let value = unsafe {
                    HeaderValue::from_shared_unchecked(
                        slice.slice(idx.value.0, idx.value.1),
                    )
                };
                hdrs.append(name, value);
            } else {
                return Err(ParseError::Header);
            }
        }

        let decoder = if status == StatusCode::SWITCHING_PROTOCOLS {
            Some(EncodingDecoder::eof())
        } else if let Some(len) = hdrs.get(header::CONTENT_LENGTH) {
            // Content-Length
            if let Ok(s) = len.to_str() {
                if let Ok(len) = s.parse::<u64>() {
                    Some(EncodingDecoder::length(len))
                } else {
                    debug!("illegal Content-Length: {:?}", len);
                    return Err(ParseError::Header);
                }
            } else {
                debug!("illegal Content-Length: {:?}", len);
                return Err(ParseError::Header);
            }
        } else if chunked(&hdrs)? {
            // Chunked encoding
            Some(EncodingDecoder::chunked())
        } else {
            None
        };

        if let Some(decoder) = decoder {
            Ok(Async::Ready((
                ClientResponse::new(ClientMessage {
                    status,
                    version,
                    headers: hdrs,
                    cookies: None,
                }),
                Some(decoder),
            )))
        } else {
            Ok(Async::Ready((
                ClientResponse::new(ClientMessage {
                    status,
                    version,
                    headers: hdrs,
                    cookies: None,
                }),
                None,
            )))
        }
    }
}

/// Check if request has chunked transfer encoding
pub fn chunked(headers: &HeaderMap) -> Result<bool, ParseError> {
    if let Some(encodings) = headers.get(header::TRANSFER_ENCODING) {
        if let Ok(s) = encodings.to_str() {
            Ok(s.to_lowercase().contains("chunked"))
        } else {
            Err(ParseError::Header)
        }
    } else {
        Ok(false)
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use libc::c_ulonglong;
use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMValueRef,
  LLVMContextRef
};
use types::LLVMTy;

#[derive(Copy, Clone)]
pub struct Value(pub LLVMValueRef);
impl_display!(Value, LLVMPrintValueToString);

pub trait ToValue {
	/// Transform this value into a constant in the context given.
  fn to_value(self, ctx: LLVMContextRef) -> Value;
}

macro_rules! int_to_value (
  ($ty:ty) => (
    impl ToValue for $ty {
      fn to_value(self, ctx: LLVMContextRef) -> Value
      {
        Value(unsafe { core::LLVMConstInt(Self::llvm_ty(ctx).as_ptr(), self as c_ulonglong, 0) })
      }
    }
  );
);

int_to_value!{i8}
int_to_value!{u8}
int_to_value!{i16}
int_to_value!{u16}
int_to_value!{i32}
int_to_value!{u32}
int_to_value!{i64}
int_to_value!{u64}
int_to_value!{usize}
int_to_value!{isize}

impl ToValue for f32 {
  fn to_value(self, ctx: LLVMContextRef) -> Value
  {
    Value(unsafe{core::LLVMConstReal(Self::llvm_ty(ctx).as_ptr(), self as f64)})
  }
}

impl ToValue for f64 {
  fn to_value(self, ctx: LLVMContextRef) -> Value
  {
    Value(unsafe{core::LLVMConstReal(Self::llvm_ty(ctx).as_ptr(), self)})
  }
}

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

	#[test]
	pub fn test_values()
	{
    let jit = JitCompiler::new("test").ok().unwrap();

    assert_eq!( "i8 1", format!("{}", 1i8.to_value(jit.context())));
    assert_eq!( "i8 1", format!("{}", 1u8.to_value(jit.context())));
    assert_eq!("i16 1", format!("{}", 1i16.to_value(jit.context())));
    assert_eq!("i16 1", format!("{}", 1u16.to_value(jit.context())));
    assert_eq!("i32 1", format!("{}", 1i32.to_value(jit.context())));
    assert_eq!("i32 1", format!("{}", 1u32.to_value(jit.context())));
    assert_eq!("i64 1", format!("{}", 1i64.to_value(jit.context())));
    assert_eq!("i64 1", format!("{}", 1u64.to_value(jit.context())));
    assert_eq!("i64 1", format!("{}", 1isize.to_value(jit.context())));
    assert_eq!("i64 1", format!("{}", 1usize.to_value(jit.context())));

    assert_eq!("float 1.000000e+00", format!("{}", 1f32.to_value(jit.context())));
    assert_eq!("double 1.000000e+00", format!("{}", 1f64.to_value(jit.context())));
	}
}<commit_msg>Add phi node to value.rs.<commit_after>#![allow(dead_code)]
use std::fmt;

use libc::c_ulonglong;
use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMValueRef,
  LLVMContextRef
};

use types::LLVMTy;
use block::BasicBlock;

#[derive(Copy, Clone)]
pub struct Value(pub LLVMValueRef);
impl_display!(Value, LLVMPrintValueToString);

pub trait ToValue {
	/// Transform this value into a constant in the context given.
  fn to_value(self, ctx: LLVMContextRef) -> Value;
}

macro_rules! int_to_value (
  ($ty:ty) => (
    impl ToValue for $ty {
      fn to_value(self, ctx: LLVMContextRef) -> Value
      {
        Value(unsafe { core::LLVMConstInt(Self::llvm_ty(ctx).as_ptr(), self as c_ulonglong, 0) })
      }
    }
  );
);

int_to_value!{i8}
int_to_value!{u8}
int_to_value!{i16}
int_to_value!{u16}
int_to_value!{i32}
int_to_value!{u32}
int_to_value!{i64}
int_to_value!{u64}
int_to_value!{usize}
int_to_value!{isize}

impl ToValue for f32 {
  fn to_value(self, ctx: LLVMContextRef) -> Value
  {
    Value(unsafe{core::LLVMConstReal(Self::llvm_ty(ctx).as_ptr(), self as f64)})
  }
}

impl ToValue for f64 {
  fn to_value(self, ctx: LLVMContextRef) -> Value
  {
    Value(unsafe{core::LLVMConstReal(Self::llvm_ty(ctx).as_ptr(), self)})
  }
}

/// A PHI node represents a value which is selected based on the predecessor of the current block.
pub struct PhiNode(pub LLVMValueRef);
impl_display!(PhiNode, LLVMPrintValueToString);

impl PhiNode {
  /// Adds an incoming value to the end of this PHI node.
  pub fn add_incoming(&self, val: &Value, block: &BasicBlock) {
    let mut values = vec![val.0];
    let mut blocks = vec![block.0];
    unsafe { core::LLVMAddIncoming(self.0, values.as_mut_ptr(), blocks.as_mut_ptr(), 1) }
  }

  /// Counts the number of incoming values attached to this PHI node.
  pub fn count_incoming(&self) -> u32 {
    unsafe { core::LLVMCountIncoming(self.0) }
  }

  /// Gets an incoming value from this PHI node from a specific index.
  pub fn get_incoming_value(&self, index: u32) -> Value {
    Value(unsafe { core::LLVMGetIncomingValue(self.0, index) })
  }

  /// Gets an incoming basic block from this PHI node from a specific index.
  pub fn get_incoming_block(&self, index: u32) -> BasicBlock {
    BasicBlock(unsafe { core::LLVMGetIncomingBlock(self.0, index)})
  }
}

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

	#[test]
	pub fn test_values()
	{
    let jit = JitCompiler::new("test").ok().unwrap();

    assert_eq!( "i8 1", format!("{}", 1i8.to_value(jit.context())));
    assert_eq!( "i8 1", format!("{}", 1u8.to_value(jit.context())));
    assert_eq!("i16 1", format!("{}", 1i16.to_value(jit.context())));
    assert_eq!("i16 1", format!("{}", 1u16.to_value(jit.context())));
    assert_eq!("i32 1", format!("{}", 1i32.to_value(jit.context())));
    assert_eq!("i32 1", format!("{}", 1u32.to_value(jit.context())));
    assert_eq!("i64 1", format!("{}", 1i64.to_value(jit.context())));
    assert_eq!("i64 1", format!("{}", 1u64.to_value(jit.context())));
    assert_eq!("i64 1", format!("{}", 1isize.to_value(jit.context())));
    assert_eq!("i64 1", format!("{}", 1usize.to_value(jit.context())));

    assert_eq!("float 1.000000e+00", format!("{}", 1f32.to_value(jit.context())));
    assert_eq!("double 1.000000e+00", format!("{}", 1f64.to_value(jit.context())));
	}
}<|endoftext|>


<commit_before>
use {
    AddEllipse,
    AddPolygon,
    AddRectangle,
    AddTween,
    BackEnd,
    Borrowed,
    Clear,
    Color,
    EllipseColorContext,
    Field,
    Matrix2d,
    PolygonColorContext,
    RectangleColorContext,
    TweenColorContext,
    View,
    Value,
};
use vecmath::{
    identity,
};
use internal::{
    CanColor,
    CanTransform,
    HasColor,
    HasTransform,
};

/// A context with color information.
pub struct ColorContext<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> HasTransform<'a, Matrix2d> for ColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, ColorContext<'a>, Matrix2d> for ColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasColor<'a, Color> for ColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, ColorContext<'a>, Color> for ColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
        }
    }
}

impl<'a> AddRectangle<'a, RectangleColorContext<'a>> for ColorContext<'a> {
    #[inline(always)]
    fn rect(&'a self, x: f64, y: f64, w: f64, h: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

#[test]
fn test_rect() {
    use {Context, AddColor};

    let c = Context::new();
    let color = c.rgba(1.0, 0.0, 0.0, 1.0);
    let rect_color = color.rect(0.0, 0.0, 100.0, 100.0);
    assert_eq!(rect_color.rect.get()[2], 100.0);
}

impl<'a> AddEllipse<'a, EllipseColorContext<'a>> for ColorContext<'a> {
    #[inline(always)]
    fn ellipse(&'a self, x: f64, y: f64, w: f64, h: f64) -> EllipseColorContext<'a> {
        EllipseColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

impl<'a> AddPolygon<'a, PolygonColorContext<'a>> for ColorContext<'a> {
    #[inline(always)]
    fn polygon(&'a self, polygon: &'a [f64]) -> PolygonColorContext<'a> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            polygon: Value(polygon),
        }
    }
}

impl<'a> AddTween<'a, TweenColorContext<'a>> for ColorContext<'a> {
    #[inline(always)]
    fn lerp(&'a self, tween_factor: f64) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Value(tween_factor),
        }
    }
}

impl<'a> Clear for ColorContext<'a> {
    fn clear<B: BackEnd>(&self, back_end: &mut B) {
        if back_end.supports_clear_rgba() {
            let color = self.color.get();
            back_end.clear_rgba(color[0], color[1], color[2], color[3]);
        }
    }
}

impl<'a> View<'a> for ColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

<commit_msg>Implemented `AddImage` for `ColorContext`<commit_after>
use {
    AddEllipse,
    AddImage,
    AddPolygon,
    AddRectangle,
    AddTween,
    BackEnd,
    Borrowed,
    Clear,
    Color,
    EllipseColorContext,
    Field,
    Image,
    ImageRectangleColorContext,
    Matrix2d,
    PolygonColorContext,
    RectangleColorContext,
    TweenColorContext,
    View,
    Value,
};
use vecmath::{
    identity,
};
use internal::{
    CanColor,
    CanTransform,
    HasColor,
    HasTransform,
};

/// A context with color information.
pub struct ColorContext<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> HasTransform<'a, Matrix2d> for ColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, ColorContext<'a>, Matrix2d> for ColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasColor<'a, Color> for ColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, ColorContext<'a>, Color> for ColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
        }
    }
}

impl<'a> AddRectangle<'a, RectangleColorContext<'a>> for ColorContext<'a> {
    #[inline(always)]
    fn rect(&'a self, x: f64, y: f64, w: f64, h: f64) -> RectangleColorContext<'a> {
        RectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

#[test]
fn test_rect() {
    use {Context, AddColor};

    let c = Context::new();
    let color = c.rgba(1.0, 0.0, 0.0, 1.0);
    let rect_color = color.rect(0.0, 0.0, 100.0, 100.0);
    assert_eq!(rect_color.rect.get()[2], 100.0);
}

impl<'a> AddEllipse<'a, EllipseColorContext<'a>> for ColorContext<'a> {
    #[inline(always)]
    fn ellipse(&'a self, x: f64, y: f64, w: f64, h: f64) -> EllipseColorContext<'a> {
        EllipseColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

impl<'a> AddPolygon<'a, PolygonColorContext<'a>> for ColorContext<'a> {
    #[inline(always)]
    fn polygon(&'a self, polygon: &'a [f64]) -> PolygonColorContext<'a> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            polygon: Value(polygon),
        }
    }
}

impl<'a> AddTween<'a, TweenColorContext<'a>> for ColorContext<'a> {
    #[inline(always)]
    fn lerp(&'a self, tween_factor: f64) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Value(tween_factor),
        }
    }
}

impl<'a> Clear for ColorContext<'a> {
    fn clear<B: BackEnd>(&self, back_end: &mut B) {
        if back_end.supports_clear_rgba() {
            let color = self.color.get();
            back_end.clear_rgba(color[0], color[1], color[2], color[3]);
        }
    }
}

impl<'a> View<'a> for ColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> AddImage<'a, ImageRectangleColorContext<'a>> for ColorContext<'a> {
    #[inline(always)]
    fn image(&'a self, image: Image) -> ImageRectangleColorContext<'a> {
        ImageRectangleColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value([0.0, 0.0, image.source_rect[2] as f64, image.source_rect[3] as f64]),
            image: Value(image),
            color: Borrowed(self.color.get()),
        }
    }
}

<|endoftext|>


<commit_before>//! This modules takes care of rendering various definitions as completion items.
use hir::{Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
use join_to_string::join;
use ra_syntax::ast::NameOwner;
use test_utils::tested_by;

use crate::completion::{
    CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
};

use crate::display::{const_label, function_label, macro_label, type_label};

impl Completions {
    pub(crate) fn add_field(
        &mut self,
        ctx: &CompletionContext,
        field: hir::StructField,
        substs: &hir::Substs,
    ) {
        CompletionItem::new(
            CompletionKind::Reference,
            ctx.source_range(),
            field.name(ctx.db).to_string(),
        )
        .kind(CompletionItemKind::Field)
        .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string())
        .set_documentation(field.docs(ctx.db))
        .add_to(self);
    }

    pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) {
        CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
            .kind(CompletionItemKind::Field)
            .detail(ty.display(ctx.db).to_string())
            .add_to(self);
    }

    pub(crate) fn add_resolution(
        &mut self,
        ctx: &CompletionContext,
        local_name: String,
        resolution: &ScopeDef,
    ) {
        use hir::ModuleDef::*;

        // if let Some(macro_) = resolution.get_macros() {
        //     self.add_macro(ctx, Some(local_name.clone()), macro_);
        // }

        // let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
        // let def = match def {
        //     // Only insert once if it is just a macro name
        //     None if resolution.get_macros().is_some() => return,
        //     None => {
        //         self.add(CompletionItem::new(
        //             CompletionKind::Reference,
        //             ctx.source_range(),
        //             local_name,
        //         ));
        //         return;
        //     }
        //     Some(it) => it,
        // };
        let mut completion_kind = CompletionKind::Reference;
        let (kind, docs) = match resolution {
            ScopeDef::ModuleDef(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
            ScopeDef::ModuleDef(Function(func)) => {
                return self.add_function_with_name(ctx, Some(local_name), *func);
            }
            ScopeDef::ModuleDef(Adt(hir::Adt::Struct(it))) => {
                (CompletionItemKind::Struct, it.docs(ctx.db))
            }
            ScopeDef::ModuleDef(Adt(hir::Adt::Union(it))) => {
                (CompletionItemKind::Struct, it.docs(ctx.db))
            }
            ScopeDef::ModuleDef(Adt(hir::Adt::Enum(it))) => {
                (CompletionItemKind::Enum, it.docs(ctx.db))
            }
            ScopeDef::ModuleDef(EnumVariant(it)) => {
                (CompletionItemKind::EnumVariant, it.docs(ctx.db))
            }
            ScopeDef::ModuleDef(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
            ScopeDef::ModuleDef(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
            ScopeDef::ModuleDef(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
            ScopeDef::ModuleDef(TypeAlias(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
            ScopeDef::ModuleDef(BuiltinType(..)) => {
                completion_kind = CompletionKind::BuiltinType;
                (CompletionItemKind::BuiltinType, None)
            }
            ScopeDef::GenericParam(..) => (CompletionItemKind::TypeParam, None),
            ScopeDef::LocalBinding(..) => (CompletionItemKind::Binding, None),
            ScopeDef::SelfType(..) => (
                CompletionItemKind::TypeParam, // (does this need its own kind?)
                None,
            ),
            ScopeDef::MacroDef(mac) => {
                self.add_macro(ctx, Some(local_name.clone()), *mac);
                return;
            }
            ScopeDef::Unknown => {
                self.add(CompletionItem::new(
                    CompletionKind::Reference,
                    ctx.source_range(),
                    local_name,
                ));
                return;
            }
        };

        let mut completion_item =
            CompletionItem::new(completion_kind, ctx.source_range(), local_name);
        if let ScopeDef::LocalBinding(pat_id) = resolution {
            let ty = ctx
                .analyzer
                .type_of_pat_by_id(ctx.db, pat_id.clone())
                .filter(|t| t != &Ty::Unknown)
                .map(|t| t.display(ctx.db).to_string());
            completion_item = completion_item.set_detail(ty);
        };
        completion_item.kind(kind).set_documentation(docs).add_to(self)
    }

    pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) {
        self.add_function_with_name(ctx, None, func)
    }

    pub(crate) fn add_macro(
        &mut self,
        ctx: &CompletionContext,
        name: Option<String>,
        macro_: hir::MacroDef,
    ) {
        let ast_node = macro_.source(ctx.db).ast;
        if let Some(name) = name {
            let detail = macro_label(&ast_node);

            let macro_braces_to_insert = match name.as_str() {
                "vec" => "[$0]",
                _ => "($0)",
            };
            let macro_declaration = name + "!";

            let builder = CompletionItem::new(
                CompletionKind::Reference,
                ctx.source_range(),
                &macro_declaration,
            )
            .kind(CompletionItemKind::Macro)
            .set_documentation(macro_.docs(ctx.db))
            .detail(detail)
            .insert_snippet(macro_declaration + macro_braces_to_insert);

            self.add(builder);
        }
    }

    fn add_function_with_name(
        &mut self,
        ctx: &CompletionContext,
        name: Option<String>,
        func: hir::Function,
    ) {
        let data = func.data(ctx.db);
        let name = name.unwrap_or_else(|| data.name().to_string());
        let ast_node = func.source(ctx.db).ast;
        let detail = function_label(&ast_node);

        let mut builder = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name)
            .kind(if data.has_self_param() {
                CompletionItemKind::Method
            } else {
                CompletionItemKind::Function
            })
            .set_documentation(func.docs(ctx.db))
            .detail(detail);
        // If not an import, add parenthesis automatically.
        if ctx.use_item_syntax.is_none()
            && !ctx.is_call
            && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
        {
            tested_by!(inserts_parens_for_function_calls);
            let snippet =
                if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 {
                    format!("{}()$0", data.name())
                } else {
                    format!("{}($0)", data.name())
                };
            builder = builder.insert_snippet(snippet);
        }
        self.add(builder)
    }

    pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
        let ast_node = constant.source(ctx.db).ast;
        let name = match ast_node.name() {
            Some(name) => name,
            _ => return,
        };
        let detail = const_label(&ast_node);

        CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
            .kind(CompletionItemKind::Const)
            .set_documentation(constant.docs(ctx.db))
            .detail(detail)
            .add_to(self);
    }

    pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
        let type_def = type_alias.source(ctx.db).ast;
        let name = match type_def.name() {
            Some(name) => name,
            _ => return,
        };
        let detail = type_label(&type_def);

        CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
            .kind(CompletionItemKind::TypeAlias)
            .set_documentation(type_alias.docs(ctx.db))
            .detail(detail)
            .add_to(self);
    }

    pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
        let name = match variant.name(ctx.db) {
            Some(it) => it,
            None => return,
        };
        let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
        let detail = join(detail_types.map(|t| t.display(ctx.db).to_string()))
            .separator(", ")
            .surround_with("(", ")")
            .to_string();

        CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
            .kind(CompletionItemKind::EnumVariant)
            .set_documentation(variant.docs(ctx.db))
            .detail(detail)
            .add_to(self);
    }
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;
    use test_utils::covers;

    fn do_reference_completion(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Reference)
    }

    #[test]
    fn inserts_parens_for_function_calls() {
        covers!(inserts_parens_for_function_calls);
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn no_args() {}
                fn main() { no_<|> }
                "
            ),
            @r###"[
    CompletionItem {
        label: "main",
        source_range: [61; 64),
        delete: [61; 64),
        insert: "main()$0",
        kind: Function,
        detail: "fn main()",
    },
    CompletionItem {
        label: "no_args",
        source_range: [61; 64),
        delete: [61; 64),
        insert: "no_args()$0",
        kind: Function,
        detail: "fn no_args()",
    },
]"###
        );
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn with_args(x: i32, y: String) {}
                fn main() { with_<|> }
                "
            ),
            @r###"[
    CompletionItem {
        label: "main",
        source_range: [80; 85),
        delete: [80; 85),
        insert: "main()$0",
        kind: Function,
        detail: "fn main()",
    },
    CompletionItem {
        label: "with_args",
        source_range: [80; 85),
        delete: [80; 85),
        insert: "with_args($0)",
        kind: Function,
        detail: "fn with_args(x: i32, y: String)",
    },
]"###
        );
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                struct S {}
                impl S {
                    fn foo(&self) {}
                }
                fn bar(s: &S) {
                    s.f<|>
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "foo",
        source_range: [163; 164),
        delete: [163; 164),
        insert: "foo()$0",
        kind: Method,
        detail: "fn foo(&self)",
    },
]"###
        );
    }

    #[test]
    fn dont_render_function_parens_in_use_item() {
        assert_debug_snapshot!(
            do_reference_completion(
                "
                //- /lib.rs
                mod m { pub fn foo() {} }
                use crate::m::f<|>;
                "
            ),
            @r#"[
    CompletionItem {
        label: "foo",
        source_range: [40; 41),
        delete: [40; 41),
        insert: "foo",
        kind: Function,
        detail: "pub fn foo()",
    },
]"#
        );
    }

    #[test]
    fn dont_render_function_parens_if_already_call() {
        assert_debug_snapshot!(
            do_reference_completion(
                "
                //- /lib.rs
                fn frobnicate() {}
                fn main() {
                    frob<|>();
                }
                "
            ),
            @r#"[
    CompletionItem {
        label: "frobnicate",
        source_range: [35; 39),
        delete: [35; 39),
        insert: "frobnicate",
        kind: Function,
        detail: "fn frobnicate()",
    },
    CompletionItem {
        label: "main",
        source_range: [35; 39),
        delete: [35; 39),
        insert: "main",
        kind: Function,
        detail: "fn main()",
    },
]"#
        );
        assert_debug_snapshot!(
            do_reference_completion(
                "
                //- /lib.rs
                struct Foo {}
                impl Foo { fn new() -> Foo {} }
                fn main() {
                    Foo::ne<|>();
                }
                "
            ),
            @r#"[
    CompletionItem {
        label: "new",
        source_range: [67; 69),
        delete: [67; 69),
        insert: "new",
        kind: Function,
        detail: "fn new() -> Foo",
    },
]"#
        );
    }
}
<commit_msg>rename add_resolution -> add_scope_def<commit_after>//! This modules takes care of rendering various definitions as completion items.
use hir::{Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
use join_to_string::join;
use ra_syntax::ast::NameOwner;
use test_utils::tested_by;

use crate::completion::{
    CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
};

use crate::display::{const_label, function_label, macro_label, type_label};

impl Completions {
    pub(crate) fn add_field(
        &mut self,
        ctx: &CompletionContext,
        field: hir::StructField,
        substs: &hir::Substs,
    ) {
        CompletionItem::new(
            CompletionKind::Reference,
            ctx.source_range(),
            field.name(ctx.db).to_string(),
        )
        .kind(CompletionItemKind::Field)
        .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string())
        .set_documentation(field.docs(ctx.db))
        .add_to(self);
    }

    pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) {
        CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
            .kind(CompletionItemKind::Field)
            .detail(ty.display(ctx.db).to_string())
            .add_to(self);
    }

    pub(crate) fn add_resolution(
        &mut self,
        ctx: &CompletionContext,
        local_name: String,
        resolution: &ScopeDef,
    ) {
        use hir::ModuleDef::*;

        let mut completion_kind = CompletionKind::Reference;
        let (kind, docs) = match resolution {
            ScopeDef::ModuleDef(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
            ScopeDef::ModuleDef(Function(func)) => {
                return self.add_function_with_name(ctx, Some(local_name), *func);
            }
            ScopeDef::ModuleDef(Adt(hir::Adt::Struct(it))) => {
                (CompletionItemKind::Struct, it.docs(ctx.db))
            }
            ScopeDef::ModuleDef(Adt(hir::Adt::Union(it))) => {
                (CompletionItemKind::Struct, it.docs(ctx.db))
            }
            ScopeDef::ModuleDef(Adt(hir::Adt::Enum(it))) => {
                (CompletionItemKind::Enum, it.docs(ctx.db))
            }
            ScopeDef::ModuleDef(EnumVariant(it)) => {
                (CompletionItemKind::EnumVariant, it.docs(ctx.db))
            }
            ScopeDef::ModuleDef(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
            ScopeDef::ModuleDef(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
            ScopeDef::ModuleDef(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
            ScopeDef::ModuleDef(TypeAlias(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
            ScopeDef::ModuleDef(BuiltinType(..)) => {
                completion_kind = CompletionKind::BuiltinType;
                (CompletionItemKind::BuiltinType, None)
            }
            ScopeDef::GenericParam(..) => (CompletionItemKind::TypeParam, None),
            ScopeDef::LocalBinding(..) => (CompletionItemKind::Binding, None),
            ScopeDef::SelfType(..) => (
                CompletionItemKind::TypeParam, // (does this need its own kind?)
                None,
            ),
            ScopeDef::MacroDef(mac) => {
                self.add_macro(ctx, Some(local_name.clone()), *mac);
                return;
            }
            ScopeDef::Unknown => {
                self.add(CompletionItem::new(
                    CompletionKind::Reference,
                    ctx.source_range(),
                    local_name,
                ));
                return;
            }
        };

        let mut completion_item =
            CompletionItem::new(completion_kind, ctx.source_range(), local_name);
        if let ScopeDef::LocalBinding(pat_id) = resolution {
            let ty = ctx
                .analyzer
                .type_of_pat_by_id(ctx.db, pat_id.clone())
                .filter(|t| t != &Ty::Unknown)
                .map(|t| t.display(ctx.db).to_string());
            completion_item = completion_item.set_detail(ty);
        };
        completion_item.kind(kind).set_documentation(docs).add_to(self)
    }

    pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) {
        self.add_function_with_name(ctx, None, func)
    }

    pub(crate) fn add_macro(
        &mut self,
        ctx: &CompletionContext,
        name: Option<String>,
        macro_: hir::MacroDef,
    ) {
        let ast_node = macro_.source(ctx.db).ast;
        if let Some(name) = name {
            let detail = macro_label(&ast_node);

            let macro_braces_to_insert = match name.as_str() {
                "vec" => "[$0]",
                _ => "($0)",
            };
            let macro_declaration = name + "!";

            let builder = CompletionItem::new(
                CompletionKind::Reference,
                ctx.source_range(),
                &macro_declaration,
            )
            .kind(CompletionItemKind::Macro)
            .set_documentation(macro_.docs(ctx.db))
            .detail(detail)
            .insert_snippet(macro_declaration + macro_braces_to_insert);

            self.add(builder);
        }
    }

    fn add_function_with_name(
        &mut self,
        ctx: &CompletionContext,
        name: Option<String>,
        func: hir::Function,
    ) {
        let data = func.data(ctx.db);
        let name = name.unwrap_or_else(|| data.name().to_string());
        let ast_node = func.source(ctx.db).ast;
        let detail = function_label(&ast_node);

        let mut builder = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name)
            .kind(if data.has_self_param() {
                CompletionItemKind::Method
            } else {
                CompletionItemKind::Function
            })
            .set_documentation(func.docs(ctx.db))
            .detail(detail);
        // If not an import, add parenthesis automatically.
        if ctx.use_item_syntax.is_none()
            && !ctx.is_call
            && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
        {
            tested_by!(inserts_parens_for_function_calls);
            let snippet =
                if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 {
                    format!("{}()$0", data.name())
                } else {
                    format!("{}($0)", data.name())
                };
            builder = builder.insert_snippet(snippet);
        }
        self.add(builder)
    }

    pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
        let ast_node = constant.source(ctx.db).ast;
        let name = match ast_node.name() {
            Some(name) => name,
            _ => return,
        };
        let detail = const_label(&ast_node);

        CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
            .kind(CompletionItemKind::Const)
            .set_documentation(constant.docs(ctx.db))
            .detail(detail)
            .add_to(self);
    }

    pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
        let type_def = type_alias.source(ctx.db).ast;
        let name = match type_def.name() {
            Some(name) => name,
            _ => return,
        };
        let detail = type_label(&type_def);

        CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
            .kind(CompletionItemKind::TypeAlias)
            .set_documentation(type_alias.docs(ctx.db))
            .detail(detail)
            .add_to(self);
    }

    pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
        let name = match variant.name(ctx.db) {
            Some(it) => it,
            None => return,
        };
        let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
        let detail = join(detail_types.map(|t| t.display(ctx.db).to_string()))
            .separator(", ")
            .surround_with("(", ")")
            .to_string();

        CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
            .kind(CompletionItemKind::EnumVariant)
            .set_documentation(variant.docs(ctx.db))
            .detail(detail)
            .add_to(self);
    }
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;
    use test_utils::covers;

    fn do_reference_completion(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Reference)
    }

    #[test]
    fn inserts_parens_for_function_calls() {
        covers!(inserts_parens_for_function_calls);
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn no_args() {}
                fn main() { no_<|> }
                "
            ),
            @r###"[
    CompletionItem {
        label: "main",
        source_range: [61; 64),
        delete: [61; 64),
        insert: "main()$0",
        kind: Function,
        detail: "fn main()",
    },
    CompletionItem {
        label: "no_args",
        source_range: [61; 64),
        delete: [61; 64),
        insert: "no_args()$0",
        kind: Function,
        detail: "fn no_args()",
    },
]"###
        );
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn with_args(x: i32, y: String) {}
                fn main() { with_<|> }
                "
            ),
            @r###"[
    CompletionItem {
        label: "main",
        source_range: [80; 85),
        delete: [80; 85),
        insert: "main()$0",
        kind: Function,
        detail: "fn main()",
    },
    CompletionItem {
        label: "with_args",
        source_range: [80; 85),
        delete: [80; 85),
        insert: "with_args($0)",
        kind: Function,
        detail: "fn with_args(x: i32, y: String)",
    },
]"###
        );
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                struct S {}
                impl S {
                    fn foo(&self) {}
                }
                fn bar(s: &S) {
                    s.f<|>
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "foo",
        source_range: [163; 164),
        delete: [163; 164),
        insert: "foo()$0",
        kind: Method,
        detail: "fn foo(&self)",
    },
]"###
        );
    }

    #[test]
    fn dont_render_function_parens_in_use_item() {
        assert_debug_snapshot!(
            do_reference_completion(
                "
                //- /lib.rs
                mod m { pub fn foo() {} }
                use crate::m::f<|>;
                "
            ),
            @r#"[
    CompletionItem {
        label: "foo",
        source_range: [40; 41),
        delete: [40; 41),
        insert: "foo",
        kind: Function,
        detail: "pub fn foo()",
    },
]"#
        );
    }

    #[test]
    fn dont_render_function_parens_if_already_call() {
        assert_debug_snapshot!(
            do_reference_completion(
                "
                //- /lib.rs
                fn frobnicate() {}
                fn main() {
                    frob<|>();
                }
                "
            ),
            @r#"[
    CompletionItem {
        label: "frobnicate",
        source_range: [35; 39),
        delete: [35; 39),
        insert: "frobnicate",
        kind: Function,
        detail: "fn frobnicate()",
    },
    CompletionItem {
        label: "main",
        source_range: [35; 39),
        delete: [35; 39),
        insert: "main",
        kind: Function,
        detail: "fn main()",
    },
]"#
        );
        assert_debug_snapshot!(
            do_reference_completion(
                "
                //- /lib.rs
                struct Foo {}
                impl Foo { fn new() -> Foo {} }
                fn main() {
                    Foo::ne<|>();
                }
                "
            ),
            @r#"[
    CompletionItem {
        label: "new",
        source_range: [67; 69),
        delete: [67; 69),
        insert: "new",
        kind: Function,
        detail: "fn new() -> Foo",
    },
]"#
        );
    }
}
<|endoftext|>