<commit_before>use hir::{db::AstDatabase, HirDisplay, Type};
use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
use syntax::{
    ast::{BlockExpr, ExprStmt},
    AstNode,
};
use text_edit::TextEdit;

use crate::{fix, Assist, Diagnostic, DiagnosticsContext};

// Diagnostic: type-mismatch
//
// This diagnostic is triggered when the type of an expression does not match
// the expected type.
pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic {
    let mut diag = Diagnostic::new(
        "type-mismatch",
        format!(
            "expected {}, found {}",
            d.expected.display(ctx.sema.db),
            d.actual.display(ctx.sema.db)
        ),
        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
    )
    .with_fixes(fixes(ctx, d));
    if diag.fixes.is_none() {
        diag.experimental = true;
    }
    diag
}

fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> {
    let mut fixes = Vec::new();

    add_reference(ctx, d, &mut fixes);
    add_missing_ok_or_some(ctx, d, &mut fixes);
    remove_semicolon(ctx, d, &mut fixes);
    str_ref_to_string(ctx, d, &mut fixes);

    if fixes.is_empty() {
        None
    } else {
        Some(fixes)
    }
}

fn add_reference(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr_node = d.expr.value.to_node(&root);

    let range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range;

    let (_, mutability) = d.expected.as_reference()?;
    let actual_with_ref = Type::reference(&d.actual, mutability);
    if !actual_with_ref.could_coerce_to(ctx.sema.db, &d.expected) {
        return None;
    }

    let ampersands = format!("&{}", mutability.as_keyword_for_ref());

    let edit = TextEdit::insert(expr_node.syntax().text_range().start(), ampersands);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
    acc.push(fix("add_reference_here", "Add reference here", source_change, range));
    Some(())
}

fn add_missing_ok_or_some(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    let expr_range = expr.syntax().text_range();
    let scope = ctx.sema.scope(expr.syntax())?;

    let expected_adt = d.expected.as_adt()?;
    let expected_enum = expected_adt.as_enum()?;

    let famous_defs = FamousDefs(&ctx.sema, scope.krate());
    let core_result = famous_defs.core_result_Result();
    let core_option = famous_defs.core_option_Option();

    if Some(expected_enum) != core_result && Some(expected_enum) != core_option {
        return None;
    }

    let variant_name = if Some(expected_enum) == core_result { "Ok" } else { "Some" };

    let wrapped_actual_ty = expected_adt.ty_with_args(ctx.sema.db, &[d.actual.clone()]);

    if !d.expected.could_unify_with(ctx.sema.db, &wrapped_actual_ty) {
        return None;
    }

    let mut builder = TextEdit::builder();
    builder.insert(expr.syntax().text_range().start(), format!("{}(", variant_name));
    builder.insert(expr.syntax().text_range().end(), ")".to_string());
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish());
    let name = format!("Wrap in {}", variant_name);
    acc.push(fix("wrap_in_constructor", &name, source_change, expr_range));
    Some(())
}

fn remove_semicolon(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    if !d.actual.is_unit() {
        return None;
    }
    let block = BlockExpr::cast(expr.syntax().clone())?;
    let expr_before_semi =
        block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?;
    let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original();
    if !type_before_semi.could_coerce_to(ctx.sema.db, &d.expected) {
        return None;
    }
    let semicolon_range = expr_before_semi.semicolon_token()?.text_range();

    let edit = TextEdit::delete(semicolon_range);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);

    acc.push(fix("remove_semicolon", "Remove this semicolon", source_change, semicolon_range));
    Some(())
}

fn str_ref_to_string(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let expected = d.expected.display(ctx.sema.db);
    let actual = d.actual.display(ctx.sema.db);

    if expected.to_string() != "String" || actual.to_string() != "&str" {
        return None;
    }

    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    let expr_range = expr.syntax().text_range();

    let to_string = format!(".to_string()");

    let edit = TextEdit::insert(expr.syntax().text_range().end(), to_string);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
    acc.push(fix("str_ref_to_string", "Use to_string() here", source_change, expr_range));

    Some(())
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_diagnostics, check_fix, check_no_fix};

    #[test]
    fn missing_reference() {
        check_diagnostics(
            r#"
fn main() {
    test(123);
       //^^^ 💡 error: expected &i32, found i32
}
fn test(arg: &i32) {}
"#,
        );
    }

    #[test]
    fn test_add_reference_to_int() {
        check_fix(
            r#"
fn main() {
    test(123$0);
}
fn test(arg: &i32) {}
            "#,
            r#"
fn main() {
    test(&123);
}
fn test(arg: &i32) {}
            "#,
        );
    }

    #[test]
    fn test_add_mutable_reference_to_int() {
        check_fix(
            r#"
fn main() {
    test($0123);
}
fn test(arg: &mut i32) {}
            "#,
            r#"
fn main() {
    test(&mut 123);
}
fn test(arg: &mut i32) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_array() {
        check_fix(
            r#"
//- minicore: coerce_unsized
fn main() {
    test($0[1, 2, 3]);
}
fn test(arg: &[i32]) {}
            "#,
            r#"
fn main() {
    test(&[1, 2, 3]);
}
fn test(arg: &[i32]) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_with_autoderef() {
        check_fix(
            r#"
//- minicore: coerce_unsized, deref
struct Foo;
struct Bar;
impl core::ops::Deref for Foo {
    type Target = Bar;
}

fn main() {
    test($0Foo);
}
fn test(arg: &Bar) {}
            "#,
            r#"
struct Foo;
struct Bar;
impl core::ops::Deref for Foo {
    type Target = Bar;
}

fn main() {
    test(&Foo);
}
fn test(arg: &Bar) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_method_call() {
        check_fix(
            r#"
fn main() {
    Test.call_by_ref($0123);
}
struct Test;
impl Test {
    fn call_by_ref(&self, arg: &i32) {}
}
            "#,
            r#"
fn main() {
    Test.call_by_ref(&123);
}
struct Test;
impl Test {
    fn call_by_ref(&self, arg: &i32) {}
}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_let_stmt() {
        check_fix(
            r#"
fn main() {
    let test: &i32 = $0123;
}
            "#,
            r#"
fn main() {
    let test: &i32 = &123;
}
            "#,
        );
    }

    #[test]
    fn test_add_mutable_reference_to_let_stmt() {
        check_fix(
            r#"
fn main() {
    let test: &mut i32 = $0123;
}
            "#,
            r#"
fn main() {
    let test: &mut i32 = &mut 123;
}
            "#,
        );
    }

    #[test]
    fn test_wrap_return_type_option() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        return None;
    }
    x / y$0
}
"#,
            r#"
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        return None;
    }
    Some(x / y)
}
"#,
        );
    }

    #[test]
    fn const_generic_type_mismatch() {
        check_diagnostics(
            r#"
            pub struct Rate<const N: u32>;
            fn f<const N: u64>() -> Rate<N> { // FIXME: add some error
                loop {}
            }
            fn run(t: Rate<5>) {
            }
            fn main() {
                run(f()) // FIXME: remove this error
                  //^^^ error: expected Rate<5>, found Rate<_>
            }
"#,
        );
    }

    #[test]
    fn const_generic_unknown() {
        check_diagnostics(
            r#"
            pub struct Rate<T, const NOM: u32, const DENOM: u32>(T);
            fn run(t: Rate<u32, 1, 1>) {
            }
            fn main() {
                run(Rate::<_, _, _>(5));
            }
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_option_tails() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        Some(0)
    } else if true {
        100$0
    } else {
        None
    }
}
"#,
            r#"
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        Some(0)
    } else if true {
        Some(100)
    } else {
        None
    }
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Result<i32, ()> {
    if y == 0 {
        return Err(());
    }
    x / y$0
}
"#,
            r#"
fn div(x: i32, y: i32) -> Result<i32, ()> {
    if y == 0 {
        return Err(());
    }
    Ok(x / y)
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_handles_generic_functions() {
        check_fix(
            r#"
//- minicore: option, result
fn div<T>(x: T) -> Result<T, i32> {
    if x == 0 {
        return Err(7);
    }
    $0x
}
"#,
            r#"
fn div<T>(x: T) -> Result<T, i32> {
    if x == 0 {
        return Err(7);
    }
    Ok(x)
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_handles_type_aliases() {
        check_fix(
            r#"
//- minicore: option, result
type MyResult<T> = Result<T, ()>;

fn div(x: i32, y: i32) -> MyResult<i32> {
    if y == 0 {
        return Err(());
    }
    x $0/ y
}
"#,
            r#"
type MyResult<T> = Result<T, ()>;

fn div(x: i32, y: i32) -> MyResult<i32> {
    if y == 0 {
        return Err(());
    }
    Ok(x / y)
}
"#,
        );
    }

    #[test]
    fn test_in_const_and_static() {
        check_fix(
            r#"
//- minicore: option, result
static A: Option<()> = {($0)};
            "#,
            r#"
static A: Option<()> = {Some(())};
            "#,
        );
        check_fix(
            r#"
//- minicore: option, result
const _: Option<()> = {($0)};
            "#,
            r#"
const _: Option<()> = {Some(())};
            "#,
        );
    }

    #[test]
    fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
        check_no_fix(
            r#"
//- minicore: option, result
fn foo() -> Result<(), i32> { 0$0 }
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
        check_no_fix(
            r#"
//- minicore: option, result
enum SomeOtherEnum { Ok(i32), Err(String) }

fn foo() -> SomeOtherEnum { 0$0 }
"#,
        );
    }

    #[test]
    fn remove_semicolon() {
        check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);
    }

    #[test]
    fn str_ref_to_string() {
        check_fix(
            r#"
fn test() -> String {
    "a"$0
}
            "#,
            r#"
fn test() -> String {
    "a".to_string()
}
            "#,
        );
    }
}
<commit_msg>Fix test<commit_after>use hir::{db::AstDatabase, HirDisplay, Type};
use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
use syntax::{
    ast::{BlockExpr, ExprStmt},
    AstNode,
};
use text_edit::TextEdit;

use crate::{fix, Assist, Diagnostic, DiagnosticsContext};

// Diagnostic: type-mismatch
//
// This diagnostic is triggered when the type of an expression does not match
// the expected type.
pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic {
    let mut diag = Diagnostic::new(
        "type-mismatch",
        format!(
            "expected {}, found {}",
            d.expected.display(ctx.sema.db),
            d.actual.display(ctx.sema.db)
        ),
        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
    )
    .with_fixes(fixes(ctx, d));
    if diag.fixes.is_none() {
        diag.experimental = true;
    }
    diag
}

fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> {
    let mut fixes = Vec::new();

    add_reference(ctx, d, &mut fixes);
    add_missing_ok_or_some(ctx, d, &mut fixes);
    remove_semicolon(ctx, d, &mut fixes);
    str_ref_to_string(ctx, d, &mut fixes);

    if fixes.is_empty() {
        None
    } else {
        Some(fixes)
    }
}

fn add_reference(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr_node = d.expr.value.to_node(&root);

    let range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range;

    let (_, mutability) = d.expected.as_reference()?;
    let actual_with_ref = Type::reference(&d.actual, mutability);
    if !actual_with_ref.could_coerce_to(ctx.sema.db, &d.expected) {
        return None;
    }

    let ampersands = format!("&{}", mutability.as_keyword_for_ref());

    let edit = TextEdit::insert(expr_node.syntax().text_range().start(), ampersands);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
    acc.push(fix("add_reference_here", "Add reference here", source_change, range));
    Some(())
}

fn add_missing_ok_or_some(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    let expr_range = expr.syntax().text_range();
    let scope = ctx.sema.scope(expr.syntax())?;

    let expected_adt = d.expected.as_adt()?;
    let expected_enum = expected_adt.as_enum()?;

    let famous_defs = FamousDefs(&ctx.sema, scope.krate());
    let core_result = famous_defs.core_result_Result();
    let core_option = famous_defs.core_option_Option();

    if Some(expected_enum) != core_result && Some(expected_enum) != core_option {
        return None;
    }

    let variant_name = if Some(expected_enum) == core_result { "Ok" } else { "Some" };

    let wrapped_actual_ty = expected_adt.ty_with_args(ctx.sema.db, &[d.actual.clone()]);

    if !d.expected.could_unify_with(ctx.sema.db, &wrapped_actual_ty) {
        return None;
    }

    let mut builder = TextEdit::builder();
    builder.insert(expr.syntax().text_range().start(), format!("{}(", variant_name));
    builder.insert(expr.syntax().text_range().end(), ")".to_string());
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish());
    let name = format!("Wrap in {}", variant_name);
    acc.push(fix("wrap_in_constructor", &name, source_change, expr_range));
    Some(())
}

fn remove_semicolon(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    if !d.actual.is_unit() {
        return None;
    }
    let block = BlockExpr::cast(expr.syntax().clone())?;
    let expr_before_semi =
        block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?;
    let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original();
    if !type_before_semi.could_coerce_to(ctx.sema.db, &d.expected) {
        return None;
    }
    let semicolon_range = expr_before_semi.semicolon_token()?.text_range();

    let edit = TextEdit::delete(semicolon_range);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);

    acc.push(fix("remove_semicolon", "Remove this semicolon", source_change, semicolon_range));
    Some(())
}

fn str_ref_to_string(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::TypeMismatch,
    acc: &mut Vec<Assist>,
) -> Option<()> {
    let expected = d.expected.display(ctx.sema.db);
    let actual = d.actual.display(ctx.sema.db);

    if expected.to_string() != "String" || actual.to_string() != "&str" {
        return None;
    }

    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
    let expr = d.expr.value.to_node(&root);
    let expr_range = expr.syntax().text_range();

    let to_string = format!(".to_string()");

    let edit = TextEdit::insert(expr.syntax().text_range().end(), to_string);
    let source_change =
        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
    acc.push(fix("str_ref_to_string", "Add .to_string() here", source_change, expr_range));

    Some(())
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_diagnostics, check_fix, check_no_fix};

    #[test]
    fn missing_reference() {
        check_diagnostics(
            r#"
fn main() {
    test(123);
       //^^^ 💡 error: expected &i32, found i32
}
fn test(arg: &i32) {}
"#,
        );
    }

    #[test]
    fn test_add_reference_to_int() {
        check_fix(
            r#"
fn main() {
    test(123$0);
}
fn test(arg: &i32) {}
            "#,
            r#"
fn main() {
    test(&123);
}
fn test(arg: &i32) {}
            "#,
        );
    }

    #[test]
    fn test_add_mutable_reference_to_int() {
        check_fix(
            r#"
fn main() {
    test($0123);
}
fn test(arg: &mut i32) {}
            "#,
            r#"
fn main() {
    test(&mut 123);
}
fn test(arg: &mut i32) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_array() {
        check_fix(
            r#"
//- minicore: coerce_unsized
fn main() {
    test($0[1, 2, 3]);
}
fn test(arg: &[i32]) {}
            "#,
            r#"
fn main() {
    test(&[1, 2, 3]);
}
fn test(arg: &[i32]) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_with_autoderef() {
        check_fix(
            r#"
//- minicore: coerce_unsized, deref
struct Foo;
struct Bar;
impl core::ops::Deref for Foo {
    type Target = Bar;
}

fn main() {
    test($0Foo);
}
fn test(arg: &Bar) {}
            "#,
            r#"
struct Foo;
struct Bar;
impl core::ops::Deref for Foo {
    type Target = Bar;
}

fn main() {
    test(&Foo);
}
fn test(arg: &Bar) {}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_method_call() {
        check_fix(
            r#"
fn main() {
    Test.call_by_ref($0123);
}
struct Test;
impl Test {
    fn call_by_ref(&self, arg: &i32) {}
}
            "#,
            r#"
fn main() {
    Test.call_by_ref(&123);
}
struct Test;
impl Test {
    fn call_by_ref(&self, arg: &i32) {}
}
            "#,
        );
    }

    #[test]
    fn test_add_reference_to_let_stmt() {
        check_fix(
            r#"
fn main() {
    let test: &i32 = $0123;
}
            "#,
            r#"
fn main() {
    let test: &i32 = &123;
}
            "#,
        );
    }

    #[test]
    fn test_add_mutable_reference_to_let_stmt() {
        check_fix(
            r#"
fn main() {
    let test: &mut i32 = $0123;
}
            "#,
            r#"
fn main() {
    let test: &mut i32 = &mut 123;
}
            "#,
        );
    }

    #[test]
    fn test_wrap_return_type_option() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        return None;
    }
    x / y$0
}
"#,
            r#"
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        return None;
    }
    Some(x / y)
}
"#,
        );
    }

    #[test]
    fn const_generic_type_mismatch() {
        check_diagnostics(
            r#"
            pub struct Rate<const N: u32>;
            fn f<const N: u64>() -> Rate<N> { // FIXME: add some error
                loop {}
            }
            fn run(t: Rate<5>) {
            }
            fn main() {
                run(f()) // FIXME: remove this error
                  //^^^ error: expected Rate<5>, found Rate<_>
            }
"#,
        );
    }

    #[test]
    fn const_generic_unknown() {
        check_diagnostics(
            r#"
            pub struct Rate<T, const NOM: u32, const DENOM: u32>(T);
            fn run(t: Rate<u32, 1, 1>) {
            }
            fn main() {
                run(Rate::<_, _, _>(5));
            }
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_option_tails() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        Some(0)
    } else if true {
        100$0
    } else {
        None
    }
}
"#,
            r#"
fn div(x: i32, y: i32) -> Option<i32> {
    if y == 0 {
        Some(0)
    } else if true {
        Some(100)
    } else {
        None
    }
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type() {
        check_fix(
            r#"
//- minicore: option, result
fn div(x: i32, y: i32) -> Result<i32, ()> {
    if y == 0 {
        return Err(());
    }
    x / y$0
}
"#,
            r#"
fn div(x: i32, y: i32) -> Result<i32, ()> {
    if y == 0 {
        return Err(());
    }
    Ok(x / y)
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_handles_generic_functions() {
        check_fix(
            r#"
//- minicore: option, result
fn div<T>(x: T) -> Result<T, i32> {
    if x == 0 {
        return Err(7);
    }
    $0x
}
"#,
            r#"
fn div<T>(x: T) -> Result<T, i32> {
    if x == 0 {
        return Err(7);
    }
    Ok(x)
}
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_handles_type_aliases() {
        check_fix(
            r#"
//- minicore: option, result
type MyResult<T> = Result<T, ()>;

fn div(x: i32, y: i32) -> MyResult<i32> {
    if y == 0 {
        return Err(());
    }
    x $0/ y
}
"#,
            r#"
type MyResult<T> = Result<T, ()>;

fn div(x: i32, y: i32) -> MyResult<i32> {
    if y == 0 {
        return Err(());
    }
    Ok(x / y)
}
"#,
        );
    }

    #[test]
    fn test_in_const_and_static() {
        check_fix(
            r#"
//- minicore: option, result
static A: Option<()> = {($0)};
            "#,
            r#"
static A: Option<()> = {Some(())};
            "#,
        );
        check_fix(
            r#"
//- minicore: option, result
const _: Option<()> = {($0)};
            "#,
            r#"
const _: Option<()> = {Some(())};
            "#,
        );
    }

    #[test]
    fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
        check_no_fix(
            r#"
//- minicore: option, result
fn foo() -> Result<(), i32> { 0$0 }
"#,
        );
    }

    #[test]
    fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
        check_no_fix(
            r#"
//- minicore: option, result
enum SomeOtherEnum { Ok(i32), Err(String) }

fn foo() -> SomeOtherEnum { 0$0 }
"#,
        );
    }

    #[test]
    fn remove_semicolon() {
        check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);
    }

    #[test]
    fn str_ref_to_string() {
        check_fix(
            r#"
struct String;

fn test() -> String {
    "a"$0
}
            "#,
            r#"
struct String;

fn test() -> String {
    "a".to_string()
}
            "#,
        );
    }
}
<|endoftext|>


<commit_before>use std;

use collect_slice::CollectSlice;

use bits::{Hexbit, HexbitBytes, Dibit};
use buffer::{Buffer, VoiceExtraStorage, VoiceFrameStorage, VoiceExtraWordStorage,
             VoiceDataFragStorage};
use coding::{cyclic, hamming, reed_solomon};
use error::{P25Error, Result};

use consts::{
    EXTRA_HEXBITS,
    EXTRA_PIECE_DIBITS,
    LINK_CONTROL_BYTES,
    CRYPTO_CONTROL_BYTES,
};

use voice::{control, crypto};
use voice::frame::VoiceFrame;

use error::P25Error::*;
use self::State::*;
use self::StateChange::*;

pub type VoiceLCFrameGroupReceiver = FrameGroupReceiver<LinkControlExtra>;
pub type VoiceCCFrameGroupReceiver = FrameGroupReceiver<CryptoControlExtra>;

pub trait Extra {
    type Fields;

    fn decode_rs(buf: &mut [Hexbit; EXTRA_HEXBITS]) -> Option<(&[Hexbit], usize)>;
    fn decode_extra(buf: &[Hexbit]) -> Self::Fields;
}

pub struct LinkControlExtra;

impl Extra for LinkControlExtra {
    type Fields = control::LinkControlFields;

    fn decode_rs(buf: &mut [Hexbit; EXTRA_HEXBITS]) -> Option<(&[Hexbit], usize)> {
        reed_solomon::short::decode(buf)
    }

    fn decode_extra(buf: &[Hexbit]) -> Self::Fields {
        let mut bytes = [0; LINK_CONTROL_BYTES];
        HexbitBytes::new(buf.iter().cloned()).collect_slice_checked(&mut bytes[..]);

        control::LinkControlFields::new(bytes)
    }
}

pub struct CryptoControlExtra;

impl Extra for CryptoControlExtra {
    type Fields = crypto::CryptoControlFields;

    fn decode_rs(buf: &mut [Hexbit; EXTRA_HEXBITS]) -> Option<(&[Hexbit], usize)> {
        reed_solomon::medium::decode(buf)
    }

    fn decode_extra(buf: &[Hexbit]) -> Self::Fields {
        let mut bytes = [0; CRYPTO_CONTROL_BYTES];
        HexbitBytes::new(buf.iter().cloned()).collect_slice_checked(&mut bytes[..]);

        crypto::CryptoControlFields::new(bytes)
    }
}

enum State {
    DecodeVoiceFrame(VoiceFrameReceiver),
    DecodeExtra,
    DecodeDataFragment,
    Done,
}

impl State {
    pub fn decode_voice_frame() -> State {
        DecodeVoiceFrame(VoiceFrameReceiver::new())
    }
}

enum StateChange<E: Extra> {
    NoChange,
    Change(State),
    EventChange(FrameGroupEvent<E>, State),
    Error(P25Error),
}

pub enum FrameGroupEvent<E: Extra> {
    VoiceFrame(VoiceFrame),
    Extra(E::Fields),
    DataFragment(u32),
}

pub struct FrameGroupReceiver<E: Extra> {
    state: State,
    extra: ExtraReceiver<E>,
    frag: DataFragmentReceiver,
    frame: usize,
}

impl<E: Extra> FrameGroupReceiver<E> {
    pub fn new() -> FrameGroupReceiver<E> {
        FrameGroupReceiver {
            state: State::decode_voice_frame(),
            extra: ExtraReceiver::new(),
            frag: DataFragmentReceiver::new(),
            frame: 0,
        }
    }

    pub fn done(&self) -> bool {
        if let Done = self.state { true } else { false }
    }

    fn handle(&mut self, dibit: Dibit) -> StateChange<E> {
        match self.state {
            DecodeVoiceFrame(ref mut decoder) => match decoder.feed(dibit) {
                Some(Ok(vf)) => {
                    self.frame += 1;

                    EventChange(FrameGroupEvent::VoiceFrame(vf), match self.frame {
                        1 => State::decode_voice_frame(),
                        2...7 => DecodeExtra,
                        8 => DecodeDataFragment,
                        9 => Done,
                        _ => unreachable!(),
                    })
                },
                Some(Err(e)) => Error(e),
                None => NoChange,
            },
            DecodeExtra => match self.extra.feed(dibit) {
                Some(Ok(extra)) => EventChange(FrameGroupEvent::Extra(extra),
                                               State::decode_voice_frame()),
                Some(Err(err)) => Error(err),
                None => if self.extra.piece_done() {
                    Change(State::decode_voice_frame())
                } else {
                    NoChange
                }
            },
            DecodeDataFragment => match self.frag.feed(dibit) {
                Some(Ok(data)) => EventChange(FrameGroupEvent::DataFragment(data),
                                              State::decode_voice_frame()),
                Some(Err(err)) => Error(err),
                None => NoChange,
            },
            _ => unreachable!(),
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<FrameGroupEvent<E>>> {
        match self.handle(dibit) {
            EventChange(event, next) => {
                self.state = next;
                Some(Ok(event))
            },
            Change(state) => {
                self.state = state;
                None
            },
            Error(e) => Some(Err(e)),
            NoChange => None,
        }
    }
}

struct VoiceFrameReceiver {
    dibits: Buffer<VoiceFrameStorage>,
}

impl VoiceFrameReceiver {
    pub fn new() -> VoiceFrameReceiver {
        VoiceFrameReceiver {
            dibits: Buffer::new(VoiceFrameStorage::new()),
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<VoiceFrame>> {
        match self.dibits.feed(dibit) {
            Some(buf) => Some(VoiceFrame::new(buf)),
            None => None,
        }
    }
}

struct ExtraReceiver<E: Extra> {
    extra: std::marker::PhantomData<E>,
    dibits: Buffer<VoiceExtraWordStorage>,
    hexbits: Buffer<VoiceExtraStorage>,
    dibit: usize,
}

impl<E: Extra> ExtraReceiver<E> {
    pub fn new() -> ExtraReceiver<E> {
        ExtraReceiver {
            extra: std::marker::PhantomData,
            dibits: Buffer::new(VoiceExtraWordStorage::new()),
            hexbits: Buffer::new(VoiceExtraStorage::new()),
            dibit: 0,
        }
    }

    pub fn piece_done(&self) -> bool { self.dibit % EXTRA_PIECE_DIBITS == 0 }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<E::Fields>> {
        self.dibit += 1;

        let buf = match self.dibits.feed(dibit) {
            Some(buf) => *buf as u16,
            None => return None,
        };

        let bits = match hamming::shortened::decode(buf) {
            Some((data, err)) => data,
            None => return Some(Err(HammingUnrecoverable)),
        };

        let hexbits = match self.hexbits.feed(Hexbit::new(bits)) {
            Some(buf) => buf,
            None => return None,
        };

        let data = match E::decode_rs(hexbits) {
            Some((data, err)) => data,
            None => return Some(Err(ReedSolomonUnrecoverable)),
        };

        Some(Ok(E::decode_extra(data)))
    }
}

struct DataFragmentReceiver {
    dibits: Buffer<VoiceDataFragStorage>,
    dibit: usize,
    data: u32,
}

impl DataFragmentReceiver {
    pub fn new() -> DataFragmentReceiver {
        DataFragmentReceiver {
            dibits: Buffer::new(VoiceDataFragStorage::new()),
            dibit: 0,
            data: 0,
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<u32>> {
        let buf = match self.dibits.feed(dibit) {
            Some(buf) => *buf as u16,
            None => return None,
        };

        let bits = match cyclic::decode(buf) {
            Some((data, err)) => data,
            None => return Some(Err(CyclicUnrecoverable)),
        };

        self.dibit += 1;

        self.data <<= 8;
        self.data |= bits as u32;

        if self.dibit == 2 {
            Some(Ok(self.data))
        } else {
            None
        }
    }
}
<commit_msg>s/dibit/byte/<commit_after>use std;

use collect_slice::CollectSlice;

use bits::{Hexbit, HexbitBytes, Dibit};
use buffer::{Buffer, VoiceExtraStorage, VoiceFrameStorage, VoiceExtraWordStorage,
             VoiceDataFragStorage};
use coding::{cyclic, hamming, reed_solomon};
use error::{P25Error, Result};

use consts::{
    EXTRA_HEXBITS,
    EXTRA_PIECE_DIBITS,
    LINK_CONTROL_BYTES,
    CRYPTO_CONTROL_BYTES,
};

use voice::{control, crypto};
use voice::frame::VoiceFrame;

use error::P25Error::*;
use self::State::*;
use self::StateChange::*;

pub type VoiceLCFrameGroupReceiver = FrameGroupReceiver<LinkControlExtra>;
pub type VoiceCCFrameGroupReceiver = FrameGroupReceiver<CryptoControlExtra>;

pub trait Extra {
    type Fields;

    fn decode_rs(buf: &mut [Hexbit; EXTRA_HEXBITS]) -> Option<(&[Hexbit], usize)>;
    fn decode_extra(buf: &[Hexbit]) -> Self::Fields;
}

pub struct LinkControlExtra;

impl Extra for LinkControlExtra {
    type Fields = control::LinkControlFields;

    fn decode_rs(buf: &mut [Hexbit; EXTRA_HEXBITS]) -> Option<(&[Hexbit], usize)> {
        reed_solomon::short::decode(buf)
    }

    fn decode_extra(buf: &[Hexbit]) -> Self::Fields {
        let mut bytes = [0; LINK_CONTROL_BYTES];
        HexbitBytes::new(buf.iter().cloned()).collect_slice_checked(&mut bytes[..]);

        control::LinkControlFields::new(bytes)
    }
}

pub struct CryptoControlExtra;

impl Extra for CryptoControlExtra {
    type Fields = crypto::CryptoControlFields;

    fn decode_rs(buf: &mut [Hexbit; EXTRA_HEXBITS]) -> Option<(&[Hexbit], usize)> {
        reed_solomon::medium::decode(buf)
    }

    fn decode_extra(buf: &[Hexbit]) -> Self::Fields {
        let mut bytes = [0; CRYPTO_CONTROL_BYTES];
        HexbitBytes::new(buf.iter().cloned()).collect_slice_checked(&mut bytes[..]);

        crypto::CryptoControlFields::new(bytes)
    }
}

enum State {
    DecodeVoiceFrame(VoiceFrameReceiver),
    DecodeExtra,
    DecodeDataFragment,
    Done,
}

impl State {
    pub fn decode_voice_frame() -> State {
        DecodeVoiceFrame(VoiceFrameReceiver::new())
    }
}

enum StateChange<E: Extra> {
    NoChange,
    Change(State),
    EventChange(FrameGroupEvent<E>, State),
    Error(P25Error),
}

pub enum FrameGroupEvent<E: Extra> {
    VoiceFrame(VoiceFrame),
    Extra(E::Fields),
    DataFragment(u32),
}

pub struct FrameGroupReceiver<E: Extra> {
    state: State,
    extra: ExtraReceiver<E>,
    frag: DataFragmentReceiver,
    frame: usize,
}

impl<E: Extra> FrameGroupReceiver<E> {
    pub fn new() -> FrameGroupReceiver<E> {
        FrameGroupReceiver {
            state: State::decode_voice_frame(),
            extra: ExtraReceiver::new(),
            frag: DataFragmentReceiver::new(),
            frame: 0,
        }
    }

    pub fn done(&self) -> bool {
        if let Done = self.state { true } else { false }
    }

    fn handle(&mut self, dibit: Dibit) -> StateChange<E> {
        match self.state {
            DecodeVoiceFrame(ref mut decoder) => match decoder.feed(dibit) {
                Some(Ok(vf)) => {
                    self.frame += 1;

                    EventChange(FrameGroupEvent::VoiceFrame(vf), match self.frame {
                        1 => State::decode_voice_frame(),
                        2...7 => DecodeExtra,
                        8 => DecodeDataFragment,
                        9 => Done,
                        _ => unreachable!(),
                    })
                },
                Some(Err(e)) => Error(e),
                None => NoChange,
            },
            DecodeExtra => match self.extra.feed(dibit) {
                Some(Ok(extra)) => EventChange(FrameGroupEvent::Extra(extra),
                                               State::decode_voice_frame()),
                Some(Err(err)) => Error(err),
                None => if self.extra.piece_done() {
                    Change(State::decode_voice_frame())
                } else {
                    NoChange
                }
            },
            DecodeDataFragment => match self.frag.feed(dibit) {
                Some(Ok(data)) => EventChange(FrameGroupEvent::DataFragment(data),
                                              State::decode_voice_frame()),
                Some(Err(err)) => Error(err),
                None => NoChange,
            },
            _ => unreachable!(),
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<FrameGroupEvent<E>>> {
        match self.handle(dibit) {
            EventChange(event, next) => {
                self.state = next;
                Some(Ok(event))
            },
            Change(state) => {
                self.state = state;
                None
            },
            Error(e) => Some(Err(e)),
            NoChange => None,
        }
    }
}

struct VoiceFrameReceiver {
    dibits: Buffer<VoiceFrameStorage>,
}

impl VoiceFrameReceiver {
    pub fn new() -> VoiceFrameReceiver {
        VoiceFrameReceiver {
            dibits: Buffer::new(VoiceFrameStorage::new()),
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<VoiceFrame>> {
        match self.dibits.feed(dibit) {
            Some(buf) => Some(VoiceFrame::new(buf)),
            None => None,
        }
    }
}

struct ExtraReceiver<E: Extra> {
    extra: std::marker::PhantomData<E>,
    dibits: Buffer<VoiceExtraWordStorage>,
    hexbits: Buffer<VoiceExtraStorage>,
    dibit: usize,
}

impl<E: Extra> ExtraReceiver<E> {
    pub fn new() -> ExtraReceiver<E> {
        ExtraReceiver {
            extra: std::marker::PhantomData,
            dibits: Buffer::new(VoiceExtraWordStorage::new()),
            hexbits: Buffer::new(VoiceExtraStorage::new()),
            dibit: 0,
        }
    }

    pub fn piece_done(&self) -> bool { self.dibit % EXTRA_PIECE_DIBITS == 0 }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<E::Fields>> {
        self.dibit += 1;

        let buf = match self.dibits.feed(dibit) {
            Some(buf) => *buf as u16,
            None => return None,
        };

        let bits = match hamming::shortened::decode(buf) {
            Some((data, err)) => data,
            None => return Some(Err(HammingUnrecoverable)),
        };

        let hexbits = match self.hexbits.feed(Hexbit::new(bits)) {
            Some(buf) => buf,
            None => return None,
        };

        let data = match E::decode_rs(hexbits) {
            Some((data, err)) => data,
            None => return Some(Err(ReedSolomonUnrecoverable)),
        };

        Some(Ok(E::decode_extra(data)))
    }
}

struct DataFragmentReceiver {
    dibits: Buffer<VoiceDataFragStorage>,
    byte: usize,
    data: u32,
}

impl DataFragmentReceiver {
    pub fn new() -> DataFragmentReceiver {
        DataFragmentReceiver {
            dibits: Buffer::new(VoiceDataFragStorage::new()),
            byte: 0,
            data: 0,
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<u32>> {
        let buf = match self.dibits.feed(dibit) {
            Some(buf) => *buf as u16,
            None => return None,
        };

        let bits = match cyclic::decode(buf) {
            Some((data, err)) => data,
            None => return Some(Err(CyclicUnrecoverable)),
        };

        self.byte += 1;

        self.data <<= 8;
        self.data |= bits as u32;

        if self.byte == 2 {
            Some(Ok(self.data))
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomFn;
use libc::{c_char, c_void};

use block::Block;
use runtime::{Class, Object, Sel};

pub struct Encoding {
    code: &'static str,
}

macro_rules! static_encoding {
    ($s:expr) => (Encoding { code: concat!($s, "\0") });
}

impl Encoding {
    pub fn as_str(&self) -> &str {
        &self.code[..self.code.len() - 1]
    }

    pub fn as_ptr(&self) -> *const c_char {
        self.as_str().as_ptr() as *const c_char
    }

    pub fn unknown() -> Encoding { static_encoding!("?") }
}

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

impl<'a> PartialEq<&'a str> for Encoding {
    fn eq(&self, other: &&'a str) -> bool {
        self.as_str() == *other
    }
}

/// Types that have an Objective-C type encoding.
///
/// For more information, see Apple's documentation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
pub trait Encode : PhantomFn<Self> {
    /// Returns the Objective-C type encoding for Self.
    fn encode() -> Encoding;
}

macro_rules! encode_impls {
    ($($t:ty : $s:expr,)*) => ($(
        impl Encode for $t {
            fn encode() -> Encoding { static_encoding!($s) }
        }
    )*);
}

encode_impls!(
    i8: "c",
    i16: "s",
    i32: "i",
    i64: "q",
    u8: "C",
    u16: "S",
    u32: "I",
    u64: "Q",
    f32: "f",
    f64: "d",
    bool: "B",
    (): "v",
    *mut c_char: "*",
    *const c_char: "r*",
    *mut c_void: "^v",
    *const c_void: "r^v",
    Sel: ":",
);

impl Encode for isize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { i32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { i64::encode() }
}

impl Encode for usize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { u32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { u64::encode() }
}

macro_rules! encode_message_impl {
    ($code:expr, $name:ident) => (
        encode_message_impl!($code, $name,);
    );
    ($code:expr, $name:ident, $($t:ident),*) => (
        impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
            fn encode() -> Encoding { static_encoding!($code) }
        }
    );
}

encode_message_impl!("@", Object);

encode_message_impl!("#", Class);

encode_message_impl!("@?", Block, A, R);

#[cfg(test)]
mod tests {
    use runtime::{Class, Object, Sel};
    use super::Encode;

    #[test]
    fn test_encode() {
        assert!(u32::encode() == "I");
        assert!(<()>::encode() == "v");
        assert!(<&Object>::encode() == "@");
        assert!(<*mut Object>::encode() == "@");
        assert!(<&Class>::encode() == "#");
        assert!(Sel::encode() == ":");
    }
}
<commit_msg>Implemented Clone and Debug for Encoding.<commit_after>use std::fmt;
use std::marker::PhantomFn;
use libc::{c_char, c_void};

use block::Block;
use runtime::{Class, Object, Sel};

pub struct Encoding {
    code: &'static str,
}

macro_rules! static_encoding {
    ($s:expr) => (Encoding { code: concat!($s, "\0") });
}

impl Encoding {
    pub fn as_str(&self) -> &str {
        &self.code[..self.code.len() - 1]
    }

    pub fn as_ptr(&self) -> *const c_char {
        self.as_str().as_ptr() as *const c_char
    }

    pub fn unknown() -> Encoding { static_encoding!("?") }
}

impl Clone for Encoding {
    fn clone(&self) -> Encoding {
        Encoding { code: self.code }
    }
}

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

impl<'a> PartialEq<&'a str> for Encoding {
    fn eq(&self, other: &&'a str) -> bool {
        self.as_str() == *other
    }
}

impl fmt::Debug for Encoding {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

/// Types that have an Objective-C type encoding.
///
/// For more information, see Apple's documentation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
pub trait Encode : PhantomFn<Self> {
    /// Returns the Objective-C type encoding for Self.
    fn encode() -> Encoding;
}

macro_rules! encode_impls {
    ($($t:ty : $s:expr,)*) => ($(
        impl Encode for $t {
            fn encode() -> Encoding { static_encoding!($s) }
        }
    )*);
}

encode_impls!(
    i8: "c",
    i16: "s",
    i32: "i",
    i64: "q",
    u8: "C",
    u16: "S",
    u32: "I",
    u64: "Q",
    f32: "f",
    f64: "d",
    bool: "B",
    (): "v",
    *mut c_char: "*",
    *const c_char: "r*",
    *mut c_void: "^v",
    *const c_void: "r^v",
    Sel: ":",
);

impl Encode for isize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { i32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { i64::encode() }
}

impl Encode for usize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { u32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { u64::encode() }
}

macro_rules! encode_message_impl {
    ($code:expr, $name:ident) => (
        encode_message_impl!($code, $name,);
    );
    ($code:expr, $name:ident, $($t:ident),*) => (
        impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
            fn encode() -> Encoding { static_encoding!($code) }
        }

        impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
            fn encode() -> Encoding { static_encoding!($code) }
        }
    );
}

encode_message_impl!("@", Object);

encode_message_impl!("#", Class);

encode_message_impl!("@?", Block, A, R);

#[cfg(test)]
mod tests {
    use runtime::{Class, Object, Sel};
    use super::Encode;

    #[test]
    fn test_encode() {
        assert!(u32::encode() == "I");
        assert!(<()>::encode() == "v");
        assert!(<&Object>::encode() == "@");
        assert!(<*mut Object>::encode() == "@");
        assert!(<&Class>::encode() == "#");
        assert!(Sel::encode() == ":");
    }
}
<|endoftext|>


<commit_before>use nn::{Module, InitModuleStruct, GetFieldStruct, ModDelegate, ModIntf, Parameter};
use nn::functional as F;
use autograd::Variable;
use std::marker::PhantomData;
use tensor::NumLimits;

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct LinearArgs<T: ::tensor::NumLimits> {
    in_features: u32,
    out_features: u32,
    #[builder(default="true")]
    bias: bool,
    #[builder(default="PhantomData")]
    phantom: PhantomData<T>,
}
impl<T: ::tensor::NumLimits> LinearArgsBuilder<T> {
    pub fn done(self) -> Linear<T> {
        let args = self.build().unwrap();
        Linear::new(args)
    }
}

#[derive(ModParse)]
pub struct Linear<T: NumLimits> {
    delegate: Module<T>,
    #[ignore]
    in_features: u32,
    #[ignore]
    out_features: u32,
    weight: Parameter<T>,
    bias: Option<Parameter<T>>,
}

impl<T: NumLimits> Linear<T> {
    pub fn build(in_features: u32, out_features: u32) -> LinearArgsBuilder<T> {
        LinearArgsBuilder::default()
            .in_features(in_features)
            .out_features(out_features)
    }
    pub fn new(args: LinearArgs<T>) -> Linear<T> {
        Linear {
                delegate: Module::new(),
                in_features: args.in_features,
                out_features: args.out_features,
                weight: Parameter::default(),
                bias: None,
            }
            .init_module()
    }
}
impl_mod_delegate!(Linear);

impl<T: NumLimits> ModIntf<T> for Linear<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T> {
        if let Some(ref mut bias) = self.bias {
            F::linear(&input, &mut self.weight.v, Some(&mut bias.v))
        } else {
            F::linear(&input, &mut self.weight.v, None)
        }
    }
}
<commit_msg>mark as unimplemented<commit_after>use nn::{Module, InitModuleStruct, GetFieldStruct, ModDelegate, ModIntf, Parameter};
use nn::functional as F;
use autograd::Variable;
use std::marker::PhantomData;
use tensor::NumLimits;

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct LinearArgs<T: ::tensor::NumLimits> {
    in_features: u32,
    out_features: u32,
    #[builder(default="true")]
    bias: bool,
    #[builder(default="PhantomData")]
    phantom: PhantomData<T>,
}
impl<T: ::tensor::NumLimits> LinearArgsBuilder<T> {
    pub fn done(self) -> Linear<T> {
        let args = self.build().unwrap();
        Linear::new(args)
    }
}

#[derive(ModParse)]
pub struct Linear<T: NumLimits> {
    delegate: Module<T>,
    #[ignore]
    in_features: u32,
    #[ignore]
    out_features: u32,
    weight: Parameter<T>,
    bias: Option<Parameter<T>>,
}

impl<T: NumLimits> Linear<T> {
    pub fn build(in_features: u32, out_features: u32) -> LinearArgsBuilder<T> {
        LinearArgsBuilder::default()
            .in_features(in_features)
            .out_features(out_features)
    }
    pub fn new(args: LinearArgs<T>) -> Linear<T> {
        unimplemented!();
        Linear {
                delegate: Module::new(),
                in_features: args.in_features,
                out_features: args.out_features,
                weight: Parameter::default(),
                bias: None,
            }
            .init_module()
    }
}
impl_mod_delegate!(Linear);

impl<T: NumLimits> ModIntf<T> for Linear<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T> {
        if let Some(ref mut bias) = self.bias {
            F::linear(&input, &mut self.weight.v, Some(&mut bias.v))
        } else {
            F::linear(&input, &mut self.weight.v, None)
        }
    }
}
<|endoftext|>


<commit_before>// TODO Disable interrupt before entering those.
use spin::{Mutex};
use core::mem::{size_of};
use core::slice;
use utils::{align_down, block_count};
use core::ptr::{Unique};
use super::{PTEntry, PT_P, PT_RW, flush, BASE_PAGE_LENGTH};
use arch::init::{OBJECT_POOL_PT, OBJECT_POOL_START_VADDR};
use common::{PAddr, VAddr};

use core::nonzero::{NonZero};
use core::marker::{PhantomData};
use core::ops::{Deref};
use core::mem;
use core::fmt;

static _next_free: Mutex<usize> = Mutex::new(0);

/// `ObjectGuard` requires T must be Sized.
pub struct ObjectGuard<T> {
    mapping_start_index: usize,
    mapping_size: usize,
    pointer: NonZero<*const T>,
    _marker: PhantomData<T>,
}

/// `ObjectGuard` pointers are not `Send` because the data they reference may be aliased.
impl<T> !Send for ObjectGuard<T> { }

/// `ObjectGuard` pointers are not `Sync` because the data they reference may be aliased.
impl<T> !Sync for ObjectGuard<T> { }

impl<T> ObjectGuard<T> {

    /// Safety: PAddr must be a non-zero pointer.
    pub unsafe fn new(paddr: PAddr) -> Self {
        let aligned = align_down(paddr, BASE_PAGE_LENGTH);
        let before_start = paddr.into(): usize - aligned.into(): usize;
        let size = size_of::<T>();
        let required_page_size = block_count((paddr + size).into(): usize - aligned.into(): usize,
                                             BASE_PAGE_LENGTH);

        let mut object_pool = OBJECT_POOL_PT.lock();
        let mapping_start_index: usize = {
            let mut mapping_start_index: Option<usize> = None;

            for i in 0..object_pool.len() {
                let mut available = true;
                for j in 0..required_page_size {
                    if object_pool[i + j].is_present() {
                        available = false;
                        break;
                    }
                }

                if available {
                    mapping_start_index = Some(i);
                    break;
                }
            }

            mapping_start_index
        }.unwrap();

        for i in 0..required_page_size {
            object_pool[mapping_start_index + i] = PTEntry::new(aligned + (i * BASE_PAGE_LENGTH), PT_P | PT_RW);
            unsafe { flush(OBJECT_POOL_START_VADDR + (mapping_start_index * BASE_PAGE_LENGTH) + i * BASE_PAGE_LENGTH); }
        }

        let vaddr = OBJECT_POOL_START_VADDR + ((mapping_start_index * BASE_PAGE_LENGTH) + before_start);

        ObjectGuard::<T> {
            mapping_start_index: mapping_start_index,
            mapping_size: required_page_size,
            pointer: NonZero::new(vaddr.into(): usize as *mut T),
            _marker: PhantomData
        }
    }
}

impl<T> Drop for ObjectGuard<T> {
    fn drop(&mut self) {
        let mut object_pool = OBJECT_POOL_PT.lock();

        for i in 0..self.mapping_size {
            object_pool[self.mapping_start_index + i] = PTEntry::empty();
            unsafe { flush(OBJECT_POOL_START_VADDR + (self.mapping_start_index * BASE_PAGE_LENGTH) + i * BASE_PAGE_LENGTH); }
        }
    }
}

impl<T> Deref for ObjectGuard<T> {
    type Target = *mut T;

    #[inline]
    fn deref(&self) -> &*mut T {
        unsafe { mem::transmute(&*self.pointer) }
    }
}

impl<T> fmt::Pointer for ObjectGuard<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Pointer::fmt(&*self.pointer, f)
    }
}

pub unsafe fn with_object_vaddr<Return, F: FnOnce(VAddr) -> Return>(paddr: PAddr, size: usize, f: F)
                                                                -> Return {
    let aligned = align_down(paddr, BASE_PAGE_LENGTH);
    let before_start = paddr.into(): usize - aligned.into(): usize;
    let required_page_size = block_count((paddr + size).into(): usize - aligned.into(): usize,
                                         BASE_PAGE_LENGTH);

    let next_free_base;
    let mut object_pool = OBJECT_POOL_PT.lock();

    {
        let mut next_free = _next_free.lock();
        next_free_base = *next_free;

        for i in 0..required_page_size {
            object_pool[next_free_base + i] = PTEntry::new(aligned + (i * BASE_PAGE_LENGTH), PT_P | PT_RW);
            unsafe { flush(OBJECT_POOL_START_VADDR + (next_free_base * BASE_PAGE_LENGTH) + i * BASE_PAGE_LENGTH); }
        }

        *next_free = next_free_base + required_page_size;
    }

    let vaddr = OBJECT_POOL_START_VADDR + ((next_free_base * BASE_PAGE_LENGTH) + before_start);

    let result = f(vaddr);

    {
        let mut next_free = _next_free.lock();
        assert!(next_free_base == (*next_free - required_page_size));

        for i in 0..required_page_size {
            object_pool[next_free_base + i] = PTEntry::empty();
            unsafe { flush(OBJECT_POOL_START_VADDR + (next_free_base * BASE_PAGE_LENGTH) + i * BASE_PAGE_LENGTH); }
        }

        *next_free = next_free_base;
    }

    result
}

pub unsafe fn with_object_unique<T, Return, F: FnOnce(Unique<T>) -> Return>(paddr: PAddr, f: F)
                                                                            -> Return {
    let size = size_of::<T>();
    with_object_vaddr(paddr, size, |vaddr| {
        let unique = unsafe {
            Unique::new(vaddr.into(): usize as *mut T) };
        f(unique)
    })
}

pub unsafe fn with_slice<T, Return, F: FnOnce(&[T]) -> Return>(paddr: PAddr, size: usize, f: F)
                                                               -> Return {
    let allsize = size * (size_of::<T>());
    with_object_vaddr(paddr, allsize, |vaddr| {
        let slice = unsafe {
            slice::from_raw_parts::<T>(vaddr.into(): usize as *const _, allsize) };
        f(slice)
    })
}

pub unsafe fn with_slice_mut<T, Return, F: FnOnce(&mut [T]) -> Return>(paddr: PAddr, size: usize, f: F)
                                                                       -> Return {
    let allsize = size * (size_of::<T>());
    with_object_vaddr(paddr, allsize, |vaddr| {
        let mut slice = unsafe {
            slice::from_raw_parts_mut::<T>(vaddr.into(): usize as *mut _, allsize) };
        f(slice)
    })
}

pub unsafe fn with_object<T, Return, F: FnOnce(&T) -> Return>(paddr: PAddr, f: F) -> Return {
    with_object_unique(paddr, |unique| {
        f(unsafe { unique.get() })
    })
}

pub unsafe fn with_object_mut<T, Return, F: FnOnce(&mut T) -> Return>(paddr: PAddr, f: F) -> Return {
    with_object_unique(paddr, |mut unique| {
        f(unsafe { unique.get_mut() })
    })
}
<commit_msg>Fix a locking problem<commit_after>// TODO Disable interrupt before entering those.
use spin::{Mutex};
use core::mem::{size_of};
use core::slice;
use utils::{align_down, block_count};
use core::ptr::{Unique};
use super::{PTEntry, PT_P, PT_RW, flush, BASE_PAGE_LENGTH};
use arch::init::{OBJECT_POOL_PT, OBJECT_POOL_START_VADDR};
use common::{PAddr, VAddr};

use core::nonzero::{NonZero};
use core::marker::{PhantomData};
use core::ops::{Deref};
use core::mem;
use core::fmt;

static _next_free: Mutex<usize> = Mutex::new(0);

/// `ObjectGuard` requires T must be Sized.
pub struct ObjectGuard<T> {
    mapping_start_index: usize,
    mapping_size: usize,
    pointer: NonZero<*const T>,
    _marker: PhantomData<T>,
}

/// `ObjectGuard` pointers are not `Send` because the data they reference may be aliased.
impl<T> !Send for ObjectGuard<T> { }

/// `ObjectGuard` pointers are not `Sync` because the data they reference may be aliased.
impl<T> !Sync for ObjectGuard<T> { }

impl<T> ObjectGuard<T> {

    /// Safety: PAddr must be a non-zero pointer.
    pub unsafe fn new(paddr: PAddr) -> Self {
        let aligned = align_down(paddr, BASE_PAGE_LENGTH);
        let before_start = paddr.into(): usize - aligned.into(): usize;
        let size = size_of::<T>();
        let required_page_size = block_count((paddr + size).into(): usize - aligned.into(): usize,
                                             BASE_PAGE_LENGTH);

        let mut object_pool = OBJECT_POOL_PT.lock();
        let mapping_start_index: usize = {
            let mut mapping_start_index: Option<usize> = None;

            for i in 0..object_pool.len() {
                let mut available = true;
                for j in 0..required_page_size {
                    if object_pool[i + j].is_present() {
                        available = false;
                        break;
                    }
                }

                if available {
                    mapping_start_index = Some(i);
                    break;
                }
            }

            mapping_start_index
        }.unwrap();

        for i in 0..required_page_size {
            object_pool[mapping_start_index + i] = PTEntry::new(aligned + (i * BASE_PAGE_LENGTH), PT_P | PT_RW);
            unsafe { flush(OBJECT_POOL_START_VADDR + (mapping_start_index * BASE_PAGE_LENGTH) + i * BASE_PAGE_LENGTH); }
        }

        let vaddr = OBJECT_POOL_START_VADDR + ((mapping_start_index * BASE_PAGE_LENGTH) + before_start);

        ObjectGuard::<T> {
            mapping_start_index: mapping_start_index,
            mapping_size: required_page_size,
            pointer: NonZero::new(vaddr.into(): usize as *mut T),
            _marker: PhantomData
        }
    }
}

impl<T> Drop for ObjectGuard<T> {
    fn drop(&mut self) {
        let mut object_pool = OBJECT_POOL_PT.lock();

        for i in 0..self.mapping_size {
            object_pool[self.mapping_start_index + i] = PTEntry::empty();
            unsafe { flush(OBJECT_POOL_START_VADDR + (self.mapping_start_index * BASE_PAGE_LENGTH) + i * BASE_PAGE_LENGTH); }
        }
    }
}

impl<T> Deref for ObjectGuard<T> {
    type Target = *mut T;

    #[inline]
    fn deref(&self) -> &*mut T {
        unsafe { mem::transmute(&*self.pointer) }
    }
}

impl<T> fmt::Pointer for ObjectGuard<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Pointer::fmt(&*self.pointer, f)
    }
}

pub unsafe fn with_object_vaddr<Return, F: FnOnce(VAddr) -> Return>(paddr: PAddr, size: usize, f: F)
                                                                -> Return {
    let aligned = align_down(paddr, BASE_PAGE_LENGTH);
    let before_start = paddr.into(): usize - aligned.into(): usize;
    let required_page_size = block_count((paddr + size).into(): usize - aligned.into(): usize,
                                         BASE_PAGE_LENGTH);

    let next_free_base;

    {
        let mut object_pool = OBJECT_POOL_PT.lock();
        let mut next_free = _next_free.lock();
        next_free_base = *next_free;

        for i in 0..required_page_size {
            object_pool[next_free_base + i] = PTEntry::new(aligned + (i * BASE_PAGE_LENGTH), PT_P | PT_RW);
            unsafe { flush(OBJECT_POOL_START_VADDR + (next_free_base * BASE_PAGE_LENGTH) + i * BASE_PAGE_LENGTH); }
        }

        *next_free = next_free_base + required_page_size;
    }

    let vaddr = OBJECT_POOL_START_VADDR + ((next_free_base * BASE_PAGE_LENGTH) + before_start);

    let result = f(vaddr);

    {
        let mut object_pool = OBJECT_POOL_PT.lock();
        let mut next_free = _next_free.lock();
        assert!(next_free_base == (*next_free - required_page_size));

        for i in 0..required_page_size {
            object_pool[next_free_base + i] = PTEntry::empty();
            unsafe { flush(OBJECT_POOL_START_VADDR + (next_free_base * BASE_PAGE_LENGTH) + i * BASE_PAGE_LENGTH); }
        }

        *next_free = next_free_base;
    }

    result
}

pub unsafe fn with_object_unique<T, Return, F: FnOnce(Unique<T>) -> Return>(paddr: PAddr, f: F)
                                                                            -> Return {
    let size = size_of::<T>();
    with_object_vaddr(paddr, size, |vaddr| {
        let unique = unsafe {
            Unique::new(vaddr.into(): usize as *mut T) };
        f(unique)
    })
}

pub unsafe fn with_slice<T, Return, F: FnOnce(&[T]) -> Return>(paddr: PAddr, size: usize, f: F)
                                                               -> Return {
    let allsize = size * (size_of::<T>());
    with_object_vaddr(paddr, allsize, |vaddr| {
        let slice = unsafe {
            slice::from_raw_parts::<T>(vaddr.into(): usize as *const _, allsize) };
        f(slice)
    })
}

pub unsafe fn with_slice_mut<T, Return, F: FnOnce(&mut [T]) -> Return>(paddr: PAddr, size: usize, f: F)
                                                                       -> Return {
    let allsize = size * (size_of::<T>());
    with_object_vaddr(paddr, allsize, |vaddr| {
        let mut slice = unsafe {
            slice::from_raw_parts_mut::<T>(vaddr.into(): usize as *mut _, allsize) };
        f(slice)
    })
}

pub unsafe fn with_object<T, Return, F: FnOnce(&T) -> Return>(paddr: PAddr, f: F) -> Return {
    with_object_unique(paddr, |unique| {
        f(unsafe { unique.get() })
    })
}

pub unsafe fn with_object_mut<T, Return, F: FnOnce(&mut T) -> Return>(paddr: PAddr, f: F) -> Return {
    with_object_unique(paddr, |mut unique| {
        f(unsafe { unique.get_mut() })
    })
}
<|endoftext|>


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

//! Lints, aka compiler warnings.
//!
//! A 'lint' check is a kind of miscellaneous constraint that a user _might_
//! want to enforce, but might reasonably want to permit as well, on a
//! module-by-module basis. They contrast with static constraints enforced by
//! other phases of the compiler, which are generally required to hold in order
//! to compile the program at all.
//!
//! Most lints can be written as `LintPass` instances. These run just before
//! translation to LLVM bytecode. The `LintPass`es built into rustc are defined
//! within `builtin.rs`, which has further comments on how to add such a lint.
//! rustc can also load user-defined lint plugins via the plugin mechanism.
//!
//! Some of rustc's lints are defined elsewhere in the compiler and work by
//! calling `add_lint()` on the overall `Session` object. This works when
//! it happens before the main lint pass, which emits the lints stored by
//! `add_lint()`. To emit lints after the main lint pass (from trans, for
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
//! in `context.rs`.

pub use self::Level::*;
pub use self::LintSource::*;

use std::hash;
use std::ascii::AsciiExt;
use syntax::codemap::Span;
use rustc_front::visit::FnKind;
use syntax::visit as ast_visit;
use syntax::ast;
use rustc_front::hir;

pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
                        raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
                        GatherNodeLevels};

/// Specification of a single lint.
#[derive(Copy, Clone, Debug)]
pub struct Lint {
    /// A string identifier for the lint.
    ///
    /// This identifies the lint in attributes and in command-line arguments.
    /// In those contexts it is always lowercase, but this field is compared
    /// in a way which is case-insensitive for ASCII characters. This allows
    /// `declare_lint!()` invocations to follow the convention of upper-case
    /// statics without repeating the name.
    ///
    /// The name is written with underscores, e.g. "unused_imports".
    /// On the command line, underscores become dashes.
    pub name: &'static str,

    /// Default level for the lint.
    pub default_level: Level,

    /// Description of the lint or the issue it detects.
    ///
    /// e.g. "imports that are never used"
    pub desc: &'static str,
}

impl Lint {
    /// Get the lint's name, with ASCII letters converted to lowercase.
    pub fn name_lower(&self) -> String {
        self.name.to_ascii_lowercase()
    }
}

/// Build a `Lint` initializer.
#[macro_export]
macro_rules! lint_initializer {
    ($name:ident, $level:ident, $desc:expr) => (
        ::rustc::lint::Lint {
            name: stringify!($name),
            default_level: ::rustc::lint::$level,
            desc: $desc,
        }
    )
}

/// Declare a static item of type `&'static Lint`.
#[macro_export]
macro_rules! declare_lint {
    // FIXME(#14660): deduplicate
    (pub $name:ident, $level:ident, $desc:expr) => (
        pub static $name: &'static ::rustc::lint::Lint
            = &lint_initializer!($name, $level, $desc);
    );
    ($name:ident, $level:ident, $desc:expr) => (
        static $name: &'static ::rustc::lint::Lint
            = &lint_initializer!($name, $level, $desc);
    );
}

/// Declare a static `LintArray` and return it as an expression.
#[macro_export]
macro_rules! lint_array { ($( $lint:expr ),*) => (
    {
        static ARRAY: LintArray = &[ $( &$lint ),* ];
        ARRAY
    }
) }

pub type LintArray = &'static [&'static &'static Lint];

pub trait LintPass {
    /// Get descriptions of the lints this `LintPass` object can emit.
    ///
    /// NB: there is no enforcement that the object only emits lints it registered.
    /// And some `rustc` internal `LintPass`es register lints to be emitted by other
    /// parts of the compiler. If you want enforced access restrictions for your
    /// `Lint`, make it a private `static` item in its own module.
    fn get_lints(&self) -> LintArray;
}

/// Trait for types providing lint checks.
///
/// Each `check` method checks a single syntax node, and should not
/// invoke methods recursively (unlike `Visitor`). By default they
/// do nothing.
//
// FIXME: eliminate the duplication with `Visitor`. But this also
// contains a few lint-specific methods with no equivalent in `Visitor`.
pub trait LateLintPass: LintPass {
    fn check_ident(&mut self, _: &LateContext, _: Span, _: ast::Ident) { }
    fn check_crate(&mut self, _: &LateContext, _: &hir::Crate) { }
    fn check_mod(&mut self, _: &LateContext, _: &hir::Mod, _: Span, _: ast::NodeId) { }
    fn check_foreign_item(&mut self, _: &LateContext, _: &hir::ForeignItem) { }
    fn check_item(&mut self, _: &LateContext, _: &hir::Item) { }
    fn check_local(&mut self, _: &LateContext, _: &hir::Local) { }
    fn check_block(&mut self, _: &LateContext, _: &hir::Block) { }
    fn check_stmt(&mut self, _: &LateContext, _: &hir::Stmt) { }
    fn check_arm(&mut self, _: &LateContext, _: &hir::Arm) { }
    fn check_pat(&mut self, _: &LateContext, _: &hir::Pat) { }
    fn check_decl(&mut self, _: &LateContext, _: &hir::Decl) { }
    fn check_expr(&mut self, _: &LateContext, _: &hir::Expr) { }
    fn check_expr_post(&mut self, _: &LateContext, _: &hir::Expr) { }
    fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { }
    fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { }
    fn check_fn(&mut self, _: &LateContext,
        _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { }
    fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { }
    fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { }
    fn check_struct_def(&mut self, _: &LateContext,
        _: &hir::StructDef, _: ast::Ident, _: &hir::Generics, _: ast::NodeId) { }
    fn check_struct_def_post(&mut self, _: &LateContext,
        _: &hir::StructDef, _: ast::Ident, _: &hir::Generics, _: ast::NodeId) { }
    fn check_struct_field(&mut self, _: &LateContext, _: &hir::StructField) { }
    fn check_variant(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
    fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
    fn check_opt_lifetime_ref(&mut self, _: &LateContext, _: Span, _: &Option<hir::Lifetime>) { }
    fn check_lifetime_ref(&mut self, _: &LateContext, _: &hir::Lifetime) { }
    fn check_lifetime_def(&mut self, _: &LateContext, _: &hir::LifetimeDef) { }
    fn check_explicit_self(&mut self, _: &LateContext, _: &hir::ExplicitSelf) { }
    // Note that you shouldn't implement both check_mac and check_ast_mac,
    // because then your lint will be called twice. Prefer check_ast_mac.
    fn check_mac(&mut self, _: &LateContext, _: &ast::Mac) { }
    fn check_path(&mut self, _: &LateContext, _: &hir::Path, _: ast::NodeId) { }
    fn check_attribute(&mut self, _: &LateContext, _: &ast::Attribute) { }

    /// Called when entering a syntax node that can have lint attributes such
    /// as `#[allow(...)]`. Called with *all* the attributes of that node.
    fn enter_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { }

    /// Counterpart to `enter_lint_attrs`.
    fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { }
}

pub trait EarlyLintPass: LintPass {
    fn check_ident(&mut self, _: &EarlyContext, _: Span, _: ast::Ident) { }
    fn check_crate(&mut self, _: &EarlyContext, _: &ast::Crate) { }
    fn check_mod(&mut self, _: &EarlyContext, _: &ast::Mod, _: Span, _: ast::NodeId) { }
    fn check_foreign_item(&mut self, _: &EarlyContext, _: &ast::ForeignItem) { }
    fn check_item(&mut self, _: &EarlyContext, _: &ast::Item) { }
    fn check_local(&mut self, _: &EarlyContext, _: &ast::Local) { }
    fn check_block(&mut self, _: &EarlyContext, _: &ast::Block) { }
    fn check_stmt(&mut self, _: &EarlyContext, _: &ast::Stmt) { }
    fn check_arm(&mut self, _: &EarlyContext, _: &ast::Arm) { }
    fn check_pat(&mut self, _: &EarlyContext, _: &ast::Pat) { }
    fn check_decl(&mut self, _: &EarlyContext, _: &ast::Decl) { }
    fn check_expr(&mut self, _: &EarlyContext, _: &ast::Expr) { }
    fn check_expr_post(&mut self, _: &EarlyContext, _: &ast::Expr) { }
    fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
    fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { }
    fn check_fn(&mut self, _: &EarlyContext,
        _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { }
    fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { }
    fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { }
    fn check_struct_def(&mut self, _: &EarlyContext,
        _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
    fn check_struct_def_post(&mut self, _: &EarlyContext,
        _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
    fn check_struct_field(&mut self, _: &EarlyContext, _: &ast::StructField) { }
    fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
    fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
    fn check_opt_lifetime_ref(&mut self,
                              _: &EarlyContext,
                              _: Span,
                              _: &Option<ast::Lifetime>) { }
    fn check_lifetime_ref(&mut self, _: &EarlyContext, _: &ast::Lifetime) { }
    fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { }
    fn check_explicit_self(&mut self, _: &EarlyContext, _: &ast::ExplicitSelf) { }
    fn check_mac(&mut self, _: &EarlyContext, _: &ast::Mac) { }
    fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { }
    fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { }

    /// Called when entering a syntax node that can have lint attributes such
    /// as `#[allow(...)]`. Called with *all* the attributes of that node.
    fn enter_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { }

    /// Counterpart to `enter_lint_attrs`.
    fn exit_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { }
}

/// A lint pass boxed up as a trait object.
pub type EarlyLintPassObject = Box<EarlyLintPass + 'static>;
pub type LateLintPassObject = Box<LateLintPass + 'static>;

/// Identifies a lint known to the compiler.
#[derive(Clone, Copy)]
pub struct LintId {
    // Identity is based on pointer equality of this field.
    lint: &'static Lint,
}

impl PartialEq for LintId {
    fn eq(&self, other: &LintId) -> bool {
        (self.lint as *const Lint) == (other.lint as *const Lint)
    }
}

impl Eq for LintId { }

impl hash::Hash for LintId {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        let ptr = self.lint as *const Lint;
        ptr.hash(state);
    }
}

impl LintId {
    /// Get the `LintId` for a `Lint`.
    pub fn of(lint: &'static Lint) -> LintId {
        LintId {
            lint: lint,
        }
    }

    /// Get the name of the lint.
    pub fn as_str(&self) -> String {
        self.lint.name_lower()
    }
}

/// Setting for how to handle a lint.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug)]
pub enum Level {
    Allow, Warn, Deny, Forbid
}

impl Level {
    /// Convert a level to a lower-case string.
    pub fn as_str(self) -> &'static str {
        match self {
            Allow => "allow",
            Warn => "warn",
            Deny => "deny",
            Forbid => "forbid",
        }
    }

    /// Convert a lower-case string to a level.
    pub fn from_str(x: &str) -> Option<Level> {
        match x {
            "allow" => Some(Allow),
            "warn" => Some(Warn),
            "deny" => Some(Deny),
            "forbid" => Some(Forbid),
            _ => None,
        }
    }
}

/// How a lint level was set.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum LintSource {
    /// Lint is at the default level as declared
    /// in rustc or a plugin.
    Default,

    /// Lint level was set by an attribute.
    Node(Span),

    /// Lint level was set by a command-line flag.
    CommandLine,
}

pub type LevelSource = (Level, LintSource);

pub mod builtin;

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

//! Lints, aka compiler warnings.
//!
//! A 'lint' check is a kind of miscellaneous constraint that a user _might_
//! want to enforce, but might reasonably want to permit as well, on a
//! module-by-module basis. They contrast with static constraints enforced by
//! other phases of the compiler, which are generally required to hold in order
//! to compile the program at all.
//!
//! Most lints can be written as `LintPass` instances. These run just before
//! translation to LLVM bytecode. The `LintPass`es built into rustc are defined
//! within `builtin.rs`, which has further comments on how to add such a lint.
//! rustc can also load user-defined lint plugins via the plugin mechanism.
//!
//! Some of rustc's lints are defined elsewhere in the compiler and work by
//! calling `add_lint()` on the overall `Session` object. This works when
//! it happens before the main lint pass, which emits the lints stored by
//! `add_lint()`. To emit lints after the main lint pass (from trans, for
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
//! in `context.rs`.

pub use self::Level::*;
pub use self::LintSource::*;

use std::hash;
use std::ascii::AsciiExt;
use syntax::codemap::Span;
use rustc_front::visit::FnKind;
use syntax::visit as ast_visit;
use syntax::ast;
use rustc_front::hir;

pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
                        raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
                        GatherNodeLevels};

/// Specification of a single lint.
#[derive(Copy, Clone, Debug)]
pub struct Lint {
    /// A string identifier for the lint.
    ///
    /// This identifies the lint in attributes and in command-line arguments.
    /// In those contexts it is always lowercase, but this field is compared
    /// in a way which is case-insensitive for ASCII characters. This allows
    /// `declare_lint!()` invocations to follow the convention of upper-case
    /// statics without repeating the name.
    ///
    /// The name is written with underscores, e.g. "unused_imports".
    /// On the command line, underscores become dashes.
    pub name: &'static str,

    /// Default level for the lint.
    pub default_level: Level,

    /// Description of the lint or the issue it detects.
    ///
    /// e.g. "imports that are never used"
    pub desc: &'static str,
}

impl Lint {
    /// Get the lint's name, with ASCII letters converted to lowercase.
    pub fn name_lower(&self) -> String {
        self.name.to_ascii_lowercase()
    }
}

/// Build a `Lint` initializer.
#[macro_export]
macro_rules! lint_initializer {
    ($name:ident, $level:ident, $desc:expr) => (
        ::rustc::lint::Lint {
            name: stringify!($name),
            default_level: ::rustc::lint::$level,
            desc: $desc,
        }
    )
}

/// Declare a static item of type `&'static Lint`.
#[macro_export]
macro_rules! declare_lint {
    // FIXME(#14660): deduplicate
    (pub $name:ident, $level:ident, $desc:expr) => (
        pub static $name: &'static ::rustc::lint::Lint
            = &lint_initializer!($name, $level, $desc);
    );
    ($name:ident, $level:ident, $desc:expr) => (
        static $name: &'static ::rustc::lint::Lint
            = &lint_initializer!($name, $level, $desc);
    );
}

/// Declare a static `LintArray` and return it as an expression.
#[macro_export]
macro_rules! lint_array { ($( $lint:expr ),*) => (
    {
        static ARRAY: LintArray = &[ $( &$lint ),* ];
        ARRAY
    }
) }

pub type LintArray = &'static [&'static &'static Lint];

pub trait LintPass {
    /// Get descriptions of the lints this `LintPass` object can emit.
    ///
    /// NB: there is no enforcement that the object only emits lints it registered.
    /// And some `rustc` internal `LintPass`es register lints to be emitted by other
    /// parts of the compiler. If you want enforced access restrictions for your
    /// `Lint`, make it a private `static` item in its own module.
    fn get_lints(&self) -> LintArray;
}

/// Trait for types providing lint checks.
///
/// Each `check` method checks a single syntax node, and should not
/// invoke methods recursively (unlike `Visitor`). By default they
/// do nothing.
//
// FIXME: eliminate the duplication with `Visitor`. But this also
// contains a few lint-specific methods with no equivalent in `Visitor`.
pub trait LateLintPass: LintPass {
    fn check_ident(&mut self, _: &LateContext, _: Span, _: ast::Ident) { }
    fn check_crate(&mut self, _: &LateContext, _: &hir::Crate) { }
    fn check_mod(&mut self, _: &LateContext, _: &hir::Mod, _: Span, _: ast::NodeId) { }
    fn check_foreign_item(&mut self, _: &LateContext, _: &hir::ForeignItem) { }
    fn check_item(&mut self, _: &LateContext, _: &hir::Item) { }
    fn check_local(&mut self, _: &LateContext, _: &hir::Local) { }
    fn check_block(&mut self, _: &LateContext, _: &hir::Block) { }
    fn check_stmt(&mut self, _: &LateContext, _: &hir::Stmt) { }
    fn check_arm(&mut self, _: &LateContext, _: &hir::Arm) { }
    fn check_pat(&mut self, _: &LateContext, _: &hir::Pat) { }
    fn check_decl(&mut self, _: &LateContext, _: &hir::Decl) { }
    fn check_expr(&mut self, _: &LateContext, _: &hir::Expr) { }
    fn check_expr_post(&mut self, _: &LateContext, _: &hir::Expr) { }
    fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { }
    fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { }
    fn check_fn(&mut self, _: &LateContext,
        _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { }
    fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { }
    fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { }
    fn check_struct_def(&mut self, _: &LateContext,
        _: &hir::StructDef, _: ast::Ident, _: &hir::Generics, _: ast::NodeId) { }
    fn check_struct_def_post(&mut self, _: &LateContext,
        _: &hir::StructDef, _: ast::Ident, _: &hir::Generics, _: ast::NodeId) { }
    fn check_struct_field(&mut self, _: &LateContext, _: &hir::StructField) { }
    fn check_variant(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
    fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
    fn check_opt_lifetime_ref(&mut self, _: &LateContext, _: Span, _: &Option<hir::Lifetime>) { }
    fn check_lifetime_ref(&mut self, _: &LateContext, _: &hir::Lifetime) { }
    fn check_lifetime_def(&mut self, _: &LateContext, _: &hir::LifetimeDef) { }
    fn check_explicit_self(&mut self, _: &LateContext, _: &hir::ExplicitSelf) { }
    fn check_path(&mut self, _: &LateContext, _: &hir::Path, _: ast::NodeId) { }
    fn check_attribute(&mut self, _: &LateContext, _: &ast::Attribute) { }

    /// Called when entering a syntax node that can have lint attributes such
    /// as `#[allow(...)]`. Called with *all* the attributes of that node.
    fn enter_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { }

    /// Counterpart to `enter_lint_attrs`.
    fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { }
}

pub trait EarlyLintPass: LintPass {
    fn check_ident(&mut self, _: &EarlyContext, _: Span, _: ast::Ident) { }
    fn check_crate(&mut self, _: &EarlyContext, _: &ast::Crate) { }
    fn check_mod(&mut self, _: &EarlyContext, _: &ast::Mod, _: Span, _: ast::NodeId) { }
    fn check_foreign_item(&mut self, _: &EarlyContext, _: &ast::ForeignItem) { }
    fn check_item(&mut self, _: &EarlyContext, _: &ast::Item) { }
    fn check_local(&mut self, _: &EarlyContext, _: &ast::Local) { }
    fn check_block(&mut self, _: &EarlyContext, _: &ast::Block) { }
    fn check_stmt(&mut self, _: &EarlyContext, _: &ast::Stmt) { }
    fn check_arm(&mut self, _: &EarlyContext, _: &ast::Arm) { }
    fn check_pat(&mut self, _: &EarlyContext, _: &ast::Pat) { }
    fn check_decl(&mut self, _: &EarlyContext, _: &ast::Decl) { }
    fn check_expr(&mut self, _: &EarlyContext, _: &ast::Expr) { }
    fn check_expr_post(&mut self, _: &EarlyContext, _: &ast::Expr) { }
    fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
    fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { }
    fn check_fn(&mut self, _: &EarlyContext,
        _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { }
    fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { }
    fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { }
    fn check_struct_def(&mut self, _: &EarlyContext,
        _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
    fn check_struct_def_post(&mut self, _: &EarlyContext,
        _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
    fn check_struct_field(&mut self, _: &EarlyContext, _: &ast::StructField) { }
    fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
    fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
    fn check_opt_lifetime_ref(&mut self,
                              _: &EarlyContext,
                              _: Span,
                              _: &Option<ast::Lifetime>) { }
    fn check_lifetime_ref(&mut self, _: &EarlyContext, _: &ast::Lifetime) { }
    fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { }
    fn check_explicit_self(&mut self, _: &EarlyContext, _: &ast::ExplicitSelf) { }
    fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { }
    fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { }

    /// Called when entering a syntax node that can have lint attributes such
    /// as `#[allow(...)]`. Called with *all* the attributes of that node.
    fn enter_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { }

    /// Counterpart to `enter_lint_attrs`.
    fn exit_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { }
}

/// A lint pass boxed up as a trait object.
pub type EarlyLintPassObject = Box<EarlyLintPass + 'static>;
pub type LateLintPassObject = Box<LateLintPass + 'static>;

/// Identifies a lint known to the compiler.
#[derive(Clone, Copy)]
pub struct LintId {
    // Identity is based on pointer equality of this field.
    lint: &'static Lint,
}

impl PartialEq for LintId {
    fn eq(&self, other: &LintId) -> bool {
        (self.lint as *const Lint) == (other.lint as *const Lint)
    }
}

impl Eq for LintId { }

impl hash::Hash for LintId {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        let ptr = self.lint as *const Lint;
        ptr.hash(state);
    }
}

impl LintId {
    /// Get the `LintId` for a `Lint`.
    pub fn of(lint: &'static Lint) -> LintId {
        LintId {
            lint: lint,
        }
    }

    /// Get the name of the lint.
    pub fn as_str(&self) -> String {
        self.lint.name_lower()
    }
}

/// Setting for how to handle a lint.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug)]
pub enum Level {
    Allow, Warn, Deny, Forbid
}

impl Level {
    /// Convert a level to a lower-case string.
    pub fn as_str(self) -> &'static str {
        match self {
            Allow => "allow",
            Warn => "warn",
            Deny => "deny",
            Forbid => "forbid",
        }
    }

    /// Convert a lower-case string to a level.
    pub fn from_str(x: &str) -> Option<Level> {
        match x {
            "allow" => Some(Allow),
            "warn" => Some(Warn),
            "deny" => Some(Deny),
            "forbid" => Some(Forbid),
            _ => None,
        }
    }
}

/// How a lint level was set.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum LintSource {
    /// Lint is at the default level as declared
    /// in rustc or a plugin.
    Default,

    /// Lint level was set by an attribute.
    Node(Span),

    /// Lint level was set by a command-line flag.
    CommandLine,
}

pub type LevelSource = (Level, LintSource);

pub mod builtin;

mod context;
<|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.

//! iOS-specific raw type definitions

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

pub type blkcnt_t = i64;
pub type blksize_t = i32;
pub type dev_t = i32;
pub type ino_t = u64;
pub type mode_t = u16;
pub type nlink_t = u16;
pub type off_t = i64;
pub type time_t = c_long;

#[repr(C)]
pub struct stat {
    pub st_dev: dev_t,
    pub st_mode: mode_t,
    pub st_nlink: nlink_t,
    pub st_ino: ino_t,
    pub st_uid: uid_t,
    pub st_gid: gid_t,
    pub st_rdev: dev_t,
    pub st_atime: time_t,
    pub st_atime_nsec: c_long,
    pub st_mtime: time_t,
    pub st_mtime_nsec: c_long,
    pub st_ctime: time_t,
    pub st_ctime_nsec: c_long,
    pub st_birthtime: time_t,
    pub st_birthtime_nsec: c_long,
    pub st_size: off_t,
    pub st_blocks: blkcnt_t,
    pub st_blksize: blksize_t,
    pub st_flags: u32,
    pub st_gen: u32,
    pub st_lspare: i32,
    pub st_qspare: [i64; 2],
}
<commit_msg>Fixed iOS build<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.

//! iOS-specific raw type definitions

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

pub type blkcnt_t = i64;
pub type blksize_t = i32;
pub type dev_t = i32;
pub type ino_t = u64;
pub type mode_t = u16;
pub type nlink_t = u16;
pub type off_t = i64;
pub type time_t = c_long;

#[repr(C)]
pub struct stat {
    pub st_dev: dev_t,
    pub st_mode: mode_t,
    pub st_nlink: nlink_t,
    pub st_ino: ino_t,
    pub st_uid: uid_t,
    pub st_gid: gid_t,
    pub st_rdev: dev_t,
    pub st_atime: time_t,
    pub st_atime_nsec: c_long,
    pub st_mtime: time_t,
    pub st_mtime_nsec: c_long,
    pub st_ctime: time_t,
    pub st_ctime_nsec: c_long,
    pub st_birthtime: time_t,
    pub st_birthtime_nsec: c_long,
    pub st_size: off_t,
    pub st_blocks: blkcnt_t,
    pub st_blksize: blksize_t,
    pub st_flags: u32,
    pub st_gen: u32,
    pub st_lspare: i32,
    pub st_qspare: [i64; 2],
}
<|endoftext|>


<commit_before>use encoding::all::UTF_16LE;
use encoding::{Encoding, DecoderTrap};
use byteorder::{ReadBytesExt, LittleEndian};
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use std::io::SeekFrom;
use std::io::Read;
use std::io::Seek;

#[derive(Debug)]
pub struct VolumeInfo {
    pub vi_size: u32,
    pub drive_type: u32,
    pub serial_number: u32,
    pub offset_vol_label: u32,
    pub offset_vol_label_unicode: Option<u32>,
    pub volume_label: String,
    pub volume_label_unicode: Option<String>
}

impl VolumeInfo {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<VolumeInfo,LnkError> {
        // Get Current Pos
        let cur_pos = reader.seek(
            SeekFrom::Current(0)
        )?;

        let vi_size = reader.read_u32::<LittleEndian>()?;
        let drive_type = reader.read_u32::<LittleEndian>()?;
        let serial_number = reader.read_u32::<LittleEndian>()?;
        let offset_vol_label = reader.read_u32::<LittleEndian>()?;

        let mut offset_vol_label_unicode = None;
        if offset_vol_label > 16 {
            offset_vol_label_unicode = Some(reader.read_u32::<LittleEndian>()?);
        }

        // Go back to start of VolumeInfo
        reader.seek(
            SeekFrom::Start(cur_pos + offset_vol_label as u64)
        )?;

        // Get volume label
        let volume_label = String::from_utf8(
            utils::get_u8_vec(&mut reader)?
        )?;

        let mut volume_label_unicode = None;
        if offset_vol_label_unicode.is_some() {
            let utf16_buffer = utils::get_u8_vec_utf16(&mut reader)?;
            let utf16_string = match UTF_16LE.decode(&utf16_buffer.as_slice(),DecoderTrap::Ignore) {
                Ok(utf16) => utf16,
                Err(error) => return Err(
                    LnkError::utf16_decode_error(
                        format!("Error decoding name in volume_label_unicode field. [{}]",error)
                    )
                )
            };
            volume_label_unicode = Some(utf16_string);
        }

        Ok(
            VolumeInfo {
                vi_size: vi_size,
                drive_type: drive_type,
                serial_number: serial_number,
                offset_vol_label: offset_vol_label,
                offset_vol_label_unicode: offset_vol_label_unicode,
                volume_label: volume_label,
                volume_label_unicode: volume_label_unicode
            }
        )
    }
}
<commit_msg>switched to string helper methods<commit_after>use encoding::all::UTF_16LE;
use encoding::{Encoding, DecoderTrap};
use byteorder::{ReadBytesExt, LittleEndian};
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use std::io::SeekFrom;
use std::io::Read;
use std::io::Seek;

#[derive(Debug)]
pub struct VolumeInfo {
    pub vi_size: u32,
    pub drive_type: u32,
    pub serial_number: u32,
    pub offset_vol_label: u32,
    pub offset_vol_label_unicode: Option<u32>,
    pub volume_label: String,
    pub volume_label_unicode: Option<String>
}

impl VolumeInfo {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<VolumeInfo,LnkError> {
        // Get Current Pos
        let _offset = reader.seek(
            SeekFrom::Current(0)
        )?;

        let vi_size = reader.read_u32::<LittleEndian>()?;
        let drive_type = reader.read_u32::<LittleEndian>()?;
        let serial_number = reader.read_u32::<LittleEndian>()?;
        let offset_vol_label = reader.read_u32::<LittleEndian>()?;

        let mut offset_vol_label_unicode = None;
        if offset_vol_label > 16 {
            offset_vol_label_unicode = Some(reader.read_u32::<LittleEndian>()?);
        }

        // Get volume label
        reader.seek(
            SeekFrom::Start(_offset + offset_vol_label as u64)
        )?;
        let volume_label = utils::read_string_u8_till_null(&mut reader)?;

        let mut volume_label_unicode = None;
        if offset_vol_label_unicode.is_some() {
            reader.seek(
                SeekFrom::Start(_offset + offset_vol_label_unicode.unwrap() as u64)
            )?;
            volume_label_unicode = Some(utils::read_string_u16_till_null(&mut reader)?);
        }

        Ok(
            VolumeInfo {
                vi_size: vi_size,
                drive_type: drive_type,
                serial_number: serial_number,
                offset_vol_label: offset_vol_label,
                offset_vol_label_unicode: offset_vol_label_unicode,
                volume_label: volume_label,
                volume_label_unicode: volume_label_unicode
            }
        )
    }
}
<|endoftext|>