<commit_before>//! A trie-structured representation of update tuples with hashable keys.
//!
//! One goal of this representation is to allow multiple kinds of types of hashable keys, including
//! keys that implement `Hash`, keys whose hashes have been computed and are stashed with the key, and
//! integers keys which are promised to be random enough to be used as the hashes themselves.
use std::rc::Rc;
use std::fmt::Debug;
// use std::hash::Hash;
// use std::borrow::Borrow;

use timely_sort::{Unsigned};

// use ::Hashable;
use hashable::HashOrdered;

use trace::layers::{Trie, TupleBuilder};
use trace::layers::Builder as TrieBuilder;
use trace::layers::Cursor as TrieCursor;
use trace::layers::hashed::{HashedLayer, HashedBuilder, HashedCursor};
use trace::layers::unordered::{UnorderedLayer, UnorderedBuilder, UnorderedCursor};

use lattice::Lattice;
use trace::{Batch, Builder, Cursor, Trace};
use trace::consolidate;
use trace::description::Description;
use trace::cursor::cursor_list::CursorList;

type RHHBuilder<Key, Time> = HashedBuilder<Key, UnorderedBuilder<(Time, isize)>>;

/// An append-only collection of update tuples.
///
/// A spine maintains a small number of immutable collections of update tuples, merging the collections when
/// two have similar sizes. In this way, it allows the addition of more tuples, which may then be merged with
/// other immutable collections.
#[derive(Debug)]
pub struct Spine<Key: HashOrdered, Time: Lattice+Ord+Debug> {
	frontier: Vec<Time>,					// Times after which the times in the traces must be distinguishable.
	layers: Vec<Rc<Layer<Key, Time>>>	// Several possibly shared collections of updates.
}

// A trace implementation for any key type that can be borrowed from or converted into `Key`.
// TODO: Almost all this implementation seems to be generic with respect to the trace and layer types.
impl<Key, Time> Trace<Key, (), Time> for Spine<Key, Time>
where
	Key: Clone+Default+HashOrdered+'static,
	Time: Lattice+Ord+Clone+Default+Debug+'static,
{

	type Batch = Rc<Layer<Key, Time>>;
	type Cursor = CursorList<Key, (), Time, LayerCursor<Key, Time>>;

	fn new(default: Time) -> Self {
		Spine {
			frontier: vec![default],
			layers: Vec::new(),
		}
	}
	// Note: this does not perform progressive merging; that code is around somewhere though.
	fn insert(&mut self, layer: Self::Batch) {
		if layer.layer.keys() > 0 {
			// while last two elements exist, both less than layer.len()
			while self.layers.len() >= 2 && self.layers[self.layers.len() - 2].len() < layer.len() {
				let layer1 = self.layers.pop().unwrap();
				let layer2 = self.layers.pop().unwrap();
				let result = Rc::new(Layer::merge(&layer1, &layer2));
				if result.len() > 0 {
					self.layers.push(result);
				}
			}

			if layer.len() > 0 {
				self.layers.push(layer);
			}

		    while self.layers.len() >= 2 && self.layers[self.layers.len() - 2].len() < 2 * self.layers[self.layers.len() - 1].len() {
				let layer1 = self.layers.pop().unwrap();
				let layer2 = self.layers.pop().unwrap();
				let mut result = Rc::new(layer1.merge(&layer2));

				// if we just merged the last layer, `advance_by` it.
				if self.layers.len() == 0 {
					result = Rc::new(Layer::<Key, Time>::advance_by(&result, &self.frontier[..]));
				}

				if result.len() > 0 {
					self.layers.push(result);
				}
			}
		}
	}
	fn cursor(&self) -> Self::Cursor {
		let mut cursors = Vec::new();
		for layer in &self.layers[..] {
			if layer.len() > 0 {
				cursors.push(layer.cursor());
			}
		}

		CursorList::new(cursors)
	}
	fn advance_by(&mut self, frontier: &[Time]) {
		self.frontier = frontier.to_vec();
	}
}

/// An immutable collection of update tuples, from a contiguous interval of logical times.
#[derive(Debug)]
pub struct Layer<Key: HashOrdered, Time: Lattice+Ord+Debug> {
	/// Where all the dataz is.
	pub layer: HashedLayer<Key, UnorderedLayer<(Time, isize)>>,
	/// Description of the update times this layer represents.
	pub desc: Description<Time>,
}

impl<Key: Clone+Default+HashOrdered, Time: Lattice+Ord+Clone+Default+Debug> Batch<Key, (), Time> for Rc<Layer<Key, Time>> {
	type Builder = LayerBuilder<Key, Time>;
	type OrderedBuilder = OrdBuilder<Key, Time>;
	type Cursor = LayerCursor<Key, Time>;
	fn cursor(&self) -> Self::Cursor {
		LayerCursor { empty: (), valid: true, cursor: self.layer.cursor() }
	}
	fn len(&self) -> usize { self.layer.tuples() }
}

impl<Key: Clone+Default+HashOrdered, Time: Lattice+Ord+Clone+Default+Debug> Layer<Key, Time> {

	/// Conducts a full merge, right away. Times not advanced.
	pub fn merge(&self, other: &Self) -> Self {
		Layer {
			layer: self.layer.merge(&other.layer),
			desc: Description::new(&[], &[], &[]),
		}
	}
	/// Advances times in `layer` and consolidates differences for like times.
	///
	/// TODO: This method could be defined on `&mut self`, exploiting in-place mutation
	/// to avoid allocation and building headaches. It is implemented on the `Rc` variant
	/// to get access to `cursor()`, and in principle to allow a progressive implementation.
	pub fn advance_by(layer: &Rc<Self>, frontier: &[Time]) -> Self {

		// TODO: This is almost certainly too much `with_capacity`.
		// TODO: We should design and implement an "in-orded builder", which takes cues from key and val
		// structure, rather than having to infer them from tuples.
		// TODO: We should understand whether in-place mutation is appropriate, or too gross. At the moment,
		// this could be a general method defined on any implementor of `trace::Cursor`.
		let mut builder = <RHHBuilder<Key, Time> as TupleBuilder>::with_capacity(layer.len());

		if layer.len() > 0 {
			let mut times = Vec::new();
			let mut cursor = layer.cursor();

			while cursor.key_valid() {
				if cursor.val_valid() {
					cursor.map_times(|time: &Time, diff| times.push((time.advance_by(frontier).unwrap(), diff)));
					consolidate(&mut times, 0);
					for (time, diff) in times.drain(..) {
						let key_ref: &Key = cursor.key();
						let key_clone: Key = key_ref.clone();
						builder.push_tuple((key_clone, (time, diff)));
					}
				}
				cursor.step_key();
			}
		}

		Layer {
			layer: builder.done(),
			desc: Description::new(layer.desc.lower(), layer.desc.upper(), frontier),
		}
	}
}

/// A cursor for navigating a single layer.
#[derive(Debug)]
pub struct LayerCursor<Key: Clone+HashOrdered, Time: Lattice+Ord+Clone+Debug> {
	valid: bool,
	empty: (),
	cursor: HashedCursor<Key, UnorderedCursor<(Time, isize)>>,
}

impl<Key: Clone+HashOrdered, Time: Lattice+Ord+Clone+Debug> Cursor<Key, (), Time> for LayerCursor<Key, Time> {
	fn key(&self) -> &Key { &self.cursor.key() }
	fn val(&self) -> &() { &self.empty }
	fn map_times<L: FnMut(&Time, isize)>(&mut self, mut logic: L) {
		self.cursor.child.rewind();
		while self.cursor.child.valid() {
			logic(&self.cursor.child.key().0, self.cursor.child.key().1);
			self.cursor.child.step();
		}
	}
	fn key_valid(&self) -> bool { self.cursor.valid() }
	fn val_valid(&self) -> bool { self.valid }
	fn step_key(&mut self){ self.cursor.step(); self.valid = true; }
	fn seek_key(&mut self, key: &Key) { self.cursor.seek(key); self.valid = true; }
	fn step_val(&mut self) { self.valid = false; }
	fn seek_val(&mut self, _val: &()) { }
	fn rewind_keys(&mut self) { self.cursor.rewind(); self.valid = true; }
	fn rewind_vals(&mut self) { self.valid = true; }
}

/// A builder for creating layers from unsorted update tuples.
pub struct LayerBuilder<K: HashOrdered, T: Ord+Debug> {
	time: T,
	// TODO : Have this build `Layer`s and merge, instead of re-sorting sorted data.
    // buffer: Vec<((K, T), isize)>,
    buffer: Vec<(K, isize)>,
    buffers: Vec<Vec<(K, isize)>>,
}

impl<Key, Time> Builder<Key, (), Time, Rc<Layer<Key, Time>>> for LayerBuilder<Key, Time>
where Key: Clone+Default+HashOrdered, Time: Lattice+Ord+Clone+Default+Debug {

	fn new() -> Self { LayerBuilder { time: Default::default(), buffer: Vec::new(), buffers: Vec::new() } }
	fn push(&mut self, (key, _, time, diff): (Key, (), Time, isize)) {
		self.time = time;
		self.buffer.push((key, diff));
		if self.buffers.len() == 1 << 12 {
			self.buffers.push(::std::mem::replace(&mut self.buffer, Vec::with_capacity(1 << 12)));
		}
	}

	#[inline(never)]
	fn done(mut self, lower: &[Time], upper: &[Time]) -> Rc<Layer<Key, Time>> {

		let mut count = self.buffer.len();
		for buffer in &self.buffers {
			count += buffer.len();
		}

		let mut builder = <RHHBuilder<Key, Time> as TupleBuilder>::with_capacity(count);

        // sort things, radix if many, `sort` if few.
        if self.buffers.len() > 0 {
        	if self.buffer.len() > 0 {
				self.buffers.push(::std::mem::replace(&mut self.buffer, Vec::new()));
        	}

        	let mut sorter = ::timely_sort::LSBRadixSorter::new();
        	sorter.sort(&mut self.buffers, &|x| x.0.hashed());

        	let mut current_hash = 0;
        	for (key, diff) in self.buffers.drain(..).flat_map(|batch| batch.into_iter()) {
        		if key.hashed().as_u64() != current_hash {
        			current_hash = key.hashed().as_u64();
					consolidate(&mut self.buffer, 0);
					for (key,diff) in self.buffer.drain(..) {
						builder.push_tuple((key, (self.time.clone(), diff)));
					}
        		}
        		self.buffer.push((key,diff));
        	}
			consolidate(&mut self.buffer, 0);
			for (key,diff) in self.buffer.drain(..) {
				builder.push_tuple((key, (self.time.clone(), diff)));
			}
        }
        else {
        	consolidate(&mut self.buffer, 0);
			for (key,diff) in self.buffer.drain(..) {
				builder.push_tuple((key, (self.time.clone(), diff)));
			}
        }

        // TODO : We should be able to build a `Layer` directly here, without the weird indirection of `push_tuple`.
        // We can compute the number of keys, (key,val)s, allocate exact amounts, and then drop everything in place.
        // This is not unethical, because we have full knowledge of the collection trace structure here.
		let layer = builder.done();

		println!("{:?}\tcount: {:?} -> {:?}", self.time, count, layer.tuples());

		Rc::new(Layer {
			layer: layer,
			desc: Description::new(lower, upper, lower)
		})
	}
}

/// A builder for creating layers from unsorted update tuples.
pub struct OrdBuilder<Key: HashOrdered, Time: Ord+Debug> {
	builder: RHHBuilder<Key, Time>,
}

impl<Key, Time> Builder<Key, (), Time, Rc<Layer<Key, Time>>> for OrdBuilder<Key, Time>
where Key: Clone+Default+HashOrdered, Time: Lattice+Ord+Clone+Default+Debug {

	fn new() -> Self { OrdBuilder { builder: RHHBuilder::new() } }
	fn push(&mut self, (key, _, time, diff): (Key, (), Time, isize)) {
		self.builder.push_tuple((key, (time, diff)));
	}

	#[inline(never)]
	fn done(self, lower: &[Time], upper: &[Time]) -> Rc<Layer<Key, Time>> {
		Rc::new(Layer {
			layer: self.builder.done(),
			desc: Description::new(lower, upper, lower)
		})
	}
}<commit_msg>removing println<commit_after>//! A trie-structured representation of update tuples with hashable keys.
//!
//! One goal of this representation is to allow multiple kinds of types of hashable keys, including
//! keys that implement `Hash`, keys whose hashes have been computed and are stashed with the key, and
//! integers keys which are promised to be random enough to be used as the hashes themselves.
use std::rc::Rc;
use std::fmt::Debug;
// use std::hash::Hash;
// use std::borrow::Borrow;

use timely_sort::{Unsigned};

// use ::Hashable;
use hashable::HashOrdered;

use trace::layers::{Trie, TupleBuilder};
use trace::layers::Builder as TrieBuilder;
use trace::layers::Cursor as TrieCursor;
use trace::layers::hashed::{HashedLayer, HashedBuilder, HashedCursor};
use trace::layers::unordered::{UnorderedLayer, UnorderedBuilder, UnorderedCursor};

use lattice::Lattice;
use trace::{Batch, Builder, Cursor, Trace};
use trace::consolidate;
use trace::description::Description;
use trace::cursor::cursor_list::CursorList;

type RHHBuilder<Key, Time> = HashedBuilder<Key, UnorderedBuilder<(Time, isize)>>;

/// An append-only collection of update tuples.
///
/// A spine maintains a small number of immutable collections of update tuples, merging the collections when
/// two have similar sizes. In this way, it allows the addition of more tuples, which may then be merged with
/// other immutable collections.
#[derive(Debug)]
pub struct Spine<Key: HashOrdered, Time: Lattice+Ord+Debug> {
	frontier: Vec<Time>,					// Times after which the times in the traces must be distinguishable.
	layers: Vec<Rc<Layer<Key, Time>>>	// Several possibly shared collections of updates.
}

// A trace implementation for any key type that can be borrowed from or converted into `Key`.
// TODO: Almost all this implementation seems to be generic with respect to the trace and layer types.
impl<Key, Time> Trace<Key, (), Time> for Spine<Key, Time>
where
	Key: Clone+Default+HashOrdered+'static,
	Time: Lattice+Ord+Clone+Default+Debug+'static,
{

	type Batch = Rc<Layer<Key, Time>>;
	type Cursor = CursorList<Key, (), Time, LayerCursor<Key, Time>>;

	fn new(default: Time) -> Self {
		Spine {
			frontier: vec![default],
			layers: Vec::new(),
		}
	}
	// Note: this does not perform progressive merging; that code is around somewhere though.
	fn insert(&mut self, layer: Self::Batch) {
		if layer.layer.keys() > 0 {
			// while last two elements exist, both less than layer.len()
			while self.layers.len() >= 2 && self.layers[self.layers.len() - 2].len() < layer.len() {
				let layer1 = self.layers.pop().unwrap();
				let layer2 = self.layers.pop().unwrap();
				let result = Rc::new(Layer::merge(&layer1, &layer2));
				if result.len() > 0 {
					self.layers.push(result);
				}
			}

			if layer.len() > 0 {
				self.layers.push(layer);
			}

		    while self.layers.len() >= 2 && self.layers[self.layers.len() - 2].len() < 2 * self.layers[self.layers.len() - 1].len() {
				let layer1 = self.layers.pop().unwrap();
				let layer2 = self.layers.pop().unwrap();
				let mut result = Rc::new(layer1.merge(&layer2));

				// if we just merged the last layer, `advance_by` it.
				if self.layers.len() == 0 {
					result = Rc::new(Layer::<Key, Time>::advance_by(&result, &self.frontier[..]));
				}

				if result.len() > 0 {
					self.layers.push(result);
				}
			}
		}
	}
	fn cursor(&self) -> Self::Cursor {
		let mut cursors = Vec::new();
		for layer in &self.layers[..] {
			if layer.len() > 0 {
				cursors.push(layer.cursor());
			}
		}

		CursorList::new(cursors)
	}
	fn advance_by(&mut self, frontier: &[Time]) {
		self.frontier = frontier.to_vec();
	}
}

/// An immutable collection of update tuples, from a contiguous interval of logical times.
#[derive(Debug)]
pub struct Layer<Key: HashOrdered, Time: Lattice+Ord+Debug> {
	/// Where all the dataz is.
	pub layer: HashedLayer<Key, UnorderedLayer<(Time, isize)>>,
	/// Description of the update times this layer represents.
	pub desc: Description<Time>,
}

impl<Key: Clone+Default+HashOrdered, Time: Lattice+Ord+Clone+Default+Debug> Batch<Key, (), Time> for Rc<Layer<Key, Time>> {
	type Builder = LayerBuilder<Key, Time>;
	type OrderedBuilder = OrdBuilder<Key, Time>;
	type Cursor = LayerCursor<Key, Time>;
	fn cursor(&self) -> Self::Cursor {
		LayerCursor { empty: (), valid: true, cursor: self.layer.cursor() }
	}
	fn len(&self) -> usize { self.layer.tuples() }
}

impl<Key: Clone+Default+HashOrdered, Time: Lattice+Ord+Clone+Default+Debug> Layer<Key, Time> {

	/// Conducts a full merge, right away. Times not advanced.
	pub fn merge(&self, other: &Self) -> Self {
		Layer {
			layer: self.layer.merge(&other.layer),
			desc: Description::new(&[], &[], &[]),
		}
	}
	/// Advances times in `layer` and consolidates differences for like times.
	///
	/// TODO: This method could be defined on `&mut self`, exploiting in-place mutation
	/// to avoid allocation and building headaches. It is implemented on the `Rc` variant
	/// to get access to `cursor()`, and in principle to allow a progressive implementation.
	pub fn advance_by(layer: &Rc<Self>, frontier: &[Time]) -> Self {

		// TODO: This is almost certainly too much `with_capacity`.
		// TODO: We should design and implement an "in-orded builder", which takes cues from key and val
		// structure, rather than having to infer them from tuples.
		// TODO: We should understand whether in-place mutation is appropriate, or too gross. At the moment,
		// this could be a general method defined on any implementor of `trace::Cursor`.
		let mut builder = <RHHBuilder<Key, Time> as TupleBuilder>::with_capacity(layer.len());

		if layer.len() > 0 {
			let mut times = Vec::new();
			let mut cursor = layer.cursor();

			while cursor.key_valid() {
				if cursor.val_valid() {
					cursor.map_times(|time: &Time, diff| times.push((time.advance_by(frontier).unwrap(), diff)));
					consolidate(&mut times, 0);
					for (time, diff) in times.drain(..) {
						let key_ref: &Key = cursor.key();
						let key_clone: Key = key_ref.clone();
						builder.push_tuple((key_clone, (time, diff)));
					}
				}
				cursor.step_key();
			}
		}

		Layer {
			layer: builder.done(),
			desc: Description::new(layer.desc.lower(), layer.desc.upper(), frontier),
		}
	}
}

/// A cursor for navigating a single layer.
#[derive(Debug)]
pub struct LayerCursor<Key: Clone+HashOrdered, Time: Lattice+Ord+Clone+Debug> {
	valid: bool,
	empty: (),
	cursor: HashedCursor<Key, UnorderedCursor<(Time, isize)>>,
}

impl<Key: Clone+HashOrdered, Time: Lattice+Ord+Clone+Debug> Cursor<Key, (), Time> for LayerCursor<Key, Time> {
	fn key(&self) -> &Key { &self.cursor.key() }
	fn val(&self) -> &() { &self.empty }
	fn map_times<L: FnMut(&Time, isize)>(&mut self, mut logic: L) {
		self.cursor.child.rewind();
		while self.cursor.child.valid() {
			logic(&self.cursor.child.key().0, self.cursor.child.key().1);
			self.cursor.child.step();
		}
	}
	fn key_valid(&self) -> bool { self.cursor.valid() }
	fn val_valid(&self) -> bool { self.valid }
	fn step_key(&mut self){ self.cursor.step(); self.valid = true; }
	fn seek_key(&mut self, key: &Key) { self.cursor.seek(key); self.valid = true; }
	fn step_val(&mut self) { self.valid = false; }
	fn seek_val(&mut self, _val: &()) { }
	fn rewind_keys(&mut self) { self.cursor.rewind(); self.valid = true; }
	fn rewind_vals(&mut self) { self.valid = true; }
}

/// A builder for creating layers from unsorted update tuples.
pub struct LayerBuilder<K: HashOrdered, T: Ord+Debug> {
	time: T,
	// TODO : Have this build `Layer`s and merge, instead of re-sorting sorted data.
    // buffer: Vec<((K, T), isize)>,
    buffer: Vec<(K, isize)>,
    buffers: Vec<Vec<(K, isize)>>,
}

impl<Key, Time> Builder<Key, (), Time, Rc<Layer<Key, Time>>> for LayerBuilder<Key, Time>
where Key: Clone+Default+HashOrdered, Time: Lattice+Ord+Clone+Default+Debug {

	fn new() -> Self { LayerBuilder { time: Default::default(), buffer: Vec::new(), buffers: Vec::new() } }
	fn push(&mut self, (key, _, time, diff): (Key, (), Time, isize)) {
		self.time = time;
		self.buffer.push((key, diff));
		if self.buffers.len() == 1 << 12 {
			self.buffers.push(::std::mem::replace(&mut self.buffer, Vec::with_capacity(1 << 12)));
		}
	}

	#[inline(never)]
	fn done(mut self, lower: &[Time], upper: &[Time]) -> Rc<Layer<Key, Time>> {

		let mut count = self.buffer.len();
		for buffer in &self.buffers {
			count += buffer.len();
		}

		let mut builder = <RHHBuilder<Key, Time> as TupleBuilder>::with_capacity(count);

        // sort things, radix if many, `sort` if few.
        if self.buffers.len() > 0 {
        	if self.buffer.len() > 0 {
				self.buffers.push(::std::mem::replace(&mut self.buffer, Vec::new()));
        	}

        	let mut sorter = ::timely_sort::LSBRadixSorter::new();
        	sorter.sort(&mut self.buffers, &|x| x.0.hashed());

        	let mut current_hash = 0;
        	for (key, diff) in self.buffers.drain(..).flat_map(|batch| batch.into_iter()) {
        		if key.hashed().as_u64() != current_hash {
        			current_hash = key.hashed().as_u64();
					consolidate(&mut self.buffer, 0);
					for (key,diff) in self.buffer.drain(..) {
						builder.push_tuple((key, (self.time.clone(), diff)));
					}
        		}
        		self.buffer.push((key,diff));
        	}
			consolidate(&mut self.buffer, 0);
			for (key,diff) in self.buffer.drain(..) {
				builder.push_tuple((key, (self.time.clone(), diff)));
			}
        }
        else {
        	consolidate(&mut self.buffer, 0);
			for (key,diff) in self.buffer.drain(..) {
				builder.push_tuple((key, (self.time.clone(), diff)));
			}
        }

        // TODO : We should be able to build a `Layer` directly here, without the weird indirection of `push_tuple`.
        // We can compute the number of keys, (key,val)s, allocate exact amounts, and then drop everything in place.
        // This is not unethical, because we have full knowledge of the collection trace structure here.
		let layer = builder.done();

		// println!("{:?}\tcount: {:?} -> {:?}", self.time, count, layer.tuples());

		Rc::new(Layer {
			layer: layer,
			desc: Description::new(lower, upper, lower)
		})
	}
}

/// A builder for creating layers from unsorted update tuples.
pub struct OrdBuilder<Key: HashOrdered, Time: Ord+Debug> {
	builder: RHHBuilder<Key, Time>,
}

impl<Key, Time> Builder<Key, (), Time, Rc<Layer<Key, Time>>> for OrdBuilder<Key, Time>
where Key: Clone+Default+HashOrdered, Time: Lattice+Ord+Clone+Default+Debug {

	fn new() -> Self { OrdBuilder { builder: RHHBuilder::new() } }
	fn push(&mut self, (key, _, time, diff): (Key, (), Time, isize)) {
		self.builder.push_tuple((key, (time, diff)));
	}

	#[inline(never)]
	fn done(self, lower: &[Time], upper: &[Time]) -> Rc<Layer<Key, Time>> {
		Rc::new(Layer {
			layer: self.builder.done(),
			desc: Description::new(lower, upper, lower)
		})
	}
}<|endoftext|>


<commit_before>fn add_cxxbridge(module: &str) {
    cxx_build::bridge(format!("src/{}.rs", module))
        .flag("-std=c++11")
        .compile(&format!("libnewsboat-ffi-{}", module));
    println!("cargo:rerun-if-changed=src/{}.rs", module);
}

fn main() {
    add_cxxbridge("fslock");
    add_cxxbridge("keymap");
    add_cxxbridge("scopemeasure");
    add_cxxbridge("utils");
}
<commit_msg>Ignore warnings in bindings<commit_after>fn add_cxxbridge(module: &str) {
    cxx_build::bridge(format!("src/{}.rs", module))
        .flag("-std=c++11")
        // Disable warnings in generated code, since we can't affect them directly. We have to do
        // this because these warnings are turned into errors when we pass `-D warnings` to Cargo
        // on CI.
        .flag("-w")
        .compile(&format!("libnewsboat-ffi-{}", module));
    println!("cargo:rerun-if-changed=src/{}.rs", module);
}

fn main() {
    add_cxxbridge("fslock");
    add_cxxbridge("keymap");
    add_cxxbridge("scopemeasure");
    add_cxxbridge("utils");
}
<|endoftext|>


<commit_before>use crate::text::{Attributes, Text};
use crate::widgets::{Widget, WidgetStream};
use alsa::mixer::{SelemChannelId, SelemId};
use alsa::{self, Mixer, PollDescriptors};
use anyhow::{anyhow, Result};
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::unix::AsyncFd;
use tokio_stream::{Stream, StreamExt};

/// Shows the current volume of the default ALSA output.
///
/// This widget shows the current volume of the default ALSA output, or '`M`' if
/// the output is muted.
///
/// The widget uses `alsa-lib` to receive events when the volume changes,
/// avoiding expensive polling. If you do not have `alsa-lib` installed, you
/// can disable the `volume-widget` feature on the `cnx` crate to avoid
/// compiling this widget.
pub struct Volume {
    attr: Attributes,
}

impl Volume {
    /// Creates a new Volume widget.
    ///
    /// Creates a new `Volume` widget, whose text will be displayed
    /// with the given [`Attributes`].
    ///
    /// The [`Cnx`] instance is borrowed during construction in order to get
    /// access to handles of its event loop. However, it is not borrowed for the
    /// lifetime of the widget. See the [`cnx_add_widget!()`] for more discussion
    /// about the lifetime of the borrow.
    ///
    /// [`Attributes`]: ../text/struct.Attributes.html
    /// [`Cnx`]: ../struct.Cnx.html
    /// [`cnx_add_widget!()`]: ../macro.cnx_add_widget.html
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use]
    /// # extern crate cnx;
    /// #
    /// # use cnx::*;
    /// # use cnx::text::*;
    /// # use cnx::widgets::*;
    /// # use anyhow::Result;
    /// #
    /// # fn run() -> Result<()> {
    /// let attr = Attributes {
    ///     font: Font::new("SourceCodePro 21"),
    ///     fg_color: Color::white(),
    ///     bg_color: None,
    ///     padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    /// };
    ///
    /// let mut cnx = Cnx::new(Position::Top);
    /// cnx.add_widget(volume::Volume::new(attr.clone()));
    /// # Ok(())
    /// # }
    /// # fn main() { run().unwrap(); }
    /// ```
    pub fn new(attr: Attributes) -> Volume {
        Volume { attr }
    }
}

// https://github.com/mjkillough/cnx/blob/92c24238be541c75d88181208862505739be33fd/src/widgets/volume.rs

impl Widget for Volume {
    fn into_stream(self: Box<Self>) -> Result<WidgetStream> {
        let mixer_name = "default";
        // We don't attempt to use the same mixer to listen for events and to
        // recompute the mixer state (in the callback below) as the Mixer seems
        // to cache the state from when it was created. It's relatively cheap
        // create a new mixer each time we get an event though.
        let mixer = Mixer::new(mixer_name, true)?;
        // .with_context(|_| format!("Failed to open ALSA mixer: {}", mixer_name))?;
        let stream = AlsaEventStream::new(mixer).expect(
            "AlsaEventStream issue"
        ).map(move |()| {
            // FrontLeft has special meaning in ALSA and is the channel
            // that's used when the mixer is mono.
            let channel = SelemChannelId::FrontLeft;

            let mixer = Mixer::new(mixer_name, true)?;
            let master = mixer.find_selem(&SelemId::new("Master", 0))
             .ok_or_else(|| anyhow!("Couldn't open Master channel"))?;

            let mute = master.get_playback_switch(channel)? == 0;

            let text = if !mute {
                let volume = master.get_playback_volume(channel)?;
                let (min, max) = master.get_playback_volume_range();
                let percentage = (volume as f64 / (max as f64 - min as f64)) * 100.0;
                format!("[🔈 {:.0}%]", percentage)
            } else {
                "🔇".to_owned()
            };

            Ok(vec![Text {
                attr: self.attr.clone(),
                text,
                stretch: false,
                markup: true,
            }])
        });

        Ok(Box::pin(stream))
    }
}

struct AlsaEvented(Mixer);

impl AlsaEvented {
    fn mixer(&self) -> &Mixer {
        &self.0
    }

    fn fds(&self) -> Vec<RawFd> {
        self.0
            .get()
            .expect("volume: no fds available")
            .iter()
            .map(|pollfd| pollfd.fd)
            .collect()
    }
}

// impl event::Source for AlsaEvented {
//     fn register(
//         &mut self,
//         registry: &Registry,
//         token: Token,
//         interests: Interest,
//     ) -> io::Result<()> {
//         for fd in &self.fds() {
//             SourceFd(fd).register(registry, token, interests)?
//         }
//         Ok(())
//     }

//     fn reregister(
//         &mut self,
//         registry: &Registry,
//         token: Token,
//         interests: Interest,
//     ) -> io::Result<()> {
//         for fd in &self.fds() {
//             SourceFd(fd).reregister(registry, token, interests);
//         }
//         Ok(())
//     }

//     fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
//         // XXX If the set of fds changes (it won't), should we deregister the
//         // original set?
//         for fd in &self.fds() {
//             SourceFd(fd).deregister(registry);
//         }
//         Ok(())
//     }
// }

struct AlsaEventStream {
    poll: AsyncFd<AlsaEvented>,
    initial: bool,
}

impl AsRawFd for AlsaEvented {
    fn as_raw_fd(&self) -> RawFd {
        self.fds()
            .into_iter()
            .next()
            .expect("volume: as_raw_fd empty")
    }
}

// I'm porting one of the crates tokio 0.2 series. Since PollEvented is removed, I'm using AsyncFd for most of them and it works well. But in one of the cases - I have to watch a bucn

impl AlsaEventStream {
    fn new(mixer: Mixer) -> Result<AlsaEventStream> {
        Ok(AlsaEventStream {
            poll: AsyncFd::new(AlsaEvented(mixer))?,
            // The first few calls to poll() need to process any existing events.
            // We don't know what state the fds are in when we give them to tokio
            // and it's edge-triggered.
            initial: true,
        })
    }
}

impl Stream for AlsaEventStream {
    // We don't bother yielding the events and just yield unit each time we get
    // an event. This stream is used only to get woken up when the ALSA state
    // changes - the caller is expected to requery all necessary state when
    // it receives a new item from the stream.
    type Item = ();

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
        // Always assume we're ready initially, so that we can clear the
        // state of the fds.

        // Do a poll with a timeout of 0 to figure out exactly which fds were
        // woken up, followed by a call to revents() which clears the pending
        // events. We don't actually care what the events are - we're just
        // using it as a wake-up so we can check the volume again.
        if self.initial {
            let mixer = self.poll.get_ref().mixer();
            let _poll_result = alsa::poll::poll_all(&[mixer], 0);
            self.initial = false;
            return Poll::Ready(Some(()));
        }
        // All events have been consumed - tell Tokio we're interested in waiting
        // for more again.
        match self.poll.poll_read_ready(cx) {
            Poll::Ready(Ok(mut r)) => {
                let mixer = self.poll.get_ref().mixer();
                let _poll_result = alsa::poll::poll_all(&[mixer], 0);
                let _result = mixer.handle_events();
                r.clear_ready();
                Poll::Ready(Some(()))
            }
            Poll::Ready(Err(_)) => Poll::Ready(Some(())),
            Poll::Pending => Poll::Pending,
        }
    }
}
<commit_msg>Better error handling<commit_after>use crate::text::{Attributes, Text};
use crate::widgets::{Widget, WidgetStream};
use alsa::mixer::{SelemChannelId, SelemId};
use alsa::{self, Mixer, PollDescriptors};
use anyhow::{anyhow, Context, Result};
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::pin::Pin;
use std::task::Poll;
use tokio::io::unix::AsyncFd;
use tokio_stream::{Stream, StreamExt};

/// Shows the current volume of the default ALSA output.
///
/// This widget shows the current volume of the default ALSA output, or '`M`' if
/// the output is muted.
///
/// The widget uses `alsa-lib` to receive events when the volume changes,
/// avoiding expensive polling. If you do not have `alsa-lib` installed, you
/// can disable the `volume-widget` feature on the `cnx` crate to avoid
/// compiling this widget.
pub struct Volume {
    attr: Attributes,
}

impl Volume {
    /// Creates a new Volume widget.
    ///
    /// Creates a new `Volume` widget, whose text will be displayed
    /// with the given [`Attributes`].
    ///
    /// The [`Cnx`] instance is borrowed during construction in order to get
    /// access to handles of its event loop. However, it is not borrowed for the
    /// lifetime of the widget. See the [`cnx_add_widget!()`] for more discussion
    /// about the lifetime of the borrow.
    ///
    /// [`Attributes`]: ../text/struct.Attributes.html
    /// [`Cnx`]: ../struct.Cnx.html
    /// [`cnx_add_widget!()`]: ../macro.cnx_add_widget.html
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use]
    /// # extern crate cnx;
    /// #
    /// # use cnx::*;
    /// # use cnx::text::*;
    /// # use cnx::widgets::*;
    /// # use anyhow::Result;
    /// #
    /// # fn run() -> Result<()> {
    /// let attr = Attributes {
    ///     font: Font::new("SourceCodePro 21"),
    ///     fg_color: Color::white(),
    ///     bg_color: None,
    ///     padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    /// };
    ///
    /// let mut cnx = Cnx::new(Position::Top);
    /// cnx.add_widget(volume::Volume::new(attr.clone()));
    /// # Ok(())
    /// # }
    /// # fn main() { run().unwrap(); }
    /// ```
    pub fn new(attr: Attributes) -> Volume {
        Volume { attr }
    }
}

// https://github.com/mjkillough/cnx/blob/92c24238be541c75d88181208862505739be33fd/src/widgets/volume.rs

impl Widget for Volume {
    fn into_stream(self: Box<Self>) -> Result<WidgetStream> {
        let mixer_name = "default";
        // We don't attempt to use the same mixer to listen for events and to
        // recompute the mixer state (in the callback below) as the Mixer seems
        // to cache the state from when it was created. It's relatively cheap
        // create a new mixer each time we get an event though.
        let mixer = Mixer::new(mixer_name, true)
            .with_context(|| format!("Failed to open ALSA mixer: {}", mixer_name))?;
        let stream = AlsaEventStream::new(mixer)?.map(move |()| {
            // FrontLeft has special meaning in ALSA and is the channel
            // that's used when the mixer is mono.
            let channel = SelemChannelId::FrontLeft;

            let mixer = Mixer::new(mixer_name, true)?;
            let master = mixer.find_selem(&SelemId::new("Master", 0))
             .ok_or_else(|| anyhow!("Couldn't open Master channel"))?;

            let mute = master.get_playback_switch(channel)? == 0;

            let text = if !mute {
                let volume = master.get_playback_volume(channel)?;
                let (min, max) = master.get_playback_volume_range();
                let percentage = (volume as f64 / (max as f64 - min as f64)) * 100.0;
                format!("[🔈 {:.0}%]", percentage)
            } else {
                "🔇".to_owned()
            };

            Ok(vec![Text {
                attr: self.attr.clone(),
                text,
                stretch: false,
                markup: true,
            }])
        });

        Ok(Box::pin(stream))
    }
}

struct AlsaEvented(Mixer);

impl AlsaEvented {
    fn mixer(&self) -> &Mixer {
        &self.0
    }

    fn fds(&self) -> Vec<RawFd> {
        self.0.get().map_or(vec![], |vec_poll| {
            vec_poll.iter().map(|pollfd| pollfd.fd).collect()
        })
    }
}

struct AlsaEventStream {
    poll: AsyncFd<AlsaEvented>,
    initial: bool,
}

impl AsRawFd for AlsaEvented {
    fn as_raw_fd(&self) -> RawFd {
        self.fds()
            .into_iter()
            .next()
            .expect("volume: as_raw_fd empty")
    }
}

impl AlsaEventStream {
    fn new(mixer: Mixer) -> Result<AlsaEventStream> {
        Ok(AlsaEventStream {
            poll: AsyncFd::new(AlsaEvented(mixer))?,
            // The first few calls to poll() need to process any existing events.
            // We don't know what state the fds are in when we give them to tokio
            // and it's edge-triggered.
            initial: true,
        })
    }
}

impl Stream for AlsaEventStream {
    // We don't bother yielding the events and just yield unit each time we get
    // an event. This stream is used only to get woken up when the ALSA state
    // changes - the caller is expected to requery all necessary state when
    // it receives a new item from the stream.
    type Item = ();

    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut std::task::Context,
    ) -> Poll<Option<Self::Item>> {
        // Always assume we're ready initially, so that we can clear the
        // state of the fds.

        // Do a poll with a timeout of 0 to figure out exactly which fds were
        // woken up, followed by a call to revents() which clears the pending
        // events. We don't actually care what the events are - we're just
        // using it as a wake-up so we can check the volume again.
        if self.initial {
            let mixer = self.poll.get_ref().mixer();
            let _poll_result = alsa::poll::poll_all(&[mixer], 0);
            self.initial = false;
            return Poll::Ready(Some(()));
        }
        // All events have been consumed - tell Tokio we're interested in waiting
        // for more again.
        match self.poll.poll_read_ready(cx) {
            Poll::Ready(Ok(mut r)) => {
                let mixer = self.poll.get_ref().mixer();
                let _poll_result = alsa::poll::poll_all(&[mixer], 0);
                let _result = mixer.handle_events();
                r.clear_ready();
                Poll::Ready(Some(()))
            }
            Poll::Ready(Err(_)) => Poll::Ready(Some(())),
            Poll::Pending => Poll::Pending,
        }
    }
}
<|endoftext|>


<commit_before>use crate::io::util::read_line::read_line_internal;
use crate::io::AsyncBufRead;

use pin_project_lite::pin_project;
use std::io;
use std::mem;
use std::pin::Pin;
use std::task::{Context, Poll};

pin_project! {
    /// Stream for the [`lines`](crate::io::AsyncBufReadExt::lines) method.
    #[derive(Debug)]
    #[must_use = "streams do nothing unless polled"]
    #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
    pub struct Lines<R> {
        #[pin]
        reader: R,
        buf: String,
        bytes: Vec<u8>,
        read: usize,
    }
}

pub(crate) fn lines<R>(reader: R) -> Lines<R>
where
    R: AsyncBufRead,
{
    Lines {
        reader,
        buf: String::new(),
        bytes: Vec::new(),
        read: 0,
    }
}

impl<R> Lines<R>
where
    R: AsyncBufRead + Unpin,
{
    /// Returns the next line in the stream.
    ///
    /// # Examples
    ///
    /// ```
    /// # use tokio::io::AsyncBufRead;
    /// use tokio::io::AsyncBufReadExt;
    ///
    /// # async fn dox(my_buf_read: impl AsyncBufRead + Unpin) -> std::io::Result<()> {
    /// let mut lines = my_buf_read.lines();
    ///
    /// while let Some(line) = lines.next_line().await? {
    ///     println!("length = {}", line.len())
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub async fn next_line(&mut self) -> io::Result<Option<String>> {
        use crate::future::poll_fn;

        poll_fn(|cx| Pin::new(&mut *self).poll_next_line(cx)).await
    }
}

impl<R> Lines<R>
where
    R: AsyncBufRead,
{
    #[doc(hidden)]
    pub fn poll_next_line(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<io::Result<Option<String>>> {
        let me = self.project();

        let n = ready!(read_line_internal(me.reader, cx, me.buf, me.bytes, me.read))?;

        if n == 0 && me.buf.is_empty() {
            return Poll::Ready(Ok(None));
        }

        if me.buf.ends_with('\n') {
            me.buf.pop();

            if me.buf.ends_with('\r') {
                me.buf.pop();
            }
        }

        Poll::Ready(Ok(Some(mem::replace(me.buf, String::new()))))
    }
}

#[cfg(feature = "stream")]
impl<R: AsyncBufRead> crate::stream::Stream for Lines<R> {
    type Item = io::Result<String>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        Poll::Ready(match ready!(self.poll_next_line(cx)) {
            Ok(Some(line)) => Some(Ok(line)),
            Ok(None) => None,
            Err(err) => Some(Err(err)),
        })
    }
}

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

    #[test]
    fn assert_unpin() {
        crate::is_unpin::<Lines<()>>();
    }
}
<commit_msg>io: add get_mut, get_ref and into_inner to Lines (#2450)<commit_after>use crate::io::util::read_line::read_line_internal;
use crate::io::AsyncBufRead;

use pin_project_lite::pin_project;
use std::io;
use std::mem;
use std::pin::Pin;
use std::task::{Context, Poll};

pin_project! {
    /// Stream for the [`lines`](crate::io::AsyncBufReadExt::lines) method.
    #[derive(Debug)]
    #[must_use = "streams do nothing unless polled"]
    #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
    pub struct Lines<R> {
        #[pin]
        reader: R,
        buf: String,
        bytes: Vec<u8>,
        read: usize,
    }
}

pub(crate) fn lines<R>(reader: R) -> Lines<R>
where
    R: AsyncBufRead,
{
    Lines {
        reader,
        buf: String::new(),
        bytes: Vec::new(),
        read: 0,
    }
}

impl<R> Lines<R>
where
    R: AsyncBufRead + Unpin,
{
    /// Returns the next line in the stream.
    ///
    /// # Examples
    ///
    /// ```
    /// # use tokio::io::AsyncBufRead;
    /// use tokio::io::AsyncBufReadExt;
    ///
    /// # async fn dox(my_buf_read: impl AsyncBufRead + Unpin) -> std::io::Result<()> {
    /// let mut lines = my_buf_read.lines();
    ///
    /// while let Some(line) = lines.next_line().await? {
    ///     println!("length = {}", line.len())
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub async fn next_line(&mut self) -> io::Result<Option<String>> {
        use crate::future::poll_fn;

        poll_fn(|cx| Pin::new(&mut *self).poll_next_line(cx)).await
    }

    /// Obtain a mutable reference to the underlying reader
    pub fn get_mut(&mut self) -> &mut R {
        &mut self.reader
    }

    /// Obtain a reference to the underlying reader
    pub fn get_ref(&mut self) -> &R {
        &self.reader
    }

    /// Unwraps this `Lines<R>`, returning the underlying reader.
    ///
    /// Note that any leftover data in the internal buffer is lost.
    /// Therefore, a following read from the underlying reader may lead to data loss.
    pub fn into_inner(self) -> R {
        self.reader
    }
}

impl<R> Lines<R>
where
    R: AsyncBufRead,
{
    #[doc(hidden)]
    pub fn poll_next_line(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<io::Result<Option<String>>> {
        let me = self.project();

        let n = ready!(read_line_internal(me.reader, cx, me.buf, me.bytes, me.read))?;

        if n == 0 && me.buf.is_empty() {
            return Poll::Ready(Ok(None));
        }

        if me.buf.ends_with('\n') {
            me.buf.pop();

            if me.buf.ends_with('\r') {
                me.buf.pop();
            }
        }

        Poll::Ready(Ok(Some(mem::replace(me.buf, String::new()))))
    }
}

#[cfg(feature = "stream")]
impl<R: AsyncBufRead> crate::stream::Stream for Lines<R> {
    type Item = io::Result<String>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        Poll::Ready(match ready!(self.poll_next_line(cx)) {
            Ok(Some(line)) => Some(Ok(line)),
            Ok(None) => None,
            Err(err) => Some(Err(err)),
        })
    }
}

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

    #[test]
    fn assert_unpin() {
        crate::is_unpin::<Lines<()>>();
    }
}
<|endoftext|>


<commit_before>//mod signal_wrappers;

use std::io;
use std::fs::File;
use std::io::Write;
use std::collections::HashMap;
use api_parser::*;
use c_api_gen::get_type_name;
use c_api_gen::generate_c_function_args;
use c_api_gen::is_struct_pod;
use c_api_gen::callback_fun_def_name;

use heck::SnakeCase;
use heck::MixedCase;

fn generate_bind_info(info: &mut HashMap<String, Function>, func: &Function) {
    if !func.callback {
        return;
    }

    let mut input_args = String::new();

    for arg in &func.function_args {
        let tname = get_type_name(&arg);

        input_args.push_str(&tname);
        input_args.push_str(", ");
    }

    input_args.push_str("void*"); // user_data

    if info.contains_key(&input_args) {
        return;
    }

    info.insert(input_args.clone(), func.clone());
}

// generates signal wrappers for the variatos depending on input parameters
pub fn build_signal_wrappers_info(info: &mut HashMap<String, Function>, api_def: &ApiDef) {
    for sdef in &api_def.entries {
        for entry in &sdef.entries {
            match *entry {
                StructEntry::Function(ref func) => generate_bind_info(info, func),
                _ => (),
            }
        }
    }
}

fn signal_type_callback(func: &Function) -> String {
    let mut name_def = "Signal_".to_owned();

    for arg in &func.function_args {
        name_def.push_str(&arg.vtype);
        name_def.push_str("_")
    }

    name_def.push_str("void");
    name_def
}

// Generate a signal wrapper that is in the style of this:
//
//    class QSlotWrapperNoArgs : public QObject {
//        Q_OBJECT
//    public:
//        QSlotWrapperNoArgs(void* data, SignalNoArgs func) {
//            m_func = func;
//            m_data = data;
//        }
//
//        Q_SLOT void method() {
//            m_func(m_data);
//        }
//
//    private:
//        SignalNoArgs m_func;
//        void* m_data;
//    };
//
pub fn generate_signal_wrappers(f: &mut File, info: &HashMap<String, Function>) -> io::Result<()> {
    for (_, func) in info {
        let signal_type_name = signal_type_callback(func);

        f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;

        f.write_fmt(format_args!("typedef void (*{})({});\n\n",
                                    signal_type_name,
                                    generate_c_function_args(func)))?;

        f.write_fmt(format_args!("class QSlotWrapper{} : public QObject {{\n    Q_OBJECT\npublic:\n", signal_type_name))?;
        f.write_fmt(format_args!("    QSlotWrapper{}(void* data, {} func) {{\n",
                                    signal_type_name,
                                    signal_type_name))?;
        f.write_all(b"        m_func = func;\n")?;
        f.write_all(b"        m_data = data;\n")?;
        f.write_all(b"    }\n\n")?;

        f.write_all(b"    Q_SLOT void method(")?;

        let args_count = func.function_args.len();

        if args_count > 0 {
            let mut input_args = String::new();

            for i in 0..args_count - 1 {
                let arg = &func.function_args[i];
                f.write_fmt(format_args!("{} {},", arg.vtype, arg.name))?;
                input_args.push_str(&arg.name);
                input_args.push_str(", ");
            }

            f.write_fmt(format_args!("{} {}) {{\n",
                                        get_type_name(&func.function_args[args_count - 1]),
                                        func.function_args[args_count - 1].name))?;
            input_args.push_str(&func.function_args[args_count - 1].name);

            f.write_fmt(format_args!("        m_func({}, m_data);\n", input_args))?;
        } else {
            f.write_all(b") {\n")?;
            f.write_all(b"        m_func(m_data);\n")?;
        }

        f.write_all(b"    }\n")?;

        f.write_all(b"private:\n")?;
        f.write_fmt(format_args!("    {} m_func;\n", signal_type_name))?;
        f.write_all(b"    void* m_data;\n")?;
        f.write_all(b"};\n\n")?;

    }

    Ok(())

}

fn function_name(struct_name: &str, func: &Function) -> String {
    format!("{}_{}", struct_name.to_snake_case(), func.name)
}

fn generate_func_def(f: &mut File,
                     struct_name: &str,
                     func: &Function,
                     struct_name_map: &HashMap<&str, &str>)
                     -> io::Result<()> {
    let ret_value;

    if let Some(ref ret_val) = func.return_val {
        ret_value = get_type_name(&ret_val);
    } else {
        ret_value = "void".to_owned();
    }

    // write return value and function name
    f.write_fmt(format_args!("static {} {}({}) {{ \n",
                                ret_value,
                                function_name(struct_name, func),
                                generate_c_function_args(func)))?;

    let struct_qt_name = struct_name_map
        .get(struct_name)
        .unwrap_or_else(|| &struct_name);

    // (changed from snake_case to camelCase matches the Qt function)

    // QWidget* qt_data = (QWidget*)priv_data;
    f.write_fmt(format_args!("    Q{}* qt_data = (Q{}*)priv_data;\n",
                                struct_qt_name,
                                struct_qt_name))?;

    // TODO: Handle return functions

    // qt_data->func(params);
    f.write_fmt(format_args!("    qt_data->{}(", func.name.to_mixed_case()))?;

    let args_count = func.function_args.len();

    if args_count > 0 {
        for i in 0..args_count - 1 {
            let arg = &func.function_args[i];
            // TODO: This is a hack for strings for now
            if arg.vtype == "String" {
                f.write_fmt(format_args!("QString::fromLatin1({}), ", &arg.name))?;
            } else {
                f.write_fmt(format_args!("{}, ", &arg.name))?;
            }
        }

        let arg = &func.function_args[args_count - 1];
        if arg.vtype == "String" {
            f.write_fmt(format_args!("QString::fromLatin1({})", &arg.name))?;
        } else {
            f.write_fmt(format_args!("{}", &arg.name))?;
        }
    }

    f.write_all(b");\n")?;
    f.write_all(b"}\n\n")?;

    Ok(())
}

///
///
///
///

fn func_def_callback(f: &mut File, struct_name: &str, func: &Function) -> io::Result<()> {
    let signal_type_name = signal_type_callback(func);
    let func_name = function_name(struct_name, func);

    println!("struct_name {}", struct_name);

    f.write_fmt(format_args!("static {} {{\n", callback_fun_def_name(false, &func_name, func)))?;

    //QSlotWrapperNoArgs* wrap = new QSlotWrapperNoArgs(reciver, (SignalNoArgs)callback);
    f.write_fmt(format_args!("    QSlotWrapper{}* wrap = new QSlotWrapper{}(user_data, ({})callback);\n", signal_type_name, signal_type_name, signal_type_name))?;
    f.write_all(b"    QObject* q_obj = (QObject*)object;\n")?;

    f.write_fmt(format_args!("    QObject::connect(q_obj, SIGNAL({}(",
                                func.name.to_mixed_case()))?;

    func.write_c_func_def(f, |_, arg| (get_type_name(arg), "".to_owned()))?;

    f.write_all(b"), wrap, SLOT(method(")?;

    func.write_c_func_def(f, |_, arg| (get_type_name(arg), "".to_owned()))?;

    f.write_all(b"));\n")?;
    f.write_all(b"}\n\n")?;

    Ok(())
}

///
///
///
///
fn generate_struct_body_recursive(f: &mut File,
                                  name: &str,
                                  sdef: &Struct,
                                  struct_name_map: &HashMap<&str, &str>,
                                  api_def: &ApiDef)
                                  -> io::Result<()> {
    if let Some(ref inherit_name) = sdef.inherit {
        for sdef in &api_def.entries {
            if &sdef.name == inherit_name {
                generate_struct_body_recursive(f, name, &sdef, struct_name_map, api_def)?;
            }
        }
    }

    for entry in &sdef.entries {
        match *entry {
            StructEntry::Function(ref func) => {
                f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;

                if func.callback == false {
                    generate_func_def(f, name, func, struct_name_map)?;
                } else {
                    func_def_callback(f, name, func)?;
                }
            }

            _ => (),
        }
    }

    Ok(())
}

///
/// Generate includes from all the structs which are non-pod
///
fn generate_includes(f: &mut File,
                     struct_name_map: &HashMap<&str, &str>,
                     api_def: &ApiDef)
                     -> io::Result<()> {
    for sdef in &api_def.entries {
        let struct_name = sdef.name.as_str();

        if is_struct_pod(sdef) {
            continue;
        }

        let struct_qt_name = struct_name_map
            .get(struct_name)
            .unwrap_or_else(|| &struct_name);
        f.write_fmt(format_args!("#include <Q{}>\n", struct_qt_name))?;
    }

    Ok(())
}

///
/// Generate the struct defs
///
fn generate_struct_defs(f: &mut File, struct_name: &str, api_def: &ApiDef, sdef: &Struct) -> io::Result<()> {
    if let Some(ref inherit_name) = sdef.inherit {
        for sdef in &api_def.entries {
            if &sdef.name == inherit_name {
                generate_struct_defs(f, struct_name, api_def, &sdef)?;
            }
        }
    }

    for entry in &sdef.entries {
        match *entry {
            StructEntry::Function(ref func) => {
                if func.callback {
                    f.write_fmt(format_args!("    connect_{},\n", function_name(struct_name, func)))?;
                } else {
                    f.write_fmt(format_args!("    {},\n", function_name(struct_name, func)))?;
                }
            }

            _ => (),
        }
    }

    Ok(())
}
///
/// This is the main entry for generating the C/C++ buindings for Qt. The current API mimics Qt
/// fairly closely when it comes to names but at the start there is a map setup that used used
/// to translate between some struct names to fit the Qt version. If more structs gets added that
/// needs to be translated into another Qt name they needs to be added here as well
///
pub fn generate_qt_bindings(filename: &str, api_def: &ApiDef) -> io::Result<()> {
    let mut f = File::create(filename)?;
    let mut signals_info = HashMap::new();

    let mut struct_name_map = HashMap::new();

    struct_name_map.insert("Button", "AbstractButton");

    f.write_all(b"#include \"c_api.h\"\n")?;

    generate_includes(&mut f, &struct_name_map, api_def)?;
    build_signal_wrappers_info(&mut signals_info, api_def);
    generate_signal_wrappers(&mut f, &signals_info)?;

    // generate wrapper functions

    for sdef in &api_def.entries {
        generate_struct_body_recursive(&mut f, &sdef.name, &sdef, &struct_name_map, api_def)?;
    }

    // generate the structs

    for sdef in &api_def.entries {
        if is_struct_pod(sdef) {
            continue;
        }

        f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;
        f.write_fmt(format_args!("static struct PU{} s_{} = {{\n", sdef.name, sdef.name.to_snake_case()))?;

        generate_struct_defs(&mut f, &sdef.name, api_def, sdef)?;

        f.write_all(b"    0,\n")?;
        f.write_all(b"};\n\n")?;
    }

    Ok(())
}
<commit_msg>Minor cleanup<commit_after>//mod signal_wrappers;

use std::io;
use std::fs::File;
use std::io::Write;
use std::collections::HashMap;
use api_parser::*;
use c_api_gen::get_type_name;
use c_api_gen::generate_c_function_args;
use c_api_gen::is_struct_pod;
use c_api_gen::callback_fun_def_name;

use heck::SnakeCase;
use heck::MixedCase;

fn generate_bind_info(info: &mut HashMap<String, Function>, func: &Function) {
    if !func.callback {
        return;
    }

    let mut input_args = String::new();

    for arg in &func.function_args {
        let tname = get_type_name(&arg);

        input_args.push_str(&tname);
        input_args.push_str(", ");
    }

    input_args.push_str("void*"); // user_data

    if info.contains_key(&input_args) {
        return;
    }

    info.insert(input_args.clone(), func.clone());
}

// generates signal wrappers for the variatos depending on input parameters
pub fn build_signal_wrappers_info(info: &mut HashMap<String, Function>, api_def: &ApiDef) {
    for sdef in &api_def.entries {
        for entry in &sdef.entries {
            match *entry {
                StructEntry::Function(ref func) => generate_bind_info(info, func),
                _ => (),
            }
        }
    }
}

fn signal_type_callback(func: &Function) -> String {
    let mut name_def = "Signal_".to_owned();

    for arg in &func.function_args {
        name_def.push_str(&arg.vtype);
        name_def.push_str("_")
    }

    name_def.push_str("void");
    name_def
}

// Generate a signal wrapper that is in the style of this:
//
//    class QSlotWrapperNoArgs : public QObject {
//        Q_OBJECT
//    public:
//        QSlotWrapperNoArgs(void* data, SignalNoArgs func) {
//            m_func = func;
//            m_data = data;
//        }
//
//        Q_SLOT void method() {
//            m_func(m_data);
//        }
//
//    private:
//        SignalNoArgs m_func;
//        void* m_data;
//    };
//
pub fn generate_signal_wrappers(f: &mut File, info: &HashMap<String, Function>) -> io::Result<()> {
    for (_, func) in info {
        let signal_type_name = signal_type_callback(func);

        f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;

        f.write_fmt(format_args!("typedef void (*{})({});\n\n",
                                    signal_type_name,
                                    generate_c_function_args(func)))?;

        f.write_fmt(format_args!("class QSlotWrapper{} : public QObject {{\n    Q_OBJECT\npublic:\n", signal_type_name))?;
        f.write_fmt(format_args!("    QSlotWrapper{}(void* data, {} func) {{\n",
                                    signal_type_name,
                                    signal_type_name))?;
        f.write_all(b"        m_func = func;\n")?;
        f.write_all(b"        m_data = data;\n")?;
        f.write_all(b"    }\n\n")?;

        f.write_all(b"    Q_SLOT void method(")?;

        let args_count = func.function_args.len();

        if args_count > 0 {
            let mut input_args = String::new();

            for i in 0..args_count - 1 {
                let arg = &func.function_args[i];
                f.write_fmt(format_args!("{} {},", arg.vtype, arg.name))?;
                input_args.push_str(&arg.name);
                input_args.push_str(", ");
            }

            f.write_fmt(format_args!("{} {}) {{\n",
                                        get_type_name(&func.function_args[args_count - 1]),
                                        func.function_args[args_count - 1].name))?;
            input_args.push_str(&func.function_args[args_count - 1].name);

            f.write_fmt(format_args!("        m_func({}, m_data);\n", input_args))?;
        } else {
            f.write_all(b") {\n")?;
            f.write_all(b"        m_func(m_data);\n")?;
        }

        f.write_all(b"    }\n")?;

        f.write_all(b"private:\n")?;
        f.write_fmt(format_args!("    {} m_func;\n", signal_type_name))?;
        f.write_all(b"    void* m_data;\n")?;
        f.write_all(b"};\n\n")?;

    }

    Ok(())

}

fn function_name(struct_name: &str, func: &Function) -> String {
    format!("{}_{}", struct_name.to_snake_case(), func.name)
}

fn generate_func_def(f: &mut File,
                     struct_name: &str,
                     func: &Function,
                     struct_name_map: &HashMap<&str, &str>)
                     -> io::Result<()> {
    let ret_value;

    if let Some(ref ret_val) = func.return_val {
        ret_value = get_type_name(&ret_val);
    } else {
        ret_value = "void".to_owned();
    }

    // write return value and function name
    f.write_fmt(format_args!("static {} {}({}) {{ \n",
                                ret_value,
                                function_name(struct_name, func),
                                generate_c_function_args(func)))?;

    let struct_qt_name = struct_name_map
        .get(struct_name)
        .unwrap_or_else(|| &struct_name);

    // (changed from snake_case to camelCase matches the Qt function)

    // QWidget* qt_data = (QWidget*)priv_data;
    f.write_fmt(format_args!("    Q{}* qt_data = (Q{}*)priv_data;\n",
                                struct_qt_name,
                                struct_qt_name))?;

    // TODO: Handle return functions

    // qt_data->func(params);
    f.write_fmt(format_args!("    qt_data->{}(", func.name.to_mixed_case()))?;

    let args_count = func.function_args.len();

    if args_count > 0 {
        for i in 0..args_count - 1 {
            let arg = &func.function_args[i];
            // TODO: This is a hack for strings for now
            if arg.vtype == "String" {
                f.write_fmt(format_args!("QString::fromLatin1({}), ", &arg.name))?;
            } else {
                f.write_fmt(format_args!("{}, ", &arg.name))?;
            }
        }

        let arg = &func.function_args[args_count - 1];
        if arg.vtype == "String" {
            f.write_fmt(format_args!("QString::fromLatin1({})", &arg.name))?;
        } else {
            f.write_fmt(format_args!("{}", &arg.name))?;
        }
    }

    f.write_all(b");\n")?;
    f.write_all(b"}\n\n")?;

    Ok(())
}

///
///
///
///

fn func_def_callback(f: &mut File, struct_name: &str, func: &Function) -> io::Result<()> {
    let signal_type_name = signal_type_callback(func);
    let func_name = function_name(struct_name, func);

    println!("struct_name {}", struct_name);

    f.write_fmt(format_args!("static {} {{\n", callback_fun_def_name(false, &func_name, func)))?;

    //QSlotWrapperNoArgs* wrap = new QSlotWrapperNoArgs(reciver, (SignalNoArgs)callback);
    f.write_fmt(format_args!("    QSlotWrapper{}* wrap = new QSlotWrapper{}(user_data, ({})callback);\n", signal_type_name, signal_type_name, signal_type_name))?;
    f.write_all(b"    QObject* q_obj = (QObject*)object;\n")?;

    f.write_fmt(format_args!("    QObject::connect(q_obj, SIGNAL({}(",
                                func.name.to_mixed_case()))?;

    func.write_c_func_def(f, |_, arg| (get_type_name(arg), "".to_owned()))?;

    f.write_all(b"), wrap, SLOT(method(")?;

    func.write_c_func_def(f, |_, arg| (get_type_name(arg), "".to_owned()))?;

    f.write_all(b"));\n")?;
    f.write_all(b"}\n\n")?;

    Ok(())
}

///
///
///
///
fn generate_struct_body_recursive(f: &mut File,
                                  name: &str,
                                  sdef: &Struct,
                                  struct_name_map: &HashMap<&str, &str>,
                                  api_def: &ApiDef)
                                  -> io::Result<()> {
    if let Some(ref inherit_name) = sdef.inherit {
        for sdef in &api_def.entries {
            if &sdef.name == inherit_name {
                generate_struct_body_recursive(f, name, &sdef, struct_name_map, api_def)?;
            }
        }
    }

    for entry in &sdef.entries {
        match *entry {
            StructEntry::Function(ref func) => {
                f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;

                if func.callback == false {
                    generate_func_def(f, name, func, struct_name_map)?;
                } else {
                    func_def_callback(f, name, func)?;
                }
            }

            _ => (),
        }
    }

    Ok(())
}

///
/// Generate includes from all the structs which are non-pod
///
fn generate_includes(f: &mut File,
                     struct_name_map: &HashMap<&str, &str>,
                     api_def: &ApiDef)
                     -> io::Result<()> {
    for sdef in &api_def.entries {
        let struct_name = sdef.name.as_str();

        if is_struct_pod(sdef) {
            continue;
        }

        let struct_qt_name = struct_name_map
            .get(struct_name)
            .unwrap_or_else(|| &struct_name);
        f.write_fmt(format_args!("#include <Q{}>\n", struct_qt_name))?;
    }

    Ok(())
}

///
/// Generate the struct defs
///
fn generate_struct_def(f: &mut File, struct_name: &str, api_def: &ApiDef, sdef: &Struct) -> io::Result<()> {
    if let Some(ref inherit_name) = sdef.inherit {
        for sdef in &api_def.entries {
            if &sdef.name == inherit_name {
                generate_struct_def(f, struct_name, api_def, &sdef)?;
            }
        }
    }

    for entry in &sdef.entries {
        match *entry {
            StructEntry::Function(ref func) => {
                if func.callback {
                    f.write_fmt(format_args!("    connect_{},\n", function_name(struct_name, func)))?;
                } else {
                    f.write_fmt(format_args!("    {},\n", function_name(struct_name, func)))?;
                }
            }

            _ => (),
        }
    }

    Ok(())
}

///
///
///
///
///
fn generate_struct_defs(f: &mut File, api_def: &ApiDef) -> io::Result<()> {
    for sdef in &api_def.entries {
        if is_struct_pod(sdef) {
            continue;
        }

        f.write_all(b"///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n")?;
        f.write_fmt(format_args!("static struct PU{} s_{} = {{\n", sdef.name, sdef.name.to_snake_case()))?;

        generate_struct_def(f, &sdef.name, api_def, sdef)?;

        f.write_all(b"    0,\n")?;
        f.write_all(b"};\n\n")?;
    }

    Ok(())
}

///
/// This is the main entry for generating the C/C++ buindings for Qt. The current API mimics Qt
/// fairly closely when it comes to names but at the start there is a map setup that used used
/// to translate between some struct names to fit the Qt version. If more structs gets added that
/// needs to be translated into another Qt name they needs to be added here as well
///

pub fn generate_qt_bindings(filename: &str, api_def: &ApiDef) -> io::Result<()> {
    let mut f = File::create(filename)?;
    let mut signals_info = HashMap::new();

    let mut struct_name_map = HashMap::new();

    struct_name_map.insert("Button", "AbstractButton");

    f.write_all(b"#include \"c_api.h\"\n")?;

    generate_includes(&mut f, &struct_name_map, api_def)?;
    build_signal_wrappers_info(&mut signals_info, api_def);
    generate_signal_wrappers(&mut f, &signals_info)?;

    // generate wrapper functions

    for sdef in &api_def.entries {
        generate_struct_body_recursive(&mut f, &sdef.name, &sdef, &struct_name_map, api_def)?;
    }

    generate_struct_defs(&mut f, api_def)?;

    Ok(())
}
<|endoftext|>


<commit_before>/// low level wrapper for the state machine, encoding and decoding from lapin-async
use lapin_async::connection::*;
use lapin_async::format::frame::*;

use nom::{IResult,Offset};
use cookie_factory::GenError;
use bytes::BytesMut;
use std::iter::repeat;
use std::io::{self,Error,ErrorKind};
use std::time::Duration;
use futures::{Async,Poll,Sink,Stream,StartSend,Future};
use tokio_io::{AsyncRead,AsyncWrite};
use tokio_io::codec::{Decoder,Encoder,Framed};
use tokio_timer::{Interval,Timer};
use client::ConnectionOptions;

/// implements tokio-io's Decoder and Encoder
pub struct AMQPCodec;

impl Decoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Frame>, io::Error> {
        let (consumed, f) = match frame(buf) {
          IResult::Incomplete(_) => {
            return Ok(None)
          },
          IResult::Error(e) => {
            return Err(io::Error::new(io::ErrorKind::Other, format!("parse error: {:?}", e)))
          },
          IResult::Done(i, frame) => {
            (buf.offset(i), frame)
          }
        };

        trace!("decoded frame: {:?}", f);

        buf.split_to(consumed);

        Ok(Some(f))
    }
}

impl Encoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn encode(&mut self, frame: Frame, buf: &mut BytesMut) -> Result<(), Self::Error> {
      let length = buf.len();
      if length < 8192 {
        //reserve more capacity and intialize it
        buf.extend(repeat(0).take(8192 - length));
      }
      trace!("will send frame: {:?}", frame);

      loop {
        let gen_res = match &frame {
          &Frame::ProtocolHeader => {
            gen_protocol_header((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Heartbeat(_) => {
            gen_heartbeat_frame((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Method(channel, ref method) => {
            gen_method_frame((buf, 0), channel, method).map(|tup| tup.1)
          },
          &Frame::Header(channel_id, class_id, ref header) => {
            gen_content_header_frame((buf, 0), channel_id, class_id, header.body_size, &header.properties).map(|tup| tup.1)
          },
          &Frame::Body(channel_id, ref data) => {
            gen_content_body_frame((buf, 0), channel_id, data).map(|tup| tup.1)
          }
        };

        match gen_res {
          Ok(sz) => {
            buf.truncate(sz);
            trace!("serialized frame: {} bytes", sz);
            return Ok(());
          },
          Err(e) => {
            error!("error generating frame: {:?}", e);
            match e {
              GenError::BufferTooSmall(sz) => {
                buf.extend(repeat(0).take(sz - length));
                //return Err(Error::new(ErrorKind::InvalidData, "send buffer too small"));
              },
              GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
                return Err(Error::new(ErrorKind::InvalidData, "could not generate"));
              }
            }
          }
        }
      }
    }
}

/// Wrappers over a `Framed` stream using `AMQPCodec` and lapin-async's `Connection`
pub struct AMQPTransport<T> {
  pub upstream: Framed<T,AMQPCodec>,
  pub heartbeat: Interval,
  pub conn: Connection,
}

impl<T> AMQPTransport<T>
   where T: AsyncRead+AsyncWrite,
         T: 'static               {

  /// starts the connection process
  ///
  /// returns a future of a `AMQPTransport` that is connected
  pub fn connect(upstream: Framed<T,AMQPCodec>, options: &ConnectionOptions) -> Box<Future<Item = AMQPTransport<T>, Error = io::Error>> {
    let mut conn = Connection::new();
    conn.set_credentials(&options.username, &options.password);
    conn.set_vhost(&options.vhost);
    conn.set_heartbeat(options.heartbeat);
    conn.connect();

    let mut t = AMQPTransport {
      upstream:  upstream,
      heartbeat: Timer::default().interval(Duration::from_secs(conn.configuration.heartbeat as u64)),
      conn:      conn,
    };

    let f = t.conn.next_frame().unwrap();
    t.upstream.start_send(f);
    t.upstream.poll_complete();
    t.poll_children();

    let mut connector = AMQPTransportConnector {
      transport: Some(t)
    };

    trace!("pre-poll");
    connector.poll();
    trace!("post-poll");

    Box::new(connector)
  }

  pub fn poll_children(&mut self) {
    self.upstream.poll();
    self.heartbeat.poll();
  }

  pub fn send_and_handle_frames(&mut self) {
    self.send_frames();
    self.handle_frames();
  }

  pub fn send_frames(&mut self) {
    //FIXME: find a way to use a future here
    while let Some(f) = self.conn.next_frame() {
      self.upstream.start_send(f);
      self.upstream.poll_complete();
    }
    //self.upstream.poll_complete();
  }

  pub fn handle_frames(&mut self) {
    loop {
      match self.poll() {
        Ok(Async::Ready(Some(frame))) => {
          trace!("handle frames: AMQPTransport received frame: {:?}", frame);
          self.conn.handle_frame(frame);
        },
        Ok(Async::Ready(None)) => {
          trace!("handle frames: upstream poll gave Ready(None)");
          break;
        },
        Ok(Async::NotReady) => {
          trace!("handle frames: upstream poll gave NotReady");
          self.poll_children();
          break;
        },
        Err(e) => {
          error!("handle frames: upstream poll got error: {:?}", e);
          break;
        },
      };
    }
  }
}

/// implements a future of `AMQPTransport`
///
/// this structure is used to perform the AMQP handshake and provide
/// a connected transport afterwards
pub struct AMQPTransportConnector<T> {
  pub transport: Option<AMQPTransport<T>>,
}

impl<T> Future for AMQPTransportConnector<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {

  type Item  = AMQPTransport<T>;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    debug!("AMQPTransportConnector poll transport is none? {}", self.transport.is_none());
    let mut transport = self.transport.take().unwrap();

    //we might have received a frame before here
    while let Some(f) = transport.conn.next_frame() {
      transport.upstream.start_send(f);
      transport.upstream.poll_complete();
    }

    debug!("conn state: {:?}", transport.conn.state);
    if transport.conn.state == ConnectionState::Connected {
      debug!("already connected");
      return Ok(Async::Ready(transport))
    }

    trace!("waiting before poll");
    transport.heartbeat.poll();
    let value = match transport.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        trace!("upstream poll gave NotReady");
        transport.poll_children();
        self.transport = Some(transport);
        return Ok(Async::NotReady);
      },
      Err(e) => {
        error!("upstream poll got error: {:?}", e);
        return Err(From::from(e));
      },
    };

    match value {
      Some(frame) => {
        trace!("got frame: {:?}", frame);
        transport.conn.handle_frame(frame);
        while let Some(f) = transport.conn.next_frame() {
          transport.upstream.start_send(f);
          transport.upstream.poll_complete();
        }
        transport.upstream.poll_complete();
        if transport.conn.state == ConnectionState::Connected {
          return Ok(Async::Ready(transport))
        } else {
          transport.poll_children();
          self.transport = Some(transport);
          return Ok(Async::NotReady)
        }
      },
      e => {
        error!("did not get a frame? -> {:?}", e);
        self.transport = Some(transport);
        return Ok(Async::NotReady)
      }
    }
  }
}

impl<T> Stream for AMQPTransport<T>
    where T: AsyncRead + AsyncWrite {
    type Item = Frame;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Frame>, io::Error> {
        if let Ok(Async::Ready(_)) = self.heartbeat.poll() {
            debug!("Heartbeat");
            self.start_send(Frame::Heartbeat(0));
            self.poll_complete();
        }

        trace!("stream poll");
        // and Async::NotReady.
        match try_ready!(self.upstream.poll()) {
            Some(frame) => {
              debug!("AMQPTransport received frame: {:?}", frame);
              //try!(self.poll_complete());
              return Ok(Async::Ready(Some(frame)))
            },
            None => {
              trace!("AMQPTransport returned NotReady");
              return Ok(Async::NotReady)
            }
        }
    }
}

impl<T> Sink for AMQPTransport<T>
    where T: AsyncWrite {
    type SinkItem = Frame;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Frame) -> StartSend<Frame, io::Error> {
        trace!("sink start send");
        self.upstream.start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        trace!("sink poll_complete");
        self.upstream.poll_complete()
    }
}

<commit_msg>futures: make more use of send_frames and send_and_handle_frames<commit_after>/// low level wrapper for the state machine, encoding and decoding from lapin-async
use lapin_async::connection::*;
use lapin_async::format::frame::*;

use nom::{IResult,Offset};
use cookie_factory::GenError;
use bytes::BytesMut;
use std::iter::repeat;
use std::io::{self,Error,ErrorKind};
use std::time::Duration;
use futures::{Async,Poll,Sink,Stream,StartSend,Future};
use tokio_io::{AsyncRead,AsyncWrite};
use tokio_io::codec::{Decoder,Encoder,Framed};
use tokio_timer::{Interval,Timer};
use client::ConnectionOptions;

/// implements tokio-io's Decoder and Encoder
pub struct AMQPCodec;

impl Decoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Frame>, io::Error> {
        let (consumed, f) = match frame(buf) {
          IResult::Incomplete(_) => {
            return Ok(None)
          },
          IResult::Error(e) => {
            return Err(io::Error::new(io::ErrorKind::Other, format!("parse error: {:?}", e)))
          },
          IResult::Done(i, frame) => {
            (buf.offset(i), frame)
          }
        };

        trace!("decoded frame: {:?}", f);

        buf.split_to(consumed);

        Ok(Some(f))
    }
}

impl Encoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn encode(&mut self, frame: Frame, buf: &mut BytesMut) -> Result<(), Self::Error> {
      let length = buf.len();
      if length < 8192 {
        //reserve more capacity and intialize it
        buf.extend(repeat(0).take(8192 - length));
      }
      trace!("will send frame: {:?}", frame);

      loop {
        let gen_res = match &frame {
          &Frame::ProtocolHeader => {
            gen_protocol_header((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Heartbeat(_) => {
            gen_heartbeat_frame((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Method(channel, ref method) => {
            gen_method_frame((buf, 0), channel, method).map(|tup| tup.1)
          },
          &Frame::Header(channel_id, class_id, ref header) => {
            gen_content_header_frame((buf, 0), channel_id, class_id, header.body_size, &header.properties).map(|tup| tup.1)
          },
          &Frame::Body(channel_id, ref data) => {
            gen_content_body_frame((buf, 0), channel_id, data).map(|tup| tup.1)
          }
        };

        match gen_res {
          Ok(sz) => {
            buf.truncate(sz);
            trace!("serialized frame: {} bytes", sz);
            return Ok(());
          },
          Err(e) => {
            error!("error generating frame: {:?}", e);
            match e {
              GenError::BufferTooSmall(sz) => {
                buf.extend(repeat(0).take(sz - length));
                //return Err(Error::new(ErrorKind::InvalidData, "send buffer too small"));
              },
              GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
                return Err(Error::new(ErrorKind::InvalidData, "could not generate"));
              }
            }
          }
        }
      }
    }
}

/// Wrappers over a `Framed` stream using `AMQPCodec` and lapin-async's `Connection`
pub struct AMQPTransport<T> {
  pub upstream: Framed<T,AMQPCodec>,
  pub heartbeat: Interval,
  pub conn: Connection,
}

impl<T> AMQPTransport<T>
   where T: AsyncRead+AsyncWrite,
         T: 'static               {

  /// starts the connection process
  ///
  /// returns a future of a `AMQPTransport` that is connected
  pub fn connect(upstream: Framed<T,AMQPCodec>, options: &ConnectionOptions) -> Box<Future<Item = AMQPTransport<T>, Error = io::Error>> {
    let mut conn = Connection::new();
    conn.set_credentials(&options.username, &options.password);
    conn.set_vhost(&options.vhost);
    conn.set_heartbeat(options.heartbeat);
    conn.connect();

    let mut t = AMQPTransport {
      upstream:  upstream,
      heartbeat: Timer::default().interval(Duration::from_secs(conn.configuration.heartbeat as u64)),
      conn:      conn,
    };

    t.send_and_handle_frames();
    t.poll_children();

    let mut connector = AMQPTransportConnector {
      transport: Some(t)
    };

    trace!("pre-poll");
    connector.poll();
    trace!("post-poll");

    Box::new(connector)
  }

  pub fn poll_children(&mut self) {
    self.upstream.poll();
    self.heartbeat.poll();
  }

  pub fn send_and_handle_frames(&mut self) {
    self.send_frames();
    self.handle_frames();
  }

  pub fn send_frames(&mut self) {
    //FIXME: find a way to use a future here
    while let Some(f) = self.conn.next_frame() {
      self.upstream.start_send(f);
      self.upstream.poll_complete();
    }
    //self.upstream.poll_complete();
  }

  pub fn handle_frames(&mut self) {
    loop {
      match self.poll() {
        Ok(Async::Ready(Some(frame))) => {
          trace!("handle frames: AMQPTransport received frame: {:?}", frame);
          self.conn.handle_frame(frame);
        },
        Ok(Async::Ready(None)) => {
          trace!("handle frames: upstream poll gave Ready(None)");
          break;
        },
        Ok(Async::NotReady) => {
          trace!("handle frames: upstream poll gave NotReady");
          self.poll_children();
          break;
        },
        Err(e) => {
          error!("handle frames: upstream poll got error: {:?}", e);
          break;
        },
      };
    }
  }
}

/// implements a future of `AMQPTransport`
///
/// this structure is used to perform the AMQP handshake and provide
/// a connected transport afterwards
pub struct AMQPTransportConnector<T> {
  pub transport: Option<AMQPTransport<T>>,
}

impl<T> Future for AMQPTransportConnector<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {

  type Item  = AMQPTransport<T>;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    debug!("AMQPTransportConnector poll transport is none? {}", self.transport.is_none());
    let mut transport = self.transport.take().unwrap();

    //we might have received a frame before here
    transport.send_frames();

    debug!("conn state: {:?}", transport.conn.state);
    if transport.conn.state == ConnectionState::Connected {
      debug!("already connected");
      return Ok(Async::Ready(transport))
    }

    trace!("waiting before poll");
    transport.heartbeat.poll();
    let value = match transport.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        trace!("upstream poll gave NotReady");
        transport.poll_children();
        self.transport = Some(transport);
        return Ok(Async::NotReady);
      },
      Err(e) => {
        error!("upstream poll got error: {:?}", e);
        return Err(From::from(e));
      },
    };

    match value {
      Some(frame) => {
        trace!("got frame: {:?}", frame);
        transport.conn.handle_frame(frame);
        transport.send_frames();
        transport.upstream.poll_complete();
        if transport.conn.state == ConnectionState::Connected {
          return Ok(Async::Ready(transport))
        } else {
          transport.poll_children();
          self.transport = Some(transport);
          return Ok(Async::NotReady)
        }
      },
      e => {
        error!("did not get a frame? -> {:?}", e);
        self.transport = Some(transport);
        return Ok(Async::NotReady)
      }
    }
  }
}

impl<T> Stream for AMQPTransport<T>
    where T: AsyncRead + AsyncWrite {
    type Item = Frame;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Frame>, io::Error> {
        if let Ok(Async::Ready(_)) = self.heartbeat.poll() {
            debug!("Heartbeat");
            self.start_send(Frame::Heartbeat(0));
            self.poll_complete();
        }

        trace!("stream poll");
        // and Async::NotReady.
        match try_ready!(self.upstream.poll()) {
            Some(frame) => {
              debug!("AMQPTransport received frame: {:?}", frame);
              //try!(self.poll_complete());
              return Ok(Async::Ready(Some(frame)))
            },
            None => {
              trace!("AMQPTransport returned NotReady");
              return Ok(Async::NotReady)
            }
        }
    }
}

impl<T> Sink for AMQPTransport<T>
    where T: AsyncWrite {
    type SinkItem = Frame;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Frame) -> StartSend<Frame, io::Error> {
        trace!("sink start send");
        self.upstream.start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        trace!("sink poll_complete");
        self.upstream.poll_complete()
    }
}

<|endoftext|>


<commit_before>extern crate easystring;

#[cfg(test)]
mod content {
    mod index {
        use std::ffi::{CStr, CString, OsStr, OsString};
        use std::path::{Path, PathBuf};
        use easystring::{Content, ToContent};

        #[test]
        fn slice() {
            let content = Content::from("abcde");
            assert_eq!(content, "abcde");
        }
    }

    mod compare {
        use std::ffi::{CStr, CString, OsStr, OsString};
        use std::path::{Path, PathBuf};
        use easystring::{Content, ToContent};

        #[test]
        fn with_str() {
            let conent = Content::from("12345");
            assert_eq!(conent, "12345");
        }

        #[test]
        fn with_string() {
            let conent = Content::from("12345");
            let string = String::from("12345");
            assert_eq!(conent, string);
        }

        #[test]
        fn with_osstr() {
            let conent = Content::from("12345");
            let osstr = OsStr::new("12345");
            assert_eq!(conent, osstr);
        }

        #[test]
        fn with_osstring() {
            let content = Content::from("12345");
            let osstring = OsString::from("12345");
            assert_eq!(content, osstring);
        }

        #[test]
        fn with_cstr() {
            let content = Content::from("12345");
            let cstring = CString::new(b"12345".to_vec()).unwrap();
            let cstr = cstring.as_ref();
            assert_eq!(content, cstr);
        }

        #[test]
        fn with_cstring() {
            let content = Content::from("12345");
            let cstring = CString::new(b"12345".to_vec()).unwrap();
            assert_eq!(content, cstring);
        }

        #[test]
        fn with_path() {
            let conent = Content::from("12345");
            let path = Path::new("12345");
            assert_eq!(conent, path);
        }

        #[test]
        fn with_pathbuf() {
            let conent = Content::from("12345");
            let pathbuf = PathBuf::from("12345");
            assert_eq!(conent, pathbuf);
        }
    }
}
<commit_msg>Drop unused imports<commit_after>extern crate easystring;

#[cfg(test)]
mod content {
    mod index {
        use easystring::Content;

        #[test]
        fn slice() {
            let content = Content::from("abcde");
            assert_eq!(content, "abcde");
        }
    }

    mod compare {
        use std::ffi::{CString, OsStr, OsString};
        use std::path::{Path, PathBuf};
        use easystring::Content;

        #[test]
        fn with_str() {
            let conent = Content::from("12345");
            assert_eq!(conent, "12345");
        }

        #[test]
        fn with_string() {
            let conent = Content::from("12345");
            let string = String::from("12345");
            assert_eq!(conent, string);
        }

        #[test]
        fn with_osstr() {
            let conent = Content::from("12345");
            let osstr = OsStr::new("12345");
            assert_eq!(conent, osstr);
        }

        #[test]
        fn with_osstring() {
            let content = Content::from("12345");
            let osstring = OsString::from("12345");
            assert_eq!(content, osstring);
        }

        #[test]
        fn with_cstr() {
            let content = Content::from("12345");
            let cstring = CString::new(b"12345".to_vec()).unwrap();
            let cstr = cstring.as_ref();
            assert_eq!(content, cstr);
        }

        #[test]
        fn with_cstring() {
            let content = Content::from("12345");
            let cstring = CString::new(b"12345".to_vec()).unwrap();
            assert_eq!(content, cstring);
        }

        #[test]
        fn with_path() {
            let conent = Content::from("12345");
            let path = Path::new("12345");
            assert_eq!(conent, path);
        }

        #[test]
        fn with_pathbuf() {
            let conent = Content::from("12345");
            let pathbuf = PathBuf::from("12345");
            assert_eq!(conent, pathbuf);
        }
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::process::Command;

#[allow(dead_code)]
mod cargo;

fn clippy_path() -> PathBuf {
    let build_info = cargo::BuildInfo::new();
    build_info.target_lib().join("cargo-clippy")
}

#[test]
fn dogfood_clippy() {
    // run clippy on itself and fail the test if lint warnings are reported
    if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) {
        return;
    }
    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let clippy_binary = clippy_path();

    let output = Command::new(clippy_binary)
        .current_dir(root_dir)
        .env("CLIPPY_DOGFOOD", "1")
        .env("CARGO_INCREMENTAL", "0")
        .arg("clippy-preview")
        .arg("--all-targets")
        .arg("--all-features")
        .arg("--")
        .args(&["-D", "clippy::all"])
        .args(&["-D", "clippy::internal"])
        .args(&["-D", "clippy::pedantic"])
        .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
        .output()
        .unwrap();
    println!("status: {}", output.status);
    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success());
}

#[test]
fn dogfood_subprojects() {
    // run clippy on remaining subprojects and fail the test if lint warnings are reported
    if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) {
        return;
    }
    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let clippy_binary = clippy_path();

    for d in &[
        "clippy_workspace_tests",
        "clippy_workspace_tests/src",
        "clippy_workspace_tests/subcrate",
        "clippy_workspace_tests/subcrate/src",
        "clippy_dev",
        "rustc_tools_util",
    ] {
        let output = Command::new(&clippy_binary)
            .current_dir(root_dir.join(d))
            .env("CLIPPY_DOGFOOD", "1")
            .env("CARGO_INCREMENTAL", "0")
            .arg("clippy")
            .arg("--")
            .args(&["-D", "clippy::all"])
            .args(&["-D", "clippy::pedantic"])
            .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
            .output()
            .unwrap();
        println!("status: {}", output.status);
        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

        assert!(output.status.success());
    }
}
<commit_msg>Use lazy_static<commit_after>use lazy_static::lazy_static;
use std::path::PathBuf;
use std::process::Command;

#[allow(dead_code)]
mod cargo;

lazy_static! {
    static ref CLIPPY_PATH: PathBuf = {
        let build_info = cargo::BuildInfo::new();
        build_info.target_lib().join("cargo-clippy")
    };
}

#[test]
fn dogfood_clippy() {
    // run clippy on itself and fail the test if lint warnings are reported
    if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) {
        return;
    }
    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));

    let output = Command::new(&*CLIPPY_PATH)
        .current_dir(root_dir)
        .env("CLIPPY_DOGFOOD", "1")
        .env("CARGO_INCREMENTAL", "0")
        .arg("clippy-preview")
        .arg("--all-targets")
        .arg("--all-features")
        .arg("--")
        .args(&["-D", "clippy::all"])
        .args(&["-D", "clippy::internal"])
        .args(&["-D", "clippy::pedantic"])
        .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
        .output()
        .unwrap();
    println!("status: {}", output.status);
    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success());
}

#[test]
fn dogfood_subprojects() {
    // run clippy on remaining subprojects and fail the test if lint warnings are reported
    if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) {
        return;
    }
    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));

    for d in &[
        "clippy_workspace_tests",
        "clippy_workspace_tests/src",
        "clippy_workspace_tests/subcrate",
        "clippy_workspace_tests/subcrate/src",
        "clippy_dev",
        "rustc_tools_util",
    ] {
        let output = Command::new(&*CLIPPY_PATH)
            .current_dir(root_dir.join(d))
            .env("CLIPPY_DOGFOOD", "1")
            .env("CARGO_INCREMENTAL", "0")
            .arg("clippy")
            .arg("--")
            .args(&["-D", "clippy::all"])
            .args(&["-D", "clippy::pedantic"])
            .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
            .output()
            .unwrap();
        println!("status: {}", output.status);
        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

        assert!(output.status.success());
    }
}
<|endoftext|>