<commit_before>use std::vec;
use lexer::Token;
use instructions::Instruction;
use instructions::{IOType, ArithmaticType, BitwiseType, ShiftType, BranchType, ControlType, AssignmentType};
use registers::Register;
pub type ParserResult<T> = Result<Option<T>, ParserError>;

pub fn parse(input: Vec<Token>) -> Vec<Instruction> {
	let mut parser = Parser::new(input);
	let mut program = vec![];

	loop {
		match parser.next() {
			Some(t) => {

				program.push(t);

			}
			None => break
		}
	}
	program
}
pub struct Parser {
	iter: vec::IntoIter<Token>
}

#[derive(Debug,PartialEq)]
pub enum ParserError {
	InvalidInstruction,
	InvalidArgument,
}

impl Parser {
	fn new(input: Vec<Token>) -> Parser {
		Parser {
			iter: input.into_iter()
		}
	}
	fn advance(&mut self) -> Option<Token> {
		if let Some(t) = self.iter.next() {
			return Some(t);
		}
		None
	}
	fn handle_io(&mut self, kind: IOType) -> ParserResult<Instruction> {
		let register = match self.advance().unwrap() {
			Token::Identifier(r) => Register::from(r),
			_ => return Err(ParserError::InvalidArgument)
		};
		Ok(Some(Instruction::IO(kind, register)))
	}
	fn handle_arithmatic(&mut self, kind: ArithmaticType) -> ParserResult<Instruction> {
		let source = match self.advance().unwrap() {
			Token::Identifier(r) => Register::from(r),
			_ => return Err(ParserError::InvalidArgument)
		};
		let target = match self.advance().unwrap() {
			Token::Identifier(r) => Register::from(r),
			_ => return Err(ParserError::InvalidArgument)
		};
		let destination = match self.advance().unwrap() {
			Token::Identifier(r) => Register::from(r),
			_ => return Err(ParserError::InvalidArgument)
		};
		Ok(Some(Instruction::Arithmatic(kind, source, target, destination)))
	}
	fn handle_bitwise(&mut self, kind: BitwiseType) -> ParserResult<Instruction> {
		let source = match self.advance().unwrap() {
			Token::Identifier(r) => Register::from(r),
			_ => return Err(ParserError::InvalidArgument)
		};
		let target = match self.advance().unwrap() {
			Token::Identifier(r) => Register::from(r),
			_ => return Err(ParserError::InvalidArgument)
		};
		let destination = match self.advance().unwrap() {
			Token::Identifier(r) => Register::from(r),
			_ => return Err(ParserError::InvalidArgument)
		};
		Ok(Some(Instruction::Bitwise(kind, source, target, destination)))
	}
	fn handle_branch(&mut self, kind: BranchType) -> ParserResult<Instruction> {
		let label = match self.advance().unwrap() {
			Token::Identifier(r) => r,
			_ => return Err(ParserError::InvalidArgument)
		};
		Ok(Some(Instruction::Branch(kind, label)))
	}
	fn handle_control(&mut self, kind: ControlType) -> ParserResult<Instruction> {
		Ok(Some(Instruction::Control(kind)))
	}
	fn handle_assignment(&mut self, kind: AssignmentType) -> ParserResult<Instruction> {
		let register = match self.advance().unwrap() {
			Token::Identifier(r) => Register::from(r),
			_ => return Err(ParserError::InvalidArgument)
		};
		Ok(Some(Instruction::Assignment(kind, register)))
	}

	fn next_instruction(&mut self) -> ParserResult<Instruction> {
		match self.advance() {
			Some(t) => {
				match t {
					Token::Identifier(mut i) => {
						match i.as_ref() {

							"nop" => Ok(Some(Instruction::NOP)),
							"hlt" => Ok(Some(Instruction::HLT)),

							"out" => self.handle_io(IOType::OUT),
							"in" => self.handle_io(IOType::IN),

							"add" => self.handle_arithmatic(ArithmaticType::ADD),
							"sub" => self.handle_arithmatic(ArithmaticType::SUB),
							"mul" => self.handle_arithmatic(ArithmaticType::MUL),
							"div" => self.handle_arithmatic(ArithmaticType::DIV),
							"max" => self.handle_arithmatic(ArithmaticType::MAX),
							"min" => self.handle_arithmatic(ArithmaticType::MIN),

							"and" => self.handle_bitwise(BitwiseType::AND),
							"or"  => self.handle_bitwise(BitwiseType::OR),
							"xor" => self.handle_bitwise(BitwiseType::XOR),
							"shr" => self.handle_bitwise(BitwiseType::SHIFT(ShiftType::RIGHT)),
							"shl" => self.handle_bitwise(BitwiseType::SHIFT(ShiftType::LEFT)),

							"jmp" => self.handle_branch(BranchType::UNCONDITIONAL),
							"jz" => {
								let register = match self.advance().unwrap() {
									Token::Identifier(r) => Register::from(r),
									_ => return Err(ParserError::InvalidArgument)
								};
								self.handle_branch(BranchType::ZERO(register))
							}
							"jnz" => {
								let register = match self.advance().unwrap() {
									Token::Identifier(r) => Register::from(r),
									_ => return Err(ParserError::InvalidArgument)
								};
								self.handle_branch(BranchType::NOTZERO(register))
							},

							"str" => {
								let value = match self.advance().unwrap() {
									Token::Value(i) => i,
									_ => return Err(ParserError::InvalidArgument)
								};
								self.handle_assignment(AssignmentType::STR(value))
							},
							"cpy" => {
								let register = match self.advance().unwrap() {
									Token::Identifier(r) => Register::from(r),
									_ => return Err(ParserError::InvalidArgument)
								};
								self.handle_assignment(AssignmentType::CPY(register))
							},
							_ if i.chars().last().unwrap() == ':' => {
								i.pop().unwrap();
								self.handle_control(ControlType::LBL(i))
							},

							_ => return Err(ParserError::InvalidInstruction)
						}

					},
					_ => return Err(ParserError::InvalidInstruction),
				}

			}
			None => return Ok(None)
		}

	}
}
impl Iterator for Parser {
	type Item = Instruction;
	fn next(&mut self) -> Option<Instruction> {

		match self.next_instruction() {
			Ok(i) => i,
			Err(e) => panic!("ParserError: {:?}", e)
		}

	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use lexer::Token;
	use instructions::Instruction;
	use instructions::{IOType, ArithmaticType, BitwiseType, ShiftType, BranchType, ControlType, AssignmentType};

	use registers::Register;
	#[test]
	fn iter(){
		let tokens = vec![Token::Identifier("str".to_string()), Token::Value(6), Token::Identifier("ra".to_string())];
		let mut parser = Parser::new(tokens);
		let mut output = vec![];

		loop {
			match parser.next() {
				Some(c) => {
					output.push(c);
				},
				None => break
			}
		}
		assert_eq!(output, vec![Instruction::Assignment(AssignmentType::STR(6), Register::RA)]);
	}
}<commit_msg>simplify parsing<commit_after>use std::vec;
use lexer::Token;
use instructions::Instruction;
use instructions::{IOType, ArithmaticType, BitwiseType, ShiftType, BranchType, ControlType, AssignmentType};
use registers::Register;
pub type ParserResult<T> = Result<Option<T>, ParserError>;

pub fn parse(input: Vec<Token>) -> Vec<Instruction> {
	let mut parser = Parser::new(input);
	let mut program = vec![];
	while let Some(i) = parser.next() {
		program.push(i)
	}
	program
}
pub struct Parser {
	iter: vec::IntoIter<Token>
}

#[derive(Debug,PartialEq)]
pub enum ParserError {
	InvalidInstruction,
	InvalidArgument,
}

impl Parser {
	fn new(input: Vec<Token>) -> Parser {
		Parser {
			iter: input.into_iter()
		}
	}
	fn advance(&mut self) -> Option<Token> {
		if let Some(t) = self.iter.next() {
			return Some(t);
		}
		None
	}
	fn take_register(&mut self) -> Option<Register> {
		match self.advance().unwrap() {
			Token::Identifier(r) => Some(Register::from(r)),
			_ => return None
		}
	}
	fn take_value(&mut self) -> Option<i32> {
		match self.advance().unwrap() {
			Token::Value(i) => Some(i),
			_ => return None
		}
	}

	fn handle_io(&mut self, kind: IOType) -> ParserResult<Instruction> {
		match self.take_register() {
			Some(register) => Ok(Some(Instruction::IO(kind, register))),
			None => return Err(ParserError::InvalidArgument)
		}
	}
	fn handle_arithmatic(&mut self, kind: ArithmaticType) -> ParserResult<Instruction> {
		match (self.take_register(), self.take_register(), self.take_register()) {
			(Some(source), Some(target), Some(destination)) => {
				Ok(Some(Instruction::Arithmatic(kind, source, target, destination)))
			},
			_ => return Err(ParserError::InvalidArgument)
		}
	}
	fn handle_bitwise(&mut self, kind: BitwiseType) -> ParserResult<Instruction> {
		match (self.take_register(), self.take_register(), self.take_register()) {
			(Some(source), Some(target), Some(destination)) => {
				Ok(Some(Instruction::Bitwise(kind, source, target, destination)))
			},
			_ => return Err(ParserError::InvalidArgument)
		}
	}
	fn handle_branch(&mut self, kind: BranchType) -> ParserResult<Instruction> {
		let label = match self.advance().unwrap() {
			Token::Identifier(r) => r,
			_ => return Err(ParserError::InvalidArgument)
		};
		Ok(Some(Instruction::Branch(kind, label)))
	}
	fn handle_control(&mut self, kind: ControlType) -> ParserResult<Instruction> {
		Ok(Some(Instruction::Control(kind)))
	}
	fn handle_assignment(&mut self, kind: AssignmentType) -> ParserResult<Instruction> {
		match self.take_register() {
			Some(register) => Ok(Some(Instruction::Assignment(kind, register))),
			None => return Err(ParserError::InvalidArgument)
		}
	}
	fn next_instruction(&mut self) -> ParserResult<Instruction> {
		let mut result = Ok(None);
		if let Some(t) = self.advance() {
			if let Token::Identifier(mut i) = t {
				match i.as_ref() {
					"nop" => result = Ok(Some(Instruction::NOP)),
					"hlt" => result = Ok(Some(Instruction::HLT)),

					"out" => result = self.handle_io(IOType::OUT),
					"in" => result =  self.handle_io(IOType::IN),

					"add" => result = self.handle_arithmatic(ArithmaticType::ADD),
					"sub" => result = self.handle_arithmatic(ArithmaticType::SUB),
					"mul" => result = self.handle_arithmatic(ArithmaticType::MUL),
					"div" => result = self.handle_arithmatic(ArithmaticType::DIV),
					"max" => result = self.handle_arithmatic(ArithmaticType::MAX),
					"min" => result = self.handle_arithmatic(ArithmaticType::MIN),

					"and" => result = self.handle_bitwise(BitwiseType::AND),
					"or"  => result = self.handle_bitwise(BitwiseType::OR),
					"xor" => result = self.handle_bitwise(BitwiseType::XOR),
					"shr" => result = self.handle_bitwise(BitwiseType::SHIFT(ShiftType::RIGHT)),
					"shl" => result = self.handle_bitwise(BitwiseType::SHIFT(ShiftType::LEFT)),

					"jmp" => result = self.handle_branch(BranchType::UNCONDITIONAL),
					"jz" => {
						match self.take_register() {
							Some(register) => result = self.handle_branch(BranchType::ZERO(register)),
							None => return Err(ParserError::InvalidArgument)
						}
					},
					"jnz" => {
						match self.take_register() {
							Some(register) => result = self.handle_branch(BranchType::NOTZERO(register)),
							None => return Err(ParserError::InvalidArgument)
						}
					},
					"str" => {
						match self.take_value() {
							Some(value) => result = self.handle_assignment(AssignmentType::STR(value)),
							None => return Err(ParserError::InvalidArgument)
						}
					},
					"cpy" => {
						match self.take_register() {
							Some(register) => result = self.handle_assignment(AssignmentType::CPY(register)),
							None => return Err(ParserError::InvalidArgument)
						}
					},
					_ if i.chars().last().unwrap() == ':' => {
						i.pop().unwrap();
						result = self.handle_control(ControlType::LBL(i))
					},
					_ => return Err(ParserError::InvalidInstruction)
				}
			}
		}
		result
	}
}
impl Iterator for Parser {
	type Item = Instruction;
	fn next(&mut self) -> Option<Instruction> {
		match self.next_instruction() {
			Ok(i) => i,
			Err(e) => panic!("ParserError: {:?}", e)
		}
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use lexer::Token;
	use instructions::Instruction;
	use instructions::{IOType, ArithmaticType, BitwiseType, ShiftType, BranchType, ControlType, AssignmentType};

	use registers::Register;
	#[test]
	fn iter(){
		let tokens = vec![Token::Identifier("str".to_string()), Token::Value(6), Token::Identifier("ra".to_string())];
		let mut parser = Parser::new(tokens);
		let mut output = vec![];

		loop {
			match parser.next() {
				Some(c) => {
					output.push(c);
				},
				None => break
			}
		}
		assert_eq!(output, vec![Instruction::Assignment(AssignmentType::STR(6), Register::RA)]);
	}
}<|endoftext|>


<commit_before>#![deny(rust_2018_idioms)]

use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
    packages: &'static [&'static str],
}

const TEST_REPOS: &'static [Test] = &[
    Test {
        name: "iron",
        repo: "https://github.com/iron/iron",
        sha: "21c7dae29c3c214c08533c2a55ac649b418f2fe3",
        lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
        packages: &[],
    },
    Test {
        name: "ripgrep",
        repo: "https://github.com/BurntSushi/ripgrep",
        sha: "ad9befbc1d3b5c695e7f6b6734ee1b8e683edd41",
        lock: None,
        packages: &[],
    },
    Test {
        name: "tokei",
        repo: "https://github.com/Aaronepower/tokei",
        sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928",
        lock: None,
        packages: &[],
    },
    Test {
        name: "treeify",
        repo: "https://github.com/dzamlo/treeify",
        sha: "999001b223152441198f117a68fb81f57bc086dd",
        lock: None,
        packages: &[],
    },
    Test {
        name: "xsv",
        repo: "https://github.com/BurntSushi/xsv",
        sha: "66956b6bfd62d6ac767a6b6499c982eae20a2c9f",
        lock: None,
        packages: &[],
    },
    Test {
        name: "servo",
        repo: "https://github.com/servo/servo",
        sha: "987e376ca7a4245dbc3e0c06e963278ee1ac92d1",
        lock: None,
        // Only test Stylo a.k.a. Quantum CSS, the parts of Servo going into Firefox.
        // This takes much less time to build than all of Servo and supports stable Rust.
        packages: &["selectors"],
    },
    Test {
        name: "webrender",
        repo: "https://github.com/servo/webrender",
        sha: "57250b2b8fa63934f80e5376a29f7dcb3f759ad6",
        lock: None,
        packages: &[],
    },
];

fn main() {
    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        fs::write(&dir.join("Cargo.lock"), lockfile).unwrap();
    }
    if !run_cargo_test(cargo, &dir, test.packages) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
                         .arg("init")
                         .arg(&out_dir)
                         .status()
                         .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                             .arg("fetch")
                             .arg(test.repo)
                             .arg("master")
                             .arg(&format!("--depth={}", depth))
                             .current_dir(&out_dir)
                             .status()
                             .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
                         .arg("reset")
                         .arg(test.sha)
                         .arg("--hard")
                         .current_dir(&out_dir)
                         .status()
                         .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
                     .arg("clean")
                     .arg("-fdx")
                     .current_dir(&out_dir)
                     .status()
                     .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path, packages: &[&str]) -> bool {
    let mut command = Command::new(cargo_path);
    command.arg("test");
    for name in packages {
        command.arg("-p").arg(name);
    }
    let status = command
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        // Relax #![deny(warnings)] in some crates
        .env("RUSTFLAGS", "--cap-lints warn")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<commit_msg>Rollup merge of #59586 - XAMPPRocky:redirect, r=alexcrichton<commit_after>#![deny(rust_2018_idioms)]

use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
    packages: &'static [&'static str],
}

const TEST_REPOS: &'static [Test] = &[
    Test {
        name: "iron",
        repo: "https://github.com/iron/iron",
        sha: "21c7dae29c3c214c08533c2a55ac649b418f2fe3",
        lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
        packages: &[],
    },
    Test {
        name: "ripgrep",
        repo: "https://github.com/BurntSushi/ripgrep",
        sha: "ad9befbc1d3b5c695e7f6b6734ee1b8e683edd41",
        lock: None,
        packages: &[],
    },
    Test {
        name: "tokei",
        repo: "https://github.com/XAMPPRocky/tokei",
        sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928",
        lock: None,
        packages: &[],
    },
    Test {
        name: "treeify",
        repo: "https://github.com/dzamlo/treeify",
        sha: "999001b223152441198f117a68fb81f57bc086dd",
        lock: None,
        packages: &[],
    },
    Test {
        name: "xsv",
        repo: "https://github.com/BurntSushi/xsv",
        sha: "66956b6bfd62d6ac767a6b6499c982eae20a2c9f",
        lock: None,
        packages: &[],
    },
    Test {
        name: "servo",
        repo: "https://github.com/servo/servo",
        sha: "987e376ca7a4245dbc3e0c06e963278ee1ac92d1",
        lock: None,
        // Only test Stylo a.k.a. Quantum CSS, the parts of Servo going into Firefox.
        // This takes much less time to build than all of Servo and supports stable Rust.
        packages: &["selectors"],
    },
    Test {
        name: "webrender",
        repo: "https://github.com/servo/webrender",
        sha: "57250b2b8fa63934f80e5376a29f7dcb3f759ad6",
        lock: None,
        packages: &[],
    },
];

fn main() {
    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        fs::write(&dir.join("Cargo.lock"), lockfile).unwrap();
    }
    if !run_cargo_test(cargo, &dir, test.packages) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
                         .arg("init")
                         .arg(&out_dir)
                         .status()
                         .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                             .arg("fetch")
                             .arg(test.repo)
                             .arg("master")
                             .arg(&format!("--depth={}", depth))
                             .current_dir(&out_dir)
                             .status()
                             .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
                         .arg("reset")
                         .arg(test.sha)
                         .arg("--hard")
                         .current_dir(&out_dir)
                         .status()
                         .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
                     .arg("clean")
                     .arg("-fdx")
                     .current_dir(&out_dir)
                     .status()
                     .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path, packages: &[&str]) -> bool {
    let mut command = Command::new(cargo_path);
    command.arg("test");
    for name in packages {
        command.arg("-p").arg(name);
    }
    let status = command
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        // Relax #![deny(warnings)] in some crates
        .env("RUSTFLAGS", "--cap-lints warn")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<|endoftext|>


<commit_before>use chan;
use hyper::server;
use hyper::client;
use hyper::header::{Connection, ContentType, Headers};
use hyper::method::Method::Post;
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use protobuf;
use std::collections::HashMap;
use std::fmt;
use std::io::Read;
use std::net::SocketAddr;
use std::str::FromStr;
use std::thread;

header! {
    (LibprocessFrom, "Libprocess-From") => [UPID]
}

lazy_static! {
    static ref ContentTypeProtobuf: ContentType = ContentType("application/x-protobuf".parse().unwrap());
}

#[derive(Clone, Debug, PartialEq)]
pub struct UPID {
    id: String,
    address: SocketAddr
}

impl UPID {
    fn new(id: &str, address: SocketAddr) -> Self {
        UPID{id: id.to_string(), address: address}
    }

    fn to_url(&self) -> String {
        format!("http://{}/{}/", self.address, self.id)
    }
}

impl fmt::Display for UPID {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        write!(fmt, "{}@{}", self.id, self.address)
    }
}

impl FromStr for UPID {
    type Err = Error;
    fn from_str(pid: &str) -> Result<UPID> {
        let mut split = pid.split("@");
        match (split.nth(0), split.nth(0)) {
            (Some(id), Some(address)) => {
                match FromStr::from_str(address) {
                    Ok(address) => Ok(UPID::new(id, address)),
                    Err(_) => Err(Error::Upid)
                }
            },
            _ => Err(Error::Upid)
        }
    }
}

#[derive(Debug)]
pub enum Error {
    Http,
    Upid,
    Serialization
}

pub type Result<T> = ::std::result::Result<T, Error>;
pub type Handler<C> = Box<Fn(UPID, Vec<u8>, &C) + Send>;

pub fn handler<F, M, C>(fun: F) -> Handler<C>
    where F: Fn(UPID, M, &C) + Send + 'static,
          M: protobuf::MessageStatic,
          C: Send + 'static {

    Box::new(move |sender: UPID, data: Vec<u8>, context: &C| {
        match protobuf::parse_from_bytes::<M>(&data) {
            Ok(message) => {
                debug!("Received {} {:?}", message.descriptor().name(), message);
                fun(sender, message, context);
            },
            _ => error!("Failed to parse protobuf message from master")
        }
    })
}

pub struct LibProcess {
    http_server: server::Listening,
    http_client: client::Client,
    pid: UPID,
    rx: chan::Receiver<(String, UPID, Vec<u8>)>
}

impl LibProcess {
    pub fn new(id: &str) -> Result<Self> {
        let (tx, rx) = chan::async();
        let http_server = try!(Self::new_server(id, tx));
        let http_client = client::Client::new();
        let pid = UPID::new(id, http_server.socket.clone());

        Ok(LibProcess{http_server: http_server,
                      http_client: http_client,
                      pid: pid,
                      rx: rx})
    }

    fn new_server(myid: &str, tx: chan::Sender<(String, UPID, Vec<u8>)>) -> Result<server::Listening> {
        let myid_len = myid.len() + 2;

        let server = try!(server::Server::http("0.0.0.0:0").map_err(|_| Error::Http));

        server.handle(move |req: server::Request, mut resp: server::Response| {
            match req.deconstruct() {
                (_, Post, headers, AbsolutePath(path), _, mut body) => {
                    let id = &path[..myid_len];
                    let mut data = Vec::new();
                    if let Err(e) = body.read_to_end(&mut data) {
                        warn!("Failed to read message for {}: {}", id, e);
                        *resp.status_mut() = StatusCode::BadRequest;
                        return
                    }

                    let name = path[myid_len..].to_string();
                    let sender = match headers.get() {
                        Some(&LibprocessFrom(ref upid)) => upid.clone(),
                        None => panic!("No LibprocessFrom in header")
                    };

                    tx.send((name, sender, data));

                    *resp.status_mut() = StatusCode::Accepted;
                },
                (_, _, _, uri, _, _) => {
                    warn!("Unhandled {:?}", uri);
                }
            }
        }).map_err(|_| Error::Http)
    }

    pub fn send(&mut self,
                pid: &UPID,
                message: &protobuf::Message) -> Result<()> {

        let mut url = pid.to_url();
        url.push_str(message.descriptor().full_name());

        let mut headers = Headers::new();
        headers.set(Connection::keep_alive());
        headers.set(ContentTypeProtobuf.clone());
        headers.set(LibprocessFrom(self.pid.clone()));

        let data = try!(message.write_to_bytes().map_err(|_| Error::Serialization));

        let resp = self.http_client.post(&url)
                                   .headers(headers)
                                   .body(&data[..])
                                   .send();

        match resp {
            Ok(client::Response{status: StatusCode::Accepted, ..}) => Ok(()),
            _ => Err(Error::Http)
        }
    }

    pub fn start<C>(&self, handlers: HashMap<String, Handler<C>>, context: C)
    where C: Send + 'static {

        let rx = self.rx.clone();
        thread::spawn(move || {
            loop {
                match rx.recv() {
                    Some((name, sender, data)) => match handlers.get(&name) {
                        Some(handler) => handler(sender, data, &context),
                        None => warn!("Unahandled message: {}", name)
                    },
                    None => return
                }
            }
        });
    }

    pub fn close(&mut self) -> Result<()> {
        self.http_server.close().map_err(|_| Error::Http)
    }
}
<commit_msg>Improve error handling in Libprocess<commit_after>use chan;
use hyper;
use hyper::server;
use hyper::client;
use hyper::header::{Connection, ContentType, Headers};
use hyper::method::Method::Post;
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use protobuf;
use std::collections::HashMap;
use std::fmt;
use std::io::Read;
use std::net::SocketAddr;
use std::str::FromStr;
use std::thread;

header! {
    (LibprocessFrom, "Libprocess-From") => [UPID]
}

lazy_static! {
    static ref ContentTypeProtobuf: ContentType = ContentType("application/x-protobuf".parse().unwrap());
}

#[derive(Clone, Debug, PartialEq)]
pub struct UPID {
    id: String,
    address: SocketAddr
}

impl UPID {
    fn new(id: &str, address: SocketAddr) -> Self {
        UPID{id: id.to_string(), address: address}
    }

    fn to_url(&self) -> String {
        format!("http://{}/{}/", self.address, self.id)
    }
}

impl fmt::Display for UPID {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
        write!(fmt, "{}@{}", self.id, self.address)
    }
}

impl FromStr for UPID {
    type Err = Error;
    fn from_str(pid: &str) -> Result<UPID> {
        let mut split = pid.split("@");
        match (split.nth(0), split.nth(0)) {
            (Some(id), Some(address)) => {
                match FromStr::from_str(address) {
                    Ok(address) => Ok(UPID::new(id, address)),
                    Err(_) => Err(Error::Upid)
                }
            },
            _ => Err(Error::Upid)
        }
    }
}

#[derive(Debug)]
pub enum Error {
    Http(hyper::error::Error),
    Upid,
    Serialization
}

pub type Result<T> = ::std::result::Result<T, Error>;
pub type Handler<C> = Box<Fn(UPID, Vec<u8>, &C) + Send>;

pub fn handler<F, M, C>(fun: F) -> Handler<C>
    where F: Fn(UPID, M, &C) + Send + 'static,
          M: protobuf::MessageStatic,
          C: Send + 'static {

    Box::new(move |sender: UPID, data: Vec<u8>, context: &C| {
        match protobuf::parse_from_bytes::<M>(&data) {
            Ok(message) => {
                debug!("Received {} {:?}", message.descriptor().name(), message);
                fun(sender, message, context);
            },
            _ => error!("Failed to parse protobuf message from master")
        }
    })
}

pub struct LibProcess {
    http_server: server::Listening,
    http_client: client::Client,
    pid: UPID,
    rx: chan::Receiver<(String, UPID, Vec<u8>)>
}

impl LibProcess {
    pub fn new(id: &str) -> Result<Self> {
        let (tx, rx) = chan::async();
        let http_server = try!(Self::new_server(id, tx));
        let http_client = client::Client::new();
        let pid = UPID::new(id, http_server.socket.clone());

        Ok(LibProcess{http_server: http_server,
                      http_client: http_client,
                      pid: pid,
                      rx: rx})
    }

    fn new_server(myid: &str, tx: chan::Sender<(String, UPID, Vec<u8>)>) -> Result<server::Listening> {
        let myid_len = myid.len() + 2;

        let server = try!(server::Server::http("0.0.0.0:0").map_err(Error::Http));

        server.handle(move |req: server::Request, mut resp: server::Response| {
            match req.deconstruct() {
                (_, Post, headers, AbsolutePath(path), _, mut body) => {
                    let id = &path[..myid_len];
                    let mut data = Vec::new();
                    if let Err(e) = body.read_to_end(&mut data) {
                        warn!("Failed to read message for {}: {}", id, e);
                        *resp.status_mut() = StatusCode::BadRequest;
                        return
                    }

                    let name = path[myid_len..].to_string();
                    let sender = match headers.get() {
                        Some(&LibprocessFrom(ref upid)) => upid.clone(),
                        None => panic!("No LibprocessFrom in header")
                    };

                    tx.send((name, sender, data));

                    *resp.status_mut() = StatusCode::Accepted;
                },
                (_, _, _, uri, _, _) => {
                    warn!("Unhandled {:?}", uri);
                }
            }
        }).map_err(Error::Http)
    }

    pub fn send(&mut self,
                pid: &UPID,
                message: &protobuf::Message) -> Result<()> {

        let mut url = pid.to_url();
        url.push_str(message.descriptor().full_name());

        let mut headers = Headers::new();
        headers.set(Connection::keep_alive());
        headers.set(ContentTypeProtobuf.clone());
        headers.set(LibprocessFrom(self.pid.clone()));

        let data = try!(message.write_to_bytes().map_err(|_| Error::Serialization));

        let resp = self.http_client.post(&url)
                                   .headers(headers)
                                   .body(&data[..])
                                   .send();

        match resp {
            Ok(client::Response{status: StatusCode::Accepted, ..}) => Ok(()),
            Ok(_) => Err(Error::Http(hyper::error::Error::Status)),
            Err(e) => Err(Error::Http(e))
        }
    }

    pub fn start<C>(&self, handlers: HashMap<String, Handler<C>>, context: C)
    where C: Send + 'static {

        let rx = self.rx.clone();
        thread::spawn(move || {
            loop {
                match rx.recv() {
                    Some((name, sender, data)) => match handlers.get(&name) {
                        Some(handler) => handler(sender, data, &context),
                        None => warn!("Unahandled message: {}", name)
                    },
                    None => return
                }
            }
        });
    }

    pub fn close(&mut self) -> Result<()> {
        self.http_server.close().map_err(Error::Http)
    }
}
<|endoftext|>


<commit_before>use crate::fdentry::FdEntry;
use crate::host;
use failure::{bail, format_err, Error};
use nix::unistd::dup;
use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::fs::File;
use std::io::{stderr, stdin, stdout};
use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::path::{Path, PathBuf};

pub struct WasiCtxBuilder {
    fds: HashMap<host::__wasi_fd_t, FdEntry>,
    preopens: HashMap<PathBuf, File>,
    args: Vec<CString>,
    env: HashMap<CString, CString>,
}

impl WasiCtxBuilder {
    /// Builder for a new `WasiCtx`.
    pub fn new() -> Self {
        let null = dev_null();
        WasiCtxBuilder {
            fds: HashMap::new(),
            preopens: HashMap::new(),
            args: vec![],
            env: HashMap::new(),
        }
        .fd_dup(0, &null)
        .fd_dup(1, &null)
        .fd_dup(2, &null)
    }

    pub fn args(mut self, args: &[&str]) -> Self {
        self.args = args
            .into_iter()
            .map(|arg| CString::new(*arg).expect("argument can be converted to a CString"))
            .collect();
        self
    }

    pub fn arg(mut self, arg: &str) -> Self {
        self.args
            .push(CString::new(arg).expect("argument can be converted to a CString"));
        self
    }

    pub fn c_args<S: AsRef<CStr>>(mut self, args: &[S]) -> Self {
        self.args = args
            .into_iter()
            .map(|arg| arg.as_ref().to_owned())
            .collect();
        self
    }

    pub fn c_arg<S: AsRef<CStr>>(mut self, arg: S) -> Self {
        self.args.push(arg.as_ref().to_owned());
        self
    }

    pub fn inherit_stdio(self) -> Self {
        self.fd_dup(0, &stdin())
            .fd_dup(1, &stdout())
            .fd_dup(2, &stderr())
    }

    pub fn inherit_env(mut self) -> Self {
        self.env = std::env::vars()
            .map(|(k, v)| {
                // TODO: handle errors, and possibly assert that the key is valid per POSIX
                (
                    CString::new(k).expect("environment key can be converted to a CString"),
                    CString::new(v).expect("environment value can be converted to a CString"),
                )
            })
            .collect();
        self
    }

    pub fn env(mut self, k: &str, v: &str) -> Self {
        self.env.insert(
            // TODO: handle errors, and possibly assert that the key is valid per POSIX
            CString::new(k).expect("environment key can be converted to a CString"),
            CString::new(v).expect("environment value can be converted to a CString"),
        );
        self
    }

    pub fn c_env<S, T>(mut self, k: S, v: T) -> Self
    where
        S: AsRef<CStr>,
        T: AsRef<CStr>,
    {
        self.env
            .insert(k.as_ref().to_owned(), v.as_ref().to_owned());
        self
    }

    /// Add an existing file-like object as a file descriptor in the context.
    ///
    /// When the `WasiCtx` is dropped, all of its associated file descriptors are `close`d. If you
    /// do not want this to close the existing object, use `WasiCtxBuilder::fd_dup()`.
    pub fn fd<F: IntoRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: F) -> Self {
        // safe because we're getting a valid RawFd from the F directly
        unsafe { self.raw_fd(wasm_fd, fd.into_raw_fd()) }
    }

    /// Add an existing file-like object as a duplicate file descriptor in the context.
    ///
    /// The underlying file descriptor of this object will be duplicated before being added to the
    /// context, so it will not be closed when the `WasiCtx` is dropped.
    ///
    /// TODO: handle `dup` errors
    pub fn fd_dup<F: AsRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: &F) -> Self {
        // safe because we're getting a valid RawFd from the F directly
        unsafe { self.raw_fd(wasm_fd, dup(fd.as_raw_fd()).unwrap()) }
    }

    /// Add an existing file descriptor to the context.
    ///
    /// When the `WasiCtx` is dropped, this file descriptor will be `close`d. If you do not want to
    /// close the existing descriptor, use `WasiCtxBuilder::raw_fd_dup()`.
    pub unsafe fn raw_fd(mut self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self {
        self.fds.insert(wasm_fd, FdEntry::from_raw_fd(fd));
        self
    }

    /// Add a duplicate of an existing file descriptor to the context.
    ///
    /// The file descriptor will be duplicated before being added to the context, so it will not be
    /// closed when the `WasiCtx` is dropped.
    ///
    /// TODO: handle `dup` errors
    pub unsafe fn raw_fd_dup(self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self {
        self.raw_fd(wasm_fd, dup(fd).unwrap())
    }

    pub fn preopened_dir<P: AsRef<Path>>(mut self, dir: File, guest_path: P) -> Self {
        self.preopens.insert(guest_path.as_ref().to_owned(), dir);
        self
    }

    pub fn build(mut self) -> Result<WasiCtx, Error> {
        // startup code starts looking at fd 3 for preopens
        let mut preopen_fd = 3;
        for (guest_path, dir) in self.preopens {
            if !dir.metadata()?.is_dir() {
                bail!("preopened file is not a directory");
            }
            while self.fds.contains_key(&preopen_fd) {
                preopen_fd = preopen_fd
                    .checked_add(1)
                    .ok_or(format_err!("not enough file handles"))?;
            }
            let mut fe = FdEntry::from_file(dir);
            fe.preopen_path = Some(guest_path);
            self.fds.insert(preopen_fd, fe);
            preopen_fd += 1;
        }

        let env = self
            .env
            .into_iter()
            .map(|(k, v)| {
                let mut pair = k.into_bytes();
                pair.extend_from_slice(b"=");
                pair.extend_from_slice(v.to_bytes_with_nul());
                // constructing a new CString from existing CStrings is safe
                unsafe { CString::from_vec_unchecked(pair) }
            })
            .collect();

        Ok(WasiCtx {
            fds: self.fds,
            args: self.args,
            env,
        })
    }
}

#[derive(Debug)]
pub struct WasiCtx {
    pub fds: HashMap<host::__wasi_fd_t, FdEntry>,
    pub args: Vec<CString>,
    pub env: Vec<CString>,
}

impl WasiCtx {
    /// Make a new `WasiCtx` with some default settings.
    ///
    /// - File descriptors 0, 1, and 2 inherit stdin, stdout, and stderr from the host process.
    ///
    /// - Environment variables are inherited from the host process.
    ///
    /// To override these behaviors, use `WasiCtxBuilder`.
    pub fn new(args: &[&str]) -> WasiCtx {
        WasiCtxBuilder::new()
            .args(args)
            .inherit_stdio()
            .inherit_env()
            .build()
            .expect("default options don't fail")
    }

    pub fn get_fd_entry(
        &self,
        fd: host::__wasi_fd_t,
        rights_base: host::__wasi_rights_t,
        rights_inheriting: host::__wasi_rights_t,
    ) -> Result<&FdEntry, host::__wasi_errno_t> {
        if let Some(fe) = self.fds.get(&fd) {
            // validate rights
            if !fe.rights_base & rights_base != 0 || !fe.rights_inheriting & rights_inheriting != 0
            {
                Err(host::__WASI_ENOTCAPABLE as host::__wasi_errno_t)
            } else {
                Ok(fe)
            }
        } else {
            Err(host::__WASI_EBADF as host::__wasi_errno_t)
        }
    }

    pub fn insert_fd_entry(
        &mut self,
        fe: FdEntry,
    ) -> Result<host::__wasi_fd_t, host::__wasi_errno_t> {
        // never insert where stdio handles usually are
        let mut fd = 3;
        while self.fds.contains_key(&fd) {
            if let Some(next_fd) = fd.checked_add(1) {
                fd = next_fd;
            } else {
                return Err(host::__WASI_EMFILE as host::__wasi_errno_t);
            }
        }
        self.fds.insert(fd, fe);
        Ok(fd)
    }
}

fn dev_null() -> File {
    File::open("/dev/null").expect("failed to open /dev/null")
}
<commit_msg>Fixes #299 - WasiCtx should open dev/null read write (#302)<commit_after>use crate::fdentry::FdEntry;
use crate::host;
use failure::{bail, format_err, Error};
use nix::unistd::dup;
use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::fs::{File, OpenOptions};
use std::io::{stderr, stdin, stdout};
use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::path::{Path, PathBuf};

pub struct WasiCtxBuilder {
    fds: HashMap<host::__wasi_fd_t, FdEntry>,
    preopens: HashMap<PathBuf, File>,
    args: Vec<CString>,
    env: HashMap<CString, CString>,
}

impl WasiCtxBuilder {
    /// Builder for a new `WasiCtx`.
    pub fn new() -> Self {
        let null = dev_null();
        WasiCtxBuilder {
            fds: HashMap::new(),
            preopens: HashMap::new(),
            args: vec![],
            env: HashMap::new(),
        }
        .fd_dup(0, &null)
        .fd_dup(1, &null)
        .fd_dup(2, &null)
    }

    pub fn args(mut self, args: &[&str]) -> Self {
        self.args = args
            .into_iter()
            .map(|arg| CString::new(*arg).expect("argument can be converted to a CString"))
            .collect();
        self
    }

    pub fn arg(mut self, arg: &str) -> Self {
        self.args
            .push(CString::new(arg).expect("argument can be converted to a CString"));
        self
    }

    pub fn c_args<S: AsRef<CStr>>(mut self, args: &[S]) -> Self {
        self.args = args
            .into_iter()
            .map(|arg| arg.as_ref().to_owned())
            .collect();
        self
    }

    pub fn c_arg<S: AsRef<CStr>>(mut self, arg: S) -> Self {
        self.args.push(arg.as_ref().to_owned());
        self
    }

    pub fn inherit_stdio(self) -> Self {
        self.fd_dup(0, &stdin())
            .fd_dup(1, &stdout())
            .fd_dup(2, &stderr())
    }

    pub fn inherit_env(mut self) -> Self {
        self.env = std::env::vars()
            .map(|(k, v)| {
                // TODO: handle errors, and possibly assert that the key is valid per POSIX
                (
                    CString::new(k).expect("environment key can be converted to a CString"),
                    CString::new(v).expect("environment value can be converted to a CString"),
                )
            })
            .collect();
        self
    }

    pub fn env(mut self, k: &str, v: &str) -> Self {
        self.env.insert(
            // TODO: handle errors, and possibly assert that the key is valid per POSIX
            CString::new(k).expect("environment key can be converted to a CString"),
            CString::new(v).expect("environment value can be converted to a CString"),
        );
        self
    }

    pub fn c_env<S, T>(mut self, k: S, v: T) -> Self
    where
        S: AsRef<CStr>,
        T: AsRef<CStr>,
    {
        self.env
            .insert(k.as_ref().to_owned(), v.as_ref().to_owned());
        self
    }

    /// Add an existing file-like object as a file descriptor in the context.
    ///
    /// When the `WasiCtx` is dropped, all of its associated file descriptors are `close`d. If you
    /// do not want this to close the existing object, use `WasiCtxBuilder::fd_dup()`.
    pub fn fd<F: IntoRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: F) -> Self {
        // safe because we're getting a valid RawFd from the F directly
        unsafe { self.raw_fd(wasm_fd, fd.into_raw_fd()) }
    }

    /// Add an existing file-like object as a duplicate file descriptor in the context.
    ///
    /// The underlying file descriptor of this object will be duplicated before being added to the
    /// context, so it will not be closed when the `WasiCtx` is dropped.
    ///
    /// TODO: handle `dup` errors
    pub fn fd_dup<F: AsRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: &F) -> Self {
        // safe because we're getting a valid RawFd from the F directly
        unsafe { self.raw_fd(wasm_fd, dup(fd.as_raw_fd()).unwrap()) }
    }

    /// Add an existing file descriptor to the context.
    ///
    /// When the `WasiCtx` is dropped, this file descriptor will be `close`d. If you do not want to
    /// close the existing descriptor, use `WasiCtxBuilder::raw_fd_dup()`.
    pub unsafe fn raw_fd(mut self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self {
        self.fds.insert(wasm_fd, FdEntry::from_raw_fd(fd));
        self
    }

    /// Add a duplicate of an existing file descriptor to the context.
    ///
    /// The file descriptor will be duplicated before being added to the context, so it will not be
    /// closed when the `WasiCtx` is dropped.
    ///
    /// TODO: handle `dup` errors
    pub unsafe fn raw_fd_dup(self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self {
        self.raw_fd(wasm_fd, dup(fd).unwrap())
    }

    pub fn preopened_dir<P: AsRef<Path>>(mut self, dir: File, guest_path: P) -> Self {
        self.preopens.insert(guest_path.as_ref().to_owned(), dir);
        self
    }

    pub fn build(mut self) -> Result<WasiCtx, Error> {
        // startup code starts looking at fd 3 for preopens
        let mut preopen_fd = 3;
        for (guest_path, dir) in self.preopens {
            if !dir.metadata()?.is_dir() {
                bail!("preopened file is not a directory");
            }
            while self.fds.contains_key(&preopen_fd) {
                preopen_fd = preopen_fd
                    .checked_add(1)
                    .ok_or(format_err!("not enough file handles"))?;
            }
            let mut fe = FdEntry::from_file(dir);
            fe.preopen_path = Some(guest_path);
            self.fds.insert(preopen_fd, fe);
            preopen_fd += 1;
        }

        let env = self
            .env
            .into_iter()
            .map(|(k, v)| {
                let mut pair = k.into_bytes();
                pair.extend_from_slice(b"=");
                pair.extend_from_slice(v.to_bytes_with_nul());
                // constructing a new CString from existing CStrings is safe
                unsafe { CString::from_vec_unchecked(pair) }
            })
            .collect();

        Ok(WasiCtx {
            fds: self.fds,
            args: self.args,
            env,
        })
    }
}

#[derive(Debug)]
pub struct WasiCtx {
    pub fds: HashMap<host::__wasi_fd_t, FdEntry>,
    pub args: Vec<CString>,
    pub env: Vec<CString>,
}

impl WasiCtx {
    /// Make a new `WasiCtx` with some default settings.
    ///
    /// - File descriptors 0, 1, and 2 inherit stdin, stdout, and stderr from the host process.
    ///
    /// - Environment variables are inherited from the host process.
    ///
    /// To override these behaviors, use `WasiCtxBuilder`.
    pub fn new(args: &[&str]) -> WasiCtx {
        WasiCtxBuilder::new()
            .args(args)
            .inherit_stdio()
            .inherit_env()
            .build()
            .expect("default options don't fail")
    }

    pub fn get_fd_entry(
        &self,
        fd: host::__wasi_fd_t,
        rights_base: host::__wasi_rights_t,
        rights_inheriting: host::__wasi_rights_t,
    ) -> Result<&FdEntry, host::__wasi_errno_t> {
        if let Some(fe) = self.fds.get(&fd) {
            // validate rights
            if !fe.rights_base & rights_base != 0 || !fe.rights_inheriting & rights_inheriting != 0
            {
                Err(host::__WASI_ENOTCAPABLE as host::__wasi_errno_t)
            } else {
                Ok(fe)
            }
        } else {
            Err(host::__WASI_EBADF as host::__wasi_errno_t)
        }
    }

    pub fn insert_fd_entry(
        &mut self,
        fe: FdEntry,
    ) -> Result<host::__wasi_fd_t, host::__wasi_errno_t> {
        // never insert where stdio handles usually are
        let mut fd = 3;
        while self.fds.contains_key(&fd) {
            if let Some(next_fd) = fd.checked_add(1) {
                fd = next_fd;
            } else {
                return Err(host::__WASI_EMFILE as host::__wasi_errno_t);
            }
        }
        self.fds.insert(fd, fe);
        Ok(fd)
    }
}

fn dev_null() -> File {
    OpenOptions::new()
        .read(true)
        .write(true)
        .open("/dev/null")
        .expect("failed to open /dev/null")
}
<|endoftext|>


<commit_before>extern crate collections;
extern crate sync;
use collections::HashMap;
use std::io::{File, Open, Read, Write, TempDir};
use sync::{Arc, RWLock};

struct BufferManager {
	size: uint,
	entries: HashMap<u64, BufferEntry>,
	directory: TempDir,
}

struct BufferEntry {
	frame: Arc<RWLock<BufferFrame>>,
}

struct BufferFrame {
	pageId: u64,
	data: Vec<u8>,
}

/* Destructor trait implementation */
impl Drop for BufferManager {
	fn drop(&mut self) {
		println!("Dropping");
		// TODO
	}
}

impl BufferManager {
	pub fn new(size: uint) -> BufferManager {
		let h = HashMap::with_capacity(size);
		let dir = match TempDir::new("buffermanager") {
			Some(temp_dir) => temp_dir,
			None => fail!("creation of temporary directory"),
		};
		BufferManager {size: size, entries: h, directory: dir}
	}

	fn openOrCreate(&self, pageId: u64) -> File {
		let page_path = self.directory.path();
		let file_path = page_path.join(pageId.to_str());
		match File::open_mode(&file_path, Open, Read) {
			Ok(f) => f,
			Err(e) => {
				match File::open_mode(&file_path, Open, Write) {
					Ok(mut f) => {
						f.write([0_u8, ..4 * 1024]);
						match File::open_mode(&file_path, Open, Read) {
							Ok(f) => f,
							Err(e) => fail!("failed reading file: {}, e"),
						}
					},
					Err(e) => fail!("Writing file failed: {}", e),
				}
			},
		}
	}

	fn loadPage(&mut self, pageId: u64) {
		if self.entries.len() == self.size {
			self.evictPage();
		}

		let mut file_handle = self.openOrCreate(pageId);
		let content = match file_handle.read_exact(4*1024) {
			Ok(c) => Vec::from_slice(c),
			Err(e) => fail!("Couldn't read from page: {}", e),
		};

		let frame = BufferFrame {data: content, pageId: pageId};
		let entry = BufferEntry {frame: Arc::new(RWLock::new(frame))};
		self.entries.insert(pageId, entry);
	}

	fn evictPage(&mut self) {
		// TODO delete a random page
	}

	pub fn fixPage(&mut self, pageId: u64, exclusive: bool) -> Option<Arc<RWLock<BufferFrame>>> {
		// TODO
		if !self.entries.contains_key(&pageId) {
			self.loadPage(pageId);
		}
		let entry = self.entries.get(&pageId);
		// Arcs can be cloned and they will all point to the same RWLock
		Some(entry.frame.clone())
	}

	pub fn unfixPage(&mut self, frame: Arc<RWLock<BufferFrame>>, isDirty: bool) {
		if !isDirty {
			return;
		}
		let frame = frame.read();
		self.writePage(frame.pageId, frame.get_data());
	}

	fn writePage(&mut self, pageId: u64, data: &[u8]) {
		// TODO: write page back to disk
		println!("Writing {}", data);
	}
}

/*
 * A buffer frame, the unit that gets the data
 */
impl BufferFrame {
	/*
	 * get_mut_data returns a borrowed reference to a mutable slice to the vector
	 * contents.
	 */
	pub fn get_mut_data<'a>(&'a mut self) -> &'a mut [u8] {
		self.data.as_mut_slice()
	}
	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

#[test]
fn test_create() {
	let _ = BufferManager::new(16);
}
<commit_msg>Added some tests<commit_after>extern crate collections;
extern crate sync;
use collections::HashMap;
use std::io::{File, Open, Read, Write, TempDir};
use sync::{Arc, RWLock};
#[cfg(test)]
use std::task::spawn;

struct BufferManager {
	size: uint,
	entries: HashMap<u64, BufferEntry>,
	directory: TempDir,
}

struct BufferEntry {
	frame: Arc<RWLock<BufferFrame>>,
}

struct BufferFrame {
	pageId: u64,
	data: Vec<u8>,
}

/* Destructor trait implementation */
impl Drop for BufferManager {
	fn drop(&mut self) {
		println!("Dropping");
		// TODO
	}
}

impl BufferManager {
	pub fn new(size: uint) -> BufferManager {
		let h = HashMap::with_capacity(size);
		let dir = match TempDir::new("buffermanager") {
			Some(temp_dir) => temp_dir,
			None => fail!("creation of temporary directory"),
		};
		BufferManager {size: size, entries: h, directory: dir}
	}

	fn openOrCreate(&self, pageId: u64) -> File {
		let page_path = self.directory.path();
		let file_path = page_path.join(pageId.to_str());
		match File::open_mode(&file_path, Open, Read) {
			Ok(f) => f,
			Err(e) => {
				match File::open_mode(&file_path, Open, Write) {
					Ok(mut f) => {
						f.write([0_u8, ..4 * 1024]);
						match File::open_mode(&file_path, Open, Read) {
							Ok(f) => f,
							Err(e) => fail!("failed reading file: {}", e),
						}
					},
					Err(e) => fail!("Writing file failed: {}", e),
				}
			},
		}
	}

	fn loadPage(&mut self, pageId: u64) {
		if self.entries.len() == self.size {
			self.evictPage();
		}

		let mut file_handle = self.openOrCreate(pageId);
		let content = match file_handle.read_exact(4*1024) {
			Ok(c) => Vec::from_slice(c),
			Err(e) => fail!("Couldn't read from page: {}", e),
		};

		let frame = BufferFrame {data: content, pageId: pageId};
		let entry = BufferEntry {frame: Arc::new(RWLock::new(frame))};
		self.entries.insert(pageId, entry);
	}

	fn evictPage(&mut self) {
		// TODO delete a random page
		// evicting is hard, let's go shopping
	}

	pub fn fixPage(&mut self, pageId: u64, exclusive: bool) -> Option<Arc<RWLock<BufferFrame>>> {
		// TODO
		if !self.entries.contains_key(&pageId) {
			self.loadPage(pageId);
		}
		let entry = self.entries.get(&pageId);
		// Arcs can be cloned and they will all point to the same RWLock
		Some(entry.frame.clone())
	}

	pub fn unfixPage(&mut self, frame: Arc<RWLock<BufferFrame>>, isDirty: bool) {
		if !isDirty {
			return;
		}
		let frame = frame.read();
		self.writePage(frame.pageId, frame.get_data());
	}

	fn writePage(&mut self, pageId: u64, data: &[u8]) {
		// TODO: write page back to disk
		println!("Writing {}", data);
	}
}

/*
 * A buffer frame, the unit that gets the data
 */
impl BufferFrame {
	/*
	 * get_mut_data returns a borrowed reference to a mutable slice to the vector
	 * contents.
	 */
	pub fn get_mut_data<'a>(&'a mut self) -> &'a mut [u8] {
		self.data.as_mut_slice()
	}
	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

#[test]
fn test_create() {
	let mut bm = BufferManager::new(16);
	let pageref = match bm.fixPage(42, false) {
		Some(p) => p,
		None => fail!("Getting page failed"),
	};
	{
		let mut page = pageref.write();
		let mut data = page.get_mut_data();
		data[0] = 42;
		println!("data: {}", Vec::from_slice(data));
	}
	bm.unfixPage(pageref, true);
	fail!("always");
}

#[test]
fn test_threads() {
	let pages_in_ram = 20;
	let pages_on_disk = 20;
	let thread_count = 10;
	let mut bm = BufferManager::new(pages_in_ram);

	for _ in range(0, thread_count) {
		spawn(proc() {
			println!("I'm a new task");
		})
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate byteorder;
extern crate elf;
use std::path::PathBuf;

extern crate rbpf;
use rbpf::helpers;

// The following example uses an ELF file that has been compiled from the C program available in
// `load_elf__block_a_port.c` in the same directory.
//
// It was compiled with the following command:
//
// ```bash
// clang -O2 -emit-llvm -c load_elf__block_a_port.c -o - | \
//     llc -march=bpf -filetype=obj -o load_elf__block_a_port.o
// ```
//
// Once compiled, this program can be injected into Linux kernel, with tc for instance. Sadly, we
// need to bring some modifications to the generated bytecode in order to run it: the three
// instructions with opcode 0x61 load data from a packet area as 4-byte words, where we need to
// load it as 8-bytes double words (0x79). The kernel does the same kind of translation before
// running the program, but rbpf does not implement this.
//
// In addition, the offset at which the pointer to the packet data is stored must be changed: since
// we use 8 bytes instead of 4 for the start and end addresses of the data packet, we cannot use
// the offsets produced by clang (0x4c and 0x50), the addresses would overlap. Instead we can use,
// for example, 0x40 and 0x50.
//
// These change were applied with the following script:
//
// ```bash
// xxd load_elf__block_a_port.o | sed '
//     s/6112 5000 0000 0000/7912 5000 0000 0000/ ;
//     s/6111 4c00 0000 0000/7911 4000 0000 0000/ ;
//     s/6111 2200 0000 0000/7911 2200 0000 0000/' | xxd -r > load_elf__block_a_port.tmp

// mv load_elf__block_a_port.tmp load_elf__block_a_port.o
// ```
//
// The eBPF program was placed into the `.classifier` ELF section (see C code above), which means
// that you can retrieve the raw bytecode with `readelf -x .classifier load_elf__block_a_port.o` or
// with `objdump -s -j .classifier load_elf__block_a_port.o`.
//
// Once the bytecode has been edited, we can load the bytecode directly from the ELF object file.

fn main() {

    let filename = "examples/load_elf__block_a_port.o";

    let path = PathBuf::from(filename);
    let file = match elf::File::open_path(&path) {
        Ok(f) => f,
        Err(e) => panic!("Error: {:?}", e),
    };

    let text_scn = match file.get_section(".classifier") {
        Some(s) => s,
        None => panic!("Failed to look up .classifier section"),
    };

    let prog = &text_scn.data;

    let packet1 = &mut [
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
        0x08, 0x00, // ethertype
        0x45, 0x00, 0x00, 0x3b, // start ip_hdr
        0xa6, 0xab, 0x40, 0x00,
        0x40, 0x06, 0x96, 0x0f,
        0x7f, 0x00, 0x00, 0x01,
        0x7f, 0x00, 0x00, 0x01,
        // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
        0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
        0xd1, 0xe5, 0xc4, 0x9d,
        0xd4, 0x30, 0xb5, 0xd2,
        0x80, 0x18, 0x01, 0x56,
        0xfe, 0x2f, 0x00, 0x00,
        0x01, 0x01, 0x08, 0x0a, // start data
        0x00, 0x23, 0x75, 0x89,
        0x00, 0x23, 0x63, 0x2d,
        0x71, 0x64, 0x66, 0x73,
        0x64, 0x66, 0x0au8
    ];

    let mut packet2 = &mut [
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
        0x08, 0x00, // ethertype
        0x45, 0x00, 0x00, 0x3b, // start ip_hdr
        0xa6, 0xab, 0x40, 0x00,
        0x40, 0x06, 0x96, 0x0f,
        0x7f, 0x00, 0x00, 0x01,
        0x7f, 0x00, 0x00, 0x01,
        // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
        0x98, 0x76, 0xc6, 0xcc, // start tcp_hdr
        0xd1, 0xe5, 0xc4, 0x9d,
        0xd4, 0x30, 0xb5, 0xd2,
        0x80, 0x18, 0x01, 0x56,
        0xfe, 0x2f, 0x00, 0x00,
        0x01, 0x01, 0x08, 0x0a, // start data
        0x00, 0x23, 0x75, 0x89,
        0x00, 0x23, 0x63, 0x2d,
        0x71, 0x64, 0x66, 0x73,
        0x64, 0x66, 0x0au8
    ];

    let mut vm = rbpf::EbpfVmFixedMbuff::new(prog, 0x40, 0x50);
    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf);

    let res = vm.prog_exec(packet1);
    println!("Packet #1, program returned: {:?} ({:#x})", res, res);
    assert_eq!(res, 0xffffffff);

    vm.jit_compile();
    unsafe {
        let res = vm.prog_exec_jit(packet2);
        println!("Packet #2, program returned: {:?} ({:#x})", res, res);
        assert_eq!(res, 0);
    }
}
<commit_msg>Remove unused mut from buffer.<commit_after>// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate byteorder;
extern crate elf;
use std::path::PathBuf;

extern crate rbpf;
use rbpf::helpers;

// The following example uses an ELF file that has been compiled from the C program available in
// `load_elf__block_a_port.c` in the same directory.
//
// It was compiled with the following command:
//
// ```bash
// clang -O2 -emit-llvm -c load_elf__block_a_port.c -o - | \
//     llc -march=bpf -filetype=obj -o load_elf__block_a_port.o
// ```
//
// Once compiled, this program can be injected into Linux kernel, with tc for instance. Sadly, we
// need to bring some modifications to the generated bytecode in order to run it: the three
// instructions with opcode 0x61 load data from a packet area as 4-byte words, where we need to
// load it as 8-bytes double words (0x79). The kernel does the same kind of translation before
// running the program, but rbpf does not implement this.
//
// In addition, the offset at which the pointer to the packet data is stored must be changed: since
// we use 8 bytes instead of 4 for the start and end addresses of the data packet, we cannot use
// the offsets produced by clang (0x4c and 0x50), the addresses would overlap. Instead we can use,
// for example, 0x40 and 0x50.
//
// These change were applied with the following script:
//
// ```bash
// xxd load_elf__block_a_port.o | sed '
//     s/6112 5000 0000 0000/7912 5000 0000 0000/ ;
//     s/6111 4c00 0000 0000/7911 4000 0000 0000/ ;
//     s/6111 2200 0000 0000/7911 2200 0000 0000/' | xxd -r > load_elf__block_a_port.tmp

// mv load_elf__block_a_port.tmp load_elf__block_a_port.o
// ```
//
// The eBPF program was placed into the `.classifier` ELF section (see C code above), which means
// that you can retrieve the raw bytecode with `readelf -x .classifier load_elf__block_a_port.o` or
// with `objdump -s -j .classifier load_elf__block_a_port.o`.
//
// Once the bytecode has been edited, we can load the bytecode directly from the ELF object file.

fn main() {

    let filename = "examples/load_elf__block_a_port.o";

    let path = PathBuf::from(filename);
    let file = match elf::File::open_path(&path) {
        Ok(f) => f,
        Err(e) => panic!("Error: {:?}", e),
    };

    let text_scn = match file.get_section(".classifier") {
        Some(s) => s,
        None => panic!("Failed to look up .classifier section"),
    };

    let prog = &text_scn.data;

    let packet1 = &mut [
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
        0x08, 0x00, // ethertype
        0x45, 0x00, 0x00, 0x3b, // start ip_hdr
        0xa6, 0xab, 0x40, 0x00,
        0x40, 0x06, 0x96, 0x0f,
        0x7f, 0x00, 0x00, 0x01,
        0x7f, 0x00, 0x00, 0x01,
        // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
        0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
        0xd1, 0xe5, 0xc4, 0x9d,
        0xd4, 0x30, 0xb5, 0xd2,
        0x80, 0x18, 0x01, 0x56,
        0xfe, 0x2f, 0x00, 0x00,
        0x01, 0x01, 0x08, 0x0a, // start data
        0x00, 0x23, 0x75, 0x89,
        0x00, 0x23, 0x63, 0x2d,
        0x71, 0x64, 0x66, 0x73,
        0x64, 0x66, 0x0au8
    ];

    let packet2 = &mut [
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
        0x08, 0x00, // ethertype
        0x45, 0x00, 0x00, 0x3b, // start ip_hdr
        0xa6, 0xab, 0x40, 0x00,
        0x40, 0x06, 0x96, 0x0f,
        0x7f, 0x00, 0x00, 0x01,
        0x7f, 0x00, 0x00, 0x01,
        // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
        0x98, 0x76, 0xc6, 0xcc, // start tcp_hdr
        0xd1, 0xe5, 0xc4, 0x9d,
        0xd4, 0x30, 0xb5, 0xd2,
        0x80, 0x18, 0x01, 0x56,
        0xfe, 0x2f, 0x00, 0x00,
        0x01, 0x01, 0x08, 0x0a, // start data
        0x00, 0x23, 0x75, 0x89,
        0x00, 0x23, 0x63, 0x2d,
        0x71, 0x64, 0x66, 0x73,
        0x64, 0x66, 0x0au8
    ];

    let mut vm = rbpf::EbpfVmFixedMbuff::new(prog, 0x40, 0x50);
    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf);

    let res = vm.prog_exec(packet1);
    println!("Packet #1, program returned: {:?} ({:#x})", res, res);
    assert_eq!(res, 0xffffffff);

    vm.jit_compile();
    unsafe {
        let res = vm.prog_exec_jit(packet2);
        println!("Packet #2, program returned: {:?} ({:#x})", res, res);
        assert_eq!(res, 0);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::cmp;
use std::sync::Arc;

use buffer::TrackedBuffer;
use command_buffer::submit::SubmitInfo;
use command_buffer::sys::PipelineBarrierBuilder;
use descriptor::descriptor_set::DescriptorSet;
use descriptor::descriptor_set::TrackedDescriptorSet;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use descriptor::descriptor_set::DescriptorPool;
use descriptor::descriptor_set::sys::UnsafeDescriptorSet;
use device::Queue;
use sync::AccessFlagBits;
use sync::Fence;
use sync::PipelineStages;

pub struct StdDescriptorSet<R> {
    inner: UnsafeDescriptorSet,
    resources: R,
}

impl<R> StdDescriptorSet<R> {
    ///
    /// # Safety
    ///
    /// - The resources must match the layout.
    ///
    pub unsafe fn new(pool: &Arc<DescriptorPool>, layout: &Arc<UnsafeDescriptorSetLayout>,
                      resources: R) -> StdDescriptorSet<R>
    {
        unimplemented!()
    }

    /// Returns the layout used to create this descriptor set.
    #[inline]
    pub fn layout(&self) -> &Arc<UnsafeDescriptorSetLayout> {
        self.inner.layout()
    }
}

unsafe impl<R> DescriptorSet for StdDescriptorSet<R> {
    #[inline]
    fn inner(&self) -> &UnsafeDescriptorSet {
        &self.inner
    }
}

unsafe impl<R, S> TrackedDescriptorSet<S> for StdDescriptorSet<R>
    where R: StdDescriptorSetResourcesCollection<S>
{
    #[inline]
    unsafe fn transition(&self, states: &mut S, num_command: usize)
                         -> (usize, PipelineBarrierBuilder)
    {
        self.resources.transition(states, num_command)
    }

    #[inline]
    unsafe fn finish(&self, i: &mut S, o: &mut S) -> PipelineBarrierBuilder {
        self.resources.finish(i, o)
    }

    #[inline]
    unsafe fn on_submit<F>(&self, states: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>
    {
        self.resources.on_submit(states, queue, fence)
    }
}

// TODO: re-read docs
/// Collection of tracked resources. Makes it possible to treat multiple buffers and images as one.
pub unsafe trait StdDescriptorSetResourcesCollection<States> {
    /// Extracts the states relevant to the buffers and images contained in the descriptor set.
    /// Then transitions them to the right state.
    // TODO: must return a Result if multiple elements conflict with one another
    unsafe fn transition(&self, states: &mut States, num_command: usize)
                         -> (usize, PipelineBarrierBuilder);

    unsafe fn finish(&self, in_s: &mut States, out: &mut States) -> PipelineBarrierBuilder;

    // TODO: write docs
    unsafe fn on_submit<F>(&self, &States, queue: &Arc<Queue>, fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>;
}

unsafe impl<S> StdDescriptorSetResourcesCollection<S> for () {
    #[inline]
    unsafe fn transition(&self, _: &mut S, _: usize) -> (usize, PipelineBarrierBuilder) {
        (0, PipelineBarrierBuilder::new())
    }

    #[inline]
    unsafe fn finish(&self, _: &mut S, _: &mut S) -> PipelineBarrierBuilder {
        PipelineBarrierBuilder::new()
    }

    #[inline]
    unsafe fn on_submit<F>(&self, _: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>
    {
        SubmitInfo::empty()
    }
}

pub struct StdDescriptorSetBuf<B> {
    pub buffer: B,
    pub ty: StdDescriptorSetBufTy,
    pub write: bool,
    pub stage: PipelineStages,
    pub access: AccessFlagBits,
}

unsafe impl<B, S> StdDescriptorSetResourcesCollection<S> for StdDescriptorSetBuf<B>
    where B: TrackedBuffer<S>
{
    #[inline]
    unsafe fn transition(&self, states: &mut S, num_command: usize)
                         -> (usize, PipelineBarrierBuilder)
    {
        let trans = self.buffer.transition(states, num_command, 0, self.buffer.size(),
                                           self.write, self.stage, self.access);

        if let Some(trans) = trans {
            let n = trans.after_command_num;
            let mut b = PipelineBarrierBuilder::new();
            b.add_buffer_barrier_request(&self.buffer, trans);
            (n, b)
        } else {
            (0, PipelineBarrierBuilder::new())
        }
    }

    #[inline]
    unsafe fn finish(&self, in_s: &mut S, out: &mut S) -> PipelineBarrierBuilder {
        if let Some(trans) = self.buffer.finish(in_s, out) {
            let mut b = PipelineBarrierBuilder::new();
            b.add_buffer_barrier_request(&self.buffer, trans);
            b
        } else {
            PipelineBarrierBuilder::new()
        }
    }

    unsafe fn on_submit<F>(&self, _: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>
    {
        unimplemented!()        // FIXME:
    }
}

pub enum StdDescriptorSetBufTy {
    StorageBuffer,
    UniformBuffer,
    DynamicStorageBuffer,
    DynamicUniformBuffer,
}

macro_rules! tuple_impl {
    ($first:ident, $($rest:ident),+) => (
        unsafe impl<S, $first, $($rest),+> StdDescriptorSetResourcesCollection<S> for ($first $(, $rest)+)
            where $first: StdDescriptorSetResourcesCollection<S>,
                  $($rest: StdDescriptorSetResourcesCollection<S>),+
        {
            #[inline]
            unsafe fn transition(&self, states: &mut S, num_command: usize)
                                 -> (usize, PipelineBarrierBuilder)
            {
                #![allow(non_snake_case)]
                let &(ref $first $(, ref $rest)+) = self;
                let (mut nc, mut barrier) = $first.transition(states, num_command);
                $({
                    let (n, b) = $rest.transition(states, num_command);
                    nc = cmp::max(nc, n);
                    barrier.merge(b);
                })+
                debug_assert!(nc <= num_command);
                (nc, barrier)
            }

            #[inline]
            unsafe fn finish(&self, in_s: &mut S, out: &mut S) -> PipelineBarrierBuilder {
                #![allow(non_snake_case)]
                let &(ref $first $(, ref $rest)+) = self;
                let mut barrier = $first.finish(in_s, out);
                $(
                    barrier.merge($rest.finish(in_s, out));
                )+
                barrier
            }

            unsafe fn on_submit<F>(&self, _: &S, queue: &Arc<Queue>, fence: F)
                                -> SubmitInfo
                where F: FnMut() -> Arc<Fence>
            {
                unimplemented!()
            }
        }

        tuple_impl!($($rest),+);
    );

    ($first:ident) => ();
}

tuple_impl!(A, C, D, E, G, H, J, K, M, N, O, P, Q, R, T, U, V, W, X, Y, Z);
<commit_msg>Add StdDescriptorSetBufView<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::cmp;
use std::sync::Arc;

use buffer::Buffer;
use buffer::BufferView;
use buffer::TrackedBuffer;
use command_buffer::submit::SubmitInfo;
use command_buffer::sys::PipelineBarrierBuilder;
use descriptor::descriptor_set::DescriptorSet;
use descriptor::descriptor_set::TrackedDescriptorSet;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use descriptor::descriptor_set::DescriptorPool;
use descriptor::descriptor_set::sys::UnsafeDescriptorSet;
use device::Queue;
use sync::AccessFlagBits;
use sync::Fence;
use sync::PipelineStages;

pub struct StdDescriptorSet<R> {
    inner: UnsafeDescriptorSet,
    resources: R,
}

impl<R> StdDescriptorSet<R> {
    ///
    /// # Safety
    ///
    /// - The resources must match the layout.
    ///
    pub unsafe fn new(pool: &Arc<DescriptorPool>, layout: &Arc<UnsafeDescriptorSetLayout>,
                      resources: R) -> StdDescriptorSet<R>
    {
        unimplemented!()
    }

    /// Returns the layout used to create this descriptor set.
    #[inline]
    pub fn layout(&self) -> &Arc<UnsafeDescriptorSetLayout> {
        self.inner.layout()
    }
}

unsafe impl<R> DescriptorSet for StdDescriptorSet<R> {
    #[inline]
    fn inner(&self) -> &UnsafeDescriptorSet {
        &self.inner
    }
}

unsafe impl<R, S> TrackedDescriptorSet<S> for StdDescriptorSet<R>
    where R: StdDescriptorSetResourcesCollection<S>
{
    #[inline]
    unsafe fn transition(&self, states: &mut S, num_command: usize)
                         -> (usize, PipelineBarrierBuilder)
    {
        self.resources.transition(states, num_command)
    }

    #[inline]
    unsafe fn finish(&self, i: &mut S, o: &mut S) -> PipelineBarrierBuilder {
        self.resources.finish(i, o)
    }

    #[inline]
    unsafe fn on_submit<F>(&self, states: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>
    {
        self.resources.on_submit(states, queue, fence)
    }
}

// TODO: re-read docs
/// Collection of tracked resources. Makes it possible to treat multiple buffers and images as one.
pub unsafe trait StdDescriptorSetResourcesCollection<States> {
    /// Extracts the states relevant to the buffers and images contained in the descriptor set.
    /// Then transitions them to the right state.
    // TODO: must return a Result if multiple elements conflict with one another
    unsafe fn transition(&self, states: &mut States, num_command: usize)
                         -> (usize, PipelineBarrierBuilder);

    unsafe fn finish(&self, in_s: &mut States, out: &mut States) -> PipelineBarrierBuilder;

    // TODO: write docs
    unsafe fn on_submit<F>(&self, &States, queue: &Arc<Queue>, fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>;
}

unsafe impl<S> StdDescriptorSetResourcesCollection<S> for () {
    #[inline]
    unsafe fn transition(&self, _: &mut S, _: usize) -> (usize, PipelineBarrierBuilder) {
        (0, PipelineBarrierBuilder::new())
    }

    #[inline]
    unsafe fn finish(&self, _: &mut S, _: &mut S) -> PipelineBarrierBuilder {
        PipelineBarrierBuilder::new()
    }

    #[inline]
    unsafe fn on_submit<F>(&self, _: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>
    {
        SubmitInfo::empty()
    }
}

pub struct StdDescriptorSetBuf<B> {
    pub buffer: B,
    pub ty: StdDescriptorSetBufTy,
    pub write: bool,
    pub stage: PipelineStages,
    pub access: AccessFlagBits,
}

unsafe impl<B, S> StdDescriptorSetResourcesCollection<S> for StdDescriptorSetBuf<B>
    where B: TrackedBuffer<S>
{
    #[inline]
    unsafe fn transition(&self, states: &mut S, num_command: usize)
                         -> (usize, PipelineBarrierBuilder)
    {
        let trans = self.buffer.transition(states, num_command, 0, self.buffer.size(),
                                           self.write, self.stage, self.access);

        if let Some(trans) = trans {
            let n = trans.after_command_num;
            let mut b = PipelineBarrierBuilder::new();
            b.add_buffer_barrier_request(&self.buffer, trans);
            (n, b)
        } else {
            (0, PipelineBarrierBuilder::new())
        }
    }

    #[inline]
    unsafe fn finish(&self, in_s: &mut S, out: &mut S) -> PipelineBarrierBuilder {
        if let Some(trans) = self.buffer.finish(in_s, out) {
            let mut b = PipelineBarrierBuilder::new();
            b.add_buffer_barrier_request(&self.buffer, trans);
            b
        } else {
            PipelineBarrierBuilder::new()
        }
    }

    unsafe fn on_submit<F>(&self, _: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfo
        where F: FnMut() -> Arc<Fence>
    {
        unimplemented!()        // FIXME:
    }
}

pub enum StdDescriptorSetBufTy {
    StorageBuffer,
    UniformBuffer,
    DynamicStorageBuffer,
    DynamicUniformBuffer,
}

pub struct StdDescriptorSetBufView<F, B> where B: Buffer {
    pub view: Arc<BufferView<F, B>>,
    pub ty: StdDescriptorSetBufViewTy,
    pub write: bool,
    pub stage: PipelineStages,
    pub access: AccessFlagBits,
}

unsafe impl<F, B, S> StdDescriptorSetResourcesCollection<S> for StdDescriptorSetBufView<F, B>
    where B: TrackedBuffer<S>
{
    #[inline]
    unsafe fn transition(&self, states: &mut S, num_command: usize)
                         -> (usize, PipelineBarrierBuilder)
    {
        let trans = self.view.buffer().transition(states, num_command, 0, self.view.buffer().size(),
                                                  self.write, self.stage, self.access);

        if let Some(trans) = trans {
            let n = trans.after_command_num;
            let mut b = PipelineBarrierBuilder::new();
            b.add_buffer_barrier_request(&self.view.buffer(), trans);
            (n, b)
        } else {
            (0, PipelineBarrierBuilder::new())
        }
    }

    #[inline]
    unsafe fn finish(&self, in_s: &mut S, out: &mut S) -> PipelineBarrierBuilder {
        if let Some(trans) = self.view.buffer().finish(in_s, out) {
            let mut b = PipelineBarrierBuilder::new();
            b.add_buffer_barrier_request(&self.view.buffer(), trans);
            b
        } else {
            PipelineBarrierBuilder::new()
        }
    }

    unsafe fn on_submit<Fe>(&self, _: &S, queue: &Arc<Queue>, fence: Fe) -> SubmitInfo
        where Fe: FnMut() -> Arc<Fence>
    {
        unimplemented!()        // FIXME:
    }
}

pub enum StdDescriptorSetBufViewTy {
    StorageBufferView,
    UniformBufferView,
}

macro_rules! tuple_impl {
    ($first:ident, $($rest:ident),+) => (
        unsafe impl<S, $first, $($rest),+> StdDescriptorSetResourcesCollection<S> for ($first $(, $rest)+)
            where $first: StdDescriptorSetResourcesCollection<S>,
                  $($rest: StdDescriptorSetResourcesCollection<S>),+
        {
            #[inline]
            unsafe fn transition(&self, states: &mut S, num_command: usize)
                                 -> (usize, PipelineBarrierBuilder)
            {
                #![allow(non_snake_case)]
                let &(ref $first $(, ref $rest)+) = self;
                let (mut nc, mut barrier) = $first.transition(states, num_command);
                $({
                    let (n, b) = $rest.transition(states, num_command);
                    nc = cmp::max(nc, n);
                    barrier.merge(b);
                })+
                debug_assert!(nc <= num_command);
                (nc, barrier)
            }

            #[inline]
            unsafe fn finish(&self, in_s: &mut S, out: &mut S) -> PipelineBarrierBuilder {
                #![allow(non_snake_case)]
                let &(ref $first $(, ref $rest)+) = self;
                let mut barrier = $first.finish(in_s, out);
                $(
                    barrier.merge($rest.finish(in_s, out));
                )+
                barrier
            }

            unsafe fn on_submit<F>(&self, _: &S, queue: &Arc<Queue>, fence: F)
                                -> SubmitInfo
                where F: FnMut() -> Arc<Fence>
            {
                unimplemented!()
            }
        }

        tuple_impl!($($rest),+);
    );

    ($first:ident) => ();
}

tuple_impl!(A, C, D, E, G, H, J, K, M, N, O, P, Q, R, T, U, V, W, X, Y, Z);
<|endoftext|>


<commit_before>//! The cc_use proc macro.
//!
//! This represents one side of the cc_use logic. The other side is in the bindings generator.

extern crate proc_macro;

use cc_use_common::{CcUse, LibName};
use proc_macro2::TokenStream;
use quote::quote;
use std::path::PathBuf;
use syn::{parse_macro_input, punctuated::Punctuated, Ident, Token};

#[proc_macro]
pub fn cc_use(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let mac = parse_macro_input!(input as CcUse);
    cc_use_impl(mac).into()
}

fn cc_use_impl(input: CcUse) -> TokenStream {
    let CcUse {
        header,
        lib_name,
        cc_paths,
        ..
    } = input;
    let native_lib = lib_name.clone().unwrap_or_else(|| LibName {
        name: PathBuf::from(header.path)
            .file_stem()
            .unwrap()
            .to_string_lossy()
            .to_string(),
        span: header.span,
    });
    let crate_name = Ident::new(&(native_lib.name + "_bind"), native_lib.span);
    let paths: Punctuated<_, Token![,]> = cc_paths.iter().collect();
    quote! {
        extern crate #crate_name;
        use #crate_name::{#paths};
    }
}
<commit_msg>Report error if header path is not UTF-8<commit_after>//! The cc_use proc macro.
//!
//! This represents one side of the cc_use logic. The other side is in the bindings generator.

extern crate proc_macro;

use cc_use_common::{CcUse, LibName};
use proc_macro2::TokenStream;
use quote::quote;
use std::path::PathBuf;
use syn::{parse_macro_input, punctuated::Punctuated, Ident, Token};

#[proc_macro]
pub fn cc_use(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let mac = parse_macro_input!(input as CcUse);
    cc_use_impl(mac).into()
}

fn cc_use_impl(input: CcUse) -> TokenStream {
    let CcUse {
        header,
        lib_name,
        cc_paths,
        ..
    } = input;
    let native_lib = lib_name.clone().unwrap_or_else(|| LibName {
        name: PathBuf::from(header.path)
            .file_stem()
            .unwrap()
            .to_str()
            .expect("Header path must be valid UTF-8")
            .to_string(),
        span: header.span,
    });
    let crate_name = Ident::new(&(native_lib.name + "_bind"), native_lib.span);
    let paths: Punctuated<_, Token![,]> = cc_paths.iter().collect();
    quote! {
        extern crate #crate_name;
        use #crate_name::{#paths};
    }
}
<|endoftext|>