<commit_before>#[macro_use(expect)]
extern crate expectest;
pub use expectest::prelude::*;

pub type TestResult = Result<(), ()>;

pub struct Context<'a> {
    tests: Vec<Box<FnMut() -> TestResult + 'a>>,
    before_each: Vec<Box<FnMut() -> () + 'a>>
}

impl<'a> Context<'a> {
    pub fn describe<F>(&mut self, _name: &'a str, mut body: F)
        where F : 'a + FnMut(&mut Context<'a>) -> () {
        body(self)
    }

    pub fn it<F>(&mut self, _name: &'a str, body: F)
        where F : 'a + FnMut() -> TestResult {

        self.tests.push(Box::new(body))
    }

    pub fn before<F>(&mut self, body: F)
        where F : 'a + FnMut() -> () {

        self.before_each.push(Box::new(body))
    }
}

pub fn describe<'a, 'b, F>(_block_name: &'b str, body: F) -> Runner<'a>
    where F : 'a + FnOnce(&mut Context<'a>) -> () {

    let mut c = Context { tests: vec!(), before_each: vec!() };
    body(&mut c);
    Runner { describe: c, report: None }
}

pub struct Runner<'a> {
    describe: Context<'a>,
    report: Option<Result<TestReport, TestReport>>
}

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

impl<'a> Runner<'a> {

    pub fn run(&mut self) -> Result<(), ()> {
        use std::panic::{catch_unwind, AssertUnwindSafe};

        let mut report = TestReport::default();
        let mut result = Ok(());

        let ref mut describe = self.describe;
        let ref mut before_functions = describe.before_each;
        for test_function in describe.tests.iter_mut() {

            let res = catch_unwind(AssertUnwindSafe(|| {
                for before_function in before_functions.iter_mut() {
                    before_function()
                }
                test_function()
            }));

            let res = match res {
                Ok(res) => res,
                _ => Err(())
            };

            result = match result {
                Ok(()) => { report.success_count += 1; res },
                old @ _ => { report.error_count += 1; old }
            };

            report.total_tests += 1;
        }

        if let Ok(_) = result {
            self.report = Some(Ok(report))
        } else {
            self.report = Some(Err(report))
        }

        Ok(())
    }

    pub fn result(&self) -> Result<TestReport, TestReport> {
        self.report.unwrap_or(Ok(TestReport::default()))
    }
}

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

    mod describe {
        pub use super::*;

        #[test]
        fn it_has_a_root_describe_function() {
            describe("A Test", |_ctx|{});
        }

        #[test]
        fn it_can_call_describe_inside_describe_body() {
            describe("A Root", |ctx| {
                ctx.describe("nested describe", |_ctx| {})
            });
        }

        #[test]
        fn it_can_call_it_inside_describe_body() {
            describe("A root", |ctx| {
                ctx.it("is a test", || { Ok(()) })
            });
        }
    }

    mod runner {
        pub use super::*;

        mod run {
            pub use super::*;

            #[test]
            fn it_create_a_runner_that_can_be_runned() {
                let mut runner = describe("A root", |ctx| {
                    ctx.it("is expected to run", || {
                        assert_eq!(true, true);
                        Ok(())
                    })
                });
                expect!(runner.run()).to(be_ok());
            }

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

                {
                    let mut runner = describe("A root", |ctx| {
                        ctx.it("is expected to run", || {
                            *ran = true;
                            Ok(())
                        })
                    });
                    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 mut runner = describe("A root", |ctx| {
                        ctx.it("first run",  || { ran_counter.fetch_add(1, Ordering::Relaxed); Ok(()) });
                        ctx.it("second run", || { ran_counter.fetch_add(1, Ordering::Relaxed); Ok(()) });
                    });
                    let _ = 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 mut runner = describe("A root", |ctx| {
                        ctx.describe("first describe", |ctx| {
                            ctx.it("first run",  || {
                                ran_counter.fetch_add(1, Ordering::Relaxed); Ok(())
                            });
                        });
                        ctx.describe("second describe", |ctx| {
                            ctx.it("second run",  || {
                                ran_counter.fetch_add(1, Ordering::Relaxed); Ok(())
                            });
                        });
                        ctx.describe("third describe", |ctx| {
                            ctx.describe("fourth describe", |ctx| {
                                ctx.it("third run",  || {
                                    ran_counter.fetch_add(1, Ordering::Relaxed); Ok(())
                                });
                            })
                        })
                    });
                    let _ = runner.run().unwrap();
                }

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

        mod results {
            pub use super::*;

            #[test]
            fn tests_can_fail_with_an_error_result() {
                let mut runner = describe("A root", |ctx| {
                    ctx.it("should fail", || {
                        Err(())
                    })
                });
                runner.run().unwrap();

                expect!(runner.result()).to(be_err());
            }

            #[test]
            fn should_be_ok_if_tests_are_ok() {
                let mut runner = describe("A root", |ctx| {
                    ctx.it("should be ok", || { Ok(()) })
                });
                runner.run().unwrap();

                expect!(runner.result()).to(be_ok());
            }

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

                expect!(runner.result()).to(be_ok());
            }

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

                expect!(runner.result()).to(be_err());
            }

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

                expect!(runner.result()).to(be_ok());
            }

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

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

                expect!(runner.result()).to(be_err());
                expect!(counter.load(Ordering::Relaxed)).to(be_equal_to(1));
            }

            #[test]
            fn can_count_the_tests() {
                let mut runner = describe("a root", |ctx| {
                    ctx.it("first", || { Ok(()) });
                    ctx.it("second", || { Ok(()) });
                    ctx.it("third", || { Ok(()) });
                });
                runner.run().unwrap();
                let result = runner.result();

                expect!(result).to(be_ok());
                if let Ok(report) = result {
                    expect!(report.total_tests).to(be_equal_to(3));
                }
            }

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

                expect!(result).to(be_ok());
                if let Ok(report) = result {
                    expect!(report.success_count).to(be_equal_to(3));
                }
            }

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

                expect!(result).to(be_err());
                if let Err(report) = result {
                    expect!(report.error_count).to(be_equal_to(2));
                }
            }
        }
    }

    mod before {
        pub use super::*;

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

            {
                let mut runner = describe("a root", |ctx| {
                    ctx.before(|| { ran_counter.fetch_add(1, Ordering::Relaxed); });
                    ctx.it("first", || { Ok(()) });
                    ctx.it("second", || { Ok(()) });
                    ctx.it("third", || { Ok(()) });
                });
                runner.run().unwrap();
            }

            expect!(ran_counter.load(Ordering::Relaxed)).to(be_equal_to(3));
        }
    }

    /*
     * Test list:
     * x check that tests can call `assert_eq!`
     * x check that tests can return Err or Ok
     * x runner can count the tests
     * x runner can count the success and failures
     * - check that runner displays the tests names and their results
     * - check that we can use before in a describe
     * - check that we can use after in a describe
     * - check that after/before are run in all child contextes
     */
}
<commit_msg> light refacto code<commit_after>#[macro_use(expect)]
extern crate expectest;
pub use expectest::prelude::*;

pub type TestResult = Result<(), ()>;

pub struct Context<'a> {
    tests: Vec<Box<FnMut() -> TestResult + 'a>>,
    before_each: Vec<Box<FnMut() -> () + 'a>>
}

impl<'a> Context<'a> {
    pub fn describe<F>(&mut self, _name: &'a str, mut body: F)
        where F : 'a + FnMut(&mut Context<'a>) -> () {
        body(self)
    }

    pub fn it<F>(&mut self, _name: &'a str, body: F)
        where F : 'a + FnMut() -> TestResult {

        self.tests.push(Box::new(body))
    }

    pub fn before<F>(&mut self, body: F)
        where F : 'a + FnMut() -> () {

        self.before_each.push(Box::new(body))
    }
}

pub fn describe<'a, 'b, F>(_block_name: &'b str, body: F) -> Runner<'a>
    where F : 'a + FnOnce(&mut Context<'a>) -> () {

    let mut c = Context { tests: vec!(), before_each: vec!() };
    body(&mut c);
    Runner { describe: c, report: None }
}

pub struct Runner<'a> {
    describe: Context<'a>,
    report: Option<Result<TestReport, TestReport>>
}

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

impl<'a> Runner<'a> {

    pub fn run(&mut self) -> Result<(), ()> {
        use std::panic::{catch_unwind, AssertUnwindSafe};

        let mut report = TestReport::default();
        let mut result = Ok(());

        let ref mut describe = self.describe;
        let ref mut before_functions = describe.before_each;
        for test_function in describe.tests.iter_mut() {

            let test_res = catch_unwind(AssertUnwindSafe(|| {
                for before_function in before_functions.iter_mut() {
                    before_function()
                }
                test_function()
            }));
            // if test panicked, it means that it failed
            let test_res = test_res.unwrap_or(Err(()));

            result = match result {
                Ok(()) => { report.success_count += 1; test_res },
                old @ _ => { report.error_count += 1; old }
            };

            report.total_tests += 1;
        }

        self.report = Some(result.and(Ok(report)).or(Err(report)));
        Ok(())
    }

    pub fn result(&self) -> Result<TestReport, TestReport> {
        self.report.unwrap_or(Ok(TestReport::default()))
    }
}

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

    mod describe {
        pub use super::*;

        #[test]
        fn it_has_a_root_describe_function() {
            describe("A Test", |_ctx|{});
        }

        #[test]
        fn it_can_call_describe_inside_describe_body() {
            describe("A Root", |ctx| {
                ctx.describe("nested describe", |_ctx| {})
            });
        }

        #[test]
        fn it_can_call_it_inside_describe_body() {
            describe("A root", |ctx| {
                ctx.it("is a test", || { Ok(()) })
            });
        }
    }

    mod runner {
        pub use super::*;

        mod run {
            pub use super::*;

            #[test]
            fn it_create_a_runner_that_can_be_runned() {
                let mut runner = describe("A root", |ctx| {
                    ctx.it("is expected to run", || {
                        assert_eq!(true, true);
                        Ok(())
                    })
                });
                expect!(runner.run()).to(be_ok());
            }

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

                {
                    let mut runner = describe("A root", |ctx| {
                        ctx.it("is expected to run", || {
                            *ran = true;
                            Ok(())
                        })
                    });
                    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 mut runner = describe("A root", |ctx| {
                        ctx.it("first run",  || { ran_counter.fetch_add(1, Ordering::Relaxed); Ok(()) });
                        ctx.it("second run", || { ran_counter.fetch_add(1, Ordering::Relaxed); Ok(()) });
                    });
                    let _ = 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 mut runner = describe("A root", |ctx| {
                        ctx.describe("first describe", |ctx| {
                            ctx.it("first run",  || {
                                ran_counter.fetch_add(1, Ordering::Relaxed); Ok(())
                            });
                        });
                        ctx.describe("second describe", |ctx| {
                            ctx.it("second run",  || {
                                ran_counter.fetch_add(1, Ordering::Relaxed); Ok(())
                            });
                        });
                        ctx.describe("third describe", |ctx| {
                            ctx.describe("fourth describe", |ctx| {
                                ctx.it("third run",  || {
                                    ran_counter.fetch_add(1, Ordering::Relaxed); Ok(())
                                });
                            })
                        })
                    });
                    let _ = runner.run().unwrap();
                }

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

        mod results {
            pub use super::*;

            #[test]
            fn tests_can_fail_with_an_error_result() {
                let mut runner = describe("A root", |ctx| {
                    ctx.it("should fail", || {
                        Err(())
                    })
                });
                runner.run().unwrap();

                expect!(runner.result()).to(be_err());
            }

            #[test]
            fn should_be_ok_if_tests_are_ok() {
                let mut runner = describe("A root", |ctx| {
                    ctx.it("should be ok", || { Ok(()) })
                });
                runner.run().unwrap();

                expect!(runner.result()).to(be_ok());
            }

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

                expect!(runner.result()).to(be_ok());
            }

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

                expect!(runner.result()).to(be_err());
            }

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

                expect!(runner.result()).to(be_ok());
            }

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

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

                expect!(runner.result()).to(be_err());
                expect!(counter.load(Ordering::Relaxed)).to(be_equal_to(1));
            }

            #[test]
            fn can_count_the_tests() {
                let mut runner = describe("a root", |ctx| {
                    ctx.it("first", || { Ok(()) });
                    ctx.it("second", || { Ok(()) });
                    ctx.it("third", || { Ok(()) });
                });
                runner.run().unwrap();
                let result = runner.result();

                expect!(result).to(be_ok());
                if let Ok(report) = result {
                    expect!(report.total_tests).to(be_equal_to(3));
                }
            }

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

                expect!(result).to(be_ok());
                if let Ok(report) = result {
                    expect!(report.success_count).to(be_equal_to(3));
                }
            }

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

                expect!(result).to(be_err());
                if let Err(report) = result {
                    expect!(report.error_count).to(be_equal_to(2));
                }
            }
        }
    }

    mod before {
        pub use super::*;

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

            {
                let mut runner = describe("a root", |ctx| {
                    ctx.before(|| { ran_counter.fetch_add(1, Ordering::Relaxed); });
                    ctx.it("first", || { Ok(()) });
                    ctx.it("second", || { Ok(()) });
                    ctx.it("third", || { Ok(()) });
                });
                runner.run().unwrap();
            }

            expect!(ran_counter.load(Ordering::Relaxed)).to(be_equal_to(3));
        }
    }

    /*
     * Test list:
     * x check that tests can call `assert_eq!`
     * x check that tests can return Err or Ok
     * x runner can count the tests
     * x runner can count the success and failures
     * - check that runner displays the tests names and their results
     * - check that we can use before in a describe
     * - check that we can use after in a describe
     * - check that after/before are run in all child contextes
     * - beforeAll
     * - afterAll
     * - bench ?
     */
}
<|endoftext|>


<commit_before>#![feature(zero_one)]
use std::iter::Iterator;
use std::num::{Zero, One};
use std::ops::{BitAnd, BitOr, Shr, Shl};

pub struct BiteratorLsb<T> {
    val: T,
    at_end: bool
}

impl<T> BiteratorLsb<T>
    where T : Sized+Eq+Shr<usize, Output=T>+Ord+BitAnd<T, Output=T>+Zero+One+Copy
{
    fn new(init: T) -> BiteratorLsb<T> {
        BiteratorLsb{val: init, at_end: false}
    }
}

impl<T> Iterator for BiteratorLsb<T>
    where T : Sized+Eq+Shr<usize, Output=T>+Ord+BitAnd<T, Output=T>+Zero+One+Copy
{
    type Item = bool;

    fn next(&mut self) -> Option<bool> {
        if self.at_end { return None; }

        let lsb = self.val & T::one();
        self.val = self.val >> 1usize;
        if self.val == T::zero() {
            self.at_end = true;
        }

        if lsb == T::zero() {
            Some(false)
        } else {
            Some(true)
        }
    }
}

fn build_from<T, I>(iter: &mut I, max: usize) -> T
    where I: Iterator<Item=bool>,
          T: Zero + One + BitOr<T, Output=T> + Shl<usize, Output=T>
{
    let mut val: T = T::zero();

    let mut i = 0;
    loop {
        if i >= max { break; }
        let bit = match iter.next() {
            Some(true)  => T::one(),
            Some(false) => T::zero(),
            None => break
        };
        val = val | (bit << i);
        i += 1;
    }

    return val;
}

#[test]
fn test_bitstream() {
    let v: Vec<_> = BiteratorLsb::new(12u64).collect();
    assert_eq!([false, false, true, true], &v[..]);

    let v: Vec<_> = BiteratorLsb::new(0b1110u8).collect();
    assert_eq!([false, true, true, true], &v[..]);

    let v: Vec<_> = BiteratorLsb::new(0b001110u8).collect();
    assert_eq!([false, true, true, true], &v[..]);
}

#[test]
fn test_build_from() {
    let num = 0b001110u8;
    let n = build_from(&mut BiteratorLsb::new(num), 8);
    assert_eq!(num, n);
}

#[test]
fn test_build_from_partial() {
    let mut iter = BiteratorLsb::new(0b1110u8);
    assert_eq!(0b0u8, build_from(&mut iter, 1));
    assert_eq!(0b11u8, build_from(&mut iter, 2));
    assert_eq!(0b1u8, build_from(&mut iter, 1));
}
<commit_msg>Make public<commit_after>#![feature(zero_one)]
use std::iter::Iterator;
use std::num::{Zero, One};
use std::ops::{BitAnd, BitOr, Shr, Shl};

pub struct BiteratorLsb<T> {
    val: T,
    at_end: bool
}

impl<T> BiteratorLsb<T>
    where T : Sized+Eq+Shr<usize, Output=T>+Ord+BitAnd<T, Output=T>+Zero+One+Copy
{
    fn new(init: T) -> BiteratorLsb<T> {
        BiteratorLsb{val: init, at_end: false}
    }
}

impl<T> Iterator for BiteratorLsb<T>
    where T : Sized+Eq+Shr<usize, Output=T>+Ord+BitAnd<T, Output=T>+Zero+One+Copy
{
    type Item = bool;

    fn next(&mut self) -> Option<bool> {
        if self.at_end { return None; }

        let lsb = self.val & T::one();
        self.val = self.val >> 1usize;
        if self.val == T::zero() {
            self.at_end = true;
        }

        if lsb == T::zero() {
            Some(false)
        } else {
            Some(true)
        }
    }
}

pub fn build_from<T, I>(iter: &mut I, max: usize) -> T
    where I: Iterator<Item=bool>,
          T: Zero + One + BitOr<T, Output=T> + Shl<usize, Output=T>
{
    let mut val: T = T::zero();

    let mut i = 0;
    loop {
        if i >= max { break; }
        let bit = match iter.next() {
            Some(true)  => T::one(),
            Some(false) => T::zero(),
            None => break
        };
        val = val | (bit << i);
        i += 1;
    }

    return val;
}

#[test]
fn test_bitstream() {
    let v: Vec<_> = BiteratorLsb::new(12u64).collect();
    assert_eq!([false, false, true, true], &v[..]);

    let v: Vec<_> = BiteratorLsb::new(0b1110u8).collect();
    assert_eq!([false, true, true, true], &v[..]);

    let v: Vec<_> = BiteratorLsb::new(0b001110u8).collect();
    assert_eq!([false, true, true, true], &v[..]);
}

#[test]
fn test_build_from() {
    let num = 0b001110u8;
    let n = build_from(&mut BiteratorLsb::new(num), 8);
    assert_eq!(num, n);
}

#[test]
fn test_build_from_partial() {
    let mut iter = BiteratorLsb::new(0b1110u8);
    assert_eq!(0b0u8, build_from(&mut iter, 1));
    assert_eq!(0b11u8, build_from(&mut iter, 2));
    assert_eq!(0b1u8, build_from(&mut iter, 1));
}
<|endoftext|>


<commit_before><commit_msg>Remove unnecessary constructor from TextureReshaper<commit_after><|endoftext|>


<commit_before>extern crate libloading;
#[macro_use]
extern crate lazy_static;

#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod ffi;

use std::os::raw::{c_char};
use std::ffi::{CString, CStr};
use std::ptr;
use std::mem;
use libloading::Library;

use ffi::{
    IVRCompositor,
    IVRSystem,
    IVRChaperone,
    IVRRenderModels,
    IVRCompositor_FnTable,
    IVRSystem_FnTable,
    // IVRChaperone_FnTable,
};

pub use ffi::{
    Texture,
    TextureID,
    TrackedDevicePose,
    HmdMatrix34,
    HmdMatrix44,
    EVREye as Eye,
    EVRInitError as InitError,
    EVRApplicationType as ApplicationType,
    EGraphicsAPIConvention as GraphicsAPIConvention,
    EVRSubmitFlags as SubmitFlags,
    EVRCompositorError as CompositorError,
    ETrackingUniverseOrigin as TrackingUniverseOrigin,
    EColorSpace as ColorSpace,
    VRTextureBounds as TextureBounds,
    ETrackedDeviceClass as TrackedDeviceClass,
    ETrackedControllerRole as TrackedControllerRole,
    EVRRenderModelError as RenderModelError,
    EVRControllerAxisType as ControllerAxisType,
    VRControllerState as ControllerState,
    k_unMaxTrackedDeviceCount as MAX_TRACKED_DEVICE_COUNT
};

#[allow(non_snake_case)]
#[allow(dead_code)]
struct ApiFunctions {
    VR_InitInternal:            extern fn (peError: *mut InitError, eType: ApplicationType) -> usize,
    VR_ShutdownInternal:        extern fn (),
    VR_IsHmdPresent:            extern fn () -> ::std::os::raw::c_char,
    VR_GetStringForHmdError:    extern fn (error: InitError) -> *mut ::std::os::raw::c_char,
    VR_GetGenericInterface:     extern fn (pchInterfaceVersion: *const ::std::os::raw::c_char, peError: *mut InitError) -> usize,
    VR_IsRuntimeInstalled:      extern fn () -> ::std::os::raw::c_char,
    VR_GetVRInitErrorAsSymbol:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    VR_GetVRInitErrorAsEnglishDescription:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    lib: Library,
}

unsafe impl Sync for ApiFunctions {}

lazy_static! {
    static ref API: ApiFunctions = {
        let lib = Library::new("openvr_api.dll").unwrap();

        unsafe {
            ApiFunctions {
                VR_InitInternal:            *lib.get(b"VR_InitInternal\0").unwrap(),
                VR_ShutdownInternal:        *lib.get(b"VR_ShutdownInternal\0").unwrap(),
                VR_IsHmdPresent:            *lib.get(b"VR_IsHmdPresent\0").unwrap(),
                VR_GetStringForHmdError:    *lib.get(b"VR_GetStringForHmdError\0").unwrap(),
                VR_GetGenericInterface:     *lib.get(b"VR_GetGenericInterface\0").unwrap(),
                VR_IsRuntimeInstalled:      *lib.get(b"VR_IsRuntimeInstalled\0").unwrap(),
                VR_GetVRInitErrorAsSymbol:  *lib.get(b"VR_GetVRInitErrorAsSymbol\0").unwrap(),
                VR_GetVRInitErrorAsEnglishDescription: *lib.get(b"VR_GetVRInitErrorAsEnglishDescription\0").unwrap(),
                lib: lib,
            }
        }
    };
}

pub struct VRCompositor {
    i: *mut IVRCompositor
}

impl VRCompositor {
    fn new(vr_compositor: *mut IVRCompositor) -> Self {
        assert!(vr_compositor as *const _ != ptr::null());
        VRCompositor {
            i:  vr_compositor
        }
    }

    /// Updated scene texture to display. If bounds is NULL the entire texture will be used.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::Submit
    pub fn submit(
        &mut self,
        eye:            Eye,
        texture:        *mut Texture,
        bounds:         *mut TextureBounds,
        submit_flags:   SubmitFlags
    ) -> CompositorError {
        unsafe {
            ((*self.i).Submit)(eye, texture, bounds, submit_flags)
        }
    }

    /// Returns pose(s) to use to render scene.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::WaitGetPoses
    pub fn wait_get_poses(
        &mut self,
    ) -> [TrackedDevicePose; ffi::k_unMaxTrackedDeviceCount as usize] {
        unsafe {
            let mut render_poses = [TrackedDevicePose::default(); ffi::k_unMaxTrackedDeviceCount as usize];
            ((*self.i).WaitGetPoses)(
                (&mut render_poses[..]).as_mut_ptr(),
                render_poses.len() as u32,
                std::ptr::null_mut(),
                0
            );

            render_poses
        }
    }
}

pub struct VRChaperone {
    _i: *mut IVRChaperone
}

pub struct RenderModel {
    ptr: *mut ffi::RenderModel
}

pub struct RenderModelTexture {
    ptr: *mut ffi::RenderModel_TextureMap
}

pub struct VRRenderModels {
    i: *mut IVRRenderModels
}

impl VRRenderModels {
    pub fn load_render_model_async(
        &mut self,
        render_model_name: *const c_char
    ) -> Result<RenderModel, RenderModelError> {
        unsafe {
            let render_model: *mut *mut ffi::RenderModel = mem::zeroed();
            let error = ((*self.i).LoadRenderModel_Async)(render_model_name, render_model);
            if error == RenderModelError::None {
                Ok(RenderModel {
                    ptr:    *render_model
                })
            } else {
                Err(error)
            }
        }
    }

    pub fn free_render_model(&mut self, render_model: RenderModel) {
        unsafe {
            ((*self.i).FreeRenderModel)(render_model.ptr)
        }
    }

    pub fn load_texture_async(
        &mut self,
        texture_id: TextureID
    ) -> Result<RenderModelTexture, RenderModelError> {
        unsafe {
            let texture: *mut *mut ffi::RenderModel_TextureMap = mem::zeroed();
            let error = ((*self.i).LoadTexture_Async)(texture_id, texture);
            if error == RenderModelError::None {
                Ok(RenderModelTexture {
                    ptr: *texture
                })
            } else {
                Err(error)
            }
        }
    }

    pub fn free_texture(&mut self, texture: RenderModelTexture) {
        unsafe {
            ((*self.i).FreeTexture)(texture.ptr)
        }
    }
}

pub struct VRSystem {
    i: *mut IVRSystem
}

impl VRSystem {
    fn new(vr_system: *mut IVRSystem) -> Self {
        assert!(vr_system as *const _ != ptr::null());
        VRSystem {
            i:  vr_system
        }
    }

    /// Provides the game with the minimum size that it should use for its offscreen render
    /// target to minimize pixel stretching. This size is matched with the projection matrix
    // and distortion function and will change from display to display depending on resolution,
    // distortion, and field of view.
    pub fn get_recommended_render_target_size(&self) -> (u32, u32) {
        unsafe {
            let mut width = 0;
            let mut height = 0;
            ((*self.i).GetRecommendedRenderTargetSize)(&mut width, &mut height);
            (width, height)
        }
    }

    /// Returns the projection matrix to use for the specified eye.
    pub fn get_projection_matrix(
        &self,
        eye:                Eye,
        near_z:             f32,
        far_z:              f32,
        api:                GraphicsAPIConvention
    ) -> HmdMatrix44 {
        unsafe {
            ((*self.i).GetProjectionMatrix)(
                eye,
                near_z,
                far_z,
                api
            )
        }
    }

    /// Returns the transform between the view space and eye space.
    pub fn get_eye_to_head_transform(&self, eye: Eye) -> HmdMatrix34 {
        unsafe {
            ((*self.i).GetEyeToHeadTransform)(eye)
        }
    }

    /// Calculates updated poses for all devices.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRSystem::GetDeviceToAbsoluteTrackingPose
    pub fn get_device_to_absolute_tracking_pose(
        &self,
        origin: TrackingUniverseOrigin,
        predicted_seconds_to_photons_from_now:  f32,
        tracked_device_pose_array: &mut [TrackedDevicePose]
    ) {
        unsafe {
            ((*self.i).GetDeviceToAbsoluteTrackingPose)(
                origin,
                predicted_seconds_to_photons_from_now,
                tracked_device_pose_array.as_mut_ptr(),
                tracked_device_pose_array.len() as u32
            )
        }
    }

    pub fn reset_seated_zero_pose(&self) {
        unsafe {
            ((*self.i).ResetSeatedZeroPose)()
        }
    }

    pub fn get_tracked_device_class(&self, device_index: usize) -> TrackedDeviceClass {
        unsafe {
            ((*self.i).GetTrackedDeviceClass)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_role_for_tracked_device_index(&self, device_index: usize) -> TrackedControllerRole {
        unsafe {
            ((*self.i).GetControllerRoleForTrackedDeviceIndex)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_state(&self, device_index: usize) -> ControllerState {
        unsafe {
            let mut state = ControllerState::default();
            ((*self.i).GetControllerState)(device_index as ffi::TrackedDeviceIndex, &mut state);
            state
        }
    }
}

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        unsafe {
            let err = CStr::from_ptr((API.VR_GetVRInitErrorAsEnglishDescription)(*self));
            write!(f, "{}", err.to_string_lossy())
        }
    }
}

impl std::error::Error for InitError {
    fn description(&self) -> &str {
        "init error"
    }
}

pub struct VRContext {
    pub system:     VRSystem,
    pub compositor: VRCompositor,

    // chaperone:         VRChaperone,
    // chaperone_setup:    IVRChaperoneSetup,
    // overlay:            IVROverlay,
    // render_models:      IVRRenderModels,
    // IVRExtendedDisplay: *mut IVRExtendedDisplay,
    // IVRSettings: *mut IVRSettings,
    // IVRApplications: *mut IVRApplications,
}

impl Drop for VRContext {
    fn drop(&mut self) {
        // VR_ShutdownInternal();
    }
}

pub fn initialize() -> Result<VRContext, InitError> {
    let mut err = InitError::None;
    let _hmd = (API.VR_InitInternal)(&mut err, ApplicationType::VRApplication_Scene);
    if err != InitError::None {
        Err(err)
    } else {

        let system = (API.VR_GetGenericInterface)(CString::new(IVRSystem_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRSystem;
        if err != InitError::None {
            return Err(err);
        }
        let system = VRSystem::new(system);

        let compositor = (API.VR_GetGenericInterface)(CString::new(IVRCompositor_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRCompositor;
        if err != InitError::None {
            return Err(err);
        }
        let compositor = VRCompositor::new(compositor);

        Ok(VRContext {
            system:     system,
            compositor: compositor
        })
    }
}

/// Returns true if the system believes that an HMD is present on the system.
pub fn is_hmd_present() -> bool {
    (API.VR_IsHmdPresent)() != 0
}

/// Returns true if the SteamVR runtime is installed.
pub fn is_runtime_installed() -> bool {
    (API.VR_IsRuntimeInstalled)() != 0
}

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

    #[test]
    fn runtime_installed() {
        assert!(is_runtime_installed());
    }

    #[test]
    fn hmd_present() {
        assert!(is_hmd_present());
    }
}

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

    #[test]
    fn vr_init() {
        // NOTE: initializing seems to fail if a window has not been created

        // match init() {
        //     Err(err) => {
        //         println!("init failed: {} - {}", err, err.description());
        //         assert!(false);
        //     }
        //     Ok(context) => {
        //         context.system.get_recommended_render_target_size();
        //     }
        // }
    }
}
<commit_msg>ButtonId bitmask helper<commit_after>extern crate libloading;
#[macro_use]
extern crate lazy_static;

#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod ffi;

use std::os::raw::{c_char};
use std::ffi::{CString, CStr};
use std::ptr;
use std::mem;
use libloading::Library;

use ffi::{
    IVRCompositor,
    IVRSystem,
    IVRChaperone,
    IVRRenderModels,
    IVRCompositor_FnTable,
    IVRSystem_FnTable,
    // IVRChaperone_FnTable,
};

pub use ffi::{
    Texture,
    TextureID,
    TrackedDevicePose,
    HmdMatrix34,
    HmdMatrix44,
    EVREye as Eye,
    EVRInitError as InitError,
    EVRApplicationType as ApplicationType,
    EGraphicsAPIConvention as GraphicsAPIConvention,
    EVRSubmitFlags as SubmitFlags,
    EVRCompositorError as CompositorError,
    ETrackingUniverseOrigin as TrackingUniverseOrigin,
    EColorSpace as ColorSpace,
    VRTextureBounds as TextureBounds,
    ETrackedDeviceClass as TrackedDeviceClass,
    ETrackedControllerRole as TrackedControllerRole,
    EVRRenderModelError as RenderModelError,
    EVRControllerAxisType as ControllerAxisType,
    VRControllerState as ControllerState,
    EVRButtonId as ButtonId,
    k_unMaxTrackedDeviceCount as MAX_TRACKED_DEVICE_COUNT
};

impl ButtonId {
    pub fn mask(self) -> u64 {
        1 << self as usize
    }
}

#[allow(non_snake_case)]
#[allow(dead_code)]
struct ApiFunctions {
    VR_InitInternal:            extern fn (peError: *mut InitError, eType: ApplicationType) -> usize,
    VR_ShutdownInternal:        extern fn (),
    VR_IsHmdPresent:            extern fn () -> ::std::os::raw::c_char,
    VR_GetStringForHmdError:    extern fn (error: InitError) -> *mut ::std::os::raw::c_char,
    VR_GetGenericInterface:     extern fn (pchInterfaceVersion: *const ::std::os::raw::c_char, peError: *mut InitError) -> usize,
    VR_IsRuntimeInstalled:      extern fn () -> ::std::os::raw::c_char,
    VR_GetVRInitErrorAsSymbol:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    VR_GetVRInitErrorAsEnglishDescription:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    lib: Library,
}

unsafe impl Sync for ApiFunctions {}

lazy_static! {
    static ref API: ApiFunctions = {
        let lib = Library::new("openvr_api.dll").unwrap();

        unsafe {
            ApiFunctions {
                VR_InitInternal:            *lib.get(b"VR_InitInternal\0").unwrap(),
                VR_ShutdownInternal:        *lib.get(b"VR_ShutdownInternal\0").unwrap(),
                VR_IsHmdPresent:            *lib.get(b"VR_IsHmdPresent\0").unwrap(),
                VR_GetStringForHmdError:    *lib.get(b"VR_GetStringForHmdError\0").unwrap(),
                VR_GetGenericInterface:     *lib.get(b"VR_GetGenericInterface\0").unwrap(),
                VR_IsRuntimeInstalled:      *lib.get(b"VR_IsRuntimeInstalled\0").unwrap(),
                VR_GetVRInitErrorAsSymbol:  *lib.get(b"VR_GetVRInitErrorAsSymbol\0").unwrap(),
                VR_GetVRInitErrorAsEnglishDescription: *lib.get(b"VR_GetVRInitErrorAsEnglishDescription\0").unwrap(),
                lib: lib,
            }
        }
    };
}

pub struct VRCompositor {
    i: *mut IVRCompositor
}

impl VRCompositor {
    fn new(vr_compositor: *mut IVRCompositor) -> Self {
        assert!(vr_compositor as *const _ != ptr::null());
        VRCompositor {
            i:  vr_compositor
        }
    }

    /// Updated scene texture to display. If bounds is NULL the entire texture will be used.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::Submit
    pub fn submit(
        &mut self,
        eye:            Eye,
        texture:        *mut Texture,
        bounds:         *mut TextureBounds,
        submit_flags:   SubmitFlags
    ) -> CompositorError {
        unsafe {
            ((*self.i).Submit)(eye, texture, bounds, submit_flags)
        }
    }

    /// Returns pose(s) to use to render scene.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::WaitGetPoses
    pub fn wait_get_poses(
        &mut self,
    ) -> [TrackedDevicePose; ffi::k_unMaxTrackedDeviceCount as usize] {
        unsafe {
            let mut render_poses = [TrackedDevicePose::default(); ffi::k_unMaxTrackedDeviceCount as usize];
            ((*self.i).WaitGetPoses)(
                (&mut render_poses[..]).as_mut_ptr(),
                render_poses.len() as u32,
                std::ptr::null_mut(),
                0
            );

            render_poses
        }
    }
}

pub struct VRChaperone {
    _i: *mut IVRChaperone
}

pub struct RenderModel {
    ptr: *mut ffi::RenderModel
}

pub struct RenderModelTexture {
    ptr: *mut ffi::RenderModel_TextureMap
}

pub struct VRRenderModels {
    i: *mut IVRRenderModels
}

impl VRRenderModels {
    pub fn load_render_model_async(
        &mut self,
        render_model_name: *const c_char
    ) -> Result<RenderModel, RenderModelError> {
        unsafe {
            let render_model: *mut *mut ffi::RenderModel = mem::zeroed();
            let error = ((*self.i).LoadRenderModel_Async)(render_model_name, render_model);
            if error == RenderModelError::None {
                Ok(RenderModel {
                    ptr:    *render_model
                })
            } else {
                Err(error)
            }
        }
    }

    pub fn free_render_model(&mut self, render_model: RenderModel) {
        unsafe {
            ((*self.i).FreeRenderModel)(render_model.ptr)
        }
    }

    pub fn load_texture_async(
        &mut self,
        texture_id: TextureID
    ) -> Result<RenderModelTexture, RenderModelError> {
        unsafe {
            let texture: *mut *mut ffi::RenderModel_TextureMap = mem::zeroed();
            let error = ((*self.i).LoadTexture_Async)(texture_id, texture);
            if error == RenderModelError::None {
                Ok(RenderModelTexture {
                    ptr: *texture
                })
            } else {
                Err(error)
            }
        }
    }

    pub fn free_texture(&mut self, texture: RenderModelTexture) {
        unsafe {
            ((*self.i).FreeTexture)(texture.ptr)
        }
    }
}

pub struct VRSystem {
    i: *mut IVRSystem
}

impl VRSystem {
    fn new(vr_system: *mut IVRSystem) -> Self {
        assert!(vr_system as *const _ != ptr::null());
        VRSystem {
            i:  vr_system
        }
    }

    /// Provides the game with the minimum size that it should use for its offscreen render
    /// target to minimize pixel stretching. This size is matched with the projection matrix
    // and distortion function and will change from display to display depending on resolution,
    // distortion, and field of view.
    pub fn get_recommended_render_target_size(&self) -> (u32, u32) {
        unsafe {
            let mut width = 0;
            let mut height = 0;
            ((*self.i).GetRecommendedRenderTargetSize)(&mut width, &mut height);
            (width, height)
        }
    }

    /// Returns the projection matrix to use for the specified eye.
    pub fn get_projection_matrix(
        &self,
        eye:                Eye,
        near_z:             f32,
        far_z:              f32,
        api:                GraphicsAPIConvention
    ) -> HmdMatrix44 {
        unsafe {
            ((*self.i).GetProjectionMatrix)(
                eye,
                near_z,
                far_z,
                api
            )
        }
    }

    /// Returns the transform between the view space and eye space.
    pub fn get_eye_to_head_transform(&self, eye: Eye) -> HmdMatrix34 {
        unsafe {
            ((*self.i).GetEyeToHeadTransform)(eye)
        }
    }

    /// Calculates updated poses for all devices.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRSystem::GetDeviceToAbsoluteTrackingPose
    pub fn get_device_to_absolute_tracking_pose(
        &self,
        origin: TrackingUniverseOrigin,
        predicted_seconds_to_photons_from_now:  f32,
        tracked_device_pose_array: &mut [TrackedDevicePose]
    ) {
        unsafe {
            ((*self.i).GetDeviceToAbsoluteTrackingPose)(
                origin,
                predicted_seconds_to_photons_from_now,
                tracked_device_pose_array.as_mut_ptr(),
                tracked_device_pose_array.len() as u32
            )
        }
    }

    pub fn reset_seated_zero_pose(&self) {
        unsafe {
            ((*self.i).ResetSeatedZeroPose)()
        }
    }

    pub fn get_tracked_device_class(&self, device_index: usize) -> TrackedDeviceClass {
        unsafe {
            ((*self.i).GetTrackedDeviceClass)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_role_for_tracked_device_index(&self, device_index: usize) -> TrackedControllerRole {
        unsafe {
            ((*self.i).GetControllerRoleForTrackedDeviceIndex)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_state(&self, device_index: usize) -> ControllerState {
        unsafe {
            let mut state = ControllerState::default();
            ((*self.i).GetControllerState)(device_index as ffi::TrackedDeviceIndex, &mut state);
            state
        }
    }
}

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        unsafe {
            let err = CStr::from_ptr((API.VR_GetVRInitErrorAsEnglishDescription)(*self));
            write!(f, "{}", err.to_string_lossy())
        }
    }
}

impl std::error::Error for InitError {
    fn description(&self) -> &str {
        "init error"
    }
}

pub struct VRContext {
    pub system:     VRSystem,
    pub compositor: VRCompositor,

    // chaperone:         VRChaperone,
    // chaperone_setup:    IVRChaperoneSetup,
    // overlay:            IVROverlay,
    // render_models:      IVRRenderModels,
    // IVRExtendedDisplay: *mut IVRExtendedDisplay,
    // IVRSettings: *mut IVRSettings,
    // IVRApplications: *mut IVRApplications,
}

impl Drop for VRContext {
    fn drop(&mut self) {
        // VR_ShutdownInternal();
    }
}

pub fn initialize() -> Result<VRContext, InitError> {
    let mut err = InitError::None;
    let _hmd = (API.VR_InitInternal)(&mut err, ApplicationType::VRApplication_Scene);
    if err != InitError::None {
        Err(err)
    } else {

        let system = (API.VR_GetGenericInterface)(CString::new(IVRSystem_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRSystem;
        if err != InitError::None {
            return Err(err);
        }
        let system = VRSystem::new(system);

        let compositor = (API.VR_GetGenericInterface)(CString::new(IVRCompositor_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRCompositor;
        if err != InitError::None {
            return Err(err);
        }
        let compositor = VRCompositor::new(compositor);

        Ok(VRContext {
            system:     system,
            compositor: compositor
        })
    }
}

/// Returns true if the system believes that an HMD is present on the system.
pub fn is_hmd_present() -> bool {
    (API.VR_IsHmdPresent)() != 0
}

/// Returns true if the SteamVR runtime is installed.
pub fn is_runtime_installed() -> bool {
    (API.VR_IsRuntimeInstalled)() != 0
}

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

    #[test]
    fn runtime_installed() {
        assert!(is_runtime_installed());
    }

    #[test]
    fn hmd_present() {
        assert!(is_hmd_present());
    }
}

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

    #[test]
    fn vr_init() {
        // NOTE: initializing seems to fail if a window has not been created

        // match init() {
        //     Err(err) => {
        //         println!("init failed: {} - {}", err, err.description());
        //         assert!(false);
        //     }
        //     Ok(context) => {
        //         context.system.get_recommended_render_target_size();
        //     }
        // }
    }
}
<|endoftext|>


<commit_before>//! Parser for bitmap fonts

mod char;
mod config_parse_error;
mod error;
mod kerning_value;
mod page;
mod rect;
mod sections;
mod string_parse_error;
mod utils;

pub use self::config_parse_error::ConfigParseError;
pub use self::error::Error;
pub use self::rect::Rect;
pub use self::string_parse_error::StringParseError;

use self::char::Char;
use self::kerning_value::KerningValue;
use self::page::Page;
use self::sections::Sections;
use std::io::Read;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _with_ the `parse-error` feature.
#[cfg(feature = "parse-error")]
pub type Parse<'a> = Result<Vec<CharPosition>, StringParseError>;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _without_ the `parse-error` feature.
#[cfg(not(feature = "parse-error"))]
pub type Parse<'a> = Vec<CharPosition>;

#[cfg(feature = "parse-error")]
type ParseLines<'a> = Result<Vec<Vec<&'a Char>>, StringParseError>;

#[cfg(not(feature = "parse-error"))]
type ParseLines<'a> = Vec<Vec<&'a Char>>;

#[derive(Clone, Debug)]
pub struct CharPosition {
    pub page_rect: Rect,
    pub screen_rect: Rect,
    pub page_index: u32,
}

#[derive(Clone, Debug)]
pub enum OrdinateOrientation {
    BottomToTop,
    TopToBottom,
}

/// Holds a decoded bitmap font defintion, including all character advance and kerning values.
#[derive(Clone, Debug)]
pub struct BMFont {
    base_height: u32,
    line_height: u32,
    characters: Vec<Char>,
    kerning_values: Vec<KerningValue>,
    pages: Vec<Page>,
    ordinate_orientation: OrdinateOrientation,
}

impl BMFont {
    /// Constructs a new [BMFont].
    ///
    /// ## Examples
    ///
    /// From a file:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// From a slice of bytes:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// # let my_font_bytes = std::fs::read("font.fnt")?;
    /// let data = std::io::Cursor::new(my_font_bytes);
    /// let font = BMFont::new(data, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    pub fn new<R>(source: R, ordinate_orientation: OrdinateOrientation) -> Result<BMFont, Error>
    where
        R: Read,
    {
        let sections = Sections::new(source)?;

        let base_height;
        let line_height;
        {
            let mut components = sections.common_section.split_whitespace();
            components.next();
            line_height =
                utils::extract_component_value(components.next(), "common", "lineHeight")?;
            base_height = utils::extract_component_value(components.next(), "common", "base")?;
        }

        let mut pages = Vec::with_capacity(sections.page_sections.len());
        for page_section in &sections.page_sections {
            pages.push(Page::new(page_section)?);
        }

        // Sort the characters while loading them so that lookup can be faster during parse
        let mut characters: Vec<Char> = Vec::with_capacity(sections.char_sections.len());
        for char_section in &sections.char_sections {
            let char = Char::new(char_section)?;
            if let Err(idx) = characters.binary_search_by(|probe| probe.id.cmp(&char.id)) {
                characters.insert(idx, char);
            }
        }

        // Also sort kerning values for the same reason, but we allow duplicates
        let mut kerning_values: Vec<KerningValue> =
            Vec::with_capacity(sections.kerning_sections.len());
        for kerning_section in &sections.kerning_sections {
            let kerning = KerningValue::new(kerning_section)?;

            match kerning_values
                .binary_search_by(|probe| probe.first_char_id.cmp(&kerning.first_char_id))
            {
                Err(idx) | Ok(idx) => kerning_values.insert(idx, kerning),
            }
        }

        Ok(BMFont {
            base_height,
            line_height,
            characters,
            kerning_values,
            pages,
            ordinate_orientation,
        })
    }

    /// Returns the height of a `EM` in pixels.
    pub fn base_height(&self) -> u32 {
        self.base_height
    }

    pub fn line_height(&self) -> u32 {
        self.line_height
    }

    /// Returns an `Iterator` of font page bitmap filenames.
    ///
    /// ## Examples
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.pages().next(), Some("font.png"));
    /// #     Ok(())
    /// # }
    /// ```
    pub fn pages(&self) -> PageIter {
        PageIter::new(&self.pages)
    }

    pub fn parse(&self, s: &str) -> Parse {
        let lines = self.parse_lines(s);

        #[cfg(feature = "parse-error")]
        let lines = lines?;

        let mut char_positions = Vec::new();
        let mut y: i32 = 0;
        for line in lines {
            let mut x: i32 = 0;
            let mut kerning_values = KerningIter::empty(&self.kerning_values);
            for character in line {
                let kerning_value = kerning_values
                    .into_iter()
                    .find(|k| k.second_char_id == character.id)
                    .map(|k| k.value)
                    .unwrap_or(0);
                let page_rect = Rect {
                    x: character.x as i32,
                    y: character.y as i32,
                    width: character.width,
                    height: character.height,
                };
                let screen_x = x + character.xoffset + kerning_value;
                let screen_y = match self.ordinate_orientation {
                    OrdinateOrientation::BottomToTop => {
                        y + self.base_height as i32 - character.yoffset - character.height as i32
                    }
                    OrdinateOrientation::TopToBottom => y + character.yoffset,
                };
                let screen_rect = Rect {
                    x: screen_x,
                    y: screen_y,
                    width: character.width,
                    height: character.height,
                };
                let char_position = CharPosition {
                    page_rect,
                    screen_rect,
                    page_index: character.page_index,
                };
                char_positions.push(char_position);
                x += character.xadvance + kerning_value;
                kerning_values = self.find_kerning_values(character.id);
            }
            match self.ordinate_orientation {
                OrdinateOrientation::TopToBottom => y += self.line_height as i32,
                OrdinateOrientation::BottomToTop => y -= self.line_height as i32,
            }
        }

        #[cfg(feature = "parse-error")]
        {
            Ok(char_positions)
        }

        #[cfg(not(feature = "parse-error"))]
        {
            char_positions
        }
    }

    fn find_kerning_values(&self, first_char_id: u32) -> KerningIter {
        let needle = (first_char_id << 1) - 1;
        let idx = self
            .kerning_values
            .binary_search_by(|probe| (probe.first_char_id << 1).cmp(&needle))
            .unwrap_err();

        KerningIter {
            first_char_id,
            idx,
            values: &self.kerning_values,
        }
    }

    fn parse_lines(&self, s: &str) -> ParseLines {
        let mut lines = Vec::new();
        let mut line = Vec::new();

        #[cfg(feature = "parse-error")]
        let mut missing_characters = Vec::new();

        #[cfg(feature = "parse-error")]
        let mut unsupported_characters = Vec::new();

        for c in s.chars() {
            if c == '\n' {
                lines.push(line);
                line = Vec::new();
                continue;
            }
            if c.len_utf16() != 1 {
                #[cfg(feature = "parse-error")]
                unsupported_characters.push(c);

                continue;
            }
            let tmp_str = {
                let mut t = String::new();
                t.push(c);
                t
            };
            let char_id = tmp_str.encode_utf16().next().unwrap() as u32;
            if let Some(c) = self.characters.iter().find(|c| c.id == char_id) {
                line.push(c);
            } else {
                #[cfg(feature = "parse-error")]
                {
                    missing_characters.push(c);
                }
            }
        }
        if !line.is_empty() {
            lines.push(line);
        }

        #[cfg(feature = "parse-error")]
        if missing_characters.is_empty() && unsupported_characters.is_empty() {
            Ok(lines)
        } else {
            Err(StringParseError {
                missing_characters,
                unsupported_characters,
            })
        }

        #[cfg(not(feature = "parse-error"))]
        lines
    }
}

struct KerningIter<'a> {
    first_char_id: u32,
    idx: usize,
    values: &'a Vec<KerningValue>,
}

impl<'a> KerningIter<'a> {
    fn empty(values: &'a Vec<KerningValue>) -> Self {
        Self {
            first_char_id: 0,
            idx: values.len(),
            values,
        }
    }
}

impl<'a> Iterator for KerningIter<'a> {
    type Item = &'a KerningValue;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(value) = self.values.get(self.idx) {
            if value.first_char_id == self.first_char_id {
                self.idx += 1;

                return Some(value);
            }
        }
        None
    }
}

#[derive(Clone, Debug)]
pub struct PageIter<'a> {
    idx: usize,
    pages: &'a Vec<Page>,
}

impl<'a> PageIter<'a> {
    fn new(pages: &'a Vec<Page>) -> Self {
        Self { idx: 0, pages }
    }
}

impl<'a> Iterator for PageIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(page) = self.pages.get(self.idx) {
            self.idx += 1;
            Some(page.file.as_str())
        } else {
            None
        }
    }
}
<commit_msg>Internal performance improvements, no api change<commit_after>//! Parser for bitmap fonts

mod char;
mod config_parse_error;
mod error;
mod kerning_value;
mod page;
mod rect;
mod sections;
mod string_parse_error;
mod utils;

pub use self::config_parse_error::ConfigParseError;
pub use self::error::Error;
pub use self::rect::Rect;
pub use self::string_parse_error::StringParseError;

use self::char::Char;
use self::kerning_value::KerningValue;
use self::page::Page;
use self::sections::Sections;
use std::io::Read;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _with_ the `parse-error` feature.
#[cfg(feature = "parse-error")]
pub type Parse<'a> = Result<Vec<CharPosition>, StringParseError>;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _without_ the `parse-error` feature.
#[cfg(not(feature = "parse-error"))]
pub type Parse<'a> = Vec<CharPosition>;

#[cfg(feature = "parse-error")]
type ParseLines<'a> = Result<Vec<Vec<&'a Char>>, StringParseError>;

#[cfg(not(feature = "parse-error"))]
type ParseLines<'a> = Vec<Vec<&'a Char>>;

#[derive(Clone, Debug)]
pub struct CharPosition {
    pub page_rect: Rect,
    pub screen_rect: Rect,
    pub page_index: u32,
}

#[derive(Clone, Debug)]
pub enum OrdinateOrientation {
    BottomToTop,
    TopToBottom,
}

/// Holds a decoded bitmap font defintion, including all character advance and kerning values.
#[derive(Clone, Debug)]
pub struct BMFont {
    base_height: u32,
    line_height: u32,
    characters: Vec<Char>,
    kerning_values: Vec<KerningValue>,
    pages: Vec<Page>,
    ordinate_orientation: OrdinateOrientation,
}

impl BMFont {
    /// Constructs a new [BMFont].
    ///
    /// ## Examples
    ///
    /// From a file:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// From a slice of bytes:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// # let my_font_bytes = std::fs::read("font.fnt")?;
    /// let data = std::io::Cursor::new(my_font_bytes);
    /// let font = BMFont::new(data, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    pub fn new<R>(source: R, ordinate_orientation: OrdinateOrientation) -> Result<BMFont, Error>
    where
        R: Read,
    {
        let sections = Sections::new(source)?;

        let base_height;
        let line_height;
        {
            let mut components = sections.common_section.split_whitespace();
            components.next();
            line_height =
                utils::extract_component_value(components.next(), "common", "lineHeight")?;
            base_height = utils::extract_component_value(components.next(), "common", "base")?;
        }

        let mut pages = Vec::with_capacity(sections.page_sections.len());
        for page_section in &sections.page_sections {
            pages.push(Page::new(page_section)?);
        }

        // Sort the characters while loading them so that lookup can be faster during parse
        let mut characters: Vec<Char> = Vec::with_capacity(sections.char_sections.len());
        for char_section in &sections.char_sections {
            let char = Char::new(char_section)?;
            if let Err(idx) = characters.binary_search_by(|probe| probe.id.cmp(&char.id)) {
                characters.insert(idx, char);
            }
        }

        // Also sort kerning values for the same reason, but we allow duplicates
        let mut kerning_values: Vec<KerningValue> =
            Vec::with_capacity(sections.kerning_sections.len());
        for kerning_section in &sections.kerning_sections {
            let kerning = KerningValue::new(kerning_section)?;

            match kerning_values
                .binary_search_by(|probe| probe.first_char_id.cmp(&kerning.first_char_id))
            {
                Err(idx) | Ok(idx) => kerning_values.insert(idx, kerning),
            }
        }

        Ok(BMFont {
            base_height,
            line_height,
            characters,
            kerning_values,
            pages,
            ordinate_orientation,
        })
    }

    /// Returns the height of a `EM` in pixels.
    pub fn base_height(&self) -> u32 {
        self.base_height
    }

    pub fn line_height(&self) -> u32 {
        self.line_height
    }

    /// Returns an `Iterator` of font page bitmap filenames.
    ///
    /// ## Examples
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.pages().next(), Some("font.png"));
    /// #     Ok(())
    /// # }
    /// ```
    pub fn pages(&self) -> PageIter {
        PageIter::new(&self.pages)
    }

    pub fn parse(&self, s: &str) -> Parse {
        let lines = self.parse_lines(s);

        #[cfg(feature = "parse-error")]
        let lines = lines?;

        let mut char_positions = Vec::new();
        let mut y: i32 = 0;
        for line in lines {
            let mut x: i32 = 0;
            let mut kerning_values = KerningIter::empty(&self.kerning_values);
            for character in line {
                let kerning_value = kerning_values
                    .into_iter()
                    .find(|k| k.second_char_id == character.id)
                    .map(|k| k.value)
                    .unwrap_or(0);
                let page_rect = Rect {
                    x: character.x as i32,
                    y: character.y as i32,
                    width: character.width,
                    height: character.height,
                };
                let screen_x = x + character.xoffset + kerning_value;
                let screen_y = match self.ordinate_orientation {
                    OrdinateOrientation::BottomToTop => {
                        y + self.base_height as i32 - character.yoffset - character.height as i32
                    }
                    OrdinateOrientation::TopToBottom => y + character.yoffset,
                };
                let screen_rect = Rect {
                    x: screen_x,
                    y: screen_y,
                    width: character.width,
                    height: character.height,
                };
                let char_position = CharPosition {
                    page_rect,
                    screen_rect,
                    page_index: character.page_index,
                };
                char_positions.push(char_position);
                x += character.xadvance + kerning_value;
                kerning_values = self.find_kerning_values(character.id);
            }
            match self.ordinate_orientation {
                OrdinateOrientation::TopToBottom => y += self.line_height as i32,
                OrdinateOrientation::BottomToTop => y -= self.line_height as i32,
            }
        }

        #[cfg(feature = "parse-error")]
        {
            Ok(char_positions)
        }

        #[cfg(not(feature = "parse-error"))]
        {
            char_positions
        }
    }

    fn find_kerning_values(&self, first_char_id: u32) -> KerningIter {
        let needle = (first_char_id << 1) - 1;
        let idx = self
            .kerning_values
            .binary_search_by(|probe| (probe.first_char_id << 1).cmp(&needle))
            .unwrap_err();

        KerningIter {
            first_char_id,
            idx,
            values: &self.kerning_values,
        }
    }

    fn parse_lines(&self, s: &str) -> ParseLines {
        let mut lines = Vec::new();
        let mut line = Vec::new();
        let mut temp = [0u16; 2];

        #[cfg(feature = "parse-error")]
        {
            let mut missing_characters: Option<Vec<char>> = None;
            let mut unsupported_characters: Option<Vec<char>> = None;

            for c in s.chars() {
                if c.len_utf16() != 1 {
                    if let Some(vec) = unsupported_characters.as_mut() {
                        vec.push(c);
                    } else {
                        unsupported_characters = Some(vec![c]);
                    }

                    continue;
                }

                c.encode_utf16(&mut temp);
                let char_id = temp[0] as u32;

                if self
                    .characters
                    .binary_search_by(|probe| probe.id.cmp(&char_id))
                    .is_ok()
                {
                    continue;
                }

                if let Some(vec) = missing_characters.as_mut() {
                    vec.push(c);
                } else {
                    missing_characters = Some(vec![c]);
                }
            }

            if missing_characters.is_some() || unsupported_characters.is_some() {
                return Err(StringParseError {
                    missing_characters: missing_characters.unwrap_or_default(),
                    unsupported_characters: unsupported_characters.unwrap_or_default(),
                });
            }
        }

        for c in s.chars() {
            #[cfg(not(feature = "parse-error"))]
            if c.len_utf16() != 1 {
                continue;
            }

            if c == '\n' {
                lines.push(line);
                line = Vec::new();
                continue;
            }

            c.encode_utf16(&mut temp);
            let char_id = temp[0] as u32;

            let char_idx = self
                .characters
                .binary_search_by(|probe| probe.id.cmp(&char_id));

            #[cfg(not(feature = "parse-error"))]
            if char_idx.is_err() {
                continue;
            }

            let char_idx = char_idx.unwrap();
            line.push(&self.characters[char_idx]);
        }

        if !line.is_empty() {
            lines.push(line);
        }

        #[cfg(feature = "parse-error")]
        {
            Ok(lines)
        }

        #[cfg(not(feature = "parse-error"))]
        lines
    }
}

struct KerningIter<'a> {
    first_char_id: u32,
    idx: usize,
    values: &'a Vec<KerningValue>,
}

impl<'a> KerningIter<'a> {
    fn empty(values: &'a Vec<KerningValue>) -> Self {
        Self {
            first_char_id: 0,
            idx: values.len(),
            values,
        }
    }
}

impl<'a> Iterator for KerningIter<'a> {
    type Item = &'a KerningValue;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(value) = self.values.get(self.idx) {
            if value.first_char_id == self.first_char_id {
                self.idx += 1;

                return Some(value);
            }
        }
        None
    }
}

#[derive(Clone, Debug)]
pub struct PageIter<'a> {
    idx: usize,
    pages: &'a Vec<Page>,
}

impl<'a> PageIter<'a> {
    fn new(pages: &'a Vec<Page>) -> Self {
        Self { idx: 0, pages }
    }
}

impl<'a> Iterator for PageIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(page) = self.pages.get(self.idx) {
            self.idx += 1;
            Some(page.file.as_str())
        } else {
            None
        }
    }
}
<|endoftext|>


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

use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ptr;
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering;
use std::sync::Arc;

/// An Atom wraps an AtomicPtr, it allows for safe mutation of an atomic
/// into common Rust Types.
pub struct Atom

where
    P: IntoRawPtr + FromRawPtr,
{
    inner: AtomicPtr<()>,
    data: PhantomData
,
}

impl
 Debug for Atom

where
    P: IntoRawPtr + FromRawPtr,
{
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        write!(f, "atom({:?})", self.inner.load(Ordering::Relaxed))
    }
}

impl
 Atom

where
    P: IntoRawPtr + FromRawPtr,
{
    /// Create a empty Atom
    pub fn empty() -> Atom
 {
        Atom {
            inner: AtomicPtr::new(ptr::null_mut()),
            data: PhantomData,
        }
    }

    /// Create a new Atomic from Pointer P
    pub fn new(value: P) -> Atom
 {
        Atom {
            inner: AtomicPtr::new(value.into_raw()),
            data: PhantomData,
        }
    }

    /// Swap a new value into the Atom, This will try multiple
    /// times until it succeeds. The old value will be returned.
    pub fn swap(&self, v: P, order: Ordering) -> Option
 {
        let new = v.into_raw();
        let old = self.inner.swap(new, order);
        if !old.is_null() {
            Some(unsafe { FromRawPtr::from_raw(old) })
        } else {
            None
        }
    }

    /// Take the value of the Atom replacing it with null pointer
    /// Returning the contents. If the contents was a `null` pointer the
    /// result will be `None`.
    pub fn take(&self, order: Ordering) -> Option
 {
        let old = self.inner.swap(ptr::null_mut(), order);
        if !old.is_null() {
            Some(unsafe { FromRawPtr::from_raw(old) })
        } else {
            None
        }
    }

    /// This will do a `CAS` setting the value only if it is NULL
    /// this will return `None` if the value was written,
    /// otherwise a `Some(v)` will be returned, where the value was
    /// the same value that you passed into this function
    pub fn set_if_none(&self, v: P, order: Ordering) -> Option
 {
        let new = v.into_raw();
        let old = self.inner.compare_and_swap(ptr::null_mut(), new, order);
        if !old.is_null() {
            Some(unsafe { FromRawPtr::from_raw(new) })
        } else {
            None
        }
    }

    /// Take the current content, write it into P then do a CAS to extent this
    /// Atom with the previous contents. This can be used to create a LIFO
    ///
    /// Returns true if this set this migrated the Atom from null.
    pub fn replace_and_set_next(
        &self,
        mut value: P,
        load_order: Ordering,
        cas_order: Ordering,
    ) -> bool
    where
        P: GetNextMut<NextPtr = Option
>,
    {
        unsafe {
            let next = value.get_next() as *mut Option
;
            let raw = value.into_raw();
            // Iff next was set to Some(P) we want to
            // assert that it was droppeds
            drop(ptr::read(next));
            loop {
                let pcurrent = self.inner.load(load_order);
                let current = if pcurrent.is_null() {
                    None
                } else {
                    Some(FromRawPtr::from_raw(pcurrent))
                };
                ptr::write(next, current);
                let last = self.inner.compare_and_swap(pcurrent, raw, cas_order);
                if last == pcurrent {
                    return last.is_null();
                }
            }
        }
    }

    /// Check to see if an atom is None
    ///
    /// This only means that the contents was None when it was measured
    pub fn is_none(&self, order: Ordering) -> bool {
        self.inner.load(order).is_null()
    }
}

impl
 Drop for Atom

where
    P: IntoRawPtr + FromRawPtr,
{
    fn drop(&mut self) {
        unsafe {
            let ptr = self.inner.load(Ordering::Relaxed);
            if !ptr.is_null() {
                let _: P = FromRawPtr::from_raw(ptr);
            }
        }
    }
}

unsafe impl
 Send for Atom

where
    P: IntoRawPtr + FromRawPtr,
{
}
unsafe impl
 Sync for Atom

where
    P: IntoRawPtr + FromRawPtr,
{
}

/// Convert from into a raw pointer
pub trait IntoRawPtr {
    fn into_raw(self) -> *mut ();
}

/// Convert from a raw ptr into a pointer
pub trait FromRawPtr {
    unsafe fn from_raw(ptr: *mut ()) -> Self;
}

impl<T> IntoRawPtr for Box<T> {
    #[inline]
    fn into_raw(self) -> *mut () {
        Box::into_raw(self) as *mut ()
    }
}

impl<T> FromRawPtr for Box<T> {
    #[inline]
    unsafe fn from_raw(ptr: *mut ()) -> Box<T> {
        Box::from_raw(ptr as *mut T)
    }
}

impl<T> IntoRawPtr for Arc<T> {
    #[inline]
    fn into_raw(self) -> *mut () {
        Arc::into_raw(self) as *mut T as *mut ()
    }
}

impl<T> FromRawPtr for Arc<T> {
    #[inline]
    unsafe fn from_raw(ptr: *mut ()) -> Arc<T> {
        Arc::from_raw(ptr as *const () as *const T)
    }
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
unsafe fn copy_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S, ptr: &T) -> &'a T {
    mem::transmute(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
unsafe fn copy_mut_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S, ptr: &mut T) -> &'a mut T {
    mem::transmute(ptr)
}

/// This is a restricted version of the Atom. It allows for only
/// `set_if_none` to be called.
///
/// `swap` and `take` can be used only with a mutable reference. Meaning
/// that AtomSetOnce is not usable as a
#[derive(Debug)]
pub struct AtomSetOnce

where
    P: IntoRawPtr + FromRawPtr,
{
    inner: Atom
,
}

impl
 AtomSetOnce

where
    P: IntoRawPtr + FromRawPtr,
{
    /// Create an empty `AtomSetOnce`
    pub fn empty() -> AtomSetOnce
 {
        AtomSetOnce {
            inner: Atom::empty(),
        }
    }

    /// Create a new `AtomSetOnce` from Pointer P
    pub fn new(value: P) -> AtomSetOnce
 {
        AtomSetOnce {
            inner: Atom::new(value),
        }
    }

    /// This will do a `CAS` setting the value only if it is NULL
    /// this will return `OK(())` if the value was written,
    /// otherwise a `Err(P)` will be returned, where the value was
    /// the same value that you passed into this function
    pub fn set_if_none(&self, v: P, order: Ordering) -> Option
 {
        self.inner.set_if_none(v, order)
    }

    /// Convert an `AtomSetOnce` into an `Atom`
    pub fn into_atom(self) -> Atom
 {
        self.inner
    }

    /// Allow access to the atom if exclusive access is granted
    pub fn atom(&mut self) -> &mut Atom
 {
        &mut self.inner
    }

    /// Check to see if an atom is None
    ///
    /// This only means that the contents was None when it was measured
    pub fn is_none(&self, order: Ordering) -> bool {
        self.inner.is_none(order)
    }
}

impl<T, P> AtomSetOnce

where
    P: IntoRawPtr + FromRawPtr + Deref<Target = T>,
{
    /// If the Atom is set, get the value
    pub fn get<'a>(&'a self, order: Ordering) -> Option<&'a T> {
        let ptr = self.inner.inner.load(order);
        if ptr.is_null() {
            None
        } else {
            unsafe {
                // This is safe since ptr cannot be changed once it is set
                // which means that this is now a Arc or a Box.
                let v: P = FromRawPtr::from_raw(ptr);
                let out = copy_lifetime(self, &*v);
                mem::forget(v);
                Some(out)
            }
        }
    }
}

impl<T> AtomSetOnce<Box<T>> {
    /// If the Atom is set, get the value
    pub fn get_mut<'a>(&'a mut self, order: Ordering) -> Option<&'a mut T> {
        let ptr = self.inner.inner.load(order);
        if ptr.is_null() {
            None
        } else {
            unsafe {
                // This is safe since ptr cannot be changed once it is set
                // which means that this is now a Arc or a Box.
                let mut v: Box<T> = FromRawPtr::from_raw(ptr);
                let out = copy_mut_lifetime(self, &mut *v);
                mem::forget(v);
                Some(out)
            }
        }
    }
}

impl<T> AtomSetOnce<T>
where
    T: Clone + IntoRawPtr + FromRawPtr,
{
    /// Duplicate the inner pointer if it is set
    pub fn dup<'a>(&self, order: Ordering) -> Option<T> {
        let ptr = self.inner.inner.load(order);
        if ptr.is_null() {
            None
        } else {
            unsafe {
                // This is safe since ptr cannot be changed once it is set
                // which means that this is now a Arc or a Box.
                let v: T = FromRawPtr::from_raw(ptr);
                let out = v.clone();
                mem::forget(v);
                Some(out)
            }
        }
    }
}

/// This is a utility Trait that fetches the next ptr from
/// an object.
pub trait GetNextMut {
    type NextPtr;
    fn get_next(&mut self) -> &mut Self::NextPtr;
}
<commit_msg>Add inner_from_raw<commit_after>//   Copyright 2015 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ptr;
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering;
use std::sync::Arc;

/// An Atom wraps an AtomicPtr, it allows for safe mutation of an atomic
/// into common Rust Types.
pub struct Atom

where
    P: IntoRawPtr + FromRawPtr,
{
    inner: AtomicPtr<()>,
    data: PhantomData
,
}

impl
 Debug for Atom

where
    P: IntoRawPtr + FromRawPtr,
{
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        write!(f, "atom({:?})", self.inner.load(Ordering::Relaxed))
    }
}

impl
 Atom

where
    P: IntoRawPtr + FromRawPtr,
{
    /// Create a empty Atom
    pub fn empty() -> Atom
 {
        Atom {
            inner: AtomicPtr::new(ptr::null_mut()),
            data: PhantomData,
        }
    }

    /// Create a new Atomic from Pointer P
    pub fn new(value: P) -> Atom
 {
        Atom {
            inner: AtomicPtr::new(value.into_raw()),
            data: PhantomData,
        }
    }

    /// Swap a new value into the Atom, This will try multiple
    /// times until it succeeds. The old value will be returned.
    pub fn swap(&self, v: P, order: Ordering) -> Option
 {
        let new = v.into_raw();
        let old = self.inner.swap(new, order);
        unsafe { Self::inner_from_raw(old) }
    }

    /// Take the value of the Atom replacing it with null pointer
    /// Returning the contents. If the contents was a `null` pointer the
    /// result will be `None`.
    pub fn take(&self, order: Ordering) -> Option
 {
        let old = self.inner.swap(ptr::null_mut(), order);
        unsafe { Self::inner_from_raw(old) }
    }

    /// This will do a `CAS` setting the value only if it is NULL
    /// this will return `None` if the value was written,
    /// otherwise a `Some(v)` will be returned, where the value was
    /// the same value that you passed into this function
    pub fn set_if_none(&self, v: P, order: Ordering) -> Option
 {
        let new = v.into_raw();
        let old = self.inner.compare_and_swap(ptr::null_mut(), new, order);
        if !old.is_null() {
            Some(unsafe { FromRawPtr::from_raw(new) })
        } else {
            None
        }
    }

    /// Take the current content, write it into P then do a CAS to extent this
    /// Atom with the previous contents. This can be used to create a LIFO
    ///
    /// Returns true if this set this migrated the Atom from null.
    pub fn replace_and_set_next(
        &self,
        mut value: P,
        load_order: Ordering,
        cas_order: Ordering,
    ) -> bool
    where
        P: GetNextMut<NextPtr = Option
>,
    {
        unsafe {
            let next = value.get_next() as *mut Option
;
            let raw = value.into_raw();
            // Iff next was set to Some(P) we want to
            // assert that it was droppeds
            drop(ptr::read(next));
            loop {
                let pcurrent = self.inner.load(load_order);
                let current = Self::inner_from_raw(pcurrent);
                ptr::write(next, current);
                let last = self.inner.compare_and_swap(pcurrent, raw, cas_order);
                if last == pcurrent {
                    return last.is_null();
                }
            }
        }
    }

    /// Check to see if an atom is None
    ///
    /// This only means that the contents was None when it was measured
    pub fn is_none(&self, order: Ordering) -> bool {
        self.inner.load(order).is_null()
    }

    #[inline]
    unsafe fn inner_from_raw(ptr: *mut ()) -> Option
 {
        if !ptr.is_null() {
            Some(FromRawPtr::from_raw(ptr))
        } else {
            None
        }
    }
}

impl
 Drop for Atom

where
    P: IntoRawPtr + FromRawPtr,
{
    fn drop(&mut self) {
        let ptr = self.inner.load(Ordering::Relaxed);
        let val = unsafe { Self::inner_from_raw(ptr) };
        match val {
            Some(_ptr) => {}
            None => {}
        }
    }
}

unsafe impl
 Send for Atom

where
    P: IntoRawPtr + FromRawPtr,
{
}
unsafe impl
 Sync for Atom

where
    P: IntoRawPtr + FromRawPtr,
{
}

/// Convert from into a raw pointer
pub trait IntoRawPtr {
    fn into_raw(self) -> *mut ();
}

/// Convert from a raw ptr into a pointer
pub trait FromRawPtr {
    unsafe fn from_raw(ptr: *mut ()) -> Self;
}

impl<T> IntoRawPtr for Box<T> {
    #[inline]
    fn into_raw(self) -> *mut () {
        Box::into_raw(self) as *mut ()
    }
}

impl<T> FromRawPtr for Box<T> {
    #[inline]
    unsafe fn from_raw(ptr: *mut ()) -> Box<T> {
        Box::from_raw(ptr as *mut T)
    }
}

impl<T> IntoRawPtr for Arc<T> {
    #[inline]
    fn into_raw(self) -> *mut () {
        Arc::into_raw(self) as *mut T as *mut ()
    }
}

impl<T> FromRawPtr for Arc<T> {
    #[inline]
    unsafe fn from_raw(ptr: *mut ()) -> Arc<T> {
        Arc::from_raw(ptr as *const () as *const T)
    }
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
unsafe fn copy_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S, ptr: &T) -> &'a T {
    mem::transmute(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
unsafe fn copy_mut_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S, ptr: &mut T) -> &'a mut T {
    mem::transmute(ptr)
}

/// This is a restricted version of the Atom. It allows for only
/// `set_if_none` to be called.
///
/// `swap` and `take` can be used only with a mutable reference. Meaning
/// that AtomSetOnce is not usable as a
#[derive(Debug)]
pub struct AtomSetOnce

where
    P: IntoRawPtr + FromRawPtr,
{
    inner: Atom
,
}

impl
 AtomSetOnce

where
    P: IntoRawPtr + FromRawPtr,
{
    /// Create an empty `AtomSetOnce`
    pub fn empty() -> AtomSetOnce
 {
        AtomSetOnce {
            inner: Atom::empty(),
        }
    }

    /// Create a new `AtomSetOnce` from Pointer P
    pub fn new(value: P) -> AtomSetOnce
 {
        AtomSetOnce {
            inner: Atom::new(value),
        }
    }

    /// This will do a `CAS` setting the value only if it is NULL
    /// this will return `OK(())` if the value was written,
    /// otherwise a `Err(P)` will be returned, where the value was
    /// the same value that you passed into this function
    pub fn set_if_none(&self, v: P, order: Ordering) -> Option
 {
        self.inner.set_if_none(v, order)
    }

    /// Convert an `AtomSetOnce` into an `Atom`
    pub fn into_atom(self) -> Atom
 {
        self.inner
    }

    /// Allow access to the atom if exclusive access is granted
    pub fn atom(&mut self) -> &mut Atom
 {
        &mut self.inner
    }

    /// Check to see if an atom is None
    ///
    /// This only means that the contents was None when it was measured
    pub fn is_none(&self, order: Ordering) -> bool {
        self.inner.is_none(order)
    }
}

impl<T, P> AtomSetOnce

where
    P: IntoRawPtr + FromRawPtr + Deref<Target = T>,
{
    /// If the Atom is set, get the value
    pub fn get<'a>(&'a self, order: Ordering) -> Option<&'a T> {
        let ptr = self.inner.inner.load(order);
        let val = unsafe { Atom::inner_from_raw(ptr) };
        val.map(|v: P| {
            // This is safe since ptr cannot be changed once it is set
            // which means that this is now a Arc or a Box.
            let out = unsafe { copy_lifetime(self, &*v) };
            mem::forget(v);
            out
        })
    }
}

impl<T> AtomSetOnce<Box<T>> {
    /// If the Atom is set, get the value
    pub fn get_mut<'a>(&'a mut self, order: Ordering) -> Option<&'a mut T> {
        let ptr = self.inner.inner.load(order);
        let val = unsafe { Atom::inner_from_raw(ptr) };
        val.map(move |mut v: Box<T>| {
            // This is safe since ptr cannot be changed once it is set
            // which means that this is now a Arc or a Box.
            let out = unsafe { copy_mut_lifetime(self, &mut *v) };
            mem::forget(v);
            out
        })
    }
}

impl<T> AtomSetOnce<T>
where
    T: Clone + IntoRawPtr + FromRawPtr,
{
    /// Duplicate the inner pointer if it is set
    pub fn dup<'a>(&self, order: Ordering) -> Option<T> {
        let ptr = self.inner.inner.load(order);
        let val = unsafe { Atom::inner_from_raw(ptr) };
        val.map(|v: T| {
            let out = v.clone();
            mem::forget(v);
            out
        })
    }
}

/// This is a utility Trait that fetches the next ptr from
/// an object.
pub trait GetNextMut {
    type NextPtr;
    fn get_next(&mut self) -> &mut Self::NextPtr;
}
<|endoftext|>


<commit_before>//! A Frames Per Second counter.

extern crate time;

use std::collections::RingBuf;

/// Measures Frames Per Second (FPS).
pub struct FPSCounter {
    /// The last registered frames.
    last_second_frames: RingBuf<time::Timespec>
}

impl FPSCounter {
    /// Creates a new FPSCounter.
    pub fn new() -> FPSCounter {
        FPSCounter {
            last_second_frames: RingBuf::with_capacity(128)
        }
    }

    /// Updates the FPSCounter and returns number of frames.
    pub fn tick(&mut self) -> uint {
        let now = time::now().to_timespec();
        let a_second_ago = time::Timespec::new(now.sec - 1, now.nsec);

        while self.last_second_frames.front().map_or(false, |t| *t < a_second_ago) {
            self.last_second_frames.pop_front();
        }

        self.last_second_frames.push_back(now);
        self.last_second_frames.len()
    }
}
<commit_msg>Upgraded to latest Rust<commit_after>//! A Frames Per Second counter.

extern crate time;

use std::collections::RingBuf;

/// Measures Frames Per Second (FPS).
pub struct FPSCounter {
    /// The last registered frames.
    last_second_frames: RingBuf<time::Timespec>
}

impl FPSCounter {
    /// Creates a new FPSCounter.
    pub fn new() -> FPSCounter {
        FPSCounter {
            last_second_frames: RingBuf::with_capacity(128)
        }
    }

    /// Updates the FPSCounter and returns number of frames.
    pub fn tick(&mut self) -> usize {
        let now = time::now().to_timespec();
        let a_second_ago = time::Timespec::new(now.sec - 1, now.nsec);

        while self.last_second_frames.front().map_or(false, |t| *t < a_second_ago) {
            self.last_second_frames.pop_front();
        }

        self.last_second_frames.push_back(now);
        self.last_second_frames.len()
    }
}
<|endoftext|>