<commit_before>
use std::rc::Rc;
use syn::*;

use ast_converters::*;
use tyhandlers::{TypeContext, TypeHandler, get_ty_handler};
use returnhandlers::{ReturnHandler, get_return_handler};
use utils;

#[derive(Debug, PartialEq)]
pub enum ComMethodInfoError {
    TooFewArguments,
    BadSelfArg,
    BadArg(Box<FnArg>),
    BadReturnType,
}

#[derive(Clone)]
pub struct RustArg {
    pub name: Ident,
    pub ty: Type,
    pub handler: Rc<TypeHandler>,
}

impl PartialEq for RustArg {

    fn eq(&self, other: &RustArg) -> bool
    {
        self.name == other.name
            && self.ty == other.ty
    }
}

impl ::std::fmt::Debug for RustArg {
    fn fmt( &self, f: &mut ::std::fmt::Formatter ) -> ::std::fmt::Result {
        write!( f, "{}: {:?}", self.name, self.ty )
    }
}

impl RustArg {

    pub fn new( name: Ident, ty: Type ) -> RustArg {

        let tyhandler = get_ty_handler( &ty, TypeContext::input() );
        RustArg {
            name,
            ty,
            handler: tyhandler,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Direction { In, Out, Retval }

pub struct ComArg {
    pub name: Ident,
    pub ty: Type,
    pub handler: Rc<TypeHandler>,
    pub dir : Direction
}

impl ComArg {

    pub fn new( name: Ident, ty: Type, dir: Direction ) -> ComArg {

        let tyhandler = get_ty_handler( &ty, TypeContext::input() );
        ComArg {
            name,
            ty,
            dir,
            handler: tyhandler,
        }
    }

    pub fn from_rustarg( rustarg: RustArg, dir: Direction ) -> ComArg {

        let tyhandler = get_ty_handler( &rustarg.ty, TypeContext::new( dir ) );
        ComArg {
            name: rustarg.name,
            ty: rustarg.ty,
            dir,
            handler: tyhandler,
        }
    }
}

impl PartialEq for ComArg {

    fn eq(&self, other: &ComArg) -> bool
    {
        self.name == other.name
            && self.ty == other.ty
            && self.dir == other.dir
    }
}

impl ::std::fmt::Debug for ComArg {
    fn fmt( &self, f: &mut ::std::fmt::Formatter ) -> ::std::fmt::Result {
        write!( f, "{}: {:?} {:?}", self.name, self.dir, self.ty )
    }
}

#[derive(Debug)]
pub struct ComMethodInfo {

    pub name: Ident,

    pub is_const: bool,
    pub rust_self_arg: ArgSelfRef,
    pub rust_return_ty: Type,

    pub retval_type: Option<Type>,
    pub return_type: Option<Type>,

    pub returnhandler: Box<ReturnHandler>,
    pub args: Vec<RustArg>,

    pub is_unsafe: bool,
}

impl PartialEq for ComMethodInfo {

    fn eq(&self, other: &ComMethodInfo) -> bool
    {
        self.name == other.name
            && self.is_const == other.is_const
            && self.rust_self_arg == other.rust_self_arg
            && self.rust_return_ty == other.rust_return_ty
            && self.retval_type == other.retval_type
            && self.return_type == other.return_type
            && self.args == other.args
    }
}

impl ComMethodInfo {

    /// Constructs new COM method info from a Rust method signature.
    pub fn new(
        m : &MethodSig
    ) -> Result<ComMethodInfo, ComMethodInfoError>
    {
        Self::new_from_parts( m.ident, &m.decl, m.unsafety.is_some() )
    }

    pub fn new_from_parts(
        n: Ident,
        decl: &FnDecl,
        unsafety: bool,
    ) -> Result<ComMethodInfo, ComMethodInfoError>
    {
        // Process all the function arguments.
        // In Rust this includes the 'self' argument and the actual function
        // arguments. For COM the self is implicit so we'll handle it
        // separately.
        let mut iter = decl.inputs.iter();
        let rust_self_arg = iter.next()
                .ok_or_else( || ComMethodInfoError::TooFewArguments )?;

        let ( is_const, rust_self_arg ) = match *rust_self_arg {
            FnArg::SelfRef( ref self_arg ) => (
                self_arg.mutability.is_none(),
                self_arg.clone()
            ),
            _ => return Err( ComMethodInfoError::BadSelfArg ),
        } ;

        // Process other arguments.
        let args = iter.map( | arg | {
            let ty = arg.get_ty()
                .or_else( |_| Err(
                    ComMethodInfoError::BadArg( Box::new( arg.clone() ) )
                ) )?;
            let ident = arg.get_ident()
                .or_else( |_| Err(
                    ComMethodInfoError::BadArg( Box::new( arg.clone() ) )
                ) )?;

            Ok( RustArg::new( ident, ty ) )
        } ).collect::<Result<_,_>>()?;

        // Get the output.
        let rust_return_ty = match decl.output {
            ReturnType::Default => parse_quote!( () ),
            ReturnType::Type( _, ref ty ) => (**ty).clone(),
        };

        // Resolve the return type and retval type.
        let ( retval_type, return_type ) = if utils::is_unit( &rust_return_ty ) {
            ( None, None )
        } else if let Some( ( retval, ret ) ) = try_parse_result( &rust_return_ty ) {
            ( Some( retval ), Some( ret ) )
        } else {
            ( None, Some( rust_return_ty.clone() ) )
        };

        let returnhandler = get_return_handler( &retval_type, &return_type )
                .or( Err( ComMethodInfoError::BadReturnType ) )?;
        Ok( ComMethodInfo {
            name: n,
            is_const,
            rust_self_arg,
            rust_return_ty,
            retval_type,
            return_type,
            returnhandler,
            args,
            is_unsafe: unsafety,
        } )
    }

    pub fn raw_com_args( &self ) -> Vec<ComArg>
    {
        let in_args = self.args
                .iter()
                .map( |ca| {
                    ComArg::from_rustarg( ca.clone(), Direction::In )
                } );
        let out_args = self.returnhandler.com_out_args();

        in_args.chain( out_args ).collect()
    }
}

fn try_parse_result( ty : &Type ) -> Option<( Type, Type )>
{
    let path = match *ty {
        Type::Path( ref p ) => &p.path,
        _ => return None,
    };

    // Ensure the type name contains 'Result'. We don't really have
    // good ways to ensure it is an actual Result type but at least we can
    // use this to discount things like Option<>, etc.
    let last_segment = path.segments.last()?;
    if ! last_segment.value().ident.to_string().contains( "Result" ) {
        return None;
    }

    // Ensure the Result has angle bracket arguments.
    if let PathArguments::AngleBracketed( ref data )
            = last_segment.value().arguments {

        // The returned types depend on how many arguments the Result has.
        return Some( match data.args.len() {
            1 => ( data.args[ 0 ].get_ty().ok()?, hresult_ty() ),
            2 => ( data.args[ 0 ].get_ty().ok()?, data.args[ 1 ].get_ty().ok()? ),
            _ => return None,
        } )
    }

    // We couldn't find a valid type. Return nothing.
    None
}

fn hresult_ty() -> Type {
    parse_quote!( ::intercom::HRESULT )
}

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

    #[test]
    fn no_args_or_return_value() {

        let info = test_info( "fn foo( &self ) {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.args.len(), 0 );
        assert_eq!( info.retval_type.is_none(), true );
        assert_eq!( info.return_type.is_none(), true );
    }

    #[test]
    fn basic_return_value() {

        let info = test_info( "fn foo( &self ) -> bool {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.args.len(), 0 );
        assert_eq!( info.retval_type.is_none(), true );
        assert_eq!(
                info.return_type,
                Some( parse_quote!( bool ) ) );
    }

    #[test]
    fn result_return_value() {

        let info = test_info( "fn foo( &self ) -> Result<String, f32> {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.args.len(), 0 );
        assert_eq!(
                info.retval_type,
                Some( parse_quote!( String ) ) );
        assert_eq!(
                info.return_type,
                Some( parse_quote!( f32 ) ) );
    }

    #[test]
    fn comresult_return_value() {

        let info = test_info( "fn foo( &self ) -> ComResult<String> {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.args.len(), 0 );
        assert_eq!(
                info.retval_type,
                Some( parse_quote!( String ) ) );
        assert_eq!(
                info.return_type,
                Some( parse_quote!( ::intercom::HRESULT ) ) );
    }

    #[test]
    fn basic_arguments() {

        let info = test_info( "fn foo( &self, a : u32, b : f32 ) {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.retval_type.is_none(), true );
        assert_eq!( info.return_type.is_none(), true );

        assert_eq!( info.args.len(), 2 );

        assert_eq!( info.args[0].name, Ident::from( "a" ) );
        assert_eq!( info.args[0].ty, parse_quote!( u32 ) );

        assert_eq!( info.args[1].name, Ident::from( "b" ) );
        assert_eq!( info.args[1].ty, parse_quote!( f32 ) );
    }

    fn test_info( code : &str ) -> ComMethodInfo {

        let item = parse_str( code ).unwrap();
        let ( ident, decl, unsafety ) = match item {
            Item::Fn( ref f ) => ( f.ident, f.decl.as_ref(), f.unsafety.is_some() ),
            _ => panic!( "Code isn't function" ),
        };
        ComMethodInfo::new_from_parts( ident, decl, unsafety ).unwrap()
    }
}
<commit_msg>Fix ComArg type context direction<commit_after>
use std::rc::Rc;
use syn::*;

use ast_converters::*;
use tyhandlers::{TypeContext, TypeHandler, get_ty_handler};
use returnhandlers::{ReturnHandler, get_return_handler};
use utils;

#[derive(Debug, PartialEq)]
pub enum ComMethodInfoError {
    TooFewArguments,
    BadSelfArg,
    BadArg(Box<FnArg>),
    BadReturnType,
}

#[derive(Clone)]
pub struct RustArg {
    pub name: Ident,
    pub ty: Type,
    pub handler: Rc<TypeHandler>,
}

impl PartialEq for RustArg {

    fn eq(&self, other: &RustArg) -> bool
    {
        self.name == other.name
            && self.ty == other.ty
    }
}

impl ::std::fmt::Debug for RustArg {
    fn fmt( &self, f: &mut ::std::fmt::Formatter ) -> ::std::fmt::Result {
        write!( f, "{}: {:?}", self.name, self.ty )
    }
}

impl RustArg {

    pub fn new( name: Ident, ty: Type ) -> RustArg {

        let tyhandler = get_ty_handler( &ty, TypeContext::input() );
        RustArg {
            name,
            ty,
            handler: tyhandler,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Direction { In, Out, Retval }

pub struct ComArg {
    pub name: Ident,
    pub ty: Type,
    pub handler: Rc<TypeHandler>,
    pub dir : Direction
}

impl ComArg {

    pub fn new( name: Ident, ty: Type, dir: Direction ) -> ComArg {

        let tyhandler = get_ty_handler( &ty, TypeContext::new( dir ) );
        ComArg {
            name,
            ty,
            dir,
            handler: tyhandler,
        }
    }

    pub fn from_rustarg( rustarg: RustArg, dir: Direction ) -> ComArg {

        let tyhandler = get_ty_handler( &rustarg.ty, TypeContext::new( dir ) );
        ComArg {
            name: rustarg.name,
            ty: rustarg.ty,
            dir,
            handler: tyhandler,
        }
    }
}

impl PartialEq for ComArg {

    fn eq(&self, other: &ComArg) -> bool
    {
        self.name == other.name
            && self.ty == other.ty
            && self.dir == other.dir
    }
}

impl ::std::fmt::Debug for ComArg {
    fn fmt( &self, f: &mut ::std::fmt::Formatter ) -> ::std::fmt::Result {
        write!( f, "{}: {:?} {:?}", self.name, self.dir, self.ty )
    }
}

#[derive(Debug)]
pub struct ComMethodInfo {

    pub name: Ident,

    pub is_const: bool,
    pub rust_self_arg: ArgSelfRef,
    pub rust_return_ty: Type,

    pub retval_type: Option<Type>,
    pub return_type: Option<Type>,

    pub returnhandler: Box<ReturnHandler>,
    pub args: Vec<RustArg>,

    pub is_unsafe: bool,
}

impl PartialEq for ComMethodInfo {

    fn eq(&self, other: &ComMethodInfo) -> bool
    {
        self.name == other.name
            && self.is_const == other.is_const
            && self.rust_self_arg == other.rust_self_arg
            && self.rust_return_ty == other.rust_return_ty
            && self.retval_type == other.retval_type
            && self.return_type == other.return_type
            && self.args == other.args
    }
}

impl ComMethodInfo {

    /// Constructs new COM method info from a Rust method signature.
    pub fn new(
        m : &MethodSig
    ) -> Result<ComMethodInfo, ComMethodInfoError>
    {
        Self::new_from_parts( m.ident, &m.decl, m.unsafety.is_some() )
    }

    pub fn new_from_parts(
        n: Ident,
        decl: &FnDecl,
        unsafety: bool,
    ) -> Result<ComMethodInfo, ComMethodInfoError>
    {
        // Process all the function arguments.
        // In Rust this includes the 'self' argument and the actual function
        // arguments. For COM the self is implicit so we'll handle it
        // separately.
        let mut iter = decl.inputs.iter();
        let rust_self_arg = iter.next()
                .ok_or_else( || ComMethodInfoError::TooFewArguments )?;

        let ( is_const, rust_self_arg ) = match *rust_self_arg {
            FnArg::SelfRef( ref self_arg ) => (
                self_arg.mutability.is_none(),
                self_arg.clone()
            ),
            _ => return Err( ComMethodInfoError::BadSelfArg ),
        } ;

        // Process other arguments.
        let args = iter.map( | arg | {
            let ty = arg.get_ty()
                .or_else( |_| Err(
                    ComMethodInfoError::BadArg( Box::new( arg.clone() ) )
                ) )?;
            let ident = arg.get_ident()
                .or_else( |_| Err(
                    ComMethodInfoError::BadArg( Box::new( arg.clone() ) )
                ) )?;

            Ok( RustArg::new( ident, ty ) )
        } ).collect::<Result<_,_>>()?;

        // Get the output.
        let rust_return_ty = match decl.output {
            ReturnType::Default => parse_quote!( () ),
            ReturnType::Type( _, ref ty ) => (**ty).clone(),
        };

        // Resolve the return type and retval type.
        let ( retval_type, return_type ) = if utils::is_unit( &rust_return_ty ) {
            ( None, None )
        } else if let Some( ( retval, ret ) ) = try_parse_result( &rust_return_ty ) {
            ( Some( retval ), Some( ret ) )
        } else {
            ( None, Some( rust_return_ty.clone() ) )
        };

        let returnhandler = get_return_handler( &retval_type, &return_type )
                .or( Err( ComMethodInfoError::BadReturnType ) )?;
        Ok( ComMethodInfo {
            name: n,
            is_const,
            rust_self_arg,
            rust_return_ty,
            retval_type,
            return_type,
            returnhandler,
            args,
            is_unsafe: unsafety,
        } )
    }

    pub fn raw_com_args( &self ) -> Vec<ComArg>
    {
        let in_args = self.args
                .iter()
                .map( |ca| {
                    ComArg::from_rustarg( ca.clone(), Direction::In )
                } );
        let out_args = self.returnhandler.com_out_args();

        in_args.chain( out_args ).collect()
    }
}

fn try_parse_result( ty : &Type ) -> Option<( Type, Type )>
{
    let path = match *ty {
        Type::Path( ref p ) => &p.path,
        _ => return None,
    };

    // Ensure the type name contains 'Result'. We don't really have
    // good ways to ensure it is an actual Result type but at least we can
    // use this to discount things like Option<>, etc.
    let last_segment = path.segments.last()?;
    if ! last_segment.value().ident.to_string().contains( "Result" ) {
        return None;
    }

    // Ensure the Result has angle bracket arguments.
    if let PathArguments::AngleBracketed( ref data )
            = last_segment.value().arguments {

        // The returned types depend on how many arguments the Result has.
        return Some( match data.args.len() {
            1 => ( data.args[ 0 ].get_ty().ok()?, hresult_ty() ),
            2 => ( data.args[ 0 ].get_ty().ok()?, data.args[ 1 ].get_ty().ok()? ),
            _ => return None,
        } )
    }

    // We couldn't find a valid type. Return nothing.
    None
}

fn hresult_ty() -> Type {
    parse_quote!( ::intercom::HRESULT )
}

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

    #[test]
    fn no_args_or_return_value() {

        let info = test_info( "fn foo( &self ) {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.args.len(), 0 );
        assert_eq!( info.retval_type.is_none(), true );
        assert_eq!( info.return_type.is_none(), true );
    }

    #[test]
    fn basic_return_value() {

        let info = test_info( "fn foo( &self ) -> bool {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.args.len(), 0 );
        assert_eq!( info.retval_type.is_none(), true );
        assert_eq!(
                info.return_type,
                Some( parse_quote!( bool ) ) );
    }

    #[test]
    fn result_return_value() {

        let info = test_info( "fn foo( &self ) -> Result<String, f32> {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.args.len(), 0 );
        assert_eq!(
                info.retval_type,
                Some( parse_quote!( String ) ) );
        assert_eq!(
                info.return_type,
                Some( parse_quote!( f32 ) ) );
    }

    #[test]
    fn comresult_return_value() {

        let info = test_info( "fn foo( &self ) -> ComResult<String> {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.args.len(), 0 );
        assert_eq!(
                info.retval_type,
                Some( parse_quote!( String ) ) );
        assert_eq!(
                info.return_type,
                Some( parse_quote!( ::intercom::HRESULT ) ) );
    }

    #[test]
    fn basic_arguments() {

        let info = test_info( "fn foo( &self, a : u32, b : f32 ) {}" );

        assert_eq!( info.is_const, true );
        assert_eq!( info.name, "foo" );
        assert_eq!( info.retval_type.is_none(), true );
        assert_eq!( info.return_type.is_none(), true );

        assert_eq!( info.args.len(), 2 );

        assert_eq!( info.args[0].name, Ident::from( "a" ) );
        assert_eq!( info.args[0].ty, parse_quote!( u32 ) );

        assert_eq!( info.args[1].name, Ident::from( "b" ) );
        assert_eq!( info.args[1].ty, parse_quote!( f32 ) );
    }

    fn test_info( code : &str ) -> ComMethodInfo {

        let item = parse_str( code ).unwrap();
        let ( ident, decl, unsafety ) = match item {
            Item::Fn( ref f ) => ( f.ident, f.decl.as_ref(), f.unsafety.is_some() ),
            _ => panic!( "Code isn't function" ),
        };
        ComMethodInfo::new_from_parts( ident, decl, unsafety ).unwrap()
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::{Parser, Token};
use properties::DeclaredValue;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use string_cache::Atom;

#[derive(Clone)]
pub struct Value {
    /// In CSS syntax
    pub value: String,

    /// Custom property names in var() functions. Do not include the `--` prefix.
    pub references: HashSet<Atom>,
}

/// Names (atoms) do not include the `--` prefix.
pub type Map = HashMap<Atom, Value>;

pub fn parse(input: &mut Parser) -> Result<Value, ()> {
    let start = input.position();
    let mut references = HashSet::new();
    try!(parse_declaration_value(input, &mut references));
    Ok(Value {
        value: input.slice_from(start).to_owned(),
        references: references,
    })
}

/// https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value
fn parse_declaration_value(input: &mut Parser, references: &mut HashSet<Atom>) -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::BadUrl |
            Token::BadString |
            Token::CloseParenthesis |
            Token::CloseSquareBracket |
            Token::CloseCurlyBracket |

            Token::Semicolon |
            Token::Delim('!') => {
                return Err(())
            }

            Token::Function(ref name) if name == "var" => {
                try!(parse_var_function(input, references));
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(parse_declaration_value_block(input, references))
            }

            _ => {}
        }
    }
    Ok(())
}

/// Like parse_declaration_value,
/// but accept `!` and `;` since they are only invalid at the top level
fn parse_declaration_value_block(input: &mut Parser, references: &mut HashSet<Atom>)
                                 -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::BadUrl |
            Token::BadString |
            Token::CloseParenthesis |
            Token::CloseSquareBracket |
            Token::CloseCurlyBracket => {
                return Err(())
            }

            Token::Function(ref name) if name == "var" => {
                try!(parse_var_function(input, references));
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(parse_declaration_value_block(input, references))
            }

            _ => {}
        }
    }
    Ok(())
}

// If the var function is valid, return Ok((custom_property_name, fallback))
fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut HashSet<Atom>)
                              -> Result<(), ()> {
    // https://drafts.csswg.org/css-variables/#typedef-custom-property-name
    let name = try!(input.expect_ident());
    let name = if name.starts_with("--") {
        &name[2..]
    } else {
        return Err(())
    };
    if input.expect_comma().is_ok() {
        try!(parse_declaration_value(input, references));
    }
    references.insert(Atom::from_slice(name));
    Ok(())
}

/// Add one custom property declaration to a map,
/// unless another with the same name was already there.
pub fn cascade<'a>(custom_properties: &mut Option<Map>,
                   inherited_custom_properties: &Option<Arc<Map>>,
                   seen: &mut HashSet<&'a Atom>,
                   name: &'a Atom,
                   value: &DeclaredValue<Value>) {
    let was_not_already_present = seen.insert(name);
    if was_not_already_present {
        let map = match *custom_properties {
            Some(ref mut map) => map,
            None => {
                *custom_properties = Some(match *inherited_custom_properties {
                    Some(ref arc) => (**arc).clone(),
                    None => HashMap::new(),
                });
                custom_properties.as_mut().unwrap()
            }
        };
        match *value {
            DeclaredValue::SpecifiedValue(ref value) => {
                map.insert(name.clone(), value.clone());
            }
            DeclaredValue::Initial => {
                map.remove(name);
            }
            DeclaredValue::Inherit => {}  // The inherited value is what we already have.
        }
    }
}

/// If any custom property declarations where found for this element (`custom_properties.is_some()`)
/// remove cycles and move the map into an `Arc`.
/// Otherwise, default to the inherited map.
pub fn finish_cascade(custom_properties: Option<Map>,
                      inherited_custom_properties: &Option<Arc<Map>>)
                      -> Option<Arc<Map>> {
    if let Some(mut map) = custom_properties {
        remove_cycles(&mut map);
        Some(Arc::new(map))
    } else {
        inherited_custom_properties.clone()
    }
}

/// https://drafts.csswg.org/css-variables/#cycles
fn remove_cycles(map: &mut Map) {
    let mut to_remove = HashSet::new();
    {
        let mut visited = HashSet::new();
        let mut stack = Vec::new();
        for name in map.keys() {
            walk(map, name, &mut stack, &mut visited, &mut to_remove);

            fn walk<'a>(map: &'a Map, name: &'a Atom, stack: &mut Vec<&'a Atom>,
                        visited: &mut HashSet<&'a Atom>, to_remove: &mut HashSet<Atom>) {
                let was_not_already_present = visited.insert(name);
                if !was_not_already_present {
                    return
                }
                if let Some(value) = map.get(name) {
                    stack.push(name);
                    for next in &value.references {
                        if let Some(position) = stack.position_elem(&next) {
                            // Found a cycle
                            for in_cycle in &stack[position..] {
                                to_remove.insert((**in_cycle).clone());
                            }
                        } else {
                            walk(map, next, stack, visited, to_remove);
                        }
                    }
                    stack.pop();
                }
            }
        }
    }
    for name in &to_remove {
        map.remove(name);
    }
}
<commit_msg>Use nested parsers as appropritate<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::{Parser, Token};
use properties::DeclaredValue;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use string_cache::Atom;

#[derive(Clone)]
pub struct Value {
    /// In CSS syntax
    pub value: String,

    /// Custom property names in var() functions. Do not include the `--` prefix.
    pub references: HashSet<Atom>,
}

/// Names (atoms) do not include the `--` prefix.
pub type Map = HashMap<Atom, Value>;

pub fn parse(input: &mut Parser) -> Result<Value, ()> {
    let start = input.position();
    let mut references = HashSet::new();
    try!(parse_declaration_value(input, &mut references));
    Ok(Value {
        value: input.slice_from(start).to_owned(),
        references: references,
    })
}

/// https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value
fn parse_declaration_value(input: &mut Parser, references: &mut HashSet<Atom>) -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::BadUrl |
            Token::BadString |
            Token::CloseParenthesis |
            Token::CloseSquareBracket |
            Token::CloseCurlyBracket |

            Token::Semicolon |
            Token::Delim('!') => {
                return Err(())
            }

            Token::Function(ref name) if name == "var" => {
                try!(input.parse_nested_block(|input| {
                    parse_var_function(input, references)
                }));
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(input.parse_nested_block(|input| {
                    parse_declaration_value_block(input, references)
                }));
            }

            _ => {}
        }
    }
    Ok(())
}

/// Like parse_declaration_value,
/// but accept `!` and `;` since they are only invalid at the top level
fn parse_declaration_value_block(input: &mut Parser, references: &mut HashSet<Atom>)
                                 -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::BadUrl |
            Token::BadString |
            Token::CloseParenthesis |
            Token::CloseSquareBracket |
            Token::CloseCurlyBracket => {
                return Err(())
            }

            Token::Function(ref name) if name == "var" => {
                try!(input.parse_nested_block(|input| {
                    parse_var_function(input, references)
                }));
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(input.parse_nested_block(|input| {
                    parse_declaration_value_block(input, references)
                }));
            }

            _ => {}
        }
    }
    Ok(())
}

// If the var function is valid, return Ok((custom_property_name, fallback))
fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut HashSet<Atom>)
                              -> Result<(), ()> {
    // https://drafts.csswg.org/css-variables/#typedef-custom-property-name
    let name = try!(input.expect_ident());
    let name = if name.starts_with("--") {
        &name[2..]
    } else {
        return Err(())
    };
    if input.expect_comma().is_ok() {
        try!(parse_declaration_value(input, references));
    }
    references.insert(Atom::from_slice(name));
    Ok(())
}

/// Add one custom property declaration to a map,
/// unless another with the same name was already there.
pub fn cascade<'a>(custom_properties: &mut Option<Map>,
                   inherited_custom_properties: &Option<Arc<Map>>,
                   seen: &mut HashSet<&'a Atom>,
                   name: &'a Atom,
                   value: &DeclaredValue<Value>) {
    let was_not_already_present = seen.insert(name);
    if was_not_already_present {
        let map = match *custom_properties {
            Some(ref mut map) => map,
            None => {
                *custom_properties = Some(match *inherited_custom_properties {
                    Some(ref arc) => (**arc).clone(),
                    None => HashMap::new(),
                });
                custom_properties.as_mut().unwrap()
            }
        };
        match *value {
            DeclaredValue::SpecifiedValue(ref value) => {
                map.insert(name.clone(), value.clone());
            }
            DeclaredValue::Initial => {
                map.remove(name);
            }
            DeclaredValue::Inherit => {}  // The inherited value is what we already have.
        }
    }
}

/// If any custom property declarations where found for this element (`custom_properties.is_some()`)
/// remove cycles and move the map into an `Arc`.
/// Otherwise, default to the inherited map.
pub fn finish_cascade(custom_properties: Option<Map>,
                      inherited_custom_properties: &Option<Arc<Map>>)
                      -> Option<Arc<Map>> {
    if let Some(mut map) = custom_properties {
        remove_cycles(&mut map);
        Some(Arc::new(map))
    } else {
        inherited_custom_properties.clone()
    }
}

/// https://drafts.csswg.org/css-variables/#cycles
fn remove_cycles(map: &mut Map) {
    let mut to_remove = HashSet::new();
    {
        let mut visited = HashSet::new();
        let mut stack = Vec::new();
        for name in map.keys() {
            walk(map, name, &mut stack, &mut visited, &mut to_remove);

            fn walk<'a>(map: &'a Map, name: &'a Atom, stack: &mut Vec<&'a Atom>,
                        visited: &mut HashSet<&'a Atom>, to_remove: &mut HashSet<Atom>) {
                let was_not_already_present = visited.insert(name);
                if !was_not_already_present {
                    return
                }
                if let Some(value) = map.get(name) {
                    stack.push(name);
                    for next in &value.references {
                        if let Some(position) = stack.position_elem(&next) {
                            // Found a cycle
                            for in_cycle in &stack[position..] {
                                to_remove.insert((**in_cycle).clone());
                            }
                        } else {
                            walk(map, next, stack, visited, to_remove);
                        }
                    }
                    stack.pop();
                }
            }
        }
    }
    for name in &to_remove {
        map.remove(name);
    }
}
<|endoftext|>


<commit_before>/*
Module: float
*/

/**
 * Section: String Conversions
 */

/*
Function: to_str

Converts a float to a string

Parameters:

num - The float value
digits: The number of significant digits
*/
fn to_str(num: float, digits: uint) -> str {
    let accum = if num < 0.0 { num = -num; "-" } else { "" };
    let trunc = num as uint;
    let frac = num - (trunc as float);
    accum += uint::str(trunc);
    if frac == 0.0 || digits == 0u { ret accum; }
    accum += ".";
    while digits > 0u && frac > 0.0 {
        frac *= 10.0;
        let digit = frac as uint;
        accum += uint::str(digit);
        frac -= digit as float;
        digits -= 1u;
    }
    ret accum;
}

/*
Function: from_str

Convert a string to a float

This function accepts strings such as
* "3.14"
* "+3.14", equivalent to "3.14"
* "-3.14"
* "2.5E10", or equivalently, "2.5e10"
* "2.5E-10"
* "", or, equivalently, "." (understood as 0)
* "5."
* ".5", or, equivalently,  "0.5"

Parameters:

num - A string, possibly empty.

Returns:

<NaN> If the string did not represent a valid number.
Otherwise, the floating-point number represented [num].
*/
fn from_str(num: str) -> float {
   let pos = 0u;                  //Current byte position in the string.
                                  //Used to walk the string in O(n).
   let len = str::byte_len(num);  //Length of the string, in bytes.

   if len == 0u { ret 0.; }
   let total = 0f;                //Accumulated result
   let c     = 'z';               //Latest char.

   //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly.
   let neg = false;               //Sign of the result
   alt str::char_at(num, 0u) {
      '-' {
          neg = true;
          pos = 1u;
      }
      '+' {
          pos = 1u;
      }
      _ {}
   }

   //Examine the following chars until '.', 'e', 'E'
   while(pos < len) {
       let char_range = str::char_range_at(num, pos);
       c   = char_range.ch;
       pos = char_range.next;
       alt c {
         '0' to '9' {
           total = total * 10f;
           total += ((c as int) - ('0' as int)) as float;
         }
         _ {
           break;
         }
       }
   }

   if c == '.' {//Examine decimal part
      let decimal = 1.f;
      while(pos < len) {
         let char_range = str::char_range_at(num, pos);
         c = char_range.ch;
         pos = char_range.next;
         alt c {
            '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9'  {
                 decimal /= 10.f;
                 total += (((c as int) - ('0' as int)) as float)*decimal;
             }
             _ {
                 break;
             }
         }
      }
   }

   if (c == 'e') | (c == 'E') {//Examine exponent
      let exponent = 0u;
      let neg_exponent = false;
      if(pos < len) {
          let char_range = str::char_range_at(num, pos);
          c   = char_range.ch;
          alt c  {
             '+' {
                pos = char_range.next;
             }
             '-' {
                pos = char_range.next;
                neg_exponent = true;
             }
             _ {}
          }
          while(pos < len) {
             let char_range = str::char_range_at(num, pos);
             c = char_range.ch;
             pos = char_range.next;
             alt c {
                 '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' {
                     exponent *= 10u;
                     exponent += ((c as uint) - ('0' as uint));
                 }
                 _ {
                     break;
                 }
             }
          }
          let multiplier = pow_uint_to_uint_as_float(10u, exponent);
              //Note: not [int::pow], otherwise, we'll quickly
              //end up with a nice overflow
          if neg_exponent {
             total = total / multiplier;
          } else {
             total = total * multiplier;
          }
      }
   }

   if(pos < len) {
     ret NaN();
   } else {
     if(neg) {
        total *= -1f;
     }
     ret total;
   }
}

/**
 * Section: Arithmetics
 */

/*
Function: pow_uint_to_uint_as_float

Compute the exponentiation of an integer by another integer as a float.

Parameters:
x - The base.
pow - The exponent.

Returns:
<NaN> of both `x` and `pow` are `0u`, otherwise `x^pow`.
*/
fn pow_uint_to_uint_as_float(x: uint, pow: uint) -> float {
   if x == 0u {
      if pow == 0u {
        ret NaN();
      }
       ret 0.;
   }
   let my_pow     = pow;
   let total      = 1f;
   let multiplier = x as float;
   while (my_pow > 0u) {
     if my_pow % 2u == 1u {
       total = total * multiplier;
     }
     my_pow     /= 2u;
     multiplier *= multiplier;
   }
   ret total;
}

/**
 * Section: Constants
 */

//TODO: Once this is possible, replace the body of these functions
//by an actual constant.

/* Function: NaN */
fn NaN() -> float {
   ret 0./0.;
}

/* Function: infinity */
fn infinity() -> float {
   ret 1./0.;
}

/* Function: neg_infinity */
fn neg_infinity() -> float {
   ret -1./0.;
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Add function aliases for float operators<commit_after>/*
Module: float
*/

/**
 * Section: String Conversions
 */

/*
Function: to_str

Converts a float to a string

Parameters:

num - The float value
digits: The number of significant digits
*/
fn to_str(num: float, digits: uint) -> str {
    let accum = if num < 0.0 { num = -num; "-" } else { "" };
    let trunc = num as uint;
    let frac = num - (trunc as float);
    accum += uint::str(trunc);
    if frac == 0.0 || digits == 0u { ret accum; }
    accum += ".";
    while digits > 0u && frac > 0.0 {
        frac *= 10.0;
        let digit = frac as uint;
        accum += uint::str(digit);
        frac -= digit as float;
        digits -= 1u;
    }
    ret accum;
}

/*
Function: from_str

Convert a string to a float

This function accepts strings such as
* "3.14"
* "+3.14", equivalent to "3.14"
* "-3.14"
* "2.5E10", or equivalently, "2.5e10"
* "2.5E-10"
* "", or, equivalently, "." (understood as 0)
* "5."
* ".5", or, equivalently,  "0.5"

Parameters:

num - A string, possibly empty.

Returns:

<NaN> If the string did not represent a valid number.
Otherwise, the floating-point number represented [num].
*/
fn from_str(num: str) -> float {
   let pos = 0u;                  //Current byte position in the string.
                                  //Used to walk the string in O(n).
   let len = str::byte_len(num);  //Length of the string, in bytes.

   if len == 0u { ret 0.; }
   let total = 0f;                //Accumulated result
   let c     = 'z';               //Latest char.

   //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly.
   let neg = false;               //Sign of the result
   alt str::char_at(num, 0u) {
      '-' {
          neg = true;
          pos = 1u;
      }
      '+' {
          pos = 1u;
      }
      _ {}
   }

   //Examine the following chars until '.', 'e', 'E'
   while(pos < len) {
       let char_range = str::char_range_at(num, pos);
       c   = char_range.ch;
       pos = char_range.next;
       alt c {
         '0' to '9' {
           total = total * 10f;
           total += ((c as int) - ('0' as int)) as float;
         }
         _ {
           break;
         }
       }
   }

   if c == '.' {//Examine decimal part
      let decimal = 1.f;
      while(pos < len) {
         let char_range = str::char_range_at(num, pos);
         c = char_range.ch;
         pos = char_range.next;
         alt c {
            '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9'  {
                 decimal /= 10.f;
                 total += (((c as int) - ('0' as int)) as float)*decimal;
             }
             _ {
                 break;
             }
         }
      }
   }

   if (c == 'e') | (c == 'E') {//Examine exponent
      let exponent = 0u;
      let neg_exponent = false;
      if(pos < len) {
          let char_range = str::char_range_at(num, pos);
          c   = char_range.ch;
          alt c  {
             '+' {
                pos = char_range.next;
             }
             '-' {
                pos = char_range.next;
                neg_exponent = true;
             }
             _ {}
          }
          while(pos < len) {
             let char_range = str::char_range_at(num, pos);
             c = char_range.ch;
             pos = char_range.next;
             alt c {
                 '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' {
                     exponent *= 10u;
                     exponent += ((c as uint) - ('0' as uint));
                 }
                 _ {
                     break;
                 }
             }
          }
          let multiplier = pow_uint_to_uint_as_float(10u, exponent);
              //Note: not [int::pow], otherwise, we'll quickly
              //end up with a nice overflow
          if neg_exponent {
             total = total / multiplier;
          } else {
             total = total * multiplier;
          }
      }
   }

   if(pos < len) {
     ret NaN();
   } else {
     if(neg) {
        total *= -1f;
     }
     ret total;
   }
}

/**
 * Section: Arithmetics
 */

/*
Function: pow_uint_to_uint_as_float

Compute the exponentiation of an integer by another integer as a float.

Parameters:
x - The base.
pow - The exponent.

Returns:
<NaN> of both `x` and `pow` are `0u`, otherwise `x^pow`.
*/
fn pow_uint_to_uint_as_float(x: uint, pow: uint) -> float {
   if x == 0u {
      if pow == 0u {
        ret NaN();
      }
       ret 0.;
   }
   let my_pow     = pow;
   let total      = 1f;
   let multiplier = x as float;
   while (my_pow > 0u) {
     if my_pow % 2u == 1u {
       total = total * multiplier;
     }
     my_pow     /= 2u;
     multiplier *= multiplier;
   }
   ret total;
}

/**
 * Section: Constants
 */

//TODO: Once this is possible, replace the body of these functions
//by an actual constant.

/* Function: NaN */
fn NaN() -> float {
   ret 0./0.;
}

/* Function: infinity */
fn infinity() -> float {
   ret 1./0.;
}

/* Function: neg_infinity */
fn neg_infinity() -> float {
   ret -1./0.;
}

pure fn add(x: float, y: float) -> float { ret x + y; }

pure fn sub(x: float, y: float) -> float { ret x - y; }

pure fn mul(x: float, y: float) -> float { ret x * y; }

pure fn div(x: float, y: float) -> float { ret x / y; }

pure fn rem(x: float, y: float) -> float { ret x % y; }

pure fn lt(x: float, y: float) -> bool { ret x < y; }

pure fn le(x: float, y: float) -> bool { ret x <= y; }

pure fn eq(x: float, y: float) -> bool { ret x == y; }

pure fn ne(x: float, y: float) -> bool { ret x != y; }

pure fn ge(x: float, y: float) -> bool { ret x >= y; }

pure fn gt(x: float, y: float) -> bool { ret x > y; }

pure fn positive(x: float) -> bool { ret x > 0.; }

pure fn negative(x: float) -> bool { ret x < 0.; }

pure fn nonpositive(x: float) -> bool { ret x <= 0.; }

pure fn nonnegative(x: float) -> bool { ret x >= 0.; }

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>#![crate_name = "cksum"]
#![feature(collections, core, old_io, old_path, rustc_private)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

use std::old_io::{EndOfFile, File, IoError, IoResult, print};
use std::old_io::stdio::stdin_raw;
use std::mem;

use crc_table::CRC_TABLE;

#[path="../common/util.rs"]
#[macro_use]
mod util;

mod crc_table;

static NAME: &'static str = "cksum";
static VERSION: &'static str = "1.0.0";

#[inline]
fn crc_update(crc: u32, input: u8) -> u32 {
    (crc << 8) ^ CRC_TABLE[((crc >> 24) as usize ^ input as usize) & 0xFF]
}

#[inline]
fn crc_final(mut crc: u32, mut length: usize) -> u32 {
    while length != 0 {
        crc = crc_update(crc, length as u8);
        length >>= 8;
    }

    !crc
}

#[inline]
fn cksum(fname: &str) -> IoResult<(u32, usize)> {
    let mut crc = 0u32;
    let mut size = 0usize;

    let mut stdin_buf;
    let mut file_buf;
    let rd = match fname {
        "-" => {
            stdin_buf = stdin_raw();
            &mut stdin_buf as &mut Reader
        }
        _ => {
            file_buf = try!(File::open(&Path::new(fname)));
            &mut file_buf as &mut Reader
        }
    };

    let mut bytes: [u8; 1024 * 1024] = unsafe { mem::uninitialized() };
    loop {
        match rd.read(&mut bytes) {
            Ok(num_bytes) => {
                for &b in bytes[..num_bytes].iter() {
                    crc = crc_update(crc, b);
                }
                size += num_bytes;
            }
            Err(IoError { kind: EndOfFile, .. }) => return Ok((crc_final(crc, size), size)),
            Err(err) => return Err(err)
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let opts = [
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(err) => panic!("{}", err),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] [FILE]...", NAME);
        println!("");
        print(getopts::usage("Print CRC and size for each file.", opts.as_slice()).as_slice());
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let files = matches.free;

    if files.is_empty() {
        match cksum("-") {
            Ok((crc, size)) => println!("{} {}", crc, size),
            Err(err) => {
                show_error!("{}", err);
                return 2;
            }
        }
        return 0;
    }

    let mut exit_code = 0;
    for fname in files.iter() {
        match cksum(fname.as_slice()) {
            Ok((crc, size)) => println!("{} {} {}", crc, size, fname),
            Err(err) => {
                show_error!("'{}' {}", fname, err);
                exit_code = 2;
            }
        }
    }

    exit_code
}
<commit_msg>new io cksum (includes BufReader fix)<commit_after>#![crate_name = "cksum"]
#![feature(rustc_private)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

use std::io::{self, stdin, Read, Write, BufReader};
use std::path::Path;
use std::fs::File;
use std::mem;

use crc_table::CRC_TABLE;

#[path="../common/util.rs"]
#[macro_use]
mod util;

mod crc_table;

static NAME: &'static str = "cksum";
static VERSION: &'static str = "1.0.0";

#[inline]
fn crc_update(crc: u32, input: u8) -> u32 {
    (crc << 8) ^ CRC_TABLE[((crc >> 24) as usize ^ input as usize) & 0xFF]
}

#[inline]
fn crc_final(mut crc: u32, mut length: usize) -> u32 {
    while length != 0 {
        crc = crc_update(crc, length as u8);
        length >>= 8;
    }

    !crc
}

#[inline]
fn cksum(fname: &str) -> io::Result<(u32, usize)> {
    let mut crc = 0u32;
    let mut size = 0usize;

    let file;
    let mut rd : Box<Read> = match fname {
        "-" => {
            Box::new(stdin())
        }
        _ => {
            file = try!(File::open(&Path::new(fname)));
            Box::new(BufReader::new(file))
        }
    };

    let mut bytes: [u8; 1024 * 1024] = unsafe { mem::uninitialized() };
    loop {
        match rd.read(&mut bytes) {
            Ok(num_bytes) => {
                if num_bytes == 0 {
                    return Ok((crc_final(crc, size), size));
                }
                for &b in bytes[..num_bytes].iter() {
                    crc = crc_update(crc, b);
                }
                size += num_bytes;
            }
            Err(err) => return Err(err)
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let opts = [
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(&args[1..], &opts) {
        Ok(m) => m,
        Err(err) => panic!("{}", err),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] [FILE]...", NAME);
        println!("");
        println!("{}", getopts::usage("Print CRC and size for each file.", opts.as_ref()));
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let files = matches.free;

    if files.is_empty() {
        match cksum("-") {
            Ok((crc, size)) => println!("{} {}", crc, size),
            Err(err) => {
                show_error!("{}", err);
                return 2;
            }
        }
        return 0;
    }

    let mut exit_code = 0;
    for fname in files.iter() {
        match cksum(fname.as_ref()) {
            Ok((crc, size)) => println!("{} {} {}", crc, size, fname),
            Err(err) => {
                show_error!("'{}' {}", fname, err);
                exit_code = 2;
            }
        }
    }

    exit_code
}
<|endoftext|>


<commit_before>//! Utilities to talk to Lua

use rlua::{self, Table};
use rustwlc::*;

const MOD_NAMES: [&str; 8] = ["Shift", "Caps", "Control", "Alt",
                              "Mod2", "Mod3", "Mod4", "Mod5"];

/// Convert a modifier to the Lua interpretation
pub fn mods_to_lua(lua: &rlua::Lua, mut mods: KeyMod) -> rlua::Result<Table> {
    let mut mods_list: Vec<String> = Vec::with_capacity(MOD_NAMES.len());
    for index in 0..MOD_NAMES.len() {
        if mods == MOD_NONE {
            break;
        }
        if mods.bits() & 1 != 0 {
            mods_list.push(MOD_NAMES[index].into());
        }
        mods = KeyMod::from_bits_truncate(mods.bits() >> 1);
    }
    lua.create_table_from(mods_list.into_iter().enumerate())
}
<commit_msg>Use iterator, not indices, in mods_to_lua<commit_after>//! Utilities to talk to Lua

use rlua::{self, Table};
use rustwlc::*;

const MOD_NAMES: [&str; 8] = ["Shift", "Caps", "Control", "Alt",
                              "Mod2", "Mod3", "Mod4", "Mod5"];

/// Convert a modifier to the Lua interpretation
pub fn mods_to_lua(lua: &rlua::Lua, mut mods: KeyMod) -> rlua::Result<Table> {
    let mut mods_list: Vec<String> = Vec::with_capacity(MOD_NAMES.len());
    for mod_name in &MOD_NAMES {
        if mods == MOD_NONE {
            break;
        }
        if mods.bits() & 1 != 0 {
            mods_list.push((*mod_name).into());
        }
        mods = KeyMod::from_bits_truncate(mods.bits() >> 1);
    }
    lua.create_table_from(mods_list.into_iter().enumerate())
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use infer::{GenericKind, InferCtxt};
use infer::outlives::free_region_map::FreeRegionMap;
use infer::outlives::bounds::{self, OutlivesBound};
use ty::{self, Ty};

use syntax::ast;
use syntax_pos::Span;

/// The `OutlivesEnvironment` collects information about what outlives
/// what in a given type-checking setting. For example, if we have a
/// where-clause like `where T: 'a` in scope, then the
/// `OutlivesEnvironment` would record that (in its
/// `region_bound_pairs` field). Similarly, it contains methods for
/// processing and adding implied bounds into the outlives
/// environment.
///
/// Other code at present does not typically take a
/// `&OutlivesEnvironment`, but rather takes some of its fields (e.g.,
/// `process_registered_region_obligations` wants the
/// region-bound-pairs). There is no mistaking it: the current setup
/// of tracking region information is quite scattered! The
/// `OutlivesEnvironment`, for example, needs to sometimes be combined
/// with the `middle::RegionRelations`, to yield a full picture of how
/// (lexical) lifetimes interact. However, I'm reluctant to do more
/// refactoring here, since the setup with NLL is quite different.
/// For example, NLL has no need of `RegionRelations`, and is solely
/// interested in the `OutlivesEnvironment`. -nmatsakis
#[derive(Clone)]
pub struct OutlivesEnvironment<'tcx> {
    param_env: ty::ParamEnv<'tcx>,
    free_region_map: FreeRegionMap<'tcx>,
    region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
}

impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
    pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
        let mut env = OutlivesEnvironment {
            param_env,
            free_region_map: FreeRegionMap::new(),
            region_bound_pairs: vec![],
        };

        env.add_outlives_bounds(None, bounds::explicit_outlives_bounds(param_env));

        env
    }

    /// Borrows current value of the `free_region_map`.
    pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
        &self.free_region_map
    }

    /// Borrows current value of the `region_bound_pairs`.
    pub fn region_bound_pairs(&self) -> &[(ty::Region<'tcx>, GenericKind<'tcx>)] {
        &self.region_bound_pairs
    }

    /// Returns ownership of the `free_region_map`.
    pub fn into_free_region_map(self) -> FreeRegionMap<'tcx> {
        self.free_region_map
    }

    /// This is a hack to support the old-skool regionck, which
    /// processes region constraints from the main function and the
    /// closure together. In that context, when we enter a closure, we
    /// want to be able to "save" the state of the surrounding a
    /// function. We can then add implied bounds and the like from the
    /// closure arguments into the environment -- these should only
    /// apply in the closure body, so once we exit, we invoke
    /// `pop_snapshot_post_closure` to remove them.
    ///
    /// Example:
    ///
    /// ```
    /// fn foo<T>() {
    ///    callback(for<'a> |x: &'a T| {
    ///         // ^^^^^^^ not legal syntax, but probably should be
    ///         // within this closure body, `T: 'a` holds
    ///    })
    /// }
    /// ```
    ///
    /// This "containment" of closure's effects only works so well. In
    /// particular, we (intentionally) leak relationships between free
    /// regions that are created by the closure's bounds. The case
    /// where this is useful is when you have (e.g.) a closure with a
    /// signature like `for<'a, 'b> fn(x: &'a &'b u32)` -- in this
    /// case, we want to keep the relationship `'b: 'a` in the
    /// free-region-map, so that later if we have to take `LUB('b,
    /// 'a)` we can get the result `'b`.
    ///
    /// I have opted to keep **all modifications** to the
    /// free-region-map, however, and not just those that concern free
    /// variables bound in the closure. The latter seems more correct,
    /// but it is not the existing behavior, and I could not find a
    /// case where the existing behavior went wrong. In any case, it
    /// seems like it'd be readily fixed if we wanted. There are
    /// similar leaks around givens that seem equally suspicious, to
    /// be honest. --nmatsakis
    pub fn push_snapshot_pre_closure(&self) -> usize {
        self.region_bound_pairs.len()
    }

    /// See `push_snapshot_pre_closure`.
    pub fn pop_snapshot_post_closure(&mut self, len: usize) {
        self.region_bound_pairs.truncate(len);
    }

    /// This method adds "implied bounds" into the outlives environment.
    /// Implied bounds are outlives relationships that we can deduce
    /// on the basis that certain types must be well-formed -- these are
    /// either the types that appear in the function signature or else
    /// the input types to an impl. For example, if you have a function
    /// like
    ///
    /// ```
    /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { }
    /// ```
    ///
    /// we can assume in the caller's body that `'b: 'a` and that `T:
    /// 'b` (and hence, transitively, that `T: 'a`). This method would
    /// add those assumptions into the outlives-environment.
    ///
    /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
    pub fn add_implied_bounds(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        fn_sig_tys: &[Ty<'tcx>],
        body_id: ast::NodeId,
        span: Span,
    ) {
        debug!("add_implied_bounds()");

        for &ty in fn_sig_tys {
            let ty = infcx.resolve_type_vars_if_possible(&ty);
            debug!("add_implied_bounds: ty = {}", ty);
            let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
            self.add_outlives_bounds(Some(infcx), implied_bounds)
        }
    }

    /// Processes outlives bounds that are known to hold, whether from implied or other sources.
    ///
    /// The `infcx` parameter is optional; if the implied bounds may
    /// contain inference variables, it should be supplied, in which
    /// case we will register "givens" on the inference context. (See
    /// `RegionConstraintData`.)
    fn add_outlives_bounds<I>(
        &mut self,
        infcx: Option<&InferCtxt<'a, 'gcx, 'tcx>>,
        outlives_bounds: I,
    ) where
        I: IntoIterator<Item = OutlivesBound<'tcx>>,
    {
        // Record relationships such as `T:'x` that don't go into the
        // free-region-map but which we use here.
        for outlives_bound in outlives_bounds {
            debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
            match outlives_bound {
                OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b)) |
                OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
                    infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b);
                }
                OutlivesBound::RegionSubParam(r_a, param_b) => {
                    self.region_bound_pairs
                        .push((r_a, GenericKind::Param(param_b)));
                }
                OutlivesBound::RegionSubProjection(r_a, projection_b) => {
                    self.region_bound_pairs
                        .push((r_a, GenericKind::Projection(projection_b)));
                }
                OutlivesBound::RegionSubRegion(r_a, r_b) => {
                    // In principle, we could record (and take
                    // advantage of) every relationship here, but
                    // we are also free not to -- it simply means
                    // strictly less that we can successfully type
                    // check. Right now we only look for things
                    // relationships between free regions. (It may
                    // also be that we should revise our inference
                    // system to be more general and to make use
                    // of *every* relationship that arises here,
                    // but presently we do not.)
                    self.free_region_map.relate_regions(r_a, r_b);
                }
            }
        }
    }
}
<commit_msg>outlives/env: fix comment, say must and not should<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use infer::{GenericKind, InferCtxt};
use infer::outlives::free_region_map::FreeRegionMap;
use infer::outlives::bounds::{self, OutlivesBound};
use ty::{self, Ty};

use syntax::ast;
use syntax_pos::Span;

/// The `OutlivesEnvironment` collects information about what outlives
/// what in a given type-checking setting. For example, if we have a
/// where-clause like `where T: 'a` in scope, then the
/// `OutlivesEnvironment` would record that (in its
/// `region_bound_pairs` field). Similarly, it contains methods for
/// processing and adding implied bounds into the outlives
/// environment.
///
/// Other code at present does not typically take a
/// `&OutlivesEnvironment`, but rather takes some of its fields (e.g.,
/// `process_registered_region_obligations` wants the
/// region-bound-pairs). There is no mistaking it: the current setup
/// of tracking region information is quite scattered! The
/// `OutlivesEnvironment`, for example, needs to sometimes be combined
/// with the `middle::RegionRelations`, to yield a full picture of how
/// (lexical) lifetimes interact. However, I'm reluctant to do more
/// refactoring here, since the setup with NLL is quite different.
/// For example, NLL has no need of `RegionRelations`, and is solely
/// interested in the `OutlivesEnvironment`. -nmatsakis
#[derive(Clone)]
pub struct OutlivesEnvironment<'tcx> {
    param_env: ty::ParamEnv<'tcx>,
    free_region_map: FreeRegionMap<'tcx>,
    region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
}

impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
    pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
        let mut env = OutlivesEnvironment {
            param_env,
            free_region_map: FreeRegionMap::new(),
            region_bound_pairs: vec![],
        };

        env.add_outlives_bounds(None, bounds::explicit_outlives_bounds(param_env));

        env
    }

    /// Borrows current value of the `free_region_map`.
    pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
        &self.free_region_map
    }

    /// Borrows current value of the `region_bound_pairs`.
    pub fn region_bound_pairs(&self) -> &[(ty::Region<'tcx>, GenericKind<'tcx>)] {
        &self.region_bound_pairs
    }

    /// Returns ownership of the `free_region_map`.
    pub fn into_free_region_map(self) -> FreeRegionMap<'tcx> {
        self.free_region_map
    }

    /// This is a hack to support the old-skool regionck, which
    /// processes region constraints from the main function and the
    /// closure together. In that context, when we enter a closure, we
    /// want to be able to "save" the state of the surrounding a
    /// function. We can then add implied bounds and the like from the
    /// closure arguments into the environment -- these should only
    /// apply in the closure body, so once we exit, we invoke
    /// `pop_snapshot_post_closure` to remove them.
    ///
    /// Example:
    ///
    /// ```
    /// fn foo<T>() {
    ///    callback(for<'a> |x: &'a T| {
    ///         // ^^^^^^^ not legal syntax, but probably should be
    ///         // within this closure body, `T: 'a` holds
    ///    })
    /// }
    /// ```
    ///
    /// This "containment" of closure's effects only works so well. In
    /// particular, we (intentionally) leak relationships between free
    /// regions that are created by the closure's bounds. The case
    /// where this is useful is when you have (e.g.) a closure with a
    /// signature like `for<'a, 'b> fn(x: &'a &'b u32)` -- in this
    /// case, we want to keep the relationship `'b: 'a` in the
    /// free-region-map, so that later if we have to take `LUB('b,
    /// 'a)` we can get the result `'b`.
    ///
    /// I have opted to keep **all modifications** to the
    /// free-region-map, however, and not just those that concern free
    /// variables bound in the closure. The latter seems more correct,
    /// but it is not the existing behavior, and I could not find a
    /// case where the existing behavior went wrong. In any case, it
    /// seems like it'd be readily fixed if we wanted. There are
    /// similar leaks around givens that seem equally suspicious, to
    /// be honest. --nmatsakis
    pub fn push_snapshot_pre_closure(&self) -> usize {
        self.region_bound_pairs.len()
    }

    /// See `push_snapshot_pre_closure`.
    pub fn pop_snapshot_post_closure(&mut self, len: usize) {
        self.region_bound_pairs.truncate(len);
    }

    /// This method adds "implied bounds" into the outlives environment.
    /// Implied bounds are outlives relationships that we can deduce
    /// on the basis that certain types must be well-formed -- these are
    /// either the types that appear in the function signature or else
    /// the input types to an impl. For example, if you have a function
    /// like
    ///
    /// ```
    /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { }
    /// ```
    ///
    /// we can assume in the caller's body that `'b: 'a` and that `T:
    /// 'b` (and hence, transitively, that `T: 'a`). This method would
    /// add those assumptions into the outlives-environment.
    ///
    /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
    pub fn add_implied_bounds(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        fn_sig_tys: &[Ty<'tcx>],
        body_id: ast::NodeId,
        span: Span,
    ) {
        debug!("add_implied_bounds()");

        for &ty in fn_sig_tys {
            let ty = infcx.resolve_type_vars_if_possible(&ty);
            debug!("add_implied_bounds: ty = {}", ty);
            let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
            self.add_outlives_bounds(Some(infcx), implied_bounds)
        }
    }

    /// Processes outlives bounds that are known to hold, whether from implied or other sources.
    ///
    /// The `infcx` parameter is optional; if the implied bounds may
    /// contain inference variables, it must be supplied, in which
    /// case we will register "givens" on the inference context. (See
    /// `RegionConstraintData`.)
    fn add_outlives_bounds<I>(
        &mut self,
        infcx: Option<&InferCtxt<'a, 'gcx, 'tcx>>,
        outlives_bounds: I,
    ) where
        I: IntoIterator<Item = OutlivesBound<'tcx>>,
    {
        // Record relationships such as `T:'x` that don't go into the
        // free-region-map but which we use here.
        for outlives_bound in outlives_bounds {
            debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
            match outlives_bound {
                OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b)) |
                OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
                    infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b);
                }
                OutlivesBound::RegionSubParam(r_a, param_b) => {
                    self.region_bound_pairs
                        .push((r_a, GenericKind::Param(param_b)));
                }
                OutlivesBound::RegionSubProjection(r_a, projection_b) => {
                    self.region_bound_pairs
                        .push((r_a, GenericKind::Projection(projection_b)));
                }
                OutlivesBound::RegionSubRegion(r_a, r_b) => {
                    // In principle, we could record (and take
                    // advantage of) every relationship here, but
                    // we are also free not to -- it simply means
                    // strictly less that we can successfully type
                    // check. Right now we only look for things
                    // relationships between free regions. (It may
                    // also be that we should revise our inference
                    // system to be more general and to make use
                    // of *every* relationship that arises here,
                    // but presently we do not.)
                    self.free_region_map.relate_regions(r_a, r_b);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

pub use self::FileMatch::*;

use std::borrow::Cow;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use crate::search_paths::{PathKind, SearchPath, SearchPathFile};
use log::debug;
use rustc_fs_util::fix_windows_verbatim_for_gcc;

#[derive(Copy, Clone)]
pub enum FileMatch {
    FileMatches,
    FileDoesntMatch,
}

// A module for searching for libraries

#[derive(Clone)]
pub struct FileSearch<'a> {
    sysroot: &'a Path,
    triple: &'a str,
    search_paths: &'a [SearchPath],
    tlib_path: &'a SearchPath,
    kind: PathKind,
}

impl<'a> FileSearch<'a> {
    pub fn search_paths(&self) -> impl Iterator<Item = &'a SearchPath> {
        let kind = self.kind;
        self.search_paths
            .iter()
            .filter(move |sp| sp.kind.matches(kind))
            .chain(std::iter::once(self.tlib_path))
    }

    pub fn get_lib_path(&self) -> PathBuf {
        make_target_lib_path(self.sysroot, self.triple)
    }

    pub fn get_self_contained_lib_path(&self) -> PathBuf {
        self.get_lib_path().join("self-contained")
    }

    pub fn search<F>(&self, mut pick: F)
    where
        F: FnMut(&SearchPathFile, PathKind) -> FileMatch,
    {
        for search_path in self.search_paths() {
            debug!("searching {}", search_path.dir.display());
            fn is_rlib(spf: &SearchPathFile) -> bool {
                if let Some(f) = &spf.file_name_str { f.ends_with(".rlib") } else { false }
            }
            // Reading metadata out of rlibs is faster, and if we find both
            // an rlib and a dylib we only read one of the files of
            // metadata, so in the name of speed, bring all rlib files to
            // the front of the search list.
            let files1 = search_path.files.iter().filter(|spf| is_rlib(&spf));
            let files2 = search_path.files.iter().filter(|spf| !is_rlib(&spf));
            for spf in files1.chain(files2) {
                debug!("testing {}", spf.path.display());
                let maybe_picked = pick(spf, search_path.kind);
                match maybe_picked {
                    FileMatches => {
                        debug!("picked {}", spf.path.display());
                    }
                    FileDoesntMatch => {
                        debug!("rejected {}", spf.path.display());
                    }
                }
            }
        }
    }

    pub fn new(
        sysroot: &'a Path,
        triple: &'a str,
        search_paths: &'a Vec<SearchPath>,
        tlib_path: &'a SearchPath,
        kind: PathKind,
    ) -> FileSearch<'a> {
        debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
        FileSearch { sysroot, triple, search_paths, tlib_path, kind }
    }

    // Returns just the directories within the search paths.
    pub fn search_path_dirs(&self) -> Vec<PathBuf> {
        self.search_paths().map(|sp| sp.dir.to_path_buf()).collect()
    }

    // Returns a list of directories where target-specific tool binaries are located.
    pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
        let mut p = PathBuf::from(self.sysroot);
        p.push(find_libdir(self.sysroot).as_ref());
        p.push(RUST_LIB_DIR);
        p.push(&self.triple);
        p.push("bin");
        if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p.clone()] }
    }
}

pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
    let mut p = PathBuf::from(find_libdir(sysroot).as_ref());
    assert!(p.is_relative());
    p.push(RUST_LIB_DIR);
    p.push(target_triple);
    p.push("lib");
    p
}

pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
    sysroot.join(&relative_target_lib_path(sysroot, target_triple))
}

pub fn get_or_default_sysroot() -> PathBuf {
    // Follow symlinks.  If the resolved path is relative, make it absolute.
    fn canonicalize(path: PathBuf) -> PathBuf {
        let path = fs::canonicalize(&path).unwrap_or(path);
        // See comments on this target function, but the gist is that
        // gcc chokes on verbatim paths which fs::canonicalize generates
        // so we try to avoid those kinds of paths.
        fix_windows_verbatim_for_gcc(&path)
    }

    match env::current_exe() {
        Ok(exe) => {
            let mut p = canonicalize(exe);
            p.pop();
            p.pop();
            p
        }
        Err(e) => panic!("failed to get current_exe: {}", e),
    }
}

// The name of the directory rustc expects libraries to be located.
fn find_libdir(sysroot: &Path) -> Cow<'static, str> {
    // FIXME: This is a quick hack to make the rustc binary able to locate
    // Rust libraries in Linux environments where libraries might be installed
    // to lib64/lib32. This would be more foolproof by basing the sysroot off
    // of the directory where `librustc_driver` is located, rather than
    // where the rustc binary is.
    // If --libdir is set during configuration to the value other than
    // "lib" (i.e., non-default), this value is used (see issue #16552).

    #[cfg(target_pointer_width = "64")]
    const PRIMARY_LIB_DIR: &str = "lib64";

    #[cfg(target_pointer_width = "32")]
    const PRIMARY_LIB_DIR: &str = "lib32";

    const SECONDARY_LIB_DIR: &str = "lib";

    match option_env!("CFG_LIBDIR_RELATIVE") {
        Some(libdir) if libdir != "lib" => libdir.into(),
        _ => {
            if sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR).exists() {
                PRIMARY_LIB_DIR.into()
            } else {
                SECONDARY_LIB_DIR.into()
            }
        }
    }
}

// The name of rustc's own place to organize libraries.
// Used to be "rustc", now the default is "rustlib"
const RUST_LIB_DIR: &str = "rustlib";
<commit_msg>fix clippy::redundant_clone: remove redundant clones<commit_after>#![allow(non_camel_case_types)]

pub use self::FileMatch::*;

use std::borrow::Cow;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use crate::search_paths::{PathKind, SearchPath, SearchPathFile};
use log::debug;
use rustc_fs_util::fix_windows_verbatim_for_gcc;

#[derive(Copy, Clone)]
pub enum FileMatch {
    FileMatches,
    FileDoesntMatch,
}

// A module for searching for libraries

#[derive(Clone)]
pub struct FileSearch<'a> {
    sysroot: &'a Path,
    triple: &'a str,
    search_paths: &'a [SearchPath],
    tlib_path: &'a SearchPath,
    kind: PathKind,
}

impl<'a> FileSearch<'a> {
    pub fn search_paths(&self) -> impl Iterator<Item = &'a SearchPath> {
        let kind = self.kind;
        self.search_paths
            .iter()
            .filter(move |sp| sp.kind.matches(kind))
            .chain(std::iter::once(self.tlib_path))
    }

    pub fn get_lib_path(&self) -> PathBuf {
        make_target_lib_path(self.sysroot, self.triple)
    }

    pub fn get_self_contained_lib_path(&self) -> PathBuf {
        self.get_lib_path().join("self-contained")
    }

    pub fn search<F>(&self, mut pick: F)
    where
        F: FnMut(&SearchPathFile, PathKind) -> FileMatch,
    {
        for search_path in self.search_paths() {
            debug!("searching {}", search_path.dir.display());
            fn is_rlib(spf: &SearchPathFile) -> bool {
                if let Some(f) = &spf.file_name_str { f.ends_with(".rlib") } else { false }
            }
            // Reading metadata out of rlibs is faster, and if we find both
            // an rlib and a dylib we only read one of the files of
            // metadata, so in the name of speed, bring all rlib files to
            // the front of the search list.
            let files1 = search_path.files.iter().filter(|spf| is_rlib(&spf));
            let files2 = search_path.files.iter().filter(|spf| !is_rlib(&spf));
            for spf in files1.chain(files2) {
                debug!("testing {}", spf.path.display());
                let maybe_picked = pick(spf, search_path.kind);
                match maybe_picked {
                    FileMatches => {
                        debug!("picked {}", spf.path.display());
                    }
                    FileDoesntMatch => {
                        debug!("rejected {}", spf.path.display());
                    }
                }
            }
        }
    }

    pub fn new(
        sysroot: &'a Path,
        triple: &'a str,
        search_paths: &'a Vec<SearchPath>,
        tlib_path: &'a SearchPath,
        kind: PathKind,
    ) -> FileSearch<'a> {
        debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
        FileSearch { sysroot, triple, search_paths, tlib_path, kind }
    }

    // Returns just the directories within the search paths.
    pub fn search_path_dirs(&self) -> Vec<PathBuf> {
        self.search_paths().map(|sp| sp.dir.to_path_buf()).collect()
    }

    // Returns a list of directories where target-specific tool binaries are located.
    pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
        let mut p = PathBuf::from(self.sysroot);
        p.push(find_libdir(self.sysroot).as_ref());
        p.push(RUST_LIB_DIR);
        p.push(&self.triple);
        p.push("bin");
        if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] }
    }
}

pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
    let mut p = PathBuf::from(find_libdir(sysroot).as_ref());
    assert!(p.is_relative());
    p.push(RUST_LIB_DIR);
    p.push(target_triple);
    p.push("lib");
    p
}

pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
    sysroot.join(&relative_target_lib_path(sysroot, target_triple))
}

pub fn get_or_default_sysroot() -> PathBuf {
    // Follow symlinks.  If the resolved path is relative, make it absolute.
    fn canonicalize(path: PathBuf) -> PathBuf {
        let path = fs::canonicalize(&path).unwrap_or(path);
        // See comments on this target function, but the gist is that
        // gcc chokes on verbatim paths which fs::canonicalize generates
        // so we try to avoid those kinds of paths.
        fix_windows_verbatim_for_gcc(&path)
    }

    match env::current_exe() {
        Ok(exe) => {
            let mut p = canonicalize(exe);
            p.pop();
            p.pop();
            p
        }
        Err(e) => panic!("failed to get current_exe: {}", e),
    }
}

// The name of the directory rustc expects libraries to be located.
fn find_libdir(sysroot: &Path) -> Cow<'static, str> {
    // FIXME: This is a quick hack to make the rustc binary able to locate
    // Rust libraries in Linux environments where libraries might be installed
    // to lib64/lib32. This would be more foolproof by basing the sysroot off
    // of the directory where `librustc_driver` is located, rather than
    // where the rustc binary is.
    // If --libdir is set during configuration to the value other than
    // "lib" (i.e., non-default), this value is used (see issue #16552).

    #[cfg(target_pointer_width = "64")]
    const PRIMARY_LIB_DIR: &str = "lib64";

    #[cfg(target_pointer_width = "32")]
    const PRIMARY_LIB_DIR: &str = "lib32";

    const SECONDARY_LIB_DIR: &str = "lib";

    match option_env!("CFG_LIBDIR_RELATIVE") {
        Some(libdir) if libdir != "lib" => libdir.into(),
        _ => {
            if sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR).exists() {
                PRIMARY_LIB_DIR.into()
            } else {
                SECONDARY_LIB_DIR.into()
            }
        }
    }
}

// The name of rustc's own place to organize libraries.
// Used to be "rustc", now the default is "rustlib"
const RUST_LIB_DIR: &str = "rustlib";
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Anagrams

use std::collections::{HashMap, HashSet};

#[cfg(not(test))]
use std::io::{File, BufferedReader};
use std::cmp::max;

fn sort_string(string: &str) -> String {
    let mut chars: Vec<char> = string.chars().collect();
    chars.sort();
    String::from_chars(chars.as_slice())
}

// Returns groups of anagrams where each group consists of a set
// containing the words
fn get_anagrams<T: Buffer>(mut reader: T) -> HashMap<String, HashSet<String>> {
    let mut groups = HashMap::new();

    // Make groups of words according to the letters they contain
    for line in reader.lines() {
	let s = line.unwrap().as_slice().trim().to_string();
	groups.insert_or_update_with(
            // The key
            sort_string(s.clone().as_slice()),
            // The value
            {
                let mut set = HashSet::new();
                set.insert(s.clone());
                set
            },
            // The closure to update the value
	    |_, group| { group.insert(s.clone()); }
            );
    }

    groups
}

// Returns the groups of anagrams that contain the most words in them
fn get_biggest_groups(groups: &HashMap<String, HashSet<String>>)
                      -> HashMap<String, HashSet<String>> {
    let max_length = groups.iter()
        .fold(0, |current_max, (_, group)| max(current_max,
                                               group.len()));
    groups.iter()
        .filter(|&(_, group)| group.len() == max_length)
        .map(|(x, y)| (x.clone(), y.clone()))
        .collect()
}

#[cfg(not(test))]
fn main () {
    let path = Path::new("src/resources/unixdict.txt");
    let reader = BufferedReader::new(File::open(&path));

    let anagram_groups = get_anagrams(reader);
    let biggest_groups = get_biggest_groups(&anagram_groups);

    // Print the words in the biggest groups of anagrams
    for (_, group) in biggest_groups.iter() {
        for word in group.iter() {
            print!("{} ", *word)
        }
        println!("")
    }
}

#[test]
fn basic_test() {
    use std::io::MemReader;

    // Groups of anagrams
    let group1: HashSet<String> = vec!["lane".to_string(),
                                       "neal".to_string(),
                                       "lean".to_string()]
                                       .move_iter().collect();
    let group2: HashSet<String> = vec!["angel".to_string(),
                                       "angle".to_string(),
                                       "galen".to_string()]
                                       .move_iter().collect();
    let group3: HashSet<String> = vec!["glare".to_string(),
                                       "large".to_string()]
                                       .move_iter().collect();

    // Prepare the input for the program
    // We will get a string like "lane\nneal\nlean\nangel\nangle..."
    let mut word_iter = group1.iter().chain(group2.iter().chain(group3.iter()));
    let mut words = String::new();

    words.push_str(word_iter.next().unwrap().as_slice());
    for word in word_iter {
        words.push_str("\n");
        words.push_str(word.as_slice());
    }

    // Here begins the real testing
    let all_groups = get_anagrams(MemReader::new(words.to_string().as_slice()
                                                 .bytes().collect()));
    let biggest_groups = get_biggest_groups(&all_groups);

    // Groups 1, 2 and 3 are contained in "all_groups"
    assert!(all_groups.iter().any(|(_, group)| *group == group1));
    assert!(all_groups.iter().any(|(_, group)| *group == group2));
    assert!(all_groups.iter().any(|(_, group)| *group == group3));

    // Groups 1 and 2 are contained in "biggest_groups". Group 3 is not.
    assert!(biggest_groups.iter().any(|(_, group)| *group == group1));
    assert!(biggest_groups.iter().any(|(_, group)| *group == group2));
    assert!(biggest_groups.iter().all(|(_, group)| *group != group3));
}
<commit_msg>anagrams: style<commit_after>// Implements http://rosettacode.org/wiki/Anagrams
#[cfg(not(test))]
use std::io::{File, BufferedReader};
use std::collections::{HashMap, HashSet};

fn sorted_characters(string: &str) -> String {
    let mut chars = string.chars().collect::<Vec<char>>();
    chars.sort();
    String::from_chars(chars.as_slice())
}

/// Returns groups of anagrams where each group consists of a set
/// containing the words
fn anagrams<T: Iterator<String>>(mut lines: T) -> HashMap<String, HashSet<String>> {
    let mut groups = HashMap::new();

    // Make groups of words according to the letters they contain
    for line in lines {
        let s = line.as_slice().trim();
        let set = groups.find_or_insert_with(// The key
                                             sorted_characters(s),
                                             // Insert new set if not found
                                             |_| HashSet::new());

        set.insert(s.to_string());
    }

    groups
}

/// Returns the groups of anagrams that contain the most words in them
fn largest_groups(groups: &HashMap<String, HashSet<String>>)
                      -> HashMap<String, HashSet<String>> {
    let max_length = groups.iter().map(|(_, group)| group.len())
                                  .max().unwrap();
    groups.iter().filter_map(|(key, group)| {
        if group.len() == max_length {
            Some((key.clone(), group.clone()))
        } else {
            None
        }
    }).collect()
}

#[cfg(not(test))]
fn main () {
    let path = Path::new("src/resources/unixdict.txt");
    let mut reader = BufferedReader::new(File::open(&path));
    let lines = reader.lines().map(|l| l.unwrap());

    let anagram_groups = anagrams(lines);
    let largest_groups = largest_groups(&anagram_groups);

    // Print the words in the largest groups of anagrams
    for (_, group) in largest_groups.iter() {
        for word in group.iter() {
            print!("{} ", word)
        }
        println!("")
    }
}

#[test]
fn basic_test() {
    fn to_hash(s: &[&str]) -> HashSet<String> {
        s.iter().map(|s| s.to_string()).collect()
    };

    fn assert_has_value(map: &HashMap<String, HashSet<String>>,
                        set: &HashSet<String>) {
        assert!(map.values().any(|v| v == set));
    }

    // Groups of anagrams
    let group1 = &to_hash(&["lane", "neal", "lean"]);
    let group2 = &to_hash(&["angel", "angle", "galen"]);
    let group3 = &to_hash(&["glare", "large"]);

    // Prepare the input for the program
    let word_iter = group1.iter().chain(group2.iter().chain(group3.iter()));

    // Here begins the real testing
    let all_groups = &anagrams(word_iter.map(|s| s.to_string()));
    let largest_groups = &largest_groups(all_groups);

    // Groups 1, 2 and 3 are contained in "all_groups"
    assert_has_value(all_groups, group1);
    assert_has_value(all_groups, group2);
    assert_has_value(all_groups, group3);

    // Groups 1 and 2 are contained in "largest_groups". Group 3 is not.
    assert_has_value(largest_groups, group1);
    assert_has_value(largest_groups, group2);
    assert!(largest_groups.values().all(|group| group != group3));
}
<|endoftext|>


<commit_before>use moqt_core::QObject;
use std::ffi::CStr;

#[test]
fn qobject() {
    unsafe {
        let obj1 = QObject::new2();
        let obj2 = QObject::new2();
        obj1.destroyed().connect(obj2.delete_later());

        let args = QObject::next_connect_args();
        assert_eq!(args.sender().as_ptr(), obj1.as_ptr().as_ptr());
        assert_eq!(args.receiver().as_ptr(), obj2.as_ptr().as_ptr());

        let signal = CStr::from_ptr(args.signal().as_ptr()).to_str().unwrap();
        assert_eq!(signal, "2destroyed(QObject*)");

        let method = CStr::from_ptr(args.method().as_ptr()).to_str().unwrap();
        assert_eq!(method, "1deleteLater()");
    }
}
<commit_msg>add raw slot test<commit_after>use moqt_core::{QObject, RawSlotOfCInt};
use cpp_utils::Ptr;
use std::ffi::CStr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::os::raw::{c_void, c_int};

#[test]
fn qobject() {
    unsafe {
        let obj1 = QObject::new2();
        let obj2 = QObject::new2();
        obj1.destroyed().connect(obj2.delete_later());

        let args = QObject::next_connect_args();
        assert_eq!(args.sender().as_ptr(), obj1.as_ptr().as_ptr());
        assert_eq!(args.receiver().as_ptr(), obj2.as_ptr().as_ptr());

        let signal = CStr::from_ptr(args.signal().as_ptr()).to_str().unwrap();
        assert_eq!(signal, "2destroyed(QObject*)");

        let method = CStr::from_ptr(args.method().as_ptr()).to_str().unwrap();
        assert_eq!(method, "1deleteLater()");
    }
}

#[test]
fn raw_slot() {
    unsafe {
        static FLAG: AtomicBool = AtomicBool::new(false);
        extern "C" fn hook(data: *mut c_void, value: c_int) {
            assert_eq!(value, 7);
            let old = FLAG.swap(true, Ordering::SeqCst);
            assert!(!old);
        }

        let mut obj = RawSlotOfCInt::new();
        obj.set(hook, Ptr::new(5 as *mut c_void));
        assert!(!FLAG.load(Ordering::SeqCst));
        obj.custom_slot(7);
        assert!(FLAG.load(Ordering::SeqCst));
    }
}
<|endoftext|>