<commit_before>//! Implementation of the `#[assert_instr]` macro
//!
//! This macro is used when testing the `stdsimd` crate and is used to generate
//! test cases to assert that functions do indeed contain the instructions that
//! we're expecting them to contain.
//!
//! The procedural macro here is relatively simple, it simply appends a
//! `#[test]` function to the original token stream which asserts that the
//! function itself contains the relevant instruction.

#![feature(proc_macro)]

extern crate proc_macro2;
extern crate proc_macro;
#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;

use proc_macro2::TokenStream;

#[proc_macro_attribute]
pub fn assert_instr(
    attr: proc_macro::TokenStream, item: proc_macro::TokenStream
) -> proc_macro::TokenStream {
    let invoc = syn::parse::<Invoc>(attr)
        .expect("expected #[assert_instr(instr, a = b, ...)]");
    let item =
        syn::parse::<syn::Item>(item).expect("must be attached to an item");
    let func = match item {
        syn::Item::Fn(ref f) => f,
        _ => panic!("must be attached to a function"),
    };

    let instr = &invoc.instr;
    let maybe_ignore = if cfg!(optimized) {
        TokenStream::empty()
    } else {
        (quote! { #[ignore] }).into()
    };
    let name = &func.ident;
    let assert_name = syn::Ident::from(
        &format!("assert_{}_{}", name.as_ref(), instr.as_ref())[..],
    );
    let shim_name = syn::Ident::from(format!("{}_shim", name.as_ref()));
    let (to_test, test_name) = if invoc.args.len() == 0 {
        (TokenStream::empty(), &func.ident)
    } else {
        let mut inputs = Vec::new();
        let mut input_vals = Vec::new();
        let ret = &func.decl.output;
        for arg in func.decl.inputs.iter() {
            let capture = match *arg {
                syn::FnArg::Captured(ref c) => c,
                _ => panic!("arguments must not have patterns"),
            };
            let ident = match capture.pat {
                syn::Pat::Ident(ref i) => &i.ident,
                _ => panic!("must have bare arguments"),
            };
            match invoc.args.iter().find(|a| a.0 == ident.as_ref()) {
                Some(&(_, ref tts)) => {
                    input_vals.push(quote! { #tts });
                }
                None => {
                    inputs.push(capture);
                    input_vals.push(quote! { #ident });
                }
            };
        }

        let attrs = func.attrs
            .iter()
            .filter(|attr| {
                attr.path
                    .segments
                    .first()
                    .unwrap()
                    .value()
                    .ident
                    .as_ref()
                    .starts_with("target")
            })
            .collect::<Vec<_>>();
        let attrs = Append(&attrs);
        (
            quote! {
                #attrs
                unsafe fn #shim_name(#(#inputs),*) #ret {
                    #name(#(#input_vals),*)
                }
            }.into(),
            &shim_name,
        )
    };

    let tts: TokenStream = quote_spanned! {
        proc_macro2::Span::call_site() =>
        #[test]
        #[allow(non_snake_case)]
        #maybe_ignore
        fn #assert_name() {
            #to_test

            ::stdsimd_test::assert(#test_name as usize,
                                   stringify!(#test_name),
                                   stringify!(#instr));
        }
    }.into();
    // why? necessary now to get tests to work?
    let tts: TokenStream = tts.to_string().parse().unwrap();

    let tts: TokenStream = quote! {
        #item
        #tts
    }.into();
    tts.into()
}

struct Invoc {
    instr: syn::Ident,
    args: Vec<(syn::Ident, syn::Expr)>,
}

impl syn::synom::Synom for Invoc {
    named!(parse -> Self, map!(parens!(do_parse!(
        instr: syn!(syn::Ident) >>
        args: many0!(do_parse!(
            syn!(syn::token::Comma) >>
            name: syn!(syn::Ident) >>
            syn!(syn::token::Eq) >>
            expr: syn!(syn::Expr) >>
            (name, expr)
        )) >>
        (Invoc {
            instr,
            args,
        })
    )), |p| p.1));
}

struct Append<T>(T);

impl<T> quote::ToTokens for Append<T>
where
    T: Clone + IntoIterator,
    T::Item: quote::ToTokens,
{
    fn to_tokens(&self, tokens: &mut quote::Tokens) {
        for item in self.0.clone() {
            item.to_tokens(tokens);
        }
    }
}
<commit_msg>Fix tests for a future nightly (#297)<commit_after>//! Implementation of the `#[assert_instr]` macro
//!
//! This macro is used when testing the `stdsimd` crate and is used to generate
//! test cases to assert that functions do indeed contain the instructions that
//! we're expecting them to contain.
//!
//! The procedural macro here is relatively simple, it simply appends a
//! `#[test]` function to the original token stream which asserts that the
//! function itself contains the relevant instruction.

#![feature(proc_macro)]

extern crate proc_macro2;
extern crate proc_macro;
#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;

use proc_macro2::TokenStream;

#[proc_macro_attribute]
pub fn assert_instr(
    attr: proc_macro::TokenStream, item: proc_macro::TokenStream
) -> proc_macro::TokenStream {
    let invoc = syn::parse::<Invoc>(attr)
        .expect("expected #[assert_instr(instr, a = b, ...)]");
    let item =
        syn::parse::<syn::Item>(item).expect("must be attached to an item");
    let func = match item {
        syn::Item::Fn(ref f) => f,
        _ => panic!("must be attached to a function"),
    };

    let instr = &invoc.instr;
    let maybe_ignore = if cfg!(optimized) {
        TokenStream::empty()
    } else {
        (quote! { #[ignore] }).into()
    };
    let name = &func.ident;
    let assert_name = syn::Ident::from(
        &format!("assert_{}_{}", name.as_ref(), instr.as_ref())[..],
    );
    let shim_name = syn::Ident::from(format!("{}_shim", name.as_ref()));
    let mut inputs = Vec::new();
    let mut input_vals = Vec::new();
    let ret = &func.decl.output;
    for arg in func.decl.inputs.iter() {
        let capture = match *arg {
            syn::FnArg::Captured(ref c) => c,
            _ => panic!("arguments must not have patterns"),
        };
        let ident = match capture.pat {
            syn::Pat::Ident(ref i) => &i.ident,
            _ => panic!("must have bare arguments"),
        };
        match invoc.args.iter().find(|a| a.0 == ident.as_ref()) {
            Some(&(_, ref tts)) => {
                input_vals.push(quote! { #tts });
            }
            None => {
                inputs.push(capture);
                input_vals.push(quote! { #ident });
            }
        };
    }

    let attrs = func.attrs
        .iter()
        .filter(|attr| {
            attr.path
                .segments
                .first()
                .unwrap()
                .value()
                .ident
                .as_ref()
                .starts_with("target")
        })
        .collect::<Vec<_>>();
    let attrs = Append(&attrs);
    let to_test = quote! {
        #attrs
        unsafe extern fn #shim_name(#(#inputs),*) #ret {
            #name(#(#input_vals),*)
        }
    };

    let tts: TokenStream = quote_spanned! {
        proc_macro2::Span::call_site() =>
        #[test]
        #[allow(non_snake_case)]
        #maybe_ignore
        fn #assert_name() {
            #to_test

            ::stdsimd_test::assert(#shim_name as usize,
                                   stringify!(#shim_name),
                                   stringify!(#instr));
        }
    }.into();
    // why? necessary now to get tests to work?
    let tts: TokenStream = tts.to_string().parse().unwrap();

    let tts: TokenStream = quote! {
        #item
        #tts
    }.into();
    tts.into()
}

struct Invoc {
    instr: syn::Ident,
    args: Vec<(syn::Ident, syn::Expr)>,
}

impl syn::synom::Synom for Invoc {
    named!(parse -> Self, map!(parens!(do_parse!(
        instr: syn!(syn::Ident) >>
        args: many0!(do_parse!(
            syn!(syn::token::Comma) >>
            name: syn!(syn::Ident) >>
            syn!(syn::token::Eq) >>
            expr: syn!(syn::Expr) >>
            (name, expr)
        )) >>
        (Invoc {
            instr,
            args,
        })
    )), |p| p.1));
}

struct Append<T>(T);

impl<T> quote::ToTokens for Append<T>
where
    T: Clone + IntoIterator,
    T::Item: quote::ToTokens,
{
    fn to_tokens(&self, tokens: &mut quote::Tokens) {
        for item in self.0.clone() {
            item.to_tokens(tokens);
        }
    }
}
<|endoftext|>


<commit_before>//! Data types and utility function for units:
//! Implemet a poor man's unit type system for now...
//!
//! Maybe we can have s.th. like this (F#) for Rust: https://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure
//! Alternatively, see here:
//! https://www.reddit.com/r/rust/comments/37qut9/typesafe_userdefined_units_of_measure_for_rust/
//! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

macro_rules! init_unit {
    ($unit:ident) => {
        #[derive(Debug,Clone,Copy)]
        pub struct $unit(pub f64);

        impl PartialEq for $unit {
            fn eq(self: &$unit, &$unit(rhs): &$unit) -> bool {
                let $unit(lhs) = *self;
                lhs == rhs
            }
        }

        impl Add for $unit {
            type Output = $unit;

            fn add(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs + rhs)
            }
        }

        impl Sub for $unit {
            type Output = $unit;

            fn sub(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs - rhs)
            }
        }

        impl Mul<f64> for $unit {
            type Output = $unit;

            fn mul(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs * rhs)
            }
        }

        impl Mul<$unit> for f64 {
            type Output = $unit;

            fn mul(self: f64, $unit(rhs): $unit) -> $unit {
                $unit(self * rhs)
            }
        }

        impl Div<f64> for $unit {
            type Output = $unit;

            fn div(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs / rhs)
            }
        }

        impl Div<$unit> for $unit {
            type Output = f64;

            fn div(self: $unit, $unit(rhs): $unit) -> f64 {
                let $unit(lhs) = self;
                lhs / rhs
            }
        }
    }
}

macro_rules! mul_div_unit {
    // $unit1 * $unit2 = $unit3
    // $unit2 * $unit1 = $unit3
    // $unit1 = $unit3 / $unit2
    // $unit2 = $unit3 / $unit1
    ($unit1:ident, $unit2:ident, $unit3:ident) => {
        impl Mul<$unit2> for $unit1 {
            type Output = $unit3;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> $unit3 {
                let $unit1(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Mul<$unit1> for $unit2 {
            type Output = $unit3;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> $unit3 {
                let $unit2(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Div<$unit2> for $unit3 {
            type Output = $unit1;

            fn div(self: $unit3, $unit2(rhs): $unit2) -> $unit1 {
                let $unit3(lhs) = self;
                $unit1(lhs / rhs)
            }
        }

        impl Div<$unit1> for $unit3 {
            type Output = $unit2;

            fn div(self: $unit3, $unit1(rhs): $unit1) -> $unit2 {
                let $unit3(lhs) = self;
                $unit2(lhs / rhs)
            }
        }
    };

    // $unit1 * $unit1 = $unit2
    // $unit1 = $unit2 / $unit1
    ($unit1:ident, $unit2:ident) => {
        impl Mul<$unit1> for $unit1 {
            type Output = $unit2;

            fn mul(self: $unit1, $unit1(rhs): $unit1) -> $unit2 {
                let $unit1(lhs) = self;
                $unit2(lhs * rhs)
            }
        }

        impl Div<$unit1> for $unit2 {
            type Output = $unit1;

            fn div(self: $unit2, $unit1(rhs): $unit1) -> $unit1 {
                let $unit2(lhs) = self;
                $unit1(lhs / rhs)
            }
        }
    }
}

macro_rules! inverse_unit {
    ($unit1:ident, $unit2:ident) => {
        // A * B = 1
        impl Mul<$unit2> for $unit1 {
            type Output = f64;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> f64 {
                let $unit1(lhs) = self;
                lhs * rhs
            }
        }

        // B * A = 1
        impl Mul<$unit1> for $unit2 {
            type Output = f64;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> f64 {
                let $unit2(lhs) = self;
                lhs * rhs
            }
        }

        // 1 / A = B
        impl Div<$unit1> for f64 {
            type Output = $unit2;

            fn div(self: f64, $unit1(rhs): $unit1) -> $unit2 {
                $unit2(self / rhs)
            }
        }

        // 1 / B = A
        impl Div<$unit2> for f64 {
            type Output = $unit1;

            fn div(self: f64, $unit2(rhs): $unit2) -> $unit1 {
                $unit1(self / rhs)
            }
        }
    }
}

macro_rules! init_unit_and_inverse {
    ($unit1:ident, $per_unit1:ident) => {
        init_unit!($unit1);
        init_unit!($per_unit1);
        inverse_unit!($unit1, $per_unit1);
    }
}

macro_rules! power3_unit {
    ($unit1:ident, $unit2:ident, $unit3:ident, $per_unit1:ident, $per_unit2:ident, $per_unit3:ident) => {
        mul_div_unit!($unit1, $unit2);
        mul_div_unit!($unit1, $unit2, $unit3);

        mul_div_unit!($per_unit1, $per_unit2);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit3);

        mul_div_unit!($unit1, $per_unit2, $per_unit1);
        mul_div_unit!($unit1, $per_unit3, $per_unit2);

        mul_div_unit!($unit2, $per_unit1, $unit1);
        mul_div_unit!($unit2, $per_unit3, $per_unit1);

        mul_div_unit!($unit3, $per_unit1, $unit2);
        mul_div_unit!($unit3, $per_unit2, $unit1);
    }
}

init_unit_and_inverse!(Meter, PerMeter);
init_unit_and_inverse!(Meter2, PerMeter2);
init_unit_and_inverse!(Meter3, PerMeter3);
power3_unit!(Meter, Meter2, Meter3, PerMeter, PerMeter2, PerMeter3);

init_unit_and_inverse!(Second, PerSecond);
init_unit_and_inverse!(Second2, PerSecond2);
init_unit_and_inverse!(Second3, PerSecond3);
power3_unit!(Second, Second2, Second3, PerSecond, PerSecond2, PerSecond3);

init_unit_and_inverse!(MeterPerSecond, SecondPerMeter);

mul_div_unit!(MeterPerSecond, Second, Meter);
mul_div_unit!(Meter, PerSecond, MeterPerSecond);
mul_div_unit!(MeterPerSecond, PerMeter, PerSecond);

mul_div_unit!(SecondPerMeter, Meter, Second);
mul_div_unit!(Second, PerMeter, SecondPerMeter);

init_unit_and_inverse!(MeterPerSecond2, Second2PerMeter);

mul_div_unit!(MeterPerSecond2, Second, MeterPerSecond);
mul_div_unit!(MeterPerSecond2, Second2, Meter);
mul_div_unit!(MeterPerSecond, PerSecond, MeterPerSecond2);

init_unit_and_inverse!(Meter2PerSecond, SecondPerMeter2);

mul_div_unit!(MeterPerSecond, Meter, Meter2PerSecond);
mul_div_unit!(Meter2, PerSecond, Meter2PerSecond);
mul_div_unit!(Meter2PerSecond, PerMeter, MeterPerSecond);

init_unit_and_inverse!(Meter2PerSecond2, Second2PerMeter2);

mul_div_unit!(Meter2PerSecond2, Second, Meter2PerSecond);
mul_div_unit!(Meter2PerSecond2, Second2, Meter2);
mul_div_unit!(MeterPerSecond, Meter2PerSecond2);

init_unit_and_inverse!(Meter2Second, PerMeter2Second);

mul_div_unit!(Meter2, Second, Meter2Second);
mul_div_unit!(PerSecond2, Meter2Second, Meter2PerSecond);

init_unit_and_inverse!(Kilogram, PerKilogram);

 // momentum, impulse
init_unit_and_inverse!(KilogramMeterPerSecond, SecondPerKilogramMeter);

mul_div_unit!(Kilogram, MeterPerSecond, KilogramMeterPerSecond);

init_unit_and_inverse!(Newton, PerNewton);

mul_div_unit!(Kilogram, MeterPerSecond2, Newton);
mul_div_unit!(Newton, Second, KilogramMeterPerSecond);

init_unit_and_inverse!(Pascal, PerPascal);

mul_div_unit!(Pascal, Meter2, Newton);

init_unit_and_inverse!(Joule, PerJoule);

mul_div_unit!(Joule, Meter, Newton);

init_unit_and_inverse!(Watt, PerWatt);

mul_div_unit!(Watt, Second, Joule);

init_unit_and_inverse!(DegC, PerDegC);

init_unit_and_inverse!(Kelvin, PerKelvin);

init_unit_and_inverse!(Kelvin2, PerKelvin2);

mul_div_unit!(Kelvin, Kelvin2);

init_unit_and_inverse!(KelvinPerSecond, SecondPerKelvin);

mul_div_unit!(KelvinPerSecond, Second, Kelvin);

init_unit_and_inverse!(DegCPerSecond, SecondPerDegC);

mul_div_unit!(DegCPerSecond, Second, DegC);

init_unit!(JouleDegCPerSecond);

mul_div_unit!(DegCPerSecond, Joule, JouleDegCPerSecond);

init_unit!(JouleKelvinPerSecond);

mul_div_unit!(KelvinPerSecond, Joule, JouleKelvinPerSecond);

init_unit_and_inverse!(Mol, PerMol);

init_unit_and_inverse!(JoulePerKelvin, KelvinPerJoule);

init_unit_and_inverse!(JoulePerMol, MolPerJoule);

init_unit_and_inverse!(JoulePerKelvinMol, KelvinMolPerJoule);

init_unit_and_inverse!(JouleKelvinPerMol, MolPerJouleKelvin);

mul_div_unit!(JoulePerKelvinMol, Kelvin2, JouleKelvinPerMol);

init_unit_and_inverse!(SecondPerMol, MolPerSecond);

mul_div_unit!(SecondPerMol, JouleKelvinPerSecond, JouleKelvinPerMol);

mul_div_unit!(Mol, SecondPerMol, Second);

mul_div_unit!(Mol, JoulePerKelvinMol, JoulePerKelvin);

mul_div_unit!(Kelvin, JoulePerKelvin, Joule);
<commit_msg>refactor add helper macro<commit_after>//! Data types and utility function for units:
//! Implemet a poor man's unit type system for now...
//!
//! Maybe we can have s.th. like this (F#) for Rust: https://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure
//! Alternatively, see here:
//! https://www.reddit.com/r/rust/comments/37qut9/typesafe_userdefined_units_of_measure_for_rust/
//! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

macro_rules! init_unit {
    ($unit:ident) => {
        #[derive(Debug,Clone,Copy)]
        pub struct $unit(pub f64);

        impl PartialEq for $unit {
            fn eq(self: &$unit, &$unit(rhs): &$unit) -> bool {
                let $unit(lhs) = *self;
                lhs == rhs
            }
        }

        impl Add for $unit {
            type Output = $unit;

            fn add(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs + rhs)
            }
        }

        impl Sub for $unit {
            type Output = $unit;

            fn sub(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs - rhs)
            }
        }

        impl Mul<f64> for $unit {
            type Output = $unit;

            fn mul(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs * rhs)
            }
        }

        impl Mul<$unit> for f64 {
            type Output = $unit;

            fn mul(self: f64, $unit(rhs): $unit) -> $unit {
                $unit(self * rhs)
            }
        }

        impl Div<f64> for $unit {
            type Output = $unit;

            fn div(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs / rhs)
            }
        }

        impl Div<$unit> for $unit {
            type Output = f64;

            fn div(self: $unit, $unit(rhs): $unit) -> f64 {
                let $unit(lhs) = self;
                lhs / rhs
            }
        }
    }
}

macro_rules! mul_div_unit {
    // $unit1 * $unit2 = $unit3
    // $unit2 * $unit1 = $unit3
    // $unit1 = $unit3 / $unit2
    // $unit2 = $unit3 / $unit1
    ($unit1:ident, $unit2:ident, $unit3:ident) => {
        impl Mul<$unit2> for $unit1 {
            type Output = $unit3;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> $unit3 {
                let $unit1(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Mul<$unit1> for $unit2 {
            type Output = $unit3;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> $unit3 {
                let $unit2(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Div<$unit2> for $unit3 {
            type Output = $unit1;

            fn div(self: $unit3, $unit2(rhs): $unit2) -> $unit1 {
                let $unit3(lhs) = self;
                $unit1(lhs / rhs)
            }
        }

        impl Div<$unit1> for $unit3 {
            type Output = $unit2;

            fn div(self: $unit3, $unit1(rhs): $unit1) -> $unit2 {
                let $unit3(lhs) = self;
                $unit2(lhs / rhs)
            }
        }
    };

    // $unit1 * $unit1 = $unit2
    // $unit1 = $unit2 / $unit1
    ($unit1:ident, $unit2:ident) => {
        impl Mul<$unit1> for $unit1 {
            type Output = $unit2;

            fn mul(self: $unit1, $unit1(rhs): $unit1) -> $unit2 {
                let $unit1(lhs) = self;
                $unit2(lhs * rhs)
            }
        }

        impl Div<$unit1> for $unit2 {
            type Output = $unit1;

            fn div(self: $unit2, $unit1(rhs): $unit1) -> $unit1 {
                let $unit2(lhs) = self;
                $unit1(lhs / rhs)
            }
        }
    }
}

macro_rules! inverse_unit {
    ($unit1:ident, $unit2:ident) => {
        // A * B = 1
        impl Mul<$unit2> for $unit1 {
            type Output = f64;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> f64 {
                let $unit1(lhs) = self;
                lhs * rhs
            }
        }

        // B * A = 1
        impl Mul<$unit1> for $unit2 {
            type Output = f64;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> f64 {
                let $unit2(lhs) = self;
                lhs * rhs
            }
        }

        // 1 / A = B
        impl Div<$unit1> for f64 {
            type Output = $unit2;

            fn div(self: f64, $unit1(rhs): $unit1) -> $unit2 {
                $unit2(self / rhs)
            }
        }

        // 1 / B = A
        impl Div<$unit2> for f64 {
            type Output = $unit1;

            fn div(self: f64, $unit2(rhs): $unit2) -> $unit1 {
                $unit1(self / rhs)
            }
        }
    }
}

macro_rules! init_unit_and_inverse {
    ($unit1:ident, $per_unit1:ident) => {
        init_unit!($unit1);
        init_unit!($per_unit1);
        inverse_unit!($unit1, $per_unit1);
    }
}

macro_rules! power3_unit {
    ($unit1:ident, $unit2:ident, $unit3:ident, $per_unit1:ident, $per_unit2:ident, $per_unit3:ident) => {
        mul_div_unit!($unit1, $unit2);
        mul_div_unit!($unit1, $unit2, $unit3);

        mul_div_unit!($per_unit1, $per_unit2);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit3);

        mul_div_unit!($unit1, $per_unit2, $per_unit1);
        mul_div_unit!($unit1, $per_unit3, $per_unit2);

        mul_div_unit!($unit2, $per_unit1, $unit1);
        mul_div_unit!($unit2, $per_unit3, $per_unit1);

        mul_div_unit!($unit3, $per_unit1, $unit2);
        mul_div_unit!($unit3, $per_unit2, $unit1);
    }
}

macro_rules! combine_unit {
    ($unit1:ident, $per_unit1:ident, $unit2:ident, $per_unit2:ident, $unit1_unit2:ident, $unit1_per_unit2:ident, $unit2_per_unit1:ident, $per_unit1_unit2:ident) => {
        mul_div_unit!($unit1, $unit2, $unit1_unit2);
        mul_div_unit!($unit1, $per_unit2, $unit1_per_unit2);

        mul_div_unit!($unit1_per_unit2, $unit2, $unit1);
        mul_div_unit!($unit1_per_unit2, $per_unit1, $per_unit2);

        mul_div_unit!($unit2_per_unit1, $unit1, $unit2);
        mul_div_unit!($unit2_per_unit1, $per_unit2, $per_unit1);

        mul_div_unit!($unit2, $per_unit1, $unit2_per_unit1);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit1_unit2);

        mul_div_unit!($unit1_unit2, $per_unit1, $unit2);
        mul_div_unit!($unit1_unit2, $per_unit2, $unit1);

        mul_div_unit!($per_unit1_unit2, $unit1, $per_unit2);
        mul_div_unit!($per_unit1_unit2, $unit2, $per_unit1);
    }
}

init_unit_and_inverse!(Meter, PerMeter);
init_unit_and_inverse!(Meter2, PerMeter2);
init_unit_and_inverse!(Meter3, PerMeter3);
power3_unit!(Meter, Meter2, Meter3, PerMeter, PerMeter2, PerMeter3);

init_unit_and_inverse!(Second, PerSecond);
init_unit_and_inverse!(Second2, PerSecond2);
init_unit_and_inverse!(Second3, PerSecond3);
power3_unit!(Second, Second2, Second3, PerSecond, PerSecond2, PerSecond3);

init_unit_and_inverse!(MeterPerSecond, SecondPerMeter);
init_unit_and_inverse!(MeterPerSecond2, Second2PerMeter);
init_unit_and_inverse!(Meter2PerSecond, SecondPerMeter2);
init_unit_and_inverse!(Meter2PerSecond2, Second2PerMeter2);
init_unit_and_inverse!(MeterSecond, PerMeterSecond);
init_unit_and_inverse!(Meter2Second, PerMeter2Second);
init_unit_and_inverse!(MeterSecond2, PerMeterSecond2);
init_unit_and_inverse!(Meter2Second2, PerMeter2Second2);

combine_unit!(Meter, PerMeter, Second, PerSecond, MeterSecond, MeterPerSecond, SecondPerMeter, PerMeterSecond);
combine_unit!(Meter2, PerMeter2, Second, PerSecond, Meter2Second, Meter2PerSecond, SecondPerMeter2, PerMeter2Second);
combine_unit!(Meter, PerMeter, Second2, PerSecond2, MeterSecond2, MeterPerSecond2, Second2PerMeter, PerMeterSecond2);
combine_unit!(Meter2, PerMeter2, Second2, PerSecond2, Meter2Second2, Meter2PerSecond2, Second2PerMeter2, PerMeter2Second2);

mul_div_unit!(PerSecond2, Meter2Second, Meter2PerSecond);

init_unit_and_inverse!(Kilogram, PerKilogram);

 // momentum, impulse
init_unit_and_inverse!(KilogramMeterPerSecond, SecondPerKilogramMeter);

mul_div_unit!(Kilogram, MeterPerSecond, KilogramMeterPerSecond);

init_unit_and_inverse!(Newton, PerNewton);

mul_div_unit!(Kilogram, MeterPerSecond2, Newton);
mul_div_unit!(Newton, Second, KilogramMeterPerSecond);

init_unit_and_inverse!(Pascal, PerPascal);

mul_div_unit!(Pascal, Meter2, Newton);

init_unit_and_inverse!(Joule, PerJoule);

mul_div_unit!(Joule, Meter, Newton);

init_unit_and_inverse!(Watt, PerWatt);

mul_div_unit!(Watt, Second, Joule);

init_unit_and_inverse!(DegC, PerDegC);

init_unit_and_inverse!(Kelvin, PerKelvin);

init_unit_and_inverse!(Kelvin2, PerKelvin2);

mul_div_unit!(Kelvin, Kelvin2);

init_unit_and_inverse!(KelvinPerSecond, SecondPerKelvin);

mul_div_unit!(KelvinPerSecond, Second, Kelvin);

init_unit_and_inverse!(DegCPerSecond, SecondPerDegC);

mul_div_unit!(DegCPerSecond, Second, DegC);

init_unit!(JouleDegCPerSecond);

mul_div_unit!(DegCPerSecond, Joule, JouleDegCPerSecond);

init_unit!(JouleKelvinPerSecond);

mul_div_unit!(KelvinPerSecond, Joule, JouleKelvinPerSecond);

init_unit_and_inverse!(Mol, PerMol);

init_unit_and_inverse!(JoulePerKelvin, KelvinPerJoule);

init_unit_and_inverse!(JoulePerMol, MolPerJoule);

init_unit_and_inverse!(JoulePerKelvinMol, KelvinMolPerJoule);

init_unit_and_inverse!(JouleKelvinPerMol, MolPerJouleKelvin);

mul_div_unit!(JoulePerKelvinMol, Kelvin2, JouleKelvinPerMol);

init_unit_and_inverse!(SecondPerMol, MolPerSecond);

mul_div_unit!(SecondPerMol, JouleKelvinPerSecond, JouleKelvinPerMol);

mul_div_unit!(Mol, SecondPerMol, Second);

mul_div_unit!(Mol, JoulePerKelvinMol, JoulePerKelvin);

mul_div_unit!(Kelvin, JoulePerKelvin, Joule);
<|endoftext|>


<commit_before>use std::string::String;

use super::sql::*;
use super::rel::*;
use super::schema::*;

pub struct SqlToRel {
    default_schema: Option<String>
}

impl SqlToRel {

    pub fn sql_to_rel(&self, sql: &ASTNode, tt: &TupleType) -> Result<Box<Rel>, String> {
        match sql {
            &ASTNode::SQLSelect { ref projection, ref relation, .. } => {

                let expr : Vec<Rex> = projection.iter()
                    .map(|e| self.sql_to_rex(&e, tt).unwrap() )
                    .collect();

                let input = match relation {
                    &Some(ref r) => Some(self.sql_to_rel(r, tt)?),
                    &None => None
                };

                Ok(Box::new(Rel::Projection {
                    expr: expr,
                    input: input
                }))
            },

            _ => panic!("not implemented")
        }
    }

    pub fn sql_to_rex(&self, sql: &ASTNode, tt: &TupleType) -> Result<Rex, String> {
        match sql {
            &ASTNode::SQLIdentifier { ref id, .. } => {
                match tt.columns.iter().position(|c| c.name.eq(id) ) {
                    Some(index) => Ok(Rex::TupleValue(index)),
                    None => Err(String::from("Invalid identifier"))
                }
            },
            _ => Err(String::from("Unsupported ast node"))
        }
    }

}
<commit_msg>cleaning up some error handling<commit_after>use std::string::String;

use super::sql::*;
use super::rel::*;
use super::schema::*;

pub struct SqlToRel {
    default_schema: Option<String>
}

impl SqlToRel {

    pub fn sql_to_rel(&self, sql: &ASTNode, tt: &TupleType) -> Result<Box<Rel>, String> {
        match sql {
            &ASTNode::SQLSelect { ref projection, ref relation, .. } => {

                let expr : Vec<Rex> = projection.iter()
                    .map(|e| self.sql_to_rex(&e, tt) )
                    .collect::<Result<Vec<Rex>,String>>()?;

                let input = match relation {
                    &Some(ref r) => Some(self.sql_to_rel(r, tt)?),
                    &None => None
                };

                Ok(Box::new(Rel::Projection {
                    expr: expr,
                    input: input
                }))
            },

            _ => panic!("not implemented")
        }
    }

    pub fn sql_to_rex(&self, sql: &ASTNode, tt: &TupleType) -> Result<Rex, String> {
        match sql {
            &ASTNode::SQLIdentifier { ref id, .. } => {
                match tt.columns.iter().position(|c| c.name.eq(id) ) {
                    Some(index) => Ok(Rex::TupleValue(index)),
                    None => Err(String::from("Invalid identifier"))
                }
            },
            _ => Err(String::from("Unsupported ast node"))
        }
    }

}
<|endoftext|>


<commit_before>//! Future-aware synchronization
//!
//! This module, which is modeled after `std::sync`, contains user-space
//! synchronization tools that work with futures, streams and sinks. In
//! particular, these synchronizers do *not* block physical OS threads, but
//! instead work at the task level.

pub mod oneshot;
pub mod spsc;
mod bilock;

pub use self::bilock::{BiLock, BiLockAcquire, BiLockAcquired};
<commit_msg>Export BiLockGuard as well<commit_after>//! Future-aware synchronization
//!
//! This module, which is modeled after `std::sync`, contains user-space
//! synchronization tools that work with futures, streams and sinks. In
//! particular, these synchronizers do *not* block physical OS threads, but
//! instead work at the task level.

pub mod oneshot;
pub mod spsc;
mod bilock;

pub use self::bilock::{BiLock, BiLockGuard, BiLockAcquire, BiLockAcquired};
<|endoftext|>


<commit_before>use types::table_flag_type::TableFlagType;

#[inline]
pub fn split_values_vec(values: Vec<String>) -> String {
    let string = values.into_iter().collect::<Vec<String>>()
        .join(",").to_owned();
    string.clone()
}

#[inline]
pub fn split_flags_vec(values: Vec<TableFlagType>) -> String {
    let string = values.into_iter().map(|v| v.as_ref().to_string())
        .collect::<Vec<String>>().join("|").to_owned();
    string.clone()
}
<commit_msg>mod: Make more generic utility method<commit_after>use std::convert::AsRef;

#[inline]
pub fn split_values_vec(values: Vec<String>) -> String {
    let string = values.into_iter().collect::<Vec<String>>()
        .join(",").to_owned();
    string.clone()
}

#[inline]
pub fn split_flags_vec<T>(values: Vec<T>) -> String where T: AsRef<str> {
    let string = values.into_iter().map(|v| v.as_ref().to_string())
        .collect::<Vec<String>>().join("|").to_owned();
    string.clone()
}
<|endoftext|>


<commit_before>use crate::{
    cli::{print_error, Command},
    config, convert, open, plugins, serve, upgrade,
    util::dirs,
};
use anyhow::{anyhow, bail, Result};
use rustyline::error::ReadlineError;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(
    about = "Stencila command line tool",
    setting = structopt::clap::AppSettings::NoBinaryName,
    setting = structopt::clap::AppSettings::ColoredHelp,
    setting = structopt::clap::AppSettings::VersionlessSubcommands
)]
pub struct Line {
    #[structopt(subcommand)]
    pub command: Command,
}

/// Run the interactive REPL
#[tracing::instrument(skip(config, plugins_store))]
pub async fn run(
    prefix: Vec<String>,
    config: &config::Config,
    plugins_store: &mut plugins::Store,
) -> Result<()> {
    let history_file = dirs::config(true)?.join("history.txt");

    let mut rl = editor::new();
    if rl.load_history(&history_file).is_err() {
        tracing::debug!("No previous history found")
    }

    let mut prefix = prefix.clone();
    let mut config = config.clone();

    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);

                let mut args = line
                    .split_whitespace()
                    .map(str::to_string)
                    .collect::<Vec<String>>();

                if let Some(first) = line.trim_start().chars().next() {
                    if first == '~' {
                        println!("Command prefix is {:?}", prefix);
                        continue;
                    } else if first == '<' {
                        prefix = args[1..].into();
                        println!("Set command prefix to {:?}", prefix);
                        continue;
                    } else if first == '>' {
                        prefix.clear();
                        println!("Cleared command prefix");
                        continue;
                    } else if first == '?' {
                        args[0] = "help".into();
                    }
                };

                let args = [prefix.as_slice(), args.as_slice()].concat();
                match Line::clap().get_matches_from_safe(args) {
                    Ok(matches) => {
                        let Line { command } = Line::from_clap(&matches);
                        if let Err(error) = match command {
                            Command::Open(args) => open::cli::run(args).await,
                            Command::Convert(args) => convert::cli::run(args),
                            Command::Serve(args) => serve::cli::run(args, &config.serve).await,
                            Command::Plugins(args) => {
                                plugins::cli::run(args, &config.plugins, plugins_store).await
                            }
                            Command::Upgrade(args) => upgrade::cli::run(args, &config.upgrade),
                            Command::Config(args) => match config::cli::run(args, &config) {
                                Ok(config_changed) => {
                                    // Update the configuration (may have been changed by `set` and `reset`)
                                    config = config_changed;
                                    Ok(())
                                }
                                Err(err) => Err(err),
                            },
                        } {
                            print_error(error)
                        }
                    }
                    Err(error) => {
                        if error.kind == structopt::clap::ErrorKind::VersionDisplayed {
                            print!("{}", error)
                        } else if error.kind == structopt::clap::ErrorKind::HelpDisplayed
                            || error.kind == structopt::clap::ErrorKind::MissingArgumentOrSubcommand
                        {
                            // Remove the unnecessary command / version line at the start
                            let lines = format!("{}\n", error)
                                .to_string()
                                .lines()
                                .skip(1)
                                .map(str::to_string)
                                .collect::<Vec<String>>()
                                .join("\n");
                            print!("{}", lines)
                        } else {
                            tracing::debug!("{:?}", error.kind);
                            print_error(anyhow!(error))
                        }
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                tracing::info!("Ctrl-C pressed, interrupting current command");
                // TODO
            }
            Err(ReadlineError::Eof) => {
                tracing::info!("Ctrl-D pressed, ending session");
                break;
            }
            Err(error) => bail!(error),
        }
    }
    rl.save_history(&history_file)?;

    Ok(())
}

mod editor {
    use ansi_term::Colour::{Blue, White, Yellow};
    use rustyline::{
        completion::{Completer, FilenameCompleter, Pair},
        config::OutputStreamType,
        highlight::{Highlighter, MatchingBracketHighlighter},
        hint::{Hinter, HistoryHinter},
        validate::{MatchingBracketValidator, Validator},
        validate::{ValidationContext, ValidationResult},
        CompletionType, Context, EditMode, Editor, Result,
    };
    use rustyline_derive::Helper;
    use std::borrow::Cow::{self, Owned};

    pub fn new() -> Editor<Helper> {
        let config = rustyline::Config::builder()
            .history_ignore_space(true)
            .max_history_size(1000)
            .completion_type(CompletionType::List)
            .edit_mode(EditMode::Emacs)
            .output_stream(OutputStreamType::Stdout)
            .build();

        let mut editor = Editor::with_config(config);

        let helper = Helper::new();
        editor.set_helper(Some(helper));

        editor
    }

    #[derive(Helper)]
    pub struct Helper {
        pub completer: FilenameCompleter,
        pub hinter: HistoryHinter,
        pub validator: MatchingBracketValidator,
        pub highlighter: MatchingBracketHighlighter,
    }

    impl Helper {
        pub fn new() -> Self {
            Helper {
                completer: FilenameCompleter::new(),
                hinter: HistoryHinter {},
                validator: MatchingBracketValidator::new(),
                highlighter: MatchingBracketHighlighter::new(),
            }
        }
    }

    /// Provides tab-completion candidates
    ///
    /// https://github.com/kkawakam/rustyline/blob/master/src/completion.rs
    impl Completer for Helper {
        type Candidate = Pair;

        fn complete(
            &self,
            line: &str,
            pos: usize,
            ctx: &Context<'_>,
        ) -> Result<(usize, Vec<Self::Candidate>)> {
            self.completer.complete(line, pos, ctx)
        }
    }

    /// Provides hints based on the current line
    ///
    /// See https://github.com/kkawakam/rustyline/blob/master/src/hint.rs
    impl Hinter for Helper {
        type Hint = String;

        // Takes the currently edited line with the cursor position and returns the string that should be
        // displayed or None if no hint is available for the text the user currently typed
        fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<String> {
            self.hinter.hint(line, pos, ctx)
        }
    }

    /// Determines whether the current buffer is a valid command or should continue.
    ///
    /// Will not validate unless brackets (round, square and curly) are balanced.
    impl Validator for Helper {
        fn validate(&self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
            self.validator.validate(ctx)
        }

        fn validate_while_typing(&self) -> bool {
            self.validator.validate_while_typing()
        }
    }

    /// Syntax highlighter
    ///
    /// Highlights brackets, prompt, hints and completion candidates.
    /// See https://github.com/kkawakam/rustyline/blob/master/src/highlight.rs
    impl Highlighter for Helper {
        fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
            self.highlighter.highlight(line, pos)
        }

        fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
            &'s self,
            prompt: &'p str,
            _default: bool,
        ) -> Cow<'b, str> {
            Owned(Blue.paint(prompt).to_string())
        }

        fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
            Owned(White.dimmed().paint(hint).to_string())
        }

        fn highlight_candidate<'c>(
            &self,
            candidate: &'c str,
            _completion: CompletionType,
        ) -> Cow<'c, str> {
            Owned(Yellow.dimmed().paint(candidate).to_string())
        }

        fn highlight_char(&self, line: &str, pos: usize) -> bool {
            self.highlighter.highlight_char(line, pos)
        }
    }
}
<commit_msg>fix(Interact): Add welcome message<commit_after>use crate::{
    cli::{print_error, Command},
    config, convert, open, plugins, serve, upgrade,
    util::dirs,
};
use anyhow::{anyhow, bail, Result};
use rustyline::error::ReadlineError;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(
    about = "Stencila CLI interactive mode",
    setting = structopt::clap::AppSettings::NoBinaryName,
    setting = structopt::clap::AppSettings::ColoredHelp,
    setting = structopt::clap::AppSettings::VersionlessSubcommands
)]
pub struct Line {
    #[structopt(subcommand)]
    pub command: Command,
}

/// Run the interactive REPL
#[tracing::instrument(skip(config, plugins_store))]
pub async fn run(
    prefix: Vec<String>,
    config: &config::Config,
    plugins_store: &mut plugins::Store,
) -> Result<()> {
    let history_file = dirs::config(true)?.join("history.txt");

    println!("Welcome to interactive mode. Use `--help` or `?` for help.");

    let mut rl = editor::new();
    if rl.load_history(&history_file).is_err() {
        tracing::debug!("No previous history found")
    }

    let mut prefix = prefix.clone();
    let mut config = config.clone();

    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);

                let mut args = line
                    .split_whitespace()
                    .map(str::to_string)
                    .collect::<Vec<String>>();

                if let Some(first) = line.trim_start().chars().next() {
                    if first == '~' {
                        println!("Command prefix is {:?}", prefix);
                        continue;
                    } else if first == '<' {
                        prefix = args[1..].into();
                        println!("Set command prefix to {:?}", prefix);
                        continue;
                    } else if first == '>' {
                        prefix.clear();
                        println!("Cleared command prefix");
                        continue;
                    } else if first == '?' {
                        args[0] = "help".into();
                    }
                };

                let args = [prefix.as_slice(), args.as_slice()].concat();
                match Line::clap().get_matches_from_safe(args) {
                    Ok(matches) => {
                        let Line { command } = Line::from_clap(&matches);
                        if let Err(error) = match command {
                            Command::Open(args) => open::cli::run(args).await,
                            Command::Convert(args) => convert::cli::run(args),
                            Command::Serve(args) => serve::cli::run(args, &config.serve).await,
                            Command::Plugins(args) => {
                                plugins::cli::run(args, &config.plugins, plugins_store).await
                            }
                            Command::Upgrade(args) => upgrade::cli::run(args, &config.upgrade),
                            Command::Config(args) => match config::cli::run(args, &config) {
                                Ok(config_changed) => {
                                    // Update the configuration (may have been changed by `set` and `reset`)
                                    config = config_changed;
                                    Ok(())
                                }
                                Err(err) => Err(err),
                            },
                        } {
                            print_error(error)
                        }
                    }
                    Err(error) => {
                        if error.kind == structopt::clap::ErrorKind::VersionDisplayed {
                            print!("{}", error)
                        } else if error.kind == structopt::clap::ErrorKind::HelpDisplayed
                            || error.kind == structopt::clap::ErrorKind::MissingArgumentOrSubcommand
                        {
                            // Remove the unnecessary command / version line at the start
                            let lines = format!("{}\n", error)
                                .to_string()
                                .lines()
                                .skip(1)
                                .map(str::to_string)
                                .collect::<Vec<String>>()
                                .join("\n");
                            print!("{}", lines)
                        } else {
                            tracing::debug!("{:?}", error.kind);
                            print_error(anyhow!(error))
                        }
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                tracing::info!("Ctrl-C pressed, interrupting current command");
                // TODO
            }
            Err(ReadlineError::Eof) => {
                tracing::info!("Ctrl-D pressed, ending session");
                break;
            }
            Err(error) => bail!(error),
        }
    }
    rl.save_history(&history_file)?;

    Ok(())
}

mod editor {
    use ansi_term::Colour::{Blue, White, Yellow};
    use rustyline::{
        completion::{Completer, FilenameCompleter, Pair},
        config::OutputStreamType,
        highlight::{Highlighter, MatchingBracketHighlighter},
        hint::{Hinter, HistoryHinter},
        validate::{MatchingBracketValidator, Validator},
        validate::{ValidationContext, ValidationResult},
        CompletionType, Context, EditMode, Editor, Result,
    };
    use rustyline_derive::Helper;
    use std::borrow::Cow::{self, Owned};

    pub fn new() -> Editor<Helper> {
        let config = rustyline::Config::builder()
            .history_ignore_space(true)
            .max_history_size(1000)
            .completion_type(CompletionType::List)
            .edit_mode(EditMode::Emacs)
            .output_stream(OutputStreamType::Stdout)
            .build();

        let mut editor = Editor::with_config(config);

        let helper = Helper::new();
        editor.set_helper(Some(helper));

        editor
    }

    #[derive(Helper)]
    pub struct Helper {
        pub completer: FilenameCompleter,
        pub hinter: HistoryHinter,
        pub validator: MatchingBracketValidator,
        pub highlighter: MatchingBracketHighlighter,
    }

    impl Helper {
        pub fn new() -> Self {
            Helper {
                completer: FilenameCompleter::new(),
                hinter: HistoryHinter {},
                validator: MatchingBracketValidator::new(),
                highlighter: MatchingBracketHighlighter::new(),
            }
        }
    }

    /// Provides tab-completion candidates
    ///
    /// https://github.com/kkawakam/rustyline/blob/master/src/completion.rs
    impl Completer for Helper {
        type Candidate = Pair;

        fn complete(
            &self,
            line: &str,
            pos: usize,
            ctx: &Context<'_>,
        ) -> Result<(usize, Vec<Self::Candidate>)> {
            self.completer.complete(line, pos, ctx)
        }
    }

    /// Provides hints based on the current line
    ///
    /// See https://github.com/kkawakam/rustyline/blob/master/src/hint.rs
    impl Hinter for Helper {
        type Hint = String;

        // Takes the currently edited line with the cursor position and returns the string that should be
        // displayed or None if no hint is available for the text the user currently typed
        fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<String> {
            self.hinter.hint(line, pos, ctx)
        }
    }

    /// Determines whether the current buffer is a valid command or should continue.
    ///
    /// Will not validate unless brackets (round, square and curly) are balanced.
    impl Validator for Helper {
        fn validate(&self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
            self.validator.validate(ctx)
        }

        fn validate_while_typing(&self) -> bool {
            self.validator.validate_while_typing()
        }
    }

    /// Syntax highlighter
    ///
    /// Highlights brackets, prompt, hints and completion candidates.
    /// See https://github.com/kkawakam/rustyline/blob/master/src/highlight.rs
    impl Highlighter for Helper {
        fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
            self.highlighter.highlight(line, pos)
        }

        fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
            &'s self,
            prompt: &'p str,
            _default: bool,
        ) -> Cow<'b, str> {
            Owned(Blue.paint(prompt).to_string())
        }

        fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
            Owned(White.dimmed().paint(hint).to_string())
        }

        fn highlight_candidate<'c>(
            &self,
            candidate: &'c str,
            _completion: CompletionType,
        ) -> Cow<'c, str> {
            Owned(Yellow.dimmed().paint(candidate).to_string())
        }

        fn highlight_char(&self, line: &str, pos: usize) -> bool {
            self.highlighter.highlight_char(line, pos)
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;

use utils::owning_iterator::{SeekingIterator, OwningIterator};

use index::boolean_index::boolean_query::*;
use index::boolean_index::posting::Posting;
use index::boolean_index::query_result_iterator::*;

pub struct NAryQueryIterator {
    pos_operator: Option<PositionalOperator>,
    bool_operator: Option<BooleanOperator>,
    operands: Vec<QueryResultIterator>,
    peeked_value: RefCell<Option<Option<*const Posting>>>,
}

impl<'a> OwningIterator<'a> for NAryQueryIterator {
    type Item = &'a Posting;

    fn next(&'a self) -> Option<Self::Item> {
        let mut peeked_value = self.peeked_value.borrow_mut();
        if peeked_value.is_some() {
            return unsafe { peeked_value.take().unwrap().map(|p| &*p) };
        }
        match self.bool_operator {
            Some(BooleanOperator::And) => self.next_and(),
            Some(BooleanOperator::Or) => self.next_or(),
            None => {
                match self.pos_operator {
                    Some(PositionalOperator::InOrder) => self.next_inorder(),
                    None => {
                        unreachable!(false);
                    }
                }
            }
        }
    }

    fn peek(&'a self) -> Option<&'a Posting> {
        let mut peeked_value = self.peeked_value.borrow_mut();
        if peeked_value.is_none() {
            *peeked_value = Some((match self.bool_operator {
                    Some(BooleanOperator::And) => self.next_and(),
                    Some(BooleanOperator::Or) => self.next_or(),
                    None => {
                        match self.pos_operator {
                            Some(PositionalOperator::InOrder) => self.next_inorder(),
                            None => {
                                unreachable!(false);
                            }
                        }
                    }
                })
                .map(|p| p as *const Posting))
        }
        unsafe { peeked_value.unwrap().map(|p| &*p) }
    }

    fn len(&self) -> usize {
        self.estimate_length()
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl<'a> SeekingIterator<'a> for NAryQueryIterator {
    type Item = &'a Posting;

    fn next_seek(&'a self, target: &Posting) -> Option<Self::Item> {
        {
            let mut peeked_value = self.peeked_value.borrow_mut();
            if peeked_value.is_some() {
                *peeked_value = None;
            }
            // Advance operands
            for op in self.operands.iter() {
                op.peek_seek(target);
            }
        }
        self.next()
    }

    fn peek_seek(&'a self, target: &Posting) -> Option<Self::Item> {
        let mut peeked_value = self.peeked_value.borrow_mut();
        if peeked_value.is_none() {
            *peeked_value = Some(self.next_seek(target).map(|p| p as *const Posting));
        }
        unsafe { peeked_value.unwrap().map(|p| &*p) }
    }
}

impl NAryQueryIterator {
    pub fn new_positional(operator: PositionalOperator, operands: Vec<QueryResultIterator>) -> NAryQueryIterator {
        let mut result = NAryQueryIterator {
            pos_operator: Some(operator),
            bool_operator: None,
            operands: operands,
            peeked_value: RefCell::new(None),
        };
        result.operands.sort_by_key(|op| op.estimate_length());
        result
    }

    pub fn new(operator: BooleanOperator, operands: Vec<QueryResultIterator>) -> NAryQueryIterator {
        let mut result = NAryQueryIterator {
            pos_operator: None,
            bool_operator: Some(operator),
            operands: operands,
            peeked_value: RefCell::new(None),
        };
        result.operands.sort_by_key(|op| op.estimate_length());
        result
    }

    pub fn estimate_length(&self) -> usize {
        match self.bool_operator {
            Some(BooleanOperator::And) => self.operands[0].estimate_length(),
            Some(BooleanOperator::Or) => self.operands[self.operands.len() - 1].estimate_length(),
            None => {
                match self.pos_operator {
                    Some(PositionalOperator::InOrder) => self.operands[0].estimate_length(),
                    None => {
                        unreachable!();
                    }
                }
            }
        }
    }

    fn next_inorder(&self) -> Option<&Posting> {
        let mut focus = None; //Acts as temporary to be compared against
        let mut focus_positions = vec![];
        // The iterator index that last set 'focus'
        let mut last_doc_iter = self.operands.len() + 1;
        // The the relative position of last_doc_iter
        let mut last_positions_iter = self.operands.len() + 1;
        'possible_documents: loop {
            // For every term
            for (i, input) in self.operands.iter().enumerate() {
                'term_documents: loop {
                    // If the focus was set by the current iterator, we have a match
                    if last_doc_iter == i {
                        break 'term_documents;
                    }
                    // Get the next doc_id for the current iterator
                    let mut v = try_option!(input.next());
                    if focus.is_none() {
                        focus = Some(v);
                        focus_positions = v.1.clone();
                        last_doc_iter = i;
                        last_positions_iter = input.relative_position();
                        break 'term_documents;
                    } else if v.0 < focus.unwrap().0 {
                        // If the doc_id is smaller, get its next value
                        continue 'term_documents;
                    } else if v.0 == focus.unwrap().0 {
                        // If the doc_id is equal, check positions
                        let position_offset = last_positions_iter as i64 - input.relative_position() as i64;
                        focus_positions = positional_intersect(&focus_positions,
                                                               &v.positions(),
                                                               (position_offset, position_offset))
                            .iter()
                            .map(|pos| pos.1)
                            .collect::<Vec<_>>();
                        if focus_positions.is_empty() {
                            // No suitable positions found. Next document
                            v = try_option!(input.next());
                            focus = Some(v);
                            focus_positions = v.1.clone();
                            last_doc_iter = i;
                            last_positions_iter = input.relative_position();
                            continue 'possible_documents;
                        } else {
                            last_positions_iter = input.relative_position();
                            break 'term_documents;
                        }
                    } else {
                        // If it is larger, we are now looking at a different focus.
                        // Reset focus and last_iter. Then start from the beginning
                        focus = Some(v);
                        focus_positions = v.1.clone();
                        last_doc_iter = i;
                        last_positions_iter = input.relative_position();
                        continue 'possible_documents;
                    }
                }
            }
            return focus;
        }
    }

    fn next_or(&self) -> Option<&Posting> {

        // Find the smallest current value of all operands
        let min_value = self.operands
            .iter()
            .map(|op| op.peek())
            .filter(|val| val.is_some())
            .map(|val| val.unwrap().0)
            .min();
        // If there is such a value
        if let Some(min) = min_value {
            let mut tmp = None;
            let mut i = 0;
            // Loop over all operands. Advance the ones which currently yield that minimal
            // value
            // Throw the ones out which are empty. Then return the minimal value as
            // reference
            while i < self.operands.len() {
                if let Some(val) = self.operands[i].peek() {
                    if val.0 == min {
                        tmp = self.operands[i].next();
                    }
                }
                i += 1;
            }
            return tmp;
        } else {
            return None;
        }
    }

    fn next_and(&self) -> Option<&Posting> {
        let mut focus = try_option!(self.operands[0].next()); //Acts as temporary to be compared against
        let mut last_iter = 0; //The iterator that last set 'focus'
        'possible_documents: loop {
            // For every term
            for (i, input) in self.operands.iter().enumerate() {
                // If the focus was set by the current iterator, we have a match
                // We cycled through all the iterators once
                if last_iter == i {
                    continue;
                }
                let v = try_option!(input.next_seek(focus));
                if v.0 > focus.0 {
                    // If it is larger, we are now looking at a different focus.
                    // Reset focus and last_iter. Then start from the beginning
                    focus = v;
                    last_iter = i;
                    continue 'possible_documents;
                }
            }
            return Some(focus);
        }
    }
}

pub fn positional_intersect(lhs: &[u32], rhs: &[u32], bounds: (i64, i64)) -> Vec<(u32, u32)> {

    // To understand this algorithm imagine a table.
    // The columns are headed with the values from the rhs slice
    // The rows start with the values from the lhs slice
    // The value in each cell is its row value minus its column value
    // Example:

    // |   | 0 |  4 |  5 |  7 |
    // | 1 | 1 | -3 | -4 | -6 |
    // | 3 | 3 | -1 | -2 | -4 |
    // | 4 | 4 |  0 | -1 | -3 |
    // | 8 | 8 |  4 |  3 |  1 |

    // As both rhs and lhs are sorted we can assume two things:
    // 1. if we "go down" the result of the substraction is going to grow
    // 2. if we "go right" the result of the substraction is going to shrink

    // This algorithm walks through this table. If a difference is to great it will
    // "go right"
    // Otherwise it will go down.
    // If a difference is inside the bounds it will check
    // to the left and to the right for adjacent matches

    let mut result = Vec::new();

    let mut lhs_ptr = 0;
    let mut rhs_ptr = 0;

    while lhs_ptr < lhs.len() && rhs_ptr < rhs.len() {
        let (lval, rval) = (lhs[lhs_ptr] as i64, rhs[rhs_ptr] as i64);
        let diff = lval - rval;
        if diff >= bounds.0 && diff <= bounds.1 {
            result.push((lhs[lhs_ptr], rhs[rhs_ptr]));

            // check "downwards"
            let mut d = lhs_ptr + 1;
            while d < lhs.len() && lhs[d] as i64 - rval <= bounds.1 {
                result.push((lhs[d], rhs[rhs_ptr]));
                d += 1;
            }

            // check "right"
            let mut r = rhs_ptr + 1;
            while r < rhs.len() && lval - rhs[r] as i64 >= bounds.0 {
                result.push((lhs[lhs_ptr], rhs[r]));
                r += 1;
            }

            rhs_ptr += 1;
            lhs_ptr += 1;
            continue;
        }
        if diff >= bounds.1 {
            rhs_ptr += 1;
        }
        if diff <= bounds.0 {
            lhs_ptr += 1;
        }
    }
    result
}
<commit_msg>use next_seek in next_inorder<commit_after>use std::cell::RefCell;

use utils::owning_iterator::{SeekingIterator, OwningIterator};

use index::boolean_index::boolean_query::*;
use index::boolean_index::posting::Posting;
use index::boolean_index::query_result_iterator::*;

pub struct NAryQueryIterator {
    pos_operator: Option<PositionalOperator>,
    bool_operator: Option<BooleanOperator>,
    operands: Vec<QueryResultIterator>,
    peeked_value: RefCell<Option<Option<*const Posting>>>,
}

impl<'a> OwningIterator<'a> for NAryQueryIterator {
    type Item = &'a Posting;

    fn next(&'a self) -> Option<Self::Item> {
        let mut peeked_value = self.peeked_value.borrow_mut();
        if peeked_value.is_some() {
            return unsafe { peeked_value.take().unwrap().map(|p| &*p) };
        }
        match self.bool_operator {
            Some(BooleanOperator::And) => self.next_and(),
            Some(BooleanOperator::Or) => self.next_or(),
            None => {
                match self.pos_operator {
                    Some(PositionalOperator::InOrder) => self.next_inorder(),
                    None => {
                        unreachable!(false);
                    }
                }
            }
        }
    }

    fn peek(&'a self) -> Option<&'a Posting> {
        let mut peeked_value = self.peeked_value.borrow_mut();
        if peeked_value.is_none() {
            *peeked_value = Some((match self.bool_operator {
                    Some(BooleanOperator::And) => self.next_and(),
                    Some(BooleanOperator::Or) => self.next_or(),
                    None => {
                        match self.pos_operator {
                            Some(PositionalOperator::InOrder) => self.next_inorder(),
                            None => {
                                unreachable!(false);
                            }
                        }
                    }
                })
                .map(|p| p as *const Posting))
        }
        unsafe { peeked_value.unwrap().map(|p| &*p) }
    }

    fn len(&self) -> usize {
        self.estimate_length()
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl<'a> SeekingIterator<'a> for NAryQueryIterator {
    type Item = &'a Posting;

    fn next_seek(&'a self, target: &Posting) -> Option<Self::Item> {
        {
            let mut peeked_value = self.peeked_value.borrow_mut();
            if peeked_value.is_some() {
                *peeked_value = None;
            }
            // Advance operands
            for op in self.operands.iter() {
                op.peek_seek(target);
            }
        }
        self.next()
    }

    fn peek_seek(&'a self, target: &Posting) -> Option<Self::Item> {
        let mut peeked_value = self.peeked_value.borrow_mut();
        if peeked_value.is_none() {
            *peeked_value = Some(self.next_seek(target).map(|p| p as *const Posting));
        }
        unsafe { peeked_value.unwrap().map(|p| &*p) }
    }
}

impl NAryQueryIterator {
    pub fn new_positional(operator: PositionalOperator, operands: Vec<QueryResultIterator>) -> NAryQueryIterator {
        let mut result = NAryQueryIterator {
            pos_operator: Some(operator),
            bool_operator: None,
            operands: operands,
            peeked_value: RefCell::new(None),
        };
        result.operands.sort_by_key(|op| op.estimate_length());
        result
    }

    pub fn new(operator: BooleanOperator, operands: Vec<QueryResultIterator>) -> NAryQueryIterator {
        let mut result = NAryQueryIterator {
            pos_operator: None,
            bool_operator: Some(operator),
            operands: operands,
            peeked_value: RefCell::new(None),
        };
        result.operands.sort_by_key(|op| op.estimate_length());
        result
    }

    pub fn estimate_length(&self) -> usize {
        match self.bool_operator {
            Some(BooleanOperator::And) => self.operands[0].estimate_length(),
            Some(BooleanOperator::Or) => self.operands[self.operands.len() - 1].estimate_length(),
            None => {
                match self.pos_operator {
                    Some(PositionalOperator::InOrder) => self.operands[0].estimate_length(),
                    None => {
                        unreachable!();
                    }
                }
            }
        }
    }

    fn next_inorder(&self) -> Option<&Posting> {
        let mut focus = try_option!(self.operands[0].next()); //Acts as temporary to be compared against
        let mut focus_positions = focus.positions().clone();
        // The iterator index that last set 'focus'
        let mut last_doc_iter = 0;
        // The relative position of last_doc_iter
        let mut last_positions_iter = self.operands[0].relative_position();;
        'possible_documents: loop {
            // For every term
            for (i, input) in self.operands.iter().enumerate() {
                // If the focus was set by the current iterator, we have a match
                if last_doc_iter == i {
                    continue;
                }
                // Get the next doc_id >= focus for the current iterator
                let mut v = try_option!(input.next_seek(focus));
                if v.0 == focus.0 {
                    // If the doc_id is equal, check positions
                    let position_offset = last_positions_iter as i64 - input.relative_position() as i64;
                    focus_positions = positional_intersect(&focus_positions,
                                                           &v.positions(),
                                                           (position_offset, position_offset))
                        .iter()
                        .map(|pos| pos.1)
                        .collect::<Vec<_>>();
                    last_positions_iter = input.relative_position();
                    if focus_positions.is_empty() {
                        // No suitable positions found. Next document
                        v = try_option!(input.next());
                    } else {
                        continue;
                    }
                }
                // If it is larger or no positions matched, we are now looking at a different focus.
                // Reset focus and last_iter. Then start from the beginning
                focus = v;
                focus_positions = v.positions().clone();
                last_doc_iter = i;
                last_positions_iter = input.relative_position();
                continue 'possible_documents;
            }
            return Some(focus);
        }
    }

    fn next_or(&self) -> Option<&Posting> {

        // Find the smallest current value of all operands
        let min_value = self.operands
            .iter()
            .map(|op| op.peek())
            .filter(|val| val.is_some())
            .map(|val| val.unwrap().0)
            .min();
        // If there is such a value
        if let Some(min) = min_value {
            let mut tmp = None;
            let mut i = 0;
            // Loop over all operands. Advance the ones which currently yield that minimal
            // value
            // Throw the ones out which are empty. Then return the minimal value as
            // reference
            while i < self.operands.len() {
                if let Some(val) = self.operands[i].peek() {
                    if val.0 == min {
                        tmp = self.operands[i].next();
                    }
                }
                i += 1;
            }
            return tmp;
        } else {
            return None;
        }
    }

    fn next_and(&self) -> Option<&Posting> {
        let mut focus = try_option!(self.operands[0].next()); //Acts as temporary to be compared against
        let mut last_iter = 0; //The iterator that last set 'focus'
        'possible_documents: loop {
            // For every term
            for (i, input) in self.operands.iter().enumerate() {
                // If the focus was set by the current iterator, we have a match
                // We cycled through all the iterators once
                if last_iter == i {
                    continue;
                }
                let v = try_option!(input.next_seek(focus));
                if v.0 > focus.0 {
                    // If it is larger, we are now looking at a different focus.
                    // Reset focus and last_iter. Then start from the beginning
                    focus = v;
                    last_iter = i;
                    continue 'possible_documents;
                }
            }
            return Some(focus);
        }
    }
}

pub fn positional_intersect(lhs: &[u32], rhs: &[u32], bounds: (i64, i64)) -> Vec<(u32, u32)> {

    // To understand this algorithm imagine a table.
    // The columns are headed with the values from the rhs slice
    // The rows start with the values from the lhs slice
    // The value in each cell is its row value minus its column value
    // Example:

    // |   | 0 |  4 |  5 |  7 |
    // | 1 | 1 | -3 | -4 | -6 |
    // | 3 | 3 | -1 | -2 | -4 |
    // | 4 | 4 |  0 | -1 | -3 |
    // | 8 | 8 |  4 |  3 |  1 |

    // As both rhs and lhs are sorted we can assume two things:
    // 1. if we "go down" the result of the substraction is going to grow
    // 2. if we "go right" the result of the substraction is going to shrink

    // This algorithm walks through this table. If a difference is to great it will
    // "go right"
    // Otherwise it will go down.
    // If a difference is inside the bounds it will check
    // to the left and to the right for adjacent matches

    let mut result = Vec::new();

    let mut lhs_ptr = 0;
    let mut rhs_ptr = 0;

    while lhs_ptr < lhs.len() && rhs_ptr < rhs.len() {
        let (lval, rval) = (lhs[lhs_ptr] as i64, rhs[rhs_ptr] as i64);
        let diff = lval - rval;
        if diff >= bounds.0 && diff <= bounds.1 {
            result.push((lhs[lhs_ptr], rhs[rhs_ptr]));

            // check "downwards"
            let mut d = lhs_ptr + 1;
            while d < lhs.len() && lhs[d] as i64 - rval <= bounds.1 {
                result.push((lhs[d], rhs[rhs_ptr]));
                d += 1;
            }

            // check "right"
            let mut r = rhs_ptr + 1;
            while r < rhs.len() && lval - rhs[r] as i64 >= bounds.0 {
                result.push((lhs[lhs_ptr], rhs[r]));
                r += 1;
            }

            rhs_ptr += 1;
            lhs_ptr += 1;
            continue;
        }
        if diff >= bounds.1 {
            rhs_ptr += 1;
        }
        if diff <= bounds.0 {
            lhs_ptr += 1;
        }
    }
    result
}
<|endoftext|>


<commit_before>use std::iter;
use std::fmt::{self, Debug};
use std::cmp::{Eq, PartialEq};
use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point, WlcOutput};
use rustwlc::render::{write_pixels, wlc_pixel_format};
use cairo::{Context, ImageSurface, Format, Operator, Status, SolidPattern};
use cairo::prelude::{SurfaceExt};

use super::super::borders::Borders;
use super::base::{BaseDraw, Drawable, DrawErr};
use super::color::Color;

/// Draws the borders with variable width.
///
/// This can be used to hide certain borders,
/// eg when touching the side of the screen.
pub struct EdgeDraw {
    base: BaseDraw,
    color: Color
}

impl EdgeDraw {
    pub fn new(base: BaseDraw, color: Color) -> Self {
        EdgeDraw {
            base: base,
            color: color
        }
    }

    fn draw_left_border(mut self,
                        mut x: f64,
                        mut y: f64,
                        mut w: f64,
                        mut h: f64,
                        border_geometry: Geometry,
                        output_res: Size)
                        -> Result<Self, DrawErr> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        x = 0.0;
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32{
            let offset = (border_geometry.origin.x as u32 + border_geometry.size.w) - output_res.w;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y as u32 + border_geometry.size.h) - output_res.h;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_right_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         mut w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size)
                         -> Result<Self, DrawErr> {
        // yay clamping
        if border_geometry.origin.x < 0 {
            x += border_geometry.origin.x as f64;
        }
        if y < 0.0 {
            h += y;
        }
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x as u32 + border_geometry.size.w) - output_res.w;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y as u32 + border_geometry.size.h) - output_res.h;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_top_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         mut w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size)
                         -> Result<Self, DrawErr> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        x = 0.0;
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x as u32 + border_geometry.size.w) - output_res.w;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y as u32 + border_geometry.size.h) - output_res.h;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_bottom_border(mut self,
                            mut x: f64,
                            mut y: f64,
                            mut w: f64,
                            mut h: f64,
                            border_geometry: Geometry,
                            output_res: Size)
                            -> Result<Self, DrawErr> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if border_geometry.origin.y < 0 {
            y += border_geometry.origin.y as f64;
        }
        x = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x as u32 + border_geometry.size.w) - output_res.w;
            x += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }
}

impl Drawable for EdgeDraw {
    fn draw(mut self, view_g: Geometry) -> Result<Borders, DrawErr> {
        let mut border_g = view_g;
        let thickness = self.base.borders().thickness;
        let edge_thickness = thickness / 2;
        // TODO This doesn't seem right, wouldn't this break on multi-head output?
        let output_res = WlcOutput::focused().get_resolution()
            .expect("Could not get focused output's resolution");
        // Even though we ignore these origin values,
        // the renderer needs to know where to start drawing the box.
        border_g.origin.x -= edge_thickness as i32;
        border_g.origin.y -= edge_thickness as i32;
        border_g.size.w += thickness;
        border_g.size.h += thickness;

        self.base.set_source_rgba(0.0, 0.0, 0.0, 0.0);
        self.base.paint();
        self.base.set_color_source(self.color);

        let Size { w, h } = border_g.size;
        let Point { x, y } = border_g.origin;
        // basically after everything after this point is floating point arithmetic
        // whee!
        let (x, y, w, h) = (x as f64,
                            y as f64,
                            w as f64,
                            h as f64);
        let edge_thickness = edge_thickness as f64;
        self = self.draw_left_border(x, y, edge_thickness, h, border_g, output_res)?
        .draw_right_border(w - edge_thickness, y, edge_thickness, h, border_g, output_res)?
        .draw_top_border(x, y, w, edge_thickness, border_g, output_res)?
        .draw_bottom_border(x, h, w, -edge_thickness, border_g, output_res)?;

        Ok(self.base.finish(border_g))
    }
}
<commit_msg>Removed possible overflow in border calculation<commit_after>use std::iter;
use std::fmt::{self, Debug};
use std::cmp::{Eq, PartialEq};
use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point, WlcOutput};
use rustwlc::render::{write_pixels, wlc_pixel_format};
use cairo::{Context, ImageSurface, Format, Operator, Status, SolidPattern};
use cairo::prelude::{SurfaceExt};

use super::super::borders::Borders;
use super::base::{BaseDraw, Drawable, DrawErr};
use super::color::Color;

/// Draws the borders with variable width.
///
/// This can be used to hide certain borders,
/// eg when touching the side of the screen.
pub struct EdgeDraw {
    base: BaseDraw,
    color: Color
}

impl EdgeDraw {
    pub fn new(base: BaseDraw, color: Color) -> Self {
        EdgeDraw {
            base: base,
            color: color
        }
    }

    fn draw_left_border(mut self,
                        mut x: f64,
                        mut y: f64,
                        mut w: f64,
                        mut h: f64,
                        border_geometry: Geometry,
                        output_res: Size)
                        -> Result<Self, DrawErr> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        x = 0.0;
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32{
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32) - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32) - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_right_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         mut w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size)
                         -> Result<Self, DrawErr> {
        // yay clamping
        if border_geometry.origin.x < 0 {
            x += border_geometry.origin.x as f64;
        }
        if y < 0.0 {
            h += y;
        }
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32) - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32) - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_top_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         mut w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size)
                         -> Result<Self, DrawErr> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        x = 0.0;
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32) - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32) - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_bottom_border(mut self,
                            mut x: f64,
                            mut y: f64,
                            mut w: f64,
                            mut h: f64,
                            border_geometry: Geometry,
                            output_res: Size)
                            -> Result<Self, DrawErr> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if border_geometry.origin.y < 0 {
            y += border_geometry.origin.y as f64;
        }
        x = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32) - output_res.w as i32;
            x += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }
}

impl Drawable for EdgeDraw {
    fn draw(mut self, view_g: Geometry) -> Result<Borders, DrawErr> {
        let mut border_g = view_g;
        let thickness = self.base.borders().thickness;
        let edge_thickness = thickness / 2;
        // TODO This doesn't seem right, wouldn't this break on multi-head output?
        let output_res = WlcOutput::focused().get_resolution()
            .expect("Could not get focused output's resolution");
        // Even though we ignore these origin values,
        // the renderer needs to know where to start drawing the box.
        border_g.origin.x -= edge_thickness as i32;
        border_g.origin.y -= edge_thickness as i32;
        border_g.size.w += thickness;
        border_g.size.h += thickness;
        warn!("Drawing EdgeDraw @ {:#?}", border_g);

        self.base.set_source_rgba(0.0, 0.0, 0.0, 0.0);
        self.base.paint();
        self.base.set_color_source(self.color);

        let Size { w, h } = border_g.size;
        let Point { x, y } = border_g.origin;
        // basically after everything after this point is floating point arithmetic
        // whee!
        let (x, y, w, h) = (x as f64,
                            y as f64,
                            w as f64,
                            h as f64);
        let edge_thickness = edge_thickness as f64;
        self = self.draw_left_border(x, y, edge_thickness, h, border_g, output_res)?
        .draw_right_border(w - edge_thickness, y, edge_thickness, h, border_g, output_res)?
        .draw_top_border(x, y, w, edge_thickness, border_g, output_res)?
        .draw_bottom_border(x, h, w, -edge_thickness, border_g, output_res)?;

        Ok(self.base.finish(border_g))
    }
}
<|endoftext|>


<commit_before>use uniforms::{Uniforms, UniformValue, AsUniformValue};

/// Object that can be used when you don't have any uniforms.
#[derive(Debug, Copy, Clone)]
pub struct EmptyUniforms;

impl Uniforms for EmptyUniforms {
    #[inline]
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, _: F) {
    }
}

/// Stores uniforms.
pub struct UniformsStorage<'n, T, R> where T: AsUniformValue, R: Uniforms {
    name: &'n str,
    value: T,
    rest: R,
}

impl<'n, T> UniformsStorage<'n, T, EmptyUniforms> where T: AsUniformValue {
    /// Builds a new storage with a value.
    #[inline]
    pub fn new(name: &'n str, value: T)
               -> UniformsStorage<'n, T, EmptyUniforms>
    {
        UniformsStorage {
            name: name,
            value: value,
            rest: EmptyUniforms,
        }
    }
}

impl<'n, T, R> UniformsStorage<'n, T, R> where T: AsUniformValue, R: Uniforms {
    /// Adds a value to the storage.
    #[inline]
    pub fn add<U>(self, name: &'n str, value: U)
                  -> UniformsStorage<'n, U, UniformsStorage<'n, T, R>>
                  where U: AsUniformValue
    {
        UniformsStorage {
            name: name,
            value: value,
            rest: self,
        }
    }
}

impl<'n, T, R> Uniforms for UniformsStorage<'n, T, R> where T: AsUniformValue, R: Uniforms {
    #[inline]
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, mut output: F) {
        output(self.name, self.value.as_uniform_value());
        self.rest.visit_values(output);
    }
}
<commit_msg>Made UniformStorage implement Copy/Clone<commit_after>use uniforms::{Uniforms, UniformValue, AsUniformValue};

/// Object that can be used when you don't have any uniforms.
#[derive(Debug, Copy, Clone)]
pub struct EmptyUniforms;

impl Uniforms for EmptyUniforms {
    #[inline]
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, _: F) {
    }
}

/// Stores uniforms.
#[derive(Copy, Clone)]
pub struct UniformsStorage<'n, T, R> where T: AsUniformValue, R: Uniforms {
    name: &'n str,
    value: T,
    rest: R,
}

impl<'n, T> UniformsStorage<'n, T, EmptyUniforms> where T: AsUniformValue {
    /// Builds a new storage with a value.
    #[inline]
    pub fn new(name: &'n str, value: T)
               -> UniformsStorage<'n, T, EmptyUniforms>
    {
        UniformsStorage {
            name: name,
            value: value,
            rest: EmptyUniforms,
        }
    }
}

impl<'n, T, R> UniformsStorage<'n, T, R> where T: AsUniformValue, R: Uniforms {
    /// Adds a value to the storage.
    #[inline]
    pub fn add<U>(self, name: &'n str, value: U)
                  -> UniformsStorage<'n, U, UniformsStorage<'n, T, R>>
                  where U: AsUniformValue
    {
        UniformsStorage {
            name: name,
            value: value,
            rest: self,
        }
    }
}

impl<'n, T, R> Uniforms for UniformsStorage<'n, T, R> where T: AsUniformValue, R: Uniforms {
    #[inline]
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, mut output: F) {
        output(self.name, self.value.as_uniform_value());
        self.rest.visit_values(output);
    }
}
<|endoftext|>