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

use std::marker::PhantomData;
use std::collections::VecDeque;

/// A polygon with 4 points. Maps to `GL_QUADS`
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
pub struct Quad<T> {
    /// the first point of a quad
    pub x: T,
    /// the second point of a quad
    pub y: T,
    /// the third point of a quad
    pub z: T,
    /// the fourth point of a quad
    pub w: T,
}

impl<T> Quad<T> {
    /// create a new `Quad` with supplied vertices
    pub fn new(v0: T, v1: T, v2: T, v3: T) -> Quad<T> {
        Quad {
            x: v0,
            y: v1,
            z: v2,
            w: v3
        }
    }
}

/// A polygon with 3 points. Maps to `GL_TRIANGLE`
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
pub struct Triangle<T> {
    /// the first point of a triangle
    pub x: T,
    /// the second point of a triangle
    pub y: T,
    /// the third point of a triangle
    pub z: T,
}

impl<T> Triangle<T> {
    /// create a new `Triangle` with supplied vertcies
    pub fn new(v0: T, v1: T, v2: T) -> Triangle<T> {
        Triangle {
            x: v0,
            y: v1,
            z: v2
        }
    }
}

/// This is All-the-types container. This exists since some generators
/// produce both `Triangles` and `Quads`.
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum Polygon<T> {
    /// A wraped triangle
    PolyTri(Triangle<T>),
    /// A wraped quad
    PolyQuad(Quad<T>)
}

/// The core mechanism of `Vertices` trait. This is a mechanism for unwraping
/// a polygon extracting all of the vertices that it bound together.
pub trait EmitVertices<T> {
    /// Consume a polygon, each
    /// vertex is emitted to the parent function by calling the supplied
    /// lambda function
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T);
}

impl<T> EmitVertices<T> for Line<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Line{x, y} = self;
        emit(x);
        emit(y);
    }
}

impl<T> EmitVertices<T> for Triangle<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Triangle{x, y, z} = self;
        emit(x);
        emit(y);
        emit(z);
    }
}

impl<T> EmitVertices<T> for Quad<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Quad{x, y, z, w} = self;
        emit(x);
        emit(y);
        emit(z);
        emit(w);
    }
}

impl<T> EmitVertices<T> for Polygon<T> {
    fn emit_vertices<F>(self, emit: F) where F: FnMut(T) {
        use self::Polygon::{ PolyQuad, PolyTri };

        match self {
            PolyTri(p) => p.emit_vertices(emit),
            PolyQuad(p) => p.emit_vertices(emit)
        }
    }
}

/// Supplies a way to convert an iterator of polygons to an iterator
/// of vertices. Useful for when you need to write the vertices into
/// a graphics pipeline.
pub trait Vertices<SRC, V> {
    /// Convert a polygon iterator to a vertices iterator.
    fn vertices(self) -> VerticesIterator<SRC, V>;
}

impl<V, P: EmitVertices<V>, T: Iterator<Item=P>> Vertices<T, V> for T {
    fn vertices(self) -> VerticesIterator<T, V> {
        VerticesIterator {
            source: self,
            buffer: VecDeque::new()
        }
    }
}

/// an iterator that breaks a polygon down into its individual
/// verticies.
pub struct VerticesIterator<SRC, V> {
    source: SRC,
    buffer: VecDeque<V>
}

impl<V, U: EmitVertices<V>, SRC: Iterator<Item=U>> Iterator for VerticesIterator<SRC, V> {
    type Item = V;

    fn next(&mut self) -> Option<V> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_vertices(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}

/// equivalent of `map` but per-vertex
pub trait MapVertex<T, U> {
    /// `Output` should be a a container of the same shape of the type
    /// It's internal values should reflect any transformation the map did.
    type Output;
    /// map a function to each vertex in polygon creating a new polygon
    fn map_vertex<F>(self, mut map: F) -> Self::Output where F: FnMut(T) -> U;
}

impl<T: Clone, U> MapVertex<T, U> for Line<T> {
    type Output = Line<U>;

    fn map_vertex<F>(self, mut map: F) -> Line<U> where F: FnMut(T) -> U {
        let Line{x, y} = self;
        Line {
            x: map(x),
            y: map(y),
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Triangle<T> {
    type Output = Triangle<U>;

    fn map_vertex<F>(self, mut map: F) -> Triangle<U> where F: FnMut(T) -> U {
        let Triangle{x, y, z} = self;
        Triangle {
            x: map(x),
            y: map(y),
            z: map(z)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Quad<T> {
    type Output = Quad<U>;

    fn map_vertex<F>(self, mut map: F) -> Quad<U> where F: FnMut(T) -> U {
        let Quad{x, y, z, w} = self;
        Quad {
            x: map(x),
            y: map(y),
            z: map(z),
            w: map(w)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Polygon<T> {
    type Output = Polygon<U>;

    fn map_vertex<F>(self, map: F) -> Polygon<U> where F: FnMut(T) -> U {
        use self::Polygon::{ PolyTri, PolyQuad };

        match self {
            PolyTri(p) => PolyTri(p.map_vertex(map)),
            PolyQuad(p) => PolyQuad(p.map_vertex(map))
        }
    }
}

/// This acts very similar to a vertex shader. It gives a way to manipulate
/// and modify the vertices in a polygon. This is useful if you need to scale
/// the mesh using a matrix multiply, or just for modifying the type of each
/// vertex.
pub trait MapToVertices<T, U> {
    /// `Output` should be a a container of the same shape of the type
    /// It's internal values should reflect any transformation the map did.
    type Output;

    /// from a iterator of polygons, produces a iterator of polygons. Each
    /// vertex in the process is modified with the suppled function.
    fn vertex<F>(self, map: F) -> MapToVerticesIter<Self, T, U, F>
        where F: FnMut(T) -> U;
}

impl<VIn, VOut,
    P, POut: MapVertex<VIn, VOut, Output=P>,
    T: Iterator<Item=POut>>
    MapToVertices<VIn, VOut> for T {
    type Output = P;

    fn vertex<F>(self, map: F) -> MapToVerticesIter<T, VIn, VOut, F>
            where F: FnMut(VIn) -> VOut {

        MapToVerticesIter {
            src: self,
            f: map,
            phantom_t: PhantomData,
            phantom_u: PhantomData
        }
    }
}

struct MapToVerticesIter<SRC, T, U, F: FnMut(T) -> U> {
    src: SRC,
    f: F,
    phantom_t: PhantomData<T>,
    phantom_u: PhantomData<U>
}

impl<'a, P,
         POut: MapVertex<T, U, Output=P>,
         SRC: Iterator<Item=POut>,
         T, U, F: FnMut(T) -> U> Iterator for MapToVerticesIter<SRC, T, U, F> {
    type Item = P;

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.src.size_hint()
    }

    fn next(&mut self) -> Option<P> {
        self.src.next().map(|x| x.map_vertex(|x| (self.f)(x)))
    }
}

/// Represents a line
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash)]
pub struct Line<T> {
    /// the first point
    pub x: T,
    /// The second point
    pub y: T
}

impl<T> Line<T> {
    /// Create a new line using point x and y
    pub fn new(x: T, y: T) -> Line<T> {
        Line{x: x, y: y}
    }
}

/// Convert a Polygon into it's fragments
pub trait EmitLines {
    /// The Vertex defines the corners of a Polygon
    type Vertex;

    /// convert a polygon into lines, each line is emitted via
    /// calling of the callback of `emit` This allow for
    /// a variable amount of lines to be returned
    fn emit_lines<E>(self, emit: E)
        where E: FnMut(Line<Self::Vertex>);
}

impl<T: Clone> EmitLines for Triangle<T> {
    type Vertex = T;

    fn emit_lines<E>(self, mut emit: E)
        where E: FnMut(Line<T>)
    {
        emit(Line::new(self.x.clone(), self.y.clone()));
        emit(Line::new(self.y        , self.z.clone()));
        emit(Line::new(self.z        , self.x        ));
    }
}

impl<T: Clone> EmitLines for Quad<T> {
    type Vertex = T;

    fn emit_lines<E>(self, mut emit: E)
        where E: FnMut(Line<T>)
    {
        emit(Line::new(self.x.clone(), self.y.clone()));
        emit(Line::new(self.y        , self.z.clone()));
        emit(Line::new(self.z        , self.w.clone()));
        emit(Line::new(self.w        , self.x        ));
    }
}

impl<T: Clone> EmitLines for Polygon<T> {
    type Vertex = T;

    fn emit_lines<E>(self, emit: E)
        where E: FnMut(Line<T>)
    {
        match self {
            Polygon::PolyTri(x) => x.emit_lines(emit),
            Polygon::PolyQuad(x) => x.emit_lines(emit)
        }
    }
}

/// Creates an LinesIterator from another Iterator
pub trait Lines {
    /// The type of each point in the lines
    type Vertex;

    /// Convert the iterator into a LinesIterator
    fn lines(self) -> LinesIterator<Self, Self::Vertex>;
}

impl<T, P, V> Lines for T
    where T: Iterator<Item=P>,
          P: EmitLines<Vertex=V>
{
    type Vertex = V;

    fn lines(self) -> LinesIterator<T, V> {
        LinesIterator {
            source: self,
            buffer: VecDeque::new()
        }
    }
}

/// An iterator that turns Polygons into an Iterator of Lines
pub struct LinesIterator<I, V> {
    source: I,
    buffer: VecDeque<Line<V>>,
}

impl<I, P, V> Iterator for LinesIterator<I, V>
    where I: Iterator<Item=P>,
          P: EmitLines<Vertex=V>

{
    type Item = Line<V>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (n, _) = self.source.size_hint();
        (n, None)
    }

    fn next(&mut self) -> Option<Line<V>> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_lines(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}
<commit_msg>fix rfc 1214 fallout<commit_after>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

use std::marker::PhantomData;
use std::collections::VecDeque;

/// A polygon with 4 points. Maps to `GL_QUADS`
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
pub struct Quad<T> {
    /// the first point of a quad
    pub x: T,
    /// the second point of a quad
    pub y: T,
    /// the third point of a quad
    pub z: T,
    /// the fourth point of a quad
    pub w: T,
}

impl<T> Quad<T> {
    /// create a new `Quad` with supplied vertices
    pub fn new(v0: T, v1: T, v2: T, v3: T) -> Quad<T> {
        Quad {
            x: v0,
            y: v1,
            z: v2,
            w: v3
        }
    }
}

/// A polygon with 3 points. Maps to `GL_TRIANGLE`
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
pub struct Triangle<T> {
    /// the first point of a triangle
    pub x: T,
    /// the second point of a triangle
    pub y: T,
    /// the third point of a triangle
    pub z: T,
}

impl<T> Triangle<T> {
    /// create a new `Triangle` with supplied vertcies
    pub fn new(v0: T, v1: T, v2: T) -> Triangle<T> {
        Triangle {
            x: v0,
            y: v1,
            z: v2
        }
    }
}

/// This is All-the-types container. This exists since some generators
/// produce both `Triangles` and `Quads`.
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum Polygon<T> {
    /// A wraped triangle
    PolyTri(Triangle<T>),
    /// A wraped quad
    PolyQuad(Quad<T>)
}

/// The core mechanism of `Vertices` trait. This is a mechanism for unwraping
/// a polygon extracting all of the vertices that it bound together.
pub trait EmitVertices<T> {
    /// Consume a polygon, each
    /// vertex is emitted to the parent function by calling the supplied
    /// lambda function
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T);
}

impl<T> EmitVertices<T> for Line<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Line{x, y} = self;
        emit(x);
        emit(y);
    }
}

impl<T> EmitVertices<T> for Triangle<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Triangle{x, y, z} = self;
        emit(x);
        emit(y);
        emit(z);
    }
}

impl<T> EmitVertices<T> for Quad<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Quad{x, y, z, w} = self;
        emit(x);
        emit(y);
        emit(z);
        emit(w);
    }
}

impl<T> EmitVertices<T> for Polygon<T> {
    fn emit_vertices<F>(self, emit: F) where F: FnMut(T) {
        use self::Polygon::{ PolyQuad, PolyTri };

        match self {
            PolyTri(p) => p.emit_vertices(emit),
            PolyQuad(p) => p.emit_vertices(emit)
        }
    }
}

/// Supplies a way to convert an iterator of polygons to an iterator
/// of vertices. Useful for when you need to write the vertices into
/// a graphics pipeline.
pub trait Vertices<SRC, V> {
    /// Convert a polygon iterator to a vertices iterator.
    fn vertices(self) -> VerticesIterator<SRC, V>;
}

impl<V, P: EmitVertices<V>, T: Iterator<Item=P>> Vertices<T, V> for T {
    fn vertices(self) -> VerticesIterator<T, V> {
        VerticesIterator {
            source: self,
            buffer: VecDeque::new()
        }
    }
}

/// an iterator that breaks a polygon down into its individual
/// verticies.
pub struct VerticesIterator<SRC, V> {
    source: SRC,
    buffer: VecDeque<V>
}

impl<V, U: EmitVertices<V>, SRC: Iterator<Item=U>> Iterator for VerticesIterator<SRC, V> {
    type Item = V;

    fn next(&mut self) -> Option<V> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_vertices(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}

/// equivalent of `map` but per-vertex
pub trait MapVertex<T, U> {
    /// `Output` should be a a container of the same shape of the type
    /// It's internal values should reflect any transformation the map did.
    type Output;
    /// map a function to each vertex in polygon creating a new polygon
    fn map_vertex<F>(self, mut map: F) -> Self::Output where F: FnMut(T) -> U;
}

impl<T: Clone, U> MapVertex<T, U> for Line<T> {
    type Output = Line<U>;

    fn map_vertex<F>(self, mut map: F) -> Line<U> where F: FnMut(T) -> U {
        let Line{x, y} = self;
        Line {
            x: map(x),
            y: map(y),
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Triangle<T> {
    type Output = Triangle<U>;

    fn map_vertex<F>(self, mut map: F) -> Triangle<U> where F: FnMut(T) -> U {
        let Triangle{x, y, z} = self;
        Triangle {
            x: map(x),
            y: map(y),
            z: map(z)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Quad<T> {
    type Output = Quad<U>;

    fn map_vertex<F>(self, mut map: F) -> Quad<U> where F: FnMut(T) -> U {
        let Quad{x, y, z, w} = self;
        Quad {
            x: map(x),
            y: map(y),
            z: map(z),
            w: map(w)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Polygon<T> {
    type Output = Polygon<U>;

    fn map_vertex<F>(self, map: F) -> Polygon<U> where F: FnMut(T) -> U {
        use self::Polygon::{ PolyTri, PolyQuad };

        match self {
            PolyTri(p) => PolyTri(p.map_vertex(map)),
            PolyQuad(p) => PolyQuad(p.map_vertex(map))
        }
    }
}

/// This acts very similar to a vertex shader. It gives a way to manipulate
/// and modify the vertices in a polygon. This is useful if you need to scale
/// the mesh using a matrix multiply, or just for modifying the type of each
/// vertex.
pub trait MapToVertices<T, U>: Sized {
    /// `Output` should be a a container of the same shape of the type
    /// It's internal values should reflect any transformation the map did.
    type Output;

    /// from a iterator of polygons, produces a iterator of polygons. Each
    /// vertex in the process is modified with the suppled function.
    fn vertex<F>(self, map: F) -> MapToVerticesIter<Self, T, U, F>
        where F: FnMut(T) -> U;
}

impl<VIn, VOut,
    P, POut: MapVertex<VIn, VOut, Output=P>,
    T: Iterator<Item=POut>>
    MapToVertices<VIn, VOut> for T {
    type Output = P;

    fn vertex<F>(self, map: F) -> MapToVerticesIter<T, VIn, VOut, F>
            where F: FnMut(VIn) -> VOut {

        MapToVerticesIter {
            src: self,
            f: map,
            phantom_t: PhantomData,
            phantom_u: PhantomData
        }
    }
}

struct MapToVerticesIter<SRC, T, U, F: FnMut(T) -> U> {
    src: SRC,
    f: F,
    phantom_t: PhantomData<T>,
    phantom_u: PhantomData<U>
}

impl<'a, P,
         POut: MapVertex<T, U, Output=P>,
         SRC: Iterator<Item=POut>,
         T, U, F: FnMut(T) -> U> Iterator for MapToVerticesIter<SRC, T, U, F> {
    type Item = P;

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.src.size_hint()
    }

    fn next(&mut self) -> Option<P> {
        self.src.next().map(|x| x.map_vertex(|x| (self.f)(x)))
    }
}

/// Represents a line
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash)]
pub struct Line<T> {
    /// the first point
    pub x: T,
    /// The second point
    pub y: T
}

impl<T> Line<T> {
    /// Create a new line using point x and y
    pub fn new(x: T, y: T) -> Line<T> {
        Line{x: x, y: y}
    }
}

/// Convert a Polygon into it's fragments
pub trait EmitLines {
    /// The Vertex defines the corners of a Polygon
    type Vertex;

    /// convert a polygon into lines, each line is emitted via
    /// calling of the callback of `emit` This allow for
    /// a variable amount of lines to be returned
    fn emit_lines<E>(self, emit: E)
        where E: FnMut(Line<Self::Vertex>);
}

impl<T: Clone> EmitLines for Triangle<T> {
    type Vertex = T;

    fn emit_lines<E>(self, mut emit: E)
        where E: FnMut(Line<T>)
    {
        emit(Line::new(self.x.clone(), self.y.clone()));
        emit(Line::new(self.y        , self.z.clone()));
        emit(Line::new(self.z        , self.x        ));
    }
}

impl<T: Clone> EmitLines for Quad<T> {
    type Vertex = T;

    fn emit_lines<E>(self, mut emit: E)
        where E: FnMut(Line<T>)
    {
        emit(Line::new(self.x.clone(), self.y.clone()));
        emit(Line::new(self.y        , self.z.clone()));
        emit(Line::new(self.z        , self.w.clone()));
        emit(Line::new(self.w        , self.x        ));
    }
}

impl<T: Clone> EmitLines for Polygon<T> {
    type Vertex = T;

    fn emit_lines<E>(self, emit: E)
        where E: FnMut(Line<T>)
    {
        match self {
            Polygon::PolyTri(x) => x.emit_lines(emit),
            Polygon::PolyQuad(x) => x.emit_lines(emit)
        }
    }
}

/// Creates an LinesIterator from another Iterator
pub trait Lines: Sized {
    /// The type of each point in the lines
    type Vertex;

    /// Convert the iterator into a LinesIterator
    fn lines(self) -> LinesIterator<Self, Self::Vertex>;
}

impl<T, P, V> Lines for T
    where T: Iterator<Item=P>,
          P: EmitLines<Vertex=V>
{
    type Vertex = V;

    fn lines(self) -> LinesIterator<T, V> {
        LinesIterator {
            source: self,
            buffer: VecDeque::new()
        }
    }
}

/// An iterator that turns Polygons into an Iterator of Lines
pub struct LinesIterator<I, V> {
    source: I,
    buffer: VecDeque<Line<V>>,
}

impl<I, P, V> Iterator for LinesIterator<I, V>
    where I: Iterator<Item=P>,
          P: EmitLines<Vertex=V>

{
    type Item = Line<V>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (n, _) = self.source.size_hint();
        (n, None)
    }

    fn next(&mut self) -> Option<Line<V>> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_lines(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait, ButtonSignals, BoxTrait};
use gtk::{Orientation};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::{RefCell};

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget: gtk::WidgetTrait>(&mut self, title: &'a str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        self.tabs.push(tab);

        Some(index)
    }
}

struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<i64>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore
}

impl Procs {
    pub fn new<'a>(proc_list: &HashMap<usize, Process>) -> Procs {
        let left_tree = gtk::TreeView::new().unwrap();
        let scroll = gtk::ScrolledWindow::new(None, None).unwrap();
        let current_pid = Rc::new(RefCell::new(None));
        let kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task").unwrap()));
        let current_pid1 = current_pid.clone();
        let current_pid2 = current_pid.clone();
        let kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        append_column("pid", &mut columns);
        append_column("process name", &mut columns);
        append_column("cpu usage", &mut columns);
        append_column("memory usage (in kB)", &mut columns);

        for i in columns {
            left_tree.append_column(&i);
        }

        let mut list_store = gtk::ListStore::new(&[glib::Type::ISize, glib::Type::String, glib::Type::String, glib::Type::USize]).unwrap();
        for (_, pro) in proc_list {
            create_and_fill_model(&mut list_store, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
        }

        left_tree.set_model(&list_store.get_model().unwrap());
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    let model = tree_view.get_model().unwrap();
                    let mut iter = gtk::TreeIter::new();

                    if selection.get_selected(&model, &mut iter) {
                        let pid = Some(model.get_value(&iter, 0).get_long());
                        let mut tmp = current_pid1.borrow_mut();
                        *tmp = pid;
                    }
                    (*kill_button1.borrow_mut()).set_sensitive((*current_pid.borrow()).is_some());
                }
                None => {
                    let mut tmp = current_pid1.borrow_mut();
                    *tmp = None;
                }
            }
        });
        (*kill_button.borrow_mut()).set_sensitive(false);

        vertical_layout.add(&scroll);
        vertical_layout.add(&(*kill_button.borrow_mut()));
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout,
            list_store: list_store
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.set_resizable(true);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, cmdline: &str, name: &str, cpu: f32, memory: u64) {
    if cmdline.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    let mut val1 = glib::Value::new();
    val1.init(glib::Type::ISize);
    val1.set_long(pid);
    let mut val2 = glib::Value::new();
    val2.init(glib::Type::USize);
    val2.set_ulong(memory);
    list_store.append(&mut top_level);
    list_store.set_value(&top_level, 0, &val1);
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{:.1}", cpu));
    list_store.set_value(&top_level, 3, &val2);
}

fn update_window(list: &mut gtk::ListStore, system: Rc<RefCell<sysinfo::System>>, info: Rc<RefCell<DisplaySysInfo>>) {
    let model = list.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    (*system.borrow_mut()).refresh_all();
    let mut entries : HashMap<usize, Process> = ((*system.borrow()).get_process_list()).clone();
    let mut nb = model.iter_n_children(None);

    let sys = system.clone();
    (*info.borrow_mut()).update_ram_display(sys.clone());
    (*info.borrow_mut()).update_process_display(sys);

    let mut i = 0;
    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = model.get_value(&iter, 0).get_long();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    let mut val2 = glib::Value::new();
                    val2.init(glib::Type::USize);
                    val2.set_ulong(p.memory);
                    list.set_string(&iter, 2, &format!("{:.1}", p.cpu_usage));
                    list.set_value(&iter, 3, &val2);
                    to_delete = true;
                }
                None => {
                    list.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
    }
}

struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : Rc<RefCell<gtk::ProgressBar>>,
    swap : Rc<RefCell<gtk::ProgressBar>>,
    vertical_layout : gtk::Box
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>) -> DisplaySysInfo {
        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(Vec::new())),
            ram: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            swap: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            vertical_layout: gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap()
        };

        let sys2 = sys1.clone();
        let v = tmp.procs.clone();

        (*tmp.ram.borrow_mut()).set_show_text(true);
        (*tmp.swap.borrow_mut()).set_show_text(true);

        tmp.vertical_layout.set_spacing(5);
        let mut i = 0;
        let mut total = false;

        tmp.vertical_layout.pack_start(&gtk::Label::new("Memory usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.ram.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Swap usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.swap.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Total CPU usage").unwrap(), false, false, 15);
        for pro in (*sys1.borrow()).get_processor_list() {
            if total {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];
                let l = gtk::Label::new(&format!("{}", i)).unwrap();
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);
                horizontal_layout.pack_start(&l, false, false, 5);
                horizontal_layout.pack_start(p, true, true, 5);
                tmp.vertical_layout.add(&horizontal_layout);
            } else {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                tmp.vertical_layout.add(p);
                tmp.vertical_layout.pack_start(&gtk::Label::new("Process usage").unwrap(), false, false, 15);
                total = true;
            }
            i += 1;
        }
        tmp.update_ram_display(sys2);
        tmp
    }

    pub fn update_ram_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let total = (*sys.borrow()).get_total_memory();
        let used = (*sys.borrow()).get_used_memory();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        (*self.ram.borrow_mut()).set_text(&disp);
        (*self.ram.borrow_mut()).set_fraction(used as f64 / total as f64);

        let total = (*sys.borrow()).get_total_swap();
        let used = total - (*sys.borrow()).get_used_swap();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        (*self.swap.borrow_mut()).set_text(&disp);
        (*self.swap.borrow_mut()).set_fraction(used as f64 / total as f64);
    }

    pub fn update_process_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let v = &*self.procs.borrow_mut();
        let mut i = 0;

        for pro in (*sys.borrow()).get_processor_list() {
            v[i].set_text(&format!("{:.1} %", pro.get_cpu_usage() * 100.));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            i += 1;
        }
    }
}

fn main() {
    gtk::init();

    let window = gtk::Window::new(gtk::WindowType::Toplevel).unwrap();
    let sys : Rc<RefCell<sysinfo::System>> = Rc::new(RefCell::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    let mut procs = Procs::new((*sys.borrow()).get_process_list());
    let current_pid2 = procs.current_pid.clone();
    let sys1 = sys.clone();
    let sys2 = sys.clone();

    window.set_title("Process viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    (*sys.borrow_mut()).refresh_all();
    (*procs.kill_button.borrow_mut()).connect_clicked(move |_| {
        let tmp = (*current_pid2.borrow_mut()).is_some() ;

        if tmp {
            let s = (*current_pid2.borrow()).clone();
            match (*sys.borrow_mut()).get_process(s.unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let display_tab = Rc::new(RefCell::new(DisplaySysInfo::new(sys2)));

    //window.add(&vertical_layout);
    note.create_tab("Process list", &procs.vertical_layout);
    //let t = gtk::Button::new_with_label("test").unwrap();
    note.create_tab("System usage", &(*display_tab.borrow()).vertical_layout);

    glib::timeout_add(1500, move || {
        update_window(&mut procs.list_store, sys1.clone(), display_tab.clone());
        glib::Continue(true)
    });

    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<commit_msg>Update (partially) to last gtk version<commit_after>#![crate_type = "bin"]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait, ButtonSignals, BoxTrait};
use gtk::{Orientation};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::{RefCell};

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget: gtk::WidgetTrait>(&mut self, title: &'a str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        self.tabs.push(tab);

        Some(index)
    }
}

struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<i64>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore
}

impl Procs {
    pub fn new<'a>(proc_list: &HashMap<usize, Process>) -> Procs {
        let left_tree = gtk::TreeView::new().unwrap();
        let scroll = gtk::ScrolledWindow::new(None, None).unwrap();
        let current_pid = Rc::new(RefCell::new(None));
        let kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task").unwrap()));
        let current_pid1 = current_pid.clone();
        let current_pid2 = current_pid.clone();
        let kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        append_column("pid", &mut columns);
        append_column("process name", &mut columns);
        append_column("cpu usage", &mut columns);
        append_column("memory usage (in kB)", &mut columns);

        for i in columns {
            left_tree.append_column(&i);
        }

        let mut list_store = gtk::ListStore::new(&[glib::Type::ISize, glib::Type::String, glib::Type::String, glib::Type::USize]).unwrap();
        for (_, pro) in proc_list {
            create_and_fill_model(&mut list_store, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
        }

        left_tree.set_model(&list_store.get_model().unwrap());
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    if let Some((model, iter)) = selection.get_selected() {
                        let pid = Some(model.get_value(&iter, 0).get_long());
                        let mut tmp = current_pid1.borrow_mut();
                        *tmp = pid;
                    }
                    (*kill_button1.borrow_mut()).set_sensitive((*current_pid.borrow()).is_some());
                }
                None => {
                    let mut tmp = current_pid1.borrow_mut();
                    *tmp = None;
                }
            }
        });
        (*kill_button.borrow_mut()).set_sensitive(false);

        vertical_layout.add(&scroll);
        vertical_layout.add(&(*kill_button.borrow_mut()));
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout,
            list_store: list_store
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.set_resizable(true);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, cmdline: &str, name: &str, cpu: f32, memory: u64) {
    if cmdline.len() < 1 {
        return;
    }

    let mut val1 = glib::Value::new();
    val1.init(glib::Type::ISize);
    val1.set_long(pid);
    let mut val2 = glib::Value::new();
    val2.init(glib::Type::USize);
    val2.set_ulong(memory);
    let top_level = list_store.append();
    list_store.set_value(&top_level, 0, &val1);
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{:.1}", cpu));
    list_store.set_value(&top_level, 3, &val2);
}

fn update_window(list: &mut gtk::ListStore, system: Rc<RefCell<sysinfo::System>>, info: Rc<RefCell<DisplaySysInfo>>) {
    let model = list.get_model().unwrap();

    (*system.borrow_mut()).refresh_all();
    let mut entries : HashMap<usize, Process> = ((*system.borrow()).get_process_list()).clone();
    let mut nb = model.iter_n_children(None);

    let sys = system.clone();
    (*info.borrow_mut()).update_ram_display(sys.clone());
    (*info.borrow_mut()).update_process_display(sys);

    let mut i = 0;
    while i < nb {
        if let Some(mut iter) = model.iter_nth_child(None, i) {
            let pid : i64 = model.get_value(&iter, 0).get_long();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    let mut val2 = glib::Value::new();
                    val2.init(glib::Type::USize);
                    val2.set_ulong(p.memory);
                    list.set_string(&iter, 2, &format!("{:.1}", p.cpu_usage));
                    list.set_value(&iter, 3, &val2);
                    to_delete = true;
                }
                None => {
                    list.remove(&mut iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
    }
}

struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : Rc<RefCell<gtk::ProgressBar>>,
    swap : Rc<RefCell<gtk::ProgressBar>>,
    vertical_layout : gtk::Box
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>) -> DisplaySysInfo {
        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(Vec::new())),
            ram: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            swap: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            vertical_layout: gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap()
        };

        let sys2 = sys1.clone();
        let v = tmp.procs.clone();

        (*tmp.ram.borrow_mut()).set_show_text(true);
        (*tmp.swap.borrow_mut()).set_show_text(true);

        tmp.vertical_layout.set_spacing(5);
        let mut i = 0;
        let mut total = false;

        tmp.vertical_layout.pack_start(&gtk::Label::new("Memory usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.ram.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Swap usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.swap.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Total CPU usage").unwrap(), false, false, 15);
        for pro in (*sys1.borrow()).get_processor_list() {
            if total {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];
                let l = gtk::Label::new(&format!("{}", i)).unwrap();
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);
                horizontal_layout.pack_start(&l, false, false, 5);
                horizontal_layout.pack_start(p, true, true, 5);
                tmp.vertical_layout.add(&horizontal_layout);
            } else {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                tmp.vertical_layout.add(p);
                tmp.vertical_layout.pack_start(&gtk::Label::new("Process usage").unwrap(), false, false, 15);
                total = true;
            }
            i += 1;
        }
        tmp.update_ram_display(sys2);
        tmp
    }

    pub fn update_ram_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let total = (*sys.borrow()).get_total_memory();
        let used = (*sys.borrow()).get_used_memory();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        (*self.ram.borrow_mut()).set_text(&disp);
        (*self.ram.borrow_mut()).set_fraction(used as f64 / total as f64);

        let total = (*sys.borrow()).get_total_swap();
        let used = total - (*sys.borrow()).get_used_swap();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        (*self.swap.borrow_mut()).set_text(&disp);
        (*self.swap.borrow_mut()).set_fraction(used as f64 / total as f64);
    }

    pub fn update_process_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let v = &*self.procs.borrow_mut();
        let mut i = 0;

        for pro in (*sys.borrow()).get_processor_list() {
            v[i].set_text(&format!("{:.1} %", pro.get_cpu_usage() * 100.));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            i += 1;
        }
    }
}

fn main() {
    gtk::init();

    let window = gtk::Window::new(gtk::WindowType::Toplevel).unwrap();
    let sys : Rc<RefCell<sysinfo::System>> = Rc::new(RefCell::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    let mut procs = Procs::new((*sys.borrow()).get_process_list());
    let current_pid2 = procs.current_pid.clone();
    let sys1 = sys.clone();
    let sys2 = sys.clone();

    window.set_title("Process viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    (*sys.borrow_mut()).refresh_all();
    (*procs.kill_button.borrow_mut()).connect_clicked(move |_| {
        let tmp = (*current_pid2.borrow_mut()).is_some() ;

        if tmp {
            let s = (*current_pid2.borrow()).clone();
            match (*sys.borrow_mut()).get_process(s.unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let display_tab = Rc::new(RefCell::new(DisplaySysInfo::new(sys2)));

    //window.add(&vertical_layout);
    note.create_tab("Process list", &procs.vertical_layout);
    //let t = gtk::Button::new_with_label("test").unwrap();
    note.create_tab("System usage", &(*display_tab.borrow()).vertical_layout);

    glib::timeout_add(1500, move || {
        update_window(&mut procs.list_store, sys1.clone(), display_tab.clone());
        glib::Continue(true)
    });

    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::mem;

use futures::{Async, Future, AsyncSink};
use futures::sink::{Sink};
use futures::sync::oneshot;
use minihttp::Status;
use minihttp::server::{Error, RecvMode};
use minihttp::server as http;
use tokio_core::io::Io;

use config::Config;
use config::proxy::Proxy;
use incoming::{Request, Input, Debug, Reply, Encoder, Context, IntoContext};
use default_error_page::error_page;
use http_pools::HttpPools;
use proxy:: {RepReq, HalfReq, Response, backend};

enum State {
    Headers(HalfReq),
    Sent {
        /// Mostly to resend the request
        request: RepReq,
        response: oneshot::Receiver<Response>,
    },
    Error(Status),
    Void,
}

pub struct Codec {
    settings: Arc<Proxy>,
    pools: HttpPools,
    state: State,
    context: Option<Context>,
}

impl<S: Io + 'static> http::Codec<S> for Codec {
    type ResponseFuture = Reply<S>;
    fn recv_mode(&mut self) -> RecvMode {
        if self.settings.stream_requests {
            unimplemented!();
        } else {
            RecvMode::BufferedUpfront(self.settings.max_payload_size)
        }
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, Error>
    {
        if self.settings.stream_requests {
            unimplemented!();
        }
        self.state = match mem::replace(&mut self.state, State::Void) {
            State::Error(e) => State::Error(e),
            State::Headers(r) => {
                assert!(end);
                let r = r.upgrade(data.to_vec());
                let mut up = self.pools.upstream(
                    &self.settings.destination.upstream);
                let (tx, rx) = oneshot::channel();
                let codec = Box::new(backend::Codec::new(r.clone(), tx));
                match up.get_mut().get_mut() {
                    Some(pool) => {
                        match pool.start_send(codec) {
                            Ok(AsyncSink::NotReady(r)) => {
                                State::Error(Status::ServiceUnavailable)
                            }
                            Ok(AsyncSink::Ready) => {
                                debug!("Sent request {:?} to proxy", r);
                                State::Sent {
                                    request: r,
                                    response: rx,
                                }
                            }
                            Err(e) => {
                                error!("Error sending to pool {:?}: {}",
                                    self.settings.destination.upstream, e);
                                State::Error(Status::InternalServerError)
                            }
                        }
                    }
                    None => {
                        error!("No such pool {:?}",
                            self.settings.destination.upstream);
                        State::Error(Status::NotFound)
                    }
                }
            }
            State::Sent { .. } => unimplemented!(),
            State::Void => unreachable!(),
        };
        return Ok(Async::Ready(data.len()));
    }
    fn start_response(&mut self, e: http::Encoder<S>) -> Reply<S> {
        if self.settings.stream_requests {
            unimplemented!();
        } else {
            let ctx = self.context.take().unwrap();
            match mem::replace(&mut self.state, State::Void) {
                State::Sent { response, .. } => {
                    Box::new(response.and_then(move |resp| {
                        let e = Encoder::new(e, ctx);
                        Ok(resp.encode(e))
                    }).map_err(|e| -> Error { unimplemented!() }))
                }
                State::Error(status) => {
                    Box::new(error_page(status, Encoder::new(e, ctx)))
                }
                _ => unreachable!(),
            }
        }
    }
}

impl Codec {
    pub fn new(settings: &Arc<Proxy>, inp: Input) -> Codec {
        Codec {
            settings: settings.clone(),
            pools: inp.runtime.http_pools.clone(),
            state: State::Headers(HalfReq::from_input(&inp)),
            context: Some(inp.into_context()),
        }
    }
}
<commit_msg>Process proxy backend errors better<commit_after>use std::sync::Arc;
use std::mem;

use futures::{Async, Future, AsyncSink};
use futures::future::{ok};
use futures::sink::{Sink};
use futures::sync::oneshot;
use minihttp::Status;
use minihttp::server::{Error, RecvMode};
use minihttp::server as http;
use tokio_core::io::Io;

use config::proxy::Proxy;
use incoming::{Input, Debug, Reply, Encoder, Context, IntoContext};
use default_error_page::error_page;
use http_pools::HttpPools;
use proxy:: {RepReq, HalfReq, Response, backend};

enum State {
    Headers(HalfReq),
    Sent {
        /// Mostly to resend the request
        request: RepReq,
        response: oneshot::Receiver<Response>,
    },
    Error(Status),
    Void,
}

pub struct Codec {
    settings: Arc<Proxy>,
    pools: HttpPools,
    state: State,
    context: Option<Context>,
}

impl<S: Io + 'static> http::Codec<S> for Codec {
    type ResponseFuture = Reply<S>;
    fn recv_mode(&mut self) -> RecvMode {
        if self.settings.stream_requests {
            unimplemented!();
        } else {
            RecvMode::BufferedUpfront(self.settings.max_payload_size)
        }
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, Error>
    {
        if self.settings.stream_requests {
            unimplemented!();
        }
        self.state = match mem::replace(&mut self.state, State::Void) {
            State::Error(e) => State::Error(e),
            State::Headers(r) => {
                assert!(end);
                let r = r.upgrade(data.to_vec());
                let mut up = self.pools.upstream(
                    &self.settings.destination.upstream);
                let (tx, rx) = oneshot::channel();
                let codec = Box::new(backend::Codec::new(r.clone(), tx));
                match up.get_mut().get_mut() {
                    Some(pool) => {
                        match pool.start_send(codec) {
                            Ok(AsyncSink::NotReady(r)) => {
                                State::Error(Status::ServiceUnavailable)
                            }
                            Ok(AsyncSink::Ready) => {
                                debug!("Sent request {:?} to proxy", r);
                                State::Sent {
                                    request: r,
                                    response: rx,
                                }
                            }
                            Err(e) => {
                                error!("Error sending to pool {:?}: {}",
                                    self.settings.destination.upstream, e);
                                State::Error(Status::InternalServerError)
                            }
                        }
                    }
                    None => {
                        error!("No such pool {:?}",
                            self.settings.destination.upstream);
                        State::Error(Status::NotFound)
                    }
                }
            }
            State::Sent { .. } => unimplemented!(),
            State::Void => unreachable!(),
        };
        return Ok(Async::Ready(data.len()));
    }
    fn start_response(&mut self, e: http::Encoder<S>) -> Reply<S> {
        if self.settings.stream_requests {
            unimplemented!();
        } else {
            let ctx = self.context.take().unwrap();
            match mem::replace(&mut self.state, State::Void) {
                State::Sent { response, .. } => {
                    Box::new(response.then(move |result| {
                        let e = Encoder::new(e, ctx);
                        match result {
                            Ok(resp) => {
                                ok(resp.encode(e))
                            }
                            Err(err) => {
                                debug!("Proxy request error: {:?}", err);
                                error_page(Status::BadGateway, e)
                            }
                        }
                    }))
                }
                State::Error(status) => {
                    Box::new(error_page(status, Encoder::new(e, ctx)))
                }
                _ => unreachable!(),
            }
        }
    }
}

impl Codec {
    pub fn new(settings: &Arc<Proxy>, inp: Input) -> Codec {
        Codec {
            settings: settings.clone(),
            pools: inp.runtime.http_pools.clone(),
            state: State::Headers(HalfReq::from_input(&inp)),
            context: Some(inp.into_context()),
        }
    }
}
<|endoftext|>


<commit_before>use std;
use std::collections::HashSet;
use std::io::Cursor;
use std::mem;
use std::ops::{Deref, Range};
use std::rc::Rc;

use digest::Digest;
use serde_json;
use sha2::Sha256;
use url::Url;
use url_serde;

use resman::ResMan;
use super::routegraph::RouteGraph;
use super::adjlist::AdjList;

#[derive(Debug)]
pub enum Error {
    /// No effect matches the metadata requested.
    NoMatchingEffect(EffectId),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

/// Serializable info needed to look up an effect.
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectId {
    /// Canonical name of the effect
    name: String,
    /// Hash of the effect's definition file, or None if the effect is primitive
    sha256: Option<[u8; 32]>,
    // TODO: consider a smallset.
    // TODO: use #[serde(with = "url_serde")]
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
}

/// All information that will be loaded from disk/network to describe how to
/// synthesize the Effect.
#[derive(Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectDesc {
    meta: EffectMeta,
    adjlist: AdjList,
}

/// Validated version of `EffectDesc`. Guaranteed to be synthesizable.
#[derive(Debug)]
pub struct Effect {
    meta: EffectMeta,
    // TODO: Effects are immutable, so we can make this an AdjList and store
    // the connectivity information separately.
    data: EffectData,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectMeta {
    id: EffectId,
    inputs: Vec<EffectInput>,
    outputs: Vec<EffectOutput>,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectIO {
    name: String,
    channel: u8,
}
pub type EffectInput = EffectIO;
pub type EffectOutput = EffectIO;

/// Implementation details of an Effect.
/// Either its route graph, a primitive effect, etc.
#[derive(Debug)]
pub enum EffectData {
    RouteGraph(RouteGraph),
    Primitive(PrimitiveEffect),
}

/// Effects that cannot be decomposed; they have no implementation details and
/// must be implemented directly by the renderer.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PrimitiveEffect {
    /// Primitive Delay effect
    Delay,
    /// Primitive Constant effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    F32Constant,
    /// Sum 2 floating point streams.
    Sum2,
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// Primitive effect to calculate A/B.
    /// Note: because not all floating point numbers have inverses,
    /// A * (1/B) != A/B. Hence, we need division (not inversion) for proper
    /// precision.
    Divide,
    /// Primitive effect to calculate A%B (true modulo; not remainder.
    /// Result, y,  is always positive: y is bounded by [0, B).
    Modulo,
    /// Primitive effect to return the sample-wise minimum of two input streams.
    /// Max(A, B) can be implemented as -Min(-A, -B).
    /// The choice to define Min instead of Max was mostly arbitrary,
    /// and chosen because Min is more common in linear programming to avoid dealing
    /// with Inf.
    Minimum,
}

/// Iterator over the outputs of a F32Constant primitive effect
pub struct F32ConstIterator {
    loc: Range<u32>,
}

impl Effect {
    pub fn are_slots_connected(&self, from_slot: u32, to_slot: u32) -> bool {
        match self.data {
            EffectData::RouteGraph(ref g) => g.are_slots_connected(from_slot, to_slot),
            // For primitive effects, we assume ALL slots are connected.
            _ => true,
        }
    }
    pub fn id(&self) -> &EffectId {
        &self.meta.id
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    /// Given the effect's information, and an interface by which to load
    /// resources, return an actual Effect.
    pub fn from_id(id: EffectId, resman: &ResMan) -> ResultE<Rc<Self>> {
        // For primitive effects, don't attempt to locate their descriptions (they don't exist)
        let prim_effect = id.get_primitive_url().and_then(PrimitiveEffect::from_url);
        // Attempt to instantiate a primitive effect, if the URL matched.
        if let Some(prim_effect) = prim_effect {
            if id.sha256 == None {
                let me = Self {
                    meta: EffectMeta {
                        // sha256 was already verified; no need to update it
                        id: id,
                        // Primitive effects have undocumented I/O;
                        inputs: Default::default(),
                        outputs: Default::default(),
                    },
                    data: EffectData::Primitive(prim_effect),
                };
                return Ok(Rc::new(me));
            } else {
                warn!("Attempted to load a primitive Effect, but cannot because of mismatched sha256: {:?}", id.sha256);
            }
        }

        // Locate descriptions for non-primitive effects
        for (path, reader) in resman.find_effect(&id) {
            // Try to deserialize to an effect description
            let desc: Result<EffectDesc, serde_json::Error> = serde_json::from_reader(reader);
            match desc {
                Ok(mut desc) => {
                    if desc.meta.id.name() == id.name() {
                        desc.update_id();
                        match RouteGraph::from_adjlist(desc.adjlist, resman) {
                            Ok(graph) => {
                                let me = Self {
                                    meta: desc.meta,
                                    data: EffectData::RouteGraph(graph),
                                };
                                // TODO: implement some form of caching
                                return Ok(Rc::new(me));
                            },
                            Err(error) => warn!("[{:?}] RouteGraph::from_adjlist failed: {:?}", path, error)
                        }
                    } else {
                        trace!("[{:?}] Effect names differ: wanted {:?} got {:?}", path, id.name(), desc.meta.id.name());
                    }
                },
                Err(error) => {
                    warn!("[{:?}] Unable to deserialize EffectDesc: {:?}", path, error)
                }
            }
        }
        // No matching effects
        Err(Error::NoMatchingEffect(id))
    }
    pub fn data(&self) -> &EffectData {
        &self.data
    }
}

impl EffectId {
    pub fn new<U>(name: String, sha256: Option<[u8; 32]>, urls: U) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            sha256,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
        }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn sha256(&self) -> &Option<[u8; 32]> {
        &self.sha256
    }
    /// Returns true if the effect cannot be decomposed.
    /// This is determined by the effect providing a SINGLE url, with the primitive:// Schema
    pub fn is_primitive(&self) -> bool {
        self.urls.len() == 1 && self.urls.iter().all(|url| {
            url.scheme() == "primitive"
        })
    }
    pub fn get_primitive_url(&self) -> Option<&Url> {
        if self.is_primitive() {
            self.urls.iter().next().map(|url| url.deref())
        } else {
            None
        }
    }
}

impl EffectDesc {
    pub fn new(meta: EffectMeta, adjlist: AdjList) -> Self {
        Self{ meta, adjlist }
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    /// Make sure the id is fully populated with hashes, etc.
    fn update_id(&mut self) {
        if self.meta.id.sha256.is_none() {
            // TODO: calculate sha using a smaller buffer
            let as_vec = serde_json::to_vec(self).unwrap();
            let result = Sha256::digest_reader(&mut Cursor::new(as_vec)).unwrap();
            let mut hash: [u8; 32] = Default::default();
            hash.copy_from_slice(result.as_slice());
            self.meta.id.sha256 = Some(hash);
        }
    }
}

impl EffectMeta {
    pub fn new<U>(name: String, urls: U, inputs: Vec<EffectInput>, outputs: Vec<EffectOutput>) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            id: EffectId::new(name, None, urls),
            inputs,
            outputs,
        }
    }
    pub fn name(&self) -> &str {
        self.id.name()
    }
    pub fn inputs<'a>(&'a self) -> Box<Iterator<Item=EffectInput> + 'a> {
        match self.prim_effect() {
            Some(PrimitiveEffect::Delay) => Box::new(vec![
                    EffectInput::new("source".into(), 0),
                    EffectInput::new("frames".into(), 0)
                ].into_iter()),
            Some(PrimitiveEffect::F32Constant) => Box::new([].iter().cloned()),
            Some(PrimitiveEffect::Sum2) | Some(PrimitiveEffect::Multiply) | Some(PrimitiveEffect::Minimum) => Box::new(vec![
                    EffectInput::new("source".into(), 0),
                    EffectInput::new("source2".into(), 0),
                ].into_iter()),
            Some(PrimitiveEffect::Divide) | Some(PrimitiveEffect::Modulo) => Box::new(vec![
                    EffectInput::new("source".into(), 0),
                    EffectInput::new("divisor".into(), 0),
                ].into_iter()),
            _ => Box::new(self.inputs.iter().cloned())
        }
    }
    pub fn outputs<'a>(&'a self) -> Box<Iterator<Item=EffectOutput> + 'a> {
        match self.prim_effect() {
            Some(PrimitiveEffect::F32Constant) => Box::new(F32ConstIterator::new()),
            Some(_) => Box::new(Some(EffectOutput::new("result".into(), 0)).into_iter()),
            None => Box::new(self.outputs.iter().cloned())
        }
    }
    pub fn inputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=EffectInput> + 'a {
        self.inputs().filter(move |item| item.name() == name)
    }
    pub fn outputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=EffectOutput> + 'a {
        self.outputs().filter(move |item| item.name() == name)
    }
    pub fn is_valid_input(&self, slotno: u32) -> bool {
        self.inputs().nth(slotno as usize).is_some()
    }
    pub fn is_valid_output(&self, slotno: u32) -> bool {
        self.outputs().nth(slotno as usize).is_some()
    }
    fn prim_effect(&self) -> Option<PrimitiveEffect> {
        self.id.get_primitive_url().and_then(PrimitiveEffect::from_url)
    }
}

impl EffectIO {
    pub fn new(name: String, channel: u8) -> Self {
        Self{ name, channel }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn channel(&self) -> u8 {
        self.channel
    }
    pub fn is_source(&self) -> bool {
        self.name == "source"
    }
    pub fn is_result(&self) -> bool {
        self.name == "result"
    }
}

impl PrimitiveEffect {
    fn from_url(url: &Url) -> Option<Self> {
        if url.scheme() == "primitive" {
            match url.path() {
                "/Delay"       => Some(PrimitiveEffect::Delay),
                "/F32Constant" => Some(PrimitiveEffect::F32Constant),
                "/Sum2"        => Some(PrimitiveEffect::Sum2),
                "/Multiply"    => Some(PrimitiveEffect::Multiply),
                "/Divide"      => Some(PrimitiveEffect::Divide),
                "/Modulo"      => Some(PrimitiveEffect::Modulo),
                "/Minimum"     => Some(PrimitiveEffect::Minimum),
                _ => {
                    warn!("Unrecognized primitive effect: {} (full url: {})", url.path(), url);
                    None
                }
            }
        } else {
            None
        }
    }
}

impl PartialEq for EffectMeta {
    // Equality implemented in a way where we can easily check things like
    //   "Is this the same primitive Delay effect this renderer knows how to implement?"
    fn eq(&self, other: &EffectMeta) -> bool {
        self.id.name == other.id.name &&
            self.id.urls == other.id.urls
    }
}
impl Eq for EffectMeta {}

impl F32ConstIterator {
    fn new() -> Self {
        Self{ loc: (0..std::u32::MAX) }
    }
    fn to_f32(v: u32) -> f32 {
        unsafe { mem::transmute(v) }
    }
    fn to_output(v: u32) -> EffectOutput {
        let name = format!("const{}", Self::to_f32(v));
        EffectOutput::new(name, 0)
    }
}

impl Iterator for F32ConstIterator {
    type Item = EffectOutput;
    fn next(&mut self) -> Option<Self::Item> {
        self.loc.next().map(Self::to_output)
    }
    fn nth(&mut self, n: usize) -> Option<Self::Item> {
        self.loc.nth(n).map(Self::to_output)
    }
}
<commit_msg>Re-add removed utility methods<commit_after>use std;
use std::collections::HashSet;
use std::io::Cursor;
use std::mem;
use std::ops::{Deref, Range};
use std::rc::Rc;

use digest::Digest;
use serde_json;
use sha2::Sha256;
use url::Url;
use url_serde;

use resman::ResMan;
use super::routegraph::RouteGraph;
use super::adjlist::AdjList;

#[derive(Debug)]
pub enum Error {
    /// No effect matches the metadata requested.
    NoMatchingEffect(EffectId),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

/// Serializable info needed to look up an effect.
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectId {
    /// Canonical name of the effect
    name: String,
    /// Hash of the effect's definition file, or None if the effect is primitive
    sha256: Option<[u8; 32]>,
    // TODO: consider a smallset.
    // TODO: use #[serde(with = "url_serde")]
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
}

/// All information that will be loaded from disk/network to describe how to
/// synthesize the Effect.
#[derive(Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectDesc {
    meta: EffectMeta,
    adjlist: AdjList,
}

/// Validated version of `EffectDesc`. Guaranteed to be synthesizable.
#[derive(Debug)]
pub struct Effect {
    meta: EffectMeta,
    // TODO: Effects are immutable, so we can make this an AdjList and store
    // the connectivity information separately.
    data: EffectData,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectMeta {
    id: EffectId,
    inputs: Vec<EffectInput>,
    outputs: Vec<EffectOutput>,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectIO {
    name: String,
    channel: u8,
}
pub type EffectInput = EffectIO;
pub type EffectOutput = EffectIO;

/// Implementation details of an Effect.
/// Either its route graph, a primitive effect, etc.
#[derive(Debug)]
pub enum EffectData {
    RouteGraph(RouteGraph),
    Primitive(PrimitiveEffect),
}

/// Effects that cannot be decomposed; they have no implementation details and
/// must be implemented directly by the renderer.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PrimitiveEffect {
    /// Primitive Delay effect
    Delay,
    /// Primitive Constant effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    F32Constant,
    /// Sum 2 floating point streams.
    Sum2,
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// Primitive effect to calculate A/B.
    /// Note: because not all floating point numbers have inverses,
    /// A * (1/B) != A/B. Hence, we need division (not inversion) for proper
    /// precision.
    Divide,
    /// Primitive effect to calculate A%B (true modulo; not remainder.
    /// Result, y,  is always positive: y is bounded by [0, B).
    Modulo,
    /// Primitive effect to return the sample-wise minimum of two input streams.
    /// Max(A, B) can be implemented as -Min(-A, -B).
    /// The choice to define Min instead of Max was mostly arbitrary,
    /// and chosen because Min is more common in linear programming to avoid dealing
    /// with Inf.
    Minimum,
}

/// Iterator over the outputs of a F32Constant primitive effect
pub struct F32ConstIterator {
    loc: Range<u32>,
}

impl Effect {
    pub fn are_slots_connected(&self, from_slot: u32, to_slot: u32) -> bool {
        match self.data {
            EffectData::RouteGraph(ref g) => g.are_slots_connected(from_slot, to_slot),
            // For primitive effects, we assume ALL slots are connected.
            _ => true,
        }
    }
    pub fn id(&self) -> &EffectId {
        &self.meta.id
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    /// Given the effect's information, and an interface by which to load
    /// resources, return an actual Effect.
    pub fn from_id(id: EffectId, resman: &ResMan) -> ResultE<Rc<Self>> {
        // For primitive effects, don't attempt to locate their descriptions (they don't exist)
        let prim_effect = id.get_primitive_url().and_then(PrimitiveEffect::from_url);
        // Attempt to instantiate a primitive effect, if the URL matched.
        if let Some(prim_effect) = prim_effect {
            if id.sha256 == None {
                let me = Self {
                    meta: EffectMeta {
                        // sha256 was already verified; no need to update it
                        id: id,
                        // Primitive effects have undocumented I/O;
                        inputs: Default::default(),
                        outputs: Default::default(),
                    },
                    data: EffectData::Primitive(prim_effect),
                };
                return Ok(Rc::new(me));
            } else {
                warn!("Attempted to load a primitive Effect, but cannot because of mismatched sha256: {:?}", id.sha256);
            }
        }

        // Locate descriptions for non-primitive effects
        for (path, reader) in resman.find_effect(&id) {
            // Try to deserialize to an effect description
            let desc: Result<EffectDesc, serde_json::Error> = serde_json::from_reader(reader);
            match desc {
                Ok(mut desc) => {
                    if desc.meta.id.name() == id.name() {
                        desc.update_id();
                        match RouteGraph::from_adjlist(desc.adjlist, resman) {
                            Ok(graph) => {
                                let me = Self {
                                    meta: desc.meta,
                                    data: EffectData::RouteGraph(graph),
                                };
                                // TODO: implement some form of caching
                                return Ok(Rc::new(me));
                            },
                            Err(error) => warn!("[{:?}] RouteGraph::from_adjlist failed: {:?}", path, error)
                        }
                    } else {
                        trace!("[{:?}] Effect names differ: wanted {:?} got {:?}", path, id.name(), desc.meta.id.name());
                    }
                },
                Err(error) => {
                    warn!("[{:?}] Unable to deserialize EffectDesc: {:?}", path, error)
                }
            }
        }
        // No matching effects
        Err(Error::NoMatchingEffect(id))
    }
    pub fn data(&self) -> &EffectData {
        &self.data
    }
}

impl EffectId {
    pub fn new<U>(name: String, sha256: Option<[u8; 32]>, urls: U) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            sha256,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
        }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn sha256(&self) -> &Option<[u8; 32]> {
        &self.sha256
    }
    /// Returns true if the effect cannot be decomposed.
    /// This is determined by the effect providing a SINGLE url, with the primitive:// Schema
    pub fn is_primitive(&self) -> bool {
        self.urls.len() == 1 && self.urls.iter().all(|url| {
            url.scheme() == "primitive"
        })
    }
    pub fn get_primitive_url(&self) -> Option<&Url> {
        if self.is_primitive() {
            self.urls.iter().next().map(|url| url.deref())
        } else {
            None
        }
    }
}

impl EffectDesc {
    pub fn new(meta: EffectMeta, adjlist: AdjList) -> Self {
        Self{ meta, adjlist }
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    pub fn id(&self) -> &EffectId {
        &self.meta.id
    }
    pub fn adjlist(&self) -> &AdjList {
        &self.adjlist
    }
    /// Make sure the id is fully populated with hashes, etc.
    fn update_id(&mut self) {
        if self.meta.id.sha256.is_none() {
            // TODO: calculate sha using a smaller buffer
            let as_vec = serde_json::to_vec(self).unwrap();
            let result = Sha256::digest_reader(&mut Cursor::new(as_vec)).unwrap();
            let mut hash: [u8; 32] = Default::default();
            hash.copy_from_slice(result.as_slice());
            self.meta.id.sha256 = Some(hash);
        }
    }
}

impl EffectMeta {
    pub fn new<U>(name: String, urls: U, inputs: Vec<EffectInput>, outputs: Vec<EffectOutput>) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            id: EffectId::new(name, None, urls),
            inputs,
            outputs,
        }
    }
    pub fn name(&self) -> &str {
        self.id.name()
    }
    pub fn inputs<'a>(&'a self) -> Box<Iterator<Item=EffectInput> + 'a> {
        match self.prim_effect() {
            Some(PrimitiveEffect::Delay) => Box::new(vec![
                    EffectInput::new("source".into(), 0),
                    EffectInput::new("frames".into(), 0)
                ].into_iter()),
            Some(PrimitiveEffect::F32Constant) => Box::new([].iter().cloned()),
            Some(PrimitiveEffect::Sum2) | Some(PrimitiveEffect::Multiply) | Some(PrimitiveEffect::Minimum) => Box::new(vec![
                    EffectInput::new("source".into(), 0),
                    EffectInput::new("source2".into(), 0),
                ].into_iter()),
            Some(PrimitiveEffect::Divide) | Some(PrimitiveEffect::Modulo) => Box::new(vec![
                    EffectInput::new("source".into(), 0),
                    EffectInput::new("divisor".into(), 0),
                ].into_iter()),
            _ => Box::new(self.inputs.iter().cloned())
        }
    }
    pub fn outputs<'a>(&'a self) -> Box<Iterator<Item=EffectOutput> + 'a> {
        match self.prim_effect() {
            Some(PrimitiveEffect::F32Constant) => Box::new(F32ConstIterator::new()),
            Some(_) => Box::new(Some(EffectOutput::new("result".into(), 0)).into_iter()),
            None => Box::new(self.outputs.iter().cloned())
        }
    }
    pub fn inputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=EffectInput> + 'a {
        self.inputs().filter(move |item| item.name() == name)
    }
    pub fn outputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=EffectOutput> + 'a {
        self.outputs().filter(move |item| item.name() == name)
    }
    pub fn is_valid_input(&self, slotno: u32) -> bool {
        self.inputs().nth(slotno as usize).is_some()
    }
    pub fn is_valid_output(&self, slotno: u32) -> bool {
        self.outputs().nth(slotno as usize).is_some()
    }
    fn prim_effect(&self) -> Option<PrimitiveEffect> {
        self.id.get_primitive_url().and_then(PrimitiveEffect::from_url)
    }
}

impl EffectIO {
    pub fn new(name: String, channel: u8) -> Self {
        Self{ name, channel }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn channel(&self) -> u8 {
        self.channel
    }
    pub fn is_source(&self) -> bool {
        self.name == "source"
    }
    pub fn is_result(&self) -> bool {
        self.name == "result"
    }
}

impl PrimitiveEffect {
    fn from_url(url: &Url) -> Option<Self> {
        if url.scheme() == "primitive" {
            match url.path() {
                "/Delay"       => Some(PrimitiveEffect::Delay),
                "/F32Constant" => Some(PrimitiveEffect::F32Constant),
                "/Sum2"        => Some(PrimitiveEffect::Sum2),
                "/Multiply"    => Some(PrimitiveEffect::Multiply),
                "/Divide"      => Some(PrimitiveEffect::Divide),
                "/Modulo"      => Some(PrimitiveEffect::Modulo),
                "/Minimum"     => Some(PrimitiveEffect::Minimum),
                _ => {
                    warn!("Unrecognized primitive effect: {} (full url: {})", url.path(), url);
                    None
                }
            }
        } else {
            None
        }
    }
}

impl PartialEq for EffectMeta {
    // Equality implemented in a way where we can easily check things like
    //   "Is this the same primitive Delay effect this renderer knows how to implement?"
    fn eq(&self, other: &EffectMeta) -> bool {
        self.id.name == other.id.name &&
            self.id.urls == other.id.urls
    }
}
impl Eq for EffectMeta {}

impl F32ConstIterator {
    fn new() -> Self {
        Self{ loc: (0..std::u32::MAX) }
    }
    fn to_f32(v: u32) -> f32 {
        unsafe { mem::transmute(v) }
    }
    fn to_output(v: u32) -> EffectOutput {
        let name = format!("const{}", Self::to_f32(v));
        EffectOutput::new(name, 0)
    }
}

impl Iterator for F32ConstIterator {
    type Item = EffectOutput;
    fn next(&mut self) -> Option<Self::Item> {
        self.loc.next().map(Self::to_output)
    }
    fn nth(&mut self, n: usize) -> Option<Self::Item> {
        self.loc.nth(n).map(Self::to_output)
    }
}
<|endoftext|>