<commit_before>#[macro_use(assert_diff)]
extern crate difference;
extern crate env_logger;
#[macro_use]
extern crate pretty_assertions;

extern crate gluon;
extern crate gluon_base as base;
extern crate gluon_format as format;

use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;

use gluon::{Compiler, VmBuilder};

fn format_expr(expr: &str) -> gluon::Result<String> {
    let mut compiler = Compiler::new();
    let thread = VmBuilder::new()
        .import_paths(Some(vec!["..".into()]))
        .build();
    format::format_expr(&mut compiler, &thread, "test", expr)
}

fn test_format(name: &str) {
    let _ = env_logger::try_init();

    let mut contents = String::new();
    File::open(Path::new("../").join(name))
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();

    let mut compiler = Compiler::new();
    let thread = VmBuilder::new()
        .import_paths(Some(vec!["..".into()]))
        .build();
    let out_str = format::format_expr(&mut compiler, &thread, name, &contents)
        .unwrap_or_else(|err| panic!("{}", err));

    if contents != out_str {
        let args: Vec<_> = env::args().collect();
        let out_path = Path::new(&args[0][..])
            .parent()
            .and_then(|p| p.parent())
            .expect("folder")
            .join(Path::new(name).file_name().unwrap());
        File::create(out_path)
            .unwrap()
            .write_all(out_str.as_bytes())
            .unwrap();

        assert_diff!(&contents, &out_str, " ", 0);
    }
}

#[test]
fn bool() {
    test_format("std/bool.glu");
}

#[test]
fn char() {
    test_format("std/char.glu");
}

#[test]
fn function() {
    test_format("std/function.glu");
}

#[test]
fn map() {
    test_format("std/map.glu");
}

#[test]
fn option() {
    test_format("std/option.glu");
}

#[test]
fn prelude() {
    test_format("std/prelude.glu");
}

#[test]
fn result() {
    test_format("std/result.glu");
}

#[test]
fn state() {
    test_format("std/state.glu");
}

#[test]
fn stream() {
    test_format("std/stream.glu");
}

#[test]
fn string() {
    test_format("std/string.glu");
}

#[test]
fn test() {
    test_format("std/test.glu");
}

#[test]
fn types() {
    test_format("std/types.glu");
}

#[test]
fn unit() {
    test_format("std/unit.glu");
}

#[test]
fn writer() {
    test_format("std/writer.glu");
}

#[test]
fn parser() {
    test_format("std/parser.glu");
}

#[test]
fn random() {
    test_format("std/random.glu");
}

#[test]
fn repl() {
    test_format("repl/src/repl.glu");
}

#[test]
fn dont_add_newline_for_let_literal() {
    let expr = r#"
let x = 1
x
"#;
    assert_eq!(
        &format_expr(expr).unwrap(),
        r#"
let x = 1
x
"#
    );
}

#[test]
fn dont_lose_information_in_literals() {
    let expr = r#"
3.14 "\t\n\r\""
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn implicit_arg() {
    let expr = r#"
f ?32 ""
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn preserve_comment_between_let_in() {
    let expr = r#"
// test1
let x = 1
// test2
type Test = Int
// test3
1
// test4
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_whitespace_in_record() {
    let expr = r#"
{
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax = 1,

    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbby = 2,
}
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_block_comments() {
    let expr = r#"
/* test */
let x = { field = f /* test */ 123 /* doc */ }
/* test */
x
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

// TODO
#[test]
fn preserve_more_block_comments() {
    let expr = r#"
{ /* abc */ field /* abc */ = /* test */ 123 }
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn preserve_shebang_line() {
    let expr = r#"#!/bin/gluon
/* test */
let x = { field = f /* test */ 123 /* doc */ }
/* test */
x
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn nested_constructor_pattern() {
    let expr = r#"
match None with
| Some (Some x) -> x
| _ -> 123
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn long_pattern_match() {
    let expr = r#"
let {
    CCCCCCCCCCCCCC,
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
} =
    test
123
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn preserve_comments_in_function_types() {
    let expr = r#"#!/bin/gluon
let x : /* first */ Int /* Int */ ->
        // Float
        Float /* last */ = ()
x
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_comments_app_types() {
    let expr = r#"#!/bin/gluon
let x : Test /* first */ Int
        // middle
        Float /* last */ = ()
x
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_doc_comments_in_record_types() {
    let expr = r#"#!/bin/gluon
type Test = {
    /// test
    field1 : Int,
    /**
     middle
    */
    field2 : Float
}
x
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn doc_comment_in_record_expr() {
    let expr = r#"
{
    /// test
    /// test
    field1 = 1,
}
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_comments_in_empty_record() {
    let expr = r#"
{
// 123
}
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_comments_in_record_base() {
    let expr = r#"
{
    // 123
    ..
    // abc
    test
/* x */
}
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn small_record_in_let() {
    let expr = r#"
let semigroup =
    { append }
()
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn do_expression() {
    let expr = r#"
do /* x1 */ x /* x2 */ = Some 1
// test
test abc 1232 ""
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn if_else_multiple() {
    let expr = r#"
if x
then y
else if z
then w
else 0
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn comments_in_block_exprs() {
    let expr = r#"
// test
test 123

// test1

// test1

abc ""
// test2
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
#[ignore] // TODO
fn function_type_with_comments() {
    let expr = r#"
type Handler a =
    // Success continuation
    (a -> HttpState -> IO Response)
    // Failure continuation
    -> (Failure -> HttpState -> IO Response)
    -> IO Response
()
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn variant_type() {
    let expr = r#"
type TestCase a =
    | LoooooooooooooooooongTest String (() -> std.test.Test a)
    | LoooooooooooooooooooooooongGroup String (Array (std.test.TestCase a))
()
"#;
    assert_diff!(
        &format_expr(expr).unwrap_or_else(|err| panic!("{}", err)),
        expr,
        " ",
        0
    );
}

#[test]
fn multiline_string() {
    let expr = r#"
let x = "abc
        123
    "
x
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}
<commit_msg>Termcolor pretty print<commit_after>extern crate difference;
extern crate env_logger;
#[macro_use]
extern crate pretty_assertions;
extern crate termcolor;

extern crate gluon;
extern crate gluon_base as base;
extern crate gluon_format as format;

use std::env;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::Path;

use difference::{Changeset, Difference};

use gluon::{Compiler, VmBuilder};

fn assert_diff(text1: &str, text2: &str) -> io::Result<()> {
    let Changeset { diffs, .. } = Changeset::new(text1, text2, "\n");

    use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

    let mut t = StandardStream::stdout(ColorChoice::Auto);

    for i in 0..diffs.len() {
        match diffs[i] {
            Difference::Same(ref x) => {
                t.reset()?;
                writeln!(t, " {}", x)?;
            }
            Difference::Add(ref x) => {
                match diffs[i - 1] {
                    Difference::Rem(ref y) => {
                        t.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
                        write!(t, "+")?;
                        let Changeset { diffs, .. } = Changeset::new(y, x, " ");
                        for c in diffs {
                            match c {
                                Difference::Same(ref z) => {
                                    t.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
                                    write!(t, "{}", z)?;
                                    write!(t, " ")?;
                                }
                                Difference::Add(ref z) => {
                                    t.set_color(ColorSpec::new().set_fg(Some(Color::White)))?;
                                    t.set_color(ColorSpec::new().set_bg(Some(Color::Green)))?;
                                    write!(t, "{}", z)?;
                                    t.reset()?;
                                    write!(t, " ")?;
                                }
                                _ => (),
                            }
                        }
                        writeln!(t)?;
                    }
                    _ => {
                        t.set_color(
                            ColorSpec::new()
                                .set_fg(Some(Color::Green))
                                .set_intense(true),
                        )?;
                        writeln!(t, "+{}", x)?;
                    }
                };
            }
            Difference::Rem(ref x) => {
                t.set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
                writeln!(t, "-{}", x)?;
            }
        }
    }
    t.reset()?;
    t.flush()?;
    Ok(())
}

macro_rules! assert_diff {
    ($lhs:expr, $rhs:expr, $sep:expr, $distance:expr) => {

        assert_diff($lhs, $rhs).unwrap();
    };
}

fn format_expr(expr: &str) -> gluon::Result<String> {
    let mut compiler = Compiler::new();
    let thread = VmBuilder::new()
        .import_paths(Some(vec!["..".into()]))
        .build();
    format::format_expr(&mut compiler, &thread, "test", expr)
}

fn format_expr_expanded(expr: &str) -> gluon::Result<String> {
    let mut compiler = Compiler::new();
    let thread = VmBuilder::new()
        .import_paths(Some(vec!["..".into()]))
        .build();
    format::Formatter { expanded: true }.format_expr(&mut compiler, &thread, "test", expr)
}

fn test_format(name: &str) {
    let _ = env_logger::try_init();

    let mut contents = String::new();
    File::open(Path::new("../").join(name))
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();

    let mut compiler = Compiler::new();
    let thread = VmBuilder::new()
        .import_paths(Some(vec!["..".into()]))
        .build();
    let out_str = format::format_expr(&mut compiler, &thread, name, &contents)
        .unwrap_or_else(|err| panic!("{}", err));

    if contents != out_str {
        let args: Vec<_> = env::args().collect();
        let out_path = Path::new(&args[0][..])
            .parent()
            .and_then(|p| p.parent())
            .expect("folder")
            .join(Path::new(name).file_name().unwrap());
        File::create(out_path)
            .unwrap()
            .write_all(out_str.as_bytes())
            .unwrap();

        assert_diff!(&contents, &out_str, " ", 0);
    }
}

#[test]
fn bool() {
    test_format("std/bool.glu");
}

#[test]
fn char() {
    test_format("std/char.glu");
}

#[test]
fn function() {
    test_format("std/function.glu");
}

#[test]
fn map() {
    test_format("std/map.glu");
}

#[test]
fn option() {
    test_format("std/option.glu");
}

#[test]
fn prelude() {
    test_format("std/prelude.glu");
}

#[test]
fn result() {
    test_format("std/result.glu");
}

#[test]
fn state() {
    test_format("std/state.glu");
}

#[test]
fn stream() {
    test_format("std/stream.glu");
}

#[test]
fn string() {
    test_format("std/string.glu");
}

#[test]
fn test() {
    test_format("std/test.glu");
}

#[test]
fn types() {
    test_format("std/types.glu");
}

#[test]
fn unit() {
    test_format("std/unit.glu");
}

#[test]
fn writer() {
    test_format("std/writer.glu");
}

#[test]
fn parser() {
    test_format("std/parser.glu");
}

#[test]
fn random() {
    test_format("std/random.glu");
}

#[test]
fn repl() {
    test_format("repl/src/repl.glu");
}

#[test]
fn dont_add_newline_for_let_literal() {
    let expr = r#"
let x = 1
x
"#;
    assert_eq!(
        &format_expr(expr).unwrap(),
        r#"
let x = 1
x
"#
    );
}

#[test]
fn dont_lose_information_in_literals() {
    let expr = r#"
3.14 "\t\n\r\""
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn implicit_arg() {
    let expr = r#"
f ?32 ""
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn preserve_comment_between_let_in() {
    let expr = r#"
// test1
let x = 1
// test2
type Test = Int
// test3
1
// test4
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_whitespace_in_record() {
    let expr = r#"
{
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax = 1,

    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbby = 2,
}
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_block_comments() {
    let expr = r#"
/* test */
let x = { field = f /* test */ 123 /* doc */ }
/* test */
x
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

// TODO
#[test]
fn preserve_more_block_comments() {
    let expr = r#"
{ /* abc */ field /* abc */ = /* test */ 123 }
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn preserve_shebang_line() {
    let expr = r#"#!/bin/gluon
/* test */
let x = { field = f /* test */ 123 /* doc */ }
/* test */
x
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn nested_constructor_pattern() {
    let expr = r#"
match None with
| Some (Some x) -> x
| _ -> 123
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn long_pattern_match() {
    let expr = r#"
let {
    CCCCCCCCCCCCCC,
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
} =
    test
123
"#;
    assert_eq!(&format_expr(expr).unwrap(), expr);
}

#[test]
fn preserve_comments_in_function_types() {
    let expr = r#"#!/bin/gluon
let x : /* first */ Int /* Int */ ->
        // Float
        Float /* last */ = ()
x
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_comments_app_types() {
    let expr = r#"#!/bin/gluon
let x : Test /* first */ Int
        // middle
        Float /* last */ = ()
x
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_doc_comments_in_record_types() {
    let expr = r#"#!/bin/gluon
type Test = {
    /// test
    field1 : Int,
    /**
     middle
    */
    field2 : Float
}
x
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn doc_comment_in_record_expr() {
    let expr = r#"
{
    /// test
    /// test
    field1 = 1,
}
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_comments_in_empty_record() {
    let expr = r#"
{
// 123
}
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn preserve_comments_in_record_base() {
    let expr = r#"
{
    // 123
    ..
    // abc
    test
/* x */
}
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn small_record_in_let() {
    let expr = r#"
let semigroup =
    { append }
()
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn do_expression() {
    let expr = r#"
do /* x1 */ x /* x2 */ = Some 1
// test
test abc 1232 ""
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn if_else_multiple() {
    let expr = r#"
if x
then y
else if z
then w
else 0
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn comments_in_block_exprs() {
    let expr = r#"
// test
test 123

// test1

// test1

abc ""
// test2
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
#[ignore] // TODO
fn function_type_with_comments() {
    let expr = r#"
type Handler a =
    // Success continuation
    (a -> HttpState -> IO Response)
    // Failure continuation
    -> (Failure -> HttpState -> IO Response)
    -> IO Response
()
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn variant_type() {
    let expr = r#"
type TestCase a =
    | LoooooooooooooooooongTest String (() -> std.test.Test a)
    | LoooooooooooooooooooooooongGroup String (Array (std.test.TestCase a))
()
"#;
    assert_diff!(
        &format_expr(expr).unwrap_or_else(|err| panic!("{}", err)),
        expr,
        " ",
        0
    );
}

#[test]
fn multiline_string() {
    let expr = r#"
let x = "abc
        123
    "
x
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn derive() {
    let expr = r#"
#[derive(Show)]
type Test =
    | Test
Test
"#;
    assert_diff!(&format_expr(expr).unwrap(), expr, " ", 0);
}

#[test]
fn derive_expanded() {
    let expr = r#"
#[derive(Show)]
type Test =
    | Test
Test
"#;
    let expected = r#"
#[derive(Show)]
type Test =
    | Test
let show =
    let show_ x =
        match x with
        | Test -> "Test"
    { show }
Test
"#;
    assert_diff!(&format_expr_expanded(expr).unwrap(), expected, " ", 0);
}
<|endoftext|>


<commit_before>//! A shared ordered log.

use std::rc::Rc;
use std::cell::RefCell;
use std::time::{Instant, Duration};
use std::collections::VecDeque;

use ::{communication::Allocate, ExchangeData, PartialOrder};
use ::scheduling::Scheduler;
use worker::Worker;
use dataflow::channels::pact::Exchange;
use dataflow::operators::generic::operator::source;
use dataflow::operators::generic::operator::Operator;
use scheduling::activate::Activator;

// A Sequencer needs all operators firing with high frequency, because
// it uses the timer to gauge progress. If other workers cease
// advancing their own capabilities, although they might receive a
// record they may not actually tick forward their own source clocks,
// and no one will actually form the sequence.
//
// A CatchupActivator is an activator with an optional timestamp
// attached. This allows us to represent a special state, where after
// receiving an action from another worker, each of the other workers
// will keep scheduling its source operator, until its capability
// timestamp exceeds the greatest timestamp that the sink has
// received.
//
// This allows operators to go quiet again until a new requests shows
// up. The operators lose the ability to confirm that nothing is
// scheduled for a particular time (they could request this with a
// no-op event bearing a timestamp), but everyone still sees the same
// sequence.
struct CatchupActivator {
    pub catchup_until: Option<Duration>,
    activator: Activator,
}

impl CatchupActivator {
    pub fn activate(&self) {
        self.activator.activate();
    }
}

/// Orders elements inserted across all workers.
///
/// A Sequencer allows each worker to insert into a consistent ordered
/// sequence that is seen by all workers in the same order.
pub struct Sequencer<T> {
    activator: Rc<RefCell<Option<CatchupActivator>>>,
    send: Rc<RefCell<VecDeque<T>>>, // proposed items.
    recv: Rc<RefCell<VecDeque<T>>>, // sequenced items.
}

impl<T: Ord+ExchangeData> Sequencer<T> {

    /// Creates a new Sequencer.
    ///
    /// The `timer` instant is used to synchronize the workers, who use this
    /// elapsed time as their timestamp. Elements are ordered by this time,
    /// and cannot be made visible until all workers have reached the time.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::time::{Instant, Duration};
    ///
    /// use timely::Configuration;
    /// use timely::synchronization::Sequencer;
    ///
    /// timely::execute(Configuration::Process(4), |worker| {
    ///     let timer = Instant::now();
    ///     let mut sequencer = Sequencer::new(worker, timer);
    ///
    ///     for round in 0 .. 10 {
    ///
    ///         // Sleep, and then send an announcement on wake-up.
    ///         std::thread::sleep(Duration::from_millis(1 + worker.index() as u64));
    ///         sequencer.push(format!("worker {:?}, round {:?}", worker.index(), round));
    ///
    ///         // Ensures the pushed string is sent.
    ///         worker.step();
    ///
    ///         // Read out received announcements.
    ///         while let Some(element) = sequencer.next() {
    ///             println!("{:?}:\tWorker {:?}:\t recv'd: {:?}", timer.elapsed(), worker.index(), element);
    ///         }
    ///     }
    /// }).expect("Timely computation did not complete correctly.");
    /// ```
    pub fn new<A: Allocate>(worker: &mut Worker<A>, timer: Instant) -> Self {

        let send: Rc<RefCell<VecDeque<T>>> = Rc::new(RefCell::new(VecDeque::new()));
        let recv = Rc::new(RefCell::new(VecDeque::new()));
        let send_weak = Rc::downgrade(&send);
        let recv_weak = Rc::downgrade(&recv);

        // The SequenceInput activator will be held by the sequencer,
        // by the operator itself, and by the sink operator. We can
        // only initialize the activator once we obtain the operator
        // address.
        let activator: Rc<RefCell<Option<CatchupActivator>>> = Rc::new(RefCell::new(None));
        let activator_source = activator.clone(); //Rc::downgrade(&activator);
        let activator_sink = activator.clone(); //Rc::downgrade(&activator);

        // build a dataflow used to serialize and circulate commands
        worker.dataflow::<Duration,_,_>(move |dataflow| {

            let scope = dataflow.clone();
            let peers = dataflow.peers();

            let mut recvd = Vec::new();
            let mut vector = Vec::new();

            // monotonic counter to maintain per-worker total order.
            let mut counter = 0;

            // a source that attempts to pull from `recv` and produce commands for everyone
            source(dataflow, "SequenceInput", move |capability, info| {

                // intialize activator, now that we have the address
                activator_source
                    .borrow_mut()
                    .replace(CatchupActivator {
                        activator: scope.activator_for(&info.address[..]),
                        catchup_until: None,
                    });

                // so we can drop, if input queue vanishes.
                let mut capability = Some(capability);

                // closure broadcasts any commands it grabs.
                move |output| {

                    if let Some(send_queue) = send_weak.upgrade() {

                        // capability *should* still be non-None.
                        let capability = capability.as_mut().expect("Capability unavailable");

                        // downgrade capability to current time.
                        capability.downgrade(&timer.elapsed());

                        // drain and broadcast `send`.
                        let mut session = output.session(&capability);
                        let mut borrow = send_queue.borrow_mut();
                        for element in borrow.drain(..) {
                            for worker_index in 0 .. peers {
                                session.give((worker_index, counter, element.clone()));
                            }
                            counter += 1;
                        }

                        let mut activator_borrow = activator_source.borrow_mut();
                        let mut activator = activator_borrow.as_mut().unwrap();

                        if let Some(t) = activator.catchup_until {
                            if capability.time().less_than(&t) {
                                activator.activate();
                            } else {
                                activator.catchup_until = None;
                            }
                        }
                    } else {
                        capability = None;
                    }
                }
            })
            .sink(
                Exchange::new(|x: &(usize, usize, T)| x.0 as u64),
                "SequenceOutput",
                move |input| {

                    // grab each command and queue it up
                    input.for_each(|time, data| {
                        data.swap(&mut vector);
                        for (worker, counter, element) in vector.drain(..) {
                            recvd.push((time.time().clone(), (worker, counter, element)));
                        }
                    });

                    recvd.sort();

                    if let Some(last) = recvd.last() {
                        let mut activator_borrow = activator_sink.borrow_mut();
                        let mut activator = activator_borrow.as_mut().unwrap();

                        activator.catchup_until = Some(last.0);
                        activator.activate();
                    }

                    // determine how many (which) elements to read from `recvd`.
                    let count = recvd.iter().filter(|&(ref time, _)| !input.frontier().less_equal(time)).count();
                    let iter = recvd.drain(..count);

                    if let Some(recv_queue) = recv_weak.upgrade() {
                        recv_queue.borrow_mut().extend(iter.map(|(_time,(_worker,_counter,elem))| elem));
                    }
                }
            );
        });

        Sequencer { activator, send, recv, }
    }

    /// Adds an element to the shared log.
    pub fn push(&mut self, element: T) {
        self.send.borrow_mut().push_back(element);
        self.activator.borrow_mut().as_mut().unwrap().activate();
    }

    /// Reads the next element from the shared log.
    pub fn next(&mut self) -> Option<T> {
        self.recv.borrow_mut().pop_front()
    }
}
<commit_msg>remove Ord requirement<commit_after>//! A shared ordered log.

use std::rc::Rc;
use std::cell::RefCell;
use std::time::{Instant, Duration};
use std::collections::VecDeque;

use ::{communication::Allocate, ExchangeData, PartialOrder};
use ::scheduling::Scheduler;
use worker::Worker;
use dataflow::channels::pact::Exchange;
use dataflow::operators::generic::operator::source;
use dataflow::operators::generic::operator::Operator;
use scheduling::activate::Activator;

// A Sequencer needs all operators firing with high frequency, because
// it uses the timer to gauge progress. If other workers cease
// advancing their own capabilities, although they might receive a
// record they may not actually tick forward their own source clocks,
// and no one will actually form the sequence.
//
// A CatchupActivator is an activator with an optional timestamp
// attached. This allows us to represent a special state, where after
// receiving an action from another worker, each of the other workers
// will keep scheduling its source operator, until its capability
// timestamp exceeds the greatest timestamp that the sink has
// received.
//
// This allows operators to go quiet again until a new requests shows
// up. The operators lose the ability to confirm that nothing is
// scheduled for a particular time (they could request this with a
// no-op event bearing a timestamp), but everyone still sees the same
// sequence.
struct CatchupActivator {
    pub catchup_until: Option<Duration>,
    activator: Activator,
}

impl CatchupActivator {
    pub fn activate(&self) {
        self.activator.activate();
    }
}

/// Orders elements inserted across all workers.
///
/// A Sequencer allows each worker to insert into a consistent ordered
/// sequence that is seen by all workers in the same order.
pub struct Sequencer<T> {
    activator: Rc<RefCell<Option<CatchupActivator>>>,
    send: Rc<RefCell<VecDeque<T>>>, // proposed items.
    recv: Rc<RefCell<VecDeque<T>>>, // sequenced items.
}

impl<T: ExchangeData> Sequencer<T> {

    /// Creates a new Sequencer.
    ///
    /// The `timer` instant is used to synchronize the workers, who use this
    /// elapsed time as their timestamp. Elements are ordered by this time,
    /// and cannot be made visible until all workers have reached the time.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::time::{Instant, Duration};
    ///
    /// use timely::Configuration;
    /// use timely::synchronization::Sequencer;
    ///
    /// timely::execute(Configuration::Process(4), |worker| {
    ///     let timer = Instant::now();
    ///     let mut sequencer = Sequencer::new(worker, timer);
    ///
    ///     for round in 0 .. 10 {
    ///
    ///         // Sleep, and then send an announcement on wake-up.
    ///         std::thread::sleep(Duration::from_millis(1 + worker.index() as u64));
    ///         sequencer.push(format!("worker {:?}, round {:?}", worker.index(), round));
    ///
    ///         // Ensures the pushed string is sent.
    ///         worker.step();
    ///
    ///         // Read out received announcements.
    ///         while let Some(element) = sequencer.next() {
    ///             println!("{:?}:\tWorker {:?}:\t recv'd: {:?}", timer.elapsed(), worker.index(), element);
    ///         }
    ///     }
    /// }).expect("Timely computation did not complete correctly.");
    /// ```
    pub fn new<A: Allocate>(worker: &mut Worker<A>, timer: Instant) -> Self {

        let send: Rc<RefCell<VecDeque<T>>> = Rc::new(RefCell::new(VecDeque::new()));
        let recv = Rc::new(RefCell::new(VecDeque::new()));
        let send_weak = Rc::downgrade(&send);
        let recv_weak = Rc::downgrade(&recv);

        // The SequenceInput activator will be held by the sequencer,
        // by the operator itself, and by the sink operator. We can
        // only initialize the activator once we obtain the operator
        // address.
        let activator: Rc<RefCell<Option<CatchupActivator>>> = Rc::new(RefCell::new(None));
        let activator_source = activator.clone(); //Rc::downgrade(&activator);
        let activator_sink = activator.clone(); //Rc::downgrade(&activator);

        // build a dataflow used to serialize and circulate commands
        worker.dataflow::<Duration,_,_>(move |dataflow| {

            let scope = dataflow.clone();
            let peers = dataflow.peers();

            let mut recvd = Vec::new();
            let mut vector = Vec::new();

            // monotonic counter to maintain per-worker total order.
            let mut counter = 0;

            // a source that attempts to pull from `recv` and produce commands for everyone
            source(dataflow, "SequenceInput", move |capability, info| {

                // intialize activator, now that we have the address
                activator_source
                    .borrow_mut()
                    .replace(CatchupActivator {
                        activator: scope.activator_for(&info.address[..]),
                        catchup_until: None,
                    });

                // so we can drop, if input queue vanishes.
                let mut capability = Some(capability);

                // closure broadcasts any commands it grabs.
                move |output| {

                    if let Some(send_queue) = send_weak.upgrade() {

                        // capability *should* still be non-None.
                        let capability = capability.as_mut().expect("Capability unavailable");

                        // downgrade capability to current time.
                        capability.downgrade(&timer.elapsed());

                        // drain and broadcast `send`.
                        let mut session = output.session(&capability);
                        let mut borrow = send_queue.borrow_mut();
                        for element in borrow.drain(..) {
                            for worker_index in 0 .. peers {
                                session.give((worker_index, counter, element.clone()));
                            }
                            counter += 1;
                        }

                        let mut activator_borrow = activator_source.borrow_mut();
                        let mut activator = activator_borrow.as_mut().unwrap();

                        if let Some(t) = activator.catchup_until {
                            if capability.time().less_than(&t) {
                                activator.activate();
                            } else {
                                activator.catchup_until = None;
                            }
                        }
                    } else {
                        capability = None;
                    }
                }
            })
            .sink(
                Exchange::new(|x: &(usize, usize, T)| x.0 as u64),
                "SequenceOutput",
                move |input| {

                    // grab each command and queue it up
                    input.for_each(|time, data| {
                        data.swap(&mut vector);
                        for (worker, counter, element) in vector.drain(..) {
                            recvd.push(((time.time().clone(), worker, counter), element));
                        }
                    });

                    recvd.sort_by(|x,y| x.0.cmp(&y.0));

                    if let Some(last) = recvd.last() {
                        let mut activator_borrow = activator_sink.borrow_mut();
                        let mut activator = activator_borrow.as_mut().unwrap();

                        activator.catchup_until = Some((last.0).0);
                        activator.activate();
                    }

                    // determine how many (which) elements to read from `recvd`.
                    let count = recvd.iter().filter(|&((ref time, _, _), _)| !input.frontier().less_equal(time)).count();
                    let iter = recvd.drain(..count);

                    if let Some(recv_queue) = recv_weak.upgrade() {
                        recv_queue.borrow_mut().extend(iter.map(|(_,elem)| elem));
                    }
                }
            );
        });

        Sequencer { activator, send, recv, }
    }

    /// Adds an element to the shared log.
    pub fn push(&mut self, element: T) {
        self.send.borrow_mut().push_back(element);
        self.activator.borrow_mut().as_mut().unwrap().activate();
    }

    /// Reads the next element from the shared log.
    pub fn next(&mut self) -> Option<T> {
        self.recv.borrow_mut().pop_front()
    }
}
<|endoftext|>


<commit_before>use std::cmp::{PartialOrd, Ordering};
use std::iter::repeat;
use std::usize;

use draw::RGB;

#[derive(Debug, PartialEq, Eq)]
pub struct Point {
   pub x: i64,
   pub y: i64,
}

impl Point {
   #[inline]
   pub fn new(x: i64, y: i64) -> Self {
      Point {
         x: x,
         y: y,
      }
   }
}

impl PartialOrd for Point {
   fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
      Some(self.cmp(other))
   }
}

impl Ord for Point {
   fn cmp(&self, other: &Point) -> Ordering {
      if self.y < other.y {
         Ordering::Less
      } else if self.y > other.y {
         Ordering::Greater
      } else if self.x < other.x {
         Ordering::Less
      } else if self.x > other.x {
         Ordering::Greater
      } else {
         Ordering::Equal
      }
   }
}

#[derive(Debug)]
pub struct Segment {
   pub p1: usize,
   pub p2: usize,
}

impl Segment {
   #[inline]
   pub fn new(p1: usize, p2: usize) -> Self {
      Segment {
         p1: p1,
         p2: p2,
      }
   }
}

#[derive(Debug)]
pub struct Circle {
   pub center: usize,
   pub radius: i64,
}

impl Circle {
   #[inline]
   pub fn new(center: usize, radius: i64) -> Self {
      Circle {
         center: center,
         radius: radius,
      }
   }
}

#[derive(Debug)]
pub enum EdgeType {
   LTR,  // line top-right
   LTL,  // line top-left
   LBR,  // line bottom-right
   LBL,  // line bottom-left

   LHR,  // line horizontal-right
   LHL,  // line horizontal-left
   LVT,  // line vertical-top
   LVB,  // line vertical-bottom

   CTR, // clockwise arc top-right
   CTL, // clockwise arc top-left
   CBR, // clockwise arc bottom-right
   CBL, // clockwise arc bottom-left

   ATR, // anti-clockwise arc top-right
   ATL, // anti-clockwise arc top-left
   ABR, // anti-clockwise arc bottom-right
   ABL, // anti-clockwise arc bottom-left
}

impl EdgeType {
   #[inline]
   pub fn reversed(&self) -> bool {
      match *self {
         EdgeType::LBR | EdgeType::LBL | EdgeType::LHL | EdgeType::LVB |
         EdgeType::CBR | EdgeType::CBL | EdgeType::ATR | EdgeType::ATL => {
            true
         },
         _ => {
            false
         }
      }
   }
}

#[derive(Debug)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub segment: usize,
   pub circle: usize,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, segment: usize, circle: usize) -> Self {
      Edge {
         edge_type: edge_type,
         segment: segment,
         circle: circle,
      }
   }

   #[inline]
   pub fn reversed(&self) -> bool {
      self.edge_type.reversed()
   }
}

#[derive(Debug)]
pub struct Poly {
   pub start: usize,
   pub end: usize,
   pub color: usize,
}

impl Poly {
   #[inline]
   pub fn new(start: usize, end: usize, color: usize) -> Self {
      Poly {
         start: start,
         end: end,
         color: color,
      }
   }
}

pub struct Scene {
   pub points: Vec<Point>,
   pub segments: Vec<Segment>,
   pub circles: Vec<Circle>,
   pub edges: Vec<Edge>,
   pub polys: Vec<Poly>,
   pub colors: Vec<RGB>,
}

impl Scene {
   pub fn check_correctness(&self) {
      for poly in &self.polys {
         self.check_poly_connected(poly);
         self.check_segments_orientation(poly);
         self.check_edges_orientation(poly);
      }

      self.check_index_coverage();
   }

   fn check_poly_connected(&self, poly: &Poly) {
      let mut prev = self.edge_head(&self.edges[poly.end - 1]);

      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let current = self.edge_tail(edge);
         if current != prev {
            panic!("Unclosed poly : {:?}", poly);
         }

         prev = self.edge_head(edge);
      }
   }

   fn check_segments_orientation(&self, poly: &Poly) {
      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];
         let ref segment = self.segments[edge.segment];

         let ref less = self.points[segment.p1];
         let ref greater = self.points[segment.p2];

         if greater <= less {
            panic!("Wrong segment orientation : {:?} / {:?}", edge, segment);
         }
      }
   }

   fn check_edges_orientation(&self, poly: &Poly) {
      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let tail = self.edge_tail(edge);
         let head = self.edge_head(edge);

         let reversed = edge.reversed();

         if (reversed && tail <= head) || (!reversed && head <= tail) {
            panic!("Wrong edge orientation : {:?}", edge);
         }
      }
   }

   fn check_index_coverage(&self) {
      self.check_edge_index_coverage();
      self.check_circle_index_coverage();
      self.check_segment_index_coverage();
   }

   fn check_edge_index_coverage(&self) {
      let len = self.edges.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for poly in &self.polys {
         for edge_index in poly.start..poly.end {
            coverage[edge_index] = true;
         }
      }

      if coverage.contains(&false) {
         panic!("Unreferenced edge found");
      }
   }

   fn check_circle_index_coverage(&self) {
      let len = self.circles.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for edge in &self.edges {
         if edge.circle != usize::MAX {
            coverage[edge.circle] = true;
         }
      }

      if coverage.contains(&false) {
         panic!("Unreferenced circle found");
      }
   }

   fn check_segment_index_coverage(&self) {
      let len = self.segments.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for edge in &self.edges {
         coverage[edge.segment] = true;
      }

      if coverage.contains(&false) {
         panic!("Unreferenced segment found");
      }
   }

   // TODO: Combine into edge_head_tail method?

   fn edge_head(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p1]
      } else {
         &self.points[segment.p2]
      }
   }

   fn edge_tail(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p2]
      } else {
         &self.points[segment.p1]
      }
   }
}
<commit_msg>Checking point index coverage<commit_after>use std::cmp::{PartialOrd, Ordering};
use std::iter::repeat;
use std::usize;

use draw::RGB;

#[derive(Debug, PartialEq, Eq)]
pub struct Point {
   pub x: i64,
   pub y: i64,
}

impl Point {
   #[inline]
   pub fn new(x: i64, y: i64) -> Self {
      Point {
         x: x,
         y: y,
      }
   }
}

impl PartialOrd for Point {
   fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
      Some(self.cmp(other))
   }
}

impl Ord for Point {
   fn cmp(&self, other: &Point) -> Ordering {
      if self.y < other.y {
         Ordering::Less
      } else if self.y > other.y {
         Ordering::Greater
      } else if self.x < other.x {
         Ordering::Less
      } else if self.x > other.x {
         Ordering::Greater
      } else {
         Ordering::Equal
      }
   }
}

#[derive(Debug)]
pub struct Segment {
   pub p1: usize,
   pub p2: usize,
}

impl Segment {
   #[inline]
   pub fn new(p1: usize, p2: usize) -> Self {
      Segment {
         p1: p1,
         p2: p2,
      }
   }
}

#[derive(Debug)]
pub struct Circle {
   pub center: usize,
   pub radius: i64,
}

impl Circle {
   #[inline]
   pub fn new(center: usize, radius: i64) -> Self {
      Circle {
         center: center,
         radius: radius,
      }
   }
}

#[derive(Debug)]
pub enum EdgeType {
   LTR,  // line top-right
   LTL,  // line top-left
   LBR,  // line bottom-right
   LBL,  // line bottom-left

   LHR,  // line horizontal-right
   LHL,  // line horizontal-left
   LVT,  // line vertical-top
   LVB,  // line vertical-bottom

   CTR, // clockwise arc top-right
   CTL, // clockwise arc top-left
   CBR, // clockwise arc bottom-right
   CBL, // clockwise arc bottom-left

   ATR, // anti-clockwise arc top-right
   ATL, // anti-clockwise arc top-left
   ABR, // anti-clockwise arc bottom-right
   ABL, // anti-clockwise arc bottom-left
}

impl EdgeType {
   #[inline]
   pub fn reversed(&self) -> bool {
      match *self {
         EdgeType::LBR | EdgeType::LBL | EdgeType::LHL | EdgeType::LVB |
         EdgeType::CBR | EdgeType::CBL | EdgeType::ATR | EdgeType::ATL => {
            true
         },
         _ => {
            false
         }
      }
   }
}

#[derive(Debug)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub segment: usize,
   pub circle: usize,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, segment: usize, circle: usize) -> Self {
      Edge {
         edge_type: edge_type,
         segment: segment,
         circle: circle,
      }
   }

   #[inline]
   pub fn reversed(&self) -> bool {
      self.edge_type.reversed()
   }
}

#[derive(Debug)]
pub struct Poly {
   pub start: usize,
   pub end: usize,
   pub color: usize,
}

impl Poly {
   #[inline]
   pub fn new(start: usize, end: usize, color: usize) -> Self {
      Poly {
         start: start,
         end: end,
         color: color,
      }
   }
}

pub struct Scene {
   pub points: Vec<Point>,
   pub segments: Vec<Segment>,
   pub circles: Vec<Circle>,
   pub edges: Vec<Edge>,
   pub polys: Vec<Poly>,
   pub colors: Vec<RGB>,
}

impl Scene {
   pub fn check_correctness(&self) {
      for poly in &self.polys {
         self.check_poly_connected(poly);
         self.check_segments_orientation(poly);
         self.check_edges_orientation(poly);
      }

      self.check_index_coverage();
   }

   fn check_poly_connected(&self, poly: &Poly) {
      let mut prev = self.edge_head(&self.edges[poly.end - 1]);

      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let current = self.edge_tail(edge);
         if current != prev {
            panic!("Unclosed poly : {:?}", poly);
         }

         prev = self.edge_head(edge);
      }
   }

   fn check_segments_orientation(&self, poly: &Poly) {
      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];
         let ref segment = self.segments[edge.segment];

         let ref less = self.points[segment.p1];
         let ref greater = self.points[segment.p2];

         if greater <= less {
            panic!("Wrong segment orientation : {:?} / {:?}", edge, segment);
         }
      }
   }

   fn check_edges_orientation(&self, poly: &Poly) {
      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let tail = self.edge_tail(edge);
         let head = self.edge_head(edge);

         let reversed = edge.reversed();

         if (reversed && tail <= head) || (!reversed && head <= tail) {
            panic!("Wrong edge orientation : {:?}", edge);
         }
      }
   }

   fn check_index_coverage(&self) {
      self.check_edge_index_coverage();
      self.check_circle_index_coverage();
      self.check_segment_index_coverage();
      self.check_point_index_coverage();
   }

   fn check_edge_index_coverage(&self) {
      let len = self.edges.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for poly in &self.polys {
         for edge_index in poly.start..poly.end {
            coverage[edge_index] = true;
         }
      }

      if coverage.contains(&false) {
         panic!("Unreferenced edge found");
      }
   }

   fn check_circle_index_coverage(&self) {
      let len = self.circles.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for edge in &self.edges {
         if edge.circle != usize::MAX {
            coverage[edge.circle] = true;
         }
      }

      if coverage.contains(&false) {
         panic!("Unreferenced circle found");
      }
   }

   fn check_segment_index_coverage(&self) {
      let len = self.segments.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for edge in &self.edges {
         coverage[edge.segment] = true;
      }

      if coverage.contains(&false) {
         panic!("Unreferenced segment found");
      }
   }

   fn check_point_index_coverage(&self) {
      let len = self.points.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for circle in &self.circles {
         coverage[circle.center] = true;
      }

      for segment in &self.segments {
         coverage[segment.p1] = true;
         coverage[segment.p2] = true;
      }

      if coverage.contains(&false) {
         panic!("Unreferenced segment found");
      }
   }

   // TODO: Combine into edge_head_tail method?

   fn edge_head(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p1]
      } else {
         &self.points[segment.p2]
      }
   }

   fn edge_tail(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p2]
      } else {
         &self.points[segment.p1]
      }
   }
}
<|endoftext|>


<commit_before>use orbclient::{self, EventIter, Renderer};
use std;

use interpolate::Interpolator;
use model::mesh::Mesh;
use primitive::edge::Edge;
use primitive::matrix::Matrix4f32;
use primitive::vertex::Vertex;
use texture::bitmap::BitmapTexture;

pub struct RenderContext {
    window: orbclient::Window,
}

impl RenderContext {
    pub fn new(width: u32, height: u32, title: &str) -> RenderContext {
        let orb_window = orbclient::Window::new_flags(100, 100, width, height, title, true).unwrap();
        RenderContext{window: orb_window}
    }

    pub fn get_height(&self) -> u32 {
        self.window.height()
    }

    pub fn get_width(&self) -> u32 {
        self.window.width()
    }

    pub fn events(&mut self) -> EventIter {
        self.window.events()
    }

    pub fn clear(&mut self) {
        self.window.set(orbclient::Color { data: 0xFF220CE8});
    }

    pub fn sync(&mut self) {
        self.window.sync();
    }

    pub fn draw_mesh(&mut self, mesh: &Mesh, transform: &Matrix4f32, texture: &BitmapTexture) {
        for idx in (0..mesh.indices.len()).step_by(3) {
            let v1 = &mesh.vertices[mesh.indices[idx as usize] as usize].transform(&transform);
            let v2 = &mesh.vertices[mesh.indices[(idx + 1) as usize] as usize].transform(&transform);
            let v3 = &mesh.vertices[mesh.indices[(idx + 2) as usize] as usize].transform(&transform);

            self.draw_triangle(v1, v2, v3, &texture);
        }
    }

    pub fn draw_triangle(&mut self, v1: &Vertex, v2: &Vertex, v3: &Vertex, texture: &BitmapTexture) {

        //TODO(dustin): optimisation do not calculate/init every time
        let screen_space_transform = Matrix4f32::new().init_sreenspace_transform(self.get_width() as f32 / 2f32, self.get_height() as f32 / 2f32);

        let mut min_vert = v1.transform(&screen_space_transform).perspective_divide();
        let mut mid_vert = v2.transform(&screen_space_transform).perspective_divide();
        let mut max_vert = v3.transform(&screen_space_transform).perspective_divide();

        if min_vert.calc_double_area(&max_vert, &mid_vert) >= 0 {
            return;
        }

        if max_vert.pos.y < mid_vert.pos.y {
            std::mem::swap(&mut mid_vert, &mut max_vert);
        }

        if mid_vert.pos.y < min_vert.pos.y {
            std::mem::swap(&mut mid_vert, &mut min_vert);
        }

        if max_vert.pos.y < mid_vert.pos.y {
            std::mem::swap(&mut max_vert, &mut mid_vert);
        }

        self.scan_triangle(&min_vert, &mid_vert, &max_vert, min_vert.calc_double_area(&max_vert, &mid_vert) >= 0, texture);
    }

    fn scan_triangle(&mut self,  min_vert: &Vertex, mid_vert: &Vertex, max_vert: &Vertex, side: bool, texture: &BitmapTexture) {

        let interpolator = Interpolator::new(min_vert, mid_vert, max_vert);
        let mut top_to_bottom = Edge::new(&interpolator, min_vert, max_vert, 0);
        let mut top_to_middle = Edge::new(&interpolator, min_vert, mid_vert, 0);
        let mut middle_to_bottom = Edge::new(&interpolator, mid_vert, max_vert, 1);

        self.scan_edges(&mut top_to_bottom, &mut top_to_middle, side, texture);
        self.scan_edges(&mut top_to_bottom, &mut middle_to_bottom, side, texture);
    }

    fn scan_edges(&mut self, first: &mut Edge, second: &mut Edge, side: bool, texture: &BitmapTexture) {

        let start_y = second.start_y;
        let end_y = second.end_y;

        let mut left = first;
        let mut right = second;

        if side {
            std::mem::swap(&mut left, &mut right);
        }

        for idx_y in start_y..end_y {
            self.draw_scan_line(&left, &right, idx_y, texture);
            left.step();
            right.step();
        }
    }

    fn draw_scan_line(&mut self, left: &Edge, right: &Edge, idx_y: i32, texture: &BitmapTexture) {

        let min_x = left.pos_x.ceil() as i32;
        let max_x = right.pos_x.ceil()as i32;
        let prestep_x = min_x as f32 - left.pos_x;

        let dist_x = right.pos_x - left.pos_x;
        let tex_coords_step_xx = (right.tex_coords_x - left.tex_coords_x) / dist_x;
        let tex_coords_step_yx = (right.tex_coords_y - left.tex_coords_y) / dist_x;
        let one_over_step_zx = (right.one_over_z - left.one_over_z) / dist_x;

        let mut tex_coords_x = left.tex_coords_x + tex_coords_step_xx * prestep_x;
        let mut tex_coords_y = left.tex_coords_y + tex_coords_step_yx * prestep_x;
        let mut one_over_z = left.one_over_z + one_over_step_zx * prestep_x;

        let ww = self.window.width();
        let wh = self.window.height();
        let data = self.window.data_mut();

        for idx_x in min_x..max_x {

            let data_idx = idx_y * ww as i32 + idx_x;
            if data_idx >= data.len() as i32 || data_idx < 0 {
                break;
            }

            let z = 1_f32 / one_over_z;
            let src_x = ((tex_coords_x * z) * (texture.width - 1) as f32 + 0.5_f32) as i32;
            let src_y = ((tex_coords_y * z) * (texture.height - 1) as f32 + 0.5_f32) as i32;

//            self.window.pixel(idx_x, idx_y, texture.get_orb_pixel(src_x, src_y));
            let new = texture.get_orb_pixel(src_x, src_y).data;
            let old = &mut data[idx_y as usize * ww as usize + idx_x as usize].data;
            *old = new;

            one_over_z += one_over_step_zx;
            tex_coords_x += tex_coords_step_xx;
            tex_coords_y += tex_coords_step_yx;
        }
    }
}
<commit_msg>Fix window flags<commit_after>use orbclient::{self, EventIter, Renderer, WindowFlag};
use std;

use interpolate::Interpolator;
use model::mesh::Mesh;
use primitive::edge::Edge;
use primitive::matrix::Matrix4f32;
use primitive::vertex::Vertex;
use texture::bitmap::BitmapTexture;

pub struct RenderContext {
    window: orbclient::Window,
}

impl RenderContext {
    pub fn new(width: u32, height: u32, title: &str) -> RenderContext {
        let orb_window = orbclient::Window::new_flags(100, 100, width, height, title, &[WindowFlag::Async]).unwrap();
        RenderContext{window: orb_window}
    }

    pub fn get_height(&self) -> u32 {
        self.window.height()
    }

    pub fn get_width(&self) -> u32 {
        self.window.width()
    }

    pub fn events(&mut self) -> EventIter {
        self.window.events()
    }

    pub fn clear(&mut self) {
        self.window.set(orbclient::Color { data: 0xFF220CE8});
    }

    pub fn sync(&mut self) {
        self.window.sync();
    }

    pub fn draw_mesh(&mut self, mesh: &Mesh, transform: &Matrix4f32, texture: &BitmapTexture) {
        for idx in (0..mesh.indices.len()).step_by(3) {
            let v1 = &mesh.vertices[mesh.indices[idx as usize] as usize].transform(&transform);
            let v2 = &mesh.vertices[mesh.indices[(idx + 1) as usize] as usize].transform(&transform);
            let v3 = &mesh.vertices[mesh.indices[(idx + 2) as usize] as usize].transform(&transform);

            self.draw_triangle(v1, v2, v3, &texture);
        }
    }

    pub fn draw_triangle(&mut self, v1: &Vertex, v2: &Vertex, v3: &Vertex, texture: &BitmapTexture) {

        //TODO(dustin): optimisation do not calculate/init every time
        let screen_space_transform = Matrix4f32::new().init_sreenspace_transform(self.get_width() as f32 / 2f32, self.get_height() as f32 / 2f32);

        let mut min_vert = v1.transform(&screen_space_transform).perspective_divide();
        let mut mid_vert = v2.transform(&screen_space_transform).perspective_divide();
        let mut max_vert = v3.transform(&screen_space_transform).perspective_divide();

        if min_vert.calc_double_area(&max_vert, &mid_vert) >= 0 {
            return;
        }

        if max_vert.pos.y < mid_vert.pos.y {
            std::mem::swap(&mut mid_vert, &mut max_vert);
        }

        if mid_vert.pos.y < min_vert.pos.y {
            std::mem::swap(&mut mid_vert, &mut min_vert);
        }

        if max_vert.pos.y < mid_vert.pos.y {
            std::mem::swap(&mut max_vert, &mut mid_vert);
        }

        self.scan_triangle(&min_vert, &mid_vert, &max_vert, min_vert.calc_double_area(&max_vert, &mid_vert) >= 0, texture);
    }

    fn scan_triangle(&mut self,  min_vert: &Vertex, mid_vert: &Vertex, max_vert: &Vertex, side: bool, texture: &BitmapTexture) {

        let interpolator = Interpolator::new(min_vert, mid_vert, max_vert);
        let mut top_to_bottom = Edge::new(&interpolator, min_vert, max_vert, 0);
        let mut top_to_middle = Edge::new(&interpolator, min_vert, mid_vert, 0);
        let mut middle_to_bottom = Edge::new(&interpolator, mid_vert, max_vert, 1);

        self.scan_edges(&mut top_to_bottom, &mut top_to_middle, side, texture);
        self.scan_edges(&mut top_to_bottom, &mut middle_to_bottom, side, texture);
    }

    fn scan_edges(&mut self, first: &mut Edge, second: &mut Edge, side: bool, texture: &BitmapTexture) {

        let start_y = second.start_y;
        let end_y = second.end_y;

        let mut left = first;
        let mut right = second;

        if side {
            std::mem::swap(&mut left, &mut right);
        }

        for idx_y in start_y..end_y {
            self.draw_scan_line(&left, &right, idx_y, texture);
            left.step();
            right.step();
        }
    }

    fn draw_scan_line(&mut self, left: &Edge, right: &Edge, idx_y: i32, texture: &BitmapTexture) {

        let min_x = left.pos_x.ceil() as i32;
        let max_x = right.pos_x.ceil()as i32;
        let prestep_x = min_x as f32 - left.pos_x;

        let dist_x = right.pos_x - left.pos_x;
        let tex_coords_step_xx = (right.tex_coords_x - left.tex_coords_x) / dist_x;
        let tex_coords_step_yx = (right.tex_coords_y - left.tex_coords_y) / dist_x;
        let one_over_step_zx = (right.one_over_z - left.one_over_z) / dist_x;

        let mut tex_coords_x = left.tex_coords_x + tex_coords_step_xx * prestep_x;
        let mut tex_coords_y = left.tex_coords_y + tex_coords_step_yx * prestep_x;
        let mut one_over_z = left.one_over_z + one_over_step_zx * prestep_x;

        let ww = self.window.width();
        let wh = self.window.height();
        let data = self.window.data_mut();

        for idx_x in min_x..max_x {

            let data_idx = idx_y * ww as i32 + idx_x;
            if data_idx >= data.len() as i32 || data_idx < 0 {
                break;
            }

            let z = 1_f32 / one_over_z;
            let src_x = ((tex_coords_x * z) * (texture.width - 1) as f32 + 0.5_f32) as i32;
            let src_y = ((tex_coords_y * z) * (texture.height - 1) as f32 + 0.5_f32) as i32;

//            self.window.pixel(idx_x, idx_y, texture.get_orb_pixel(src_x, src_y));
            let new = texture.get_orb_pixel(src_x, src_y).data;
            let old = &mut data[idx_y as usize * ww as usize + idx_x as usize].data;
            *old = new;

            one_over_z += one_over_step_zx;
            tex_coords_x += tex_coords_step_xx;
            tex_coords_y += tex_coords_step_yx;
        }
    }
}
<|endoftext|>


<commit_before>extern crate toml;
extern crate reqwest;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate glob;
extern crate nix;

#[macro_use]
extern crate lazy_static;

use std::io::{Write, BufRead};
use std::ffi::CStr;
extern crate libc;

mod structs;
use structs::Config;
mod ghclient;
mod buffer;
use buffer::Buffer;
mod cstructs;
use cstructs::{Passwd, Spwd, Group};
mod runfiles;
mod statics;
use statics::{CLIENT, CONFIG};

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

fn string_from(cstrptr: *const libc::c_char) -> String {
    let cstr: &CStr = unsafe { CStr::from_ptr(cstrptr) };
    String::from(cstr.to_str().unwrap())
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwnam_r(cnameptr: *const libc::c_char,
                                         pw: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         pwbufp: *mut *mut Passwd)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => {
            unsafe { *pwbufp = std::ptr::null_mut() };
            return libc::c_int::from(NssStatus::NotFound);
        }
    };
    match team.members.get(&name) {
        Some(member) => {
            match unsafe { (*pw).pack_args(&mut buffer, &member.login, member.id, team.id, &CONFIG) } {
                Ok(_) => {
                    unsafe { *pwbufp = pw };
                    return libc::c_int::from(NssStatus::Success);
                }
                Err(_) => {
                    unsafe { *pwbufp = std::ptr::null_mut() };
                    return nix::Errno::ERANGE as libc::c_int;
                }

            }
        }
        None => {
            unsafe { *pwbufp = std::ptr::null_mut() };
            libc::c_int::from(NssStatus::NotFound)
        }
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwuid_r(uid: libc::uid_t,
                                         pw: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         pwbufp: *mut *mut Passwd)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => {
            unsafe { *pwbufp = std::ptr::null_mut() };
            return libc::c_int::from(NssStatus::NotFound);
        }
    };
    for member in team.members.values() {
        if uid == member.id as libc::uid_t {
            match unsafe { (*pw).pack_args(&mut buffer, &member.login, member.id, team.id, &CONFIG) } {
                Ok(_) => {
                    unsafe { *pwbufp = pw };
                    return libc::c_int::from(NssStatus::Success);
                }
                Err(_) => {
                    unsafe { *pwbufp = std::ptr::null_mut() };
                    return nix::Errno::ERANGE as libc::c_int;
                }
            }
        }
    }
    unsafe { *pwbufp = std::ptr::null_mut() };
    libc::c_int::from(NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setpwent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    for member in team.members.values() {
        list_file.write(format!("{}\t{}\t{}\n", member.login, member.id, team.id).as_bytes())
                 .unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwent_r(pwbuf: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         pwbufp: *mut *mut Passwd)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Unavail),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let id = words[1].parse::<u64>().unwrap();
        let gid = words[2].parse::<u64>().unwrap();
        match unsafe { (*pwbuf).pack_args(&mut buffer, words[0], id, gid, &CONFIG) } {
            Ok(_) => {
                runfiles::increment(idx, idx_file);
                unsafe { *pwbufp = pwbuf };
                return libc::c_int::from(NssStatus::Success);
            }
            Err(_) => {
                unsafe { *pwbufp = std::ptr::null_mut() };
                return nix::Errno::ERANGE as libc::c_int;
            }
        }
    }
    libc::c_int::from(NssStatus::Unavail)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getspnam_r(cnameptr: *const libc::c_char,
                                         spwd: *mut Spwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         spbufp: *mut *mut Spwd)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => {
            unsafe { *spbufp = std::ptr::null_mut() };
            return libc::c_int::from(NssStatus::NotFound);
        }
    };
    match team.members.get(&name) {
        Some(member) => {
            match unsafe { (*spwd).pack_args(&mut buffer, &member.login, &CONFIG) } {
                Ok(_) => {
                    unsafe { *spbufp = spwd };
                    libc::c_int::from(NssStatus::Success)
                }
                Err(_) => {
                    unsafe { *spbufp = std::ptr::null_mut() };
                    nix::Errno::ERANGE as libc::c_int
                }
            }
        }
        None => {
            unsafe { *spbufp = std::ptr::null_mut() };
            libc::c_int::from(NssStatus::NotFound)
        }
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setspent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    for member in team.members.values() {
        list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                 .unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getspent_r(spbuf: *mut Spwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         spbufp: *mut *mut Spwd)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Unavail),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        match unsafe { (*spbuf).pack_args(&mut buffer, words[0], &CONFIG) } {
            Ok(_) => {
                runfiles::increment(idx, idx_file);
                unsafe { *spbufp = spbuf };
                return libc::c_int::from(NssStatus::Success);
            }
            Err(_) => {
                unsafe { *spbufp = std::ptr::null_mut() };
                return nix::Errno::ERANGE as libc::c_int;
            }
        }
    }
    libc::c_int::from(NssStatus::Unavail)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrgid_r(gid: libc::gid_t,
                                         group: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         grbufp: *mut *mut Group)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => {
            unsafe { *grbufp = std::ptr::null_mut() };
            return libc::c_int::from(NssStatus::NotFound);
        }
    };
    let members: Vec<&str> = team.members.values().map(|m| m.login.as_str()).collect();
    if gid as u64 == team.id {
        match unsafe { (*group).pack_args(&mut buffer, &team.name, gid as u64, &members) } {
            Ok(_) => {
                unsafe { *grbufp = group };
                libc::c_int::from(NssStatus::Success)
            }
            Err(_) => {
                unsafe { *grbufp = std::ptr::null_mut() };
                nix::Errno::ERANGE as libc::c_int
            }
        }
    } else {
        unsafe { *grbufp = std::ptr::null_mut() };
        libc::c_int::from(NssStatus::NotFound)
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrnam_r(cnameptr: *const libc::c_char,
                                         group: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         grbufp: *mut *mut Group)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => {
            unsafe { *grbufp = std::ptr::null_mut() };
            return libc::c_int::from(NssStatus::NotFound);
        }
    };
    let members: Vec<&str> = team.members.values().map(|m| m.login.as_str()).collect();
    if name == team.name {
        match unsafe { (*group).pack_args(&mut buffer, &team.name, team.id, &members) } {
            Ok(_) => {
                unsafe { *grbufp = group };
                libc::c_int::from(NssStatus::Success)
            }
            Err(_) => {
                unsafe { *grbufp = std::ptr::null_mut() };
                nix::Errno::ERANGE as libc::c_int
            }
        }
    } else {
        unsafe { *grbufp = std::ptr::null_mut() };
        libc::c_int::from(NssStatus::NotFound)
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setgrent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let member_names = team.members.values().map(|x| x.login.as_str()).collect::<Vec<&str>>().join(" ");
    list_file.write(format!("{}\t{}\t{}\n", team.name, team.id, member_names).as_bytes())
             .unwrap();
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrent_r(grbuf: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         grbufp: *mut *mut Group)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Unavail),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let member_names: Vec<&str> = words[2].split(" ").collect();
        let gid = words[1].parse::<u64>().unwrap();
        match unsafe { (*grbuf).pack_args(&mut buffer, words[0], gid, &member_names) } {
            Ok(_) => {
                runfiles::increment(idx, idx_file);
                unsafe { *grbufp = grbuf };
                return libc::c_int::from(NssStatus::Success);
            }
            Err(_) => {
                unsafe { *grbufp = std::ptr::null_mut() };
                return nix::Errno::ERANGE as libc::c_int;
            }
        }
    }
    libc::c_int::from(NssStatus::Unavail)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<commit_msg>Refactor with macro<commit_after>extern crate toml;
extern crate reqwest;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate glob;
extern crate nix;

#[macro_use]
extern crate lazy_static;

use std::io::{Write, BufRead};
use std::ffi::CStr;
extern crate libc;

mod structs;
use structs::Config;
mod ghclient;
mod buffer;
use buffer::Buffer;
mod cstructs;
use cstructs::{Passwd, Spwd, Group};
mod runfiles;
mod statics;
use statics::{CLIENT, CONFIG};

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

fn string_from(cstrptr: *const libc::c_char) -> String {
    let cstr: &CStr = unsafe { CStr::from_ptr(cstrptr) };
    String::from(cstr.to_str().unwrap())
}

macro_rules! succeed {
    ($ret_struct_p:ident,$ret_struct:ident) => {{
        unsafe { *$ret_struct_p = $ret_struct };
        return libc::c_int::from(NssStatus::Success);
    }};
    ($ret_struct_p:ident,$ret_struct:ident,$finalize:expr) => {{
        $finalize;
        unsafe { *$ret_struct_p = $ret_struct };
        return libc::c_int::from(NssStatus::Success);
    }}
}

macro_rules! fail {
    ($ret_struct_p:ident, $return_val:expr) => {{
        unsafe { *$ret_struct_p = std::ptr::null_mut() };
        return $return_val;
    }}
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwnam_r(cnameptr: *const libc::c_char,
                                         pw: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         pwbufp: *mut *mut Passwd)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => fail!(pwbufp, libc::c_int::from(NssStatus::NotFound)),
    };
    match team.members.get(&name) {
        Some(member) => {
            match unsafe { (*pw).pack_args(&mut buffer, &member.login, member.id, team.id, &CONFIG) } {
                Ok(_) => succeed!(pwbufp, pw),
                Err(_) => fail!(pwbufp, nix::Errno::ERANGE as libc::c_int),
            }
        }
        None => fail!(pwbufp, libc::c_int::from(NssStatus::NotFound)),
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwuid_r(uid: libc::uid_t,
                                         pw: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         pwbufp: *mut *mut Passwd)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => fail!(pwbufp, libc::c_int::from(NssStatus::NotFound)),
    };
    for member in team.members.values() {
        if uid == member.id as libc::uid_t {
            match unsafe { (*pw).pack_args(&mut buffer, &member.login, member.id, team.id, &CONFIG) } {
                Ok(_) => succeed!(pwbufp, pw),
                Err(_) => fail!(pwbufp, nix::Errno::ERANGE as libc::c_int),
            }
        }
    }
    fail!(pwbufp, libc::c_int::from(NssStatus::NotFound))
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setpwent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    for member in team.members.values() {
        list_file.write(format!("{}\t{}\t{}\n", member.login, member.id, team.id).as_bytes())
                 .unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getpwent_r(pwbuf: *mut Passwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         pwbufp: *mut *mut Passwd)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(pwbufp, libc::c_int::from(NssStatus::Unavail)),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let id = words[1].parse::<u64>().unwrap();
        let gid = words[2].parse::<u64>().unwrap();
        match unsafe { (*pwbuf).pack_args(&mut buffer, words[0], id, gid, &CONFIG) } {
            Ok(_) => succeed!(pwbufp, pwbuf, runfiles::increment(idx, idx_file)),
            Err(_) => fail!(pwbufp, nix::Errno::ERANGE as libc::c_int),
        }
    }
    fail!(pwbufp, libc::c_int::from(NssStatus::Unavail))
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getspnam_r(cnameptr: *const libc::c_char,
                                         spwd: *mut Spwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         spbufp: *mut *mut Spwd)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => fail!(spbufp, libc::c_int::from(NssStatus::NotFound)),
    };
    match team.members.get(&name) {
        Some(member) => {
            match unsafe { (*spwd).pack_args(&mut buffer, &member.login, &CONFIG) } {
                Ok(_) => succeed!(spbufp, spwd),
                Err(_) => fail!(spbufp, nix::Errno::ERANGE as libc::c_int),
            }
        }
        None => fail!(spbufp, libc::c_int::from(NssStatus::NotFound)),
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setspent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    for member in team.members.values() {
        list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                 .unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getspent_r(spbuf: *mut Spwd,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         spbufp: *mut *mut Spwd)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(spbufp, libc::c_int::from(NssStatus::Unavail)),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        match unsafe { (*spbuf).pack_args(&mut buffer, words[0], &CONFIG) } {
            Ok(_) => succeed!(spbufp, spbuf, runfiles::increment(idx, idx_file)),
            Err(_) => fail!(spbufp, nix::Errno::ERANGE as libc::c_int),
        }
    }
    fail!(spbufp, libc::c_int::from(NssStatus::Unavail))
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrgid_r(gid: libc::gid_t,
                                         group: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         grbufp: *mut *mut Group)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => fail!(grbufp, libc::c_int::from(NssStatus::NotFound)),
    };
    let members: Vec<&str> = team.members.values().map(|m| m.login.as_str()).collect();
    if gid as u64 == team.id {
        match unsafe { (*group).pack_args(&mut buffer, &team.name, gid as u64, &members) } {
            Ok(_) => succeed!(grbufp, group),
            Err(_) => fail!(grbufp, nix::Errno::ERANGE as libc::c_int),
        }
    } else {
        fail!(grbufp, libc::c_int::from(NssStatus::NotFound))
    }
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrnam_r(cnameptr: *const libc::c_char,
                                         group: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         grbufp: *mut *mut Group)
                                         -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => fail!(grbufp, libc::c_int::from(NssStatus::NotFound)),
    };
    let members: Vec<&str> = team.members.values().map(|m| m.login.as_str()).collect();
    if name == team.name {
        match unsafe { (*group).pack_args(&mut buffer, &team.name, team.id, &members) } {
            Ok(_) => succeed!(grbufp, group),
            Err(_) => fail!(grbufp, nix::Errno::ERANGE as libc::c_int),
        }
    }
    fail!(grbufp, libc::c_int::from(NssStatus::NotFound))
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_setgrent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let team = match CLIENT.get_team() {
        Ok(team) => team,
        Err(_) => return libc::c_int::from(NssStatus::Success),
    };
    let member_names = team.members.values().map(|x| x.login.as_str()).collect::<Vec<&str>>().join(" ");
    list_file.write(format!("{}\t{}\t{}\n", team.name, team.id, member_names).as_bytes())
             .unwrap();
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_getgrent_r(grbuf: *mut Group,
                                         buf: *mut libc::c_char,
                                         buflen: libc::size_t,
                                         grbufp: *mut *mut Group)
                                         -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(grbufp, libc::c_int::from(NssStatus::Unavail)),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let member_names: Vec<&str> = words[2].split(" ").collect();
        let gid = words[1].parse::<u64>().unwrap();
        match unsafe { (*grbuf).pack_args(&mut buffer, words[0], gid, &member_names) } {
            Ok(_) => succeed!(grbufp, grbuf, runfiles::increment(idx, idx_file)),
            Err(_) => fail!(grbufp, nix::Errno::ERANGE as libc::c_int),
        }
    }
    fail!(grbufp, libc::c_int::from(NssStatus::Unavail))
}

#[no_mangle]
pub extern "C" fn _nss_ghteam_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<|endoftext|>


<commit_before>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::Ordering;
use score::Score;

struct Search {
    config: Configuration,
    current: uint,
    max_index: uint,
    query: String,
    selection: String,
    result: Vec<String>,
}

impl Search {
    fn blank(config: Configuration) -> Search {
        let max_index = config.visible_limit;
        let query = config.initial_search.clone();

        Search::new(config, query, max_index, 0)
    }

    fn new(config: Configuration, query: String, max_index: uint, index: uint) -> Search {
        let result = Search::filter(query.as_slice(), config.choices.clone());

        Search { config: config,
                 current: index,
                 max_index: max_index,
                 query: query,
                 selection: result[index].to_string(),
                 result: result }
    }

    fn new_for_index(self, index: uint) -> Search {
        Search::new(self.config, self.query, self.max_index, index)
    }

    fn filter(query: &str, choices: Vec<String>) -> Vec<String> {
        let mut filtered = choices.iter().filter_map( |choice| {
            let quality = Score::score(choice.as_slice(), query);
            if quality > 0.0 {
                Some((quality, choice.to_string()))
            } else {
                None
            }
        }).collect::<Vec<(f32, String)>>();

        filtered.sort_by( |&(quality_a, _), &(quality_b, _)| {
            quality_a.partial_cmp(&quality_b).unwrap_or(Ordering::Equal).reverse()
        });

        filtered.iter().map( |&(_, ref choice)| choice.to_string() ).collect::<Vec<String>>()
    }

    fn down(self) -> Search {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    fn up(self) -> Search {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    fn append_to_search(self, input: String) -> Search {
        let mut new_query = self.query;
        new_query.push_str(input.as_slice());
        Search::new(self.config, new_query, self.max_index, self.current)
    }

    fn next_index(&self) -> uint {
        let next_index = self.current + 1;

        if next_index >= self.max_index { 0 } else { next_index }
    }

    fn prev_index(&self) -> uint {
        if self.current == 0 { self.max_index - 1 } else  { self.current - 1 }
    }
}

#[cfg(test)]

#[test]
fn it_selects_the_first_choice_by_default() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.selection, "one");
}

fn one_two_three() -> Vec<String> {
    vec!["one".to_string(),
         "two".to_string(),
         "three".to_string()]
}

#[test]
fn it_selets_the_second_when_down_is_called() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.down().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_end_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.down().down().down().down().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_top_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.up().up().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_visible_limit() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, Some(2));
    let search = Search::blank(config);

    assert_eq!(search.down().down().down().selection, "two");
}

#[test]
fn it_moves_down_the_filtered_search_results() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t".to_string()).down().selection, "three");
}

#[test]
fn it_moves_down_the_filtered_search_results_twice() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t".to_string())
               .append_to_search("w".to_string()).selection, "two");
}
<commit_msg>Access visible_limit directly rather than storing max.<commit_after>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::Ordering;
use score::Score;

struct Search {
    config: Configuration,
    current: uint,
    query: String,
    selection: String,
    result: Vec<String>,
}

impl Search {
    fn blank(config: Configuration) -> Search {
        let query = config.initial_search.clone();

        Search::new(config, query, 0)
    }

    fn new(config: Configuration, query: String, index: uint) -> Search {
        let result = Search::filter(query.as_slice(), &config.choices.clone());

        Search { config: config,
                 current: index,
                 query: query,
                 selection: result[index].to_string(),
                 result: result }
    }

    fn new_for_index(self, index: uint) -> Search {
        Search::new(self.config, self.query, index)
    }

    fn filter(query: &str, choices: &Vec<String>) -> Vec<String> {
        let mut filtered = choices.iter().filter_map( |choice| {
            let quality = Score::score(choice.as_slice(), query);
            if quality > 0.0 {
                Some((quality, choice.to_string()))
            } else {
                None
            }
        }).collect::<Vec<(f32, String)>>();

        filtered.sort_by( |&(quality_a, _), &(quality_b, _)| {
            quality_a.partial_cmp(&quality_b).unwrap_or(Ordering::Equal).reverse()
        });

        filtered.iter().map( |&(_, ref choice)| choice.to_string() ).collect::<Vec<String>>()
    }

    fn down(self) -> Search {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    fn up(self) -> Search {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    fn append_to_search(self, input: String) -> Search {
        let mut new_query = self.query;
        new_query.push_str(input.as_slice());
        Search::new(self.config, new_query, self.current)
    }

    fn next_index(&self) -> uint {
        let next_index = self.current + 1;

        if next_index >= self.config.visible_limit { 0 } else { next_index }
    }

    fn prev_index(&self) -> uint {
        if self.current == 0 { self.config.visible_limit - 1 } else  { self.current - 1 }
    }
}

#[cfg(test)]

#[test]
fn it_selects_the_first_choice_by_default() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.selection, "one");
}

fn one_two_three() -> Vec<String> {
    vec!["one".to_string(),
         "two".to_string(),
         "three".to_string()]
}

#[test]
fn it_selets_the_second_when_down_is_called() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.down().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_end_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.down().down().down().down().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_top_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.up().up().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_visible_limit() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, Some(2));
    let search = Search::blank(config);

    assert_eq!(search.down().down().down().selection, "two");
}

#[test]
fn it_moves_down_the_filtered_search_results() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t".to_string()).down().selection, "three");
}

#[test]
fn it_moves_down_the_filtered_search_results_twice() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t".to_string())
               .append_to_search("w".to_string()).selection, "two");
}
<|endoftext|>