<commit_before>//! A formatted and aligned table printer written in rust
use std::io::{stdout, Write, Error, ErrorKind};
use std::fmt;
use std::str;
use std::string::ToString;

/// A Struct representing a printable table
#[derive(Clone, Debug)]
pub struct Table {
	num_cols: usize,
	titles: Vec<String>,
	rows: Vec<Vec<String>>,
	col_sep: char,
	line_sep: char,
	sep_cross: char
}

impl Table {
	/// Create a new table with the number of columns equals to the length of `titles`
	pub fn new(titles: Vec<String>) -> Table {
		let n = titles.len();
		return Table {
			num_cols: n,
			titles: titles,
			rows: Vec::new(),
			col_sep: '|',
			line_sep: '-',
			sep_cross: '+'
		};
	}

	/// Change separators
	///
	/// `col` is the column separator
	/// `line` is the line separator
	/// `cross` is a special separator used when line and collumn separators meet
	/// Default separators used are '|', '-' and '+'
	pub fn separators(&mut self, col: char, line: char, cross: char) {
		self.col_sep = col;
		self.line_sep = line;
		self.sep_cross = cross;
	}

	/// Get the number of column
	pub fn get_column_num(&self) -> usize {
		return self.num_cols;
	}

	/// Get the number of rows
	pub fn len(&self) -> usize {
		return self.rows.len();
	}

	/// Get a mutable reference to a row
	pub fn get_mut_row(&mut self, row: usize) -> &mut Vec<String> {
		return &mut self.rows[row];
	}

	/// Get an immutable reference to a row
	pub fn get_row(&self, row: usize) -> &Vec<String> {
		return &self.rows[row];
	}

	/// Append a row in the table, transferring ownership of this row to the table
	/// and returning a mutable reference to the row
	pub fn add_row(&mut self, row: Vec<String>) -> Result<&mut Vec<String>, &str> {
		if row.len() != self.num_cols {
			return Err("Row does not have the proper number of column");
		}
		self.rows.push(row);
		let l = self.rows.len()-1;
		return Ok(self.get_mut_row(l));
	}

	/// Append an empty row in the table. Return a mutable reference to this new row.
	pub fn add_empty_row(&mut self) -> Result<&mut Vec<String>, &str> {
		let n = self.num_cols;
		return Ok(try!(self.add_row(vec!["".to_string(); n])));
	}

	/// Modify a single element in the table
	pub fn set_element(&mut self, element: String, column: usize, row: usize) -> Result<(), &str> {
		if column >= self.num_cols {
			return Err("Column index is higher than expected");
		}
		let rowline: &mut Vec<String>;
		if row > self.rows.len() {
			rowline = try!(self.add_empty_row());
		}
		else {
			rowline = self.get_mut_row(row);
		}
		rowline[column] = element;
		return Ok(());
	}

	/// Remove a row
	pub fn remove_row(&mut self, row: usize) {
		self.rows.remove(row);
	}

	fn get_col_width(&self, col_idx: usize) -> Result<usize, &str> {
		if col_idx >= self.num_cols {
			return Err("Column index is too high");
		}
		let mut width = self.titles[col_idx].len();
		for r in &self.rows {
			let l = r[col_idx].len();
			if l > width {
				width = l;
			}
		}
		return Ok(width);
	}

	fn print_line_separator(&self, out: &mut Write, col_width: &[usize]) -> Result<(), Error> {
		try!(write!(out, "{}", self.sep_cross));
		for i in 0..self.num_cols {
			for _ in 0..(col_width[i] + 2) {
				try!(write!(out, "{}", self.line_sep));
			}
			try!(write!(out, "{}", self.sep_cross));
		}
		return writeln!(out, "");
	}

	fn print_line(&self, out: &mut Write, line: &[String], col_width: &[usize]) -> Result<(), Error> {
		try!(write!(out, "{}", self.col_sep));
		for i in 0..self.num_cols {
			try!(write!(out, " {} ", line[i]));
			for _ in 0..(col_width[i] - line[i].len()) {
				try!(write!(out, " "));
			}
			try!(write!(out, "{}", self.col_sep));
		}
		return writeln!(out, "");
	}

	/// Print the table to `out`
	pub fn print(&self, out: &mut Write) -> Result<(), Error> {
		let mut col_width = vec![0usize; self.num_cols];
		for i in 0..self.num_cols {
			col_width[i] = self.get_col_width(i).unwrap();
		}
		try!(self.print_line_separator(out, &col_width));
		try!(self.print_line(out, &self.titles, &col_width));
		try!(self.print_line_separator(out, &col_width));
		for r in &self.rows {
			try!(self.print_line(out, r, &col_width));
			try!(self.print_line_separator(out, &col_width));
		}
		return out.flush();
	}

	/// Print the table to standard output
	/// # Panic
	/// Panic if writing to standard output fails
	pub fn printstd(&self) {
		self.print(&mut stdout())
			.ok()
			.expect("Cannot print table to standard output");
	}
}

impl fmt::Display for Table {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		let mut writer =  StringWriter::new();
		if let Err(_) = self.print(&mut writer) {
			return Err(fmt::Error)
		}
		return write!(fmt, "{}", writer.as_string());
	}
}

/// Internal utility for writing data into a string
struct StringWriter {
	string: String
}

impl StringWriter {
	/// Create a new `StringWriter`
	fn new() -> StringWriter {
		return StringWriter{string: String::new()};
	}

	/// Return a reference to the internal written `String`
	fn as_string(&self) -> &String {
		return &self.string;
	}
}

impl Write for StringWriter {
	fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
		let string = match str::from_utf8(data) {
			Ok(s) => s,
			Err(e) => return Err(Error::new(ErrorKind::Other, format!("Cannot decode utf8 string : {}", e)))
		};
		self.string.push_str(string);
		return Ok(data.len());
	}

	fn flush(&mut self) -> Result<(), Error> {
		return Ok(());
	}
}

/// Create a table with column's titles from arguments.
///
/// The table can also be initialized with some values.
/// All the arguments used for titles and elements must implement the `std::string::ToString` trait
/// # Syntax
/// table!([Title1, Title2, ...], [Element1_ row1, Element2_ row1, ...], [Element1_row2, ...], ...);
/// # Panic
/// May panic if some rows could not be inserted
/// # Example
/// ```
/// # #[macro_use] extern crate tabprint;
/// # fn main() {
/// // Create an empty table with titles :
/// let tab = table!(["Title1", "Title2", "Title3"]);
/// // Create a table initialized with some rows :
/// let tab = table!(["Title1", "Title2", "Title3"],
/// 				 ["Element1", "Element2", "Element3"],
/// 				 [1, 2, 3]
/// 				 );
/// # drop(tab);
/// # }
/// ```
#[macro_export]
macro_rules! table {
	([$($title: expr), *]) => ($crate::Table::new(vec![$($title.to_string()), *]));
	(
		[$($title: expr), *], $([$($key:expr), *]), *
	) => (
		{
			let mut tab = table!([$($title), *]);
			$(
				let row = vec![$($key.to_string()), *];
				if let Err(e) = tab.add_row(row) {
					panic!("Cannot create table from : {}", e);
				}
			)*
			tab
		}
	)
}

/// Create a table with `table!` macro, print it to standard output, then return this table for future usage.
///
/// The syntax is the same that the one for the `table!` macro
/// # Panic
/// May panic if some rows could not be inserted
#[macro_export]
macro_rules! ptable {
	([$($title: expr), *]) => (
		{
			let tab = table!([$($title), *]);
			tab.printstd();
			tab
		}
	);
	(
		[$($title: expr), *], $([$($key:expr), *]), *
	) => (
		{
			let tab = table!([$($title), *], $([$($key), *]), *);
			tab.printstd();
			tab
		}
	)
}<commit_msg>Table printing now use static dispatch to object implementing trait Write instead of dynamic dispatch to a &mut Write<commit_after>//! A formatted and aligned table printer written in rust
use std::io::{stdout, Write, Error, ErrorKind};
use std::fmt;
use std::str;
use std::string::ToString;

/// A Struct representing a printable table
#[derive(Clone, Debug)]
pub struct Table {
	num_cols: usize,
	titles: Vec<String>,
	rows: Vec<Vec<String>>,
	col_sep: char,
	line_sep: char,
	sep_cross: char
}

impl Table {
	/// Create a new table with the number of columns equals to the length of `titles`
	pub fn new(titles: Vec<String>) -> Table {
		let n = titles.len();
		return Table {
			num_cols: n,
			titles: titles,
			rows: Vec::new(),
			col_sep: '|',
			line_sep: '-',
			sep_cross: '+'
		};
	}

	/// Change separators
	///
	/// `col` is the column separator
	/// `line` is the line separator
	/// `cross` is a special separator used when line and collumn separators meet
	/// Default separators used are '|', '-' and '+'
	pub fn separators(&mut self, col: char, line: char, cross: char) {
		self.col_sep = col;
		self.line_sep = line;
		self.sep_cross = cross;
	}

	/// Get the number of column
	pub fn get_column_num(&self) -> usize {
		return self.num_cols;
	}

	/// Get the number of rows
	pub fn len(&self) -> usize {
		return self.rows.len();
	}

	/// Get a mutable reference to a row
	pub fn get_mut_row(&mut self, row: usize) -> &mut Vec<String> {
		return &mut self.rows[row];
	}

	/// Get an immutable reference to a row
	pub fn get_row(&self, row: usize) -> &Vec<String> {
		return &self.rows[row];
	}

	/// Append a row in the table, transferring ownership of this row to the table
	/// and returning a mutable reference to the row
	pub fn add_row(&mut self, row: Vec<String>) -> Result<&mut Vec<String>, &str> {
		if row.len() != self.num_cols {
			return Err("Row does not have the proper number of column");
		}
		self.rows.push(row);
		let l = self.rows.len()-1;
		return Ok(self.get_mut_row(l));
	}

	/// Append an empty row in the table. Return a mutable reference to this new row.
	pub fn add_empty_row(&mut self) -> Result<&mut Vec<String>, &str> {
		let n = self.num_cols;
		return Ok(try!(self.add_row(vec!["".to_string(); n])));
	}

	/// Modify a single element in the table
	pub fn set_element<T: ToString>(&mut self, element: T, column: usize, row: usize) -> Result<(), &str> {
		if column >= self.num_cols {
			return Err("Column index is higher than expected");
		}
		let rowline: &mut Vec<String>;
		if row > self.rows.len() {
			rowline = try!(self.add_empty_row());
		}
		else {
			rowline = self.get_mut_row(row);
		}
		rowline[column] = element.to_string();
		return Ok(());
	}

	/// Remove a row
	pub fn remove_row(&mut self, row: usize) {
		self.rows.remove(row);
	}

	fn get_col_width(&self, col_idx: usize) -> Result<usize, &str> {
		if col_idx >= self.num_cols {
			return Err("Column index is too high");
		}
		let mut width = self.titles[col_idx].len();
		for r in &self.rows {
			let l = r[col_idx].len();
			if l > width {
				width = l;
			}
		}
		return Ok(width);
	}

	fn print_line_separator<T: Write>(&self, out: &mut T, col_width: &[usize]) -> Result<(), Error> {
		try!(write!(out, "{}", self.sep_cross));
		for i in 0..self.num_cols {
			for _ in 0..(col_width[i] + 2) {
				try!(write!(out, "{}", self.line_sep));
			}
			try!(write!(out, "{}", self.sep_cross));
		}
		return writeln!(out, "");
	}

	fn print_line<T: Write>(&self, out: &mut T, line: &[String], col_width: &[usize]) -> Result<(), Error> {
		try!(write!(out, "{}", self.col_sep));
		for i in 0..self.num_cols {
			try!(write!(out, " {} ", line[i]));
			for _ in 0..(col_width[i] - line[i].len()) {
				try!(write!(out, " "));
			}
			try!(write!(out, "{}", self.col_sep));
		}
		return writeln!(out, "");
	}

	/// Print the table to `out`
	pub fn print<T: Write>(&self, out: &mut T) -> Result<(), Error> {
		let mut col_width = vec![0usize; self.num_cols];
		for i in 0..self.num_cols {
			col_width[i] = self.get_col_width(i).unwrap();
		}
		try!(self.print_line_separator(out, &col_width));
		try!(self.print_line(out, &self.titles, &col_width));
		try!(self.print_line_separator(out, &col_width));
		for r in &self.rows {
			try!(self.print_line(out, r, &col_width));
			try!(self.print_line_separator(out, &col_width));
		}
		return out.flush();
	}

	/// Print the table to standard output
	/// # Panic
	/// Panic if writing to standard output fails
	pub fn printstd(&self) {
		self.print(&mut stdout())
			.ok()
			.expect("Cannot print table to standard output");
	}
}

impl fmt::Display for Table {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		let mut writer =  StringWriter::new();
		if let Err(_) = self.print(&mut writer) {
			return Err(fmt::Error)
		}
		return fmt.write_str(writer.as_string());
	}
}

/// Internal utility for writing data into a string
struct StringWriter {
	string: String
}

impl StringWriter {
	/// Create a new `StringWriter`
	fn new() -> StringWriter {
		return StringWriter{string: String::new()};
	}

	/// Return a reference to the internally written `String`
	fn as_string(&self) -> &String {
		return &self.string;
	}
}

impl Write for StringWriter {
	fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
		let string = match str::from_utf8(data) {
			Ok(s) => s,
			Err(e) => return Err(Error::new(ErrorKind::Other, format!("Cannot decode utf8 string : {}", e)))
		};
		self.string.push_str(string);
		return Ok(data.len());
	}

	fn flush(&mut self) -> Result<(), Error> {
		return Ok(());
	}
}

/// Create a table with column's titles from arguments.
///
/// The table can also be initialized with some values.
/// All the arguments used for titles and elements must implement the `std::string::ToString` trait
/// # Syntax
/// table!([Title1, Title2, ...], [Element1_ row1, Element2_ row1, ...], [Element1_row2, ...], ...);
/// # Panic
/// May panic if some rows could not be inserted
/// # Example
/// ```
/// # #[macro_use] extern crate tabprint;
/// # fn main() {
/// // Create an empty table with titles :
/// let tab = table!(["Title1", "Title2", "Title3"]);
/// // Create a table initialized with some rows :
/// let tab = table!(["Title1", "Title2", "Title3"],
/// 				 ["Element1", "Element2", "Element3"],
/// 				 [1, 2, 3]
/// 				 );
/// # drop(tab);
/// # }
/// ```
#[macro_export]
macro_rules! table {
	([$($title: expr), *]) => ($crate::Table::new(vec![$($title.to_string()), *]));
	(
		[$($title: expr), *], $([$($key:expr), *]), *
	) => (
		{
			let mut tab = table!([$($title), *]);
			$(
				let row = vec![$($key.to_string()), *];
				if let Err(e) = tab.add_row(row) {
					panic!("Cannot create table from : {}", e);
				}
			)*
			tab
		}
	)
}

/// Create a table with `table!` macro, print it to standard output, then return this table for future usage.
///
/// The syntax is the same that the one for the `table!` macro
/// # Panic
/// May panic if some rows could not be inserted
#[macro_export]
macro_rules! ptable {
	([$($title: expr), *]) => (
		{
			let tab = table!([$($title), *]);
			tab.printstd();
			tab
		}
	);
	(
		[$($title: expr), *], $([$($key:expr), *]), *
	) => (
		{
			let tab = table!([$($title), *], $([$($key), *]), *);
			tab.printstd();
			tab
		}
	)
}<|endoftext|>


<commit_before>// Copyright 2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Types that facilitate representing `GObject` descendants.

use std::marker::PhantomData;
use std::ptr;
use translate::*;
use types::{self, Type, StaticType};
use gobject_ffi;

/// A reference to any GObject descendant.
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq, Eq)]
pub struct Ref(*mut gobject_ffi::GObject);

impl Ref {
    #[inline]
    fn add_ref(&self) { unsafe { gobject_ffi::g_object_ref_sink(self.0 as *mut _); } }

    #[inline]
    fn unref(&self) { unsafe { gobject_ffi::g_object_unref(self.0 as *mut _); } }

    /// Transfer: none constructor.
    #[inline]
    pub fn from_glib_none(ptr: *mut gobject_ffi::GObject) -> Ref {
        let r = Ref(ptr);
        r.add_ref();
        r
    }

    /// Transfer: full constructor.
    #[inline]
    pub fn from_glib_full(ptr: *mut gobject_ffi::GObject) -> Ref {
        Ref(ptr)
    }

    /// Returns a transfer: none raw pointer.
    #[inline]
    pub fn to_glib_none(&self) -> *mut gobject_ffi::GObject {
        self.0
    }

    /// Returns a transfer: full raw pointer.
    #[inline]
    pub fn to_glib_full(&self) -> *mut gobject_ffi::GObject {
        self.add_ref();
        self.0
    }
}

impl Clone for Ref {
    #[inline]
    fn clone(&self) -> Ref {
        self.add_ref();
        Ref(self.0)
    }
}

impl Drop for Ref {
    #[inline]
    fn drop(&mut self) {
        self.unref();
    }
}

/// A helper type holding a reference to a specific object or interface.
///
/// `T` is the foreign `struct` type corresponding to the object.
pub struct VirtualRef<'a, T> (&'a Ref, PhantomData<T>);

impl<'a, T> VirtualRef<'a, T> {
    #[inline]
    fn new(r: &'a Ref) -> VirtualRef<'a, T> { VirtualRef(r, PhantomData) }
}

impl<'a, T> ToGlibPtr<'a, *mut T> for VirtualRef<'a, T> {
    type Storage = &'a Ref;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, VirtualRef<'a, T>> {
        Stash(self.0.to_glib_none() as *mut _, self.0)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.0.to_glib_full() as *mut _
    }
}

impl<'a, T> ToGlibPtr<'a, *mut T> for Option<&'a VirtualRef<'a, T>> {
    type Storage = Option<&'a Ref>;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, Option<&'a VirtualRef<'a, T>>> {
        if let Some(ref s) = *self {
            Stash(s.0.to_glib_none() as *mut _, Some(s.0))
        }
        else {
            Stash(ptr::null_mut(), None)
        }
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().map_or(ptr::null_mut(), |s| s.0.to_glib_full() as *mut _)
    }
}

/// A wrapper around the `Ref`.
pub trait Wrapper: StaticType {
    /// The foreign `struct` type corresponding to the object.
    type GlibType;
    /// Wraps a `Ref`.
    unsafe fn wrap(r: Ref) -> Self;
    /// Returns a reference to the inner `Ref`.
    fn as_ref(&self) -> &Ref;
    /// Transforms into the inner `Ref`.
    fn unwrap(self) -> Ref;
}

impl<'a, T, W: Wrapper<GlibType = T>> ToGlibPtr<'a, *mut T> for &'a W {
    type Storage = &'a Ref;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, &'a W> {
        Stash(self.as_ref().to_glib_none() as *mut _, self.as_ref())
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().to_glib_full() as *mut _
    }
}

impl <T: Wrapper> FromGlibPtr<*mut <T as Wrapper>::GlibType> for T {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut <T as Wrapper>::GlibType) -> Self {
        assert!(!ptr.is_null());
        debug_assert!(types::instance_of::<T>(ptr as *const _));
        T::wrap(Ref::from_glib_none(ptr as *mut _))
    }

    #[inline]
    unsafe fn from_glib_full(ptr: *mut <T as Wrapper>::GlibType) -> Self {
        assert!(!ptr.is_null());
        debug_assert!(types::instance_of::<T>(ptr as *const _));
        T::wrap(Ref::from_glib_full(ptr as *mut _))
    }
}

/// Declares the "is a" relationship.
///
/// `Self` is said to implement `T` and can be `upcast` to a corresponding type.
///
/// `T` always implements `Upcast<T>`.
pub unsafe trait Upcast<T: Wrapper>: Wrapper {
    /// Upcasts to a helper type corresponding to `T`.
    #[inline]
    fn upcast(&self) -> VirtualRef<<T as Wrapper>::GlibType> {
        debug_assert!(types::instance_of::<T>(self.as_ref().to_glib_none() as *const _));
        VirtualRef::<<T as Wrapper>::GlibType>::new(self.as_ref())
    }
}

unsafe impl<T: Wrapper> Upcast<T> for T { }

/// A complement to `Upcast` that allows downcasting.
pub trait Downcast<T> {
    /// Tries to downcast to `T`.
    ///
    /// Returns `Ok(T)` if the instance implements `T` and `Err(Self)` otherwise.
    fn downcast(self) -> Result<T, Self>;
    /// Downcasts to `T` unconditionally.
    ///
    /// Panics if the instance doesn't implement `T`.
    fn downcast_unchecked(self) -> T;
}

impl <Super, Sub> Downcast<Sub> for Super
where Super: Wrapper, Sub: Wrapper + Upcast<Super> {
    #[inline]
    fn downcast(self) -> Result<Sub, Super> {
        if types::instance_of::<Sub>(self.as_ref().to_glib_none() as *const _) {
            unsafe { Ok(Sub::wrap(self.unwrap())) }
        }
        else {
            Err(self)
        }
    }

    #[inline]
    fn downcast_unchecked(self) -> Sub {
        assert!(types::instance_of::<Sub>(self.as_ref().to_glib_none() as *const _));
        unsafe { Sub::wrap(self.unwrap()) }
    }
}

#[derive(Clone)]
pub struct Object(Ref);

impl Wrapper for Object {
    type GlibType = gobject_ffi::GObject;
    #[inline]
    unsafe fn wrap(r: Ref) -> Object { Object(r) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl StaticType for Object {
    #[inline]
    fn static_type() -> Type { Type::BaseObject }
}

pub trait ObjectExt {
}

impl<T: Upcast<Object>> ObjectExt for T {
}

/// The crate-local generic type for `GObject` descendants in GLib.
#[derive(Debug)]
pub struct GenericObject<T>(Ref, PhantomData<T>);

impl<T> Wrapper for GenericObject<T> where GenericObject<T>: StaticType {
    type GlibType = T;
    #[inline]
    unsafe fn wrap(r: Ref) -> GenericObject<T> { GenericObject(r, PhantomData) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl<T> Clone for GenericObject<T> {
    #[inline]
    fn clone(&self) -> GenericObject<T> {
        GenericObject(self.0.clone(), PhantomData)
    }
}

unsafe impl<T> Upcast<Object> for GenericObject<T> where GenericObject<T>: StaticType { }
<commit_msg>Remove compilation warning<commit_after>// Copyright 2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Types that facilitate representing `GObject` descendants.

use std::marker::PhantomData;
use std::ptr;
use translate::*;
use types::{self, Type, StaticType};
use gobject_ffi;

/// A reference to any GObject descendant.
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq, Eq)]
pub struct Ref(*mut gobject_ffi::GObject);

impl Ref {
    #[inline]
    fn add_ref(&self) { unsafe { gobject_ffi::g_object_ref_sink(self.0 as *mut _); } }

    #[inline]
    fn unref(&self) { unsafe { gobject_ffi::g_object_unref(self.0 as *mut _); } }

    /// Transfer: none constructor.
    #[inline]
    pub fn from_glib_none(ptr: *mut gobject_ffi::GObject) -> Ref {
        let r = Ref(ptr);
        r.add_ref();
        r
    }

    /// Transfer: full constructor.
    #[inline]
    pub fn from_glib_full(ptr: *mut gobject_ffi::GObject) -> Ref {
        Ref(ptr)
    }

    /// Returns a transfer: none raw pointer.
    #[inline]
    pub fn to_glib_none(&self) -> *mut gobject_ffi::GObject {
        self.0
    }

    /// Returns a transfer: full raw pointer.
    #[inline]
    pub fn to_glib_full(&self) -> *mut gobject_ffi::GObject {
        self.add_ref();
        self.0
    }
}

impl Clone for Ref {
    #[inline]
    fn clone(&self) -> Ref {
        self.add_ref();
        Ref(self.0)
    }
}

impl Drop for Ref {
    #[inline]
    fn drop(&mut self) {
        self.unref();
    }
}

/// A helper type holding a reference to a specific object or interface.
///
/// `T` is the foreign `struct` type corresponding to the object.
pub struct VirtualRef<'a, T> (&'a Ref, PhantomData<T>);

impl<'a, T> VirtualRef<'a, T> {
    #[inline]
    fn new(r: &'a Ref) -> VirtualRef<'a, T> { VirtualRef(r, PhantomData) }
}

impl<'a, T> ToGlibPtr<'a, *mut T> for VirtualRef<'a, T> {
    type Storage = &'a Ref;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, VirtualRef<'a, T>> {
        Stash(self.0.to_glib_none() as *mut _, self.0)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.0.to_glib_full() as *mut _
    }
}

impl<'a, T> ToGlibPtr<'a, *mut T> for Option<&'a VirtualRef<'a, T>> {
    type Storage = Option<&'a Ref>;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, Option<&'a VirtualRef<'a, T>>> {
        if let Some(ref s) = *self {
            Stash(s.0.to_glib_none() as *mut _, Some(s.0))
        }
        else {
            Stash(ptr::null_mut(), None)
        }
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().map_or(ptr::null_mut(), |s| s.0.to_glib_full() as *mut _)
    }
}

/// A wrapper around the `Ref`.
pub trait Wrapper: StaticType {
    /// The foreign `struct` type corresponding to the object.
    type GlibType;
    /// Wraps a `Ref`.
    unsafe fn wrap(r: Ref) -> Self;
    /// Returns a reference to the inner `Ref`.
    fn as_ref(&self) -> &Ref;
    /// Transforms into the inner `Ref`.
    fn unwrap(self) -> Ref;
}

impl<'a, T, W: Wrapper<GlibType = T>> ToGlibPtr<'a, *mut T> for &'a W {
    type Storage = &'a Ref;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, &'a W> {
        Stash(self.as_ref().to_glib_none() as *mut _, self.as_ref())
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().to_glib_full() as *mut _
    }
}

impl <T: Wrapper> FromGlibPtr<*mut <T as Wrapper>::GlibType> for T {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut <T as Wrapper>::GlibType) -> Self {
        assert!(!ptr.is_null());
        debug_assert!(types::instance_of::<T>(ptr as *const _));
        T::wrap(Ref::from_glib_none(ptr as *mut _))
    }

    #[inline]
    unsafe fn from_glib_full(ptr: *mut <T as Wrapper>::GlibType) -> Self {
        assert!(!ptr.is_null());
        debug_assert!(types::instance_of::<T>(ptr as *const _));
        T::wrap(Ref::from_glib_full(ptr as *mut _))
    }
}

/// Declares the "is a" relationship.
///
/// `Self` is said to implement `T` and can be `upcast` to a corresponding type.
///
/// `T` always implements `Upcast<T>`.
pub unsafe trait Upcast<T: Wrapper>: Wrapper {
    /// Upcasts to a helper type corresponding to `T`.
    #[inline]
    fn upcast(&self) -> VirtualRef<<T as Wrapper>::GlibType> {
        debug_assert!(types::instance_of::<T>(self.as_ref().to_glib_none() as *const _));
        VirtualRef::<<T as Wrapper>::GlibType>::new(self.as_ref())
    }
}

unsafe impl<T: Wrapper> Upcast<T> for T { }

/// A complement to `Upcast` that allows downcasting.
pub trait Downcast<T> {
    /// Tries to downcast to `T`.
    ///
    /// Returns `Ok(T)` if the instance implements `T` and `Err(Self)` otherwise.
    fn downcast(self) -> Result<T, Self>
        where Self: Sized;
    /// Downcasts to `T` unconditionally.
    ///
    /// Panics if the instance doesn't implement `T`.
    fn downcast_unchecked(self) -> T;
}

impl <Super, Sub> Downcast<Sub> for Super
where Super: Wrapper, Sub: Wrapper + Upcast<Super> {
    #[inline]
    fn downcast(self) -> Result<Sub, Super> {
        if types::instance_of::<Sub>(self.as_ref().to_glib_none() as *const _) {
            unsafe { Ok(Sub::wrap(self.unwrap())) }
        }
        else {
            Err(self)
        }
    }

    #[inline]
    fn downcast_unchecked(self) -> Sub {
        assert!(types::instance_of::<Sub>(self.as_ref().to_glib_none() as *const _));
        unsafe { Sub::wrap(self.unwrap()) }
    }
}

#[derive(Clone)]
pub struct Object(Ref);

impl Wrapper for Object {
    type GlibType = gobject_ffi::GObject;
    #[inline]
    unsafe fn wrap(r: Ref) -> Object { Object(r) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl StaticType for Object {
    #[inline]
    fn static_type() -> Type { Type::BaseObject }
}

pub trait ObjectExt {
}

impl<T: Upcast<Object>> ObjectExt for T {
}

/// The crate-local generic type for `GObject` descendants in GLib.
#[derive(Debug)]
pub struct GenericObject<T>(Ref, PhantomData<T>);

impl<T> Wrapper for GenericObject<T> where GenericObject<T>: StaticType {
    type GlibType = T;
    #[inline]
    unsafe fn wrap(r: Ref) -> GenericObject<T> { GenericObject(r, PhantomData) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl<T> Clone for GenericObject<T> {
    #[inline]
    fn clone(&self) -> GenericObject<T> {
        GenericObject(self.0.clone(), PhantomData)
    }
}

unsafe impl<T> Upcast<Object> for GenericObject<T> where GenericObject<T>: StaticType { }
<|endoftext|>


<commit_before>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::io::Read;
use std::result;

use byteorder::{LittleEndian, ReadBytesExt};

// MARK: Error types

/// Represents an error that occurred while reading a wave file.
#[derive(Debug)]
pub enum ReadError {
    /// The file format is incorrect or unsupported.
    Format(FormatErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type ReadResult<T> = result::Result<T, ReadError>;

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            ReadError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when the wave file is incorrect or unsupported.
#[derive(Debug)]
pub enum FormatErrorKind {
    /// The file does not start with a "RIFF" tag and chunk size.
    NotARiffFile,
}

impl FormatErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            FormatErrorKind::NotARiffFile => "not a RIFF file",
        }
    }
}

impl fmt::Display for FormatErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for ReadError {
    fn description(&self) -> &str {
        match *self {
            ReadError::Format(ref kind) => kind.to_string(),
            ReadError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ReadError::Format(_) => None,
            ReadError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError {
        ReadError::Io(err)
    }
}

// MARK: Validation and parsing functions

trait WaveReader: Read {
    fn validate_is_riff_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"RIFF", FormatErrorKind::NotARiffFile));
        // The next four bytes represent the chunk size. We're not going to
        // validate it, so that we can still try to read files that might have
        // an incorrect chunk size, so let's skip over it.
        let _ = try!(self.read_chunk_size());
        Ok(())
    }

    fn validate_tag(&mut self,
                    expected_tag: &[u8; 4],
                    err_kind: FormatErrorKind)
                    -> ReadResult<()> {
        let tag = try!(self.read_tag());
        if &tag != expected_tag {
            return Err(ReadError::Format(err_kind));
        }
        Ok(())
    }

    fn read_tag(&mut self) -> ReadResult<[u8; 4]> {
        let mut tag: [u8; 4] = [0; 4];
        try!(self.read_exact(&mut tag));
        Ok(tag)
    }

    fn read_chunk_size(&mut self) -> ReadResult<u32> {
        Ok(try!(self.read_u32::<LittleEndian>()))
    }
}

impl<T> WaveReader for T where T: Read {}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use {FormatErrorKind, ReadError, WaveReader};

    // This is a helper macro that helps us validate results in our tests.
    // Thank you bluss and durka42!
    macro_rules! assert_matches {
        ($expected:pat $(if $guard:expr)*, $value:expr) => {
            match $value {
                $expected $(if $guard)* => {},
                ref actual => {
                    panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                        stringify!($expected), actual);
                },
            }
        };
    }

    #[test]
    fn test_validate_is_riff_file_ok() {
        let mut data = Cursor::new(b"RIFF    ");
        assert_matches!(Ok(()), data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_incomplete() {
        let mut data = Cursor::new(b"RIF     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }
}
<commit_msg>Validate that after the RIFF chunk header, the file continues with "WAVE".<commit_after>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::io::Read;
use std::result;

use byteorder::{LittleEndian, ReadBytesExt};

// MARK: Error types

/// Represents an error that occurred while reading a wave file.
#[derive(Debug)]
pub enum ReadError {
    /// The file format is incorrect or unsupported.
    Format(FormatErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type ReadResult<T> = result::Result<T, ReadError>;

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            ReadError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when the wave file is incorrect or unsupported.
#[derive(Debug)]
pub enum FormatErrorKind {
    /// The file does not start with a "RIFF" tag and chunk size.
    NotARiffFile,
    /// The file doesn't continue with "WAVE" after the RIFF chunk header.
    NotAWaveFile,
}

impl FormatErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            FormatErrorKind::NotARiffFile => "not a RIFF file",
            FormatErrorKind::NotAWaveFile => "not a WAVE file",
        }
    }
}

impl fmt::Display for FormatErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for ReadError {
    fn description(&self) -> &str {
        match *self {
            ReadError::Format(ref kind) => kind.to_string(),
            ReadError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ReadError::Format(_) => None,
            ReadError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError {
        ReadError::Io(err)
    }
}

// MARK: Validation and parsing functions

trait WaveReader: Read {
    fn validate_is_riff_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"RIFF", FormatErrorKind::NotARiffFile));
        // The next four bytes represent the chunk size. We're not going to
        // validate it, so that we can still try to read files that might have
        // an incorrect chunk size, so let's skip over it.
        let _ = try!(self.read_chunk_size());
        Ok(())
    }

    fn validate_is_wave_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"WAVE", FormatErrorKind::NotAWaveFile));
        Ok(())
    }

    fn validate_tag(&mut self,
                    expected_tag: &[u8; 4],
                    err_kind: FormatErrorKind)
                    -> ReadResult<()> {
        let tag = try!(self.read_tag());
        if &tag != expected_tag {
            return Err(ReadError::Format(err_kind));
        }
        Ok(())
    }

    fn read_tag(&mut self) -> ReadResult<[u8; 4]> {
        let mut tag: [u8; 4] = [0; 4];
        try!(self.read_exact(&mut tag));
        Ok(tag)
    }

    fn read_chunk_size(&mut self) -> ReadResult<u32> {
        Ok(try!(self.read_u32::<LittleEndian>()))
    }
}

impl<T> WaveReader for T where T: Read {}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use {FormatErrorKind, ReadError, WaveReader};

    // This is a helper macro that helps us validate results in our tests.
    // Thank you bluss and durka42!
    macro_rules! assert_matches {
        ($expected:pat $(if $guard:expr)*, $value:expr) => {
            match $value {
                $expected $(if $guard)* => {},
                ref actual => {
                    panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                        stringify!($expected), actual);
                },
            }
        };
    }

    // RIFF header tests

    #[test]
    fn test_validate_is_riff_file_ok() {
        let mut data = Cursor::new(b"RIFF    ");
        assert_matches!(Ok(()), data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_incomplete() {
        let mut data = Cursor::new(b"RIF     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    // Wave tag tests

    #[test]
    fn test_validate_is_wave_file_ok() {
        let mut data = Cursor::new(b"WAVE");
        assert_matches!(Ok(()), data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_incomplete() {
        let mut data = Cursor::new(b"WAV ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[macro_use]
extern crate bitflags;

extern crate fsevent_sys as fsevent;
extern crate libc;

use fsevent::core_foundation as cf;
use fsevent::fsevent as fs;

use std::convert::AsRef;
use std::ffi::CStr;
use std::ptr;
use std::slice;
use std::slice::from_raw_parts_mut;
use std::str::from_utf8;

use std::sync::mpsc::Sender;

pub const NULL: cf::CFRef = cf::NULL;

pub struct FsEvent {
    paths: cf::CFMutableArrayRef,
    since_when: fs::FSEventStreamEventId,
    latency: cf::CFTimeInterval,
    flags: fs::FSEventStreamCreateFlags,
    sender: Sender<Event>,
}

#[derive(Debug)]
pub struct Event {
    pub event_id: u64,
    pub flag: StreamFlags,
    pub path: String,
}

pub type FsEventCallback = fn(Vec<Event>);

// Synchronize with
// /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Headers/FSEvents.h
bitflags! {
  #[repr(C)]
  pub struct StreamFlags: u32 {
    const NONE = 0x00000000;
    const MUST_SCAN_SUBDIRS = 0x00000001;
    const USER_DROPPED = 0x00000002;
    const KERNEL_DROPPED = 0x00000004;
    const IDS_WRAPPED = 0x00000008;
    const HISTORY_DONE = 0x00000010;
    const ROOT_CHANGED = 0x00000020;
    const MOUNT = 0x00000040;
    const UNMOUNT = 0x00000080;
    const ITEM_CREATED = 0x00000100;
    const ITEM_REMOVED = 0x00000200;
    const INOTE_META_MOD = 0x00000400;
    const ITEM_RENAMED = 0x00000800;
    const ITEM_MODIFIED = 0x00001000;
    const FINDER_INFO_MOD = 0x00002000;
    const ITEM_CHANGE_OWNER = 0x00004000;
    const ITEM_XATTR_MOD = 0x00008000;
    const IS_FILE = 0x00010000;
    const IS_DIR = 0x00020000;
    const IS_SYMLIMK = 0x00040000;
    const OWN_EVENT = 0x00080000;
    const IS_HARDLINK = 0x00100000;
    const IS_LAST_HARDLINK = 0x00200000;
    const ITEM_CLONED = 0x400000;
  }
}

impl std::fmt::Display for StreamFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        if self.contains(StreamFlags::MUST_SCAN_SUBDIRS) {
            let _d = write!(f, "MUST_SCAN_SUBDIRS ");
        }
        if self.contains(StreamFlags::USER_DROPPED) {
            let _d = write!(f, "USER_DROPPED ");
        }
        if self.contains(StreamFlags::KERNEL_DROPPED) {
            let _d = write!(f, "KERNEL_DROPPED ");
        }
        if self.contains(StreamFlags::IDS_WRAPPED) {
            let _d = write!(f, "IDS_WRAPPED ");
        }
        if self.contains(StreamFlags::HISTORY_DONE) {
            let _d = write!(f, "HISTORY_DONE ");
        }
        if self.contains(StreamFlags::ROOT_CHANGED) {
            let _d = write!(f, "ROOT_CHANGED ");
        }
        if self.contains(StreamFlags::MOUNT) {
            let _d = write!(f, "MOUNT ");
        }
        if self.contains(StreamFlags::UNMOUNT) {
            let _d = write!(f, "UNMOUNT ");
        }
        if self.contains(StreamFlags::ITEM_CREATED) {
            let _d = write!(f, "ITEM_CREATED ");
        }
        if self.contains(StreamFlags::ITEM_REMOVED) {
            let _d = write!(f, "ITEM_REMOVED ");
        }
        if self.contains(StreamFlags::INOTE_META_MOD) {
            let _d = write!(f, "INOTE_META_MOD ");
        }
        if self.contains(StreamFlags::ITEM_RENAMED) {
            let _d = write!(f, "ITEM_RENAMED ");
        }
        if self.contains(StreamFlags::ITEM_MODIFIED) {
            let _d = write!(f, "ITEM_MODIFIED ");
        }
        if self.contains(StreamFlags::FINDER_INFO_MOD) {
            let _d = write!(f, "FINDER_INFO_MOD ");
        }
        if self.contains(StreamFlags::ITEM_CHANGE_OWNER) {
            let _d = write!(f, "ITEM_CHANGE_OWNER ");
        }
        if self.contains(StreamFlags::ITEM_XATTR_MOD) {
            let _d = write!(f, "ITEM_XATTR_MOD ");
        }
        if self.contains(StreamFlags::IS_FILE) {
            let _d = write!(f, "IS_FILE ");
        }
        if self.contains(StreamFlags::IS_DIR) {
            let _d = write!(f, "IS_DIR ");
        }
        if self.contains(StreamFlags::IS_SYMLIMK) {
            let _d = write!(f, "IS_SYMLIMK ");
        }
        if self.contains(StreamFlags::OWN_EVENT) {
            let _d = write!(f, "OWN_EVENT ");
        }
        if self.contains(StreamFlags::IS_LAST_HARDLINK) {
            let _d = write!(f, "IS_LAST_HARDLINK ");
        }
        if self.contains(StreamFlags::IS_HARDLINK) {
            let _d = write!(f, "IS_HARDLINK ");
        }
        if self.contains(StreamFlags::ITEM_CLONED) {
            let _d = write!(f, "ITEM_CLONED ");
        }
        write!(f, "")
    }
}

pub fn is_api_available() -> (bool, String) {
    let ma = cf::system_version_major();
    let mi = cf::system_version_minor();

    if ma == 10 && mi < 5 {
        (
            false,
            "This version of OSX does not support the FSEvent library, cannot proceed".to_string(),
        )
    } else {
        (true, "ok".to_string())
    }
}

fn default_stream_context(info: *const FsEvent) -> fs::FSEventStreamContext {
    let ptr = info as *mut libc::c_void;
    fs::FSEventStreamContext {
        version: 0,
        info: ptr,
        retain: cf::NULL,
        copy_description: cf::NULL,
    }
}

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub struct Error {
    msg: String,
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.msg
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.msg.fmt(f)
    }
}

impl FsEvent {
    pub fn new(sender: Sender<Event>) -> FsEvent {
        let fsevent: FsEvent;

        unsafe {
            fsevent = FsEvent {
                paths: cf::CFArrayCreateMutable(
                    cf::kCFAllocatorDefault,
                    0,
                    &cf::kCFTypeArrayCallBacks,
                ),
                since_when: fs::kFSEventStreamEventIdSinceNow,
                latency: 0.0,
                flags: fs::kFSEventStreamCreateFlagFileEvents | fs::kFSEventStreamCreateFlagNoDefer,
                sender,
            };
        }
        fsevent
    }

    // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
    pub fn append_path(&self, source: &str) -> Result<()> {
        unsafe {
            let mut err = ptr::null_mut();
            let cf_path = cf::str_path_to_cfstring_ref(source, &mut err);
            if !err.is_null() {
                let cf_str = cf::CFCopyDescription(err as cf::CFRef);
                let mut buf = [0; 1024];
                cf::CFStringGetCString(
                    cf_str,
                    buf.as_mut_ptr(),
                    buf.len() as cf::CFIndex,
                    cf::kCFStringEncodingUTF8,
                );
                Err(Error {
                    msg: CStr::from_ptr(buf.as_ptr())
                        .to_str()
                        .unwrap_or("Unknown error")
                        .to_string(),
                })
            } else {
                cf::CFArrayAppendValue(self.paths, cf_path);
                cf::CFRelease(cf_path);
                Ok(())
            }
        }
    }
    pub fn observe(&self) {
        let stream_context = default_stream_context(self);

        let cb = callback as *mut _;

        unsafe {
            let stream = fs::FSEventStreamCreate(
                cf::kCFAllocatorDefault,
                cb,
                &stream_context,
                self.paths,
                self.since_when,
                self.latency,
                self.flags,
            );

            // fs::FSEventStreamShow(stream);

            fs::FSEventStreamScheduleWithRunLoop(
                stream,
                cf::CFRunLoopGetCurrent(),
                cf::kCFRunLoopDefaultMode,
            );

            fs::FSEventStreamStart(stream);
            cf::CFRunLoopRun();

            fs::FSEventStreamFlushSync(stream);
            fs::FSEventStreamStop(stream);
        }
    }
}

#[allow(unused_variables)]
pub unsafe fn callback(
    stream_ref: fs::FSEventStreamRef,
    info: *mut libc::c_void,
    num_events: libc::size_t,                // size_t numEvents
    event_paths: *const *const libc::c_char, // void *eventPaths
    event_flags: *mut libc::c_void,          // const FSEventStreamEventFlags eventFlags[]
    event_ids: *mut libc::c_void,            // const FSEventStreamEventId eventIds[]
) {
    let num = num_events as usize;
    let e_ptr = event_flags as *mut u32;
    let i_ptr = event_ids as *mut u64;
    let fs_event = info as *mut FsEvent;

    let paths: &[*const libc::c_char] =
        std::mem::transmute(slice::from_raw_parts(event_paths, num));
    let flags = from_raw_parts_mut(e_ptr, num);
    let ids = from_raw_parts_mut(i_ptr, num);

    for p in 0..num {
        let i = CStr::from_ptr(paths[p]).to_bytes();
        let path = from_utf8(i).expect("Invalid UTF8 string.");
        let flag: StreamFlags = StreamFlags::from_bits(flags[p] as u32).expect(
            format!(
                "Unable to decode StreamFlags: {} for {}",
                flags[p] as u32, path
            ).as_ref(),
        );
        // println!("{}: {}", ids[p], flag);

        let event = Event {
            event_id: ids[p],
            flag,
            path: path.to_string(),
        };
        let _s = (*fs_event).sender.send(event);
    }
}
<commit_msg>The `callback` unsafe fn doesn't need to be pub.<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[macro_use]
extern crate bitflags;

extern crate fsevent_sys as fsevent;
extern crate libc;

use fsevent::core_foundation as cf;
use fsevent::fsevent as fs;

use std::convert::AsRef;
use std::ffi::CStr;
use std::ptr;
use std::slice;
use std::slice::from_raw_parts_mut;
use std::str::from_utf8;

use std::sync::mpsc::Sender;

pub const NULL: cf::CFRef = cf::NULL;

pub struct FsEvent {
    paths: cf::CFMutableArrayRef,
    since_when: fs::FSEventStreamEventId,
    latency: cf::CFTimeInterval,
    flags: fs::FSEventStreamCreateFlags,
    sender: Sender<Event>,
}

#[derive(Debug)]
pub struct Event {
    pub event_id: u64,
    pub flag: StreamFlags,
    pub path: String,
}

pub type FsEventCallback = fn(Vec<Event>);

// Synchronize with
// /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Headers/FSEvents.h
bitflags! {
  #[repr(C)]
  pub struct StreamFlags: u32 {
    const NONE = 0x00000000;
    const MUST_SCAN_SUBDIRS = 0x00000001;
    const USER_DROPPED = 0x00000002;
    const KERNEL_DROPPED = 0x00000004;
    const IDS_WRAPPED = 0x00000008;
    const HISTORY_DONE = 0x00000010;
    const ROOT_CHANGED = 0x00000020;
    const MOUNT = 0x00000040;
    const UNMOUNT = 0x00000080;
    const ITEM_CREATED = 0x00000100;
    const ITEM_REMOVED = 0x00000200;
    const INOTE_META_MOD = 0x00000400;
    const ITEM_RENAMED = 0x00000800;
    const ITEM_MODIFIED = 0x00001000;
    const FINDER_INFO_MOD = 0x00002000;
    const ITEM_CHANGE_OWNER = 0x00004000;
    const ITEM_XATTR_MOD = 0x00008000;
    const IS_FILE = 0x00010000;
    const IS_DIR = 0x00020000;
    const IS_SYMLIMK = 0x00040000;
    const OWN_EVENT = 0x00080000;
    const IS_HARDLINK = 0x00100000;
    const IS_LAST_HARDLINK = 0x00200000;
    const ITEM_CLONED = 0x400000;
  }
}

impl std::fmt::Display for StreamFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        if self.contains(StreamFlags::MUST_SCAN_SUBDIRS) {
            let _d = write!(f, "MUST_SCAN_SUBDIRS ");
        }
        if self.contains(StreamFlags::USER_DROPPED) {
            let _d = write!(f, "USER_DROPPED ");
        }
        if self.contains(StreamFlags::KERNEL_DROPPED) {
            let _d = write!(f, "KERNEL_DROPPED ");
        }
        if self.contains(StreamFlags::IDS_WRAPPED) {
            let _d = write!(f, "IDS_WRAPPED ");
        }
        if self.contains(StreamFlags::HISTORY_DONE) {
            let _d = write!(f, "HISTORY_DONE ");
        }
        if self.contains(StreamFlags::ROOT_CHANGED) {
            let _d = write!(f, "ROOT_CHANGED ");
        }
        if self.contains(StreamFlags::MOUNT) {
            let _d = write!(f, "MOUNT ");
        }
        if self.contains(StreamFlags::UNMOUNT) {
            let _d = write!(f, "UNMOUNT ");
        }
        if self.contains(StreamFlags::ITEM_CREATED) {
            let _d = write!(f, "ITEM_CREATED ");
        }
        if self.contains(StreamFlags::ITEM_REMOVED) {
            let _d = write!(f, "ITEM_REMOVED ");
        }
        if self.contains(StreamFlags::INOTE_META_MOD) {
            let _d = write!(f, "INOTE_META_MOD ");
        }
        if self.contains(StreamFlags::ITEM_RENAMED) {
            let _d = write!(f, "ITEM_RENAMED ");
        }
        if self.contains(StreamFlags::ITEM_MODIFIED) {
            let _d = write!(f, "ITEM_MODIFIED ");
        }
        if self.contains(StreamFlags::FINDER_INFO_MOD) {
            let _d = write!(f, "FINDER_INFO_MOD ");
        }
        if self.contains(StreamFlags::ITEM_CHANGE_OWNER) {
            let _d = write!(f, "ITEM_CHANGE_OWNER ");
        }
        if self.contains(StreamFlags::ITEM_XATTR_MOD) {
            let _d = write!(f, "ITEM_XATTR_MOD ");
        }
        if self.contains(StreamFlags::IS_FILE) {
            let _d = write!(f, "IS_FILE ");
        }
        if self.contains(StreamFlags::IS_DIR) {
            let _d = write!(f, "IS_DIR ");
        }
        if self.contains(StreamFlags::IS_SYMLIMK) {
            let _d = write!(f, "IS_SYMLIMK ");
        }
        if self.contains(StreamFlags::OWN_EVENT) {
            let _d = write!(f, "OWN_EVENT ");
        }
        if self.contains(StreamFlags::IS_LAST_HARDLINK) {
            let _d = write!(f, "IS_LAST_HARDLINK ");
        }
        if self.contains(StreamFlags::IS_HARDLINK) {
            let _d = write!(f, "IS_HARDLINK ");
        }
        if self.contains(StreamFlags::ITEM_CLONED) {
            let _d = write!(f, "ITEM_CLONED ");
        }
        write!(f, "")
    }
}

pub fn is_api_available() -> (bool, String) {
    let ma = cf::system_version_major();
    let mi = cf::system_version_minor();

    if ma == 10 && mi < 5 {
        (
            false,
            "This version of OSX does not support the FSEvent library, cannot proceed".to_string(),
        )
    } else {
        (true, "ok".to_string())
    }
}

fn default_stream_context(info: *const FsEvent) -> fs::FSEventStreamContext {
    let ptr = info as *mut libc::c_void;
    fs::FSEventStreamContext {
        version: 0,
        info: ptr,
        retain: cf::NULL,
        copy_description: cf::NULL,
    }
}

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub struct Error {
    msg: String,
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.msg
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.msg.fmt(f)
    }
}

impl FsEvent {
    pub fn new(sender: Sender<Event>) -> FsEvent {
        let fsevent: FsEvent;

        unsafe {
            fsevent = FsEvent {
                paths: cf::CFArrayCreateMutable(
                    cf::kCFAllocatorDefault,
                    0,
                    &cf::kCFTypeArrayCallBacks,
                ),
                since_when: fs::kFSEventStreamEventIdSinceNow,
                latency: 0.0,
                flags: fs::kFSEventStreamCreateFlagFileEvents | fs::kFSEventStreamCreateFlagNoDefer,
                sender,
            };
        }
        fsevent
    }

    // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
    pub fn append_path(&self, source: &str) -> Result<()> {
        unsafe {
            let mut err = ptr::null_mut();
            let cf_path = cf::str_path_to_cfstring_ref(source, &mut err);
            if !err.is_null() {
                let cf_str = cf::CFCopyDescription(err as cf::CFRef);
                let mut buf = [0; 1024];
                cf::CFStringGetCString(
                    cf_str,
                    buf.as_mut_ptr(),
                    buf.len() as cf::CFIndex,
                    cf::kCFStringEncodingUTF8,
                );
                Err(Error {
                    msg: CStr::from_ptr(buf.as_ptr())
                        .to_str()
                        .unwrap_or("Unknown error")
                        .to_string(),
                })
            } else {
                cf::CFArrayAppendValue(self.paths, cf_path);
                cf::CFRelease(cf_path);
                Ok(())
            }
        }
    }
    pub fn observe(&self) {
        let stream_context = default_stream_context(self);

        let cb = callback as *mut _;

        unsafe {
            let stream = fs::FSEventStreamCreate(
                cf::kCFAllocatorDefault,
                cb,
                &stream_context,
                self.paths,
                self.since_when,
                self.latency,
                self.flags,
            );

            // fs::FSEventStreamShow(stream);

            fs::FSEventStreamScheduleWithRunLoop(
                stream,
                cf::CFRunLoopGetCurrent(),
                cf::kCFRunLoopDefaultMode,
            );

            fs::FSEventStreamStart(stream);
            cf::CFRunLoopRun();

            fs::FSEventStreamFlushSync(stream);
            fs::FSEventStreamStop(stream);
        }
    }
}

#[allow(unused_variables)]
unsafe fn callback(
    stream_ref: fs::FSEventStreamRef,
    info: *mut libc::c_void,
    num_events: libc::size_t,                // size_t numEvents
    event_paths: *const *const libc::c_char, // void *eventPaths
    event_flags: *mut libc::c_void,          // const FSEventStreamEventFlags eventFlags[]
    event_ids: *mut libc::c_void,            // const FSEventStreamEventId eventIds[]
) {
    let num = num_events as usize;
    let e_ptr = event_flags as *mut u32;
    let i_ptr = event_ids as *mut u64;
    let fs_event = info as *mut FsEvent;

    let paths: &[*const libc::c_char] =
        std::mem::transmute(slice::from_raw_parts(event_paths, num));
    let flags = from_raw_parts_mut(e_ptr, num);
    let ids = from_raw_parts_mut(i_ptr, num);

    for p in 0..num {
        let i = CStr::from_ptr(paths[p]).to_bytes();
        let path = from_utf8(i).expect("Invalid UTF8 string.");
        let flag: StreamFlags = StreamFlags::from_bits(flags[p] as u32).expect(
            format!(
                "Unable to decode StreamFlags: {} for {}",
                flags[p] as u32, path
            ).as_ref(),
        );
        // println!("{}: {}", ids[p], flag);

        let event = Event {
            event_id: ids[p],
            flag,
            path: path.to_string(),
        };
        let _s = (*fs_event).sender.send(event);
    }
}
<|endoftext|>


<commit_before>//! # derive_more
//! Rust has lots of builtin traits that are implemented for its basic types, such as [`Add`],
//! [`Not`] or [`From`].
//! However, when wrapping these types inside your own structs or enums you lose the
//! implementations of these traits and are required to recreate them.
//! This is especially annoying when your own structures are very simple, such as when using the
//! commonly advised newtype pattern (e.g. `MyInt(i32)`).
//!
//! This library tries to remove these annoyances and the corresponding boilerplate code.
//! It does this by allowing you to derive lots of commonly used traits for both structs and enums.
//!
//! ## Example code
//!
//! By using this library the following code just works:
//!
//!
//! ```rust
//! # #[macro_use] extern crate derive_more;
//!
//! #[derive(Debug, Eq, PartialEq, From, Add)]
//! struct MyInt(i32);
//!
//! #[derive(Debug, Eq, PartialEq, From, Mul)]
//! struct Point2D {
//!     x: i32,
//!     y: i32,
//! }
//!
//! #[derive(Debug, Eq, PartialEq, From, Add)]
//! enum MyEnum {
//!     Int(i32),
//!     UnsignedInt(u32),
//!     Nothing,
//! }
//!
//! fn main() {
//!     let my_11 = MyInt(5) + 6.into();
//!     assert_eq!(MyInt(11), MyInt(5) + 6.into());
//!     assert_eq!(Point2D { x: 5, y: 6 } * 10, (50, 60).into());
//!     assert_eq!(MyEnum::Int(15), (MyEnum::Int(8) + 7.into()).unwrap())
//! }
//!
//!
//! ```
//!
//! ## The newly derivable traits
//!
//! Obviously not all traits should be derived to the same code, because they are different
//! different traits after all.
//! However, some of the semantics of the traits overlap a lot, so they have been grouped in the
//! following way:
//!
//! 1. `From`, only contains the [`From`].
//! 2. `Not`-like, contains [`Not`] and [`Neg`].
//! 3. `Add`-like, contains [`Add`], [`Sub`], [`BitAnd`], [`BitOr`] and [`BitXor`].
//! 4. `AddAssign`-like, contains [`AddAssign`], [`SubAssign`], [`BitAndAssign`], [`BitOrAssign`]
//!    and [`BitXorAssign`].
//! 5. `Mul`-like, contains [`Mul`], [`Div`], [`Rem`], [`Shr`] and [`Shl`].
//!
//!
//! ## Generated code
//!
//! It is important to understand what code gets generated when using one of the derives from this
//! crate.
//! That is why the links below explain what code gets generated for a trait for each group from
//! before.
//!
//! 1. [`#[derive(From)]`](from.html)
//! 2. [`#[derive(Not)]`](not.html)
//! 3. [`#[derive(Add)]`](add.html)
//! 4. [`#[derive(AddAssign)]`](add_assign.html)
//! 5. [`#[derive(Mul)]`](mul.html)
//!
//! If you want to be sure what code is generated for your specific trait I recommend using the
//! [`cargo-expand`] utility.
//! This will show you your code with all macros and derives expanded.
//!
//! ## Installation
//!
//! This library heavily uses Macros 1.1, which is to stabilized in Rust 1.15 (the next Rust
//! release).
//! To use it before that time you have to install the nightly or beta channel.
//!
//! After doing this, add this to `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! derive_more = "0.4.0"
//! ```
//!
//! And this to the top of your Rust file:
//!
//! ```rust
//! #[macro_use]
//! extern crate derive_more;
//! # fn main () {}
//! ```
//!
//! [`cargo-expand`]: https://github.com/dtolnay/cargo-expand
//! [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
//! [`Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html
//! [`Neg`]: https://doc.rust-lang.org/std/ops/trait.Neg.html
//! [`Add`]: https://doc.rust-lang.org/std/ops/trait.Add.html
//! [`Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
//! [`BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
//! [`BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
//! [`BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html
//! [`Mul`]: https://doc.rust-lang.org/std/ops/trait.Mul.html
//! [`Div`]: https://doc.rust-lang.org/std/ops/trait.Div.html
//! [`Rem`]: https://doc.rust-lang.org/std/ops/trait.Rem.html
//! [`Shr`]: https://doc.rust-lang.org/std/ops/trait.Shr.html
//! [`Shl`]: https://doc.rust-lang.org/std/ops/trait.Shl.html
//! [`AddAssign`]: https://doc.rust-lang.org/std/ops/trait.AddAssign.html
//! [`SubAssign`]: https://doc.rust-lang.org/std/ops/trait.SubAssign.html
//! [`BitAndAssign`]: https://doc.rust-lang.org/std/ops/trait.BitAndAssign.html
//! [`BitOrAssign`]: https://doc.rust-lang.org/std/ops/trait.BitOrAssign.html
//! [`BitXorAssign`]: https://doc.rust-lang.org/std/ops/trait.BitXorAssign.html

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

use proc_macro::TokenStream;

mod utils;

mod from;
mod constructor;
mod add_like;
mod add_assign_like;
mod mul_like;
mod mul_assign_like;
mod not_like;

macro_rules! create_derive(
    ($mod_:ident, $trait_:ident, $fn_name: ident) => {
        #[proc_macro_derive($trait_)]
        #[doc(hidden)]
        pub fn $fn_name(input: TokenStream) -> TokenStream {
            let s = input.to_string();
            let ast = syn::parse_macro_input(&s).unwrap();
            $mod_::expand(&ast, stringify!($trait_)).parse().expect("Expanded output was no correct Rust code")
        }
    }
);

create_derive!(from, From, from_derive);

create_derive!(constructor, Constructor, constructor_derive);

create_derive!(add_like, Add, add_derive);
create_derive!(add_like, Sub, sub_derive);
create_derive!(add_like, BitAnd, bit_and_derive);
create_derive!(add_like, BitOr, bit_or_derive);
create_derive!(add_like, BitXor, bit_xor_derive);

create_derive!(mul_like, Mul, mul_derive);
create_derive!(mul_like, Div, div_derive);
create_derive!(mul_like, Rem, rem_derive);
create_derive!(mul_like, Shr, shr_derive);
create_derive!(mul_like, Shl, shl_derive);

create_derive!(not_like, Not, not_derive);
create_derive!(not_like, Neg, neg_derive);

create_derive!(add_assign_like, AddAssign, add_assign_derive);
create_derive!(add_assign_like, SubAssign, sub_assign_derive);
create_derive!(add_assign_like, BitAndAssign, bit_and_assign_derive);
create_derive!(add_assign_like, BitOrAssign, bit_or_assign_derive);
create_derive!(add_assign_like, BitXorAssign, bit_xor_assign_derive);

create_derive!(mul_assign_like, MulAssign, mul_assign_derive);
create_derive!(mul_assign_like, DivAssign, div_assign_derive);
create_derive!(mul_assign_like, RemAssign, rem_assign_derive);
create_derive!(mul_assign_like, ShrAssign, shr_assign_derive);
create_derive!(mul_assign_like, ShlAssign, shl_assign_derive);
<commit_msg>Cleanup: Reorder some code to match docs<commit_after>//! # derive_more
//! Rust has lots of builtin traits that are implemented for its basic types, such as [`Add`],
//! [`Not`] or [`From`].
//! However, when wrapping these types inside your own structs or enums you lose the
//! implementations of these traits and are required to recreate them.
//! This is especially annoying when your own structures are very simple, such as when using the
//! commonly advised newtype pattern (e.g. `MyInt(i32)`).
//!
//! This library tries to remove these annoyances and the corresponding boilerplate code.
//! It does this by allowing you to derive lots of commonly used traits for both structs and enums.
//!
//! ## Example code
//!
//! By using this library the following code just works:
//!
//!
//! ```rust
//! # #[macro_use] extern crate derive_more;
//!
//! #[derive(Debug, Eq, PartialEq, From, Add)]
//! struct MyInt(i32);
//!
//! #[derive(Debug, Eq, PartialEq, From, Mul)]
//! struct Point2D {
//!     x: i32,
//!     y: i32,
//! }
//!
//! #[derive(Debug, Eq, PartialEq, From, Add)]
//! enum MyEnum {
//!     Int(i32),
//!     UnsignedInt(u32),
//!     Nothing,
//! }
//!
//! fn main() {
//!     let my_11 = MyInt(5) + 6.into();
//!     assert_eq!(MyInt(11), MyInt(5) + 6.into());
//!     assert_eq!(Point2D { x: 5, y: 6 } * 10, (50, 60).into());
//!     assert_eq!(MyEnum::Int(15), (MyEnum::Int(8) + 7.into()).unwrap())
//! }
//!
//!
//! ```
//!
//! ## The newly derivable traits
//!
//! Obviously not all traits should be derived to the same code, because they are different
//! different traits after all.
//! However, some of the semantics of the traits overlap a lot, so they have been grouped in the
//! following way:
//!
//! 1. `From`, only contains the [`From`].
//! 2. `Not`-like, contains [`Not`] and [`Neg`].
//! 3. `Add`-like, contains [`Add`], [`Sub`], [`BitAnd`], [`BitOr`] and [`BitXor`].
//! 4. `AddAssign`-like, contains [`AddAssign`], [`SubAssign`], [`BitAndAssign`], [`BitOrAssign`]
//!    and [`BitXorAssign`].
//! 5. `Mul`-like, contains [`Mul`], [`Div`], [`Rem`], [`Shr`] and [`Shl`].
//!
//!
//! ## Generated code
//!
//! It is important to understand what code gets generated when using one of the derives from this
//! crate.
//! That is why the links below explain what code gets generated for a trait for each group from
//! before.
//!
//! 1. [`#[derive(From)]`](from.html)
//! 2. [`#[derive(Not)]`](not.html)
//! 3. [`#[derive(Add)]`](add.html)
//! 4. [`#[derive(AddAssign)]`](add_assign.html)
//! 5. [`#[derive(Mul)]`](mul.html)
//!
//! If you want to be sure what code is generated for your specific trait I recommend using the
//! [`cargo-expand`] utility.
//! This will show you your code with all macros and derives expanded.
//!
//! ## Installation
//!
//! This library heavily uses Macros 1.1, which is to stabilized in Rust 1.15 (the next Rust
//! release).
//! To use it before that time you have to install the nightly or beta channel.
//!
//! After doing this, add this to `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! derive_more = "0.4.0"
//! ```
//!
//! And this to the top of your Rust file:
//!
//! ```rust
//! #[macro_use]
//! extern crate derive_more;
//! # fn main () {}
//! ```
//!
//! [`cargo-expand`]: https://github.com/dtolnay/cargo-expand
//! [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
//! [`Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html
//! [`Neg`]: https://doc.rust-lang.org/std/ops/trait.Neg.html
//! [`Add`]: https://doc.rust-lang.org/std/ops/trait.Add.html
//! [`Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
//! [`BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
//! [`BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
//! [`BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html
//! [`Mul`]: https://doc.rust-lang.org/std/ops/trait.Mul.html
//! [`Div`]: https://doc.rust-lang.org/std/ops/trait.Div.html
//! [`Rem`]: https://doc.rust-lang.org/std/ops/trait.Rem.html
//! [`Shr`]: https://doc.rust-lang.org/std/ops/trait.Shr.html
//! [`Shl`]: https://doc.rust-lang.org/std/ops/trait.Shl.html
//! [`AddAssign`]: https://doc.rust-lang.org/std/ops/trait.AddAssign.html
//! [`SubAssign`]: https://doc.rust-lang.org/std/ops/trait.SubAssign.html
//! [`BitAndAssign`]: https://doc.rust-lang.org/std/ops/trait.BitAndAssign.html
//! [`BitOrAssign`]: https://doc.rust-lang.org/std/ops/trait.BitOrAssign.html
//! [`BitXorAssign`]: https://doc.rust-lang.org/std/ops/trait.BitXorAssign.html

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

use proc_macro::TokenStream;

mod utils;

mod from;
mod constructor;
mod not_like;
mod add_like;
mod add_assign_like;
mod mul_like;
mod mul_assign_like;

macro_rules! create_derive(
    ($mod_:ident, $trait_:ident, $fn_name: ident) => {
        #[proc_macro_derive($trait_)]
        #[doc(hidden)]
        pub fn $fn_name(input: TokenStream) -> TokenStream {
            let s = input.to_string();
            let ast = syn::parse_macro_input(&s).unwrap();
            $mod_::expand(&ast, stringify!($trait_)).parse().expect("Expanded output was no correct Rust code")
        }
    }
);

create_derive!(from, From, from_derive);

create_derive!(constructor, Constructor, constructor_derive);

create_derive!(not_like, Not, not_derive);
create_derive!(not_like, Neg, neg_derive);

create_derive!(add_like, Add, add_derive);
create_derive!(add_like, Sub, sub_derive);
create_derive!(add_like, BitAnd, bit_and_derive);
create_derive!(add_like, BitOr, bit_or_derive);
create_derive!(add_like, BitXor, bit_xor_derive);

create_derive!(mul_like, Mul, mul_derive);
create_derive!(mul_like, Div, div_derive);
create_derive!(mul_like, Rem, rem_derive);
create_derive!(mul_like, Shr, shr_derive);
create_derive!(mul_like, Shl, shl_derive);

create_derive!(add_assign_like, AddAssign, add_assign_derive);
create_derive!(add_assign_like, SubAssign, sub_assign_derive);
create_derive!(add_assign_like, BitAndAssign, bit_and_assign_derive);
create_derive!(add_assign_like, BitOrAssign, bit_or_assign_derive);
create_derive!(add_assign_like, BitXorAssign, bit_xor_assign_derive);

create_derive!(mul_assign_like, MulAssign, mul_assign_derive);
create_derive!(mul_assign_like, DivAssign, div_assign_derive);
create_derive!(mul_assign_like, RemAssign, rem_assign_derive);
create_derive!(mul_assign_like, ShrAssign, shr_assign_derive);
create_derive!(mul_assign_like, ShlAssign, shl_assign_derive);
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! An implementation of the [Cap'n Proto remote procedure call](https://capnproto.org/rpc.html)
//! protocol. Includes all [Level 1](https://capnproto.org/rpc.html#protocol-features) features.
//!
//! # Example
//!
//! ```capnp
//! # Cap'n Proto schema
//! interface Foo {
//!     identity @0 (x: UInt32) -> (y: UInt32);
//! }
//! ```
//!
//! ```ignore
//! // Rust server defining an implementation of Foo.
//! struct FooImpl;
//! impl foo::Server for FooImpl {
//!     fn identity(&mut self,
//!                 params: foo::IdentityParams,
//!                 mut results: foo::IdentityResults)
//!                 -> Promise<(), ::capnp::Error>
//!     {
//!         let x = pry!(params.get()).get_x();
//!         results.get().set_y(x);
//!         Promise::ok(())
//!     }
//! }
//! ```
//!
//! ```ignore
//! // Rust client calling a remote implementation of Foo.
//! let mut request = foo_client.identity_request();
//! request.get().set_x(123);
//! let promise = request.send().promise.map(|response| {
//!     println!("results = {}", try!(response.get()).get_y());
//!     Ok(())
//! });
//! ```
//!
//! For a more complete example, see https://github.com/dwrensha/capnp-rpc-rust/tree/master/examples/calculator

extern crate capnp;
#[macro_use] extern crate gj;
extern crate gjio;
extern crate capnp_gj;

use gj::Promise;
use capnp::Error;
use capnp::private::capability::{ClientHook, ServerHook};
use std::cell::RefCell;
use std::rc::Rc;

/// Code generated from [rpc.capnp]
/// (https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc.capnp).
pub mod rpc_capnp {
  include!(concat!(env!("OUT_DIR"), "/rpc_capnp.rs"));
}

/// Code generated from [rpc-twoparty.capnp]
/// (https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc-twoparty.capnp).
pub mod rpc_twoparty_capnp {
  include!(concat!(env!("OUT_DIR"), "/rpc_twoparty_capnp.rs"));
}

mod broken;
mod local;
mod queued;
mod rpc;
pub mod twoparty;

pub trait OutgoingMessage {
    fn get_body<'a>(&'a mut self) -> ::capnp::Result<::capnp::any_pointer::Builder<'a>>;
    fn get_body_as_reader<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;

    /// Sends the message. Returns a promise for the message that resolves once the send has completed.
    /// Dropping the returned promise does *not* cancel the send.
    fn send(self: Box<Self>)
            -> Promise<::capnp::message::Builder<::capnp::message::HeapAllocator>, ::capnp::Error>;

    fn take(self: Box<Self>) -> ::capnp::message::Builder<::capnp::message::HeapAllocator>;
}

pub trait IncomingMessage {
    fn get_body<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;
}

pub trait Connection<VatId> {
    fn get_peer_vat_id(&self) -> VatId;
    fn new_outgoing_message(&mut self, first_segment_word_size: u32) -> Box<OutgoingMessage>;

    /// Waits for a message to be received and returns it.  If the read stream cleanly terminates,
    /// returns None. If any other problem occurs, returns an Error.
    fn receive_incoming_message(&mut self) -> Promise<Option<Box<IncomingMessage>>, Error>;

    // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The
    // returned promise resolves after shutdown is complete.
    fn shutdown(&mut self) -> Promise<(), Error>;
}

pub trait VatNetwork<VatId> {
    /// Returns None if `hostId` refers to the local vat.
    fn connect(&mut self, hostId: VatId) -> Option<Box<Connection<VatId>>>;

    /// Waits for the next incoming connection and return it.
    fn accept(&mut self) -> ::gj::Promise<Box<Connection<VatId>>, ::capnp::Error>;
}

struct SystemTaskReaper;
impl ::gj::TaskReaper<(), Error> for SystemTaskReaper {
    fn task_failed(&mut self, error: Error) {
        println!("ERROR: {}", error);
    }
}

/// A portal to objects available on the network.
///
/// The RPC implemententation sits on top of an implementation of `VatNetwork`, which
/// determines how to form connections between vats. The RPC implementation determines
/// how to use such connections to manage object references and make method calls.
///
/// At the moment, this is all rather more general than it needs to be, because the only
/// implementation of `VatNetwork` is `twoparty::VatNetwork`. However, eventually we
/// will need to have more sophistocated `VatNetwork` implementations, in order to support
/// [level 3](https://capnproto.org/rpc.html#protocol-features) features.
pub struct RpcSystem<VatId> where VatId: 'static {
    network: Box<::VatNetwork<VatId>>,

    bootstrap_cap: Box<ClientHook>,

    // XXX To handle three or more party networks, this should be a map from connection pointers
    // to connection states.
    connection_state: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,

    tasks: Rc<RefCell<::gj::TaskSet<(), Error>>>,
}

impl <VatId> RpcSystem <VatId> {
    /// Constructs a new `RpcSystem` with the given network and bootstrap capability.
    pub fn new(network: Box<::VatNetwork<VatId>>,
               bootstrap: Option<::capnp::capability::Client>) -> RpcSystem<VatId> {
        let bootstrap_cap = match bootstrap {
            Some(cap) => cap.hook,
            None => broken::new_cap(Error::failed("no bootstrap capabiity".to_string())),
        };
        let mut result = RpcSystem {
            network: network,
            bootstrap_cap: bootstrap_cap,
            connection_state: Rc::new(RefCell::new(None)),
            tasks: Rc::new(RefCell::new(::gj::TaskSet::new(Box::new(SystemTaskReaper)))),
        };
        let accept_loop = result.accept_loop();
        result.tasks.borrow_mut().add(accept_loop);
        result
    }

    /// Connects to the given vat and returns its bootstrap interface.
    pub fn bootstrap<T>(&mut self, vat_id: VatId) -> T
        where T: ::capnp::capability::FromClientHook
    {
        let connection = match self.network.connect(vat_id) {
            Some(connection) => connection,
            None => {
                return T::new(self.bootstrap_cap.clone());
            }
        };
        let connection_state =
            RpcSystem::get_connection_state(self.connection_state.clone(),
                                            self.bootstrap_cap.clone(),
                                            connection, self.tasks.clone());

        let hook = rpc::ConnectionState::bootstrap(connection_state.clone());
        T::new(hook)
    }

    fn accept_loop(&mut self) -> Promise<(), Error> {
        let connection_state_ref = self.connection_state.clone();
        let tasks_ref = Rc::downgrade(&self.tasks);
        let bootstrap_cap = self.bootstrap_cap.clone();
        self.network.accept().map(move |connection| {
            RpcSystem::get_connection_state(connection_state_ref,
                                            bootstrap_cap,
                                            connection,
                                            tasks_ref.upgrade().expect("dangling reference to task set"));
            Ok(())
        })
    }

    fn get_connection_state(connection_state_ref: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,
                            bootstrap_cap: Box<ClientHook>,
                            connection: Box<::Connection<VatId>>,
                            tasks: Rc<RefCell<::gj::TaskSet<(), Error>>>)
                            -> Rc<rpc::ConnectionState<VatId>>
    {

        // TODO this needs to be updated once we allow more general VatNetworks.
        let result = match &*connection_state_ref.borrow() {
            &Some(ref connection_state) => {
                // return early.
                return connection_state.clone()
            }
            &None => {
                let (on_disconnect_promise, on_disconnect_fulfiller) = Promise::and_fulfiller();
                let connection_state_ref1 = connection_state_ref.clone();
                tasks.borrow_mut().add(on_disconnect_promise.then(move |shutdown_promise| {
                    *connection_state_ref1.borrow_mut() = None;
                    shutdown_promise
                }));
                rpc::ConnectionState::new(bootstrap_cap, connection, on_disconnect_fulfiller)
            }
        };
        *connection_state_ref.borrow_mut() = Some(result.clone());
        result
    }
}

/// Hook that allows local implementations of interfaces to be passed to the RPC system
/// so that they can be called remotely.
///
/// To use this, you need to do the following dance:
///
/// ```ignore
/// let client = foo:ToClient::new(FooImpl).from_server::<::capnp_rpc::Server>());
/// ```
pub struct Server;

impl ServerHook for Server {
    fn new_client(server: Box<::capnp::capability::Server>) -> ::capnp::capability::Client {
        ::capnp::capability::Client::new(Box::new(local::Client::new(server)))
    }
}

/// Converts a promise for a client into a client that queues up any calls that arrive
/// before the promise resolves.
// TODO: figure out a better way to allow construction of promise clients.
pub fn new_promise_client<T>(client_promise: Promise<::capnp::capability::Client, Error>) -> T
    where T: ::capnp::capability::FromClientHook
{
    T::new(Box::new(queued::Client::new(client_promise.map(|c| Ok(c.hook)))))
}
<commit_msg>fix doc typo<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! An implementation of the [Cap'n Proto remote procedure call](https://capnproto.org/rpc.html)
//! protocol. Includes all [Level 1](https://capnproto.org/rpc.html#protocol-features) features.
//!
//! # Example
//!
//! ```capnp
//! # Cap'n Proto schema
//! interface Foo {
//!     identity @0 (x: UInt32) -> (y: UInt32);
//! }
//! ```
//!
//! ```ignore
//! // Rust server defining an implementation of Foo.
//! struct FooImpl;
//! impl foo::Server for FooImpl {
//!     fn identity(&mut self,
//!                 params: foo::IdentityParams,
//!                 mut results: foo::IdentityResults)
//!                 -> Promise<(), ::capnp::Error>
//!     {
//!         let x = pry!(params.get()).get_x();
//!         results.get().set_y(x);
//!         Promise::ok(())
//!     }
//! }
//! ```
//!
//! ```ignore
//! // Rust client calling a remote implementation of Foo.
//! let mut request = foo_client.identity_request();
//! request.get().set_x(123);
//! let promise = request.send().promise.map(|response| {
//!     println!("results = {}", try!(response.get()).get_y());
//!     Ok(())
//! });
//! ```
//!
//! For a more complete example, see https://github.com/dwrensha/capnp-rpc-rust/tree/master/examples/calculator

extern crate capnp;
#[macro_use] extern crate gj;
extern crate gjio;
extern crate capnp_gj;

use gj::Promise;
use capnp::Error;
use capnp::private::capability::{ClientHook, ServerHook};
use std::cell::RefCell;
use std::rc::Rc;

/// Code generated from [rpc.capnp]
/// (https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc.capnp).
pub mod rpc_capnp {
  include!(concat!(env!("OUT_DIR"), "/rpc_capnp.rs"));
}

/// Code generated from [rpc-twoparty.capnp]
/// (https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/rpc-twoparty.capnp).
pub mod rpc_twoparty_capnp {
  include!(concat!(env!("OUT_DIR"), "/rpc_twoparty_capnp.rs"));
}

mod broken;
mod local;
mod queued;
mod rpc;
pub mod twoparty;

pub trait OutgoingMessage {
    fn get_body<'a>(&'a mut self) -> ::capnp::Result<::capnp::any_pointer::Builder<'a>>;
    fn get_body_as_reader<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;

    /// Sends the message. Returns a promise for the message that resolves once the send has completed.
    /// Dropping the returned promise does *not* cancel the send.
    fn send(self: Box<Self>)
            -> Promise<::capnp::message::Builder<::capnp::message::HeapAllocator>, ::capnp::Error>;

    fn take(self: Box<Self>) -> ::capnp::message::Builder<::capnp::message::HeapAllocator>;
}

pub trait IncomingMessage {
    fn get_body<'a>(&'a self) -> ::capnp::Result<::capnp::any_pointer::Reader<'a>>;
}

pub trait Connection<VatId> {
    fn get_peer_vat_id(&self) -> VatId;
    fn new_outgoing_message(&mut self, first_segment_word_size: u32) -> Box<OutgoingMessage>;

    /// Waits for a message to be received and returns it.  If the read stream cleanly terminates,
    /// returns None. If any other problem occurs, returns an Error.
    fn receive_incoming_message(&mut self) -> Promise<Option<Box<IncomingMessage>>, Error>;

    // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The
    // returned promise resolves after shutdown is complete.
    fn shutdown(&mut self) -> Promise<(), Error>;
}

pub trait VatNetwork<VatId> {
    /// Returns None if `hostId` refers to the local vat.
    fn connect(&mut self, hostId: VatId) -> Option<Box<Connection<VatId>>>;

    /// Waits for the next incoming connection and return it.
    fn accept(&mut self) -> ::gj::Promise<Box<Connection<VatId>>, ::capnp::Error>;
}

struct SystemTaskReaper;
impl ::gj::TaskReaper<(), Error> for SystemTaskReaper {
    fn task_failed(&mut self, error: Error) {
        println!("ERROR: {}", error);
    }
}

/// A portal to objects available on the network.
///
/// The RPC implemententation sits on top of an implementation of `VatNetwork`, which
/// determines how to form connections between vats. The RPC implementation determines
/// how to use such connections to manage object references and make method calls.
///
/// At the moment, this is all rather more general than it needs to be, because the only
/// implementation of `VatNetwork` is `twoparty::VatNetwork`. However, eventually we
/// will need to have more sophistocated `VatNetwork` implementations, in order to support
/// [level 3](https://capnproto.org/rpc.html#protocol-features) features.
pub struct RpcSystem<VatId> where VatId: 'static {
    network: Box<::VatNetwork<VatId>>,

    bootstrap_cap: Box<ClientHook>,

    // XXX To handle three or more party networks, this should be a map from connection pointers
    // to connection states.
    connection_state: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,

    tasks: Rc<RefCell<::gj::TaskSet<(), Error>>>,
}

impl <VatId> RpcSystem <VatId> {
    /// Constructs a new `RpcSystem` with the given network and bootstrap capability.
    pub fn new(network: Box<::VatNetwork<VatId>>,
               bootstrap: Option<::capnp::capability::Client>) -> RpcSystem<VatId> {
        let bootstrap_cap = match bootstrap {
            Some(cap) => cap.hook,
            None => broken::new_cap(Error::failed("no bootstrap capabiity".to_string())),
        };
        let mut result = RpcSystem {
            network: network,
            bootstrap_cap: bootstrap_cap,
            connection_state: Rc::new(RefCell::new(None)),
            tasks: Rc::new(RefCell::new(::gj::TaskSet::new(Box::new(SystemTaskReaper)))),
        };
        let accept_loop = result.accept_loop();
        result.tasks.borrow_mut().add(accept_loop);
        result
    }

    /// Connects to the given vat and returns its bootstrap interface.
    pub fn bootstrap<T>(&mut self, vat_id: VatId) -> T
        where T: ::capnp::capability::FromClientHook
    {
        let connection = match self.network.connect(vat_id) {
            Some(connection) => connection,
            None => {
                return T::new(self.bootstrap_cap.clone());
            }
        };
        let connection_state =
            RpcSystem::get_connection_state(self.connection_state.clone(),
                                            self.bootstrap_cap.clone(),
                                            connection, self.tasks.clone());

        let hook = rpc::ConnectionState::bootstrap(connection_state.clone());
        T::new(hook)
    }

    fn accept_loop(&mut self) -> Promise<(), Error> {
        let connection_state_ref = self.connection_state.clone();
        let tasks_ref = Rc::downgrade(&self.tasks);
        let bootstrap_cap = self.bootstrap_cap.clone();
        self.network.accept().map(move |connection| {
            RpcSystem::get_connection_state(connection_state_ref,
                                            bootstrap_cap,
                                            connection,
                                            tasks_ref.upgrade().expect("dangling reference to task set"));
            Ok(())
        })
    }

    fn get_connection_state(connection_state_ref: Rc<RefCell<Option<Rc<rpc::ConnectionState<VatId>>>>>,
                            bootstrap_cap: Box<ClientHook>,
                            connection: Box<::Connection<VatId>>,
                            tasks: Rc<RefCell<::gj::TaskSet<(), Error>>>)
                            -> Rc<rpc::ConnectionState<VatId>>
    {

        // TODO this needs to be updated once we allow more general VatNetworks.
        let result = match &*connection_state_ref.borrow() {
            &Some(ref connection_state) => {
                // return early.
                return connection_state.clone()
            }
            &None => {
                let (on_disconnect_promise, on_disconnect_fulfiller) = Promise::and_fulfiller();
                let connection_state_ref1 = connection_state_ref.clone();
                tasks.borrow_mut().add(on_disconnect_promise.then(move |shutdown_promise| {
                    *connection_state_ref1.borrow_mut() = None;
                    shutdown_promise
                }));
                rpc::ConnectionState::new(bootstrap_cap, connection, on_disconnect_fulfiller)
            }
        };
        *connection_state_ref.borrow_mut() = Some(result.clone());
        result
    }
}

/// Hook that allows local implementations of interfaces to be passed to the RPC system
/// so that they can be called remotely.
///
/// To use this, you need to do the following dance:
///
/// ```ignore
/// let client = foo::ToClient::new(FooImpl).from_server::<::capnp_rpc::Server>());
/// ```
pub struct Server;

impl ServerHook for Server {
    fn new_client(server: Box<::capnp::capability::Server>) -> ::capnp::capability::Client {
        ::capnp::capability::Client::new(Box::new(local::Client::new(server)))
    }
}

/// Converts a promise for a client into a client that queues up any calls that arrive
/// before the promise resolves.
// TODO: figure out a better way to allow construction of promise clients.
pub fn new_promise_client<T>(client_promise: Promise<::capnp::capability::Client, Error>) -> T
    where T: ::capnp::capability::FromClientHook
{
    T::new(Box::new(queued::Client::new(client_promise.map(|c| Ok(c.hook)))))
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::platform::Context;
use ::paint::{Canvas, Point, Rect};
use std::cmp::Ordering;
use std::slice::{Iter, IterMut};

pub struct AbsoluteLayout {
    children: Vec<Child>,
    bounding_box: BoundingBox,

    baseline: Option<f32>,
    axis: Option<f32>,
}

pub struct Child {
    drawable: Box<Drawable>,
    params: AbsoluteLayoutParams
}

pub struct AbsoluteLayoutParams {
    position: Point
}

impl Drawable for AbsoluteLayout {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        for child in &self.children {
            child.drawable.draw(canvas, &(pen_pos+&child.params.position))
        }
    }

    fn calculate(&mut self, _: &Context, _: f32, _: &MeasureMode, _: f32,
                 _: &MeasureMode) {
        let end_x_calc = |child: &Child|
            child.drawable.bounding_box().width() + child.params.position.x();

        let width = self.children.iter().max_by(|c1, c2| {
            end_x_calc(*c1).partial_cmp(&end_x_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_x_calc(c))
        }).unwrap_or(0f32);

        let end_y_calc = |child: &Child|
            child.drawable.bounding_box().height() + child.params.position.y();

        let height = self.children.iter().max_by(|c1, c2| {
            end_y_calc(*c1).partial_cmp(&end_y_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_y_calc(c))
        }).unwrap_or(0f32);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: self.baseline.unwrap_or(height),
            axis: self.axis.unwrap_or(height/2f32),
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl AbsoluteLayout {
    pub fn new() -> AbsoluteLayout {
        AbsoluteLayout {
            children: Vec::new(),
            bounding_box: BoundingBox::default(),
            baseline: None,
            axis: None,
        }
    }

    pub fn add_child(&mut self, child: Box<Drawable>, params: AbsoluteLayoutParams) {
        self.children.push(Child { drawable: child, params });
    }

    pub fn remove_child_at(&mut self, index: usize) {
        self.children.remove(index);
    }

    pub fn clear(&mut self) {
        self.children.clear();
    }

    pub fn set_baseline(&mut self, baseline: Option<f32>) {
        self.baseline = baseline;
    }

    pub fn set_axis(&mut self, axis: Option<f32>) {
        self.axis = axis;
    }

    pub fn set_child_params(&mut self, index: usize, params: AbsoluteLayoutParams) {
        if let Some(val) = self.children.get_mut(index) {
            val.params = params;
        }
    }

    pub fn iter(&self) -> Iter<Child> {
        self.children.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<Child> {
        self.children.iter_mut()
    }
}<commit_msg>Lifetime parameter for adding drawables with same lifetime as that of element<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::platform::Context;
use ::paint::{Canvas, Point, Rect};
use std::cmp::Ordering;
use std::slice::{Iter, IterMut};

pub struct AbsoluteLayout<'a> {
    children: Vec<Child<'a>>,
    bounding_box: BoundingBox,

    baseline: Option<f32>,
    axis: Option<f32>,
}

pub struct Child<'a> {
    drawable: Box<Drawable+'a>,
    params: AbsoluteLayoutParams
}

pub struct AbsoluteLayoutParams {
    position: Point
}

impl<'a> Drawable for AbsoluteLayout<'a> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        for child in &self.children {
            child.drawable.draw(canvas, &(pen_pos+&child.params.position))
        }
    }

    fn calculate(&mut self, _: &Context, _: f32, _: &MeasureMode, _: f32,
                 _: &MeasureMode) {
        let end_x_calc = |child: &Child|
            child.drawable.bounding_box().width() + child.params.position.x();

        let width = self.children.iter().max_by(|c1, c2| {
            end_x_calc(*c1).partial_cmp(&end_x_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_x_calc(c))
        }).unwrap_or(0f32);

        let end_y_calc = |child: &Child|
            child.drawable.bounding_box().height() + child.params.position.y();

        let height = self.children.iter().max_by(|c1, c2| {
            end_y_calc(*c1).partial_cmp(&end_y_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_y_calc(c))
        }).unwrap_or(0f32);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: self.baseline.unwrap_or(height),
            axis: self.axis.unwrap_or(height/2f32),
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a> AbsoluteLayout<'a> {
    pub fn new() -> AbsoluteLayout<'a> {
        AbsoluteLayout {
            children: Vec::new(),
            bounding_box: BoundingBox::default(),
            baseline: None,
            axis: None,
        }
    }

    pub fn add_child(&mut self, child: Box<Drawable + 'a>, params: AbsoluteLayoutParams) {
        self.children.push(Child { drawable: child, params });
    }

    pub fn remove_child_at(&mut self, index: usize) {
        self.children.remove(index);
    }

    pub fn clear(&mut self) {
        self.children.clear();
    }

    pub fn set_baseline(&mut self, baseline: Option<f32>) {
        self.baseline = baseline;
    }

    pub fn set_axis(&mut self, axis: Option<f32>) {
        self.axis = axis;
    }

    pub fn set_child_params(&mut self, index: usize, params: AbsoluteLayoutParams) {
        if let Some(val) = self.children.get_mut(index) {
            val.params = params;
        }
    }

    pub fn iter(&self) -> Iter<Child<'a>> {
        self.children.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<Child<'a>> {
        self.children.iter_mut()
    }
}<|endoftext|>