<commit_before>use crate::core::{property::HasVertex, Directedness, Edge, Graph};

/// Performs [depth-first traversal](https://mathworld.wolfram.com/Depth-FirstTraversal.html)
/// of a graph's vertices.
///
/// Even though the 's' in its name implies a search, this struct only performs
/// traversal, delegating the searching to the user.
///
/// It implements [`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). [`next`]
/// is therefore the primary way to use this struct.
/// Each call will traverse the graph just enough to visit the next vertex and
/// return it. The initial vertex visited is the one returned by calling the
/// graph's [`get_vertex`](../core/property/trait.HasVertex.html#method.
/// get_vertex) method. That vertex is also guaranteed to be returned by the
/// first call to [`next`].
///
/// When the traversal is finished, either because all vertices in the graph
/// have been visited or because no more vertices can be reached,
/// [`next`] will return [`None`](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None).
///
/// ### Simple Usage
///
/// ```
/// # use graphene::{
/// # 	algo::Dfs,
/// # 	common::AdjListGraph,
/// # 	core::{
/// # 		Ensure,
/// # 		property::{
/// # 			NewVertex, AddEdge, VertexInGraph
/// # 		}
/// # 	},
/// # };
/// # use graphene::core::Graph;
/// let mut graph = AdjListGraph::<usize,()>::new();
///
/// let v0 = graph.new_vertex_weighted(0).unwrap();
/// let v1 = graph.new_vertex_weighted(1).unwrap();
/// let v2 = graph.new_vertex_weighted(2).unwrap();
///
/// graph.add_edge((v0,v1)).unwrap();
/// graph.add_edge((v1,v2)).unwrap();
///
/// // We use `VertexInGraph` to ensure traversal starts at v0.
/// let graph = VertexInGraph::ensure(graph, v0).unwrap();
///
/// // Initialize the traversal
/// let mut dfs = Dfs::new_simple(&graph);
///
/// // We search for the first vertex with weight == 1.
/// let found_vertex = dfs.find(|&v| graph.vertex_weight(v).unwrap() == &1).unwrap();
/// assert_eq!(v1, found_vertex)
/// ```
///
/// The most basic use of this struct is through the
/// [`new_simple`](#method.new_simple) function which creates a traversal over
/// the given graph. In our example above, we use this to implement an actual
/// search, by using [`find`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find), looking for the
/// first vertex visited that has a given weight.
/// Since traversal is lazy, `v2` was never visited, since `v1` was found before
/// `v2` was explored. Therefore, we could theoretically continue the traversal
/// on the same dfs.
///
/// ### Notes
///
/// _Why isn't `on_exit` a closure?_
///
/// There are Three possibilities for an API using closures:
///
/// 1. Direct closure : This requires Dfs to be generic on the closures type.
/// this is possible but means Dfs cannot be used in places where its explicit
/// type is needed. I.e. it cannot be a field in a different struct nor be
/// returned by a function.
///
/// 2. Referenced closure: If Dfs takes a reference to a closure, it no longer
/// needs to be generic on the closures type. However, it limits where Dfs can
/// be used, since its now bound by the lifetime of the reference. It also
/// doesn't solve the issue with other struct using Dfs, because you can't have
/// the closure anywhere when not using the Dfs.
///
/// 3. Boxed closure: Technically possible, but requires `std` and imposes
/// allocations.
///
/// This solution is as flexible as nr. 1, but solves the issue with naming the
/// closures type. In essence, we are simulating a closure by have `on_exit` be
/// a function and taking `on_exit_args`, that's basically what a closure is.
///
/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
///
pub struct Dfs<'a, G, F>
where
	G: 'a + Graph,
{
	/// The graph being traversed.
	pub graph: &'a G,

	/// A custom payload, available to the function called upon a vertex exit.
	pub payload: F,
	visited: Vec<G::Vertex>,

	/// The vertex on the stack, and whether on_exit should be called upon
	/// popping.
	stack: Vec<(G::Vertex, bool)>,

	/// Function to call when exiting a vertex.
	///
	/// Provices a reference to the graph, the vertex that is exiting,
	/// and a mutable reference to the payload given to the Dfs.
	on_exit: fn(&G, G::Vertex, &mut F),
}

impl<'a, G, F> Dfs<'a, G, F>
where
	G: 'a + Graph,
{
	pub fn new(g: &'a G, on_exit: fn(&G, G::Vertex, &mut F), payload: F) -> Self
	where
		G: HasVertex,
	{
		Self {
			graph: g,
			visited: Vec::new(),
			stack: vec![(g.get_vertex(), true)],
			on_exit,
			payload,
		}
	}

	pub fn visited(&self, v: G::Vertex) -> bool
	{
		self.visited.contains(&v)
	}

	/// Pops the next vertex that it is finished visiting off the stack, calling
	/// `on_exit` on it.
	///
	///  If there was nothing to pop and call `on_exit` on, return false,
	/// otherwise returns true.
	pub fn advance_next_exit(&mut self) -> Option<G::Vertex>
	{
		while let Some(last) = self.stack.last()
		{
			if self.visited(last.0.clone())
			{
				let last = self.stack.pop().unwrap();

				// If its exit marked, call the closure on it.
				if last.1
				{
					(self.on_exit)(self.graph, last.0, &mut self.payload);
					return Some(last.0);
				}
			}
			else
			{
				return None;
			}
		}
		None
	}

	pub fn continue_from(&mut self, v: G::Vertex) -> bool
	{
		if !self.visited(v.clone())
		{
			self.stack.push((v, true));
			true
		}
		else
		{
			false
		}
	}
}

impl<'a, G> Dfs<'a, G, ()>
where
	G: 'a + HasVertex,
{
	pub fn new_simple(g: &'a G) -> Self
	{
		fn do_nothing<G, T>(_: &G, _: T, _: &mut ()) {}
		Self::new(g, do_nothing, ())
	}
}

impl<'a, G, F> Iterator for Dfs<'a, G, F>
where
	G: 'a + Graph,
{
	type Item = G::Vertex;

	fn next(&mut self) -> Option<Self::Item>
	{
		// The meaning of markers:
		//
		// If its on the stack it means we are still visiting it or its children.
		//
		// If its exit marked, it means when we are finished visiting it and its
		// children, we will call the 'on_exit' closure on it, and then pop it.
		// If its not exit marked, it means this instance of it on the stack was
		// never used for visiting this vertex's children and we just pop it, without
		// calling the closure.
		//
		// If it is marked visited it means we are either visiting its children, or
		// we are finished doing so. Either way, it shouldn't go on the stack again
		// at any point.

		// Pop any vertices that we are done visiting (and since its on the top of the
		// stack, we must be done visiting its children).
		while self.advance_next_exit().is_some()
		{}

		// Get the top of the stack. This is necessarily a non-visited vertex.
		// If the stack is empty, then this will return none
		let to_return = self.stack.last()?.0.clone();

		// Mark visited
		self.visited.push(to_return);
		// Exit mark, since we will use it for exploring its children
		self.stack.last_mut()?.1 = true;

		// Explore children
		for e in self.graph.edges_incident_on(to_return.clone())
		{
			let child = if to_return == e.source()
			{
				e.sink()
			}
			// In a directed graph, we have to skip incoming edges
			else if G::Directedness::directed()
			{
				continue;
			}
			else
			{
				e.source()
			};

			if !self.visited(child.clone())
			{
				// Push to stack without exit mark
				self.stack.push((child, false));
			}
		}
		Some(to_return)
	}
}
<commit_msg>Documented algo::Dfs::new_simple.<commit_after>use crate::core::{property::HasVertex, Directedness, Edge, Graph};

/// Performs [depth-first traversal](https://mathworld.wolfram.com/Depth-FirstTraversal.html)
/// of a graph's vertices.
///
/// Even though the 's' in its name implies a search, this struct only performs
/// traversal, delegating the searching to the user.
///
/// It implements [`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). [`next`]
/// is therefore the primary way to use this struct.
/// Each call will traverse the graph just enough to visit the next vertex and
/// return it. The initial vertex visited is the one returned by calling the
/// graph's [`get_vertex`] method. That vertex is also guaranteed to be returned
/// by the first call to [`next`].
///
/// When the traversal is finished, either because all vertices in the graph
/// have been visited or because no more vertices can be reached,
/// [`next`] will return [`None`](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None).
///
/// ### Simple Usage
///
/// ```
/// # use graphene::{
/// # 	algo::Dfs,
/// # 	common::AdjListGraph,
/// # 	core::{
/// # 		Ensure,
/// # 		property::{
/// # 			NewVertex, AddEdge, VertexInGraph
/// # 		}
/// # 	},
/// # };
/// # use graphene::core::Graph;
/// let mut graph = AdjListGraph::<usize,()>::new();
///
/// let v0 = graph.new_vertex_weighted(0).unwrap();
/// let v1 = graph.new_vertex_weighted(1).unwrap();
/// let v2 = graph.new_vertex_weighted(2).unwrap();
///
/// graph.add_edge((v0,v1)).unwrap();
/// graph.add_edge((v1,v2)).unwrap();
///
/// // We use `VertexInGraph` to ensure traversal starts at v0.
/// let graph = VertexInGraph::ensure(graph, v0).unwrap();
///
/// // Initialize the traversal
/// let mut dfs = Dfs::new_simple(&graph);
///
/// // We search for the first vertex with weight == 1.
/// let found_vertex = dfs.find(|&v| graph.vertex_weight(v).unwrap() == &1).unwrap();
/// assert_eq!(v1, found_vertex)
/// ```
///
/// The most basic use of this struct is through the
/// [`new_simple`](#method.new_simple) function which creates a traversal over
/// the given graph. In our example above, we use this to implement an actual
/// search, by using [`find`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find), looking for the
/// first vertex visited that has a given weight.
/// Since traversal is lazy, `v2` was never visited, since `v1` was found before
/// `v2` was explored. Therefore, we could theoretically continue the traversal
/// on the same dfs.
///
/// ### Notes
///
/// _Why isn't `on_exit` a closure?_
///
/// There are Three possibilities for an API using closures:
///
/// 1. Direct closure : This requires Dfs to be generic on the closures type.
/// this is possible but means Dfs cannot be used in places where its explicit
/// type is needed. I.e. it cannot be a field in a different struct nor be
/// returned by a function.
///
/// 2. Referenced closure: If Dfs takes a reference to a closure, it no longer
/// needs to be generic on the closures type. However, it limits where Dfs can
/// be used, since its now bound by the lifetime of the reference. It also
/// doesn't solve the issue with other struct using Dfs, because you can't have
/// the closure anywhere when not using the Dfs.
///
/// 3. Boxed closure: Technically possible, but requires `std` and imposes
/// allocations.
///
/// This solution is as flexible as nr. 1, but solves the issue with naming the
/// closures type. In essence, we are simulating a closure by have `on_exit` be
/// a function and taking `on_exit_args`, that's basically what a closure is.
///
/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
/// [`get_vertex`]: ../core/property/trait.HasVertex.html#method.get_vertex
pub struct Dfs<'a, G, F>
where
	G: 'a + Graph,
{
	/// A reference to the graph being traversed.
	///
	/// This is use by `Dfs` when doing the traversal. Mutating
	/// this reference between calls to
	/// [`next`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next)
	/// is undefined behaviour.
	pub graph: &'a G,

	/// A custom payload, available to the function called upon a vertex exit.
	/// See [`new`](#method.new).
	pub payload: F,
	visited: Vec<G::Vertex>,

	/// The vertex on the stack, and whether on_exit should be called upon
	/// popping.
	stack: Vec<(G::Vertex, bool)>,

	/// Function to call when exiting a vertex.
	///
	/// Provides a reference to the graph, the vertex that is exiting,
	/// and a mutable reference to the payload given to the Dfs.
	on_exit: fn(&G, G::Vertex, &mut F),
}

impl<'a, G, F> Dfs<'a, G, F>
where
	G: 'a + Graph,
{
	pub fn new(g: &'a G, on_exit: fn(&G, G::Vertex, &mut F), payload: F) -> Self
	where
		G: HasVertex,
	{
		Self {
			graph: g,
			visited: Vec::new(),
			stack: vec![(g.get_vertex(), true)],
			on_exit,
			payload,
		}
	}

	pub fn visited(&self, v: G::Vertex) -> bool
	{
		self.visited.contains(&v)
	}

	/// Pops the next vertex that it is finished visiting off the stack, calling
	/// `on_exit` on it.
	///
	///  If there was nothing to pop and call `on_exit` on, return false,
	/// otherwise returns true.
	pub fn advance_next_exit(&mut self) -> Option<G::Vertex>
	{
		while let Some(last) = self.stack.last()
		{
			if self.visited(last.0.clone())
			{
				let last = self.stack.pop().unwrap();

				// If its exit marked, call the closure on it.
				if last.1
				{
					(self.on_exit)(self.graph, last.0, &mut self.payload);
					return Some(last.0);
				}
			}
			else
			{
				return None;
			}
		}
		None
	}

	pub fn continue_from(&mut self, v: G::Vertex) -> bool
	{
		if !self.visited(v.clone())
		{
			self.stack.push((v, true));
			true
		}
		else
		{
			false
		}
	}
}

impl<'a, G> Dfs<'a, G, ()>
where
	G: 'a + HasVertex,
{
	/// Constructs a new `Dfs` to traverse the specified graph.
	///
	/// It calls [`get_vertex`] on the graph making the traversal start from the
	/// returned vertex. The first call to [`next`]
	/// on the constructed `Dfs` is guaranteed to return the aforementioned
	/// vertex.
	///
	/// ### Hint
	///
	/// [`VertexInGraph`](../core/property/struct.VertexInGraph.html) can be
	/// used to select which specific vertex is returned by [`get_vertex`] and
	/// thereby the starting vertex for the traversal.
	///
	/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
	/// [`get_vertex`]: ../core/property/trait.HasVertex.html#method.get_vertex
	pub fn new_simple(g: &'a G) -> Self
	{
		fn do_nothing<G, T>(_: &G, _: T, _: &mut ()) {}
		Self::new(g, do_nothing, ())
	}
}

impl<'a, G, F> Iterator for Dfs<'a, G, F>
where
	G: 'a + Graph,
{
	type Item = G::Vertex;

	fn next(&mut self) -> Option<Self::Item>
	{
		// The meaning of markers:
		//
		// If its on the stack it means we are still visiting it or its children.
		//
		// If its exit marked, it means when we are finished visiting it and its
		// children, we will call the 'on_exit' closure on it, and then pop it.
		// If its not exit marked, it means this instance of it on the stack was
		// never used for visiting this vertex's children and we just pop it, without
		// calling the closure.
		//
		// If it is marked visited it means we are either visiting its children, or
		// we are finished doing so. Either way, it shouldn't go on the stack again
		// at any point.

		// Pop any vertices that we are done visiting (and since its on the top of the
		// stack, we must be done visiting its children).
		while self.advance_next_exit().is_some()
		{}

		// Get the top of the stack. This is necessarily a non-visited vertex.
		// If the stack is empty, then this will return none
		let to_return = self.stack.last()?.0.clone();

		// Mark visited
		self.visited.push(to_return);
		// Exit mark, since we will use it for exploring its children
		self.stack.last_mut()?.1 = true;

		// Explore children
		for e in self.graph.edges_incident_on(to_return.clone())
		{
			let child = if to_return == e.source()
			{
				e.sink()
			}
			// In a directed graph, we have to skip incoming edges
			else if G::Directedness::directed()
			{
				continue;
			}
			else
			{
				e.source()
			};

			if !self.visited(child.clone())
			{
				// Push to stack without exit mark
				self.stack.push((child, false));
			}
		}
		Some(to_return)
	}
}
<|endoftext|>


<commit_before>use libc::{c_int, c_char, c_long, c_double};
use super::geom::Point;
use utils::_string;

pub struct Proj {
    c_proj: *const (),
}

pub static DEG_TO_RAD: f64 = 0.017453292519943295769236907684886;

#[link(name="proj")]
extern {
    fn pj_init_plus(definition: *const c_char) -> *const ();
    fn pj_free(pj: *const ());
    fn pj_get_def(pj: *const ()) -> *const c_char;
    fn pj_transform(
        srcdefn: *const (),
        dstdefn: *const (),
        point_count: c_long,
        point_offset: c_int,
        x: *mut c_double,
        y: *mut c_double,
        z: *mut c_double
    ) -> c_int;
    fn pj_strerrno(code: c_int) -> *const c_char;
}

fn error_message(code: c_int) -> String {
    let rv = unsafe { pj_strerrno(code) };
    return _string(rv);
}

impl Proj {
    pub fn new(definition: &str) -> Option<Proj> {
        let c_proj = definition.with_c_str(|c_definition| {
            unsafe { return pj_init_plus(c_definition) }
        });
        return match c_proj.is_null() {
            true  => None,
            false => Some(Proj{c_proj: c_proj}),
        };
    }

    pub fn def(&self) -> String {
        let rv = unsafe { pj_get_def(self.c_proj) };
        return _string(rv);
    }

    pub fn project(&self, target: &Proj, point: Point<f64>) -> Point<f64> {
        let mut c_x: c_double = point.x;
        let mut c_y: c_double = point.y;
        let mut c_z: c_double = 0.;
        unsafe {
            let rv = pj_transform(
                self.c_proj,
                target.c_proj,
                1,
                1,
                &mut c_x,
                &mut c_y,
                &mut c_z
            );
            //if rv != 0 {
            //    println!("{}", error_message(rv));
            //}
            assert!(rv == 0);
        }
        return Point::new(c_x, c_y);
    }
}

impl Drop for Proj {
    fn drop(&mut self) {
        unsafe { pj_free(self.c_proj); }
    }
}

#[cfg(test)]
mod test {
    use super::super::geom::Point;
    use super::Proj;

    #[test]
    fn test_new_projection() {
        let wgs84 = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs";
        let proj = Proj::new(wgs84).unwrap();
        assert_eq!(
            proj.def().as_slice(),
            " +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0");
    }

    fn assert_almost_eq(a: f64, b: f64) {
        let f: f64 = a / b;
        assert!(f < 1.00001);
        assert!(f > 0.99999);
    }

    #[test]
    fn test_transform() {
        let wgs84_name = "+proj=longlat +datum=WGS84 +no_defs";
        let wgs84 = Proj::new(wgs84_name).unwrap();
        let stereo70 = Proj::new("+proj=sterea +lat_0=46 +lon_0=25 +k=0.99975 +x_0=500000 +y_0=500000 +ellps=krass +units=m +no_defs").unwrap();

        let rv = stereo70.project(&wgs84, Point::new(500000., 500000.));
        assert_almost_eq(rv.x, 0.436332);
        assert_almost_eq(rv.y, 0.802851);

        let rv = wgs84.project(&stereo70, Point::new(0.436332, 0.802851));
        assert_almost_eq(rv.x, 500000.);
        assert_almost_eq(rv.y, 500000.);
    }
}
<commit_msg>print errors<commit_after>use libc::{c_int, c_char, c_long, c_double};
use super::geom::Point;
use utils::_string;

pub struct Proj {
    c_proj: *const (),
}

pub static DEG_TO_RAD: f64 = 0.017453292519943295769236907684886;

#[link(name="proj")]
extern {
    fn pj_init_plus(definition: *const c_char) -> *const ();
    fn pj_free(pj: *const ());
    fn pj_get_def(pj: *const ()) -> *const c_char;
    fn pj_transform(
        srcdefn: *const (),
        dstdefn: *const (),
        point_count: c_long,
        point_offset: c_int,
        x: *mut c_double,
        y: *mut c_double,
        z: *mut c_double
    ) -> c_int;
    fn pj_strerrno(code: c_int) -> *const c_char;
}

fn error_message(code: c_int) -> String {
    let rv = unsafe { pj_strerrno(code) };
    return _string(rv);
}

impl Proj {
    pub fn new(definition: &str) -> Option<Proj> {
        let c_proj = definition.with_c_str(|c_definition| {
            unsafe { return pj_init_plus(c_definition) }
        });
        return match c_proj.is_null() {
            true  => None,
            false => Some(Proj{c_proj: c_proj}),
        };
    }

    pub fn def(&self) -> String {
        let rv = unsafe { pj_get_def(self.c_proj) };
        return _string(rv);
    }

    pub fn project(&self, target: &Proj, point: Point<f64>) -> Point<f64> {
        let mut c_x: c_double = point.x;
        let mut c_y: c_double = point.y;
        let mut c_z: c_double = 0.;
        unsafe {
            let rv = pj_transform(
                self.c_proj,
                target.c_proj,
                1,
                1,
                &mut c_x,
                &mut c_y,
                &mut c_z
            );
            if rv != 0 {
                println!("{}", error_message(rv));
            }
            assert!(rv == 0);
        }
        return Point::new(c_x, c_y);
    }
}

impl Drop for Proj {
    fn drop(&mut self) {
        unsafe { pj_free(self.c_proj); }
    }
}

#[cfg(test)]
mod test {
    use super::super::geom::Point;
    use super::Proj;

    #[test]
    fn test_new_projection() {
        let wgs84 = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs";
        let proj = Proj::new(wgs84).unwrap();
        assert_eq!(
            proj.def().as_slice(),
            " +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0");
    }

    fn assert_almost_eq(a: f64, b: f64) {
        let f: f64 = a / b;
        assert!(f < 1.00001);
        assert!(f > 0.99999);
    }

    #[test]
    fn test_transform() {
        let wgs84_name = "+proj=longlat +datum=WGS84 +no_defs";
        let wgs84 = Proj::new(wgs84_name).unwrap();
        let stereo70 = Proj::new("+proj=sterea +lat_0=46 +lon_0=25 +k=0.99975 +x_0=500000 +y_0=500000 +ellps=krass +units=m +no_defs").unwrap();

        let rv = stereo70.project(&wgs84, Point::new(500000., 500000.));
        assert_almost_eq(rv.x, 0.436332);
        assert_almost_eq(rv.y, 0.802851);

        let rv = wgs84.project(&stereo70, Point::new(0.436332, 0.802851));
        assert_almost_eq(rv.x, 500000.);
        assert_almost_eq(rv.y, 500000.);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::thread::sleep;
use std::time::Duration;

use anyhow::Result;
use chrono::Local;
use crossterm::style::{Attribute, Color};

use pueue::protocol::Socket;
use pueue::task::{Task, TaskResult, TaskStatus};

use crate::commands::get_state;
use crate::output_helper::style_text;

/// Wait until tasks are done.
/// Tasks can be specified by:
/// - Default queue (no parameter given)
/// - Group
/// - A list of task ids
/// - All tasks (`all == true`)
///
/// By default, this will log status changes on tasks.
/// Pass `quiet == true` to supress any logging.
pub async fn wait(
    socket: &mut Socket,
    task_ids: &Option<Vec<usize>>,
    group: &Option<String>,
    all: bool,
    quiet: bool,
) -> Result<()> {
    let mut first_run = true;
    // Create a list of tracked tasks.
    // This way we can track any status changes and if any new tasks are added.
    let mut watched_tasks: HashMap<usize, TaskStatus> = HashMap::new();

    loop {
        let state = get_state(socket).await?;

        let tasks: Vec<Task> = if all {
            // Get all tasks
            state.tasks.iter().map(|(_, task)| task.clone()).collect()
        } else if let Some(group) = group {
            // Get all tasks of a specific group
            state
                .tasks
                .iter()
                .filter(|(_, task)| task.group == Some(group.clone()))
                .map(|(_, task)| task.clone())
                .collect()
        } else if let Some(ids) = task_ids {
            // Get all tasks of a specific group
            state
                .tasks
                .iter()
                .filter(|(id, _)| ids.contains(id))
                .map(|(_, task)| task.clone())
                .collect()
        } else {
            // Get all tasks of the default queue by default
            state
                .tasks
                .iter()
                .filter(|(_, task)| task.group == None)
                .map(|(_, task)| task.clone())
                .collect()
        };

        // Get current time for log output
        let current_time = Local::now().format("%H:%M:%S").to_string();

        // Iterate over all matching tasks
        for task in tasks.iter() {
            // Check if we already know this task or if it is new.
            let previous_status = match watched_tasks.get(&task.id) {
                None => {
                    // Add any unknown tasks to our watchlist
                    // Don't log anything if this is the first run
                    if !quiet && !first_run {
                        let color = get_color_for_status(&task.status);
                        println!(
                            "{} - New task {} with status {}",
                            current_time,
                            style_text(task.id, None, Some(Attribute::Bold)),
                            style_text(&task.status, Some(color), None),
                        );
                    }
                    watched_tasks.insert(task.id, task.status.clone());

                    continue;
                }
                Some(previous_status) => {
                    if previous_status == &task.status {
                        continue;
                    }
                    previous_status.clone()
                }
            };

            // Update the (previous) task status and log any changes
            watched_tasks.insert(task.id, task.status.clone());
            if !quiet {
                log_status_change(&current_time, previous_status, &task);
            }
        }

        // We can stop waiting, if every task is on `Done`
        // Always check the actual task list instead of the watched_tasks list.
        // Otherwise we get locked if tasks get removed.
        let all_finished = tasks.iter().all(|task| task.status == TaskStatus::Done);

        if all_finished {
            break;
        }

        // Sleep for a few milliseconds. We don't want to hurt the CPU.
        let timeout = Duration::from_millis(2000);
        // Don't use recv_timeout for now, until this bug get's fixed.
        // https://github.com/rust-lang/rust/issues/39364
        //match self.receiver.recv_timeout(timeout) {
        sleep(timeout);
        first_run = false;
    }

    Ok(())
}

fn log_status_change(current_time: &str, previous_status: TaskStatus, task: &Task) {
    // Finishing tasks get some special handling
    if task.status == TaskStatus::Done {
        let text = match task.result {
            Some(TaskResult::Success) => {
                format!(
                    "Task {} succeeded with {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text("0", Some(Color::Green), None)
                )
            }
            Some(TaskResult::DependencyFailed) => {
                format!(
                    "Task {} failed due to {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text("failed dependencies", Some(Color::Red), None)
                )
            }

            Some(TaskResult::FailedToSpawn(_)) => {
                format!(
                    "Task {} {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text("failed to spawn", Some(Color::Red), None)
                )
            }
            Some(TaskResult::Failed(exit_code)) => {
                format!(
                    "Task {} failed with {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text(exit_code, Some(Color::Red), Some(Attribute::Bold))
                )
            }
            Some(TaskResult::Killed) => {
                format!(
                    "Task {} has been {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text("killed", Some(Color::Red), None)
                )
            }
            None => panic!("Got a 'Done' task without a task result. Please report this bug."),
        };
        println!("{} - {}", current_time, text);

        return;
    }
    let new_status_color = get_color_for_status(&task.status);
    let previous_status_color = get_color_for_status(&previous_status);

    println!(
        "{} - Task {} changed from {} to {}",
        current_time,
        style_text(task.id, None, Some(Attribute::Bold)),
        style_text(previous_status, Some(previous_status_color), None),
        style_text(&task.status, Some(new_status_color), None),
    );
}

fn get_color_for_status(task_status: &TaskStatus) -> Color {
    match task_status {
        TaskStatus::Running | TaskStatus::Done => Color::Green,
        TaskStatus::Paused | TaskStatus::Locked => Color::White,
        _ => Color::Yellow,
    }
}
<commit_msg>Cleanup wrong comments in wait<commit_after>use std::collections::HashMap;
use std::thread::sleep;
use std::time::Duration;

use anyhow::Result;
use chrono::Local;
use crossterm::style::{Attribute, Color};

use pueue::protocol::Socket;
use pueue::task::{Task, TaskResult, TaskStatus};

use crate::commands::get_state;
use crate::output_helper::style_text;

/// Wait until tasks are done.
/// Tasks can be specified by:
/// - Default queue (no parameter given)
/// - Group
/// - A list of task ids
/// - All tasks (`all == true`)
///
/// By default, this will log status changes on tasks.
/// Pass `quiet == true` to supress any logging.
pub async fn wait(
    socket: &mut Socket,
    task_ids: &Option<Vec<usize>>,
    group: &Option<String>,
    all: bool,
    quiet: bool,
) -> Result<()> {
    let mut first_run = true;
    // Create a list of tracked tasks.
    // This way we can track any status changes and if any new tasks are added.
    let mut watched_tasks: HashMap<usize, TaskStatus> = HashMap::new();

    loop {
        let state = get_state(socket).await?;

        let tasks: Vec<Task> = if all {
            // Get all tasks
            state.tasks.iter().map(|(_, task)| task.clone()).collect()
        } else if let Some(group) = group {
            // Get all tasks of a specific group
            state
                .tasks
                .iter()
                .filter(|(_, task)| task.group == Some(group.clone()))
                .map(|(_, task)| task.clone())
                .collect()
        } else if let Some(ids) = task_ids {
            // Get all tasks of a specific group
            state
                .tasks
                .iter()
                .filter(|(id, _)| ids.contains(id))
                .map(|(_, task)| task.clone())
                .collect()
        } else {
            // Get all tasks of the default queue by default
            state
                .tasks
                .iter()
                .filter(|(_, task)| task.group == None)
                .map(|(_, task)| task.clone())
                .collect()
        };

        // Get current time for log output
        let current_time = Local::now().format("%H:%M:%S").to_string();

        // Iterate over all matching tasks
        for task in tasks.iter() {
            // Check if we already know this task or if it is new.
            let previous_status = match watched_tasks.get(&task.id) {
                None => {
                    // Add any unknown tasks to our watchlist
                    // Don't log anything if this is the first run
                    if !quiet && !first_run {
                        let color = get_color_for_status(&task.status);
                        println!(
                            "{} - New task {} with status {}",
                            current_time,
                            style_text(task.id, None, Some(Attribute::Bold)),
                            style_text(&task.status, Some(color), None),
                        );
                    }
                    watched_tasks.insert(task.id, task.status.clone());

                    continue;
                }
                Some(previous_status) => {
                    if previous_status == &task.status {
                        continue;
                    }
                    previous_status.clone()
                }
            };

            // Update the (previous) task status and log any changes
            watched_tasks.insert(task.id, task.status.clone());
            if !quiet {
                log_status_change(&current_time, previous_status, &task);
            }
        }

        // We can stop waiting, if every task is on `Done`
        // Always check the actual task list instead of the watched_tasks list.
        // Otherwise we get locked if tasks get removed.
        let all_finished = tasks.iter().all(|task| task.status == TaskStatus::Done);

        if all_finished {
            break;
        }

        // Sleep for a few seconds. We don't want to hurt the CPU.
        sleep(Duration::from_millis(2000));
        first_run = false;
    }

    Ok(())
}

fn log_status_change(current_time: &str, previous_status: TaskStatus, task: &Task) {
    // Finishing tasks get some special handling
    if task.status == TaskStatus::Done {
        let text = match task.result {
            Some(TaskResult::Success) => {
                format!(
                    "Task {} succeeded with {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text("0", Some(Color::Green), None)
                )
            }
            Some(TaskResult::DependencyFailed) => {
                format!(
                    "Task {} failed due to {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text("failed dependencies", Some(Color::Red), None)
                )
            }

            Some(TaskResult::FailedToSpawn(_)) => {
                format!(
                    "Task {} {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text("failed to spawn", Some(Color::Red), None)
                )
            }
            Some(TaskResult::Failed(exit_code)) => {
                format!(
                    "Task {} failed with {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text(exit_code, Some(Color::Red), Some(Attribute::Bold))
                )
            }
            Some(TaskResult::Killed) => {
                format!(
                    "Task {} has been {}",
                    style_text(task.id, None, Some(Attribute::Bold)),
                    style_text("killed", Some(Color::Red), None)
                )
            }
            None => panic!("Got a 'Done' task without a task result. Please report this bug."),
        };
        println!("{} - {}", current_time, text);

        return;
    }
    let new_status_color = get_color_for_status(&task.status);
    let previous_status_color = get_color_for_status(&previous_status);

    println!(
        "{} - Task {} changed from {} to {}",
        current_time,
        style_text(task.id, None, Some(Attribute::Bold)),
        style_text(previous_status, Some(previous_status_color), None),
        style_text(&task.status, Some(new_status_color), None),
    );
}

fn get_color_for_status(task_status: &TaskStatus) -> Color {
    match task_status {
        TaskStatus::Running | TaskStatus::Done => Color::Green,
        TaskStatus::Paused | TaskStatus::Locked => Color::White,
        _ => Color::Yellow,
    }
}
<|endoftext|>


<commit_before>//! Types for the *m.room.power_levels* event.

use std::collections::HashMap;

use js_int::{Int, UInt};
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use serde_json::Value;

use crate::{Event as _, EventType, FromRaw};

/// Defines the power levels (privileges) of users in the room.
#[derive(Clone, Debug, PartialEq)]
pub struct PowerLevelsEvent {
    /// The event's content.
    pub content: PowerLevelsEventContent,

    /// The unique identifier for the event.
    pub event_id: EventId,

    /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
    /// event was sent.
    pub origin_server_ts: UInt,

    /// The previous content for this state key, if any.
    pub prev_content: Option<PowerLevelsEventContent>,

    /// The unique identifier for the room associated with this event.
    pub room_id: Option<RoomId>,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: Option<Value>,

    /// The unique identifier for the user who sent this event.
    pub sender: UserId,

    /// A key that determines which piece of room state the event represents.
    pub state_key: String,
}

/// The payload for `PowerLevelsEvent`.
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct PowerLevelsEventContent {
    /// The level required to ban a user.
    #[serde(default = "default_power_level")]
    pub ban: Int,

    /// The level required to send specific event types.
    ///
    /// This is a mapping from event type to power level required.
    pub events: HashMap<EventType, Int>,

    /// The default level required to send message events.
    #[serde(default)]
    pub events_default: Int,

    /// The level required to invite a user.
    #[serde(default = "default_power_level")]
    pub invite: Int,

    /// The level required to kick a user.
    #[serde(default = "default_power_level")]
    pub kick: Int,

    /// The level required to redact an event.
    #[serde(default = "default_power_level")]
    pub redact: Int,

    /// The default level required to send state events.
    #[serde(default = "default_power_level")]
    pub state_default: Int,

    /// The power levels for specific users.
    ///
    /// This is a mapping from `user_id` to power level for that user.
    pub users: HashMap<UserId, Int>,

    /// The default power level for every user in the room.
    #[serde(default)]
    pub users_default: Int,

    /// The power level requirements for specific notification types.
    ///
    /// This is a mapping from `key` to power level for that notifications key.
    pub notifications: NotificationPowerLevels,
}

impl FromRaw for PowerLevelsEvent {
    type Raw = raw::PowerLevelsEvent;

    fn from_raw(raw: raw::PowerLevelsEvent) -> Self {
        Self {
            content: FromRaw::from_raw(raw.content),
            event_id: raw.event_id,
            origin_server_ts: raw.origin_server_ts,
            prev_content: raw.prev_content.map(FromRaw::from_raw),
            room_id: raw.room_id,
            unsigned: raw.unsigned,
            sender: raw.sender,
            state_key: raw.state_key,
        }
    }
}

impl FromRaw for PowerLevelsEventContent {
    type Raw = raw::PowerLevelsEventContent;

    fn from_raw(raw: raw::PowerLevelsEventContent) -> Self {
        Self {
            ban: raw.ban,
            events: raw.events,
            events_default: raw.events_default,
            invite: raw.invite,
            kick: raw.kick,
            redact: raw.redact,
            state_default: raw.state_default,
            users: raw.users,
            users_default: raw.users_default,
            notifications: raw.notifications,
        }
    }
}

impl Serialize for PowerLevelsEvent {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut len = 6;

        if self.prev_content.is_some() {
            len += 1;
        }

        if self.room_id.is_some() {
            len += 1;
        }

        if self.unsigned.is_some() {
            len += 1;
        }

        let mut state = serializer.serialize_struct("PowerLevelsEvent", len)?;

        state.serialize_field("content", &self.content)?;
        state.serialize_field("event_id", &self.event_id)?;
        state.serialize_field("origin_server_ts", &self.origin_server_ts)?;

        if self.prev_content.is_some() {
            state.serialize_field("prev_content", &self.prev_content)?;
        }

        if self.room_id.is_some() {
            state.serialize_field("room_id", &self.room_id)?;
        }

        state.serialize_field("sender", &self.sender)?;
        state.serialize_field("state_key", &self.state_key)?;
        state.serialize_field("type", &self.event_type())?;

        if self.unsigned.is_some() {
            state.serialize_field("unsigned", &self.unsigned)?;
        }

        state.end()
    }
}

impl_state_event!(
    PowerLevelsEvent,
    PowerLevelsEventContent,
    EventType::RoomPowerLevels
);

pub(crate) mod raw {
    use super::*;

    /// Defines the power levels (privileges) of users in the room.
    #[derive(Clone, Debug, Deserialize, PartialEq)]
    pub struct PowerLevelsEvent {
        /// The event's content.
        pub content: PowerLevelsEventContent,

        /// The unique identifier for the event.
        pub event_id: EventId,

        /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
        /// event was sent.
        pub origin_server_ts: UInt,

        /// The previous content for this state key, if any.
        pub prev_content: Option<PowerLevelsEventContent>,

        /// The unique identifier for the room associated with this event.
        pub room_id: Option<RoomId>,

        /// Additional key-value pairs not signed by the homeserver.
        pub unsigned: Option<Value>,

        /// The unique identifier for the user who sent this event.
        pub sender: UserId,

        /// A key that determines which piece of room state the event represents.
        pub state_key: String,
    }

    /// The payload for `PowerLevelsEvent`.
    #[derive(Clone, Debug, Deserialize, PartialEq)]
    pub struct PowerLevelsEventContent {
        /// The level required to ban a user.
        #[serde(default = "default_power_level")]
        pub ban: Int,

        /// The level required to send specific event types.
        ///
        /// This is a mapping from event type to power level required.
        pub events: HashMap<EventType, Int>,

        /// The default level required to send message events.
        #[serde(default)]
        pub events_default: Int,

        /// The level required to invite a user.
        #[serde(default = "default_power_level")]
        pub invite: Int,

        /// The level required to kick a user.
        #[serde(default = "default_power_level")]
        pub kick: Int,

        /// The level required to redact an event.
        #[serde(default = "default_power_level")]
        pub redact: Int,

        /// The default level required to send state events.
        #[serde(default = "default_power_level")]
        pub state_default: Int,

        /// The power levels for specific users.
        ///
        /// This is a mapping from `user_id` to power level for that user.
        pub users: HashMap<UserId, Int>,

        /// The default power level for every user in the room.
        #[serde(default)]
        pub users_default: Int,

        /// The power level requirements for specific notification types.
        ///
        /// This is a mapping from `key` to power level for that notifications key.
        pub notifications: NotificationPowerLevels,
    }
}

/// The power level requirements for specific notification types.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct NotificationPowerLevels {
    /// The level required to trigger an `@room` notification.
    #[serde(default = "default_power_level")]
    pub room: Int,
}

/// Used to default power levels to 50 during deserialization.
fn default_power_level() -> Int {
    Int::from(50)
}

#[cfg(test)]
mod tests {
    use std::{collections::HashMap, convert::TryFrom};

    use js_int::{Int, UInt};
    use ruma_identifiers::{EventId, RoomId, UserId};
    use serde_json::Value;

    use super::{NotificationPowerLevels, PowerLevelsEvent, PowerLevelsEventContent};

    #[test]
    fn serialization_with_optional_fields_as_none() {
        let default = Int::try_from(50).unwrap();

        let power_levels_event = PowerLevelsEvent {
            content: PowerLevelsEventContent {
                ban: default,
                events: HashMap::new(),
                events_default: default,
                invite: default,
                kick: default,
                redact: default,
                state_default: default,
                users: HashMap::new(),
                users_default: default,
                notifications: NotificationPowerLevels { room: default },
            },
            event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
            origin_server_ts: UInt::try_from(1).unwrap(),
            prev_content: None,
            room_id: None,
            unsigned: None,
            sender: UserId::try_from("@carl:example.com").unwrap(),
            state_key: "".to_string(),
        };

        let actual = serde_json::to_string(&power_levels_event).unwrap();
        let expected = r#"{"content":{"ban":50,"events":{},"events_default":50,"invite":50,"kick":50,"redact":50,"state_default":50,"users":{},"users_default":50,"notifications":{"room":50}},"event_id":"$h29iv0s8:example.com","origin_server_ts":1,"sender":"@carl:example.com","state_key":"","type":"m.room.power_levels"}"#;

        assert_eq!(actual, expected);
    }

    #[test]
    fn serialization_with_all_fields() {
        let default = Int::try_from(50).unwrap();

        let power_levels_event = PowerLevelsEvent {
            content: PowerLevelsEventContent {
                ban: default,
                events: HashMap::new(),
                events_default: default,
                invite: default,
                kick: default,
                redact: default,
                state_default: default,
                users: HashMap::new(),
                users_default: default,
                notifications: NotificationPowerLevels { room: default },
            },
            event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
            origin_server_ts: UInt::try_from(1).unwrap(),
            prev_content: Some(PowerLevelsEventContent {
                // Make just one field different so we at least know they're two different objects.
                ban: Int::try_from(75).unwrap(),
                events: HashMap::new(),
                events_default: default,
                invite: default,
                kick: default,
                redact: default,
                state_default: default,
                users: HashMap::new(),
                users_default: default,
                notifications: NotificationPowerLevels { room: default },
            }),
            room_id: Some(RoomId::try_from("!n8f893n9:example.com").unwrap()),
            unsigned: Some(serde_json::from_str::<Value>(r#"{"foo":"bar"}"#).unwrap()),
            sender: UserId::try_from("@carl:example.com").unwrap(),
            state_key: "".to_string(),
        };

        let actual = serde_json::to_string(&power_levels_event).unwrap();
        let expected = r#"{"content":{"ban":50,"events":{},"events_default":50,"invite":50,"kick":50,"redact":50,"state_default":50,"users":{},"users_default":50,"notifications":{"room":50}},"event_id":"$h29iv0s8:example.com","origin_server_ts":1,"prev_content":{"ban":75,"events":{},"events_default":50,"invite":50,"kick":50,"redact":50,"state_default":50,"users":{},"users_default":50,"notifications":{"room":50}},"room_id":"!n8f893n9:example.com","sender":"@carl:example.com","state_key":"","type":"m.room.power_levels","unsigned":{"foo":"bar"}}"#;

        assert_eq!(actual, expected);
    }
}
<commit_msg>Allow *all* m.room.power_levels fields to be absent<commit_after>//! Types for the *m.room.power_levels* event.

use std::collections::HashMap;

use js_int::{Int, UInt};
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use serde_json::Value;

use crate::{Event as _, EventType, FromRaw};

/// Defines the power levels (privileges) of users in the room.
#[derive(Clone, Debug, PartialEq)]
pub struct PowerLevelsEvent {
    /// The event's content.
    pub content: PowerLevelsEventContent,

    /// The unique identifier for the event.
    pub event_id: EventId,

    /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
    /// event was sent.
    pub origin_server_ts: UInt,

    /// The previous content for this state key, if any.
    pub prev_content: Option<PowerLevelsEventContent>,

    /// The unique identifier for the room associated with this event.
    pub room_id: Option<RoomId>,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: Option<Value>,

    /// The unique identifier for the user who sent this event.
    pub sender: UserId,

    /// A key that determines which piece of room state the event represents.
    pub state_key: String,
}

/// The payload for `PowerLevelsEvent`.
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct PowerLevelsEventContent {
    /// The level required to ban a user.
    #[serde(default = "default_power_level")]
    pub ban: Int,

    /// The level required to send specific event types.
    ///
    /// This is a mapping from event type to power level required.
    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
    pub events: HashMap<EventType, Int>,

    /// The default level required to send message events.
    #[serde(default)]
    pub events_default: Int,

    /// The level required to invite a user.
    #[serde(default = "default_power_level")]
    pub invite: Int,

    /// The level required to kick a user.
    #[serde(default = "default_power_level")]
    pub kick: Int,

    /// The level required to redact an event.
    #[serde(default = "default_power_level")]
    pub redact: Int,

    /// The default level required to send state events.
    #[serde(default = "default_power_level")]
    pub state_default: Int,

    /// The power levels for specific users.
    ///
    /// This is a mapping from `user_id` to power level for that user.
    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
    pub users: HashMap<UserId, Int>,

    /// The default power level for every user in the room.
    #[serde(default)]
    pub users_default: Int,

    /// The power level requirements for specific notification types.
    ///
    /// This is a mapping from `key` to power level for that notifications key.
    #[serde(default, skip_serializing_if = "NotificationPowerLevels::is_default")]
    pub notifications: NotificationPowerLevels,
}

impl FromRaw for PowerLevelsEvent {
    type Raw = raw::PowerLevelsEvent;

    fn from_raw(raw: raw::PowerLevelsEvent) -> Self {
        Self {
            content: FromRaw::from_raw(raw.content),
            event_id: raw.event_id,
            origin_server_ts: raw.origin_server_ts,
            prev_content: raw.prev_content.map(FromRaw::from_raw),
            room_id: raw.room_id,
            unsigned: raw.unsigned,
            sender: raw.sender,
            state_key: raw.state_key,
        }
    }
}

impl FromRaw for PowerLevelsEventContent {
    type Raw = raw::PowerLevelsEventContent;

    fn from_raw(raw: raw::PowerLevelsEventContent) -> Self {
        Self {
            ban: raw.ban,
            events: raw.events,
            events_default: raw.events_default,
            invite: raw.invite,
            kick: raw.kick,
            redact: raw.redact,
            state_default: raw.state_default,
            users: raw.users,
            users_default: raw.users_default,
            notifications: raw.notifications,
        }
    }
}

impl Serialize for PowerLevelsEvent {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut len = 6;

        if self.prev_content.is_some() {
            len += 1;
        }

        if self.room_id.is_some() {
            len += 1;
        }

        if self.unsigned.is_some() {
            len += 1;
        }

        let mut state = serializer.serialize_struct("PowerLevelsEvent", len)?;

        state.serialize_field("content", &self.content)?;
        state.serialize_field("event_id", &self.event_id)?;
        state.serialize_field("origin_server_ts", &self.origin_server_ts)?;

        if self.prev_content.is_some() {
            state.serialize_field("prev_content", &self.prev_content)?;
        }

        if self.room_id.is_some() {
            state.serialize_field("room_id", &self.room_id)?;
        }

        state.serialize_field("sender", &self.sender)?;
        state.serialize_field("state_key", &self.state_key)?;
        state.serialize_field("type", &self.event_type())?;

        if self.unsigned.is_some() {
            state.serialize_field("unsigned", &self.unsigned)?;
        }

        state.end()
    }
}

impl_state_event!(
    PowerLevelsEvent,
    PowerLevelsEventContent,
    EventType::RoomPowerLevels
);

pub(crate) mod raw {
    use super::*;

    /// Defines the power levels (privileges) of users in the room.
    #[derive(Clone, Debug, Deserialize, PartialEq)]
    pub struct PowerLevelsEvent {
        /// The event's content.
        pub content: PowerLevelsEventContent,

        /// The unique identifier for the event.
        pub event_id: EventId,

        /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
        /// event was sent.
        pub origin_server_ts: UInt,

        /// The previous content for this state key, if any.
        pub prev_content: Option<PowerLevelsEventContent>,

        /// The unique identifier for the room associated with this event.
        pub room_id: Option<RoomId>,

        /// Additional key-value pairs not signed by the homeserver.
        pub unsigned: Option<Value>,

        /// The unique identifier for the user who sent this event.
        pub sender: UserId,

        /// A key that determines which piece of room state the event represents.
        pub state_key: String,
    }

    /// The payload for `PowerLevelsEvent`.
    #[derive(Clone, Debug, Deserialize, PartialEq)]
    pub struct PowerLevelsEventContent {
        /// The level required to ban a user.
        #[serde(default = "default_power_level")]
        pub ban: Int,

        /// The level required to send specific event types.
        ///
        /// This is a mapping from event type to power level required.
        #[serde(default, skip_serializing_if = "HashMap::is_empty")]
        pub events: HashMap<EventType, Int>,

        /// The default level required to send message events.
        #[serde(default)]
        pub events_default: Int,

        /// The level required to invite a user.
        #[serde(default = "default_power_level")]
        pub invite: Int,

        /// The level required to kick a user.
        #[serde(default = "default_power_level")]
        pub kick: Int,

        /// The level required to redact an event.
        #[serde(default = "default_power_level")]
        pub redact: Int,

        /// The default level required to send state events.
        #[serde(default = "default_power_level")]
        pub state_default: Int,

        /// The power levels for specific users.
        ///
        /// This is a mapping from `user_id` to power level for that user.
        #[serde(default, skip_serializing_if = "HashMap::is_empty")]
        pub users: HashMap<UserId, Int>,

        /// The default power level for every user in the room.
        #[serde(default)]
        pub users_default: Int,

        /// The power level requirements for specific notification types.
        ///
        /// This is a mapping from `key` to power level for that notifications key.
        #[serde(default, skip_serializing_if = "NotificationPowerLevels::is_default")]
        pub notifications: NotificationPowerLevels,
    }
}

/// The power level requirements for specific notification types.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct NotificationPowerLevels {
    /// The level required to trigger an `@room` notification.
    #[serde(default = "default_power_level")]
    pub room: Int,
}

impl NotificationPowerLevels {
    // TODO: Make public under this name?
    // pass-by-ref required for #[serde(skip_serializing_if)]
    #[allow(clippy::trivially_copy_pass_by_ref)]
    fn is_default(&self) -> bool {
        *self == Self::default()
    }
}

impl Default for NotificationPowerLevels {
    fn default() -> Self {
        Self {
            room: default_power_level(),
        }
    }
}

/// Used to default power levels to 50 during deserialization.
fn default_power_level() -> Int {
    Int::from(50)
}

#[cfg(test)]
mod tests {
    use std::{collections::HashMap, convert::TryFrom};

    use js_int::{Int, UInt};
    use ruma_identifiers::{EventId, RoomId, UserId};
    use serde_json::Value;

    use super::{NotificationPowerLevels, PowerLevelsEvent, PowerLevelsEventContent};

    #[test]
    fn serialization_with_optional_fields_as_none() {
        let default = Int::try_from(50).unwrap();

        let power_levels_event = PowerLevelsEvent {
            content: PowerLevelsEventContent {
                ban: default,
                events: HashMap::new(),
                events_default: default,
                invite: default,
                kick: default,
                redact: default,
                state_default: default,
                users: HashMap::new(),
                users_default: default,
                notifications: NotificationPowerLevels { room: default },
            },
            event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
            origin_server_ts: UInt::try_from(1).unwrap(),
            prev_content: None,
            room_id: None,
            unsigned: None,
            sender: UserId::try_from("@carl:example.com").unwrap(),
            state_key: "".to_string(),
        };

        let actual = serde_json::to_string(&power_levels_event).unwrap();
        let expected = r#"{"content":{"ban":50,"events":{},"events_default":50,"invite":50,"kick":50,"redact":50,"state_default":50,"users":{},"users_default":50,"notifications":{"room":50}},"event_id":"$h29iv0s8:example.com","origin_server_ts":1,"sender":"@carl:example.com","state_key":"","type":"m.room.power_levels"}"#;

        assert_eq!(actual, expected);
    }

    #[test]
    fn serialization_with_all_fields() {
        let default = Int::try_from(50).unwrap();

        let power_levels_event = PowerLevelsEvent {
            content: PowerLevelsEventContent {
                ban: default,
                events: HashMap::new(),
                events_default: default,
                invite: default,
                kick: default,
                redact: default,
                state_default: default,
                users: HashMap::new(),
                users_default: default,
                notifications: NotificationPowerLevels { room: default },
            },
            event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
            origin_server_ts: UInt::try_from(1).unwrap(),
            prev_content: Some(PowerLevelsEventContent {
                // Make just one field different so we at least know they're two different objects.
                ban: Int::try_from(75).unwrap(),
                events: HashMap::new(),
                events_default: default,
                invite: default,
                kick: default,
                redact: default,
                state_default: default,
                users: HashMap::new(),
                users_default: default,
                notifications: NotificationPowerLevels { room: default },
            }),
            room_id: Some(RoomId::try_from("!n8f893n9:example.com").unwrap()),
            unsigned: Some(serde_json::from_str::<Value>(r#"{"foo":"bar"}"#).unwrap()),
            sender: UserId::try_from("@carl:example.com").unwrap(),
            state_key: "".to_string(),
        };

        let actual = serde_json::to_string(&power_levels_event).unwrap();
        let expected = r#"{"content":{"ban":50,"events":{},"events_default":50,"invite":50,"kick":50,"redact":50,"state_default":50,"users":{},"users_default":50,"notifications":{"room":50}},"event_id":"$h29iv0s8:example.com","origin_server_ts":1,"prev_content":{"ban":75,"events":{},"events_default":50,"invite":50,"kick":50,"redact":50,"state_default":50,"users":{},"users_default":50,"notifications":{"room":50}},"room_id":"!n8f893n9:example.com","sender":"@carl:example.com","state_key":"","type":"m.room.power_levels","unsigned":{"foo":"bar"}}"#;

        assert_eq!(actual, expected);
    }
}
<|endoftext|>


<commit_before>// mrusty. mruby bindings for Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use rl_sys::readline;
use rl_sys::history::{listmgmt, mgmt};

use super::mruby::*;

/// A `struct` that exposes an `MRuby` to a REPL. Requires `repl` build feature.
///
/// # Examples
///
/// ```no-run
/// # use mrusty::MRuby;
/// # use mrusty::Repl;
/// let mruby = MRuby::new();
/// let repl = Repl::new(mruby);
///
/// repl.start();
/// ```
#[cfg(feature = "repl")]
pub struct Repl {
    mruby: MRubyType
}

impl Repl {
    /// Creates a new `Repl`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// # use mrusty::Repl;
    /// let mruby = MRuby::new();
    /// let repl = Repl::new(mruby);
    /// ```
    pub fn new(mruby: MRubyType) -> Repl {
        mruby.filename("repl");

        Repl {
            mruby: mruby
        }
    }

    /// Starts a `Repl`.
    ///
    /// Use `'\'` for multiline statements.
    ///
    /// # Examples
    ///
    /// ```no-run
    /// # use mrusty::MRuby;
    /// # use mrusty::Repl;
    /// let mruby = MRuby::new();
    /// let repl = Repl::new(mruby);
    ///
    /// repl.start();
    /// ```
    pub fn start(&self) {
        let mut command = String::new();

        loop {
            let head = if command.is_empty() {
                "mrusty> "
            } else {
                "mrusty* "
            };

            let input = match readline::readline(head) {
                Ok(Some(s)) => s,
                Ok(None) => break,
                Err(e) => {
                    println!("{}", e);

                    break
                }
            };

            if input.ends_with("\\") {
                let trimmed = input.trim_right_matches("\\");

                command = command + trimmed + "\n";
                listmgmt::add(&trimmed).unwrap();

                continue
            } else {
                listmgmt::add(&input).unwrap();
            }

            if command == "" {
                command = input;
            } else {
                command = command + &input;
            }

            match self.mruby.run(&command) {
                Ok(value) => {
                    let result = value.call("to_s", vec![]).unwrap().to_str().unwrap();

                    println!("{}", result);
                },
                Err(message) => {
                    println!("{}", message);
                }
            }

            if !command.is_empty() {
                command = String::new();
            }
        }

        mgmt::cleanup();
    }
}
<commit_msg>Added new line after Repl close.<commit_after>// mrusty. mruby bindings for Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use rl_sys::readline;
use rl_sys::history::{listmgmt, mgmt};

use super::mruby::*;

/// A `struct` that exposes an `MRuby` to a REPL. Requires `repl` build feature.
///
/// # Examples
///
/// ```no-run
/// # use mrusty::MRuby;
/// # use mrusty::Repl;
/// let mruby = MRuby::new();
/// let repl = Repl::new(mruby);
///
/// repl.start();
/// ```
#[cfg(feature = "repl")]
pub struct Repl {
    mruby: MRubyType
}

impl Repl {
    /// Creates a new `Repl`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// # use mrusty::Repl;
    /// let mruby = MRuby::new();
    /// let repl = Repl::new(mruby);
    /// ```
    pub fn new(mruby: MRubyType) -> Repl {
        mruby.filename("repl");

        Repl {
            mruby: mruby
        }
    }

    /// Starts a `Repl`.
    ///
    /// Use `'\'` for multiline statements.
    ///
    /// # Examples
    ///
    /// ```no-run
    /// # use mrusty::MRuby;
    /// # use mrusty::Repl;
    /// let mruby = MRuby::new();
    /// let repl = Repl::new(mruby);
    ///
    /// repl.start();
    /// ```
    pub fn start(&self) {
        let mut command = String::new();

        loop {
            let head = if command.is_empty() {
                "mrusty> "
            } else {
                "mrusty* "
            };

            let input = match readline::readline(head) {
                Ok(Some(s)) => s,
                Ok(None) => break,
                Err(e) => {
                    println!("{}", e);

                    break
                }
            };

            if input.ends_with("\\") {
                let trimmed = input.trim_right_matches("\\");

                command = command + trimmed + "\n";
                listmgmt::add(&trimmed).unwrap();

                continue
            } else {
                listmgmt::add(&input).unwrap();
            }

            if command == "" {
                command = input;
            } else {
                command = command + &input;
            }

            match self.mruby.run(&command) {
                Ok(value) => {
                    let result = value.call("to_s", vec![]).unwrap().to_str().unwrap();

                    println!("{}", result);
                },
                Err(message) => {
                    println!("{}", message);
                }
            }

            if !command.is_empty() {
                command = String::new();
            }
        }

        mgmt::cleanup();

        println!("");
    }
}
<|endoftext|>


<commit_before>use std::io::fs;
use std::path::posix::Path;
use std::os::homedir;
#[cfg(test)] use test_helper::{cleanup_dir,random_name};

static MUXED_NAME_STR: &'static str = "muxed";
#[cfg(test)] static MUXED_PATH: Path = Path::new(format!("/tmp/.{}/", &MUXED_NAME_STR.to_string()));
//#[cfg(not_test)] static MUXED_DIR: Path = Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string()));

/// Create the muxed directory and return the path if creation is successful.
pub fn create_muxed_dir(name: &Path) -> Path {
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create muxed directory: {}", path.filename())
    }

    path.clone()
}

/// Return the users current homedir as a string.
pub fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

pub fn muxed_dir() -> Path {
    match MUXED_DIR.exists() {
        true  => MUXED_DIR,
        false => create_muxed_dir(MUXED_DIR)
    }
}

#[test]
fn muxed_dir_exists_returns_false() {
    assert!(!muxed_dir_exists(&random_name()));
}

#[test]
fn muxed_dir_exists_returns_true() {
    let dir = random_name();
    create_muxed_dir(&dir);
    assert!(muxed_dir_exists(&dir));

    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    cleanup_dir(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let dir = random_name();
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}
<commit_msg>Remove the static methods for paths in favour of functions.<commit_after>use std::io::fs;
use std::path::posix::Path;
use std::os::homedir;
#[cfg(test)] use test_helper::{cleanup_dir,random_name};

static MUXED_NAME_STR: &'static str = "muxed";

/// Create the muxed directory and return the path if creation is successful.
pub fn create_muxed_dir(name: &Path) -> Path {
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create muxed directory: {}", path.filename())
    }

    path.clone()
}

/// Return the users current homedir as a string.
pub fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

pub fn muxed_dir() -> Path {
    match MUXED_DIR.exists() {
        true  => MUXED_DIR,
        false => create_muxed_dir(MUXED_DIR)
    }
}

#[test]
fn muxed_dir_exists_returns_false() {
    assert!(!muxed_dir_exists(&random_name()));
}

#[test]
fn muxed_dir_exists_returns_true() {
    let dir = random_name();
    create_muxed_dir(&dir);
    assert!(muxed_dir_exists(&dir));

    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    cleanup_dir(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let dir = random_name();
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    cleanup_dir(muxed_path);
}
<|endoftext|>


<commit_before>use error::{Result, SassError, ErrorKind};
use std::str::FromStr;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SassOutputStyle {
    Expanded,
    Nested,
    Compact,
    Compressed,
    Debug,
    Tokens,
    AST,
}

impl FromStr for SassOutputStyle {
    type Err = SassError;
    fn from_str(s: &str) -> Result<Self> {
        match s {
            "nested"     => Ok(SassOutputStyle::Nested),
            "compressed" => Ok(SassOutputStyle::Compressed),
            "expanded"   => Ok(SassOutputStyle::Expanded),
            "compact"    => Ok(SassOutputStyle::Compact),
            "debug"      => Ok(SassOutputStyle::Debug),
            "tokens"     => Ok(SassOutputStyle::Tokens),
            "ast"        => Ok(SassOutputStyle::AST),
            style        => Err(SassError {
                offset: 0,
                kind: ErrorKind::InvalidOutputStyle,
                // Intentionally hiding debug/tokens/ast
                message: format!("Unknown output style {:?}. Please specify one of nested, compressed, expanded, or compact.", style),
            }),
        }
    }
}

impl SassOutputStyle {
    pub fn rule_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Compressed => "",
            _ => "\n\n",
        })
    }

    pub fn selector_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Compressed => ",",
            _ => ", ",
        })
    }

    pub fn selector_brace_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Compressed => "",
            _ => " ",
        })
    }

    pub fn brace_property_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Nested => "\n",
            SassOutputStyle::Expanded => "\n",
            SassOutputStyle::Compact => " ",
            _ => "",
        })
    }

    pub fn before_property(&self, nesting: &str) -> String {
        match *self {
            SassOutputStyle::Compact => String::from(""),
            SassOutputStyle::Compressed => String::from(""),
            SassOutputStyle::Nested => String::from(nesting),
            _ => String::from("\n"),
        }
    }

    pub fn after_property(&self) -> String {
        match *self {
            SassOutputStyle::Compact => String::from(" "),
            SassOutputStyle::Compressed => String::from(";"),
            _ => String::from("\n"),
        }
    }

    pub fn property_brace_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Nested => " ",
            SassOutputStyle::Expanded => "\n",
            SassOutputStyle::Compact => " ",
            _ => "",
        })
    }

    pub fn rule_and_child_rules_separator(&self, nesting: &str) -> String {
        match *self {
            SassOutputStyle::Nested => format!("\n{}", nesting),
            SassOutputStyle::Expanded => String::from("\n"),
            SassOutputStyle::Compact => String::from("\n"),
            _ => String::from(""),
        }
    }

    pub fn child_rule_separator(&self, has_properties: bool) -> String {
        String::from(match (*self, has_properties) {
            (SassOutputStyle::Nested, true) => "\n  ",
            (SassOutputStyle::Compressed, _) => "",
            (_, _) => "\n",
        })
    }
}
<commit_msg>Get rid of extra newlines in the expanded output<commit_after>use error::{Result, SassError, ErrorKind};
use std::str::FromStr;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SassOutputStyle {
    Expanded,
    Nested,
    Compact,
    Compressed,
    Debug,
    Tokens,
    AST,
}

impl FromStr for SassOutputStyle {
    type Err = SassError;
    fn from_str(s: &str) -> Result<Self> {
        match s {
            "nested"     => Ok(SassOutputStyle::Nested),
            "compressed" => Ok(SassOutputStyle::Compressed),
            "expanded"   => Ok(SassOutputStyle::Expanded),
            "compact"    => Ok(SassOutputStyle::Compact),
            "debug"      => Ok(SassOutputStyle::Debug),
            "tokens"     => Ok(SassOutputStyle::Tokens),
            "ast"        => Ok(SassOutputStyle::AST),
            style        => Err(SassError {
                offset: 0,
                kind: ErrorKind::InvalidOutputStyle,
                // Intentionally hiding debug/tokens/ast
                message: format!("Unknown output style {:?}. Please specify one of nested, compressed, expanded, or compact.", style),
            }),
        }
    }
}

impl SassOutputStyle {
    pub fn rule_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Compressed => "",
            _ => "\n\n",
        })
    }

    pub fn selector_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Compressed => ",",
            _ => ", ",
        })
    }

    pub fn selector_brace_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Compressed => "",
            _ => " ",
        })
    }

    pub fn brace_property_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Nested => "\n",
            SassOutputStyle::Expanded => "",
            SassOutputStyle::Compact => " ",
            _ => "",
        })
    }

    pub fn before_property(&self, nesting: &str) -> String {
        match *self {
            SassOutputStyle::Compact => String::from(""),
            SassOutputStyle::Compressed => String::from(""),
            SassOutputStyle::Nested => String::from(nesting),
            _ => String::from("\n"),
        }
    }

    pub fn after_property(&self) -> String {
        match *self {
            SassOutputStyle::Compact => String::from(" "),
            SassOutputStyle::Compressed => String::from(";"),
            SassOutputStyle::Nested => String::from("\n"),
            _ => String::from(""),
        }
    }

    pub fn property_brace_separator(&self) -> String {
        String::from(match *self {
            SassOutputStyle::Nested => " ",
            SassOutputStyle::Expanded => "\n",
            SassOutputStyle::Compact => " ",
            _ => "",
        })
    }

    pub fn rule_and_child_rules_separator(&self, nesting: &str) -> String {
        match *self {
            SassOutputStyle::Nested => format!("\n{}", nesting),
            SassOutputStyle::Expanded => String::from("\n"),
            SassOutputStyle::Compact => String::from("\n"),
            _ => String::from(""),
        }
    }

    pub fn child_rule_separator(&self, has_properties: bool) -> String {
        String::from(match (*self, has_properties) {
            (SassOutputStyle::Nested, true) => "\n  ",
            (SassOutputStyle::Compressed, _) => "",
            (_, _) => "\n",
        })
    }
}
<|endoftext|>


<commit_before>/*!

Suffix Array Construction

worst time: O(N)
worst space: N bytes (for input) + N words (for suffix array)

# Credit
Ge Nong and the team:
https://code.google.com/p/ge-nong/

*/

use std::{iter, vec};
use compress::bwt;

pub type Symbol = u8;
pub type Suffix = u32;

static EMPTY: Suffix = 0x80000000;

fn get_buckets(input: &[Symbol], buckets: &mut [uint], end: bool) {
	for buck in buckets.mut_iter() {
		*buck = 0;
	}
	for sym in input.iter() {
		buckets[*sym] += 1;
	}
	let mut sum = 0u;
	for buck in buckets.mut_iter() {
		sum += *buck;
		*buck = if end {sum} else {sum - *buck};
	}
}

fn put_substr0(suffixes: &mut [Suffix], input: &[Symbol], buckets: &mut [uint]) {
	// Find the end of each bucket.
	get_buckets(input, buckets, true);

	// Set each item in SA as empty.
	for suf in suffixes.mut_iter() {
		*suf = 0;
	}

	// Last string is L-type
	input.iter().zip(input.slice_from(1).iter()).enumerate().rev().fold(false, |succ_t, (i,(&prev,&cur))| {
		if prev < cur || (prev==cur && succ_t) {
			true
		}else {
			if succ_t {
				buckets[cur] -= 1;
				suffixes[buckets[cur]] = i as Suffix;
			}
			false
		}
	});

	// Set the single sentinel LMS-substring.
	*suffixes.mut_last().unwrap() = (input.len()-1) as Suffix;
}

fn induce_l0(suffixes: &mut [Suffix], input: &[Symbol], buckets: &mut [uint], clean: bool) {
	// Find the head of each bucket.
	get_buckets(input, buckets, false);

	buckets[0]+=1; // skip the virtual sentinel.

	for i in range(0,suffixes.len()) {
		let suf = suffixes[i];
		if suf > 0 {
			let sym = input[suf-1];
			if sym >= input[suf] {
				suffixes[buckets[sym]] = suf-1;
				buckets[sym] += 1;
				if clean && i>0 {
					suffixes[i] = 0;
				}
			}
		}
	}
}

fn induce_s0(suffixes: &mut [Suffix], input: &[Symbol], buckets: &mut [uint], clean: bool) {
	// Find the head of each bucket.
	get_buckets(input, buckets, true);

	for i in range(1,suffixes.len()).rev() {
		let suf = suffixes[i];
		if suf > 0 {
			let sym = input[suf-1];
			if sym <= input[suf] && buckets[sym] < i {
				buckets[sym] -= 1;
				suffixes[buckets[sym]] = suf-1;
				if clean {
					suffixes[i] = 0;
				}
			}
		}
	}
}

fn gather_lms(suffixes: &mut [Suffix], input: &[Suffix]) {
	//TODO

	for suf in suffixes.mut_iter() {
		*suf = input[*suf];
	}
}

fn put_suffix0(suffixes: &mut [Suffix], n1: uint, input: &[Symbol], buckets: &mut [uint]) {
	// Find the end of each bucket.
	get_buckets(input, buckets, true);

	for i in range(0,n1).rev() {
		let p = suffixes[i];
		suffixes[i] = 0;
		let sym = input[p];
		buckets[sym] -= 1;
		suffixes[buckets[sym]] = p;
	}

	// Set the single sentinel suffix.
	suffixes[0] = (input.len()-1) as Suffix;
}

fn name_substr(_suffixes: &mut [Suffix], _input: &[Symbol], _new_input: &[Suffix], _level: uint) -> uint {
	0 //TODO
}

fn saca_kn(input: &[Suffix], suffixes: &mut [Suffix], _level: uint) {
	//TODO

	let n1 = 0u;

	assert!(n1+n1 <= input.len());
	let (sa_new, input_new) = suffixes.mut_split_at(n1);
	//TODO

	// Stage 3: induce SA(S) from SA(S1).
	gather_lms(sa_new, input_new);
	for s in input_new.mut_iter() {
		*s = EMPTY;
	}

	//TODO
}

fn saca_k0(input: &[Symbol], K: uint, suffixes: &mut [Suffix]) {
	let mut buckets = vec::from_elem(K, 0u);

	// Stage 1: reduce the problem by at least 1/2.
	put_substr0(suffixes, input, buckets.as_mut_slice());
	induce_l0(suffixes, input, buckets.as_mut_slice(), true);
	induce_s0(suffixes, input, buckets.as_mut_slice(), true);

	// Now, all the LMS-substrings are sorted and stored sparsely in SA.
	// Compact all the sorted substrings into the first n1 items of SA.
	let mut n1 = 0u;
	for i in range(0, suffixes.len()) {
		if suffixes[i]>0 {
			suffixes[n1] = suffixes[i];
			n1 += 1;
		}
	}

	// Stage 2: solve the reduced problem.
	{
		assert!(n1+n1 <= input.len());
		let (sa_new, input_new) = suffixes.mut_split_at(n1);
		let num_names = name_substr(sa_new, input, input_new, 0);

		if num_names < n1 {
			// Recurse if names are not yet unique.
			saca_kn(input_new, sa_new, 1);
		}else {
			// Get the suffix array of s1 directly.
			for (i,&sym) in input_new.iter().enumerate() {
				sa_new[sym] = i as Suffix;
			}
		}

		// Stage 3: induce SA(S) from SA(S1).
		gather_lms(sa_new, input_new);
		for s in input_new.mut_iter() {
			*s = 0;
		}
	}

	put_suffix0(suffixes, n1, input, buckets.as_mut_slice());
	induce_l0(suffixes, input, buckets.as_mut_slice(), false);
	induce_s0(suffixes, input, buckets.as_mut_slice(), false);
}

/// main entry point for SAC
pub fn construct_suffix_array(input: &[Symbol], suffixes: &mut [Suffix]) {
	assert_eq!(input.len(), suffixes.len());
	for (i,p) in suffixes.mut_iter().enumerate() {
		*p = i as Suffix;
	}

	if true {
		saca_k0(input, 0x100, suffixes);
	}else {
		suffixes.sort_by(|&a,&b| {
			iter::order::cmp(
				input.slice_from(a as uint).iter(),
				input.slice_from(b as uint).iter())
		});
	}

	debug!("construct suf: {:?}", suffixes);
}

/// An iterator over BWT output
pub struct LastColumnIterator<'a> {
	priv input		: &'a [Symbol],
	priv suf_iter	: iter::Enumerate<vec::Items<'a,Suffix>>,
	priv origin		: Option<uint>,
}

impl<'a> LastColumnIterator<'a> {
	/// create a new BWT iterator from the suffix array
	pub fn new(input: &'a [Symbol], suffixes: &'a [Suffix]) -> LastColumnIterator<'a> {
		LastColumnIterator {
			input: input,
			suf_iter: suffixes.iter().enumerate(),
			origin: None,
		}
	}

	/// return the index of the original string
	pub fn get_origin(&self) -> uint {
		self.origin.unwrap()
	}
}

impl<'a> Iterator<Symbol> for LastColumnIterator<'a> {
	fn next(&mut self) -> Option<Symbol> {
		self.suf_iter.next().map(|(i,&p)| {
			if p == 0 {
				assert!( self.origin.is_none() );
				self.origin = Some(i);
				*self.input.last().unwrap()
			}else {
				self.input[p-1]
			}
		})
	}
}

/// A helper method to perform BWT on a given block and place the result into output
/// returns the original string index in the sorted matrix
pub fn BW_transform(input: &[Symbol], suf: &mut [Suffix], output: &mut [Symbol]) -> uint {
	construct_suffix_array(input, suf);
	let mut iter = LastColumnIterator::new(input, suf);
	for (out,s) in output.mut_iter().zip(iter.by_ref()) {
		*out = s;
	}
	iter.get_origin()
}

/// An iterator over inverse BWT
pub struct InverseIterator<'a> {
	priv input		: &'a [Symbol],
	priv suffixes	: &'a [Suffix],
	priv origin		: uint,
	priv current	: Suffix,
}

impl<'a> InverseIterator<'a> {
	/// create a new inverse BWT iterator
	pub fn new(input: &'a [Symbol], origin: uint, suffixes: &'a mut [Suffix]) -> InverseIterator<'a> {
		assert_eq!(input.len(), suffixes.len())
		debug!("decode origin={}, input: {:?}", origin, input)

		let mut radix = bwt::Radix::new();
		radix.gather(input);
		radix.accumulate();

		suffixes[radix.place(input[origin])] = 0;
		for (i,&ch) in input.slice_to(origin).iter().enumerate() {
			suffixes[radix.place(ch)] = (i+1) as Suffix;
		}
		for (i,&ch) in input.slice_from(origin+1).iter().enumerate() {
			suffixes[radix.place(ch)] = (origin+2+i) as Suffix;
		}
		//suffixes[-1] = origin;
		debug!("decode table: {:?}", suffixes)

		InverseIterator {
			input: input,
			suffixes: suffixes,
			origin: origin,
			current: origin as Suffix,
		}
	}
}

impl<'a> Iterator<Symbol> for InverseIterator<'a> {
	fn next(&mut self) -> Option<Symbol> {
		if self.current == -1 {
			None
		}else {
			self.current = self.suffixes[self.current] - 1;
			debug!("\tjumped to {}", self.current);
			let p = if self.current!=-1 {
				self.current
			}else {
				self.origin as Suffix
			};
			Some(self.input[p])
		}
	}
}

#[cfg(test)]
pub mod test {
	use std::{mem, vec};
	use super::{EMPTY, Suffix, Symbol};

	#[test]
	fn consts() {
		assert_eq!(EMPTY, 1<<(mem::size_of::<Suffix>()*8-1));
	}

	#[test]
	fn abracadabra() {
		let input = bytes!("abracadabra");
		let mut suf = vec::from_elem(input.len(), 0 as Suffix);
		super::construct_suffix_array(input, suf);
		assert_eq!(suf.as_slice(), &[10,7,0,3,5,8,1,4,6,9,2]);
		let (output, origin) = {
			let mut iter = super::LastColumnIterator::new(input,suf);
			let out = iter.by_ref().take(input.len()).to_owned_vec();
			(out, iter.get_origin())
		};
		assert_eq!(origin, 2);
		let expected = bytes!("rdarcaaaabb");
		assert_eq!(output.as_slice(), expected.as_slice());
		let decoded = super::InverseIterator::new(output, origin, suf).to_owned_vec();
		assert_eq!(input.as_slice(), decoded.as_slice());
	}

	#[test]
	fn roundtrip() {
		let input = include_bin!("../LICENSE");
		let mut suf = vec::from_elem(input.len(), 0 as Suffix);
		let mut output = vec::from_elem(input.len(), 0 as Symbol);
		let origin = super::BW_transform(input, suf, output);
		let decoded = super::InverseIterator::new(output, origin, suf).
			take(input.len()).to_owned_vec();
		assert_eq!(input.as_slice(), decoded.as_slice());
	}
}
<commit_msg>SACA - implemented the rest of level[0] routines, not operational yet.<commit_after>/*!

Suffix Array Construction

worst time: O(N)
worst space: N bytes (for input) + N words (for suffix array)

# Credit
Ge Nong and the team:
https://code.google.com/p/ge-nong/

*/

use std::{iter, vec};
use compress::bwt;

pub type Symbol = u8;
pub type Suffix = u32;

static EMPTY: Suffix = 0x80000000;

fn get_buckets(input: &[Symbol], buckets: &mut [uint], end: bool) {
	for buck in buckets.mut_iter() {
		*buck = 0;
	}
	for sym in input.iter() {
		buckets[*sym] += 1;
	}
	let mut sum = 0u;
	for buck in buckets.mut_iter() {
		sum += *buck;
		*buck = if end {sum} else {sum - *buck};
	}
}

fn put_substr0(suffixes: &mut [Suffix], input: &[Symbol], buckets: &mut [uint]) {
	// Find the end of each bucket.
	get_buckets(input, buckets, true);

	// Set each item in SA as empty.
	for suf in suffixes.mut_iter() {
		*suf = 0;
	}

	// Last string is L-type
	input.iter().zip(input.slice_from(1).iter()).enumerate().rev().fold(false, |succ_t, (i,(&prev,&cur))| {
		if prev < cur || (prev==cur && succ_t) {
			true
		}else {
			if succ_t {
				buckets[cur] -= 1;
				suffixes[buckets[cur]] = i as Suffix;
			}
			false
		}
	});

	// Set the single sentinel LMS-substring.
	*suffixes.mut_last().unwrap() = (input.len()-1) as Suffix;
}

fn induce_l0(suffixes: &mut [Suffix], input: &[Symbol], buckets: &mut [uint], clean: bool) {
	// Find the head of each bucket.
	get_buckets(input, buckets, false);

	buckets[0] += 1; // skip the virtual sentinel.

	for i in range(0,suffixes.len()) {
		let suf = suffixes[i];
		if suf > 0 {
			let sym = input[suf-1];
			if sym >= input[suf] {
				suffixes[buckets[sym]] = suf-1;
				buckets[sym] += 1;
				if clean && i>0 {
					suffixes[i] = 0;
				}
			}
		}
	}
}

fn induce_s0(suffixes: &mut [Suffix], input: &[Symbol], buckets: &mut [uint], clean: bool) {
	// Find the head of each bucket.
	get_buckets(input, buckets, true);

	for i in range(1,suffixes.len()).rev() {
		let suf = suffixes[i];
		if suf > 0 {
			let sym = input[suf-1];
			if sym <= input[suf] && buckets[sym] < i {
				buckets[sym] -= 1;
				suffixes[buckets[sym]] = suf-1;
				if clean {
					suffixes[i] = 0;
				}
			}
		}
	}
}

fn get_lms_length<T: Eq + Ord + Pod>(input: &[T]) -> uint {
	if input.len() == 1 {
		return 1
	}

	let mut dist = 0u;
	let mut i = 0u;
	while {i+=1; input[i-1] <= input[i]} {}

	loop {
		if i >= input.len()-0 || input[i-1] < input[i] {break}
		if i == input.len()-1 || input[i-1] > input[i] {dist=i}
		i += 1;
	}

	dist+1
}

fn name_substr<T: Eq + Ord + Pod>(new_suffixes: &mut [Suffix], new_input: &mut [Suffix], input: &[T]) -> uint {
	// Init the name array buffer.
	for suf in new_input.mut_iter() {
		*suf = EMPTY;
	}

 	// Scan to compute the interim s1.
	let mut pre_pos = 0u;
	let mut pre_len = 0u;
	let mut name = 0u;
	let mut name_count = 0u;
	for i in range(0, new_suffixes.len()) {
		let pos = new_suffixes[i] as uint;
		let len = get_lms_length(input.slice_from(pos));
		if len != pre_len || input.slice(pre_pos, pre_pos+len) != input.slice(pos, pos+len) {
			name = i;	// A new name.
			name_count += 1;
			new_suffixes[name] = 1;
			pre_pos = pos;
			pre_len = len;
		}else {
			new_suffixes[name] += 1;	// Count this name.
		}
		new_input[pos>>1] = name as Suffix;
	}

	// Compact the interim s1 sparsely stored in SA[n1, n-1] into SA[m-n1, m-1].
	{
		let non_empty = new_input.iter().rev().filter(|&s| *s!=EMPTY);
		for (suf, val) in new_suffixes.mut_iter().rev().zip(non_empty) {
			*suf = *val;
		}
	}

	// Rename each S-type character of the interim s1 as the end
	// of its bucket to produce the final s1.
	range(1, new_input.len()).rev().fold(true, |succ_t, i| {
		let prev = new_input[i-1];
		let cur = new_input[i];
		if prev < cur || (prev == cur && succ_t) {
			new_input[i-1] += new_suffixes[prev] - 1;
			true
		}else {
			false
		}
	});

	name_count
}

fn gather_lms<T: Eq + Ord + Pod>(new_suffixes: &mut [Suffix], new_input: &mut [Suffix], input: &[T] ) {
	let mut j = new_input.len();
	j -= 1;
	new_input[j] = (input.len()-1) as Suffix;

	// s[n-2] must be L-type
	input.iter().zip(input.slice_from(1).iter()).enumerate().rev().fold(false, |succ_t, (i,(&prev,&cur))| {
		if prev < cur || (prev == cur && succ_t) {
			true
		}else {
			if succ_t {
				j -= 1;
				new_input[j] = i as Suffix;
			}
			false
		}
	});

	for suf in new_suffixes.mut_iter() {
		*suf = new_input[*suf];
	}
}

fn put_suffix0(suffixes: &mut [Suffix], n1: uint, input: &[Symbol], buckets: &mut [uint]) {
	// Find the end of each bucket.
	get_buckets(input, buckets, true);

	for i in range(0,n1).rev() {
		let p = suffixes[i];
		suffixes[i] = 0;
		let sym = input[p];
		buckets[sym] -= 1;
		suffixes[buckets[sym]] = p;
	}

	// Set the single sentinel suffix.
	suffixes[0] = (input.len()-1) as Suffix;
}

fn saca_k1(input: &[Suffix], suffixes: &mut [Suffix], _level: uint) {
	//TODO
	let n1 = 0u;

	assert!(n1+n1 <= input.len());
	let (sa_new, input_new) = suffixes.mut_split_at(n1);
	//TODO

	// Stage 3: induce SA(S) from SA(S1).
	gather_lms(sa_new, input_new, input);
	for s in input_new.mut_iter() {
		*s = EMPTY;
	}

	unimplemented!()
	//TODO
}

fn saca_k0(input: &[Symbol], suffixes: &mut [Suffix], buckets: &mut [uint]) {
	// Stage 1: reduce the problem by at least 1/2.
	put_substr0(suffixes, input, buckets);
	induce_l0(suffixes, input, buckets, true);
	induce_s0(suffixes, input, buckets, true);

	// Now, all the LMS-substrings are sorted and stored sparsely in SA.
	// Compact all the sorted substrings into the first n1 items of SA.
	let mut n1 = 0u;
	for i in range(0, suffixes.len()) {
		if suffixes[i]>0 {
			suffixes[n1] = suffixes[i];
			n1 += 1;
		}
	}

	// Stage 2: solve the reduced problem.
	{
		assert!(n1+n1 <= input.len());
		let (sa_new, input_new) = suffixes.mut_split_at(n1);
		let num_names = name_substr(sa_new, input_new, input);

		if num_names < n1 {
			// Recurse if names are not yet unique.
			saca_k1(input_new, sa_new, 1);
		}else {
			// Get the suffix array of s1 directly.
			for (i,&sym) in input_new.iter().enumerate() {
				sa_new[sym] = i as Suffix;
			}
		}

		gather_lms(sa_new, input_new, input);
		for s in input_new.mut_iter() {
			*s = 0;
		}
	}

	// Stage 3: induce SA(S) from SA(S1).
	put_suffix0(suffixes, n1, input, buckets);
	induce_l0(suffixes, input, buckets, false);
	induce_s0(suffixes, input, buckets, false);
}

/// main entry point for SAC
pub fn construct_suffix_array(input: &[Symbol], suffixes: &mut [Suffix]) {
	assert_eq!(input.len(), suffixes.len());

	if true {
		let mut buckets = [0u, ..0x100];
		saca_k0(input, suffixes, buckets.as_mut_slice());
	}else {
		for (i,p) in suffixes.mut_iter().enumerate() {
			*p = i as Suffix;
		}
		suffixes.sort_by(|&a,&b| {
			iter::order::cmp(
				input.slice_from(a as uint).iter(),
				input.slice_from(b as uint).iter())
		});
	}

	debug!("construct suf: {:?}", suffixes);
}

/// An iterator over BWT output
pub struct LastColumnIterator<'a> {
	priv input		: &'a [Symbol],
	priv suf_iter	: iter::Enumerate<vec::Items<'a,Suffix>>,
	priv origin		: Option<uint>,
}

impl<'a> LastColumnIterator<'a> {
	/// create a new BWT iterator from the suffix array
	pub fn new(input: &'a [Symbol], suffixes: &'a [Suffix]) -> LastColumnIterator<'a> {
		LastColumnIterator {
			input: input,
			suf_iter: suffixes.iter().enumerate(),
			origin: None,
		}
	}

	/// return the index of the original string
	pub fn get_origin(&self) -> uint {
		self.origin.unwrap()
	}
}

impl<'a> Iterator<Symbol> for LastColumnIterator<'a> {
	fn next(&mut self) -> Option<Symbol> {
		self.suf_iter.next().map(|(i,&p)| {
			if p == 0 {
				assert!( self.origin.is_none() );
				self.origin = Some(i);
				*self.input.last().unwrap()
			}else {
				self.input[p-1]
			}
		})
	}
}

/// A helper method to perform BWT on a given block and place the result into output
/// returns the original string index in the sorted matrix
pub fn BW_transform(input: &[Symbol], suf: &mut [Suffix], output: &mut [Symbol]) -> uint {
	construct_suffix_array(input, suf);
	let mut iter = LastColumnIterator::new(input, suf);
	for (out,s) in output.mut_iter().zip(iter.by_ref()) {
		*out = s;
	}
	iter.get_origin()
}

/// An iterator over inverse BWT
pub struct InverseIterator<'a> {
	priv input		: &'a [Symbol],
	priv suffixes	: &'a [Suffix],
	priv origin		: uint,
	priv current	: Suffix,
}

impl<'a> InverseIterator<'a> {
	/// create a new inverse BWT iterator
	pub fn new(input: &'a [Symbol], origin: uint, suffixes: &'a mut [Suffix]) -> InverseIterator<'a> {
		assert_eq!(input.len(), suffixes.len())
		debug!("decode origin={}, input: {:?}", origin, input)

		let mut radix = bwt::Radix::new();
		radix.gather(input);
		radix.accumulate();

		suffixes[radix.place(input[origin])] = 0;
		for (i,&ch) in input.slice_to(origin).iter().enumerate() {
			suffixes[radix.place(ch)] = (i+1) as Suffix;
		}
		for (i,&ch) in input.slice_from(origin+1).iter().enumerate() {
			suffixes[radix.place(ch)] = (origin+2+i) as Suffix;
		}
		//suffixes[-1] = origin;
		debug!("decode table: {:?}", suffixes)

		InverseIterator {
			input: input,
			suffixes: suffixes,
			origin: origin,
			current: origin as Suffix,
		}
	}
}

impl<'a> Iterator<Symbol> for InverseIterator<'a> {
	fn next(&mut self) -> Option<Symbol> {
		if self.current == -1 {
			None
		}else {
			self.current = self.suffixes[self.current] - 1;
			debug!("\tjumped to {}", self.current);
			let p = if self.current!=-1 {
				self.current
			}else {
				self.origin as Suffix
			};
			Some(self.input[p])
		}
	}
}

#[cfg(test)]
pub mod test {
	use std::{mem, vec};
	use super::{EMPTY, Suffix, Symbol};

	#[test]
	fn consts() {
		assert_eq!(EMPTY, 1<<(mem::size_of::<Suffix>()*8-1));
	}

	#[test]
	fn abracadabra() {
		let input = bytes!("abracadabra");
		let mut suf = vec::from_elem(input.len(), 0 as Suffix);
		super::construct_suffix_array(input, suf);
		assert_eq!(suf.as_slice(), &[10,7,0,3,5,8,1,4,6,9,2]);
		let (output, origin) = {
			let mut iter = super::LastColumnIterator::new(input,suf);
			let out = iter.by_ref().take(input.len()).to_owned_vec();
			(out, iter.get_origin())
		};
		assert_eq!(origin, 2);
		let expected = bytes!("rdarcaaaabb");
		assert_eq!(output.as_slice(), expected.as_slice());
		let decoded = super::InverseIterator::new(output, origin, suf).to_owned_vec();
		assert_eq!(input.as_slice(), decoded.as_slice());
	}

	#[test]
	fn roundtrip() {
		let input = include_bin!("../LICENSE");
		let mut suf = vec::from_elem(input.len(), 0 as Suffix);
		let mut output = vec::from_elem(input.len(), 0 as Symbol);
		let origin = super::BW_transform(input, suf, output);
		let decoded = super::InverseIterator::new(output, origin, suf).
			take(input.len()).to_owned_vec();
		assert_eq!(input.as_slice(), decoded.as_slice());
	}
}
<|endoftext|>