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

use syntax::{ast, ast_util, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::{attr, codemap};
use syntax::parse::token;
use syntax::ptr::P;

#[deriving(PartialEq, Show)]
enum ParamType {
    ParamUniform,
    ParamBlock,
    ParamTexture,
}

#[deriving(Show)]
enum ParamError {
    ErrorDeprecatedTexture,
    ErrorUnknown,
}

/// Classify variable types (`i32`, `TextureParam`, etc) into the `ParamType`
fn classify(node: &ast::Ty_) -> Result<ParamType, ParamError> {
    match *node {
        ast::TyPath(ref path, _, _) => match path.segments.last() {
            Some(segment) => match segment.identifier.name.as_str() {
                "RawBufferHandle" => Ok(ParamBlock),
                "TextureParam" => Ok(ParamTexture),
                "TextureHandle" => Err(ErrorDeprecatedTexture),
                _ => Ok(ParamUniform),
            },
            None => Ok(ParamUniform),
        },
        _ => Ok(ParamUniform),
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::create_link`
fn method_create(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                 substr: &generic::Substructure,
                 link_name: &str,
                 path_root: ast::Ident) -> P<ast::Expr> {
    let link_ident = cx.ident_of(link_name);
    match *substr.fields {
        generic::StaticStruct(definition, generic::Named(ref fields)) => {
            let init_expr = cx.expr_struct_ident(
                span, link_ident,
                fields.iter().map(|&(fname, fspan)| {
                    cx.field_imm(fspan, fname, cx.expr_none(fspan))
                }).collect()
            );
            let class_info: Vec<(ParamType, P<ast::Expr>)> = definition.fields.iter()
                    .zip(fields.iter()).scan((), |_, (def, &(fname, fspan))|
                match classify(&def.node.ty.node) {
                    Ok(c) => {
                        let name = match super::find_name(cx, span, def.node.attrs.as_slice()) {
                            Some(name) => name,
                            None => token::get_ident(fname),
                        };
                        Some((c, cx.expr_str(fspan, name)))
                    },
                    Err(e) => {
                        cx.span_err(fspan, format!(
                            "Unrecognized parameter ({}) type {}",
                            fname.as_str(), e
                            ).as_slice()
                        );
                        None
                    },
                }
            ).collect();
            let gen_arms = |ptype: ParamType, var: ast::Ident| -> Vec<ast::Arm> {
                class_info.iter().zip(fields.iter())
                          .filter(|&(&(class, _), _)| class == ptype)
                          .map(|(&(_, ref name_expr), &(fname, fspan))|
                    cx.arm(fspan,
                        vec![cx.pat_lit(fspan, name_expr.clone())],
                        quote_expr!(cx,
                            out.$fname = Some(i as $path_root::gfx::shade::$var)
                        )
                    )
                ).collect()
            };
            let uniform_arms = gen_arms(ParamUniform, cx.ident_of("VarUniform"));
            let block_arms = gen_arms(ParamBlock, cx.ident_of("VarBlock"));
            let texture_arms = gen_arms(ParamTexture, cx.ident_of("VarTexture"));
            let input = &substr.nonself_args[1];
            quote_expr!(cx, {
                let mut out = $init_expr;
                for (i, u) in $input.uniforms.iter().enumerate() {
                    match u.name.as_slice() {
                        $uniform_arms
                        _ => return Err($path_root::gfx::shade::MissingUniform(u.name.clone())),
                    }
                }
                for (i, b) in $input.blocks.iter().enumerate() {
                    match b.name.as_slice() {
                        $block_arms
                        _ => return Err($path_root::gfx::shade::MissingBlock(b.name.clone())),
                    }
                }
                for (i, t) in $input.textures.iter().enumerate() {
                    match t.name.as_slice() {
                        $texture_arms
                        _ => return Err($path_root::gfx::shade::MissingTexture(t.name.clone())),
                    }
                }
                Ok(out)
            })
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::create_link()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        },
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::fill_params`
fn method_fill(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               substr: &generic::Substructure,
               definition: P<ast::StructDef>,
               path_root: ast::Ident)
               -> P<ast::Expr> {
    match *substr.fields {
        generic::Struct(ref fields) => {
            let out = &substr.nonself_args[1];
            let max_num = cx.expr_uint(span, fields.len());
            let mut calls = vec![
                quote_stmt!(cx, $out.uniforms.reserve($max_num);),
                quote_stmt!(cx, $out.blocks.reserve($max_num);),
                quote_stmt!(cx, $out.textures.reserve($max_num);),
            ];
            calls.push_all_move(definition.fields.iter().zip(fields.iter())
                                .map(|(def, f)| {
                let value_id = &f.self_;
                let var_id = cx.expr_field_access(
                    span,
                    substr.nonself_args[0].clone(),
                    f.name.unwrap()
                    );
                match classify(&def.node.ty.node) {
                    Ok(ParamUniform) => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.uniforms.len() <= id as uint {
                                unsafe { $out.uniforms.set_len(id as uint + 1) }
                            }
                            *$out.uniforms.get_mut(id as uint) = $value_id.to_uniform()
                        })
                    ),
                    Ok(ParamBlock)   => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.blocks.len() <= id as uint {
                                unsafe { $out.blocks.set_len(id as uint + 1) }
                            }
                            *$out.blocks.get_mut(id as uint) = {$value_id}
                        })
                    ),
                    Ok(ParamTexture) => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.textures.len() <= id as uint {
                                unsafe { $out.textures.set_len(id as uint + 1) }
                            }
                            *$out.textures.get_mut(id as uint) = {$value_id}
                        })
                    ),
                    Err(_) => {
                        cx.span_err(span, format!(
                            "Invalid uniform: {}",
                            f.name.unwrap().as_str(),
                            ).as_slice()
                        );
                        cx.stmt_expr(cx.expr_uint(span, 0))
                    },
                }
            }).collect());
            let view = cx.view_use_simple(
                span,
                ast::Inherited,
                cx.path(span, vec![
                    cx.ident_of("self"),
                    path_root,
                    cx.ident_of("gfx"),
                    cx.ident_of("shade"),
                    cx.ident_of("ToUniform"),
                ])
            );
            cx.expr_block(cx.block_all(span, vec![view], calls, None))
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::bind()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// A helper function that translates variable type (`i32`, `TextureHandle`, etc)
/// into the corresponding shader var id type (`VarUniform`, `VarBlock`, or `VarTexture`)
fn node_to_var_type(cx: &mut ext::base::ExtCtxt,
                    span: codemap::Span, node: &ast::Ty_,
                    path_root: ast::Ident) -> P<ast::Ty> {
    let id = match classify(node) {
        Ok(ParamUniform) => "VarUniform",
        Ok(ParamBlock)   => "VarBlock",
        Ok(ParamTexture) => "VarTexture",
        Err(ErrorDeprecatedTexture) => {
            cx.span_err(span, "Use gfx::shade::TextureParam for texture vars instead of gfx::shade::TextureHandle");
            ""
        },
        Err(ErrorUnknown) => {
            cx.span_err(span, format!("Unknown node: {}", node).as_slice());
            ""
        },
    };
    cx.ty_option(cx.ty_path(
        cx.path(span, vec![
            path_root,
            cx.ident_of("gfx"),
            cx.ident_of("shade"),
            cx.ident_of(id),
        ]),
        None
    ))
}

/// Extract all deriving() attributes into a separate array
fn copy_deriving(attribs: &[ast::Attribute]) -> Vec<ast::Attribute> {
    attribs.iter().filter(|at| {
        match at.node.value.node {
            ast::MetaList(ref s, _) => s.get() == "deriving",
            _ => false,
        }
    }).map(|at| at.clone()).collect()
}

/// Decorator for `shader_param` attribute
pub fn expand(context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: |P<ast::Item>|) {
    // Insert the `gfx` reexport module
    let path_root = super::extern_crate_hack(context, span, |i| push(i));

    // constructing the Link struct
    let (base_def, link_def) = match item.node {
        ast::ItemStruct(ref definition, ref generics) => {
            if generics.lifetimes.len() > 0 {
                context.bug("Generics are not allowed in ShaderParam struct");
            }
            (definition, ast::StructDef {
                fields: definition.fields.iter()
                    .map(|f| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: f.node.kind,
                            id: f.node.id,
                            ty: node_to_var_type(context, f.span, &f.node.ty.node, path_root),
                            attrs: Vec::new(),
                        },
                        span: f.span,
                    }).collect(),
                ctor_id: None,
                super_struct: None,
                is_virtual: false,
            })
        },
        _ => {
            context.span_err(span, "Only free-standing named structs allowed to derive ShaderParam");
            return;
        }
    };
    let link_name = format!("_{}Link", item.ident.as_str());
    let link_ident = context.ident_of(link_name.as_slice());
    let link_ty = box generic::ty::Literal(
        generic::ty::Path::new_local(link_name.as_slice())
    );
    // Almost `context.item_struct(span, link_ident, link_def)` but with visibility
    push(P(ast::Item {
        ident: link_ident,
        attrs: copy_deriving(item.attrs.as_slice()),
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemStruct(
            P(link_def),
            ast_util::empty_generics()
        ),
        vis: item.vis,
        span: span,
    }));
    // constructing the `Batch` implementation typedef
    match meta_item.node {
        ast::MetaList(_, ref items) if items.len() <= 2 => {
            let batch_names = ["RefBatch", "OwnedBatch"];
            for (&batch, param) in batch_names.iter().zip(items.iter()) {
                match param.node {
                    ast::MetaWord(ref shell_name) => {
                        // pub type $shell_ident = hack::gfx::batch::RefBatch<$link_ident, $self_ident>
                        let path = context.ty_path(
                            context.path_all(span, false,
                                vec![
                                    path_root,
                                    context.ident_of("gfx"),
                                    context.ident_of("batch"),
                                    context.ident_of(batch),
                                ],
                                Vec::new(),
                                vec![
                                    context.ty_ident(span, link_ident),
                                    context.ty_ident(span, item.ident)
                                ]
                            ), None
                        );
                        push(P(ast::Item {
                            ident: context.ident_of(shell_name.get()),
                            attrs: Vec::new(),
                            id: ast::DUMMY_NODE_ID,
                            node: ast::ItemTy(path, ast_util::empty_generics()),
                            vis: item.vis,
                            span: span,
                        }))
                    },
                    _ => {
                        context.span_err(meta_item.span,
                            "The new batch name has to be a word")
                    }
                }
            }
        },
        _ => {
            context.span_err(meta_item.span,
                "Invalid argument. Please specify the typedef for your `Program`\n\
                as `#[shader_param(MyLightBatch, MyHeavyBatch)]`")
        }
    }
    // deriving ShaderParam
    let trait_def = generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ShaderParam"],
            lifetime: None,
            params: vec![link_ty.clone()],
            global: false,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            generic::MethodDef {
                name: "create_link",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: None,
                args: vec![
                    generic::ty::Literal(generic::ty::Path {
                        path: vec!["Option"],
                        lifetime: None,
                        params: vec![
                            box generic::ty::Ptr(
                                box generic::ty::Self,
                                generic::ty::Borrowed(None, ast::MutImmutable)
                            ),
                        ],
                        global: false,
                    }),
                    generic::ty::Ptr(
                        box generic::ty::Literal(generic::ty::Path::new(
                            vec![super::EXTERN_CRATE_HACK, "gfx", "ProgramInfo"])),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Result"],
                        lifetime: None,
                        params: vec![
                            link_ty.clone(),
                            box generic::ty::Literal(generic::ty::Path::new(
                                vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParameterError"]
                            ))
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_create(cx, span, sub, link_name.as_slice(), path_root)
                ),
            },
            generic::MethodDef {
                name: "fill_params",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: Some(Some(generic::ty::Borrowed(
                    None, ast::MutImmutable
                ))),
                args: vec![
                    generic::ty::Ptr(
                        link_ty.clone(),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                    generic::ty::Literal(
                        generic::ty::Path::new(vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParamValues"]),
                    ),
                ],
                ret_ty: generic::ty::Tuple(Vec::new()),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_fill(cx, span, sub, base_def.clone(), path_root)
                ),
            },
        ],
    };
    let fixup = |item| {
        push(super::fixup_extern_crate_paths(item, path_root))
    };
    trait_def.expand(context, meta_item, item, fixup);
}
<commit_msg>Remove unused import<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::{ast, ast_util, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::codemap;
use syntax::parse::token;
use syntax::ptr::P;

#[deriving(PartialEq, Show)]
enum ParamType {
    ParamUniform,
    ParamBlock,
    ParamTexture,
}

#[deriving(Show)]
enum ParamError {
    ErrorDeprecatedTexture,
    ErrorUnknown,
}

/// Classify variable types (`i32`, `TextureParam`, etc) into the `ParamType`
fn classify(node: &ast::Ty_) -> Result<ParamType, ParamError> {
    match *node {
        ast::TyPath(ref path, _, _) => match path.segments.last() {
            Some(segment) => match segment.identifier.name.as_str() {
                "RawBufferHandle" => Ok(ParamBlock),
                "TextureParam" => Ok(ParamTexture),
                "TextureHandle" => Err(ErrorDeprecatedTexture),
                _ => Ok(ParamUniform),
            },
            None => Ok(ParamUniform),
        },
        _ => Ok(ParamUniform),
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::create_link`
fn method_create(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                 substr: &generic::Substructure,
                 link_name: &str,
                 path_root: ast::Ident) -> P<ast::Expr> {
    let link_ident = cx.ident_of(link_name);
    match *substr.fields {
        generic::StaticStruct(definition, generic::Named(ref fields)) => {
            let init_expr = cx.expr_struct_ident(
                span, link_ident,
                fields.iter().map(|&(fname, fspan)| {
                    cx.field_imm(fspan, fname, cx.expr_none(fspan))
                }).collect()
            );
            let class_info: Vec<(ParamType, P<ast::Expr>)> = definition.fields.iter()
                    .zip(fields.iter()).scan((), |_, (def, &(fname, fspan))|
                match classify(&def.node.ty.node) {
                    Ok(c) => {
                        let name = match super::find_name(cx, span, def.node.attrs.as_slice()) {
                            Some(name) => name,
                            None => token::get_ident(fname),
                        };
                        Some((c, cx.expr_str(fspan, name)))
                    },
                    Err(e) => {
                        cx.span_err(fspan, format!(
                            "Unrecognized parameter ({}) type {}",
                            fname.as_str(), e
                            ).as_slice()
                        );
                        None
                    },
                }
            ).collect();
            let gen_arms = |ptype: ParamType, var: ast::Ident| -> Vec<ast::Arm> {
                class_info.iter().zip(fields.iter())
                          .filter(|&(&(class, _), _)| class == ptype)
                          .map(|(&(_, ref name_expr), &(fname, fspan))|
                    cx.arm(fspan,
                        vec![cx.pat_lit(fspan, name_expr.clone())],
                        quote_expr!(cx,
                            out.$fname = Some(i as $path_root::gfx::shade::$var)
                        )
                    )
                ).collect()
            };
            let uniform_arms = gen_arms(ParamUniform, cx.ident_of("VarUniform"));
            let block_arms = gen_arms(ParamBlock, cx.ident_of("VarBlock"));
            let texture_arms = gen_arms(ParamTexture, cx.ident_of("VarTexture"));
            let input = &substr.nonself_args[1];
            quote_expr!(cx, {
                let mut out = $init_expr;
                for (i, u) in $input.uniforms.iter().enumerate() {
                    match u.name.as_slice() {
                        $uniform_arms
                        _ => return Err($path_root::gfx::shade::MissingUniform(u.name.clone())),
                    }
                }
                for (i, b) in $input.blocks.iter().enumerate() {
                    match b.name.as_slice() {
                        $block_arms
                        _ => return Err($path_root::gfx::shade::MissingBlock(b.name.clone())),
                    }
                }
                for (i, t) in $input.textures.iter().enumerate() {
                    match t.name.as_slice() {
                        $texture_arms
                        _ => return Err($path_root::gfx::shade::MissingTexture(t.name.clone())),
                    }
                }
                Ok(out)
            })
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::create_link()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        },
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::fill_params`
fn method_fill(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               substr: &generic::Substructure,
               definition: P<ast::StructDef>,
               path_root: ast::Ident)
               -> P<ast::Expr> {
    match *substr.fields {
        generic::Struct(ref fields) => {
            let out = &substr.nonself_args[1];
            let max_num = cx.expr_uint(span, fields.len());
            let mut calls = vec![
                quote_stmt!(cx, $out.uniforms.reserve($max_num);),
                quote_stmt!(cx, $out.blocks.reserve($max_num);),
                quote_stmt!(cx, $out.textures.reserve($max_num);),
            ];
            calls.push_all_move(definition.fields.iter().zip(fields.iter())
                                .map(|(def, f)| {
                let value_id = &f.self_;
                let var_id = cx.expr_field_access(
                    span,
                    substr.nonself_args[0].clone(),
                    f.name.unwrap()
                    );
                match classify(&def.node.ty.node) {
                    Ok(ParamUniform) => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.uniforms.len() <= id as uint {
                                unsafe { $out.uniforms.set_len(id as uint + 1) }
                            }
                            *$out.uniforms.get_mut(id as uint) = $value_id.to_uniform()
                        })
                    ),
                    Ok(ParamBlock)   => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.blocks.len() <= id as uint {
                                unsafe { $out.blocks.set_len(id as uint + 1) }
                            }
                            *$out.blocks.get_mut(id as uint) = {$value_id}
                        })
                    ),
                    Ok(ParamTexture) => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.textures.len() <= id as uint {
                                unsafe { $out.textures.set_len(id as uint + 1) }
                            }
                            *$out.textures.get_mut(id as uint) = {$value_id}
                        })
                    ),
                    Err(_) => {
                        cx.span_err(span, format!(
                            "Invalid uniform: {}",
                            f.name.unwrap().as_str(),
                            ).as_slice()
                        );
                        cx.stmt_expr(cx.expr_uint(span, 0))
                    },
                }
            }).collect());
            let view = cx.view_use_simple(
                span,
                ast::Inherited,
                cx.path(span, vec![
                    cx.ident_of("self"),
                    path_root,
                    cx.ident_of("gfx"),
                    cx.ident_of("shade"),
                    cx.ident_of("ToUniform"),
                ])
            );
            cx.expr_block(cx.block_all(span, vec![view], calls, None))
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::bind()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// A helper function that translates variable type (`i32`, `TextureHandle`, etc)
/// into the corresponding shader var id type (`VarUniform`, `VarBlock`, or `VarTexture`)
fn node_to_var_type(cx: &mut ext::base::ExtCtxt,
                    span: codemap::Span, node: &ast::Ty_,
                    path_root: ast::Ident) -> P<ast::Ty> {
    let id = match classify(node) {
        Ok(ParamUniform) => "VarUniform",
        Ok(ParamBlock)   => "VarBlock",
        Ok(ParamTexture) => "VarTexture",
        Err(ErrorDeprecatedTexture) => {
            cx.span_err(span, "Use gfx::shade::TextureParam for texture vars instead of gfx::shade::TextureHandle");
            ""
        },
        Err(ErrorUnknown) => {
            cx.span_err(span, format!("Unknown node: {}", node).as_slice());
            ""
        },
    };
    cx.ty_option(cx.ty_path(
        cx.path(span, vec![
            path_root,
            cx.ident_of("gfx"),
            cx.ident_of("shade"),
            cx.ident_of(id),
        ]),
        None
    ))
}

/// Extract all deriving() attributes into a separate array
fn copy_deriving(attribs: &[ast::Attribute]) -> Vec<ast::Attribute> {
    attribs.iter().filter(|at| {
        match at.node.value.node {
            ast::MetaList(ref s, _) => s.get() == "deriving",
            _ => false,
        }
    }).map(|at| at.clone()).collect()
}

/// Decorator for `shader_param` attribute
pub fn expand(context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: |P<ast::Item>|) {
    // Insert the `gfx` reexport module
    let path_root = super::extern_crate_hack(context, span, |i| push(i));

    // constructing the Link struct
    let (base_def, link_def) = match item.node {
        ast::ItemStruct(ref definition, ref generics) => {
            if generics.lifetimes.len() > 0 {
                context.bug("Generics are not allowed in ShaderParam struct");
            }
            (definition, ast::StructDef {
                fields: definition.fields.iter()
                    .map(|f| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: f.node.kind,
                            id: f.node.id,
                            ty: node_to_var_type(context, f.span, &f.node.ty.node, path_root),
                            attrs: Vec::new(),
                        },
                        span: f.span,
                    }).collect(),
                ctor_id: None,
                super_struct: None,
                is_virtual: false,
            })
        },
        _ => {
            context.span_err(span, "Only free-standing named structs allowed to derive ShaderParam");
            return;
        }
    };
    let link_name = format!("_{}Link", item.ident.as_str());
    let link_ident = context.ident_of(link_name.as_slice());
    let link_ty = box generic::ty::Literal(
        generic::ty::Path::new_local(link_name.as_slice())
    );
    // Almost `context.item_struct(span, link_ident, link_def)` but with visibility
    push(P(ast::Item {
        ident: link_ident,
        attrs: copy_deriving(item.attrs.as_slice()),
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemStruct(
            P(link_def),
            ast_util::empty_generics()
        ),
        vis: item.vis,
        span: span,
    }));
    // constructing the `Batch` implementation typedef
    match meta_item.node {
        ast::MetaList(_, ref items) if items.len() <= 2 => {
            let batch_names = ["RefBatch", "OwnedBatch"];
            for (&batch, param) in batch_names.iter().zip(items.iter()) {
                match param.node {
                    ast::MetaWord(ref shell_name) => {
                        // pub type $shell_ident = hack::gfx::batch::RefBatch<$link_ident, $self_ident>
                        let path = context.ty_path(
                            context.path_all(span, false,
                                vec![
                                    path_root,
                                    context.ident_of("gfx"),
                                    context.ident_of("batch"),
                                    context.ident_of(batch),
                                ],
                                Vec::new(),
                                vec![
                                    context.ty_ident(span, link_ident),
                                    context.ty_ident(span, item.ident)
                                ]
                            ), None
                        );
                        push(P(ast::Item {
                            ident: context.ident_of(shell_name.get()),
                            attrs: Vec::new(),
                            id: ast::DUMMY_NODE_ID,
                            node: ast::ItemTy(path, ast_util::empty_generics()),
                            vis: item.vis,
                            span: span,
                        }))
                    },
                    _ => {
                        context.span_err(meta_item.span,
                            "The new batch name has to be a word")
                    }
                }
            }
        },
        _ => {
            context.span_err(meta_item.span,
                "Invalid argument. Please specify the typedef for your `Program`\n\
                as `#[shader_param(MyLightBatch, MyHeavyBatch)]`")
        }
    }
    // deriving ShaderParam
    let trait_def = generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ShaderParam"],
            lifetime: None,
            params: vec![link_ty.clone()],
            global: false,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            generic::MethodDef {
                name: "create_link",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: None,
                args: vec![
                    generic::ty::Literal(generic::ty::Path {
                        path: vec!["Option"],
                        lifetime: None,
                        params: vec![
                            box generic::ty::Ptr(
                                box generic::ty::Self,
                                generic::ty::Borrowed(None, ast::MutImmutable)
                            ),
                        ],
                        global: false,
                    }),
                    generic::ty::Ptr(
                        box generic::ty::Literal(generic::ty::Path::new(
                            vec![super::EXTERN_CRATE_HACK, "gfx", "ProgramInfo"])),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Result"],
                        lifetime: None,
                        params: vec![
                            link_ty.clone(),
                            box generic::ty::Literal(generic::ty::Path::new(
                                vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParameterError"]
                            ))
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_create(cx, span, sub, link_name.as_slice(), path_root)
                ),
            },
            generic::MethodDef {
                name: "fill_params",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: Some(Some(generic::ty::Borrowed(
                    None, ast::MutImmutable
                ))),
                args: vec![
                    generic::ty::Ptr(
                        link_ty.clone(),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                    generic::ty::Literal(
                        generic::ty::Path::new(vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParamValues"]),
                    ),
                ],
                ret_ty: generic::ty::Tuple(Vec::new()),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_fill(cx, span, sub, base_def.clone(), path_root)
                ),
            },
        ],
    };
    let fixup = |item| {
        push(super::fixup_extern_crate_paths(item, path_root))
    };
    trait_def.expand(context, meta_item, item, fixup);
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! Dragonfly-specific raw type definitions

#![stable(feature = "raw_ext", since = "1.1.0")]
#![rustc_deprecated(since = "1.8.0",
                    reason = "these type aliases are no longer supported by \
                              the standard library, the `libc` crate on \
                              crates.io should be used instead for the correct \
                              definitions")]
#![allow(deprecated)]

use os::raw::c_long;
use os::unix::raw::{uid_t, gid_t};

#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;

#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;

#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_dev: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ino: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mode: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_nlink: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_uid: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gid: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_rdev: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime_nsec: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime_nsec: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime_nsec: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_size: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blocks: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blksize: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_flags: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gen: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_lspare: i32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_birthtime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_birthtime_nsec: i64,
}
<commit_msg>remove unused import from dragonfly os raw<commit_after>// Copyright 2015 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.

//! Dragonfly-specific raw type definitions

#![stable(feature = "raw_ext", since = "1.1.0")]
#![rustc_deprecated(since = "1.8.0",
                    reason = "these type aliases are no longer supported by \
                              the standard library, the `libc` crate on \
                              crates.io should be used instead for the correct \
                              definitions")]
#![allow(deprecated)]

#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;

#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;

#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_dev: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ino: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mode: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_nlink: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_uid: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gid: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_rdev: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime_nsec: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime_nsec: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime_nsec: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_size: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blocks: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blksize: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_flags: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gen: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_lspare: i32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_birthtime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_birthtime_nsec: i64,
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

/*!
The Finally trait provides a method, `finally` on
stack closures that emulates Java-style try/finally blocks.

# Example

~~~
do || {
    ...
}.finally {
    alway_run_this();
}
~~~
*/

use ops::Drop;

#[cfg(test)] use task::{failing, spawn};

pub trait Finally<T> {
    fn finally(&self, dtor: &fn()) -> T;
}

impl<'self,T> Finally<T> for &'self fn() -> T {
    fn finally(&self, dtor: &fn()) -> T {
        let _d = Finallyalizer {
            dtor: dtor
        };

        (*self)()
    }
}

impl<T> Finally<T> for ~fn() -> T {
    fn finally(&self, dtor: &fn()) -> T {
        let _d = Finallyalizer {
            dtor: dtor
        };

        (*self)()
    }
}

impl<T> Finally<T> for @fn() -> T {
    fn finally(&self, dtor: &fn()) -> T {
        let _d = Finallyalizer {
            dtor: dtor
        };

        (*self)()
    }
}

struct Finallyalizer<'self> {
    dtor: &'self fn()
}

#[unsafe_destructor]
impl<'self> Drop for Finallyalizer<'self> {
    fn finalize(&self) {
        (self.dtor)();
    }
}

#[test]
fn test_success() {
    let mut i = 0;
    do (|| {
        i = 10;
    }).finally {
        assert!(!failing());
        assert_eq!(i, 10);
        i = 20;
    }
    assert_eq!(i, 20);
}

#[test]
#[ignore(cfg(windows))]
#[should_fail]
fn test_fail() {
    let mut i = 0;
    do (|| {
        i = 10;
        fail!();
    }).finally {
        assert!(failing());
        assert_eq!(i, 10);
    }
}

#[test]
fn test_retval() {
    let closure: &fn() -> int = || 10;
    let i = do closure.finally { };
    assert_eq!(i, 10);
}

#[test]
fn test_compact() {
    // FIXME #4727: Should be able to use a fn item instead
    // of a closure for do_some_fallible_work,
    // but it's a type error.
    let do_some_fallible_work: &fn() = || { };
    fn but_always_run_this_function() { }
    do_some_fallible_work.finally(
        but_always_run_this_function);
}

#[test]
fn test_owned() {
    fn spawn_with_finalizer(f: ~fn()) {
        do spawn { do f.finally { } }
    }
    let owned: ~fn() = || { };
    spawn_with_finalizer(owned);
}

#[test]
fn test_managed() {
    let i = @mut 10;
    let managed: @fn() -> int = || {
        let r = *i;
        *i += 10;
        r
    };
    assert_eq!(do managed.finally {}, 10);
    assert_eq!(*i, 20);
}<commit_msg>Add a finally impl for `extern "Rust" fn()`<commit_after>// Copyright 2013 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.

/*!
The Finally trait provides a method, `finally` on
stack closures that emulates Java-style try/finally blocks.

# Example

~~~
do || {
    ...
}.finally {
    alway_run_this();
}
~~~
*/

use ops::Drop;

#[cfg(test)] use task::{failing, spawn};

pub trait Finally<T> {
    fn finally(&self, dtor: &fn()) -> T;
}

macro_rules! finally_fn {
    ($fnty:ty) => {
        impl<T> Finally<T> for $fnty {
            fn finally(&self, dtor: &fn()) -> T {
                let _d = Finallyalizer {
                    dtor: dtor
                };
                (*self)()
            }
        }
    }
}

impl<'self,T> Finally<T> for &'self fn() -> T {
    fn finally(&self, dtor: &fn()) -> T {
        let _d = Finallyalizer {
            dtor: dtor
        };

        (*self)()
    }
}

finally_fn!(~fn() -> T)
finally_fn!(@fn() -> T)
finally_fn!(extern "Rust" fn() -> T)

struct Finallyalizer<'self> {
    dtor: &'self fn()
}

#[unsafe_destructor]
impl<'self> Drop for Finallyalizer<'self> {
    fn finalize(&self) {
        (self.dtor)();
    }
}

#[test]
fn test_success() {
    let mut i = 0;
    do (|| {
        i = 10;
    }).finally {
        assert!(!failing());
        assert_eq!(i, 10);
        i = 20;
    }
    assert_eq!(i, 20);
}

#[test]
#[ignore(cfg(windows))]
#[should_fail]
fn test_fail() {
    let mut i = 0;
    do (|| {
        i = 10;
        fail!();
    }).finally {
        assert!(failing());
        assert_eq!(i, 10);
    }
}

#[test]
fn test_retval() {
    let closure: &fn() -> int = || 10;
    let i = do closure.finally { };
    assert_eq!(i, 10);
}

#[test]
fn test_compact() {
    fn do_some_fallible_work() {}
    fn but_always_run_this_function() { }
    do_some_fallible_work.finally(
        but_always_run_this_function);
}

#[test]
fn test_owned() {
    fn spawn_with_finalizer(f: ~fn()) {
        do spawn { do f.finally { } }
    }
    let owned: ~fn() = || { };
    spawn_with_finalizer(owned);
}

#[test]
fn test_managed() {
    let i = @mut 10;
    let managed: @fn() -> int = || {
        let r = *i;
        *i += 10;
        r
    };
    assert_eq!(do managed.finally {}, 10);
    assert_eq!(*i, 20);
}
<|endoftext|>


<commit_before><commit_msg>derive ordering experiment<commit_after>enum Pet {
  Cat,
  Dog,
  Mouse
}

use self::Pet::*;

enum HttpStatus {
  Ok = 200,
  NotModified = 304,
  NotFound = 404
}

use std::mem::size_of;

assert_eq!(size_of::<Pet>(), 1);
assert_eq!(size_of::<HttpStatus>(), 2);

assert_eq!(HttpStatus::Ok as i32, 200);
<|endoftext|>


<commit_before><commit_msg>docs(Argon2PasswordHasher): add an extra security note on `default`<commit_after><|endoftext|>


<commit_before><commit_msg>Account for proper directory destinations when using 2 args<commit_after><|endoftext|>


<commit_before><commit_msg>update error checking in config<commit_after><|endoftext|>


<commit_before>//! ExcelError management module
//!
//! Provides all excel error conversion and description
//! Also provides `Result` as a alias of `Result<_, ExcelError>

use quick_xml::error::Error as XmlError;

error_chain! {
    types {
        Error, ErrorKind, ChainErr, Result;
    }

//     links {
//         rustup_dist::Error, rustup_dist::ErrorKind, Dist;
//         rustup_utils::Error, rustup_utils::ErrorKind, Utils;
//     }

    foreign_links {
        ::std::io::Error, Io;
        ::zip::result::ZipError, Zip;
        XmlError, Xml;
        ::std::num::ParseIntError, ParseInt;
        ::std::num::ParseFloatError, ParseFloat;
        ::std::str::ParseBoolError, ParseBool;
        ::std::str::Utf8Error, Utf8;
        ::std::string::FromUtf8Error, FromUtf8;
    }

//     errors {
//         InvalidToolchainName(t: String) {
//             description("invalid toolchain name")
//             display("invalid toolchain name: '{}'", t)
//         }
//     }
}

impl From<(XmlError, usize)> for Error {
    fn from(err: (XmlError, usize)) -> Error { err.0.into() }
}
<commit_msg>remove unused ParseBoolError<commit_after>//! ExcelError management module
//!
//! Provides all excel error conversion and description
//! Also provides `Result` as a alias of `Result<_, ExcelError>

use quick_xml::error::Error as XmlError;

error_chain! {
    types {
        Error, ErrorKind, ChainErr, Result;
    }

//     links {
//         rustup_dist::Error, rustup_dist::ErrorKind, Dist;
//         rustup_utils::Error, rustup_utils::ErrorKind, Utils;
//     }

    foreign_links {
        ::std::io::Error, Io;
        ::zip::result::ZipError, Zip;
        XmlError, Xml;
        ::std::num::ParseIntError, ParseInt;
        ::std::num::ParseFloatError, ParseFloat;
        ::std::str::Utf8Error, Utf8;
        ::std::string::FromUtf8Error, FromUtf8;
    }

//     errors {
//         InvalidToolchainName(t: String) {
//             description("invalid toolchain name")
//             display("invalid toolchain name: '{}'", t)
//         }
//     }
}

impl From<(XmlError, usize)> for Error {
    fn from(err: (XmlError, usize)) -> Error { err.0.into() }
}
<|endoftext|>


<commit_before><commit_msg>Allow custom Packet impls to override len<commit_after><|endoftext|>


<commit_before><commit_msg>Implement a data Reader utility<commit_after>use std::str;
use object_id;
use object_id::ObjectId;

pub struct Reader<'a> {
    position: uint,
    data: &'a [u8]
}

impl<'a> Reader<'a> {
    pub fn from_data(bytes: &'a[u8]) -> Reader<'a> {
        Reader {
            position: 0,
            data: bytes
        }
    }

    pub fn take(&mut self, length: uint) -> &'a [u8] {
        self.skip(length);
        self.data.slice(self.position - length, self.position)
    }

    pub fn take_while(&mut self, predicate: |&u8| -> bool) -> &'a [u8] {
        let mut next_position = self.position;

        while predicate(&(self.data[next_position])) {
            next_position += 1;
        }

        let length = next_position - self.position;
        self.take(length)
    }

    pub fn take_string_while(&mut self, predicate: |&u8| -> bool) -> &'a str {
        str::from_utf8(self.take_while(predicate)).unwrap()
    }

    pub fn take_string(&mut self, length: uint) -> &'a str {
        str::from_utf8(self.take(length)).unwrap()
    }

    pub fn take_string_based_object_id(&mut self) -> ObjectId {
        ObjectId::from_string(self.take_string(40))
    }

    pub fn take_object_id(&mut self) -> ObjectId {
        ObjectId::from_bytes(self.take(object_id::RAW_SIZE))
    }

    pub fn get(&self, length: uint) -> &'a [u8] {
        self.data.slice(self.position, self.position + length)
    }

    pub fn get_rest(&self) -> &'a [u8] {
        self.data.slice_from(self.position)
    }

    pub fn get_rest_as_string(&self) -> &'a str {
        str::from_utf8(self.get_rest()).unwrap()
    }

    pub fn skip(&mut self, length: uint) {
        self.position += length;
    }

    pub fn back(&mut self, length: uint) {
        self.position -= length;
    }
}<|endoftext|>


<commit_before><commit_msg>Compute shading from object space vectors<commit_after><|endoftext|>


<commit_before><commit_msg>update<commit_after><|endoftext|>


<commit_before>// Copyright 2018 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.

/* This test is flakey, so it has been commented out.

pub struct Inner<T> {
    field: T,
}

unsafe impl<T> Send for Inner<T>
where
    T: Copy + Send,
{
}

// @has no_redundancy/struct.Outer.html
// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl<T> Send for \
// Outer<T> where T: Copy + Send"
pub struct Outer<T> {
    inner_field: Inner<T>,
}

*/
<commit_msg>Ignore properly.<commit_after>// Copyright 2018 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.

// ignore

pub struct Inner<T> {
    field: T,
}

unsafe impl<T> Send for Inner<T>
where
    T: Copy + Send,
{
}

// @has no_redundancy/struct.Outer.html
// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl<T> Send for \
// Outer<T> where T: Copy + Send"
pub struct Outer<T> {
    inner_field: Inner<T>,
}
<|endoftext|>


<commit_before><commit_msg>honour --squeeze (#110)<commit_after><|endoftext|>


<commit_before><commit_msg>del service<commit_after><|endoftext|>


<commit_before><commit_msg>Correct a missing parameter in filter doc<commit_after><|endoftext|>


<commit_before><commit_msg>'grains': add possible optimization.<commit_after><|endoftext|>


<commit_before>use core::ptr;

#[lang="stack_exhausted"]
extern "C" fn stack_exhausted() {

}

#[lang="eh_personality"]
extern "C" fn eh_personality() {

}

#[no_mangle]
pub unsafe extern "C" fn memcmp(a: *mut i8, b: *const i8, len: usize) -> i32 {
    for i in 0..len {
        let c_a = ptr::read(a.offset(i as isize));
        let c_b = ptr::read(b.offset(i as isize));
        if c_a != c_b {
            return c_a as i32 - c_b as i32;
        }
    }
    return 0;
}

#[no_mangle]
pub unsafe extern "C" fn memmove(dst: *mut u8, src: *const u8, len: usize) {
    if src < dst {
        for i_reverse in 0..len as isize {
            let i = len as isize - i_reverse - 1;
            ptr::write(dst.offset(i), ptr::read(src.offset(i)));
        }
    } else {
        for i in 0..len as isize {
            ptr::write(dst.offset(i), ptr::read(src.offset(i)));
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn memcpy(dst: *mut u8, src: *const u8, len: usize) {
    for i in 0..len as isize {
        ptr::write(dst.offset(i), ptr::read(src.offset(i)));
    }
}

#[no_mangle]
pub unsafe extern "C" fn memset(dst: *mut u8, c: i32, len: usize) {
    for i in 0..len as isize {
        ptr::write(dst.offset(i), c as u8);
    }
}

#[no_mangle]
#[cfg(target_arch = "x86")]
//TODO Make this better
/// 64 bit remainder on 32 bit arch
pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 {
    if b == 0 {
        return 0;
    }

    let mut rem = a;
    while rem >= b {
        rem -= b;
    }
    rem
}

#[no_mangle]
#[cfg(target_arch = "x86")]
//TODO Make this better
/// 64 bit division on 32 bit arch
pub extern "C" fn __udivdi3(a: u64, b: u64) -> u64 {
    if b == 0 {
        return 0;
    }

    let mut quot = 0;
    let mut rem = a;
    while rem >= b {
        rem -= b;
        quot += 1;
    }
    quot
}
<commit_msg>Make division and modulo in the kernel 2-5 times faster<commit_after>use core::ptr;

#[lang="stack_exhausted"]
extern "C" fn stack_exhausted() {

}

#[lang="eh_personality"]
extern "C" fn eh_personality() {

}

#[no_mangle]
pub unsafe extern "C" fn memcmp(a: *mut i8, b: *const i8, len: usize) -> i32 {
    for i in 0..len {
        let c_a = ptr::read(a.offset(i as isize));
        let c_b = ptr::read(b.offset(i as isize));
        if c_a != c_b {
            return c_a as i32 - c_b as i32;
        }
    }
    return 0;
}

#[no_mangle]
pub unsafe extern "C" fn memmove(dst: *mut u8, src: *const u8, len: usize) {
    if src < dst {
        for i_reverse in 0..len as isize {
            let i = len as isize - i_reverse - 1;
            ptr::write(dst.offset(i), ptr::read(src.offset(i)));
        }
    } else {
        for i in 0..len as isize {
            ptr::write(dst.offset(i), ptr::read(src.offset(i)));
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn memcpy(dst: *mut u8, src: *const u8, len: usize) {
    for i in 0..len as isize {
        ptr::write(dst.offset(i), ptr::read(src.offset(i)));
    }
}

#[no_mangle]
pub unsafe extern "C" fn memset(dst: *mut u8, c: i32, len: usize) {
    for i in 0..len as isize {
        ptr::write(dst.offset(i), c as u8);
    }
}

#[no_mangle]
#[cfg(target_arch = "x86")]
/// 64 bit remainder on 32 bit arch
pub extern "C" fn __umoddi3(mut a: u64, mut b: u64) -> u64 {
    let mut hig = a >> 32; // The first 32 bits of a
    let mut d   = 1;

    if hig >= b {
        hig /= b;
        a -= (hig * b) << 32;
    }

    while b > 0 && b < a {
        b *= 2;
        d *= 2;
    }

    loop {
        if a >= b {
            a -= b;
        }
        b >>= 1;
        d >>= 1;

        if d == 0 {
            break;
        }
    }

    a
}

#[no_mangle]
#[cfg(target_arch = "x86")]
/// 64 bit division on 32 bit arch
pub extern "C" fn __udivdi3(mut a: u64, mut b: u64) -> u64 {
    let mut res = 0;
    let mut hig = a >> 32; // The first 32 bits of a
    let mut d   = 1;

    if hig >= b {
        hig /= b;
        res = hig << 32;
        a -= (hig * b) << 32;
    }

    while b > 0 && b < a {
        b *= 2;
        d *= 2;
    }

    loop {
        if a >= b {
            a -= b;
            res += d;
        }
        b >>= 1;
        d >>= 1;

        if d == 0 {
            break;
        }
    }

    res
}

#[no_mangle]
#[cfg(target_arch = "x86")]
/// 64 bit division and rem on 32 bit arch
pub extern "C" fn __udivremi3(mut a: u64, mut b: u64) -> (u64, u64) {
    let mut res = 0;
    let mut hig = a >> 32; // The first 32 bits of a
    let mut d   = 1;

    if hig >= b {
        hig /= b;
        res = hig << 32;
        a -= (hig * b) << 32;
    }

    while b > 0 && b < a {
        b *= 2;
        d *= 2;
    }

    loop {
        if a >= b {
            a -= b;
            res += d;
        }
        b >>= 1;
        d >>= 1;

        if d == 0 {
            break;
        }
    }

    (res, a)
}
<|endoftext|>


<commit_before><commit_msg>Rust playground updates<commit_after><|endoftext|>


<commit_before><commit_msg>Chapter about ownership escape.<commit_after><|endoftext|>


<commit_before><commit_msg>day 23 solved.<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::collections::HashMap;

#[derive(Clone)]
enum Instr { // been a while since enums were required
    Hlf(String),        // halve
    Tpl(String),        // triple
    Inc(String),        // increment
    Jmp(i32),           // jump
    Jie(String, i32),   // jump if even
    Jio(String, i32)    // jump if one
}

fn parse_offset(s: String) -> i32 {
    let mut rev: String = s.chars().rev().collect();
    let sign = rev.pop();
    rev = rev.chars().rev().collect();
    let offset: i32 = rev.parse().ok().expect("Could not parse into an integer!");
    if sign == Some('-') {
        -offset
    } else {
        offset
    }
}

fn main() {
    let mut f = File::open(Path::new("/Users/PetarV/rust-proj/advent-of-rust/target/input.txt"))
    	.ok()
    	.expect("Failed to open the input file!");

	let mut input = String::new();
	f.read_to_string(&mut input)
		.ok()
		.expect("Failed to read from the input file!");

    let mut instrs = Vec::new();

    for line in input.lines() {
        let parts: Vec<_> = line.split_whitespace().collect();
        if parts[0] == "hlf" {
            instrs.push(Instr::Hlf(parts[1].to_string()));
        } else if parts[0] == "tpl" {
            instrs.push(Instr::Tpl(parts[1].to_string()));
        } else if parts[0] == "inc" {
            instrs.push(Instr::Inc(parts[1].to_string()));
        } else if parts[0] == "jmp" {
            instrs.push(Instr::Jmp(parse_offset(parts[1].to_string())));
        } else if parts[0] == "jie" {
            let mut reg_str = parts[1].to_string(); reg_str.pop();
            instrs.push(Instr::Jie(reg_str, parse_offset(parts[2].to_string())));
        } else if parts[0] == "jio" {
            let mut reg_str = parts[1].to_string(); reg_str.pop();
            instrs.push(Instr::Jio(reg_str, parse_offset(parts[2].to_string())));
        }
    }

    let mut pc = 0 as i32;
    let mut state = HashMap::new();
    state.insert("a".to_string(), 0);
    state.insert("b".to_string(), 0);

    while 0 <= pc && pc < instrs.len() as i32 {
        match instrs[pc as usize].clone() {
            Instr::Hlf(x)      => {
                let curr = state[&x];
                state.insert(x, curr >> 1);
                pc += 1;
            },
            Instr::Tpl(x)      => {
                let curr = state[&x];
                state.insert(x, curr * 3);
                pc += 1;
            },
            Instr::Inc(x)      => {
                let curr = state[&x];
                state.insert(x, curr + 1);
                pc += 1;
            },
            Instr::Jmp(off)    => {
                pc += off;
            },
            Instr::Jie(x, off) => {
                if state[&x] & 1 == 0 {
                    pc += off;
                } else {
                    pc += 1;
                }
            },
            Instr::Jio(x, off) => {
                if state[&x] == 1 {
                    pc += off;
                } else {
                    pc += 1;
                }
            }
        }
    }

    println!("The final state of register b is {}.", state[&"b".to_string()]);

    state.insert("a".to_string(), 1);
    state.insert("b".to_string(), 0);
    pc = 0;

    while 0 <= pc && pc < instrs.len() as i32 {
        match instrs[pc as usize].clone() {
            Instr::Hlf(x)      => {
                let curr = state[&x];
                state.insert(x, curr >> 1);
                pc += 1;
            },
            Instr::Tpl(x)      => {
                let curr = state[&x];
                state.insert(x, curr * 3);
                pc += 1;
            },
            Instr::Inc(x)      => {
                let curr = state[&x];
                state.insert(x, curr + 1);
                pc += 1;
            },
            Instr::Jmp(off)    => {
                pc += off;
            },
            Instr::Jie(x, off) => {
                if state[&x] & 1 == 0 {
                    pc += off;
                } else {
                    pc += 1;
                }
            },
            Instr::Jio(x, off) => {
                if state[&x] == 1 {
                    pc += off;
                } else {
                    pc += 1;
                }
            }
        }
    }

    println!("Should a start at one, the final state of register b is {}.", state[&"b".to_string()]);
}<|endoftext|>


<commit_before>#![crate_type = "bin"]
#![feature(lang_items)]
#![feature(panic_implementation)]
#![no_main]
#![no_std]

use core::panic::PanicInfo;

#[panic_implementation]
fn panic(_: &PanicInfo) -> ! {
    loop {}
}

#[lang = "eh_personality"]
fn eh() {}

#[lang = "oom"]
fn oom() {}
<commit_msg>fix tidy<commit_after>// Copyright 2018 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.

#![crate_type = "bin"]
#![feature(lang_items)]
#![feature(panic_implementation)]
#![no_main]
#![no_std]

use core::panic::PanicInfo;

#[panic_implementation]
fn panic(_: &PanicInfo) -> ! {
    loop {}
}

#[lang = "eh_personality"]
fn eh() {}

#[lang = "oom"]
fn oom() {}
<|endoftext|>


<commit_before>// Copyright 2013 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.

//! A native mutex and condition variable type
//!
//! This module contains bindings to the platform's native mutex/condition
//! variable primitives. It provides a single type, `Mutex`, which can be
//! statically initialized via the `MUTEX_INIT` value. This object serves as both a
//! mutex and a condition variable simultaneously.
//!
//! The lock is lazily initialized, but it can only be unsafely destroyed. A
//! statically initialized lock doesn't necessarily have a time at which it can
//! get deallocated. For this reason, there is no `Drop` implementation of the
//! mutex, but rather the `destroy()` method must be invoked manually if
//! destruction of the mutex is desired.
//!
//! It is not recommended to use this type for idiomatic rust use. This type is
//! appropriate where no other options are available, but other rust concurrency
//! primitives should be used before this type.
//!
//! # Example
//!
//!     use std::unstable::mutex::{Mutex, MUTEX_INIT};
//!
//!     // Use a statically initialized mutex
//!     static mut lock: Mutex = MUTEX_INIT;
//!
//!     unsafe {
//!         lock.lock();
//!         lock.unlock();
//!     }
//!
//!     // Use a normally initialized mutex
//!     let mut lock = Mutex::new();
//!     unsafe {
//!         lock.lock();
//!         lock.unlock();
//!         lock.destroy();
//!     }

#[allow(non_camel_case_types)];

use libc::c_void;
use sync::atomics;

pub struct Mutex {
    // pointers for the lock/cond handles, atomically updated
    priv lock: atomics::AtomicUint,
    priv cond: atomics::AtomicUint,
}

pub static MUTEX_INIT: Mutex = Mutex {
    lock: atomics::INIT_ATOMIC_UINT,
    cond: atomics::INIT_ATOMIC_UINT,
};

impl Mutex {
    /// Creates a new mutex, with the lock/condition variable pre-initialized
    pub unsafe fn new() -> Mutex {
        Mutex {
            lock: atomics::AtomicUint::new(imp::init_lock() as uint),
            cond: atomics::AtomicUint::new(imp::init_cond() as uint),
        }
    }

    /// Creates a new mutex, with the lock/condition variable not initialized.
    /// This is the same as initializing from the MUTEX_INIT static.
    pub unsafe fn empty() -> Mutex {
        Mutex {
            lock: atomics::AtomicUint::new(0),
            cond: atomics::AtomicUint::new(0),
        }
    }

    /// Creates a new copy of this mutex. This is an unsafe operation because
    /// there is no reference counting performed on this type.
    ///
    /// This function may only be called on mutexes which have had both the
    /// internal condition variable and lock initialized. This means that the
    /// mutex must have been created via `new`, or usage of it has already
    /// initialized the internal handles.
    ///
    /// This is a dangerous function to call as both this mutex and the returned
    /// mutex will share the same handles to the underlying mutex/condition
    /// variable. Care must be taken to ensure that deallocation happens
    /// accordingly.
    pub unsafe fn clone(&self) -> Mutex {
        let lock = self.lock.load(atomics::Relaxed);
        let cond = self.cond.load(atomics::Relaxed);
        assert!(lock != 0);
        assert!(cond != 0);
        Mutex {
            lock: atomics::AtomicUint::new(lock),
            cond: atomics::AtomicUint::new(cond),
        }
    }

    /// Acquires this lock. This assumes that the current thread does not
    /// already hold the lock.
    pub unsafe fn lock(&mut self) { imp::lock(self.getlock()) }

    /// Attempts to acquire the lock. The value returned is whether the lock was
    /// acquired or not
    pub unsafe fn trylock(&mut self) -> bool { imp::trylock(self.getlock()) }

    /// Unlocks the lock. This assumes that the current thread already holds the
    /// lock.
    pub unsafe fn unlock(&mut self) { imp::unlock(self.getlock()) }

    /// Block on the internal condition variable.
    ///
    /// This function assumes that the lock is already held
    pub unsafe fn wait(&mut self) { imp::wait(self.getcond(), self.getlock()) }

    /// Signals a thread in `wait` to wake up
    pub unsafe fn signal(&mut self) { imp::signal(self.getcond()) }

    /// This function is especially unsafe because there are no guarantees made
    /// that no other thread is currently holding the lock or waiting on the
    /// condition variable contained inside.
    pub unsafe fn destroy(&mut self) {
        let lock = self.lock.swap(0, atomics::Relaxed);
        let cond = self.cond.swap(0, atomics::Relaxed);
        if lock != 0 { imp::free_lock(lock) }
        if cond != 0 { imp::free_cond(cond) }
    }

    unsafe fn getlock(&mut self) -> *c_void {
        match self.lock.load(atomics::Relaxed) {
            0 => {}
            n => return n as *c_void
        }
        let lock = imp::init_lock();
        match self.lock.compare_and_swap(0, lock, atomics::SeqCst) {
            0 => return lock as *c_void,
            _ => {}
        }
        imp::free_lock(lock);
        return self.lock.load(atomics::Relaxed) as *c_void;
    }

    unsafe fn getcond(&mut self) -> *c_void {
        match self.cond.load(atomics::Relaxed) {
            0 => {}
            n => return n as *c_void
        }
        let cond = imp::init_cond();
        match self.cond.compare_and_swap(0, cond, atomics::SeqCst) {
            0 => return cond as *c_void,
            _ => {}
        }
        imp::free_cond(cond);
        return self.cond.load(atomics::Relaxed) as *c_void;
    }
}

#[cfg(unix)]
mod imp {
    use libc::c_void;
    use libc;
    use ptr;

    type pthread_mutex_t = libc::c_void;
    type pthread_mutexattr_t = libc::c_void;
    type pthread_cond_t = libc::c_void;
    type pthread_condattr_t = libc::c_void;

    pub unsafe fn init_lock() -> uint {
        let block = libc::malloc(rust_pthread_mutex_t_size() as libc::size_t);
        assert!(!block.is_null());
        let n = pthread_mutex_init(block, ptr::null());
        assert_eq!(n, 0);
        return block as uint;
    }

    pub unsafe fn init_cond() -> uint {
        let block = libc::malloc(rust_pthread_cond_t_size() as libc::size_t);
        assert!(!block.is_null());
        let n = pthread_cond_init(block, ptr::null());
        assert_eq!(n, 0);
        return block as uint;
    }

    pub unsafe fn free_lock(h: uint) {
        let block = h as *c_void;
        assert_eq!(pthread_mutex_destroy(block), 0);
        libc::free(block);
    }

    pub unsafe fn free_cond(h: uint) {
        let block = h as *c_void;
        assert_eq!(pthread_cond_destroy(block), 0);
        libc::free(block);
    }

    pub unsafe fn lock(l: *pthread_mutex_t) {
        assert_eq!(pthread_mutex_lock(l), 0);
    }

    pub unsafe fn trylock(l: *c_void) -> bool {
        pthread_mutex_trylock(l) == 0
    }

    pub unsafe fn unlock(l: *pthread_mutex_t) {
        assert_eq!(pthread_mutex_unlock(l), 0);
    }

    pub unsafe fn wait(cond: *pthread_cond_t, m: *pthread_mutex_t) {
        assert_eq!(pthread_cond_wait(cond, m), 0);
    }

    pub unsafe fn signal(cond: *pthread_cond_t) {
        assert_eq!(pthread_cond_signal(cond), 0);
    }

    extern {
        fn rust_pthread_mutex_t_size() -> libc::c_int;
        fn rust_pthread_cond_t_size() -> libc::c_int;
    }

    extern {
        fn pthread_mutex_init(lock: *pthread_mutex_t,
                              attr: *pthread_mutexattr_t) -> libc::c_int;
        fn pthread_mutex_destroy(lock: *pthread_mutex_t) -> libc::c_int;
        fn pthread_cond_init(cond: *pthread_cond_t,
                              attr: *pthread_condattr_t) -> libc::c_int;
        fn pthread_cond_destroy(cond: *pthread_cond_t) -> libc::c_int;
        fn pthread_mutex_lock(lock: *pthread_mutex_t) -> libc::c_int;
        fn pthread_mutex_trylock(lock: *pthread_mutex_t) -> libc::c_int;
        fn pthread_mutex_unlock(lock: *pthread_mutex_t) -> libc::c_int;

        fn pthread_cond_wait(cond: *pthread_cond_t,
                             lock: *pthread_mutex_t) -> libc::c_int;
        fn pthread_cond_signal(cond: *pthread_cond_t) -> libc::c_int;
    }
}

#[cfg(windows)]
mod imp {
    use libc;
    use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR};
    use ptr;
    type LPCRITICAL_SECTION = *c_void;
    static SPIN_COUNT: DWORD = 4000;

    pub unsafe fn init_lock() -> uint {
        let block = libc::malloc(rust_crit_section_size() as libc::size_t);
        assert!(!block.is_null());
        InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
        return block as uint;
    }

    pub unsafe fn init_cond() -> uint {
        return CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
                            ptr::null()) as uint;
    }

    pub unsafe fn free_lock(h: uint) {
        DeleteCriticalSection(h as LPCRITICAL_SECTION);
        libc::free(h as *c_void);
    }

    pub unsafe fn free_cond(h: uint) {
        let block = h as HANDLE;
        libc::CloseHandle(block);
    }

    pub unsafe fn lock(l: *c_void) {
        EnterCriticalSection(l as LPCRITICAL_SECTION)
    }

    pub unsafe fn trylock(l: *c_void) -> bool {
        TryEnterCriticalSection(l as LPCRITICAL_SECTION) != 0
    }

    pub unsafe fn unlock(l: *c_void) {
        LeaveCriticalSection(l as LPCRITICAL_SECTION)
    }

    pub unsafe fn wait(cond: *c_void, m: *c_void) {
        unlock(m);
        WaitForSingleObject(cond as HANDLE, 0);
        lock(m);
    }

    pub unsafe fn signal(cond: *c_void) {
        assert!(SetEvent(cond as HANDLE) != 0);
    }

    extern {
        fn rust_crit_section_size() -> libc::c_int;
    }

    extern "system" {
        fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
                        bManualReset: BOOL,
                        bInitialState: BOOL,
                        lpName: LPCSTR) -> HANDLE;
        fn InitializeCriticalSectionAndSpinCount(
                        lpCriticalSection: LPCRITICAL_SECTION,
                        dwSpinCount: DWORD) -> BOOL;
        fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
        fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
        fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
        fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL;
        fn SetEvent(hEvent: HANDLE) -> BOOL;
        fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
    }
}

#[cfg(test)]
mod test {
    use super::{Mutex, MUTEX_INIT};
    use rt::thread::Thread;

    #[test]
    fn somke_lock() {
        static mut lock: Mutex = MUTEX_INIT;
        unsafe {
            lock.lock();
            lock.unlock();
        }
    }

    #[test]
    fn somke_cond() {
        static mut lock: Mutex = MUTEX_INIT;
        unsafe {
            lock.lock();
            let t = do Thread::start {
                lock.lock();
                lock.signal();
                lock.unlock();
            };
            lock.wait();
            lock.unlock();
            t.join();
        }
    }

    #[test]
    fn destroy_immediately() {
        unsafe {
            let mut m = Mutex::empty();
            m.destroy();
        }
    }
}
<commit_msg>Implement a Once primitive for initialization<commit_after>// Copyright 2013 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.

//! A native mutex and condition variable type
//!
//! This module contains bindings to the platform's native mutex/condition
//! variable primitives. It provides a single type, `Mutex`, which can be
//! statically initialized via the `MUTEX_INIT` value. This object serves as both a
//! mutex and a condition variable simultaneously.
//!
//! The lock is lazily initialized, but it can only be unsafely destroyed. A
//! statically initialized lock doesn't necessarily have a time at which it can
//! get deallocated. For this reason, there is no `Drop` implementation of the
//! mutex, but rather the `destroy()` method must be invoked manually if
//! destruction of the mutex is desired.
//!
//! It is not recommended to use this type for idiomatic rust use. This type is
//! appropriate where no other options are available, but other rust concurrency
//! primitives should be used before this type.
//!
//! # Example
//!
//!     use std::unstable::mutex::{Mutex, MUTEX_INIT};
//!
//!     // Use a statically initialized mutex
//!     static mut lock: Mutex = MUTEX_INIT;
//!
//!     unsafe {
//!         lock.lock();
//!         lock.unlock();
//!     }
//!
//!     // Use a normally initialized mutex
//!     let mut lock = Mutex::new();
//!     unsafe {
//!         lock.lock();
//!         lock.unlock();
//!         lock.destroy();
//!     }

#[allow(non_camel_case_types)];

use libc::c_void;
use sync::atomics;

pub struct Mutex {
    // pointers for the lock/cond handles, atomically updated
    priv lock: atomics::AtomicUint,
    priv cond: atomics::AtomicUint,
}

pub static MUTEX_INIT: Mutex = Mutex {
    lock: atomics::INIT_ATOMIC_UINT,
    cond: atomics::INIT_ATOMIC_UINT,
};

impl Mutex {
    /// Creates a new mutex, with the lock/condition variable pre-initialized
    pub unsafe fn new() -> Mutex {
        Mutex {
            lock: atomics::AtomicUint::new(imp::init_lock() as uint),
            cond: atomics::AtomicUint::new(imp::init_cond() as uint),
        }
    }

    /// Creates a new mutex, with the lock/condition variable not initialized.
    /// This is the same as initializing from the MUTEX_INIT static.
    pub unsafe fn empty() -> Mutex {
        Mutex {
            lock: atomics::AtomicUint::new(0),
            cond: atomics::AtomicUint::new(0),
        }
    }

    /// Creates a new copy of this mutex. This is an unsafe operation because
    /// there is no reference counting performed on this type.
    ///
    /// This function may only be called on mutexes which have had both the
    /// internal condition variable and lock initialized. This means that the
    /// mutex must have been created via `new`, or usage of it has already
    /// initialized the internal handles.
    ///
    /// This is a dangerous function to call as both this mutex and the returned
    /// mutex will share the same handles to the underlying mutex/condition
    /// variable. Care must be taken to ensure that deallocation happens
    /// accordingly.
    pub unsafe fn clone(&self) -> Mutex {
        let lock = self.lock.load(atomics::Relaxed);
        let cond = self.cond.load(atomics::Relaxed);
        assert!(lock != 0);
        assert!(cond != 0);
        Mutex {
            lock: atomics::AtomicUint::new(lock),
            cond: atomics::AtomicUint::new(cond),
        }
    }

    /// Acquires this lock. This assumes that the current thread does not
    /// already hold the lock.
    pub unsafe fn lock(&mut self) { imp::lock(self.getlock()) }

    /// Attempts to acquire the lock. The value returned is whether the lock was
    /// acquired or not
    pub unsafe fn trylock(&mut self) -> bool { imp::trylock(self.getlock()) }

    /// Unlocks the lock. This assumes that the current thread already holds the
    /// lock.
    pub unsafe fn unlock(&mut self) { imp::unlock(self.getlock()) }

    /// Block on the internal condition variable.
    ///
    /// This function assumes that the lock is already held
    pub unsafe fn wait(&mut self) { imp::wait(self.getcond(), self.getlock()) }

    /// Signals a thread in `wait` to wake up
    pub unsafe fn signal(&mut self) { imp::signal(self.getcond()) }

    /// This function is especially unsafe because there are no guarantees made
    /// that no other thread is currently holding the lock or waiting on the
    /// condition variable contained inside.
    pub unsafe fn destroy(&mut self) {
        let lock = self.lock.swap(0, atomics::Relaxed);
        let cond = self.cond.swap(0, atomics::Relaxed);
        if lock != 0 { imp::free_lock(lock) }
        if cond != 0 { imp::free_cond(cond) }
    }

    unsafe fn getlock(&mut self) -> *c_void {
        match self.lock.load(atomics::Relaxed) {
            0 => {}
            n => return n as *c_void
        }
        let lock = imp::init_lock();
        match self.lock.compare_and_swap(0, lock, atomics::SeqCst) {
            0 => return lock as *c_void,
            _ => {}
        }
        imp::free_lock(lock);
        return self.lock.load(atomics::Relaxed) as *c_void;
    }

    unsafe fn getcond(&mut self) -> *c_void {
        match self.cond.load(atomics::Relaxed) {
            0 => {}
            n => return n as *c_void
        }
        let cond = imp::init_cond();
        match self.cond.compare_and_swap(0, cond, atomics::SeqCst) {
            0 => return cond as *c_void,
            _ => {}
        }
        imp::free_cond(cond);
        return self.cond.load(atomics::Relaxed) as *c_void;
    }
}

#[cfg(unix)]
mod imp {
    use libc::c_void;
    use libc;
    use ptr;

    type pthread_mutex_t = libc::c_void;
    type pthread_mutexattr_t = libc::c_void;
    type pthread_cond_t = libc::c_void;
    type pthread_condattr_t = libc::c_void;

    pub unsafe fn init_lock() -> uint {
        let block = libc::malloc(rust_pthread_mutex_t_size() as libc::size_t);
        assert!(!block.is_null());
        let n = pthread_mutex_init(block, ptr::null());
        assert_eq!(n, 0);
        return block as uint;
    }

    pub unsafe fn init_cond() -> uint {
        let block = libc::malloc(rust_pthread_cond_t_size() as libc::size_t);
        assert!(!block.is_null());
        let n = pthread_cond_init(block, ptr::null());
        assert_eq!(n, 0);
        return block as uint;
    }

    pub unsafe fn free_lock(h: uint) {
        let block = h as *c_void;
        assert_eq!(pthread_mutex_destroy(block), 0);
        libc::free(block);
    }

    pub unsafe fn free_cond(h: uint) {
        let block = h as *c_void;
        assert_eq!(pthread_cond_destroy(block), 0);
        libc::free(block);
    }

    pub unsafe fn lock(l: *pthread_mutex_t) {
        assert_eq!(pthread_mutex_lock(l), 0);
    }

    pub unsafe fn trylock(l: *c_void) -> bool {
        pthread_mutex_trylock(l) == 0
    }

    pub unsafe fn unlock(l: *pthread_mutex_t) {
        assert_eq!(pthread_mutex_unlock(l), 0);
    }

    pub unsafe fn wait(cond: *pthread_cond_t, m: *pthread_mutex_t) {
        assert_eq!(pthread_cond_wait(cond, m), 0);
    }

    pub unsafe fn signal(cond: *pthread_cond_t) {
        assert_eq!(pthread_cond_signal(cond), 0);
    }

    extern {
        fn rust_pthread_mutex_t_size() -> libc::c_int;
        fn rust_pthread_cond_t_size() -> libc::c_int;
    }

    extern {
        fn pthread_mutex_init(lock: *pthread_mutex_t,
                              attr: *pthread_mutexattr_t) -> libc::c_int;
        fn pthread_mutex_destroy(lock: *pthread_mutex_t) -> libc::c_int;
        fn pthread_cond_init(cond: *pthread_cond_t,
                              attr: *pthread_condattr_t) -> libc::c_int;
        fn pthread_cond_destroy(cond: *pthread_cond_t) -> libc::c_int;
        fn pthread_mutex_lock(lock: *pthread_mutex_t) -> libc::c_int;
        fn pthread_mutex_trylock(lock: *pthread_mutex_t) -> libc::c_int;
        fn pthread_mutex_unlock(lock: *pthread_mutex_t) -> libc::c_int;

        fn pthread_cond_wait(cond: *pthread_cond_t,
                             lock: *pthread_mutex_t) -> libc::c_int;
        fn pthread_cond_signal(cond: *pthread_cond_t) -> libc::c_int;
    }
}

#[cfg(windows)]
mod imp {
    use libc;
    use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR};
    use ptr;
    type LPCRITICAL_SECTION = *c_void;
    static SPIN_COUNT: DWORD = 4000;

    pub unsafe fn init_lock() -> uint {
        let block = libc::malloc(rust_crit_section_size() as libc::size_t);
        assert!(!block.is_null());
        InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
        return block as uint;
    }

    pub unsafe fn init_cond() -> uint {
        return CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
                            ptr::null()) as uint;
    }

    pub unsafe fn free_lock(h: uint) {
        DeleteCriticalSection(h as LPCRITICAL_SECTION);
        libc::free(h as *c_void);
    }

    pub unsafe fn free_cond(h: uint) {
        let block = h as HANDLE;
        libc::CloseHandle(block);
    }

    pub unsafe fn lock(l: *c_void) {
        EnterCriticalSection(l as LPCRITICAL_SECTION)
    }

    pub unsafe fn trylock(l: *c_void) -> bool {
        TryEnterCriticalSection(l as LPCRITICAL_SECTION) != 0
    }

    pub unsafe fn unlock(l: *c_void) {
        LeaveCriticalSection(l as LPCRITICAL_SECTION)
    }

    pub unsafe fn wait(cond: *c_void, m: *c_void) {
        unlock(m);
        WaitForSingleObject(cond as HANDLE, 0);
        lock(m);
    }

    pub unsafe fn signal(cond: *c_void) {
        assert!(SetEvent(cond as HANDLE) != 0);
    }

    extern {
        fn rust_crit_section_size() -> libc::c_int;
    }

    extern "system" {
        fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
                        bManualReset: BOOL,
                        bInitialState: BOOL,
                        lpName: LPCSTR) -> HANDLE;
        fn InitializeCriticalSectionAndSpinCount(
                        lpCriticalSection: LPCRITICAL_SECTION,
                        dwSpinCount: DWORD) -> BOOL;
        fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
        fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
        fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
        fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL;
        fn SetEvent(hEvent: HANDLE) -> BOOL;
        fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
    }
}

/// A type which can be used to run a one-time global initialization. This type
/// is *unsafe* to use because it is built on top of the `Mutex` in this module.
/// It does not know whether the currently running task is in a green or native
/// context, and a blocking mutex should *not* be used under normal
/// circumstances on a green task.
///
/// Despite its unsafety, it is often useful to have a one-time initialization
/// routine run for FFI bindings or related external functionality. This type
/// can only be statically constructed with the `ONCE_INIT` value.
///
/// # Example
///
/// ```rust
/// use std::unstable::mutex::{Once, ONCE_INIT};
///
/// static mut START: Once = ONCE_INIT;
/// unsafe {
///     START.doit(|| {
///         // run initialization here
///     });
/// }
/// ```
pub struct Once {
    priv mutex: Mutex,
    priv cnt: AtomicInt,
    priv lock_cnt: AtomicInt,
}

/// Initialization value for static `Once` values.
pub static ONCE_INIT: Once = Once {
    mutex: MUTEX_INIT,
    cnt: INIT_ATOMIC_INT,
    lock_cnt: INIT_ATOMIC_INT,
};

impl Once {
    /// Perform an initialization routine once and only once. The given closure
    /// will be executed if this is the first time `doit` has been called, and
    /// otherwise the routine will *not* be invoked.
    ///
    /// This method will block the calling *os thread* if another initialization
    /// routine is currently running.
    ///
    /// When this function returns, it is guaranteed that some initialization
    /// has run and completed (it may not be the closure specified).
    pub fn doit(&mut self, f: ||) {
        // Implementation-wise, this would seem like a fairly trivial primitive.
        // The stickler part is where our mutexes currently require an
        // allocation, and usage of a `Once` should't leak this allocation.
        //
        // This means that there must be a deterministic destroyer of the mutex
        // contained within (because it's not needed after the initialization
        // has run).
        //
        // The general scheme here is to gate all future threads once
        // initialization has completed with a "very negative" count, and to
        // allow through threads to lock the mutex if they see a non negative
        // count. For all threads grabbing the mutex, exactly one of them should
        // be responsible for unlocking the mutex, and this should only be done
        // once everyone else is done with the mutex.
        //
        // This atomicity is achieved by swapping a very negative value into the
        // shared count when the initialization routine has completed. This will
        // read the number of threads which will at some point attempt to
        // acquire the mutex. This count is then squirreled away in a separate
        // variable, and the last person on the way out of the mutex is then
        // responsible for destroying the mutex.
        //
        // It is crucial that the negative value is swapped in *after* the
        // initialization routine has completed because otherwise new threads
        // calling `doit` will return immediately before the initialization has
        // completed.

        let prev = self.cnt.fetch_add(1, SeqCst);
        if prev < 0 {
            // Make sure we never overflow, we'll never have int::min_value
            // simultaneous calls to `doit` to make this value go back to 0
            self.cnt.store(int::min_value, SeqCst);
            return
        }

        // If the count is negative, then someone else finished the job,
        // otherwise we run the job and record how many people will try to grab
        // this lock
        unsafe { self.mutex.lock() }
        if self.cnt.load(SeqCst) > 0 {
            f();
            let prev = self.cnt.swap(int::min_value, SeqCst);
            self.lock_cnt.store(prev, SeqCst);
        }
        unsafe { self.mutex.unlock() }

        // Last one out cleans up after everyone else, no leaks!
        if self.lock_cnt.fetch_add(-1, SeqCst) == 1 {
            unsafe { self.mutex.destroy() }
        }
    }
}

#[cfg(test)]
mod test {
    use rt::thread::Thread;
    use super::{ONCE_INIT, Once, Mutex, MUTEX_INIT};
    use task;

    #[test]
    fn smoke_once() {
        static mut o: Once = ONCE_INIT;
        let mut a = 0;
        unsafe { o.doit(|| a += 1); }
        assert_eq!(a, 1);
        unsafe { o.doit(|| a += 1); }
        assert_eq!(a, 1);
    }

    #[test]
    fn stampede_once() {
        static mut o: Once = ONCE_INIT;
        static mut run: bool = false;

        let (p, c) = SharedChan::new();
        for _ in range(0, 10) {
            let c = c.clone();
            do spawn {
                for _ in range(0, 4) { task::deschedule() }
                unsafe {
                    o.doit(|| {
                        assert!(!run);
                        run = true;
                    });
                    assert!(run);
                }
                c.send(());
            }
        }

        unsafe {
            o.doit(|| {
                assert!(!run);
                run = true;
            });
            assert!(run);
        }

        for _ in range(0, 10) {
            p.recv();
        }
    }

    #[test]
    fn somke_lock() {
        static mut lock: Mutex = MUTEX_INIT;
        unsafe {
            lock.lock();
            lock.unlock();
        }
    }

    #[test]
    fn somke_cond() {
        static mut lock: Mutex = MUTEX_INIT;
        unsafe {
            lock.lock();
            let t = do Thread::start {
                lock.lock();
                lock.signal();
                lock.unlock();
            };
            lock.wait();
            lock.unlock();
            t.join();
        }
    }

    #[test]
    fn destroy_immediately() {
        unsafe {
            let mut m = Mutex::empty();
            m.destroy();
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Add IVec implementation for inlinable boxed slices<commit_after>use super::*;

use std::{fmt, ops::Deref};

const INLINE_LEN_MASK: u8 = 0b0000_1111;
const KIND_MASK: u8 = 0b1111_0000;
const KIND_INLINE: u8 = 0b1000_0000;
const KIND_OWNED: u8 = 0b0100_0000;
const KIND_BORROWED: u8 = 0b0010_0000;

#[derive(Default, Ord, Eq, Serialize, Deserialize)]
pub(crate) struct IVec {
    #[serde(with = "ser")]
    data: [u8; 16],
}

impl IVec {
    pub(crate) fn new(v: Vec<u8>) -> IVec {
        if v.len() <= 15 {
            let sz = v.len() as u8;
            let tag = KIND_INLINE | sz;

            let mut data = [0u8; 16];
            data[15] = tag;
            data[0..v.len()].copy_from_slice(&v[0..v.len()]);

            IVec { data }
        } else {
            let bs = v.into_boxed_slice();
            let ptr: *mut _ = Box::into_raw(bs);
            let mut data: [u8; 16] =
                unsafe { std::mem::transmute(ptr) };

            assert_eq!(
                data[15],
                0,
                "we incorrectly assumed that we could use \
                the highest bits in the length field. please \
                report this bug ASAP!"
            );

            data[15] = KIND_OWNED;

            IVec { data }
        }
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> IVec {
        IVec::new(v)
    }
}

impl Deref for IVec {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        let tag = self.data[15];
        let kind = tag & KIND_MASK;
        match kind {
            k if k == KIND_INLINE => {
                let base = self.data.as_ptr();
                let len = (tag & INLINE_LEN_MASK) as usize;
                unsafe { std::slice::from_raw_parts(base, len) }
            }
            k if (k == KIND_OWNED || k == KIND_BORROWED) => {
                let mut data = self.data.clone();
                data[15] = 0;
                let ptr: *mut [u8] =
                    unsafe { std::mem::transmute(data) };

                unsafe { &*ptr }
            }
            other => {
                panic!("unknown kind {}", other);
            }
        }
    }
}

impl Clone for IVec {
    fn clone(&self) -> IVec {
        self.to_vec().into()
    }
}

impl Drop for IVec {
    fn drop(&mut self) {
        let tag = self.data[15];
        let kind = tag & KIND_MASK;
        match kind {
            k if k == KIND_OWNED => {
                let mut data = self.data.clone();
                data[15] = 0;
                let ptr: *mut [u8] =
                    unsafe { std::mem::transmute(data) };
                let b: Box<[u8]> = unsafe { Box::from_raw(ptr) };
                drop(b);
            }
            _ => {
                // no owned remote storage
            }
        }
    }
}

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

impl PartialEq for IVec {
    fn eq(&self, other: &IVec) -> bool {
        self.deref() == other.deref()
    }
}

impl<'a, T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.deref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.deref() == other
    }
}

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "IVec( {:?} )", self.deref())
    }
}

pub(crate) mod ser {
    use super::IVec;

    use std::ops::Deref;

    use serde::de::{Deserialize, Deserializer};
    use serde::ser::Serializer;

    pub(crate) fn serialize<S>(
        data: &[u8; 16],
        serializer: S,
    ) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let iv = IVec { data: *data };
        let ivr: &[u8] = iv.deref();
        serializer.collect_seq(ivr)
    }

    pub(crate) fn deserialize<'de, D>(
        deserializer: D,
    ) -> Result<[u8; 16], D::Error>
    where
        D: Deserializer<'de>,
    {
        let v = Vec::<u8>::deserialize(deserializer)?;
        let iv: IVec = v.into();
        let data: [u8; 16] = iv.data;
        std::mem::forget(iv);
        Ok(data)
    }
}

#[test]
fn ivec_usage() {
    let iv1: IVec = vec![1, 2, 3].into();
    assert_eq!(iv1, vec![1, 2, 3]);
    let iv2 = IVec::new(vec![4; 128]);
    assert_eq!(iv2, vec![4; 128]);
}
<|endoftext|>