<commit_before>//! The Runner is where all the examples are actually executed.
//!
//! A Runner is instanciated by using [`context::describe`](../context/fn.describe.html) and
//! [`context::rdescribe`](../context/fn.rdescribe.html). You should not try to instanciate
//! a Runner directly.
//!
//! The main methods are `Runner::run` and `Runner::result`.

use context::*;
use events;
use events::Event;
use example_result;
use example_result::ExampleResult;

pub type RunnerResult = Result<TestReport, TestReport>;

/// Handlers is a separate struct which only holds the registered handlers.
/// This is useful to Runner so that its recursive call doesn't have to keep a refernce to `self`
#[derive(Default)]
struct Handlers<'a> {
    handlers: Vec<&'a mut events::EventHandler>,
}

impl<'a> Handlers<'a> {
    fn broadcast(&mut self, event: &events::Event) {
        for h in &mut self.handlers {
            h.trigger(event)
        }
    }
}

pub struct Runner<'a> {
    describe: Context<'a>,
    report: Option<RunnerResult>,
    handlers: Handlers<'a>,
}

impl<'a> Runner<'a> {
    pub fn new(context: Context<'a>) -> Runner<'a> {
        Runner {
            describe: context,
            handlers: Handlers::default(),
            report: None,
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub struct TestReport {
    pub total_tests: u32,
    pub success_count: u32,
    pub error_count: u32,
}

impl<'a> Runner<'a> {

    #[cfg_attr(feature="clippy", allow(redundant_closure))]
    fn run_test(mut test_function: Box<TestFunction>)
                -> ExampleResult {

        use std::panic::{catch_unwind, AssertUnwindSafe};
        use example_result;

        let res = catch_unwind(AssertUnwindSafe(|| test_function()));

        res.unwrap_or_else(|_| example_result::FAILED_RES)
    }

    fn run_and_recurse(report: &mut TestReport,
                       child_ctx: &mut Context,
                       handlers: &mut Handlers)
                       -> ExampleResult {

        use std::mem;
        let mut result = example_result::SUCCESS_RES;

        // As Runner::run consomes the runner, we can deconstruct the context tree as we travel
        // among it.
        // This effectively takes ownership of the context node and replace it with an empty one.
        let ctx = mem::replace(child_ctx, Context::default());

        let tests = ctx.tests;
        let mut before_functions = ctx.before_each;
        let mut after_functions = ctx.after_each;

        for mut test_function in tests {
            let test_res = {
                for before_function in before_functions.iter_mut() {
                    before_function()
                }
                let res = match test_function {
                    Testable::Test(name, test_function) => {
                        handlers.broadcast(&Event::StartTest(name));
                        let res = Runner::run_test(test_function);
                        handlers.broadcast(&Event::EndTest(res));
                        res
                    }
                    Testable::Describe(ref name, ref mut desc) => {
                        handlers.broadcast(&Event::StartDescribe(name.clone()));
                        let res = Runner::run_and_recurse(report, desc, handlers);
                        handlers.broadcast(&Event::EndDescribe);
                        res
                    }
                };
                for after_function in after_functions.iter_mut() {
                    after_function()
                }
                res
            };

            report.total_tests += 1;

            if test_res.is_ok() {
                report.success_count += 1;
            } else {
                report.error_count += 1
            }

            result = test_res.or(result);
        }

        result
    }

    pub fn run(mut self) -> RunnerResult {
        self.handlers.broadcast(&Event::StartRunner);

        let mut report = TestReport::default();
        let result = Runner::run_and_recurse(&mut report, &mut self.describe, &mut self.handlers);
        let result = result.res().and(Ok(report)).or_else(|_| Err(report));

        self.handlers.broadcast(&Event::FinishedRunner(result));
        result
    }

    pub fn result(&self) -> RunnerResult {
        self.report.unwrap_or_else(|| Ok(TestReport::default()))
    }

    pub fn add_event_handler<H: events::EventHandler>(&mut self, handler: &'a mut H) {
        self.handlers.handlers.push(handler)
    }
}

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

    mod run {
        pub use super::*;

        #[test]
        fn it_create_a_runner_that_can_be_runned() {
            let runner = describe("A root", |ctx| {
                ctx.it("is expected to run", || {
                    assert_eq!(true, true);
                    Ok(()) as Result<(),()>
                })
            });
            assert!(runner.run().is_ok());
        }

        #[test]
        fn effectively_run_tests() {
            let ran = &mut false;

            {
                let runner = describe("A root", |ctx| {
                    ctx.it("is expected to run", || {
                        *ran = true;
                        Ok(()) as Result<(),()>
                    })
                });
                runner.run().unwrap();
            }

            assert_eq!(true, *ran)
        }

        #[test]
        fn effectively_run_two_tests() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let ran_counter = &mut AtomicUsize::new(0);

            {
                let runner = describe("A root", |ctx| {
                    ctx.it("first run", || {
                        ran_counter.fetch_add(1, Ordering::Relaxed);
                        Ok(()) as Result<(),()>
                    });
                    ctx.it("second run", || {
                        ran_counter.fetch_add(1, Ordering::Relaxed);
                        Ok(()) as Result<(),()>
                    });
                });
                runner.run().unwrap();
            }

            assert_eq!(2, ran_counter.load(Ordering::Relaxed))
        }

        #[test]
        fn effectively_run_two_tests_in_nested_describe() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let ran_counter = &mut AtomicUsize::new(0);

            {
                let runner = describe("A root", |ctx| {
                    ctx.describe("first describe", |ctx| {
                        ctx.it("first run", || {
                            ran_counter.fetch_add(1, Ordering::Relaxed);
                            Ok(()) as Result<(),()>
                        });
                    });
                    ctx.describe("second describe", |ctx| {
                        ctx.it("second run", || {
                            ran_counter.fetch_add(1, Ordering::Relaxed);
                            Ok(()) as Result<(),()>
                        });
                    });
                    ctx.describe("third describe", |ctx| {
                        ctx.describe("fourth describe", |ctx| {
                            ctx.it("third run", || {
                                ran_counter.fetch_add(1, Ordering::Relaxed);
                                Ok(()) as Result<(),()>
                            });
                        })
                    })
                });
                runner.run().unwrap();
            }

            assert_eq!(3, ran_counter.load(Ordering::Relaxed))
        }

        mod events {
            pub use super::*;
            pub use events::*;
            pub use events::Event::*;

            #[derive(Default)]
            struct StubEventHandler {
                pub events: Vec<Event>,
            }

            impl EventHandler for StubEventHandler {
                fn trigger(&mut self, event: &Event) {
                    self.events.push(event.clone())
                }
            }

            #[test]
            fn start_runner_event_is_sent() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartRunner), handler.events.get(0))
            }

            #[test]
            fn no_event_when_no_run() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);
                }

                assert_eq!(None, handler.events.get(0))
            }

            #[test]
            fn finished_runner_event_is_last_event_sent() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                if let Some(&FinishedRunner(_)) = handler.events.last() {
                    assert!(true);
                } else {
                    assert!(false, "FinishedRunner event not sent at last")
                }
            }

            #[test]
            fn finished_runner_event_has_correct_test_report() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("one good test",
                                              |ctx| ctx.it("is a good test", || Ok(()) as Result<(),()>));
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                if let Some(&FinishedRunner(Ok(report))) = handler.events.last() {
                    let expected_report = TestReport {
                        total_tests: 1,
                        success_count: 1,
                        error_count: 0,
                    };
                    assert_eq!(expected_report, report)
                } else {
                    assert!(false, "FinishedRunner send bad TestReport")
                }
            }

            #[test]
            fn start_test_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root", |ctx| {
                        ctx.it("should run with an event", || Ok(()) as Result<(),()>);
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartTest(String::from("should run with an event"))),
                           handler.events.get(1))
            }

            #[test]
            fn end_test_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root", |ctx| {
                        ctx.it("should run with an event", || Ok(()) as Result<(),()>);
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&EndTest(SUCCESS_RES)), handler.events.get(2));
            }

            #[test]
            fn start_describe_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root, no hook", |ctx| {
                        ctx.describe("this has a hook", |_| {});
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartDescribe(String::from("this has a hook"))),
                           handler.events.get(1));
            }

            #[test]
            fn end_describe_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root, no hook", |ctx| {
                        ctx.describe("this has a hook", |_| {});
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&EndDescribe), handler.events.get(2));
            }
        }
    }

    mod results {
        pub use super::*;

        #[test]
        fn tests_can_fail_with_an_error_result() {
            let runner = describe("A root", |ctx| ctx.it("should fail", || Err(()) as Result<(),()>));
            let result = runner.run();

            assert!(result.is_err());
        }

        #[test]
        fn should_be_ok_if_tests_are_ok() {
            let runner = describe("A root", |ctx| ctx.it("should be ok", || Ok(()) as Result<(),()>));
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn is_ok_if_no_tests_have_been_runned() {
            let runner = describe("A root", |_ctx| {});
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn is_err_if_one_test_is_err() {
            let runner = describe("A root", |ctx| {
                ctx.it("an err", || Err(()) as Result<(),()>);
                ctx.it("an ok", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_err());
        }

        #[test]
        fn is_ok_if_all_tests_are_ok() {
            let runner = describe("A root", |ctx| {
                ctx.it("ok 1", || Ok(()) as Result<(),()>);
                ctx.it("ok 2", || Ok(()) as Result<(),()>);
                ctx.it("ok 3", || Ok(()) as Result<(),()>);
                ctx.it("ok 4", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn correctly_count_errors() {
            let runner = describe("a root", |ctx| {
                ctx.it("first is ok", || ());
                ctx.it("second is not", || false);
            });

            if let Err(res) = runner.run() {
                assert_eq!((1, 1),
                           (res.success_count, res.error_count));
            } else {
                assert!(false, "unreachable");
            }

        }

        #[test]
        fn tests_can_contains_asserts_that_panic() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let counter = &mut AtomicUsize::new(0);

            let runner = describe("A root", |ctx| {
                ctx.it("assert_eq fail", || {
                    assert_eq!(true, false);
                    Ok(()) as Result<(),()>
                });
                ctx.it("this should also be runned", || {
                    counter.fetch_add(1, Ordering::Relaxed);
                    Ok(()) as Result<(),()>
                })
            });
            let result = runner.run();

            // TODO refactor this to tuple
            assert!(result.is_err());
            assert_eq!(1, counter.load(Ordering::Relaxed));
        }

        #[test]
        fn can_count_the_tests() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Ok(()) as Result<(),()>);
                ctx.it("second", || Ok(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let results = runner.run();

            assert!(results.is_ok());
            if let Ok(report) = results {
                assert_eq!(3, report.total_tests);
            }
        }

        #[test]
        fn can_count_succes() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Ok(()) as Result<(),()>);
                ctx.it("second", || Ok(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_ok());
            if let Ok(report) = result {
                assert_eq!(3, report.success_count);
            }
        }

        #[test]
        fn can_count_errors() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Err(()) as Result<(),()>);
                ctx.it("second", || Err(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_err());
            if let Err(report) = result {
                assert_eq!(2, report.error_count);
            }
        }
    }
}
<commit_msg>rm now useless Runner#result<commit_after>//! The Runner is where all the examples are actually executed.
//!
//! A Runner is instanciated by using [`context::describe`](../context/fn.describe.html) and
//! [`context::rdescribe`](../context/fn.rdescribe.html). You should not try to instanciate
//! a Runner directly.
//!
//! The main methods are `Runner::run` and `Runner::result`.

use context::*;
use events;
use events::Event;
use example_result;
use example_result::ExampleResult;

pub type RunnerResult = Result<TestReport, TestReport>;

/// Handlers is a separate struct which only holds the registered handlers.
/// This is useful to Runner so that its recursive call doesn't have to keep a refernce to `self`
#[derive(Default)]
struct Handlers<'a> {
    handlers: Vec<&'a mut events::EventHandler>,
}

impl<'a> Handlers<'a> {
    fn broadcast(&mut self, event: &events::Event) {
        for h in &mut self.handlers {
            h.trigger(event)
        }
    }
}

pub struct Runner<'a> {
    describe: Context<'a>,
    report: Option<RunnerResult>,
    handlers: Handlers<'a>,
}

impl<'a> Runner<'a> {
    pub fn new(context: Context<'a>) -> Runner<'a> {
        Runner {
            describe: context,
            handlers: Handlers::default(),
            report: None,
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub struct TestReport {
    pub total_tests: u32,
    pub success_count: u32,
    pub error_count: u32,
}

impl<'a> Runner<'a> {

    #[cfg_attr(feature="clippy", allow(redundant_closure))]
    fn run_test(mut test_function: Box<TestFunction>)
                -> ExampleResult {

        use std::panic::{catch_unwind, AssertUnwindSafe};
        use example_result;

        let res = catch_unwind(AssertUnwindSafe(|| test_function()));

        res.unwrap_or_else(|_| example_result::FAILED_RES)
    }

    fn run_and_recurse(report: &mut TestReport,
                       child_ctx: &mut Context,
                       handlers: &mut Handlers)
                       -> ExampleResult {

        use std::mem;
        let mut result = example_result::SUCCESS_RES;

        // As Runner::run consomes the runner, we can deconstruct the context tree as we travel
        // among it.
        // This effectively takes ownership of the context node and replace it with an empty one.
        let ctx = mem::replace(child_ctx, Context::default());

        let tests = ctx.tests;
        let mut before_functions = ctx.before_each;
        let mut after_functions = ctx.after_each;

        for mut test_function in tests {
            let test_res = {
                for before_function in before_functions.iter_mut() {
                    before_function()
                }
                let res = match test_function {
                    Testable::Test(name, test_function) => {
                        handlers.broadcast(&Event::StartTest(name));
                        let res = Runner::run_test(test_function);
                        handlers.broadcast(&Event::EndTest(res));
                        res
                    }
                    Testable::Describe(ref name, ref mut desc) => {
                        handlers.broadcast(&Event::StartDescribe(name.clone()));
                        let res = Runner::run_and_recurse(report, desc, handlers);
                        handlers.broadcast(&Event::EndDescribe);
                        res
                    }
                };
                for after_function in after_functions.iter_mut() {
                    after_function()
                }
                res
            };

            report.total_tests += 1;

            if test_res.is_ok() {
                report.success_count += 1;
            } else {
                report.error_count += 1
            }

            result = test_res.or(result);
        }

        result
    }

    pub fn run(mut self) -> RunnerResult {
        self.handlers.broadcast(&Event::StartRunner);

        let mut report = TestReport::default();
        let result = Runner::run_and_recurse(&mut report, &mut self.describe, &mut self.handlers);
        let result = result.res().and(Ok(report)).or_else(|_| Err(report));

        self.handlers.broadcast(&Event::FinishedRunner(result));
        result
    }

    pub fn add_event_handler<H: events::EventHandler>(&mut self, handler: &'a mut H) {
        self.handlers.handlers.push(handler)
    }
}

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

    mod run {
        pub use super::*;

        #[test]
        fn it_create_a_runner_that_can_be_runned() {
            let runner = describe("A root", |ctx| {
                ctx.it("is expected to run", || {
                    assert_eq!(true, true);
                    Ok(()) as Result<(),()>
                })
            });
            assert!(runner.run().is_ok());
        }

        #[test]
        fn effectively_run_tests() {
            let ran = &mut false;

            {
                let runner = describe("A root", |ctx| {
                    ctx.it("is expected to run", || {
                        *ran = true;
                        Ok(()) as Result<(),()>
                    })
                });
                runner.run().unwrap();
            }

            assert_eq!(true, *ran)
        }

        #[test]
        fn effectively_run_two_tests() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let ran_counter = &mut AtomicUsize::new(0);

            {
                let runner = describe("A root", |ctx| {
                    ctx.it("first run", || {
                        ran_counter.fetch_add(1, Ordering::Relaxed);
                        Ok(()) as Result<(),()>
                    });
                    ctx.it("second run", || {
                        ran_counter.fetch_add(1, Ordering::Relaxed);
                        Ok(()) as Result<(),()>
                    });
                });
                runner.run().unwrap();
            }

            assert_eq!(2, ran_counter.load(Ordering::Relaxed))
        }

        #[test]
        fn effectively_run_two_tests_in_nested_describe() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let ran_counter = &mut AtomicUsize::new(0);

            {
                let runner = describe("A root", |ctx| {
                    ctx.describe("first describe", |ctx| {
                        ctx.it("first run", || {
                            ran_counter.fetch_add(1, Ordering::Relaxed);
                            Ok(()) as Result<(),()>
                        });
                    });
                    ctx.describe("second describe", |ctx| {
                        ctx.it("second run", || {
                            ran_counter.fetch_add(1, Ordering::Relaxed);
                            Ok(()) as Result<(),()>
                        });
                    });
                    ctx.describe("third describe", |ctx| {
                        ctx.describe("fourth describe", |ctx| {
                            ctx.it("third run", || {
                                ran_counter.fetch_add(1, Ordering::Relaxed);
                                Ok(()) as Result<(),()>
                            });
                        })
                    })
                });
                runner.run().unwrap();
            }

            assert_eq!(3, ran_counter.load(Ordering::Relaxed))
        }

        mod events {
            pub use super::*;
            pub use events::*;
            pub use events::Event::*;

            #[derive(Default)]
            struct StubEventHandler {
                pub events: Vec<Event>,
            }

            impl EventHandler for StubEventHandler {
                fn trigger(&mut self, event: &Event) {
                    self.events.push(event.clone())
                }
            }

            #[test]
            fn start_runner_event_is_sent() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartRunner), handler.events.get(0))
            }

            #[test]
            fn no_event_when_no_run() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);
                }

                assert_eq!(None, handler.events.get(0))
            }

            #[test]
            fn finished_runner_event_is_last_event_sent() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("empty but should run anyway", |_| {});
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                if let Some(&FinishedRunner(_)) = handler.events.last() {
                    assert!(true);
                } else {
                    assert!(false, "FinishedRunner event not sent at last")
                }
            }

            #[test]
            fn finished_runner_event_has_correct_test_report() {
                let mut handler = StubEventHandler::default();
                {
                    let mut runner = describe("one good test",
                                              |ctx| ctx.it("is a good test", || Ok(()) as Result<(),()>));
                    runner.add_event_handler(&mut handler);

                    runner.run().unwrap();
                }

                if let Some(&FinishedRunner(Ok(report))) = handler.events.last() {
                    let expected_report = TestReport {
                        total_tests: 1,
                        success_count: 1,
                        error_count: 0,
                    };
                    assert_eq!(expected_report, report)
                } else {
                    assert!(false, "FinishedRunner send bad TestReport")
                }
            }

            #[test]
            fn start_test_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root", |ctx| {
                        ctx.it("should run with an event", || Ok(()) as Result<(),()>);
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartTest(String::from("should run with an event"))),
                           handler.events.get(1))
            }

            #[test]
            fn end_test_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root", |ctx| {
                        ctx.it("should run with an event", || Ok(()) as Result<(),()>);
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&EndTest(SUCCESS_RES)), handler.events.get(2));
            }

            #[test]
            fn start_describe_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root, no hook", |ctx| {
                        ctx.describe("this has a hook", |_| {});
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&StartDescribe(String::from("this has a hook"))),
                           handler.events.get(1));
            }

            #[test]
            fn end_describe_is_broadcasted() {
                let mut handler = StubEventHandler::default();

                {
                    let mut runner = describe("root, no hook", |ctx| {
                        ctx.describe("this has a hook", |_| {});
                    });
                    runner.add_event_handler(&mut handler);
                    runner.run().unwrap();
                }

                assert_eq!(Some(&EndDescribe), handler.events.get(2));
            }
        }
    }

    mod results {
        pub use super::*;

        #[test]
        fn tests_can_fail_with_an_error_result() {
            let runner = describe("A root", |ctx| ctx.it("should fail", || Err(()) as Result<(),()>));
            let result = runner.run();

            assert!(result.is_err());
        }

        #[test]
        fn should_be_ok_if_tests_are_ok() {
            let runner = describe("A root", |ctx| ctx.it("should be ok", || Ok(()) as Result<(),()>));
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn is_ok_if_no_tests_have_been_runned() {
            let runner = describe("A root", |_ctx| {});
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn is_err_if_one_test_is_err() {
            let runner = describe("A root", |ctx| {
                ctx.it("an err", || Err(()) as Result<(),()>);
                ctx.it("an ok", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_err());
        }

        #[test]
        fn is_ok_if_all_tests_are_ok() {
            let runner = describe("A root", |ctx| {
                ctx.it("ok 1", || Ok(()) as Result<(),()>);
                ctx.it("ok 2", || Ok(()) as Result<(),()>);
                ctx.it("ok 3", || Ok(()) as Result<(),()>);
                ctx.it("ok 4", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_ok());
        }

        #[test]
        fn correctly_count_errors() {
            let runner = describe("a root", |ctx| {
                ctx.it("first is ok", || ());
                ctx.it("second is not", || false);
            });

            if let Err(res) = runner.run() {
                assert_eq!((1, 1),
                           (res.success_count, res.error_count));
            } else {
                assert!(false, "unreachable");
            }

        }

        #[test]
        fn tests_can_contains_asserts_that_panic() {
            use std::sync::atomic::{AtomicUsize, Ordering};
            let counter = &mut AtomicUsize::new(0);

            let runner = describe("A root", |ctx| {
                ctx.it("assert_eq fail", || {
                    assert_eq!(true, false);
                    Ok(()) as Result<(),()>
                });
                ctx.it("this should also be runned", || {
                    counter.fetch_add(1, Ordering::Relaxed);
                    Ok(()) as Result<(),()>
                })
            });
            let result = runner.run();

            // TODO refactor this to tuple
            assert!(result.is_err());
            assert_eq!(1, counter.load(Ordering::Relaxed));
        }

        #[test]
        fn can_count_the_tests() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Ok(()) as Result<(),()>);
                ctx.it("second", || Ok(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let results = runner.run();

            assert!(results.is_ok());
            if let Ok(report) = results {
                assert_eq!(3, report.total_tests);
            }
        }

        #[test]
        fn can_count_succes() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Ok(()) as Result<(),()>);
                ctx.it("second", || Ok(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_ok());
            if let Ok(report) = result {
                assert_eq!(3, report.success_count);
            }
        }

        #[test]
        fn can_count_errors() {
            let runner = describe("a root", |ctx| {
                ctx.it("first", || Err(()) as Result<(),()>);
                ctx.it("second", || Err(()) as Result<(),()>);
                ctx.it("third", || Ok(()) as Result<(),()>);
            });
            let result = runner.run();

            assert!(result.is_err());
            if let Err(report) = result {
                assert_eq!(2, report.error_count);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::fs::OpenOptions;
use std::io::BufWriter;
use std::io::Result;
use time::{now, Tm};

// Internal modules:
use configuration::{Configuration, HEADER_LENGTH};

fn write_xml_data(tm: Tm, local_port: u16, buffer: &[u8], file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.xml", file_name))));

    let current_date_time = tm.strftime("%Y.%m.%d - %H:%M:%S").unwrap();

    try!(write!(file_handle, "<measure>\n"));
    try!(write!(file_handle, "<port>{}</port>\n", local_port));
    try!(write!(file_handle, "<date_time>{}</date_time>\n", &current_date_time));
    try!(write!(file_handle, "<data>\n"));
    try!(write!(file_handle, "{:?}\n", buffer));
    try!(write!(file_handle, "</data>\n"));
    try!(write!(file_handle, "</measure>\n\n"));

    Ok(())
}

fn write_csv_data(buffer: &[u8], file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.csv", file_name))));

    for i in 3..buffer.len() {
        try!(write!(file_handle, "{}", buffer[i].to_string()));
    }

    try!(write!(file_handle, "\n"));

    Ok(())
}

fn port_to_station(port: u16) -> String{
    match port {
        2100 => "2100_Na".to_string(),
        2101 => "2101_SG".to_string(),
        2102 => "2102_PdA".to_string(),
        2103 => "2103_LC".to_string(),
        _ => "unknown".to_string()
    }
}

fn handle_client(stream: &mut TcpStream, remote_addr: &SocketAddr,
    all_data_file: &Arc<Mutex<String>>, monthly_data_folder: &Arc<Mutex<String>>) -> Result<()> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
        SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

    let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);

    // TODO: use str::from_utf8(buf) if data is sent in clear text
    // Otherwise parse binary data to floats

    // base16 2 byte floats:
    // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
    // https://github.com/sgothel/jogl/blob/master/src/jogl/classes/com/jogamp/opengl/math/Binary16.java
    // https://books.google.de/books?id=FPlICAAAQBAJ&pg=PA84&lpg=PA84&dq=binary16&source=bl&ots=0FAzD4XOqn&sig=98h_pzPlLzUXjB4uY1T8MRIZOnA&hl=de&sa=X&ved=0ahUKEwjkpvXU5ZzLAhVD9HIKHQOfAxYQ6AEITzAH#v=onepage&q=binary16&f=false
    // http://www.gamedev.net/topic/557338-ieee-754-2008-binary-16-inaccuracy-in-wikipedia/

    if buffer.len() > HEADER_LENGTH {
        let (buffer_left, buffer_right) = buffer.split_at(HEADER_LENGTH);

        let str_header = String::from_utf8_lossy(buffer_left);
        let str_data = String::from_utf8_lossy(buffer_right);

        info!("Header: {:?}", buffer_left);
        info!("Data: {:?}", buffer_right);

        info!("Header (ASCII): '{}'", str_header);
        info!("Data (ASCII): '{}'", str_data);

        let station_folder = port_to_station(local_port);

        match all_data_file.lock() {
            Ok(all_data_file) => {
                let tm = now();
                let file_name = format!("{}/{}", station_folder, *all_data_file);
                try!(write_xml_data(tm, local_port, buffer_right, &file_name));
                try!(write_csv_data(buffer_right, &file_name));
            },
            Err(e) => info!("Mutex (poison) error (all_data_file): {}", e)
        }

        match monthly_data_folder.lock() {
            Ok(monthly_data_folder) => {
                let tm = now();
                let current_year = tm.strftime("%Y").unwrap();
                let current_month = tm.strftime("%m").unwrap();
                // TODO: create separate folder for year and month in Rust
                let file_name = format!("{}/{}/{}_{}", *monthly_data_folder, station_folder, current_year, current_month);
                try!(write_xml_data(tm, local_port, buffer_right, &file_name));
                try!(write_csv_data(buffer_right, &file_name));
            },
            Err(e) => info!("Mutex (poison) error (monthly_data_folder): {}", e)
        }
    } else if buffer.len() < HEADER_LENGTH {
        info!("Invalid header (less than {} bytes received)!", HEADER_LENGTH);
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    } else { // buffer.len() == HEADER_LENGTH -> no data, only header
        info!("No data received, just header.");
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    }

    Ok(())
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        match TcpListener::bind(("0.0.0.0", port)) {
            Ok(listener) => {
                info!("Create listener for port {}", port);
                listeners.push(listener);
            },
            Err(e) => info!("Network error: {}", e)
        }
    }

    let all_data_file = Arc::new(Mutex::new(config.all_data_file.clone()));
    let monthly_data_folder = Arc::new(Mutex::new(config.monthly_data_folder.clone()));

    for listener in listeners {
        let all_data_file = all_data_file.clone();
        let monthly_data_folder = monthly_data_folder.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
                    let (mut stream, addr) = result;
                    if let Err(io_error) = handle_client(&mut stream, &addr,
                            &all_data_file, &monthly_data_folder) {
                        info!("IOError: {}", io_error);
                    }
                }
            }
        });
    }
}
<commit_msg>fix conversion from integer to ascii char<commit_after>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::fs::OpenOptions;
use std::io::BufWriter;
use std::io::Result;
use time::{now, Tm};

// Internal modules:
use configuration::{Configuration, HEADER_LENGTH};

fn write_xml_data(tm: Tm, local_port: u16, buffer: &[u8], file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.xml", file_name))));

    let current_date_time = tm.strftime("%Y.%m.%d - %H:%M:%S").unwrap();

    try!(write!(file_handle, "<measure>\n"));
    try!(write!(file_handle, "<port>{}</port>\n", local_port));
    try!(write!(file_handle, "<date_time>{}</date_time>\n", &current_date_time));
    try!(write!(file_handle, "<data>\n"));
    try!(write!(file_handle, "{:?}\n", buffer));
    try!(write!(file_handle, "</data>\n"));
    try!(write!(file_handle, "</measure>\n\n"));

    Ok(())
}

fn write_csv_data(buffer: &[u8], file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.csv", file_name))));

    for i in 3..buffer.len() {
        try!(write!(file_handle, "{}", (buffer[i] as char) ));
    }

    try!(write!(file_handle, "\n"));

    Ok(())
}

fn port_to_station(port: u16) -> String{
    match port {
        2100 => "2100_Na".to_string(),
        2101 => "2101_SG".to_string(),
        2102 => "2102_PdA".to_string(),
        2103 => "2103_LC".to_string(),
        _ => "unknown".to_string()
    }
}

fn handle_client(stream: &mut TcpStream, remote_addr: &SocketAddr,
    all_data_file: &Arc<Mutex<String>>, monthly_data_folder: &Arc<Mutex<String>>) -> Result<()> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
        SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

    let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);

    // TODO: use str::from_utf8(buf) if data is sent in clear text
    // Otherwise parse binary data to floats

    // base16 2 byte floats:
    // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
    // https://github.com/sgothel/jogl/blob/master/src/jogl/classes/com/jogamp/opengl/math/Binary16.java
    // https://books.google.de/books?id=FPlICAAAQBAJ&pg=PA84&lpg=PA84&dq=binary16&source=bl&ots=0FAzD4XOqn&sig=98h_pzPlLzUXjB4uY1T8MRIZOnA&hl=de&sa=X&ved=0ahUKEwjkpvXU5ZzLAhVD9HIKHQOfAxYQ6AEITzAH#v=onepage&q=binary16&f=false
    // http://www.gamedev.net/topic/557338-ieee-754-2008-binary-16-inaccuracy-in-wikipedia/

    if buffer.len() > HEADER_LENGTH {
        let (buffer_left, buffer_right) = buffer.split_at(HEADER_LENGTH);

        let str_header = String::from_utf8_lossy(buffer_left);
        let str_data = String::from_utf8_lossy(buffer_right);

        info!("Header: {:?}", buffer_left);
        info!("Data: {:?}", buffer_right);

        info!("Header (ASCII): '{}'", str_header);
        info!("Data (ASCII): '{}'", str_data);

        let station_folder = port_to_station(local_port);

        match all_data_file.lock() {
            Ok(all_data_file) => {
                let tm = now();
                let file_name = format!("{}/{}", station_folder, *all_data_file);
                try!(write_xml_data(tm, local_port, buffer_right, &file_name));
                try!(write_csv_data(buffer_right, &file_name));
            },
            Err(e) => info!("Mutex (poison) error (all_data_file): {}", e)
        }

        match monthly_data_folder.lock() {
            Ok(monthly_data_folder) => {
                let tm = now();
                let current_year = tm.strftime("%Y").unwrap();
                let current_month = tm.strftime("%m").unwrap();
                // TODO: create separate folder for year and month in Rust
                let file_name = format!("{}/{}/{}_{}", *monthly_data_folder, station_folder, current_year, current_month);
                try!(write_xml_data(tm, local_port, buffer_right, &file_name));
                try!(write_csv_data(buffer_right, &file_name));
            },
            Err(e) => info!("Mutex (poison) error (monthly_data_folder): {}", e)
        }
    } else if buffer.len() < HEADER_LENGTH {
        info!("Invalid header (less than {} bytes received)!", HEADER_LENGTH);
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    } else { // buffer.len() == HEADER_LENGTH -> no data, only header
        info!("No data received, just header.");
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    }

    Ok(())
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        match TcpListener::bind(("0.0.0.0", port)) {
            Ok(listener) => {
                info!("Create listener for port {}", port);
                listeners.push(listener);
            },
            Err(e) => info!("Network error: {}", e)
        }
    }

    let all_data_file = Arc::new(Mutex::new(config.all_data_file.clone()));
    let monthly_data_folder = Arc::new(Mutex::new(config.monthly_data_folder.clone()));

    for listener in listeners {
        let all_data_file = all_data_file.clone();
        let monthly_data_folder = monthly_data_folder.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
                    let (mut stream, addr) = result;
                    if let Err(io_error) = handle_client(&mut stream, &addr,
                            &all_data_file, &monthly_data_folder) {
                        info!("IOError: {}", io_error);
                    }
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>extern crate dbus;
use self::dbus::{Connection, Message, MessageType, NameFlag, ReleaseNameReply};
use self::dbus::obj::ObjectPath;

use super::error::DBusError;
use super::target::DBusTarget;

use std::collections::btree_map::{BTreeMap, Entry};
use std::error::Error;

pub struct DBusServer<'a> {
    conn: &'a Connection,
    name: String,

    objects: BTreeMap<String, ObjectPath<'a>>,
    signals: BTreeMap<DBusTarget, Vec<fn (&Connection, &DBusTarget) -> ()>>,
    namespace_signals: BTreeMap<DBusTarget, Vec<fn (&Connection, &DBusTarget) -> ()>>,
}

impl<'a> DBusServer<'a> {
    pub fn new(conn: &'a Connection, name: &str) -> Result<DBusServer<'a>, dbus::Error> {
        try!(conn.register_name(name, NameFlag::DoNotQueue as u32));

        Ok(DBusServer {
            conn: conn,
            name: name.to_owned(),

            objects: BTreeMap::new(),
            signals: BTreeMap::new(),
            namespace_signals: BTreeMap::new(),
        })
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn add_object(&mut self, path: &str, add_interfaces: fn (&mut ObjectPath<'a>) -> ()) -> Result<&mut Self, Box<Error>> {
        // XXX: Use `.map` when type resolution works better. Currently, `.map` causes the caller
        // type to be set in stone due to eager type resolution and no fluidity in setting it. This
        // causes the type to be too concrete on the caller side which then fails to map to the end
        // result type of `.map` even though `.map` is "transparent" to the error type.
        Result::map(match self.objects.entry(path.to_owned()) {
            Entry::Vacant(v)    => {
                let mut obj = ObjectPath::new(self.conn, path, true);
                try!(obj.set_registered(true));

                // Add interfaces.
                add_interfaces(&mut obj);

                v.insert(obj);

                Ok(())
            },
            Entry::Occupied(_)  => Err(Box::new(DBusError::PathAlreadyRegistered(path.to_owned()))),
        }, |_| self)
    }

    pub fn remove_object(&mut self, path: &str) -> Result<&mut Self, DBusError> {
        match self.objects.remove(path) {
            Some(_) => Ok(self),
            None    => Err(DBusError::NoSuchPath(path.to_owned())),
        }
    }

    pub fn connect(&mut self, signal: DBusTarget, callback: fn (&Connection, &DBusTarget) -> ()) -> &mut Self {
        match self.signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };

        self

    pub fn connect_namespace(&mut self, signal: DBusTarget, callback: fn (&Connection, &DBusTarget) -> ()) -> &mut Self {
        match self.namespace_signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };

        self
    }

    pub fn handle_message<'b>(&mut self, m: &'b mut Message) -> Option<&'b mut Message> {
        match m.msg_type() {
            MessageType::Signal     => Some(self._match_signal(m)),
            MessageType::MethodCall => self._call_method(m),
            _                       => Some(m),
        }
    }

    fn _call_method<'b>(&mut self, m: &'b mut Message) -> Option<&'b mut Message> {
        self.objects.iter_mut().fold(Some(m), |opt_m, (_, object)| {
            opt_m.and_then(|mut m| {
                match object.handle_message(&mut m) {
                    None          => Some(m),
                    Some(Ok(()))  => None,
                    Some(Err(())) => {
                        println!("failed to send a reply for {:?}", m);
                        None
                    },
                }
            })
        })
    }

    fn _match_signal<'b>(&self, m: &'b mut Message) -> &'b mut Message {
        DBusTarget::extract(m).map(|signal| {
            self.signals.get(&signal).map(|fs| {
                fs.iter().map(|f| {
                    f(&self.conn, &signal);
                })
            });

            self.namespace_signals.get(&signal).map(|fs| {
                fs.iter().map(|f| {
                    f(&self.conn, &signal);
                })
            });
        });

        m
    }
}

impl<'a> Drop for DBusServer<'a> {
    fn drop(&mut self) {
        let res = self.conn.release_name(&self.name);
        match res {
            Ok(reply) =>
                match reply {
                    ReleaseNameReply::Released    => (),
                    ReleaseNameReply::NonExistent => panic!("internal error: non-existent name {}?!", self.name),
                    ReleaseNameReply::NotOwner    => panic!("internal error: not the owner of {}?!", self.name),
                },
            Err(err) => println!("failed to release {}: {:?}: {:?}", self.name, err.name(), err.message()),
        }
    }
}
<commit_msg>server: add match statements for signal watchers<commit_after>extern crate dbus;
use self::dbus::{Connection, Message, MessageType, NameFlag, ReleaseNameReply};
use self::dbus::obj::ObjectPath;

use super::error::DBusError;
use super::target::DBusTarget;

use std::collections::btree_map::{BTreeMap, Entry};
use std::error::Error;

pub struct DBusServer<'a> {
    conn: &'a Connection,
    name: String,

    objects: BTreeMap<String, ObjectPath<'a>>,
    signals: BTreeMap<DBusTarget, Vec<fn (&Connection, &DBusTarget) -> ()>>,
    namespace_signals: BTreeMap<DBusTarget, Vec<fn (&Connection, &DBusTarget) -> ()>>,
}

impl<'a> DBusServer<'a> {
    pub fn new(conn: &'a Connection, name: &str) -> Result<DBusServer<'a>, dbus::Error> {
        try!(conn.register_name(name, NameFlag::DoNotQueue as u32));

        Ok(DBusServer {
            conn: conn,
            name: name.to_owned(),

            objects: BTreeMap::new(),
            signals: BTreeMap::new(),
            namespace_signals: BTreeMap::new(),
        })
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn add_object(&mut self, path: &str, add_interfaces: fn (&mut ObjectPath<'a>) -> ()) -> Result<&mut Self, Box<Error>> {
        // XXX: Use `.map` when type resolution works better. Currently, `.map` causes the caller
        // type to be set in stone due to eager type resolution and no fluidity in setting it. This
        // causes the type to be too concrete on the caller side which then fails to map to the end
        // result type of `.map` even though `.map` is "transparent" to the error type.
        Result::map(match self.objects.entry(path.to_owned()) {
            Entry::Vacant(v)    => {
                let mut obj = ObjectPath::new(self.conn, path, true);
                try!(obj.set_registered(true));

                // Add interfaces.
                add_interfaces(&mut obj);

                v.insert(obj);

                Ok(())
            },
            Entry::Occupied(_)  => Err(Box::new(DBusError::PathAlreadyRegistered(path.to_owned()))),
        }, |_| self)
    }

    pub fn remove_object(&mut self, path: &str) -> Result<&mut Self, DBusError> {
        match self.objects.remove(path) {
            Some(_) => Ok(self),
            None    => Err(DBusError::NoSuchPath(path.to_owned())),
        }
    }

    pub fn connect(&mut self, signal: DBusTarget, callback: fn (&Connection, &DBusTarget) -> ()) -> Result<&mut Self, dbus::Error> {
        try!(self.conn.add_match(&format!("type='signal',interface='{}',path='{}',member='{}'",
                                          signal.interface,
                                          signal.object,
                                          signal.method)));

        match self.signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };

        Ok(self)
    }

    pub fn connect_namespace(&mut self, signal: DBusTarget, callback: fn (&Connection, &DBusTarget) -> ()) -> Result<&mut Self, dbus::Error> {
        try!(self.conn.add_match(&format!("type='signal',interface='{}',path_namespace='{}',member='{}'",
                                          signal.interface,
                                          signal.object,
                                          signal.method)));

        match self.namespace_signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };

        Ok(self)
    }

    pub fn handle_message<'b>(&mut self, m: &'b mut Message) -> Option<&'b mut Message> {
        match m.msg_type() {
            MessageType::Signal     => Some(self._match_signal(m)),
            MessageType::MethodCall => self._call_method(m),
            _                       => Some(m),
        }
    }

    fn _call_method<'b>(&mut self, m: &'b mut Message) -> Option<&'b mut Message> {
        self.objects.iter_mut().fold(Some(m), |opt_m, (_, object)| {
            opt_m.and_then(|mut m| {
                match object.handle_message(&mut m) {
                    None          => Some(m),
                    Some(Ok(()))  => None,
                    Some(Err(())) => {
                        println!("failed to send a reply for {:?}", m);
                        None
                    },
                }
            })
        })
    }

    fn _match_signal<'b>(&self, m: &'b mut Message) -> &'b mut Message {
        DBusTarget::extract(m).map(|signal| {
            self.signals.get(&signal).map(|fs| {
                fs.iter().map(|f| {
                    f(&self.conn, &signal);
                })
            });

            self.namespace_signals.get(&signal).map(|fs| {
                fs.iter().map(|f| {
                    f(&self.conn, &signal);
                })
            });
        });

        m
    }
}

impl<'a> Drop for DBusServer<'a> {
    fn drop(&mut self) {
        let res = self.conn.release_name(&self.name);
        match res {
            Ok(reply) =>
                match reply {
                    ReleaseNameReply::Released    => (),
                    ReleaseNameReply::NonExistent => panic!("internal error: non-existent name {}?!", self.name),
                    ReleaseNameReply::NotOwner    => panic!("internal error: not the owner of {}?!", self.name),
                },
            Err(err) => println!("failed to release {}: {:?}: {:?}", self.name, err.name(), err.message()),
        }
    }
}
<|endoftext|>


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

//! Slices
//!
//! See `Slice`-structure documentation for more information on this module.

use core::{handle, buffer};
use core::{Primitive, Resources, VertexCount};
use core::command::InstanceParams;
use core::factory::Factory;
use core::memory::Bind;
use format::Format;
use pso;

/// A `Slice` dictates in which and in what order vertices get processed. It is required for
/// processing a PSO.
///
/// # Overview
/// A `Slice` object in essence dictates in what order the vertices in a `VertexBuffer` get
/// processed. To do this, it contains an internal index-buffer. This `Buffer` is a list of
/// indices into this `VertexBuffer` (vertex-index). A vertex-index of 0 represents the first
/// vertex in the `VertexBuffer`, a vertex-index of 1 represents the second, 2 represents the
/// third, and so on. The vertex-indices in the index-buffer are read in order; every vertex-index
/// tells the pipeline which vertex to process next.
///
/// Because the same index can re-appear multiple times, duplicate-vertices can be avoided. For
/// instance, if you want to draw a square, you need two triangles, and thus six vertices. Because
/// the same index can reappear multiple times, this means we can instead use 4 vertices, and 6
/// vertex-indices.
///
/// This index-buffer has a few variants. See the `IndexBuffer` documentation for a detailed
/// description.
///
/// The `start` and `end` fields say where in the index-buffer to start and stop reading.
/// Setting `start` to 0, and `end` to the length of the index-buffer, will cause the entire
/// index-buffer to be processed. The `base_vertex` dictates the index of the first vertex
/// in the `VertexBuffer`. This essentially moves the the start of the `VertexBuffer`, to the
/// vertex with this index.
///
/// # Constuction & Handling
/// The `Slice` structure can be constructed automatically when using a `Factory` to create a
/// vertex buffer. If needed, it can also be created manually.
///
/// A `Slice` is required to process a PSO, as it contains the needed information on in what order
/// to draw which vertices. As such, every `draw` call on an `Encoder` requires a `Slice`.
#[derive(Clone, Debug, PartialEq)]
pub struct Slice<R: Resources> {
    /// The start index of the index-buffer. Processing will start at this location in the
    /// index-buffer.
    pub start: VertexCount,
    /// The end index in the index-buffer. Processing will stop at this location (exclusive) in
    /// the index buffer.
    pub end: VertexCount,
    /// This is the index of the first vertex in the `VertexBuffer`. This value will be added to
    /// every index in the index-buffer, effectively moving the start of the `VertexBuffer` to this
    /// base-vertex.
    pub base_vertex: VertexCount,
    /// Instancing configuration.
    pub instances: Option<InstanceParams>,
    /// Represents the type of index-buffer used.
    pub buffer: IndexBuffer<R>,
}

impl<R: Resources> Slice<R> {
    /// Creates a new `Slice` to match the supplied vertex buffer, from start to end, in order.
    pub fn new_match_vertex_buffer<V>(vbuf: &handle::Buffer<R, V>) -> Self
                                      where V: pso::buffer::Structure<Format> {
        Slice {
            start: 0,
            end: vbuf.len() as u32,
            base_vertex: 0,
            instances: None,
            buffer: IndexBuffer::Auto,
        }
    }

    /// Calculates the number of primitives of the specified type in this `Slice`.
    pub fn get_prim_count(&self, prim: Primitive) -> u32 {
        use core::Primitive as p;
        let nv = (self.end - self.start) as u32;
        match prim {
            p::PointList => nv,
            p::LineList => nv / 2,
            p::LineStrip => (nv-1),
            p::TriangleList => nv / 3,
            p::TriangleStrip => (nv-2) / 3,
            p::PatchList(num) => nv / (num as u32),
        }
    }
}

/// Type of index-buffer used in a Slice.
///
/// The `Auto` variant represents a hypothetical index-buffer from 0 to infinity. In other words,
/// all vertices get processed in order. Do note that the `Slice`' `start` and `end` restrictions
/// still apply for this variant. To render every vertex in the `VertexBuffer`, you would set
/// `start` to 0, and `end` to the `VertexBuffer`'s length.
///
/// The `Index*` variants represent an actual `Buffer` with a list of vertex-indices. The numeric
/// suffix specifies the amount of bits to use per index. Each of these also contains a
/// base-vertex. This is the index of the first vertex in the `VertexBuffer`. This value will be
/// added to every index in the index-buffer, effectively moving the start of the `VertexBuffer` to
/// this base-vertex.
///
/// # Construction & Handling
/// A `IndexBuffer` can be constructed using the `IntoIndexBuffer` trait, from either a slice or a
/// `Buffer` of integers, using a factory.
///
/// An `IndexBuffer` is exclusively used to create `Slice`s.
#[derive(Clone, Debug, PartialEq)]
pub enum IndexBuffer<R: Resources> {
    /// Represents a hypothetical index-buffer from 0 to infinity. In other words, all vertices
    /// get processed in order.
    Auto,
    /// An index-buffer with unsigned 16 bit indices.
    Index16(handle::Buffer<R, u16>),
    /// An index-buffer with unsigned 32 bit indices.
    Index32(handle::Buffer<R, u32>),
}

impl<R: Resources> Default for IndexBuffer<R> {
    fn default() -> Self {
        IndexBuffer::Auto
    }
}
/// A helper trait to create `IndexBuffers` from different kinds of data.
pub trait IntoIndexBuffer<R: Resources> {
    /// Turns self into an `IndexBuffer`.
    fn into_index_buffer<F: Factory<R> + ?Sized>(self, factory: &mut F) -> IndexBuffer<R>;
}

impl<R: Resources> IntoIndexBuffer<R> for IndexBuffer<R> {
    fn into_index_buffer<F: Factory<R> + ?Sized>(self, _: &mut F) -> IndexBuffer<R> {
        self
    }
}

impl<R: Resources> IntoIndexBuffer<R> for () {
    fn into_index_buffer<F: Factory<R> + ?Sized>(self, _: &mut F) -> IndexBuffer<R> {
        IndexBuffer::Auto
    }
}

macro_rules! impl_index_buffer {
    ($prim_ty:ty, $buf_ty:ident) => (
        impl<R: Resources> IntoIndexBuffer<R> for handle::Buffer<R, $prim_ty> {
            fn into_index_buffer<F: Factory<R> + ?Sized>(self, _: &mut F) -> IndexBuffer<R> {
                IndexBuffer::$buf_ty(self)
            }
        }

        impl<'s, R: Resources> IntoIndexBuffer<R> for &'s [$prim_ty] {
            fn into_index_buffer<F: Factory<R> + ?Sized>(self, factory: &mut F) -> IndexBuffer<R> {
                factory.create_buffer_immutable(self, buffer::Role::Index, Bind::empty())
                       .unwrap()
                       .into_index_buffer(factory)
            }
        }
    )
}

impl_index_buffer!(u16, Index16);
impl_index_buffer!(u32, Index32);
<commit_msg>Auto merge of #1139 - nical:slice-split, r=kvark<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Slices
//!
//! See `Slice`-structure documentation for more information on this module.

use core::{handle, buffer};
use core::{Primitive, Resources, VertexCount};
use core::command::InstanceParams;
use core::factory::Factory;
use core::memory::Bind;
use format::Format;
use pso;

/// A `Slice` dictates in which and in what order vertices get processed. It is required for
/// processing a PSO.
///
/// # Overview
/// A `Slice` object in essence dictates in what order the vertices in a `VertexBuffer` get
/// processed. To do this, it contains an internal index-buffer. This `Buffer` is a list of
/// indices into this `VertexBuffer` (vertex-index). A vertex-index of 0 represents the first
/// vertex in the `VertexBuffer`, a vertex-index of 1 represents the second, 2 represents the
/// third, and so on. The vertex-indices in the index-buffer are read in order; every vertex-index
/// tells the pipeline which vertex to process next.
///
/// Because the same index can re-appear multiple times, duplicate-vertices can be avoided. For
/// instance, if you want to draw a square, you need two triangles, and thus six vertices. Because
/// the same index can reappear multiple times, this means we can instead use 4 vertices, and 6
/// vertex-indices.
///
/// This index-buffer has a few variants. See the `IndexBuffer` documentation for a detailed
/// description.
///
/// The `start` and `end` fields say where in the index-buffer to start and stop reading.
/// Setting `start` to 0, and `end` to the length of the index-buffer, will cause the entire
/// index-buffer to be processed. The `base_vertex` dictates the index of the first vertex
/// in the `VertexBuffer`. This essentially moves the the start of the `VertexBuffer`, to the
/// vertex with this index.
///
/// # Constuction & Handling
/// The `Slice` structure can be constructed automatically when using a `Factory` to create a
/// vertex buffer. If needed, it can also be created manually.
///
/// A `Slice` is required to process a PSO, as it contains the needed information on in what order
/// to draw which vertices. As such, every `draw` call on an `Encoder` requires a `Slice`.
#[derive(Clone, Debug, PartialEq)]
pub struct Slice<R: Resources> {
    /// The start index of the index-buffer. Processing will start at this location in the
    /// index-buffer.
    pub start: VertexCount,
    /// The end index in the index-buffer. Processing will stop at this location (exclusive) in
    /// the index buffer.
    pub end: VertexCount,
    /// This is the index of the first vertex in the `VertexBuffer`. This value will be added to
    /// every index in the index-buffer, effectively moving the start of the `VertexBuffer` to this
    /// base-vertex.
    pub base_vertex: VertexCount,
    /// Instancing configuration.
    pub instances: Option<InstanceParams>,
    /// Represents the type of index-buffer used.
    pub buffer: IndexBuffer<R>,
}

impl<R: Resources> Slice<R> {
    /// Creates a new `Slice` to match the supplied vertex buffer, from start to end, in order.
    pub fn new_match_vertex_buffer<V>(vbuf: &handle::Buffer<R, V>) -> Self
                                      where V: pso::buffer::Structure<Format> {
        Slice {
            start: 0,
            end: vbuf.len() as u32,
            base_vertex: 0,
            instances: None,
            buffer: IndexBuffer::Auto,
        }
    }

    /// Calculates the number of primitives of the specified type in this `Slice`.
    pub fn get_prim_count(&self, prim: Primitive) -> u32 {
        use core::Primitive as p;
        let nv = (self.end - self.start) as u32;
        match prim {
            p::PointList => nv,
            p::LineList => nv / 2,
            p::LineStrip => (nv-1),
            p::TriangleList => nv / 3,
            p::TriangleStrip => (nv-2) / 3,
            p::PatchList(num) => nv / (num as u32),
        }
    }

    /// Divides one slice into two at an index.
    ///
    /// The first will contain the range in the index-buffer [self.start, mid) (excluding the index mid itself) and the
    /// second will contain the range [mid, self.end).
    pub fn split_at(&self, mid: VertexCount) -> (Self, Self) {
        let mut first = self.clone();
        let mut second = self.clone();
        first.end = mid;
        second.start = mid;

        (first, second)
    }
}

/// Type of index-buffer used in a Slice.
///
/// The `Auto` variant represents a hypothetical index-buffer from 0 to infinity. In other words,
/// all vertices get processed in order. Do note that the `Slice`' `start` and `end` restrictions
/// still apply for this variant. To render every vertex in the `VertexBuffer`, you would set
/// `start` to 0, and `end` to the `VertexBuffer`'s length.
///
/// The `Index*` variants represent an actual `Buffer` with a list of vertex-indices. The numeric
/// suffix specifies the amount of bits to use per index. Each of these also contains a
/// base-vertex. This is the index of the first vertex in the `VertexBuffer`. This value will be
/// added to every index in the index-buffer, effectively moving the start of the `VertexBuffer` to
/// this base-vertex.
///
/// # Construction & Handling
/// A `IndexBuffer` can be constructed using the `IntoIndexBuffer` trait, from either a slice or a
/// `Buffer` of integers, using a factory.
///
/// An `IndexBuffer` is exclusively used to create `Slice`s.
#[derive(Clone, Debug, PartialEq)]
pub enum IndexBuffer<R: Resources> {
    /// Represents a hypothetical index-buffer from 0 to infinity. In other words, all vertices
    /// get processed in order.
    Auto,
    /// An index-buffer with unsigned 16 bit indices.
    Index16(handle::Buffer<R, u16>),
    /// An index-buffer with unsigned 32 bit indices.
    Index32(handle::Buffer<R, u32>),
}

impl<R: Resources> Default for IndexBuffer<R> {
    fn default() -> Self {
        IndexBuffer::Auto
    }
}
/// A helper trait to create `IndexBuffers` from different kinds of data.
pub trait IntoIndexBuffer<R: Resources> {
    /// Turns self into an `IndexBuffer`.
    fn into_index_buffer<F: Factory<R> + ?Sized>(self, factory: &mut F) -> IndexBuffer<R>;
}

impl<R: Resources> IntoIndexBuffer<R> for IndexBuffer<R> {
    fn into_index_buffer<F: Factory<R> + ?Sized>(self, _: &mut F) -> IndexBuffer<R> {
        self
    }
}

impl<R: Resources> IntoIndexBuffer<R> for () {
    fn into_index_buffer<F: Factory<R> + ?Sized>(self, _: &mut F) -> IndexBuffer<R> {
        IndexBuffer::Auto
    }
}

macro_rules! impl_index_buffer {
    ($prim_ty:ty, $buf_ty:ident) => (
        impl<R: Resources> IntoIndexBuffer<R> for handle::Buffer<R, $prim_ty> {
            fn into_index_buffer<F: Factory<R> + ?Sized>(self, _: &mut F) -> IndexBuffer<R> {
                IndexBuffer::$buf_ty(self)
            }
        }

        impl<'s, R: Resources> IntoIndexBuffer<R> for &'s [$prim_ty] {
            fn into_index_buffer<F: Factory<R> + ?Sized>(self, factory: &mut F) -> IndexBuffer<R> {
                factory.create_buffer_immutable(self, buffer::Role::Index, Bind::empty())
                       .unwrap()
                       .into_index_buffer(factory)
            }
        }
    )
}

impl_index_buffer!(u16, Index16);
impl_index_buffer!(u32, Index32);
<|endoftext|>


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

//! `IMPL` Low level signal support.

use libc::{c_void, c_ulong};

use gobject_ffi::{self, GCallback};
use ffi::gboolean;
use object::{IsA, Object};
use translate::{from_glib, FromGlib, ToGlib, ToGlibPtr};

/// The id of a signal that is returned by `connect`.
#[derive(Debug, Eq, PartialEq)]
pub struct SignalHandlerId(c_ulong);

impl ToGlib for SignalHandlerId {
    type GlibType = c_ulong;

    #[inline]
    fn to_glib(&self) -> c_ulong {
        self.0
    }
}

impl FromGlib<c_ulong> for SignalHandlerId {
    #[inline]
    fn from_glib(val: c_ulong) -> SignalHandlerId {
        assert_ne!(val, 0);
        SignalHandlerId(val)
    }
}

/// Whether to propagate the signal to the default handler.
///
/// Don't inhibit default handlers without a reason, they're usually helpful.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Inhibit(pub bool);

#[doc(hidden)]
impl ToGlib for Inhibit {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> SignalHandlerId {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name.to_glib_none().0,
        trampoline, closure as *mut _, Some(destroy_closure), 0);
    assert!(handle > 0);
    from_glib(handle)
}

pub fn signal_handler_block<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_block(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_unblock<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_unblock(instance.to_glib_none().0, handler_id.to_glib());
    }
}

#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
pub fn signal_handler_disconnect<T: IsA<Object>>(instance: &T, handler_id: SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_disconnect(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_stop_emission_by_name<T: IsA<Object>>(instance: &T, signal_name: &str) {
    unsafe {
        gobject_ffi::g_signal_stop_emission_by_name(instance.to_glib_none().0, signal_name.to_glib_none().0);
    }
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<commit_msg>Add signal::connect_raw() working on raw c_char pointers for the signal name<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Low level signal support.

use libc::{c_char, c_void, c_ulong};

use gobject_ffi::{self, GCallback};
use ffi::gboolean;
use object::{IsA, Object};
use translate::{from_glib, FromGlib, ToGlib, ToGlibPtr};

/// The id of a signal that is returned by `connect`.
#[derive(Debug, Eq, PartialEq)]
pub struct SignalHandlerId(c_ulong);

impl ToGlib for SignalHandlerId {
    type GlibType = c_ulong;

    #[inline]
    fn to_glib(&self) -> c_ulong {
        self.0
    }
}

impl FromGlib<c_ulong> for SignalHandlerId {
    #[inline]
    fn from_glib(val: c_ulong) -> SignalHandlerId {
        assert_ne!(val, 0);
        SignalHandlerId(val)
    }
}

/// Whether to propagate the signal to the default handler.
///
/// Don't inhibit default handlers without a reason, they're usually helpful.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Inhibit(pub bool);

#[doc(hidden)]
impl ToGlib for Inhibit {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> SignalHandlerId {
    connect_raw(receiver, signal_name.to_glib_none().0, trampoline, closure)
}

pub unsafe fn connect_raw(receiver: *mut gobject_ffi::GObject, signal_name: *const c_char, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> SignalHandlerId {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name,
        trampoline, closure as *mut _, Some(destroy_closure), 0);
    assert!(handle > 0);
    from_glib(handle)
}

pub fn signal_handler_block<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_block(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_unblock<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_unblock(instance.to_glib_none().0, handler_id.to_glib());
    }
}

#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
pub fn signal_handler_disconnect<T: IsA<Object>>(instance: &T, handler_id: SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_disconnect(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_stop_emission_by_name<T: IsA<Object>>(instance: &T, signal_name: &str) {
    unsafe {
        gobject_ffi::g_signal_stop_emission_by_name(instance.to_glib_none().0, signal_name.to_glib_none().0);
    }
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate xml;

use std::io::Read;

pub struct Client {
    http_client: hyper::Client,
    server_uri: String,
}

impl Client {
    pub fn new(server_uri: String) -> Client {
        Client {
            http_client: hyper::Client::new(),
            server_uri: server_uri,
        }
    }

    pub fn request(&self, function_name: String, parameters: &Vec<(String, String)>) -> String {
        let mut body = Vec::<u8>::new();
        {
            let mut writer = xml::EventWriter::new(&mut body);
            writer.write(xml::writer::XmlEvent::start_element("methodCall")).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("methodName")).unwrap();
            writer.write(xml::writer::XmlEvent::characters(function_name.as_str())).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("params")).unwrap();
            for param in parameters {
                writer.write(xml::writer::XmlEvent::start_element(param.0.as_str())).unwrap();
                writer.write(xml::writer::XmlEvent::start_element("value")).unwrap();
                writer.write(xml::writer::XmlEvent::start_element("string")).unwrap();
                writer.write(xml::writer::XmlEvent::characters(param.1.as_str())).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            }
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
        }

        let mut res = self.http_client
            .post(self.server_uri.as_str())
            .body(String::from_utf8(body).unwrap().as_str())
            .send()
            .unwrap();

        let mut buf = String::new();
        res.read_to_string(&mut buf).unwrap();
        buf
    }
}
<commit_msg>Remove unneeded argument keys<commit_after>extern crate hyper;
extern crate xml;

use std::io::Read;

pub struct Client {
    http_client: hyper::Client,
    server_uri: String,
}

impl Client {
    pub fn new(server_uri: String) -> Client {
        Client {
            http_client: hyper::Client::new(),
            server_uri: server_uri,
        }
    }

    pub fn request(&self, function_name: String, parameters: &Vec<String>) -> String {
        let mut body = Vec::<u8>::new();
        {
            let mut writer = xml::EventWriter::new(&mut body);
            writer.write(xml::writer::XmlEvent::start_element("methodCall")).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("methodName")).unwrap();
            writer.write(xml::writer::XmlEvent::characters(function_name.as_str())).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("params")).unwrap();
            for param in parameters {
                writer.write(xml::writer::XmlEvent::start_element("value")).unwrap();
                writer.write(xml::writer::XmlEvent::start_element("string")).unwrap();
                writer.write(xml::writer::XmlEvent::characters(param.as_str())).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            }
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
        }

        let mut res = self.http_client
            .post(self.server_uri.as_str())
            .body(String::from_utf8(body).unwrap().as_str())
            .send()
            .unwrap();

        let mut buf = String::new();
        res.read_to_string(&mut buf).unwrap();
        buf
    }
}
<|endoftext|>