<commit_before>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
use collections::HashMap;
use std::io::{File, Open, Read, Write, TempDir};
use std::num::Zero;
use std::comm::{Data, Empty, Disconnected};
use sync::{Arc, RWLock};
use sync::Future;
use rand::task_rng;
use rand::distributions::{IndependentSample, Range};
use rand::distributions::range::SampleRange;

static PAGE_SIZE: uint = 4 * 1024;

struct BufferManager {
	size: uint,
	entries: HashMap<u64, BufferEntry>,
	path: Path,
}

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

#[deriving(Eq)]
enum Status {
	Free,
	Fixed(uint),
}

struct BufferFrame {
	page_id: u64,
	data: Vec<u8>,
	fixed: Status,
}

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

impl BufferManager {
	pub fn new(size: uint, path: Path) -> BufferManager {
		let h = HashMap::with_capacity(size);
		BufferManager {size: size, entries: h, path: path}
	}

	fn open_or_create(&self, page_id: u64) -> File {
		let file_path = self.path.join(page_id.to_str());
		match File::open_mode(&file_path, Open, Read) {
			Ok(f) => f,
			Err(_) => {
				match File::open_mode(&file_path, Open, Write) {
					Ok(mut f) => {
						match f.write([0_u8, ..PAGE_SIZE]) {
							Ok(_) => (),
							Err(e) => fail!("writing page failed: {}", e),
						}
						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),
				}
			},
		}
	}

	/*
	 * returns true if page could be loaded
	 */
	fn load_page(&mut self, page_id: u64) -> bool {
		if self.entries.len() == self.size {
			if !self.evict_page() {
				return false;
			}
		}

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

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

	/*
	 * return false if no page could be evicted
	 */
	fn evict_page(&mut self) -> bool {
		let random_key = {
			let mut free_keys = self.entries.iter().filter_map(|e| {
				// iterate over entries, check if they are free
				// and return the keys of the free entries
				let (k,v) = e;
				let frame = v.frame.read();
				if frame.fixed == Free {
					Some(k)
				} else {
					None
				}
			});
			// pick a random key
			sample(&mut free_keys).map(|v| v.clone())
		};

		match random_key {
			None => false,
			Some(key) => self.entries.remove(&key),
		}
	}

	pub fn fix_page(&mut self, page_id: u64) -> Option<Arc<RWLock<BufferFrame>>> {
		if !self.entries.contains_key(&page_id) {
			if !self.load_page(page_id) {
				return None;
			}
		}
		let entry = self.entries.get(&page_id);
		{
			let mut f = entry.frame.write();
			f.fixed = match f.fixed {
				Free => Fixed(1),
				Fixed(n) => Fixed(n+1),
			};
		}
		// Arcs can be cloned and they will all point to the same RWLock
		Some(entry.frame.clone())
	}

	pub fn unfix_page(&mut self, frame: Arc<RWLock<BufferFrame>>, is_dirty: bool) {
		{
			let mut frame = frame.write();
			frame.fixed = match frame.fixed {
				Fixed(1) => Free,
				Fixed(n) => Fixed(n-1),
				Free => fail!("Unfixing unfixed page"),
			};
		}

		if !is_dirty {
			return;
		}
		let frame = frame.read();
		if frame.fixed == Free {
			info!("writing back page \\#{}", frame.page_id);
			self.write_page(frame.page_id, frame.get_data());
		}
	}

	fn write_page(&mut self, page_id: u64, data: &[u8]) {
		let file_path = self.path.join(page_id.to_str());
		let mut handle = match File::open_mode(&file_path, Open, Write) {
			Ok(handle) => handle,
			Err(e) => fail!("Opening file for writing failed: {}", e),
		};

		match handle.write(data) {
			Ok(_) => (),
			Err(e) => fail!("Writing to file failed: {}", e),
		};
	}
}

/*
 * 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()
	}
}

fn sample<'a, T, I:Iterator<T>>(from: &'a mut I) -> Option<T> {
	let from: ~[T] = from.collect();
	let l = from.len();
	if l == 0 {
		return None;
	}
	let index = randrange(l);
	Some(from[index])
}

fn randrange<X: SampleRange + Ord + Zero>(high: X) -> X {
	let between: Range<X> = Range::new(Zero::zero(), high);
	let mut rng = rand::task_rng();
	between.ind_sample(&mut rng)
}

#[test]
fn test_create() {
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	let mut bm = BufferManager::new(16, dir.path().clone());
	let pageref = match bm.fix_page(42) {
		Some(p) => p,
		None => fail!("Getting page failed"),
	};
	{
		let mut page = pageref.write();
		let data = page.get_mut_data();
		data[0] = 42;
	}
	bm.unfix_page(pageref, true);
}

#[test]
fn test_threads() {
	use rand::random;
	use std::task::spawn;
	use std::os;

	let pages_in_ram: uint = match os::getenv("PAGES_IN_RAM") {
		Some(v) => from_str(v).expect("PAGES_IN_RAM expects integer"),
		None => 1,
	};
	let pages_on_disk: u64 = match os::getenv("PAGES_ON_DISK") {
		Some(v) => from_str(v).expect("PAGES_ON_DISK expects integer"),
		None => 20,
	};
	let thread_count: uint = match os::getenv("THREADS") {
		Some(v) => from_str(v).expect("THREADS expects integer"),
		None => 3,
	};
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let p = dir.path();
	let p = Path::new(".");

	let mut buffermanager = BufferManager::new(pages_in_ram, p.clone());

	for i in range(0, pages_on_disk) {
		let bf = match buffermanager.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page {}", i),
		};
		{
			let mut lock = bf.write();
			lock.get_mut_data()[0] = 0;
		}
		buffermanager.unfix_page(bf, true);
	}
	let bm = Arc::new(RWLock::new(buffermanager));

	// start scan thread
	let (tx, rx) = channel();
	let bm_scan = bm.clone();
	let mut scan = Future::spawn(proc() {
		let mut counters = Vec::from_elem(pages_on_disk as uint, 0_u8);
		loop {
			info!("Running scan thread...");
			match rx.try_recv() {
				Empty => {
					let page_number = randrange(pages_on_disk);
					let mut bm = bm_scan.write();
					let bf = match bm.fix_page(page_number) {
						Some(frame) => frame,
						None => fail!("Couldn't scan/fix page"),
					};
					let current_val = {
						let lock = bf.read();
						lock.get_data()[0]
					};
					bm.unfix_page(bf, false);
					bm.downgrade();
					// check if the value is going up
					assert!(&current_val >= counters.get(page_number as uint));
					// set to the new value
					let v = counters.get_mut(page_number as uint);
					*v = current_val;

				},
				/*
				 * terminate on both disconnect and when any kind of
				 * data arrives
				 */
				Disconnected => break,
				Data(_) => break,
			};
		}
	});

	// start read/write threads
	let mut rw_threads: Vec<Future<int>> = Vec::new();
	for _ in range(0, thread_count) {
		let bm = bm.clone();
		rw_threads.push(Future::spawn(proc() {
			let is_write = random::<bool>();
			info!("Creating new {} task",
				if is_write {"write"} else {"read"});
			let page_number = randrange(pages_on_disk);
			let mut bm = bm.write();
			if is_write {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				{
					let mut lock = bf.write();
					let data = lock.get_mut_data();
					data[0] = data[0] + 1;
					info!("Wrote to page {}", page_number);
					debug!("data: {}", Vec::from_slice(data));
				}
				bm.unfix_page(bf, is_write);
			} else {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				bm.unfix_page(bf, is_write);
			}
			// return whether we wrote (1) or read (0) as future
			if is_write {1} else {0}
		}));
	}

	// Rust does not have join, but we can wait on Futures which does the same
	let total_count = rw_threads.mut_iter().fold(0, |acc, val| acc + val.get());
	info!("Total count in RAM: {}", total_count);

	// terminate the scan thread and wait until it has completed
	tx.send("terminate");
	scan.get();

	// re-open the pages and check whether all numbers got saved
	let mut bm = BufferManager::new(pages_in_ram, p.clone());
	let mut total_count_on_disk = 0;
	for i in range(0, pages_on_disk) {
		let bf = match bm.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page")
		};
		let value = {
			let lock = bf.read();
			let data = lock.get_data();
			data[0]
		};
		bm.unfix_page(bf, false);
		// cast up from u8 to int
		total_count_on_disk += value as int;
	}
	info!("Total count on disk: {}", total_count_on_disk);
	assert_eq!(total_count, total_count_on_disk);
}
<commit_msg>Using pwrite now to create the files<commit_after>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
use collections::HashMap;
use std::io::{File, Open, Read, Write, TempDir};
use std::num::Zero;
use std::comm::{Data, Empty, Disconnected};
use sync::{Arc, RWLock};
use sync::Future;
use rand::task_rng;
use rand::distributions::{IndependentSample, Range};
use rand::distributions::range::SampleRange;
use native::io::file;
use native::io::file::FileDesc;
use std::rt::rtio::RtioFileStream;

static PAGE_SIZE: uint = 4 * 1024;
/* how much of the page_id should be reserved for pages */
static PAGE_BITS: uint = 4;

struct BufferManager {
	size: uint,
	entries: HashMap<u64, BufferEntry>,
	path: Path,
}

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

#[deriving(Eq)]
enum Status {
	Free,
	Fixed(uint),
}

struct BufferFrame {
	page_id: u64,
	data: Vec<u8>,
	fixed: Status,
}

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

impl BufferManager {
	pub fn new(size: uint, path: Path) -> BufferManager {
		let h = HashMap::with_capacity(size);
		BufferManager {size: size, entries: h, path: path}
	}

	fn open_or_create(&self, page_id: u64) -> FileDesc {
		let file_path = self.path.join(page_id.to_str());
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => return f,
			Err(_) => self.create(&file_path),
		};
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => f,
			Err(e) => fail!("Failed reopening written file: {}", e),
		}
	}

	fn create(&self, page_id: u64) {
		let path = self.path.join(page_id.to_str());
		match file::open(&path.to_c_str(), Open, Write) {
			Ok(mut f) => {
				match f.pwrite([0_u8, ..PAGE_SIZE], 0) {
					Ok(_) => (),
					//Err(e) => fail!("Failed pwriting to file {}: {}", &path.to_c_str().as_str(), e),
					// in this case, err means everything is fine, since there is a bug in Rust' libnative
					Err(e) => (),
				};
			},
			Err(e) => fail!("Failed opening file for write: {}", e),
		};
	}

	/*
	 * returns true if page could be loaded
	 */
	fn load_page(&mut self, page_id: u64) -> bool {
		if self.entries.len() == self.size {
			if !self.evict_page() {
				return false;
			}
		}

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

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

	/*
	 * return false if no page could be evicted
	 */
	fn evict_page(&mut self) -> bool {
		let random_key = {
			let mut free_keys = self.entries.iter().filter_map(|e| {
				// iterate over entries, check if they are free
				// and return the keys of the free entries
				let (k,v) = e;
				let frame = v.frame.read();
				if frame.fixed == Free {
					Some(k)
				} else {
					None
				}
			});
			// pick a random key
			sample(&mut free_keys).map(|v| v.clone())
		};

		match random_key {
			None => false,
			Some(key) => self.entries.remove(&key),
		}
	}

	pub fn fix_page(&mut self, page_id: u64) -> Option<Arc<RWLock<BufferFrame>>> {
		if !self.entries.contains_key(&page_id) {
			if !self.load_page(page_id) {
				return None;
			}
		}
		let entry = self.entries.get(&page_id);
		{
			let mut f = entry.frame.write();
			f.fixed = match f.fixed {
				Free => Fixed(1),
				Fixed(n) => Fixed(n+1),
			};
		}
		// Arcs can be cloned and they will all point to the same RWLock
		Some(entry.frame.clone())
	}

	pub fn unfix_page(&mut self, frame: Arc<RWLock<BufferFrame>>, is_dirty: bool) {
		{
			let mut frame = frame.write();
			frame.fixed = match frame.fixed {
				Fixed(1) => Free,
				Fixed(n) => Fixed(n-1),
				Free => fail!("Unfixing unfixed page"),
			};
		}

		if !is_dirty {
			return;
		}
		let frame = frame.read();
		if frame.fixed == Free {
			info!("writing back page \\#{}", frame.page_id);
			self.write_page(frame.page_id, frame.get_data());
		}
	}

	fn write_page(&mut self, page_id: u64, data: &[u8]) {
		let file_path = self.path.join(page_id.to_str());
		let mut handle = match File::open_mode(&file_path, Open, Write) {
			Ok(handle) => handle,
			Err(e) => fail!("Opening file for writing failed: {}", e),
		};

		match handle.write(data) {
			Ok(_) => (),
			Err(e) => fail!("Writing to file failed: {}", e),
		};
	}
}

/*
 * 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()
	}
}

fn sample<'a, T, I:Iterator<T>>(from: &'a mut I) -> Option<T> {
	let from: ~[T] = from.collect();
	let l = from.len();
	if l == 0 {
		return None;
	}
	let index = randrange(l);
	Some(from[index])
}

fn randrange<X: SampleRange + Ord + Zero>(high: X) -> X {
	let between: Range<X> = Range::new(Zero::zero(), high);
	let mut rng = rand::task_rng();
	between.ind_sample(&mut rng)
}

fn split_segment(num: u64) -> (u64, u64) {
	let high = num >> (64 - PAGE_BITS);
	let low = num & ((1 << PAGE_BITS) - 1);
	(high, low)
}

#[test]
fn test_create() {
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	let mut bm = BufferManager::new(16, dir.path().clone());
	let pageref = match bm.fix_page(42) {
		Some(p) => p,
		None => fail!("Getting page failed"),
	};
	{
		let mut page = pageref.write();
		let data = page.get_mut_data();
		data[0] = 42;
	}
	bm.unfix_page(pageref, true);
}

#[test]
fn test_threads() {
	use rand::random;
	use std::task::spawn;
	use std::os;

	let pages_in_ram: uint = match os::getenv("PAGES_IN_RAM") {
		Some(v) => from_str(v).expect("PAGES_IN_RAM expects integer"),
		None => 1,
	};
	let pages_on_disk: u64 = match os::getenv("PAGES_ON_DISK") {
		Some(v) => from_str(v).expect("PAGES_ON_DISK expects integer"),
		None => 20,
	};
	let thread_count: uint = match os::getenv("THREADS") {
		Some(v) => from_str(v).expect("THREADS expects integer"),
		None => 3,
	};
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let p = dir.path();
	let p = Path::new(".");

	let mut buffermanager = BufferManager::new(pages_in_ram, p.clone());

	for i in range(0, pages_on_disk) {
		let bf = match buffermanager.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page {}", i),
		};
		{
			let mut lock = bf.write();
			lock.get_mut_data()[0] = 0;
		}
		buffermanager.unfix_page(bf, true);
	}
	let bm = Arc::new(RWLock::new(buffermanager));

	// start scan thread
	let (tx, rx) = channel();
	let bm_scan = bm.clone();
	let mut scan = Future::spawn(proc() {
		let mut counters = Vec::from_elem(pages_on_disk as uint, 0_u8);
		loop {
			info!("Running scan thread...");
			match rx.try_recv() {
				Empty => {
					let page_number = randrange(pages_on_disk);
					let mut bm = bm_scan.write();
					let bf = match bm.fix_page(page_number) {
						Some(frame) => frame,
						None => fail!("Couldn't scan/fix page"),
					};
					let current_val = {
						let lock = bf.read();
						lock.get_data()[0]
					};
					bm.unfix_page(bf, false);
					bm.downgrade();
					// check if the value is going up
					assert!(&current_val >= counters.get(page_number as uint));
					// set to the new value
					let v = counters.get_mut(page_number as uint);
					*v = current_val;

				},
				/*
				 * terminate on both disconnect and when any kind of
				 * data arrives
				 */
				Disconnected => break,
				Data(_) => break,
			};
		}
	});

	// start read/write threads
	let mut rw_threads: Vec<Future<int>> = Vec::new();
	for _ in range(0, thread_count) {
		let bm = bm.clone();
		rw_threads.push(Future::spawn(proc() {
			let is_write = random::<bool>();
			info!("Creating new {} task",
				if is_write {"write"} else {"read"});
			let page_number = randrange(pages_on_disk);
			let mut bm = bm.write();
			if is_write {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				{
					let mut lock = bf.write();
					let data = lock.get_mut_data();
					data[0] = data[0] + 1;
					info!("Wrote to page {}", page_number);
					debug!("data: {}", Vec::from_slice(data));
				}
				bm.unfix_page(bf, is_write);
			} else {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				bm.unfix_page(bf, is_write);
			}
			// return whether we wrote (1) or read (0) as future
			if is_write {1} else {0}
		}));
	}

	// Rust does not have join, but we can wait on Futures which does the same
	let total_count = rw_threads.mut_iter().fold(0, |acc, val| acc + val.get());
	info!("Total count in RAM: {}", total_count);

	// terminate the scan thread and wait until it has completed
	tx.send("terminate");
	scan.get();

	// re-open the pages and check whether all numbers got saved
	let mut bm = BufferManager::new(pages_in_ram, p.clone());
	let mut total_count_on_disk = 0;
	for i in range(0, pages_on_disk) {
		let bf = match bm.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page")
		};
		let value = {
			let lock = bf.read();
			let data = lock.get_data();
			data[0]
		};
		bm.unfix_page(bf, false);
		// cast up from u8 to int
		total_count_on_disk += value as int;
	}
	info!("Total count on disk: {}", total_count_on_disk);
	assert_eq!(total_count, total_count_on_disk);
}
<|endoftext|>


<commit_before>use super::code_writer::CodeWriter;
use super::rust_types_values::*;
use protobuf::descriptor::*;
use scope::RootScope;
use rust_name::RustIdentWithPath;
use rust_name::RustRelativePath;
use field::rust_field_name_for_protobuf_field_name;
use ProtobufAbsolutePath;
use file_and_mod::FileAndMod;

struct ExtGen<'a> {
    file: &'a FileDescriptorProto,
    root_scope: &'a RootScope<'a>,
    field: &'a FieldDescriptorProto,
}

impl<'a> ExtGen<'a> {
    fn extendee_rust_name(&self) -> RustIdentWithPath {
        type_name_to_rust_relative(
            &ProtobufAbsolutePath::from(self.field.get_extendee()),
            &FileAndMod {
                file: self.file.get_name().to_owned(),
                relative_mod: RustRelativePath::from("exts"),
            },
            self.root_scope)
    }

    fn repeated(&self) -> bool {
        match self.field.get_label() {
            field_descriptor_proto::Label::LABEL_REPEATED => true,
            field_descriptor_proto::Label::LABEL_OPTIONAL => false,
            field_descriptor_proto::Label::LABEL_REQUIRED => {
                panic!("required ext field: {}", self.field.get_name())
            }
        }
    }

    fn return_type_gen(&self) -> ProtobufTypeGen {
        if self.field.has_type_name() {
            let rust_name_relative = type_name_to_rust_relative(
                &ProtobufAbsolutePath::from(self.field.get_type_name()),
                &FileAndMod {
                    file: self.file.get_name().to_owned(),
                    relative_mod: RustRelativePath::from("exts"),
                },
                self.root_scope,
            );
            match self.field.get_field_type() {
                field_descriptor_proto::Type::TYPE_MESSAGE => {
                    ProtobufTypeGen::Message(rust_name_relative)
                }
                field_descriptor_proto::Type::TYPE_ENUM => ProtobufTypeGen::EnumOrUnknown(rust_name_relative),
                t => panic!("unknown type: {:?}", t),
            }
        } else {
            ProtobufTypeGen::Primitive(self.field.get_field_type(), PrimitiveTypeVariant::Default)
        }
    }

    fn write(&self, w: &mut CodeWriter) {
        let suffix = if self.repeated() {
            "ExtFieldRepeated"
        } else {
            "ExtFieldOptional"
        };
        let field_type = format!("::protobuf::ext::{}", suffix);
        w.pub_const(
            rust_field_name_for_protobuf_field_name(self.field.get_name()).get(),
            &format!(
                "{}<{}, {}>",
                field_type,
                self.extendee_rust_name(),
                self.return_type_gen().rust_type()
            ),
            &format!(
                "{} {{ field_number: {}, phantom: ::std::marker::PhantomData }}",
                field_type,
                self.field.get_number()
            ),
        );
    }
}

pub(crate) fn write_extensions(file: &FileDescriptorProto, root_scope: &RootScope, w: &mut CodeWriter) {
    if file.extension.is_empty() {
        return;
    }

    w.write_line("");
    w.pub_mod("exts", |w| {
        w.write_line("use protobuf::Message as Message_imported_for_functions;");

        for field in &file.extension {
            if field.get_field_type() == field_descriptor_proto::Type::TYPE_GROUP {
                continue;
            }

            w.write_line("");
            ExtGen {
                file: file,
                root_scope: root_scope,
                field: field,
            }.write(w);
        }
    });
}
<commit_msg>Unnecessary import in generated exts module<commit_after>use super::code_writer::CodeWriter;
use super::rust_types_values::*;
use protobuf::descriptor::*;
use scope::RootScope;
use rust_name::RustIdentWithPath;
use rust_name::RustRelativePath;
use field::rust_field_name_for_protobuf_field_name;
use ProtobufAbsolutePath;
use file_and_mod::FileAndMod;

struct ExtGen<'a> {
    file: &'a FileDescriptorProto,
    root_scope: &'a RootScope<'a>,
    field: &'a FieldDescriptorProto,
}

impl<'a> ExtGen<'a> {
    fn extendee_rust_name(&self) -> RustIdentWithPath {
        type_name_to_rust_relative(
            &ProtobufAbsolutePath::from(self.field.get_extendee()),
            &FileAndMod {
                file: self.file.get_name().to_owned(),
                relative_mod: RustRelativePath::from("exts"),
            },
            self.root_scope)
    }

    fn repeated(&self) -> bool {
        match self.field.get_label() {
            field_descriptor_proto::Label::LABEL_REPEATED => true,
            field_descriptor_proto::Label::LABEL_OPTIONAL => false,
            field_descriptor_proto::Label::LABEL_REQUIRED => {
                panic!("required ext field: {}", self.field.get_name())
            }
        }
    }

    fn return_type_gen(&self) -> ProtobufTypeGen {
        if self.field.has_type_name() {
            let rust_name_relative = type_name_to_rust_relative(
                &ProtobufAbsolutePath::from(self.field.get_type_name()),
                &FileAndMod {
                    file: self.file.get_name().to_owned(),
                    relative_mod: RustRelativePath::from("exts"),
                },
                self.root_scope,
            );
            match self.field.get_field_type() {
                field_descriptor_proto::Type::TYPE_MESSAGE => {
                    ProtobufTypeGen::Message(rust_name_relative)
                }
                field_descriptor_proto::Type::TYPE_ENUM => ProtobufTypeGen::EnumOrUnknown(rust_name_relative),
                t => panic!("unknown type: {:?}", t),
            }
        } else {
            ProtobufTypeGen::Primitive(self.field.get_field_type(), PrimitiveTypeVariant::Default)
        }
    }

    fn write(&self, w: &mut CodeWriter) {
        let suffix = if self.repeated() {
            "ExtFieldRepeated"
        } else {
            "ExtFieldOptional"
        };
        let field_type = format!("::protobuf::ext::{}", suffix);
        w.pub_const(
            rust_field_name_for_protobuf_field_name(self.field.get_name()).get(),
            &format!(
                "{}<{}, {}>",
                field_type,
                self.extendee_rust_name(),
                self.return_type_gen().rust_type()
            ),
            &format!(
                "{} {{ field_number: {}, phantom: ::std::marker::PhantomData }}",
                field_type,
                self.field.get_number()
            ),
        );
    }
}

pub(crate) fn write_extensions(file: &FileDescriptorProto, root_scope: &RootScope, w: &mut CodeWriter) {
    if file.extension.is_empty() {
        return;
    }

    w.write_line("");
    w.pub_mod("exts", |w| {
        for field in &file.extension {
            if field.get_field_type() == field_descriptor_proto::Type::TYPE_GROUP {
                continue;
            }

            w.write_line("");
            ExtGen {
                file: file,
                root_scope: root_scope,
                field: field,
            }.write(w);
        }
    });
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::future::Future;

use async_task::Task;

use base::{AsRawDescriptors, RawDescriptor};

use super::{
    poll_source::Error as PollError, uring_executor::use_uring, FdExecutor, PollSource,
    URingExecutor, UringSource,
};

use crate::{AsyncResult, IntoAsync, IoSourceExt};

pub(crate) fn async_uring_from<'a, F: IntoAsync + Send + 'a>(
    f: F,
    ex: &URingExecutor,
) -> AsyncResult<Box<dyn IoSourceExt<F> + 'a + Send>> {
    Ok(UringSource::new(f, ex).map(|u| Box::new(u) as Box<dyn IoSourceExt<F> + Send>)?)
}

/// Creates a concrete `IoSourceExt` using the fd_executor.
pub(crate) fn async_poll_from<'a, F: IntoAsync + Send + 'a>(
    f: F,
    ex: &FdExecutor,
) -> AsyncResult<Box<dyn IoSourceExt<F> + Send + 'a>> {
    Ok(PollSource::new(f, ex).map(|u| Box::new(u) as Box<dyn IoSourceExt<F> + Send>)?)
}

/// Same as [`async_uring_from`], but without the `Send` requirement and only usable on thread-local
/// executors.
pub(crate) fn async_uring_from_local<'a, F: IntoAsync + 'a>(
    f: F,
    ex: &URingExecutor,
) -> AsyncResult<Box<dyn IoSourceExt<F> + 'a>> {
    Ok(UringSource::new(f, ex).map(|u| Box::new(u) as Box<dyn IoSourceExt<F>>)?)
}

/// Same as [`async_poll_from`], but without the `Send` requirement and only usable on thread-local
/// executors.
pub(crate) fn async_poll_from_local<'a, F: IntoAsync + 'a>(
    f: F,
    ex: &FdExecutor,
) -> AsyncResult<Box<dyn IoSourceExt<F> + 'a>> {
    Ok(PollSource::new(f, ex).map(|u| Box::new(u) as Box<dyn IoSourceExt<F>>)?)
}

/// An executor for scheduling tasks that poll futures to completion.
///
/// All asynchronous operations must run within an executor, which is capable of spawning futures as
/// tasks. This executor also provides a mechanism for performing asynchronous I/O operations.
///
/// The returned type is a cheap, clonable handle to the underlying executor. Cloning it will only
/// create a new reference, not a new executor.
///
/// Note that language limitations (trait objects can have <=1 non auto trait) require this to be
/// represented on the POSIX side as an enum, rather than a trait. This leads to some code &
/// interface duplication, but as far as we understand that is unavoidable.
///
/// See <https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2571401/2..6/cros_async/src/executor.rs#b75>
/// for further details.
///
/// # Examples
///
/// Concurrently wait for multiple files to become readable/writable and then read/write the data.
///
/// ```
/// use std::cmp::min;
/// use std::error::Error;
/// use std::fs::{File, OpenOptions};
///
/// use cros_async::{AsyncResult, Executor, IoSourceExt, complete3};
/// const CHUNK_SIZE: usize = 32;
///
/// // Write all bytes from `data` to `f`.
/// async fn write_file(f: &dyn IoSourceExt<File>, mut data: Vec<u8>) -> AsyncResult<()> {
///     while data.len() > 0 {
///         let (count, mut buf) = f.write_from_vec(Some(0), data).await?;
///
///         data = buf.split_off(count);
///     }
///
///     Ok(())
/// }
///
/// // Transfer `len` bytes of data from `from` to `to`.
/// async fn transfer_data(
///     from: Box<dyn IoSourceExt<File>>,
///     to: Box<dyn IoSourceExt<File>>,
///     len: usize,
/// ) -> AsyncResult<usize> {
///     let mut rem = len;
///
///     while rem > 0 {
///         let buf = vec![0u8; min(rem, CHUNK_SIZE)];
///         let (count, mut data) = from.read_to_vec(Some(0), buf).await?;
///
///         if count == 0 {
///             // End of file. Return the number of bytes transferred.
///             return Ok(len - rem);
///         }
///
///         data.truncate(count);
///         write_file(&*to, data).await?;
///
///         rem = rem.saturating_sub(count);
///     }
///
///     Ok(len)
/// }
///
/// #[cfg(unix)]
/// # fn do_it() -> Result<(), Box<dyn Error>> {
///     let ex = Executor::new()?;
///
///     let (rx, tx) = base::unix::pipe(true)?;
///     let zero = File::open("/dev/zero")?;
///     let zero_bytes = CHUNK_SIZE * 7;
///     let zero_to_pipe = transfer_data(
///         ex.async_from(zero)?,
///         ex.async_from(tx.try_clone()?)?,
///         zero_bytes,
///     );
///
///     let rand = File::open("/dev/urandom")?;
///     let rand_bytes = CHUNK_SIZE * 19;
///     let rand_to_pipe = transfer_data(ex.async_from(rand)?, ex.async_from(tx)?, rand_bytes);
///
///     let null = OpenOptions::new().write(true).open("/dev/null")?;
///     let null_bytes = zero_bytes + rand_bytes;
///     let pipe_to_null = transfer_data(ex.async_from(rx)?, ex.async_from(null)?, null_bytes);
///
///     ex.run_until(complete3(
///         async { assert_eq!(pipe_to_null.await.unwrap(), null_bytes) },
///         async { assert_eq!(zero_to_pipe.await.unwrap(), zero_bytes) },
///         async { assert_eq!(rand_to_pipe.await.unwrap(), rand_bytes) },
///     ))?;
///
/// #     Ok(())
/// # }
/// #[cfg(unix)]
/// # do_it().unwrap();
/// ```

#[derive(Clone)]
pub enum Executor {
    Uring(URingExecutor),
    Fd(FdExecutor),
}

impl Executor {
    /// Create a new `Executor`.
    pub fn new() -> AsyncResult<Self> {
        if use_uring() {
            Ok(URingExecutor::new().map(Executor::Uring)?)
        } else {
            Ok(FdExecutor::new()
                .map(Executor::Fd)
                .map_err(PollError::Executor)?)
        }
    }

    /// Create a new `Box<dyn IoSourceExt<F>>` associated with `self`. Callers may then use the
    /// returned `IoSourceExt` to directly start async operations without needing a separate
    /// reference to the executor.
    pub fn async_from<'a, F: IntoAsync + Send + 'a>(
        &self,
        f: F,
    ) -> AsyncResult<Box<dyn IoSourceExt<F> + Send + 'a>> {
        match self {
            Executor::Uring(ex) => async_uring_from(f, ex),
            Executor::Fd(ex) => async_poll_from(f, ex),
        }
    }

    /// Same as [`async_from`], but without the `Send` requirement and only usable on thread-local
    /// executors.
    pub fn async_from_local<'a, F: IntoAsync + 'a>(
        &self,
        f: F,
    ) -> AsyncResult<Box<dyn IoSourceExt<F> + 'a>> {
        match self {
            Executor::Uring(ex) => async_uring_from_local(f, ex),
            Executor::Fd(ex) => async_poll_from_local(f, ex),
        }
    }

    /// Spawn a new future for this executor to run to completion. Callers may use the returned
    /// `Task` to await on the result of `f`. Dropping the returned `Task` will cancel `f`,
    /// preventing it from being polled again. To drop a `Task` without canceling the future
    /// associated with it use `Task::detach`. To cancel a task gracefully and wait until it is
    /// fully destroyed, use `Task::cancel`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use cros_async::AsyncResult;
    /// # fn example_spawn() -> AsyncResult<()> {
    /// #      use std::thread;
    ///
    /// #      use cros_async::Executor;
    ///       use futures::executor::block_on;
    ///
    /// #      let ex = Executor::new()?;
    ///
    /// #      // Spawn a thread that runs the executor.
    /// #      let ex2 = ex.clone();
    /// #      thread::spawn(move || ex2.run());
    ///
    ///       let task = ex.spawn(async { 7 + 13 });
    ///
    ///       let result = block_on(task);
    ///       assert_eq!(result, 20);
    /// #     Ok(())
    /// # }
    ///
    /// # example_spawn().unwrap();
    /// ```
    pub fn spawn<F>(&self, f: F) -> Task<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        match self {
            Executor::Uring(ex) => ex.spawn(f),
            Executor::Fd(ex) => ex.spawn(f),
        }
    }

    /// Spawn a thread-local task for this executor to drive to completion. Like `spawn` but without
    /// requiring `Send` on `F` or `F::Output`. This method should only be called from the same
    /// thread where `run()` or `run_until()` is called.
    ///
    /// # Panics
    ///
    /// `Executor::run` and `Executor::run_util` will panic if they try to poll a future that was
    /// added by calling `spawn_local` from a different thread.
    ///
    /// # Examples
    ///
    /// ```
    /// # use cros_async::AsyncResult;
    /// # fn example_spawn_local() -> AsyncResult<()> {
    /// #      use cros_async::Executor;
    ///
    /// #      let ex = Executor::new()?;
    ///
    ///       let task = ex.spawn_local(async { 7 + 13 });
    ///
    ///       let result = ex.run_until(task)?;
    ///       assert_eq!(result, 20);
    /// #     Ok(())
    /// # }
    ///
    /// # example_spawn_local().unwrap();
    /// ```
    pub fn spawn_local<F>(&self, f: F) -> Task<F::Output>
    where
        F: Future + 'static,
        F::Output: 'static,
    {
        match self {
            Executor::Uring(ex) => ex.spawn_local(f),
            Executor::Fd(ex) => ex.spawn_local(f),
        }
    }

    /// Run the provided closure on a dedicated thread where blocking is allowed.
    ///
    /// Callers may `await` on the returned `Task` to wait for the result of `f`. Dropping or
    /// canceling the returned `Task` may not cancel the operation if it was already started on a
    /// worker thread.
    ///
    /// # Panics
    ///
    /// `await`ing the `Task` after the `Executor` is dropped will panic if the work was not already
    /// completed.
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// # use cros_async::Executor;
    ///
    /// # async fn do_it(ex: &Executor) {
    ///     let res = ex.spawn_blocking(move || {
    ///         // Do some CPU-intensive or blocking work here.
    ///
    ///         42
    ///     }).await;
    ///
    ///     assert_eq!(res, 42);
    /// # }
    ///
    /// # let ex = Executor::new().unwrap();
    /// # ex.run_until(do_it(&ex)).unwrap();
    /// ```
    pub fn spawn_blocking<F, R>(&self, f: F) -> Task<R>
    where
        F: FnOnce() -> R + Send + 'static,
        R: Send + 'static,
    {
        match self {
            Executor::Uring(ex) => ex.spawn_blocking(f),
            Executor::Fd(ex) => ex.spawn_blocking(f),
        }
    }

    /// Run the executor indefinitely, driving all spawned futures to completion. This method will
    /// block the current thread and only return in the case of an error.
    ///
    /// # Panics
    ///
    /// Once this method has been called on a thread, it may only be called on that thread from that
    /// point on. Attempting to call it from another thread will panic.
    ///
    /// # Examples
    ///
    /// ```
    /// # use cros_async::AsyncResult;
    /// # fn example_run() -> AsyncResult<()> {
    ///       use std::thread;
    ///
    ///       use cros_async::Executor;
    ///       use futures::executor::block_on;
    ///
    ///       let ex = Executor::new()?;
    ///
    ///       // Spawn a thread that runs the executor.
    ///       let ex2 = ex.clone();
    ///       thread::spawn(move || ex2.run());
    ///
    ///       let task = ex.spawn(async { 7 + 13 });
    ///
    ///       let result = block_on(task);
    ///       assert_eq!(result, 20);
    /// #     Ok(())
    /// # }
    ///
    /// # example_run().unwrap();
    /// ```
    pub fn run(&self) -> AsyncResult<()> {
        match self {
            Executor::Uring(ex) => ex.run()?,
            Executor::Fd(ex) => ex.run().map_err(PollError::Executor)?,
        }

        Ok(())
    }

    /// Drive all futures spawned in this executor until `f` completes. This method will block the
    /// current thread only until `f` is complete and there may still be unfinished futures in the
    /// executor.
    ///
    /// # Panics
    ///
    /// Once this method has been called on a thread, from then onwards it may only be called on
    /// that thread. Attempting to call it from another thread will panic.
    ///
    /// # Examples
    ///
    /// ```
    /// # use cros_async::AsyncResult;
    /// # fn example_run_until() -> AsyncResult<()> {
    ///       use cros_async::Executor;
    ///
    ///       let ex = Executor::new()?;
    ///
    ///       let task = ex.spawn_local(async { 7 + 13 });
    ///
    ///       let result = ex.run_until(task)?;
    ///       assert_eq!(result, 20);
    /// #     Ok(())
    /// # }
    ///
    /// # example_run_until().unwrap();
    /// ```
    pub fn run_until<F: Future>(&self, f: F) -> AsyncResult<F::Output> {
        match self {
            Executor::Uring(ex) => Ok(ex.run_until(f)?),
            Executor::Fd(ex) => Ok(ex.run_until(f).map_err(PollError::Executor)?),
        }
    }
}

impl AsRawDescriptors for Executor {
    fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
        match self {
            Executor::Uring(ex) => ex.as_raw_descriptors(),
            Executor::Fd(ex) => ex.as_raw_descriptors(),
        }
    }
}
<commit_msg>cros_async: fix unknown function warning in docs<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::future::Future;

use async_task::Task;

use base::{AsRawDescriptors, RawDescriptor};

use super::{
    poll_source::Error as PollError, uring_executor::use_uring, FdExecutor, PollSource,
    URingExecutor, UringSource,
};

use crate::{AsyncResult, IntoAsync, IoSourceExt};

pub(crate) fn async_uring_from<'a, F: IntoAsync + Send + 'a>(
    f: F,
    ex: &URingExecutor,
) -> AsyncResult<Box<dyn IoSourceExt<F> + 'a + Send>> {
    Ok(UringSource::new(f, ex).map(|u| Box::new(u) as Box<dyn IoSourceExt<F> + Send>)?)
}

/// Creates a concrete `IoSourceExt` using the fd_executor.
pub(crate) fn async_poll_from<'a, F: IntoAsync + Send + 'a>(
    f: F,
    ex: &FdExecutor,
) -> AsyncResult<Box<dyn IoSourceExt<F> + Send + 'a>> {
    Ok(PollSource::new(f, ex).map(|u| Box::new(u) as Box<dyn IoSourceExt<F> + Send>)?)
}

/// Same as [`async_uring_from`], but without the `Send` requirement and only usable on thread-local
/// executors.
pub(crate) fn async_uring_from_local<'a, F: IntoAsync + 'a>(
    f: F,
    ex: &URingExecutor,
) -> AsyncResult<Box<dyn IoSourceExt<F> + 'a>> {
    Ok(UringSource::new(f, ex).map(|u| Box::new(u) as Box<dyn IoSourceExt<F>>)?)
}

/// Same as [`async_poll_from`], but without the `Send` requirement and only usable on thread-local
/// executors.
pub(crate) fn async_poll_from_local<'a, F: IntoAsync + 'a>(
    f: F,
    ex: &FdExecutor,
) -> AsyncResult<Box<dyn IoSourceExt<F> + 'a>> {
    Ok(PollSource::new(f, ex).map(|u| Box::new(u) as Box<dyn IoSourceExt<F>>)?)
}

/// An executor for scheduling tasks that poll futures to completion.
///
/// All asynchronous operations must run within an executor, which is capable of spawning futures as
/// tasks. This executor also provides a mechanism for performing asynchronous I/O operations.
///
/// The returned type is a cheap, clonable handle to the underlying executor. Cloning it will only
/// create a new reference, not a new executor.
///
/// Note that language limitations (trait objects can have <=1 non auto trait) require this to be
/// represented on the POSIX side as an enum, rather than a trait. This leads to some code &
/// interface duplication, but as far as we understand that is unavoidable.
///
/// See <https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2571401/2..6/cros_async/src/executor.rs#b75>
/// for further details.
///
/// # Examples
///
/// Concurrently wait for multiple files to become readable/writable and then read/write the data.
///
/// ```
/// use std::cmp::min;
/// use std::error::Error;
/// use std::fs::{File, OpenOptions};
///
/// use cros_async::{AsyncResult, Executor, IoSourceExt, complete3};
/// const CHUNK_SIZE: usize = 32;
///
/// // Write all bytes from `data` to `f`.
/// async fn write_file(f: &dyn IoSourceExt<File>, mut data: Vec<u8>) -> AsyncResult<()> {
///     while data.len() > 0 {
///         let (count, mut buf) = f.write_from_vec(Some(0), data).await?;
///
///         data = buf.split_off(count);
///     }
///
///     Ok(())
/// }
///
/// // Transfer `len` bytes of data from `from` to `to`.
/// async fn transfer_data(
///     from: Box<dyn IoSourceExt<File>>,
///     to: Box<dyn IoSourceExt<File>>,
///     len: usize,
/// ) -> AsyncResult<usize> {
///     let mut rem = len;
///
///     while rem > 0 {
///         let buf = vec![0u8; min(rem, CHUNK_SIZE)];
///         let (count, mut data) = from.read_to_vec(Some(0), buf).await?;
///
///         if count == 0 {
///             // End of file. Return the number of bytes transferred.
///             return Ok(len - rem);
///         }
///
///         data.truncate(count);
///         write_file(&*to, data).await?;
///
///         rem = rem.saturating_sub(count);
///     }
///
///     Ok(len)
/// }
///
/// #[cfg(unix)]
/// # fn do_it() -> Result<(), Box<dyn Error>> {
///     let ex = Executor::new()?;
///
///     let (rx, tx) = base::unix::pipe(true)?;
///     let zero = File::open("/dev/zero")?;
///     let zero_bytes = CHUNK_SIZE * 7;
///     let zero_to_pipe = transfer_data(
///         ex.async_from(zero)?,
///         ex.async_from(tx.try_clone()?)?,
///         zero_bytes,
///     );
///
///     let rand = File::open("/dev/urandom")?;
///     let rand_bytes = CHUNK_SIZE * 19;
///     let rand_to_pipe = transfer_data(ex.async_from(rand)?, ex.async_from(tx)?, rand_bytes);
///
///     let null = OpenOptions::new().write(true).open("/dev/null")?;
///     let null_bytes = zero_bytes + rand_bytes;
///     let pipe_to_null = transfer_data(ex.async_from(rx)?, ex.async_from(null)?, null_bytes);
///
///     ex.run_until(complete3(
///         async { assert_eq!(pipe_to_null.await.unwrap(), null_bytes) },
///         async { assert_eq!(zero_to_pipe.await.unwrap(), zero_bytes) },
///         async { assert_eq!(rand_to_pipe.await.unwrap(), rand_bytes) },
///     ))?;
///
/// #     Ok(())
/// # }
/// #[cfg(unix)]
/// # do_it().unwrap();
/// ```

#[derive(Clone)]
pub enum Executor {
    Uring(URingExecutor),
    Fd(FdExecutor),
}

impl Executor {
    /// Create a new `Executor`.
    pub fn new() -> AsyncResult<Self> {
        if use_uring() {
            Ok(URingExecutor::new().map(Executor::Uring)?)
        } else {
            Ok(FdExecutor::new()
                .map(Executor::Fd)
                .map_err(PollError::Executor)?)
        }
    }

    /// Create a new `Box<dyn IoSourceExt<F>>` associated with `self`. Callers may then use the
    /// returned `IoSourceExt` to directly start async operations without needing a separate
    /// reference to the executor.
    pub fn async_from<'a, F: IntoAsync + Send + 'a>(
        &self,
        f: F,
    ) -> AsyncResult<Box<dyn IoSourceExt<F> + Send + 'a>> {
        match self {
            Executor::Uring(ex) => async_uring_from(f, ex),
            Executor::Fd(ex) => async_poll_from(f, ex),
        }
    }

    /// Same as [`Executor::async_from()`], but without the `Send` requirement and only usable on thread-local
    /// executors.
    pub fn async_from_local<'a, F: IntoAsync + 'a>(
        &self,
        f: F,
    ) -> AsyncResult<Box<dyn IoSourceExt<F> + 'a>> {
        match self {
            Executor::Uring(ex) => async_uring_from_local(f, ex),
            Executor::Fd(ex) => async_poll_from_local(f, ex),
        }
    }

    /// Spawn a new future for this executor to run to completion. Callers may use the returned
    /// `Task` to await on the result of `f`. Dropping the returned `Task` will cancel `f`,
    /// preventing it from being polled again. To drop a `Task` without canceling the future
    /// associated with it use `Task::detach`. To cancel a task gracefully and wait until it is
    /// fully destroyed, use `Task::cancel`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use cros_async::AsyncResult;
    /// # fn example_spawn() -> AsyncResult<()> {
    /// #      use std::thread;
    ///
    /// #      use cros_async::Executor;
    ///       use futures::executor::block_on;
    ///
    /// #      let ex = Executor::new()?;
    ///
    /// #      // Spawn a thread that runs the executor.
    /// #      let ex2 = ex.clone();
    /// #      thread::spawn(move || ex2.run());
    ///
    ///       let task = ex.spawn(async { 7 + 13 });
    ///
    ///       let result = block_on(task);
    ///       assert_eq!(result, 20);
    /// #     Ok(())
    /// # }
    ///
    /// # example_spawn().unwrap();
    /// ```
    pub fn spawn<F>(&self, f: F) -> Task<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        match self {
            Executor::Uring(ex) => ex.spawn(f),
            Executor::Fd(ex) => ex.spawn(f),
        }
    }

    /// Spawn a thread-local task for this executor to drive to completion. Like `spawn` but without
    /// requiring `Send` on `F` or `F::Output`. This method should only be called from the same
    /// thread where `run()` or `run_until()` is called.
    ///
    /// # Panics
    ///
    /// `Executor::run` and `Executor::run_util` will panic if they try to poll a future that was
    /// added by calling `spawn_local` from a different thread.
    ///
    /// # Examples
    ///
    /// ```
    /// # use cros_async::AsyncResult;
    /// # fn example_spawn_local() -> AsyncResult<()> {
    /// #      use cros_async::Executor;
    ///
    /// #      let ex = Executor::new()?;
    ///
    ///       let task = ex.spawn_local(async { 7 + 13 });
    ///
    ///       let result = ex.run_until(task)?;
    ///       assert_eq!(result, 20);
    /// #     Ok(())
    /// # }
    ///
    /// # example_spawn_local().unwrap();
    /// ```
    pub fn spawn_local<F>(&self, f: F) -> Task<F::Output>
    where
        F: Future + 'static,
        F::Output: 'static,
    {
        match self {
            Executor::Uring(ex) => ex.spawn_local(f),
            Executor::Fd(ex) => ex.spawn_local(f),
        }
    }

    /// Run the provided closure on a dedicated thread where blocking is allowed.
    ///
    /// Callers may `await` on the returned `Task` to wait for the result of `f`. Dropping or
    /// canceling the returned `Task` may not cancel the operation if it was already started on a
    /// worker thread.
    ///
    /// # Panics
    ///
    /// `await`ing the `Task` after the `Executor` is dropped will panic if the work was not already
    /// completed.
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// # use cros_async::Executor;
    ///
    /// # async fn do_it(ex: &Executor) {
    ///     let res = ex.spawn_blocking(move || {
    ///         // Do some CPU-intensive or blocking work here.
    ///
    ///         42
    ///     }).await;
    ///
    ///     assert_eq!(res, 42);
    /// # }
    ///
    /// # let ex = Executor::new().unwrap();
    /// # ex.run_until(do_it(&ex)).unwrap();
    /// ```
    pub fn spawn_blocking<F, R>(&self, f: F) -> Task<R>
    where
        F: FnOnce() -> R + Send + 'static,
        R: Send + 'static,
    {
        match self {
            Executor::Uring(ex) => ex.spawn_blocking(f),
            Executor::Fd(ex) => ex.spawn_blocking(f),
        }
    }

    /// Run the executor indefinitely, driving all spawned futures to completion. This method will
    /// block the current thread and only return in the case of an error.
    ///
    /// # Panics
    ///
    /// Once this method has been called on a thread, it may only be called on that thread from that
    /// point on. Attempting to call it from another thread will panic.
    ///
    /// # Examples
    ///
    /// ```
    /// # use cros_async::AsyncResult;
    /// # fn example_run() -> AsyncResult<()> {
    ///       use std::thread;
    ///
    ///       use cros_async::Executor;
    ///       use futures::executor::block_on;
    ///
    ///       let ex = Executor::new()?;
    ///
    ///       // Spawn a thread that runs the executor.
    ///       let ex2 = ex.clone();
    ///       thread::spawn(move || ex2.run());
    ///
    ///       let task = ex.spawn(async { 7 + 13 });
    ///
    ///       let result = block_on(task);
    ///       assert_eq!(result, 20);
    /// #     Ok(())
    /// # }
    ///
    /// # example_run().unwrap();
    /// ```
    pub fn run(&self) -> AsyncResult<()> {
        match self {
            Executor::Uring(ex) => ex.run()?,
            Executor::Fd(ex) => ex.run().map_err(PollError::Executor)?,
        }

        Ok(())
    }

    /// Drive all futures spawned in this executor until `f` completes. This method will block the
    /// current thread only until `f` is complete and there may still be unfinished futures in the
    /// executor.
    ///
    /// # Panics
    ///
    /// Once this method has been called on a thread, from then onwards it may only be called on
    /// that thread. Attempting to call it from another thread will panic.
    ///
    /// # Examples
    ///
    /// ```
    /// # use cros_async::AsyncResult;
    /// # fn example_run_until() -> AsyncResult<()> {
    ///       use cros_async::Executor;
    ///
    ///       let ex = Executor::new()?;
    ///
    ///       let task = ex.spawn_local(async { 7 + 13 });
    ///
    ///       let result = ex.run_until(task)?;
    ///       assert_eq!(result, 20);
    /// #     Ok(())
    /// # }
    ///
    /// # example_run_until().unwrap();
    /// ```
    pub fn run_until<F: Future>(&self, f: F) -> AsyncResult<F::Output> {
        match self {
            Executor::Uring(ex) => Ok(ex.run_until(f)?),
            Executor::Fd(ex) => Ok(ex.run_until(f).map_err(PollError::Executor)?),
        }
    }
}

impl AsRawDescriptors for Executor {
    fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
        match self {
            Executor::Uring(ex) => ex.as_raw_descriptors(),
            Executor::Fd(ex) => ex.as_raw_descriptors(),
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "kernel"]
#![crate_type = "staticlib"]
#![no_std]
#![feature(asm, lang_items)]

extern crate rlibc;

#[path = "arch/x86/"]
pub mod platform {
	pub mod vga;
	pub mod cpu;
	pub mod mmu;
	mod io;
	pub mod keyboard;
}

pub mod kernel {
	pub mod main;
	pub mod interrupts;
	mod stdio;
	mod keyboard;
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
<commit_msg>Remove stack_exhausted<commit_after>#![crate_name = "kernel"]
#![crate_type = "staticlib"]
#![no_std]
#![feature(asm, lang_items)]

extern crate rlibc;

#[path = "arch/x86/"]
pub mod platform {
	pub mod vga;
	pub mod cpu;
	pub mod mmu;
	mod io;
	pub mod keyboard;
}

pub mod kernel {
	pub mod main;
	pub mod interrupts;
	mod stdio;
	mod keyboard;
}

#[lang = "eh_personality"] extern fn eh_personality() {}
<|endoftext|>


<commit_before>use winapi::um::shobjidl::IFileDialog;
use crate::win32::resources_helper as rh;

use crate::win32::base_helper::to_utf16;
use crate::{ControlHandle, NwgError};
use std::{fmt, ptr, mem};

/**
    A enum that dictates how a file dialog should behave
    Members:
    * `Open`: User can select a file that is not a directory
    * `OpenDirectory`: User can select a directory
    * `Save`: User select the name of a file. If it already exists, a confirmation message will be raised
*/
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum FileDialogAction {
    Open,
    OpenDirectory,
    Save,
}

/**
    A file dialog control

    The file dialog builders accepts the following parameters:
        * title: The title of the dialog
        * action: The action to execute. Open, OpenDirectory for Save
        * multiselect: Whether the user can select more than one file. Only supported with the Open action
        * default_folder: Default folder to show in the dialog.
        * filters: If defined, filter the files that the user can select (In a Open dialog) or which extension to add to the saved file (in a Save dialog)

    ```rust
        use native_windows_gui as nwg;
        fn layout(dialog: &mut nwg::FileDialog) {
            nwg::FileDialog::builder()
                .title("Hello")
                .action(nwg::FileDialogAction::Open)
                .multiselect(true)
                .build(dialog);
        }
    ```
*/
pub struct FileDialog {
    handle: *mut IFileDialog,
    action: FileDialogAction
}

impl FileDialog {

    pub fn builder() -> FileDialogBuilder {
        FileDialogBuilder {
            title: None,
            action: FileDialogAction::Save,
            multiselect: false,
            default_folder: None,
            filters: None
        }
    }

    /// Return the action type executed by this dialog
    pub fn action(&self) -> FileDialogAction {
        self.action
    }

    /**
        Display the dialog. Return true if the dialog was accepted or false if it was cancelled
        If the dialog was accepted, `get_selected_item` or `get_selected_items` can be used to find the selected file(s)

        It's important to note that `run` blocks the current thread until the user as chosen a file (similar to `dispatch_thread_events`)

        The parent argument must be a window control otherwise the method will panic.
    */
    pub fn run<C: Into<ControlHandle>>(&self, parent: Option<C>) -> bool {
        use winapi::shared::winerror::S_OK;

        let parent_handle = match parent {
            Some(p) => p.into().hwnd().expect("File dialog parent must be a window control"),
            None => ptr::null_mut()
        };

        unsafe { (&mut *self.handle).Show(parent_handle) == S_OK }
    }

    /**
        Return the item selected in the dialog by the user.

        Failures:
        • if the dialog was not called
        • if there was a system error while reading the selected item
        • if the dialog has the `multiselect` flag
    */
    pub fn get_selected_item(&self) -> Result<String, NwgError> {

        if self.multiselect() {
            return Err(NwgError::file_dialog("FileDialog have the multiselect flag"));
        }

        unsafe {
            rh::filedialog_get_item(&mut *self.handle)
        }
    }

    /**
        Return the selected items in the dialog by the user.
        Failures:
        • if the dialog was not called
        • if there was a system error while reading the selected items
        • if the dialog has `Save` for action
    */
    pub fn get_selected_items(&self) -> Result<Vec<String>, NwgError> {
        if self.action == FileDialogAction::Save {
            return Err(NwgError::file_dialog("Save dialog cannot have more than one item selected"));
        }

        unsafe {
            rh::filedialog_get_items(mem::transmute(&mut *self.handle))
        }
    }

    /// Return `true` if the dialog accepts multiple values or `false` otherwise
    pub fn multiselect(&self) -> bool {
        use winapi::um::shobjidl::FOS_ALLOWMULTISELECT;

        unsafe {
            let flags = rh::file_dialog_options(&mut *self.handle).unwrap_or(0);
            flags & FOS_ALLOWMULTISELECT == FOS_ALLOWMULTISELECT
        }
    }

    /**
        Set the multiselect flag of the dialog.
        Failures:
        • if there was a system error while setting the new flag value
        • if the dialog has `Save` for action
    */
    pub fn set_multiselect(&self, multiselect: bool) -> Result<(), NwgError> {
        use winapi::um::shobjidl::FOS_ALLOWMULTISELECT;

        if self.action == FileDialogAction::Save {
            return Err(NwgError::file_dialog("Cannot set multiselect flag for a save file dialog"));
        }

        let result = unsafe{ rh::toggle_dialog_flags(&mut *self.handle, FOS_ALLOWMULTISELECT, multiselect) };
        match result {
            Ok(_) => Ok(()),
            Err(e) => Err(e)
        }
    }

    /**
        Set the first opened folder when the dialog is shown. This value is overriden by the user after the dialog ran.
        Call `clear_client_data` to fix that.
        Failures:
        • if the default folder do not identify a folder
        • if the folder do not exists
    */
    pub fn set_default_folder<'a>(&self, folder: &'a str) -> Result<(), NwgError> {
        unsafe{
            let handle = &mut *self.handle;
            rh::file_dialog_set_default_folder(handle, &folder)
        }
    }

    /**
        Filter the files that the user can select (In a `Open` dialog) in the dialog or which extension to add to the saved file (in a `Save` dialog).
        This can only be set ONCE (the initialization counts) and won't work if the dialog is `OpenDirectory`.

        The `filters` value must be a '|' separated string having this format: "Test(*.txt;*.rs)|Any(*.*)"
        Where the fist part is the "human name" and the second part is a filter for the system.
    */
    pub fn set_filters<'a>(&self, filters: &'a str) -> Result<(), NwgError> {
        unsafe{
            let handle = &mut *self.handle;
            rh::file_dialog_set_filters(handle, &filters)
        }
    }

    /// Change the dialog title
    pub fn set_title<'a>(&self, title: &'a str) {
        unsafe {
            let title = to_utf16(title);
            let handle = &mut *self.handle;
            handle.SetTitle(title.as_ptr());
        }
    }

    /// Instructs the dialog to clear all persisted state information (such as the last folder visited).
    pub fn clear_client_data(&self) {
        unsafe{
            let handle =  &mut *self.handle;
            handle.ClearClientData();
        }
    }

}

impl fmt::Debug for FileDialog {

    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "FileDialog {{ action: {:?} }}", self.action)
    }

}

impl Default for FileDialog {
    fn default() -> FileDialog {
        FileDialog {
            handle: ptr::null_mut(),
            action: FileDialogAction::Open
        }
    }
}

impl PartialEq for FileDialog {
    fn eq(&self, other: &Self) -> bool {
        self.handle == other.handle && self.action == other.action
    }
}

impl Eq for FileDialog {}

/*
    Structure that hold the state required to build a file dialog
*/
pub struct FileDialogBuilder {
    pub title: Option<String>,
    pub action: FileDialogAction,
    pub multiselect: bool,
    pub default_folder: Option<String>,
    pub filters: Option<String>
}

impl FileDialogBuilder {

    pub fn title<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
        self.title = Some(t.into());
        self
    }

    pub fn default_folder<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
        self.default_folder = Some(t.into());
        self
    }

    pub fn filters<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
        self.filters = Some(t.into());
        self
    }

    pub fn action(mut self, a: FileDialogAction) -> FileDialogBuilder {
        self.action = a;
        self
    }

    pub fn multiselect(mut self, m: bool) -> FileDialogBuilder {
        self.multiselect = m;
        self
    }

    pub fn build(self, out: &mut FileDialog) -> Result<(), NwgError> {
        unsafe {
            out.handle = rh::create_file_dialog(
                self.action,
                self.multiselect,
                self.default_folder,
                self.filters
            )?;
        }

        out.action = self.action;

        if let Some(title) = self.title {
            out.set_title(&title);
        }

        Ok(())
    }

}

<commit_msg>Fix documentation formatting for FileDialog.<commit_after>use winapi::um::shobjidl::IFileDialog;
use crate::win32::resources_helper as rh;

use crate::win32::base_helper::to_utf16;
use crate::{ControlHandle, NwgError};
use std::{fmt, ptr, mem};

/**
    A enum that dictates how a file dialog should behave
    Members:
    * `Open`: User can select a file that is not a directory
    * `OpenDirectory`: User can select a directory
    * `Save`: User select the name of a file. If it already exists, a confirmation message will be raised
*/
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum FileDialogAction {
    Open,
    OpenDirectory,
    Save,
}

/**
    A file dialog control

    The file dialog builders accepts the following parameters:
    * title: The title of the dialog
    * action: The action to execute. Open, OpenDirectory for Save
    * multiselect: Whether the user can select more than one file. Only supported with the Open action
    * default_folder: Default folder to show in the dialog.
    * filters: If defined, filter the files that the user can select (In a Open dialog) or which extension to add to the saved file (in a Save dialog)

    ```rust
        use native_windows_gui as nwg;
        fn layout(dialog: &mut nwg::FileDialog) {
            nwg::FileDialog::builder()
                .title("Hello")
                .action(nwg::FileDialogAction::Open)
                .multiselect(true)
                .build(dialog);
        }
    ```
*/
pub struct FileDialog {
    handle: *mut IFileDialog,
    action: FileDialogAction
}

impl FileDialog {

    pub fn builder() -> FileDialogBuilder {
        FileDialogBuilder {
            title: None,
            action: FileDialogAction::Save,
            multiselect: false,
            default_folder: None,
            filters: None
        }
    }

    /// Return the action type executed by this dialog
    pub fn action(&self) -> FileDialogAction {
        self.action
    }

    /**
        Display the dialog. Return true if the dialog was accepted or false if it was cancelled
        If the dialog was accepted, `get_selected_item` or `get_selected_items` can be used to find the selected file(s)

        It's important to note that `run` blocks the current thread until the user as chosen a file (similar to `dispatch_thread_events`)

        The parent argument must be a window control otherwise the method will panic.
    */
    pub fn run<C: Into<ControlHandle>>(&self, parent: Option<C>) -> bool {
        use winapi::shared::winerror::S_OK;

        let parent_handle = match parent {
            Some(p) => p.into().hwnd().expect("File dialog parent must be a window control"),
            None => ptr::null_mut()
        };

        unsafe { (&mut *self.handle).Show(parent_handle) == S_OK }
    }

    /**
        Return the item selected in the dialog by the user.

        Failures:
        • if the dialog was not called
        • if there was a system error while reading the selected item
        • if the dialog has the `multiselect` flag
    */
    pub fn get_selected_item(&self) -> Result<String, NwgError> {

        if self.multiselect() {
            return Err(NwgError::file_dialog("FileDialog have the multiselect flag"));
        }

        unsafe {
            rh::filedialog_get_item(&mut *self.handle)
        }
    }

    /**
        Return the selected items in the dialog by the user.
        Failures:
        • if the dialog was not called
        • if there was a system error while reading the selected items
        • if the dialog has `Save` for action
    */
    pub fn get_selected_items(&self) -> Result<Vec<String>, NwgError> {
        if self.action == FileDialogAction::Save {
            return Err(NwgError::file_dialog("Save dialog cannot have more than one item selected"));
        }

        unsafe {
            rh::filedialog_get_items(mem::transmute(&mut *self.handle))
        }
    }

    /// Return `true` if the dialog accepts multiple values or `false` otherwise
    pub fn multiselect(&self) -> bool {
        use winapi::um::shobjidl::FOS_ALLOWMULTISELECT;

        unsafe {
            let flags = rh::file_dialog_options(&mut *self.handle).unwrap_or(0);
            flags & FOS_ALLOWMULTISELECT == FOS_ALLOWMULTISELECT
        }
    }

    /**
        Set the multiselect flag of the dialog.
        Failures:
        • if there was a system error while setting the new flag value
        • if the dialog has `Save` for action
    */
    pub fn set_multiselect(&self, multiselect: bool) -> Result<(), NwgError> {
        use winapi::um::shobjidl::FOS_ALLOWMULTISELECT;

        if self.action == FileDialogAction::Save {
            return Err(NwgError::file_dialog("Cannot set multiselect flag for a save file dialog"));
        }

        let result = unsafe{ rh::toggle_dialog_flags(&mut *self.handle, FOS_ALLOWMULTISELECT, multiselect) };
        match result {
            Ok(_) => Ok(()),
            Err(e) => Err(e)
        }
    }

    /**
        Set the first opened folder when the dialog is shown. This value is overriden by the user after the dialog ran.
        Call `clear_client_data` to fix that.
        Failures:
        • if the default folder do not identify a folder
        • if the folder do not exists
    */
    pub fn set_default_folder<'a>(&self, folder: &'a str) -> Result<(), NwgError> {
        unsafe{
            let handle = &mut *self.handle;
            rh::file_dialog_set_default_folder(handle, &folder)
        }
    }

    /**
        Filter the files that the user can select (In a `Open` dialog) in the dialog or which extension to add to the saved file (in a `Save` dialog).
        This can only be set ONCE (the initialization counts) and won't work if the dialog is `OpenDirectory`.

        The `filters` value must be a '|' separated string having this format: "Test(*.txt;*.rs)|Any(*.*)"
        Where the fist part is the "human name" and the second part is a filter for the system.
    */
    pub fn set_filters<'a>(&self, filters: &'a str) -> Result<(), NwgError> {
        unsafe{
            let handle = &mut *self.handle;
            rh::file_dialog_set_filters(handle, &filters)
        }
    }

    /// Change the dialog title
    pub fn set_title<'a>(&self, title: &'a str) {
        unsafe {
            let title = to_utf16(title);
            let handle = &mut *self.handle;
            handle.SetTitle(title.as_ptr());
        }
    }

    /// Instructs the dialog to clear all persisted state information (such as the last folder visited).
    pub fn clear_client_data(&self) {
        unsafe{
            let handle =  &mut *self.handle;
            handle.ClearClientData();
        }
    }

}

impl fmt::Debug for FileDialog {

    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "FileDialog {{ action: {:?} }}", self.action)
    }

}

impl Default for FileDialog {
    fn default() -> FileDialog {
        FileDialog {
            handle: ptr::null_mut(),
            action: FileDialogAction::Open
        }
    }
}

impl PartialEq for FileDialog {
    fn eq(&self, other: &Self) -> bool {
        self.handle == other.handle && self.action == other.action
    }
}

impl Eq for FileDialog {}

/*
    Structure that hold the state required to build a file dialog
*/
pub struct FileDialogBuilder {
    pub title: Option<String>,
    pub action: FileDialogAction,
    pub multiselect: bool,
    pub default_folder: Option<String>,
    pub filters: Option<String>
}

impl FileDialogBuilder {

    pub fn title<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
        self.title = Some(t.into());
        self
    }

    pub fn default_folder<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
        self.default_folder = Some(t.into());
        self
    }

    pub fn filters<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
        self.filters = Some(t.into());
        self
    }

    pub fn action(mut self, a: FileDialogAction) -> FileDialogBuilder {
        self.action = a;
        self
    }

    pub fn multiselect(mut self, m: bool) -> FileDialogBuilder {
        self.multiselect = m;
        self
    }

    pub fn build(self, out: &mut FileDialog) -> Result<(), NwgError> {
        unsafe {
            out.handle = rh::create_file_dialog(
                self.action,
                self.multiselect,
                self.default_folder,
                self.filters
            )?;
        }

        out.action = self.action;

        if let Some(title) = self.title {
            out.set_title(&title);
        }

        Ok(())
    }

}

<|endoftext|>


<commit_before>use std::result;

use analysis::ref_mode::RefMode;
use env::Env;
use library::{self, Nullable};
use super::conversion_type::ConversionType;
use traits::*;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TypeError {
    Ignored(String),
    Mismatch(String),
    Unimplemented(String),
}

pub type Result = result::Result<String, TypeError>;

fn into_inner(res: Result) -> String {
    use self::TypeError::*;
    match res {
        Ok(s) |
            Err(Ignored(s)) |
            Err(Mismatch(s)) |
            Err(Unimplemented(s)) => s,
    }
}

impl IntoString for Result {
    fn into_string(self) -> String {
        use self::TypeError::*;
        match self {
            Ok(s) => s,
            Err(Ignored(s)) => format!("/*Ignored*/{}", s),
            Err(Mismatch(s)) => format!("/*Metadata mismatch*/{}", s),
            Err(Unimplemented(s)) => format!("/*Unimplemented*/{}", s),
        }
    }
}

impl MapAny<String> for Result {
    fn map_any<F: FnOnce(String) -> String>(self, op: F) -> Result {
        use self::TypeError::*;
        match self {
            Ok(s) => Ok(op(s)),
            Err(Ignored(s)) => Err(Ignored(op(s))),
            Err(Mismatch(s)) => Err(Mismatch(op(s))),
            Err(Unimplemented(s)) => Err(Unimplemented(op(s))),
        }
    }
}

pub fn rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::None)
}

pub fn bounds_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::ByRefFake)
}

fn rust_type_full(env: &Env, type_id: library::TypeId, nullable: Nullable, ref_mode: RefMode) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let ok = |s: &str| Ok(s.into());
    let err = |s: &str| Err(TypeError::Unimplemented(s.into()));
    let mut skip_option = false;
    let type_ = env.library.type_(type_id);
    let mut rust_type = match *type_ {
        Fundamental(fund) => {
            match fund {
                None => err("()"),
                Boolean => ok("bool"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("i32"),      //maybe dependent on target system
                UInt => ok("u32"),     //maybe dependent on target system

                Short => ok("libc::c_short"),   //depends of target system
                UShort => ok("libc::c_ushort"), //depends of target system
                Long => ok("libc::c_long"),     //depends of target system
                ULong => ok("libc::c_ulong"),   //depends of target system

                Size => ok("usize"),     //depends of target system
                SSize => ok("isize"),    //depends of target system

                Float => ok("f32"),
                Double => ok("f64"),

                UniChar => ok("char"),
                Utf8 => if ref_mode.is_ref() { ok("str") } else { ok("String") },
                Filename => {
                    if ref_mode.is_ref() {
                        ok("std::path::Path")
                    } else {
                        ok("std::path::PathBuf")
                    }
                }
                Type if env.namespaces.glib_ns_id == library::MAIN_NAMESPACE => ok("types::Type"),
                Type => ok("glib::types::Type"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        }
        Alias(ref alias) => {
            rust_type_full(env, alias.typ, nullable, ref_mode)
                .map_any(|_| alias.name.clone())
        }
        Record(library::Record { ref c_type, .. }) if c_type == "GVariantType" => {
            if ref_mode.is_ref() { ok("VariantTy") } else { ok("VariantType") }
        }
        Enumeration(..) |
            Bitfield(..) |
            Record(..) |
            Union(..) |
            Class(..) |
            Interface(..) => {
            let name = type_.get_name().to_owned();
            if env.type_status(&type_id.full_name(&env.library)).ignored() {
                Err(TypeError::Ignored(name))
            }
            else {
                Ok(name)
            }
        }
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid)
            if ConversionType::of(&env.library, inner_tid) == ConversionType::Pointer => {
            skip_option = true;
            let inner_ref_mode = match *env.library.type_(inner_tid) {
                Class(..) |
                    Interface(..) => RefMode::None,
                _ => ref_mode,
            };
            rust_type_full(env, inner_tid, Nullable(false), inner_ref_mode)
                .map_any(|s| if ref_mode.is_ref() {
                    format!("[{}]", s)
                } else {
                    format!("Vec<{}>", s)
                })
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    };

    if type_id.ns_id != library::MAIN_NAMESPACE && type_id.ns_id != library::INTERNAL_NAMESPACE
        && !implemented_in_main_namespace(&env.library, type_id) {
        if env.type_status(&type_id.full_name(&env.library)).ignored() {
            rust_type = Err(TypeError::Ignored(into_inner(rust_type)));
        }
        rust_type = rust_type.map_any(|s| format!("{}::{}",
            env.namespaces[type_id.ns_id].higher_crate_name, s));
    }

    match ref_mode {
        RefMode::None | RefMode::ByRefFake => {}
        RefMode::ByRef | RefMode::ByRefImmut => rust_type = rust_type.map_any(|s| format!("&{}", s)),
        RefMode::ByRefMut => rust_type = rust_type.map_any(|s| format!("&mut {}", s)),
    }
    if *nullable && !skip_option {
        match ConversionType::of(&env.library, type_id) {
            ConversionType::Pointer
                | ConversionType::Scalar => {
                rust_type = rust_type.map_any(|s| format!("Option<{}>", s))
            }
            _ => (),
        }
    }

    rust_type
}

pub fn used_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    match *env.library.type_(type_id) {
        Fundamental(library::Fundamental::Type) |
            Fundamental(library::Fundamental::Short) |
            Fundamental(library::Fundamental::UShort) |
            Fundamental(library::Fundamental::Long) |
            Fundamental(library::Fundamental::ULong) |
            Fundamental(library::Fundamental::Filename) |
            Alias(..) |
            Bitfield(..) |
            Record(..) |
            Union(..) |
            Class(..) |
            Enumeration(..) |
            Interface(..) => rust_type(env, type_id),
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid) => used_rust_type(env, inner_tid),
        _ => Err(TypeError::Ignored("Don't need use".to_owned())),
    }
}

pub fn parameter_rust_type(env: &Env, type_id: library::TypeId,
                           direction: library::ParameterDirection, nullable: Nullable,
                           ref_mode: RefMode) -> Result {
    use library::Type::*;
    let type_ = env.library.type_(type_id);
    let rust_type = rust_type_full(env, type_id, nullable, ref_mode);
    match *type_ {
        Fundamental(..) => {
            rust_type.map_any(|s| format_parameter(s, direction))
        }

        Alias(ref alias) => {
            rust_type.and_then(|s| {
                parameter_rust_type(env, alias.typ, direction, nullable, ref_mode)
                    .map_any(|_| s)
            })
                .map_any(|s| format_parameter(s, direction))
        }

        Enumeration(..) |
            Union(..) |
            Bitfield(..) => rust_type.map_any(|s| format_parameter(s, direction)),

        Record(..) => {
            if direction == library::ParameterDirection::InOut {
                Err(TypeError::Unimplemented(into_inner(rust_type)))
            } else {
                rust_type
            }
        }

        Class(..) |
            Interface (..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Out |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }

        List(..) |
            SList(..) |
            CArray(..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    }
}

#[inline]
fn format_parameter(rust_type: String, direction: library::ParameterDirection) -> String {
    if direction.is_out() {
        format!("&mut {}", rust_type)
    } else {
        rust_type
    }
}

//TODO: remove
fn implemented_in_main_namespace(library: &library::Library, type_id: library::TypeId) -> bool {
    type_id.full_name(library) == "GLib.Error"
}
<commit_msg>Don't support String InOut parameters and &mut String Out parameters<commit_after>use std::result;

use analysis::ref_mode::RefMode;
use env::Env;
use library::{self, Nullable};
use super::conversion_type::ConversionType;
use traits::*;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TypeError {
    Ignored(String),
    Mismatch(String),
    Unimplemented(String),
}

pub type Result = result::Result<String, TypeError>;

fn into_inner(res: Result) -> String {
    use self::TypeError::*;
    match res {
        Ok(s) |
            Err(Ignored(s)) |
            Err(Mismatch(s)) |
            Err(Unimplemented(s)) => s,
    }
}

impl IntoString for Result {
    fn into_string(self) -> String {
        use self::TypeError::*;
        match self {
            Ok(s) => s,
            Err(Ignored(s)) => format!("/*Ignored*/{}", s),
            Err(Mismatch(s)) => format!("/*Metadata mismatch*/{}", s),
            Err(Unimplemented(s)) => format!("/*Unimplemented*/{}", s),
        }
    }
}

impl MapAny<String> for Result {
    fn map_any<F: FnOnce(String) -> String>(self, op: F) -> Result {
        use self::TypeError::*;
        match self {
            Ok(s) => Ok(op(s)),
            Err(Ignored(s)) => Err(Ignored(op(s))),
            Err(Mismatch(s)) => Err(Mismatch(op(s))),
            Err(Unimplemented(s)) => Err(Unimplemented(op(s))),
        }
    }
}

pub fn rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::None)
}

pub fn bounds_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::ByRefFake)
}

fn rust_type_full(env: &Env, type_id: library::TypeId, nullable: Nullable, ref_mode: RefMode) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let ok = |s: &str| Ok(s.into());
    let err = |s: &str| Err(TypeError::Unimplemented(s.into()));
    let mut skip_option = false;
    let type_ = env.library.type_(type_id);
    let mut rust_type = match *type_ {
        Fundamental(fund) => {
            match fund {
                None => err("()"),
                Boolean => ok("bool"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("i32"),      //maybe dependent on target system
                UInt => ok("u32"),     //maybe dependent on target system

                Short => ok("libc::c_short"),   //depends of target system
                UShort => ok("libc::c_ushort"), //depends of target system
                Long => ok("libc::c_long"),     //depends of target system
                ULong => ok("libc::c_ulong"),   //depends of target system

                Size => ok("usize"),     //depends of target system
                SSize => ok("isize"),    //depends of target system

                Float => ok("f32"),
                Double => ok("f64"),

                UniChar => ok("char"),
                Utf8 => if ref_mode.is_ref() { ok("str") } else { ok("String") },
                Filename => {
                    if ref_mode.is_ref() {
                        ok("std::path::Path")
                    } else {
                        ok("std::path::PathBuf")
                    }
                }
                Type if env.namespaces.glib_ns_id == library::MAIN_NAMESPACE => ok("types::Type"),
                Type => ok("glib::types::Type"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        }
        Alias(ref alias) => {
            rust_type_full(env, alias.typ, nullable, ref_mode)
                .map_any(|_| alias.name.clone())
        }
        Record(library::Record { ref c_type, .. }) if c_type == "GVariantType" => {
            if ref_mode.is_ref() { ok("VariantTy") } else { ok("VariantType") }
        }
        Enumeration(..) |
            Bitfield(..) |
            Record(..) |
            Union(..) |
            Class(..) |
            Interface(..) => {
            let name = type_.get_name().to_owned();
            if env.type_status(&type_id.full_name(&env.library)).ignored() {
                Err(TypeError::Ignored(name))
            }
            else {
                Ok(name)
            }
        }
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid)
            if ConversionType::of(&env.library, inner_tid) == ConversionType::Pointer => {
            skip_option = true;
            let inner_ref_mode = match *env.library.type_(inner_tid) {
                Class(..) |
                    Interface(..) => RefMode::None,
                _ => ref_mode,
            };
            rust_type_full(env, inner_tid, Nullable(false), inner_ref_mode)
                .map_any(|s| if ref_mode.is_ref() {
                    format!("[{}]", s)
                } else {
                    format!("Vec<{}>", s)
                })
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    };

    if type_id.ns_id != library::MAIN_NAMESPACE && type_id.ns_id != library::INTERNAL_NAMESPACE
        && !implemented_in_main_namespace(&env.library, type_id) {
        if env.type_status(&type_id.full_name(&env.library)).ignored() {
            rust_type = Err(TypeError::Ignored(into_inner(rust_type)));
        }
        rust_type = rust_type.map_any(|s| format!("{}::{}",
            env.namespaces[type_id.ns_id].higher_crate_name, s));
    }

    match ref_mode {
        RefMode::None | RefMode::ByRefFake => {}
        RefMode::ByRef | RefMode::ByRefImmut => rust_type = rust_type.map_any(|s| format!("&{}", s)),
        RefMode::ByRefMut => rust_type = rust_type.map_any(|s| format!("&mut {}", s)),
    }
    if *nullable && !skip_option {
        match ConversionType::of(&env.library, type_id) {
            ConversionType::Pointer
                | ConversionType::Scalar => {
                rust_type = rust_type.map_any(|s| format!("Option<{}>", s))
            }
            _ => (),
        }
    }

    rust_type
}

pub fn used_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    match *env.library.type_(type_id) {
        Fundamental(library::Fundamental::Type) |
            Fundamental(library::Fundamental::Short) |
            Fundamental(library::Fundamental::UShort) |
            Fundamental(library::Fundamental::Long) |
            Fundamental(library::Fundamental::ULong) |
            Fundamental(library::Fundamental::Filename) |
            Alias(..) |
            Bitfield(..) |
            Record(..) |
            Union(..) |
            Class(..) |
            Enumeration(..) |
            Interface(..) => rust_type(env, type_id),
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid) => used_rust_type(env, inner_tid),
        _ => Err(TypeError::Ignored("Don't need use".to_owned())),
    }
}

pub fn parameter_rust_type(env: &Env, type_id: library::TypeId,
                           direction: library::ParameterDirection, nullable: Nullable,
                           ref_mode: RefMode) -> Result {
    use library::Type::*;
    let type_ = env.library.type_(type_id);
    let rust_type = rust_type_full(env, type_id, nullable, ref_mode);
    match *type_ {
        Fundamental(fund) => {
            if fund == library::Fundamental::Utf8 || fund == library::Fundamental::Filename {
                if direction == library::ParameterDirection::InOut ||
                    (direction == library::ParameterDirection::Out && ref_mode == RefMode::ByRefMut) {
                    return Err(TypeError::Unimplemented(into_inner(rust_type)));
                }
            }
            rust_type.map_any(|s| format_parameter(s, direction))
        }

        Alias(ref alias) => {
            rust_type.and_then(|s| {
                parameter_rust_type(env, alias.typ, direction, nullable, ref_mode)
                    .map_any(|_| s)
            })
                .map_any(|s| format_parameter(s, direction))
        }

        Enumeration(..) |
            Union(..) |
            Bitfield(..) => rust_type.map_any(|s| format_parameter(s, direction)),

        Record(..) => {
            if direction == library::ParameterDirection::InOut {
                Err(TypeError::Unimplemented(into_inner(rust_type)))
            } else {
                rust_type
            }
        }

        Class(..) |
            Interface (..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Out |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }

        List(..) |
            SList(..) |
            CArray(..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    }
}

#[inline]
fn format_parameter(rust_type: String, direction: library::ParameterDirection) -> String {
    if direction.is_out() {
        format!("&mut {}", rust_type)
    } else {
        rust_type
    }
}

//TODO: remove
fn implemented_in_main_namespace(library: &library::Library, type_id: library::TypeId) -> bool {
    type_id.full_name(library) == "GLib.Error"
}
<|endoftext|>


<commit_before>#![feature(build_hasher_simple_hash_one)]

use ahash::*;
use core::slice;
use std::hash::{BuildHasher};

#[no_mangle]
pub extern "C" fn ahash64(buf: *const (), len: usize, seed: u64) -> u64 {
    let buf: &[u8] = unsafe { slice::from_raw_parts(buf as *const u8, len) };
    let build_hasher = RandomState::with_seed(seed as usize);
    build_hasher.hash_one(&buf)
}
<commit_msg>Run smhasher test with weaker keys<commit_after>#![feature(build_hasher_simple_hash_one)]

use ahash::*;
use core::slice;
use std::hash::{BuildHasher};

#[no_mangle]
pub extern "C" fn ahash64(buf: *const (), len: usize, seed: u64) -> u64 {
    let buf: &[u8] = unsafe { slice::from_raw_parts(buf as *const u8, len) };
    let build_hasher = RandomState::with_seeds(seed, seed, seed, seed);
    build_hasher.hash_one(&buf)
}
<|endoftext|>