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

use std::io::Write;

use rustc::hir::def_id::DefId;
use rustc_serialize::json::as_json;

use external_data::*;
use data::VariableKind;
use dump::Dump;
use super::Format;

pub struct JsonDumper<'b, W: Write + 'b> {
    output: &'b mut W,
    result: Analysis,
}

impl<'b, W: Write> JsonDumper<'b, W> {
    pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> {
        JsonDumper { output: writer, result: Analysis::new() }
    }
}

impl<'b, W: Write> Drop for JsonDumper<'b, W> {
    fn drop(&mut self) {
        if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
            error!("Error writing output");
        }
    }
}

macro_rules! impl_fn {
    ($fn_name: ident, $data_type: ident, $bucket: ident) => {
        fn $fn_name(&mut self, data: $data_type) {
            self.result.$bucket.push(From::from(data));
        }
    }
}

impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> {
    fn crate_prelude(&mut self, data: CratePreludeData) {
        self.result.prelude = Some(data)
    }

    impl_fn!(extern_crate, ExternCrateData, imports);
    impl_fn!(use_data, UseData, imports);
    impl_fn!(use_glob, UseGlobData, imports);

    impl_fn!(enum_data, EnumData, defs);
    impl_fn!(tuple_variant, TupleVariantData, defs);
    impl_fn!(struct_variant, StructVariantData, defs);
    impl_fn!(struct_data, StructData, defs);
    impl_fn!(trait_data, TraitData, defs);
    impl_fn!(function, FunctionData, defs);
    impl_fn!(method, MethodData, defs);
    impl_fn!(macro_data, MacroData, defs);
    impl_fn!(mod_data, ModData, defs);
    impl_fn!(typedef, TypeDefData, defs);
    impl_fn!(variable, VariableData, defs);

    impl_fn!(function_ref, FunctionRefData, refs);
    impl_fn!(function_call, FunctionCallData, refs);
    impl_fn!(method_call, MethodCallData, refs);
    impl_fn!(mod_ref, ModRefData, refs);
    impl_fn!(type_ref, TypeRefData, refs);
    impl_fn!(variable_ref, VariableRefData, refs);

    impl_fn!(macro_use, MacroUseData, macro_refs);

    // FIXME store this instead of throwing it away.
    fn impl_data(&mut self, _data: ImplData) {}
    fn inheritance(&mut self, _data: InheritanceData) {}
}

// FIXME do we want to change ExternalData to this mode? It will break DXR.
// FIXME methods. The defs have information about possible overriding and the
// refs have decl information (e.g., a trait method where we know the required
// method, but not the supplied method). In both cases, we are currently
// ignoring it.

#[derive(Debug, RustcEncodable)]
struct Analysis {
    kind: Format,
    prelude: Option<CratePreludeData>,
    imports: Vec<Import>,
    defs: Vec<Def>,
    refs: Vec<Ref>,
    macro_refs: Vec<MacroRef>,
}

impl Analysis {
    fn new() -> Analysis {
        Analysis {
            kind: Format::Json,
            prelude: None,
            imports: vec![],
            defs: vec![],
            refs: vec![],
            macro_refs: vec![],
        }
    }
}

// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore
// we use our own Id which is the same, but without the newtype.
#[derive(Debug, RustcEncodable)]
struct Id {
    krate: u32,
    index: u32,
}

impl From<DefId> for Id {
    fn from(id: DefId) -> Id {
        Id {
            krate: id.krate.as_u32(),
            index: id.index.as_u32(),
        }
    }
}

#[derive(Debug, RustcEncodable)]
struct Import {
    kind: ImportKind,
    ref_id: Option<Id>,
    span: SpanData,
    name: String,
    value: String,
}

#[derive(Debug, RustcEncodable)]
enum ImportKind {
    ExternCrate,
    Use,
    GlobUse,
}

impl From<ExternCrateData> for Import {
    fn from(data: ExternCrateData) -> Import {
        Import {
            kind: ImportKind::ExternCrate,
            ref_id: None,
            span: data.span,
            name: data.name,
            value: String::new(),
        }
    }
}
impl From<UseData> for Import {
    fn from(data: UseData) -> Import {
        Import {
            kind: ImportKind::Use,
            ref_id: data.mod_id.map(|id| From::from(id)),
            span: data.span,
            name: data.name,
            value: String::new(),
        }
    }
}
impl From<UseGlobData> for Import {
    fn from(data: UseGlobData) -> Import {
        Import {
            kind: ImportKind::GlobUse,
            ref_id: None,
            span: data.span,
            name: "*".to_owned(),
            value: data.names.join(", "),
        }
    }
}

#[derive(Debug, RustcEncodable)]
struct Def {
    kind: DefKind,
    id: Id,
    span: SpanData,
    name: String,
    qualname: String,
    value: String,
    children: Vec<Id>,
    decl_id: Option<Id>,
    docs: String,
}

#[derive(Debug, RustcEncodable)]
enum DefKind {
    // value = variant names
    Enum,
    // value = enum name + variant name + types
    Tuple,
    // value = [enum name +] name + fields
    Struct,
    // value = signature
    Trait,
    // value = type + generics
    Function,
    // value = type + generics
    Method,
    // No id, no value.
    Macro,
    // value = file_name
    Mod,
    // value = aliased type
    Type,
    // value = type and init expression (for all variable kinds).
    Local,
    Static,
    Const,
    Field,
}

impl From<EnumData> for Def {
    fn from(data: EnumData) -> Def {
        Def {
            kind: DefKind::Enum,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: data.variants.into_iter().map(|id| From::from(id)).collect(),
            decl_id: None,
            docs: data.docs,
        }
    }
}

impl From<TupleVariantData> for Def {
    fn from(data: TupleVariantData) -> Def {
        Def {
            kind: DefKind::Tuple,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<StructVariantData> for Def {
    fn from(data: StructVariantData) -> Def {
        Def {
            kind: DefKind::Struct,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<StructData> for Def {
    fn from(data: StructData) -> Def {
        Def {
            kind: DefKind::Struct,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: data.fields.into_iter().map(|id| From::from(id)).collect(),
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<TraitData> for Def {
    fn from(data: TraitData) -> Def {
        Def {
            kind: DefKind::Trait,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: data.items.into_iter().map(|id| From::from(id)).collect(),
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<FunctionData> for Def {
    fn from(data: FunctionData) -> Def {
        Def {
            kind: DefKind::Function,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<MethodData> for Def {
    fn from(data: MethodData) -> Def {
        Def {
            kind: DefKind::Method,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: data.decl_id.map(|id| From::from(id)),
            docs: data.docs,
        }
    }
}
impl From<MacroData> for Def {
    fn from(data: MacroData) -> Def {
        Def {
            kind: DefKind::Macro,
            id: From::from(null_def_id()),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: String::new(),
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<ModData> for Def {
    fn from(data:ModData) -> Def {
        Def {
            kind: DefKind::Mod,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.filename,
            children: data.items.into_iter().map(|id| From::from(id)).collect(),
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<TypeDefData> for Def {
    fn from(data: TypeDefData) -> Def {
        Def {
            kind: DefKind::Type,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: None,
            docs: String::new(),
        }
    }
}
impl From<VariableData> for Def {
    fn from(data: VariableData) -> Def {
        Def {
            kind: match data.kind {
                VariableKind::Static => DefKind::Static,
                VariableKind::Const => DefKind::Const,
                VariableKind::Local => DefKind::Local,
                VariableKind::Field => DefKind::Field,
            },
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.type_value,
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}

#[derive(Debug, RustcEncodable)]
enum RefKind {
    Function,
    Mod,
    Type,
    Variable,
}

#[derive(Debug, RustcEncodable)]
struct Ref {
    kind: RefKind,
    span: SpanData,
    ref_id: Id,
}

impl From<FunctionRefData> for Ref {
    fn from(data: FunctionRefData) -> Ref {
        Ref {
            kind: RefKind::Function,
            span: data.span,
            ref_id: From::from(data.ref_id),
        }
    }
}
impl From<FunctionCallData> for Ref {
    fn from(data: FunctionCallData) -> Ref {
        Ref {
            kind: RefKind::Function,
            span: data.span,
            ref_id: From::from(data.ref_id),
        }
    }
}
impl From<MethodCallData> for Ref {
    fn from(data: MethodCallData) -> Ref {
        Ref {
            kind: RefKind::Function,
            span: data.span,
            ref_id: From::from(data.ref_id.or(data.decl_id).unwrap_or(null_def_id())),
        }
    }
}
impl From<ModRefData> for Ref {
    fn from(data: ModRefData) -> Ref {
        Ref {
            kind: RefKind::Mod,
            span: data.span,
            ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
        }
    }
}
impl From<TypeRefData> for Ref {
    fn from(data: TypeRefData) -> Ref {
        Ref {
            kind: RefKind::Type,
            span: data.span,
            ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
        }
    }
}
impl From<VariableRefData> for Ref {
    fn from(data: VariableRefData) -> Ref {
        Ref {
            kind: RefKind::Variable,
            span: data.span,
            ref_id: From::from(data.ref_id),
        }
    }
}

#[derive(Debug, RustcEncodable)]
struct MacroRef {
    span: SpanData,
    qualname: String,
    callee_span: SpanData,
}

impl From<MacroUseData> for MacroRef {
    fn from(data: MacroUseData) -> MacroRef {
        MacroRef {
            span: data.span,
            qualname: data.qualname,
            callee_span: data.callee_span,
        }
    }
}
<commit_msg>Auto merge of #37989 - nrc:save-mod, r=nikomatsakis<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io::Write;

use rustc::hir::def_id::DefId;
use rustc_serialize::json::as_json;

use external_data::*;
use data::VariableKind;
use dump::Dump;
use super::Format;

pub struct JsonDumper<'b, W: Write + 'b> {
    output: &'b mut W,
    result: Analysis,
}

impl<'b, W: Write> JsonDumper<'b, W> {
    pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> {
        JsonDumper { output: writer, result: Analysis::new() }
    }
}

impl<'b, W: Write> Drop for JsonDumper<'b, W> {
    fn drop(&mut self) {
        if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
            error!("Error writing output");
        }
    }
}

macro_rules! impl_fn {
    ($fn_name: ident, $data_type: ident, $bucket: ident) => {
        fn $fn_name(&mut self, data: $data_type) {
            self.result.$bucket.push(From::from(data));
        }
    }
}

impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> {
    fn crate_prelude(&mut self, data: CratePreludeData) {
        self.result.prelude = Some(data)
    }

    impl_fn!(extern_crate, ExternCrateData, imports);
    impl_fn!(use_data, UseData, imports);
    impl_fn!(use_glob, UseGlobData, imports);

    impl_fn!(enum_data, EnumData, defs);
    impl_fn!(tuple_variant, TupleVariantData, defs);
    impl_fn!(struct_variant, StructVariantData, defs);
    impl_fn!(struct_data, StructData, defs);
    impl_fn!(trait_data, TraitData, defs);
    impl_fn!(function, FunctionData, defs);
    impl_fn!(method, MethodData, defs);
    impl_fn!(macro_data, MacroData, defs);
    impl_fn!(typedef, TypeDefData, defs);
    impl_fn!(variable, VariableData, defs);

    impl_fn!(function_ref, FunctionRefData, refs);
    impl_fn!(function_call, FunctionCallData, refs);
    impl_fn!(method_call, MethodCallData, refs);
    impl_fn!(mod_ref, ModRefData, refs);
    impl_fn!(type_ref, TypeRefData, refs);
    impl_fn!(variable_ref, VariableRefData, refs);

    impl_fn!(macro_use, MacroUseData, macro_refs);

    fn mod_data(&mut self, data: ModData) {
        let id: Id = From::from(data.id);
        let mut def = Def {
            kind: DefKind::Mod,
            id: id,
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.filename,
            children: data.items.into_iter().map(|id| From::from(id)).collect(),
            decl_id: None,
            docs: data.docs,
        };
        if def.span.file_name != def.value {
            // If the module is an out-of-line defintion, then we'll make the
            // defintion the first character in the module's file and turn the
            // the declaration into a reference to it.
            let rf = Ref {
                kind: RefKind::Mod,
                span: def.span,
                ref_id: id,
            };
            self.result.refs.push(rf);
            def.span = SpanData {
                file_name: def.value.clone(),
                byte_start: 0,
                byte_end: 0,
                line_start: 1,
                line_end: 1,
                column_start: 1,
                column_end: 1,
            }
        }

        self.result.defs.push(def);
    }

    // FIXME store this instead of throwing it away.
    fn impl_data(&mut self, _data: ImplData) {}
    fn inheritance(&mut self, _data: InheritanceData) {}
}

// FIXME do we want to change ExternalData to this mode? It will break DXR.
// FIXME methods. The defs have information about possible overriding and the
// refs have decl information (e.g., a trait method where we know the required
// method, but not the supplied method). In both cases, we are currently
// ignoring it.

#[derive(Debug, RustcEncodable)]
struct Analysis {
    kind: Format,
    prelude: Option<CratePreludeData>,
    imports: Vec<Import>,
    defs: Vec<Def>,
    refs: Vec<Ref>,
    macro_refs: Vec<MacroRef>,
}

impl Analysis {
    fn new() -> Analysis {
        Analysis {
            kind: Format::Json,
            prelude: None,
            imports: vec![],
            defs: vec![],
            refs: vec![],
            macro_refs: vec![],
        }
    }
}

// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore
// we use our own Id which is the same, but without the newtype.
#[derive(Clone, Copy, Debug, RustcEncodable)]
struct Id {
    krate: u32,
    index: u32,
}

impl From<DefId> for Id {
    fn from(id: DefId) -> Id {
        Id {
            krate: id.krate.as_u32(),
            index: id.index.as_u32(),
        }
    }
}

#[derive(Debug, RustcEncodable)]
struct Import {
    kind: ImportKind,
    ref_id: Option<Id>,
    span: SpanData,
    name: String,
    value: String,
}

#[derive(Debug, RustcEncodable)]
enum ImportKind {
    ExternCrate,
    Use,
    GlobUse,
}

impl From<ExternCrateData> for Import {
    fn from(data: ExternCrateData) -> Import {
        Import {
            kind: ImportKind::ExternCrate,
            ref_id: None,
            span: data.span,
            name: data.name,
            value: String::new(),
        }
    }
}
impl From<UseData> for Import {
    fn from(data: UseData) -> Import {
        Import {
            kind: ImportKind::Use,
            ref_id: data.mod_id.map(|id| From::from(id)),
            span: data.span,
            name: data.name,
            value: String::new(),
        }
    }
}
impl From<UseGlobData> for Import {
    fn from(data: UseGlobData) -> Import {
        Import {
            kind: ImportKind::GlobUse,
            ref_id: None,
            span: data.span,
            name: "*".to_owned(),
            value: data.names.join(", "),
        }
    }
}

#[derive(Debug, RustcEncodable)]
struct Def {
    kind: DefKind,
    id: Id,
    span: SpanData,
    name: String,
    qualname: String,
    value: String,
    children: Vec<Id>,
    decl_id: Option<Id>,
    docs: String,
}

#[derive(Debug, RustcEncodable)]
enum DefKind {
    // value = variant names
    Enum,
    // value = enum name + variant name + types
    Tuple,
    // value = [enum name +] name + fields
    Struct,
    // value = signature
    Trait,
    // value = type + generics
    Function,
    // value = type + generics
    Method,
    // No id, no value.
    Macro,
    // value = file_name
    Mod,
    // value = aliased type
    Type,
    // value = type and init expression (for all variable kinds).
    Local,
    Static,
    Const,
    Field,
}

impl From<EnumData> for Def {
    fn from(data: EnumData) -> Def {
        Def {
            kind: DefKind::Enum,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: data.variants.into_iter().map(|id| From::from(id)).collect(),
            decl_id: None,
            docs: data.docs,
        }
    }
}

impl From<TupleVariantData> for Def {
    fn from(data: TupleVariantData) -> Def {
        Def {
            kind: DefKind::Tuple,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<StructVariantData> for Def {
    fn from(data: StructVariantData) -> Def {
        Def {
            kind: DefKind::Struct,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<StructData> for Def {
    fn from(data: StructData) -> Def {
        Def {
            kind: DefKind::Struct,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: data.fields.into_iter().map(|id| From::from(id)).collect(),
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<TraitData> for Def {
    fn from(data: TraitData) -> Def {
        Def {
            kind: DefKind::Trait,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: data.items.into_iter().map(|id| From::from(id)).collect(),
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<FunctionData> for Def {
    fn from(data: FunctionData) -> Def {
        Def {
            kind: DefKind::Function,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}
impl From<MethodData> for Def {
    fn from(data: MethodData) -> Def {
        Def {
            kind: DefKind::Method,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: data.decl_id.map(|id| From::from(id)),
            docs: data.docs,
        }
    }
}
impl From<MacroData> for Def {
    fn from(data: MacroData) -> Def {
        Def {
            kind: DefKind::Macro,
            id: From::from(null_def_id()),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: String::new(),
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}

impl From<TypeDefData> for Def {
    fn from(data: TypeDefData) -> Def {
        Def {
            kind: DefKind::Type,
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.value,
            children: vec![],
            decl_id: None,
            docs: String::new(),
        }
    }
}
impl From<VariableData> for Def {
    fn from(data: VariableData) -> Def {
        Def {
            kind: match data.kind {
                VariableKind::Static => DefKind::Static,
                VariableKind::Const => DefKind::Const,
                VariableKind::Local => DefKind::Local,
                VariableKind::Field => DefKind::Field,
            },
            id: From::from(data.id),
            span: data.span,
            name: data.name,
            qualname: data.qualname,
            value: data.type_value,
            children: vec![],
            decl_id: None,
            docs: data.docs,
        }
    }
}

#[derive(Debug, RustcEncodable)]
enum RefKind {
    Function,
    Mod,
    Type,
    Variable,
}

#[derive(Debug, RustcEncodable)]
struct Ref {
    kind: RefKind,
    span: SpanData,
    ref_id: Id,
}

impl From<FunctionRefData> for Ref {
    fn from(data: FunctionRefData) -> Ref {
        Ref {
            kind: RefKind::Function,
            span: data.span,
            ref_id: From::from(data.ref_id),
        }
    }
}
impl From<FunctionCallData> for Ref {
    fn from(data: FunctionCallData) -> Ref {
        Ref {
            kind: RefKind::Function,
            span: data.span,
            ref_id: From::from(data.ref_id),
        }
    }
}
impl From<MethodCallData> for Ref {
    fn from(data: MethodCallData) -> Ref {
        Ref {
            kind: RefKind::Function,
            span: data.span,
            ref_id: From::from(data.ref_id.or(data.decl_id).unwrap_or(null_def_id())),
        }
    }
}
impl From<ModRefData> for Ref {
    fn from(data: ModRefData) -> Ref {
        Ref {
            kind: RefKind::Mod,
            span: data.span,
            ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
        }
    }
}
impl From<TypeRefData> for Ref {
    fn from(data: TypeRefData) -> Ref {
        Ref {
            kind: RefKind::Type,
            span: data.span,
            ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
        }
    }
}
impl From<VariableRefData> for Ref {
    fn from(data: VariableRefData) -> Ref {
        Ref {
            kind: RefKind::Variable,
            span: data.span,
            ref_id: From::from(data.ref_id),
        }
    }
}

#[derive(Debug, RustcEncodable)]
struct MacroRef {
    span: SpanData,
    qualname: String,
    callee_span: SpanData,
}

impl From<MacroUseData> for MacroRef {
    fn from(data: MacroUseData) -> MacroRef {
        MacroRef {
            span: data.span,
            qualname: data.qualname,
            callee_span: data.callee_span,
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Add file descriptor type<commit_after>/// A file descriptor type
pub type Fd = usize;
<|endoftext|>


<commit_before><commit_msg>Actually note when the writer thread flushes.<commit_after><|endoftext|>


<commit_before><commit_msg>Add regression test for atomics being Send + Sync<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.

// pretty-expanded FIXME #23616

use std::sync::atomic::*;

trait SendSync: Send + Sync {}

impl SendSync for AtomicBool {}
impl SendSync for AtomicIsize {}
impl SendSync for AtomicUsize {}
impl<T> SendSync for AtomicPtr<T> {}

fn main() {}
<|endoftext|>


<commit_before><commit_msg>Don't show <: and :(id):> around Unicode emoji<commit_after><|endoftext|>


<commit_before>const NEXT: *mut u64 = 0x200010 as *mut u64;

/// Generate pseudo random number
pub fn rand() -> usize {
    unsafe {
        (*NEXT) = (*NEXT) * 1103515245 + 12345;
        ((*NEXT) / 65536) as usize
    }
}

/// Generate pseudo random number via seed
pub fn srand(seed: usize) {
    unsafe {
        (*NEXT) = seed as u64;
    }
}
<commit_msg>Make PRNG in the kernel more random<commit_after>static mut seed: u64 = 19940046431; //259261034506304368955239; //1706322144714608529217229883707268827757977089;

/// Generate pseudo random number
pub fn rand() -> usize {
    seed ^= seed << 12;
    seed ^= seed << 25;
    seed ^= seed << 27;
    seed = seed * 82724793451 + 12345;
    seed as usize % ::core::usize::MAX
}

/// Generate pseudo random number via seed
pub fn srand(s: usize) {
    seed = s as u64;
}
<|endoftext|>


<commit_before><commit_msg>First version<commit_after>#![crate_type = "rlib"]
#![crate_id = "jlens#0.0.1"]
#![feature(globs)]

extern crate serialize;

use serialize::json;
use std::collections::hashmap;

pub struct Path<'a,'b>(&'a json::Json, Option<&'b Path<'a,'b>>);

pub trait Selector {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|);
}

pub struct Node {
    _dummy: ()
}

impl<'f> Selector for Node {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        f(input)
    }
}

pub struct Object<S> {
    inner: S
}

impl<S:Selector> Selector for Object<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::Object(..),_) => f(x),
                _ => ()
            }
        })
    }
}

pub struct List<S> {
    inner: S
}

impl<S:Selector> Selector for List<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::List(..),_) => f(x),
                _ => ()
            }
        })
    }
}

pub struct String<S> {
    inner: S
}

pub struct StringEquals<'a,S> {
    inner: S,
    comp: &'a str
}

impl<S:Selector> String<S> {
    pub fn equals<'a,'b>(self, comp: &'a str) -> StringEquals<'a,S> {
        let String { inner: inner } = self;
        StringEquals { inner: inner, comp: comp }
    }
}

impl<S:Selector> Selector for String<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::String(..),_) => f(x),
                _ => ()
            }
        })
    }
}

impl<'a,S:Selector> Selector for StringEquals<'a,S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::String(ref s),_) if self.comp.equiv(s) => f(x),
                _ => ()
            }
        })
    }
}

pub struct Boolean<S> {
    inner: S
}

pub struct BooleanEquals<S> {
    inner: S,
    comp: bool
}

impl<S:Selector> Boolean<S> {
    pub fn equals(self, comp: bool) -> BooleanEquals<S> {
        let Boolean { inner: inner } = self;
        BooleanEquals { inner: inner, comp: comp }
    }
}

impl<S:Selector> Selector for Boolean<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::Boolean(..),_) => f(x),
                _ => ()
            }
        })
    }
}

impl<S:Selector> Selector for BooleanEquals<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::Boolean(b),_) if b == self.comp => f(x),
                _ => ()
            }
        })
    }
}

pub struct Number<S> {
    inner: S
}

pub struct NumberEquals<S> {
    inner: S,
    comp: f64
}

impl<S:Selector> Number<S> {
    pub fn equals(self, comp: f64) -> NumberEquals<S> {
        let Number { inner: inner } = self;
        NumberEquals { inner: inner, comp: comp }
    }
}

impl<S:Selector> Selector for Number<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::Number(..),_) => f(x),
                _ => ()
            }
        })
    }
}

impl<S:Selector> Selector for NumberEquals<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::Number(b),_) if b == self.comp => f(x),
                _ => ()
            }
        })
    }
}

pub struct At<S> {
    inner: S,
    index: uint
}

impl<S:Selector> Selector for At<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::List(ref v),_) => {
                    if v.len() > self.index {
                        f(Path(v.get(self.index),Some(&x)))
                    }
                }
                _ => ()
            }
        })
    }
}

pub struct Key<'f,S> {
    inner: S,
    name: &'f str
}

impl<'f,S:Selector> Selector for Key<'f,S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::Object(box ref m),_) => {
                    match m.find(&self.name.to_string()) {
                        Some(e) => f(Path(e,Some(&x))),
                        _ => ()
                    }
                },
                _ => ()
            }
        })
    }
}

pub struct Child<S> {
    inner: S
}

impl<S:Selector> Selector for Child<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(&json::Object(box ref m),_) => {
                    for (_,child) in m.iter() {
                        f(Path(child,Some(&x)))
                    }
                },
                Path(&json::List(ref v),_) => {
                    for child in v.iter() {
                        f(Path(child,Some(&x)))
                    }
                },
                _ => ()
            }
        })
    }
}

pub struct Parent<S> {
    inner: S
}

impl<S:Selector> Selector for Parent<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            match x {
                Path(_,Some(&p)) => f(p),
                _ => ()
            }
        })
    }
}

pub struct Descend<S> {
    inner: S
}

fn descend_helper<'a,'b>(input@Path(j,_): Path<'a,'b>,
                         seen: &mut hashmap::HashSet<*json::Json>,
                         f: <'c>|Path<'a,'c>|) {
    if !seen.contains(&(j as *json::Json)) {
        seen.insert(j as *json::Json);
        match j {
            &json::Object(box ref m) => {
                for (_,c) in m.iter() {
                    let inner = Path(c,Some(&input));
                    f(inner);
                    descend_helper(inner, seen, |x| f(x))
                }
            },
            &json::List(ref v) => {
                for c in v.iter() {
                    let inner = Path(c,Some(&input));
                    f(inner);
                    descend_helper(inner, seen, |x| f(x))
                }
            },
            _ => ()
        }
    }
}

impl<S:Selector> Selector for Descend<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        let mut seen = hashmap::HashSet::new();
        self.inner.select(input, |x| {
            descend_helper(x, &mut seen, |x| f(x))
        })
    }
}

pub struct Ascend<S> {
    inner: S
}

impl<S:Selector> Selector for Ascend<S> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |mut n| {
            loop {
                match n {
                    Path(_,Some(&x)) => {
                        f(x);
                        n = x;
                    },
                    _ => break
                }
            }
        })
    }
}

pub struct Where<S,T> {
    inner: S,
    filter: T
}

impl<S:Selector,T:Selector> Selector for Where<S,T> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        self.inner.select(input, |x| {
            let mut matches = false;
            self.filter.select(x, |_| matches = true);
            if matches {
                f(x)
            }
        })
    }
}

pub struct Union<I,S,T> {
    inner: I,
    left: S,
    right: T
}

impl<I:Selector,S:Selector,T:Selector> Selector for Union<I,S,T> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        let mut seen = hashmap::HashSet::new();
        self.inner.select(input, |x| {
            self.left.select(x, |x@Path(j,_)| {
                if !seen.contains(&(j as *json::Json)) {
                    seen.insert(j as *json::Json);
                    f(x)
                }
            });
            self.right.select(x, |x@Path(j,_)| {
                if !seen.contains(&(j as *json::Json)) {
                    seen.insert(j as *json::Json);
                    f(x)
                }
            })
        })
    }
}

pub struct Intersect<I,S,T> {
    inner: I,
    left: S,
    right: T
}

impl<I:Selector,S:Selector,T:Selector> Selector for Intersect<I,S,T> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        let mut seen_left = hashmap::HashSet::new();
        let mut seen_right = hashmap::HashSet::new();
        self.inner.select(input, |x| {
            self.left.select(x, |Path(j,_)| {
                seen_left.insert(j as *json::Json);
                if seen_right.contains(&(j as *json::Json)) {
                    f(x)
                }
            });
            self.right.select(x, |x@Path(j,_)| {
                seen_right.insert(j as *json::Json);
                if seen_left.contains(&(j as *json::Json)) {
                    f(x)
                }
            })
        })
    }
}

pub struct Diff<I,S,T> {
    inner: I,
    left: S,
    right: T
}

// FIXME: this has bad asymptotic behavior
// The results of the inner select can't be cached
// because the path breadcrumbs have a lifetime that
// can't escape the callback
impl<I:Selector,S:Selector,T:Selector> Selector for Diff<I,S,T> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        let mut seen = hashmap::HashSet::new();
        self.inner.select(input, |x| {
            self.right.select(x, |Path(j,_)| {
                seen.insert(j as *json::Json);
            })
        });
        self.inner.select(input, |x| {
            self.left.select(x, |x@Path(j,_)| {
                if !seen.contains(&(j as *json::Json)) {
                    f(x)
                }
            })
        })
    }
}

pub struct And<I,S,T> {
    inner: I,
    left: S,
    right: T
}

static SINGLETON: json::Json = json::Boolean(true);

impl<I:Selector,S:Selector,T:Selector> Selector for And<I,S,T> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        let mut found_left = false;
        let mut found_right = false;
        self.inner.select(input, |x| {
            self.left.select(x, |_| found_left = true);
            self.right.select(x, |_| found_right = true)
        });
        if found_left && found_right {
            f(Path(&SINGLETON, Some(&input)))
        }
    }
}

pub struct Or<I,S,T> {
    inner: I,
    left: S,
    right: T
}

impl<I:Selector,S:Selector,T:Selector> Selector for Or<I,S,T> {
    fn select<'a,'b>(&self, input: Path<'a,'b>, f: <'c>|Path<'a,'c>|) {
        let mut found_left = false;
        let mut found_right = false;
        self.inner.select(input, |x| {
            self.left.select(x, |_| found_left = true);
            self.right.select(x, |_| found_right = true)
        });
        if found_left || found_right {
            f(Path(&SINGLETON, Some(&input)))
        }
    }
}

pub trait SelectorExt {
    fn boolean(self) -> Boolean<Self>;
    fn number(self) -> Number<Self>;
    fn string(self) -> String<Self>;
    fn object(self) -> Object<Self>;
    fn list(self) -> List<Self>;
    fn at(self, index: uint) -> At<Self>;
    fn key<'a>(self, name: &'a str) -> Key<'a, Self>;
    fn child(self) -> Child<Self>;
    fn parent(self) -> Parent<Self>;
    fn descend(self) -> Descend<Self>;
    fn ascend(self) -> Ascend<Self>;
    fn where<T:Selector>(self, filter: T) -> Where<Self,T>;
    fn intersect<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> Intersect<Self,T1,T2>;
    fn union<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> Union<Self,T1,T2>;
    fn diff<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> Diff<Self,T1,T2>;
    fn and<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> And<Self,T1,T2>;
    fn or<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> Or<Self,T1,T2>;
}

impl<S:Selector> SelectorExt for S {
    fn boolean(self) -> Boolean<S> {
        Boolean { inner: self }
    }
    fn number(self) -> Number<S> {
        Number { inner: self }
    }
    fn string(self) -> String<S> {
        String { inner: self }
    }
    fn object(self) -> Object<S> {
        Object { inner: self }
    }
    fn list(self) -> List<S> {
        List { inner: self }
    }
    fn at(self, index: uint) -> At<S> {
        At { inner: self, index: index }
    }
    fn key<'a>(self, name: &'a str) -> Key<'a, S> {
        Key { inner: self, name: name }
    }
    fn child(self) -> Child<S> {
        Child { inner: self }
    }
    fn parent(self) -> Parent<S> {
        Parent { inner: self }
    }
    fn descend(self) -> Descend<S> {
        Descend { inner: self }
    }
    fn ascend(self) -> Ascend<S> {
        Ascend { inner: self }
    }
    fn where<T:Selector>(self, filter: T) -> Where<S,T> {
        Where { inner: self, filter: filter }
    }
    fn union<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> Union<S,T1,T2> {
        Union { inner: self, left: left, right: right }
    }
    fn intersect<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> Intersect<S,T1,T2> {
        Intersect { inner: self, left: left, right: right }
    }
    fn diff<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> Diff<S,T1,T2> {
        Diff { inner: self, left: left, right: right }
    }
    fn and<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> And<S,T1,T2> {
        And { inner: self, left: left, right: right }
    }
    fn or<T1:Selector,T2:Selector>(self, left: T1, right: T2) -> Or<S,T1,T2> {
        Or { inner: self, left: left, right: right }
    }
}

pub trait JsonExt {
    fn query<'a,S:Selector>(&'a self, s: S) -> Vec<&'a json::Json>;
}

impl JsonExt for json::Json {
    fn query<'a,S:Selector>(&'a self, s: S) -> Vec<&'a json::Json> {
        let mut outvec = Vec::new();
        {
            let output = &mut outvec;
            s.select(Path(self,None), |Path(j,_)| {
                output.push(j)
            });
        }

        outvec
    }
}

pub fn node() -> Node {
    Node { _dummy: () }
}

pub fn boolean() -> Boolean<Node> {
    node().boolean()
}

pub fn number() -> Number<Node> {
    node().number()
}

pub fn string() -> String<Node> {
    node().string()
}

pub fn object() -> Object<Node> {
    node().object()
}

pub fn list() -> List<Node> {
    node().list()
}

pub fn child() -> Child<Node> {
    node().child()
}

pub fn parent() -> Parent<Node> {
    node().parent()
}

pub fn descend() -> Descend<Node> {
    node().descend()
}

pub fn ascend() -> Ascend<Node> {
    node().ascend()
}

pub fn at(index: uint) -> At<Node> {
    node().at(index)
}

pub fn key<'a>(name: &'a str) -> Key<'a, Node> {
    node().key(name)
}

pub fn where<T:Selector>(filter: T) -> Where<Node,T> {
    node().where(filter)
}

pub fn intersect<T1:Selector,T2:Selector>(left: T1, right: T2) -> Intersect<Node,T1,T2> {
    node().intersect(left, right)
}

pub fn union<T1:Selector,T2:Selector>(left: T1, right: T2) -> Union<Node,T1,T2> {
    node().union(left, right)
}

pub fn diff<T1:Selector,T2:Selector>(left: T1, right: T2) -> Diff<Node,T1,T2> {
    node().diff(left, right)
}

pub fn and<T1:Selector,T2:Selector>(left: T1, right: T2) -> And<Node,T1,T2> {
    node().and(left, right)
}

pub fn or<T1:Selector,T2:Selector>(left: T1, right: T2) -> Or<Node,T1,T2> {
    node().or(left, right)
}

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

    #[test]
    fn basic() {
        // Test JSON document
        let json = json::from_str(
r#"
[
    {
        "foo": ["Hello, world!", 3.14, false]
    },
    {
        "foo": [42, true]
    },
    {
        "foo": "Nope"
    },
    {
        "bar": [42, "Hello, world!"]
    }
]
"#).unwrap();

        // Given a list, match all objects in it that
        // have a "foo" key where the value is a list
        // that contains either the string "Hello, world!"
        // or the number 42
        let matches = json.query(
            list().child().where(
                key("foo").list().child().or(
                    string().equals("Hello, world!"),
                    number().equals(42f64))));

        // Expected matches
        let match1 = json::from_str(
            r#"{"foo": ["Hello, world!", 3.14, false]}"#).unwrap();
        let match2 = json::from_str(
            r#"{"foo": [42, true]}"#).unwrap();

        assert_eq!(matches.len(), 2);
        assert!(matches.contains(& &match1));
        assert!(matches.contains(& &match2));
    }
}
<|endoftext|>


<commit_before><commit_msg>add helper methods for class tangles<commit_after><|endoftext|>


<commit_before>/// score is responsible for calculating the scores of the similarity between
/// the query and the choice.
///
/// It is modeled after https://github.com/felipesere/icepick.git

use std::cmp::max;
use std::cell::RefCell;
const BONUS_ADJACENCY: i32 = 5;
const BONUS_SEPARATOR: i32 = 10;
const BONUS_CAMEL: i32 = 10;
const PENALTY_LEADING: i32 = -3; // penalty applied for every letter before the first match
const PENALTY_MAX_LEADING: i32 = -9; // maxing penalty for leading letters
const PENALTY_UNMATCHED: i32 = -1;

// judge how many scores the current index should get
fn fuzzy_score(string: &Vec<char>, index: usize, is_first: bool) -> i32 {
    let mut score = 0;
    if index == 0 {
        return 0;
    }

    let prev = string[index-1];
    let cur = string[index];

    // apply bonus for matches after a separator
    if prev == ' ' || prev == '_' || prev == '-' || prev == '/' || prev == '\\' {
        score += BONUS_SEPARATOR;
    }

    // apply bonus for camelCases
    if prev.is_lowercase() && cur.is_uppercase() {
        score += BONUS_CAMEL;
    }

    if is_first {
        score += max((index as i32) * PENALTY_LEADING, PENALTY_MAX_LEADING);
    }

    score
}

pub fn fuzzy_match(choice: &str, pattern: &str) -> Option<(i32, Vec<usize>)>{
    if pattern.len() == 0 {
        return Some((0, Vec::new()));
    }

    let choice_chars: Vec<char> = choice.chars().collect();
    let choice_lower = choice.to_lowercase();
    let pattern_chars: Vec<char> = pattern.to_lowercase().chars().collect();

    let mut scores = vec![];
    let mut picked = vec![];

    let mut prev_matched_idx = -1; // to ensure that the pushed char are able to match the pattern
    for pattern_idx in 0..pattern_chars.len() {
        let pattern_char = pattern_chars[pattern_idx];
        let vec_cell = RefCell::new(vec![]);
        {
            let mut vec = vec_cell.borrow_mut();
            for (idx, ch) in choice_lower.chars().enumerate() {
                if ch == pattern_char && (idx as i32) > prev_matched_idx {
                    vec.push((idx, fuzzy_score(&choice_chars, idx, pattern_idx == 0), 0)); // (char_idx, score, vec_idx back_ref)
                }
            }

            if vec.len() <= 0 {
                // not matched
                return None;
            }
            prev_matched_idx = vec[0].0 as i32;
        }
        scores.push(vec_cell);
    }

    for pattern_idx in 0..pattern.len()-1 {
        let cur_row = scores[pattern_idx].borrow();
        let mut next_row = scores[pattern_idx+1].borrow_mut();

        for idx in 0..next_row.len() {
            let (next_char_idx, next_score, _) = next_row[idx];
//(back_ref, &score)
            let (back_ref, score) = cur_row.iter()
                .take_while(|&&(idx, _, _)| idx < next_char_idx)
                .map(|&(char_idx, score, _)| {
                    let adjacent_num = next_char_idx - char_idx - 1;
                    score + next_score + if adjacent_num == 0 {BONUS_ADJACENCY} else {PENALTY_UNMATCHED * adjacent_num as i32}
                })
                .enumerate()
                .max_by_key(|&(_, x)| x)
                .unwrap();

            next_row[idx] = (next_char_idx, score, back_ref);
        }
    }

    let (mut next_col, &(_, score, _)) = scores[pattern.len()-1].borrow().iter().enumerate().max_by_key(|&(_, &x)| x.1).unwrap();
    let mut pattern_idx = pattern.len() as i32 - 1;
    while pattern_idx >= 0 {
        let (idx, _, next) = scores[pattern_idx as usize].borrow()[next_col];
        next_col = next;
        picked.push(idx);
        pattern_idx -= 1;
    }
    picked.reverse();
    Some((score, picked))
}

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

    #[test]
    fn test_compute_match_length() {
        let choice_1 = "I am a 中国人.";
        let query_1 = "a人";
        assert_eq!(super::compute_match_length(&choice_1, &query_1), Some((2, 8)));

        let choice_2 = "Choice did not matter";
        let query_2 = "";
        assert_eq!(super::compute_match_length(&choice_2, &query_2), Some((0, 0)));

        let choice_3 = "abcdefg";
        let query_3 = "hi";
        assert_eq!(super::compute_match_length(&choice_3, &query_3), None);

        let choice_4 = "Partial match did not count";
        let query_4 = "PP";
        assert_eq!(compute_match_length(&choice_4, &query_4), None);
    }

    #[test]
    fn teset_fuzzy_match() {
        // the score in this test doesn't actually matter, but the index matters.
        let choice_1 = "1111121";
        let query_1 = "21";
        assert_eq!(fuzzy_match(&choice_1, &query_1), Some((-4, vec![5,6])));

        let choice_2 = "Ca";
        let query_2 = "ac";
        assert_eq!(fuzzy_match(&choice_2, &query_2), None);

        let choice_3 = ".";
        let query_3 = "s";
        assert_eq!(fuzzy_match(&choice_3, &query_3), None);

        let choice_4 = "AaBbCc";
        let query_4 = "abc";
        assert_eq!(fuzzy_match(&choice_4, &query_4), Some((28, vec![0,2,4])));
    }
}
<commit_msg>[score] refine the weihts<commit_after>/// score is responsible for calculating the scores of the similarity between
/// the query and the choice.
///
/// It is modeled after https://github.com/felipesere/icepick.git

use std::cmp::max;
use std::cell::RefCell;
const BONUS_UPPER_MATCH: i32 = 10;
const BONUS_ADJACENCY: i32 = 10;
const BONUS_SEPARATOR: i32 = 20;
const BONUS_CAMEL: i32 = 20;
const PENALTY_CASE_UNMATCHED: i32 = -1;
const PENALTY_LEADING: i32 = -6; // penalty applied for every letter before the first match
const PENALTY_MAX_LEADING: i32 = -18; // maxing penalty for leading letters
const PENALTY_UNMATCHED: i32 = -2;

// judge how many scores the current index should get
fn fuzzy_score(string: &Vec<char>, index: usize, pattern: &Vec<char>, pattern_idx: usize) -> i32 {
    let mut score = 0;

    let pattern_char = pattern[pattern_idx];
    let cur = string[index];

    if pattern_char.is_uppercase() && cur.is_uppercase() && pattern_char == cur {
        score += BONUS_UPPER_MATCH;
    } else {
        score += PENALTY_CASE_UNMATCHED;
    }

    if index == 0 {
        return score + if cur.is_uppercase() {BONUS_CAMEL} else {0};
    }

    let prev = string[index-1];

    // apply bonus for matches after a separator
    if prev == ' ' || prev == '_' || prev == '-' || prev == '/' || prev == '\\' {
        score += BONUS_SEPARATOR;
    }

    // apply bonus for camelCases
    if prev.is_lowercase() && cur.is_uppercase() {
        score += BONUS_CAMEL;
    }

    if pattern_idx == 0 {
        score += max((index as i32) * PENALTY_LEADING, PENALTY_MAX_LEADING);
    }

    score
}

pub fn fuzzy_match(choice: &str, pattern: &str) -> Option<(i32, Vec<usize>)>{
    if pattern.len() == 0 {
        return Some((0, Vec::new()));
    }

    let choice_chars: Vec<char> = choice.chars().collect();
    let choice_lower = choice.to_lowercase();
    let pattern_chars: Vec<char> = pattern.chars().collect();
    let pattern_chars_lower: Vec<char> = pattern.to_lowercase().chars().collect();

    let mut scores = vec![];
    let mut picked = vec![];

    let mut prev_matched_idx = -1; // to ensure that the pushed char are able to match the pattern
    for pattern_idx in 0..pattern_chars_lower.len() {
        let pattern_char = pattern_chars_lower[pattern_idx];
        let vec_cell = RefCell::new(vec![]);
        {
            let mut vec = vec_cell.borrow_mut();
            for (idx, ch) in choice_lower.chars().enumerate() {
                if ch == pattern_char && (idx as i32) > prev_matched_idx {
                    vec.push((idx, fuzzy_score(&choice_chars, idx, &pattern_chars, pattern_idx), 0)); // (char_idx, score, vec_idx back_ref)
                }
            }

            if vec.len() <= 0 {
                // not matched
                return None;
            }
            prev_matched_idx = vec[0].0 as i32;
        }
        scores.push(vec_cell);
    }

    for pattern_idx in 0..pattern.len()-1 {
        let cur_row = scores[pattern_idx].borrow();
        let mut next_row = scores[pattern_idx+1].borrow_mut();

        for idx in 0..next_row.len() {
            let (next_char_idx, next_score, _) = next_row[idx];
//(back_ref, &score)
            let (back_ref, score) = cur_row.iter()
                .take_while(|&&(idx, _, _)| idx < next_char_idx)
                .map(|&(char_idx, score, _)| {
                    let adjacent_num = next_char_idx - char_idx - 1;
                    score + next_score + if adjacent_num == 0 {BONUS_ADJACENCY} else {PENALTY_UNMATCHED * adjacent_num as i32}
                })
                .enumerate()
                .max_by_key(|&(_, x)| x)
                .unwrap();

            next_row[idx] = (next_char_idx, score, back_ref);
        }
    }

    let (mut next_col, &(_, score, _)) = scores[pattern.len()-1].borrow().iter().enumerate().max_by_key(|&(_, &x)| x.1).unwrap();
    let mut pattern_idx = pattern.len() as i32 - 1;
    while pattern_idx >= 0 {
        let (idx, _, next) = scores[pattern_idx as usize].borrow()[next_col];
        next_col = next;
        picked.push(idx);
        pattern_idx -= 1;
    }
    picked.reverse();
    Some((score, picked))
}

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

    #[test]
    fn teset_fuzzy_match() {
        // the score in this test doesn't actually matter, but the index matters.
        let choice_1 = "1111121";
        let query_1 = "21";
        assert_eq!(fuzzy_match(&choice_1, &query_1), Some((-10, vec![5,6])));

        let choice_2 = "Ca";
        let query_2 = "ac";
        assert_eq!(fuzzy_match(&choice_2, &query_2), None);

        let choice_3 = ".";
        let query_3 = "s";
        assert_eq!(fuzzy_match(&choice_3, &query_3), None);

        let choice_4 = "AaBbCc";
        let query_4 = "abc";
        assert_eq!(fuzzy_match(&choice_4, &query_4), Some((53, vec![0,2,4])));
    }
}
<|endoftext|>


<commit_before><commit_msg>Add missing attr.rs file<commit_after>use std::collections::HashMap;
use std::collections::HashSet;

use syntax::ast;
use syntax::ext::base::ExtCtxt;
use syntax::ptr::P;

/// Represents field name information
pub enum FieldNames {
    Global(P<ast::Expr>),
    Format{
        formats: HashMap<P<ast::Expr>, P<ast::Expr>>,
        default: P<ast::Expr>,
    }
}

/// Represents field attribute information
pub struct FieldAttrs {
    names: FieldNames,
    use_default: bool,
}

impl FieldAttrs {

    /// Create a FieldAttr with a single default field name
    pub fn new(default_value: bool, name: P<ast::Expr>) -> FieldAttrs {
        FieldAttrs {
            names: FieldNames::Global(name),
            use_default: default_value,
        }
    }

    /// Create a FieldAttr with format specific field names
    pub fn new_with_formats(
        default_value: bool,
        default_name: P<ast::Expr>,
        formats: HashMap<P<ast::Expr>, P<ast::Expr>>,
        ) -> FieldAttrs {
        FieldAttrs {
            names:  FieldNames::Format {
                formats: formats,
                default: default_name,
            },
            use_default: default_value,
        }
    }

    /// Return a set of formats that the field has attributes for.
    pub fn formats(&self) -> HashSet<P<ast::Expr>> {
        match self.names {
            FieldNames::Format{ref formats, default: _} => {
                let mut set = HashSet::new();
                for (fmt, _) in formats.iter() {
                    set.insert(fmt.clone());
                };
                set
            },
            _ => HashSet::new()
        }
    }

    /// Return an expression for the field key name for serialisation.
    ///
    /// The resulting expression assumes that `S` refers to a type
    /// that implements `Serializer`.
    pub fn serializer_key_expr(self, cx: &ExtCtxt) -> P<ast::Expr> {
        match self.names {
            FieldNames::Global(x) => x,
            FieldNames::Format{formats, default} => {
                let arms = formats.iter()
                    .map(|(fmt, lit)| {
                        quote_arm!(cx, $fmt => { $lit })
                    })
                    .collect::<Vec<_>>();
                quote_expr!(cx,
                            {
                                match S::format() {
                                    $arms,
                                    _ => $default
                                }
                            })
            },
        }
    }

    /// Return the default field name for the field.
    pub fn default_key_expr(&self) -> &P<ast::Expr> {
        match self.names {
            FieldNames::Global(ref expr) => expr,
            FieldNames::Format{formats: _, ref default} => default
        }
    }

    /// Return the field name for the field in the specified format.
    pub fn key_expr(&self, format: &P<ast::Expr>) -> &P<ast::Expr> {
        match self.names {
            FieldNames::Global(ref expr) =>
                expr,
            FieldNames::Format{ref formats, ref default} =>
                formats.get(format).unwrap_or(default)
        }
    }

    /// Predicate for using a field's default value
    pub fn use_default(&self) -> bool {
        self.use_default
    }
}
<|endoftext|>


<commit_before><commit_msg>WIP on debugging MUL sections<commit_after>export slice_mul;
export get_writer;

fn slice_mul(record: mul_reader::mul_record, name: ~str) {

    let header: io::writer = get_writer(#fmt("%s.mulheader", name));
    let body: io::writer = get_writer(#fmt("%s.mulslice", name));

    header.write_le_u16(record.opt1);
    header.write_le_u16(record.opt2);

    for record.data.each |byte| {
        body.write_u8(byte);
    }
}

fn get_writer(path: ~string) -> io::writer {

    let maybe_writer = io::file_writer(path, ~[io::create, io::truncate]);

    if result::is_err::<io::writer, ~str>(maybe_writer) {
        io::println(#fmt("%s", result::get_err(maybe_writer)));
        assert false;
    }

    result::unwrap(maybe_writer);
}
<|endoftext|>


<commit_before>import std::os;
import std::fs;
import std::os_fs;
import vec;
import std::map;
import str;
import uint;
import metadata::cstore;
import driver::session;
import util::filesearch;

// FIXME #721: Despite the compiler warning, test does exist and needs
// to be exported
export get_rpath_flags, test;

fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
    let os = sess.get_targ_cfg().os;

    // No rpath on windows
    if os == session::os_win32 {
        ret [];
    }

    #debug("preparing the RPATH!");

    let cwd = os::getcwd();
    let sysroot = sess.filesearch().sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.get_cstore());
    // We don't currently rpath native libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = libs + [get_sysroot_absolute_rt_lib(sess)];

    let target_triple = sess.get_opts().target_triple;
    let rpaths = get_rpaths(os, cwd, sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path {
    let path = [sess.filesearch().sysroot()]
        + filesearch::relative_target_lib_path(
            sess.get_opts().target_triple)
        + [os::dylib_filename("rustrt")];
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn rpaths_to_flags(rpaths: [str]) -> [str] {
    vec::map(rpaths, { |rpath| #fmt("-Wl,-rpath,%s",rpath)})
}

fn get_rpaths(os: session::os, cwd: fs::path, sysroot: fs::path,
              output: fs::path, libs: [fs::path],
              target_triple: str) -> [str] {
    #debug("cwd: %s", cwd);
    #debug("sysroot: %s", sysroot);
    #debug("output: %s", output);
    #debug("libs:");
    for libpath in libs {
        #debug("    %s", libpath);
    }
    #debug("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, cwd, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(cwd, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = [get_install_prefix_rpath(cwd, target_triple)];

    fn log_rpaths(desc: str, rpaths: [str]) {
        #debug("%s rpaths:", desc);
        for rpath in rpaths {
            #debug("    %s", rpath);
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("absolute", abs_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths;

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    ret rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 cwd: fs::path,
                                 output: fs::path,
                                 libs: [fs::path]) -> [str] {
    vec::map(libs, bind get_rpath_relative_to_output(os, cwd, output, _))
}

fn get_rpath_relative_to_output(os: session::os,
                                cwd: fs::path,
                                output: fs::path,
                                &&lib: fs::path) -> str {
    // Mac doesn't appear to support $ORIGIN
    let prefix = alt os {
        session::os_linux. { "$ORIGIN" + fs::path_sep() }
        session::os_freebsd. { "$ORIGIN" + fs::path_sep() }
        session::os_macos. { "@executable_path" + fs::path_sep() }
    };

    prefix + get_relative_to(
        get_absolute(cwd, output),
        get_absolute(cwd, lib))
}

// Find the relative path from one file to another
fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path {
    assert fs::path_is_absolute(abs1);
    assert fs::path_is_absolute(abs2);
    #debug("finding relative path from %s to %s",
           abs1, abs2);
    let normal1 = fs::normalize(abs1);
    let normal2 = fs::normalize(abs2);
    let split1 = str::split(normal1, os_fs::path_sep as u8);
    let split2 = str::split(normal2, os_fs::path_sep as u8);
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0u;
    assert len2 > 0u;

    let max_common_path = math::min(len1, len2) - 1u;
    let start_idx = 0u;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1u;
    }

    let path = [];

    uint::range(start_idx, len1 - 1u) {|_i| path += [".."]; };

    path += vec::slice(split2, start_idx, len2 - 1u);

    if check vec::is_not_empty(path) {
        ret fs::connect_many(path);
    } else {
        ret ".";
    }
}

fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] {
    vec::map(libs, bind get_absolute_rpath(cwd, _))
}

fn get_absolute_rpath(cwd: fs::path, &&lib: fs::path) -> str {
    fs::dirname(get_absolute(cwd, lib))
}

fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path {
    if fs::path_is_absolute(lib) {
        lib
    } else {
        fs::connect(cwd, lib)
    }
}

fn get_install_prefix_rpath(cwd: fs::path, target_triple: str) -> str {
    let install_prefix = #env("CFG_PREFIX");

    if install_prefix == "" {
        fail "rustc compiled without CFG_PREFIX environment variable";
    }

    let path = [install_prefix]
        + filesearch::relative_target_lib_path(target_triple);
    check vec::is_not_empty(path);
    get_absolute(cwd, fs::connect_many(path))
}

fn minimize_rpaths(rpaths: [str]) -> [str] {
    let set = map::new_str_hash::<()>();
    let minimized = [];
    for rpath in rpaths {
        if !set.contains_key(rpath) {
            minimized += [rpath];
            set.insert(rpath, ());
        }
    }
    ret minimized;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
#[cfg(test)]
mod test {
    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(["path1", "path2"]);
        assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"];
    }

    #[test]
    fn test_get_absolute1() {
        let cwd = "/dir";
        let lib = "some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/dir/some/path/lib";
    }

    #[test]
    fn test_get_absolute2() {
        let cwd = "/dir";
        let lib = "/some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/some/path/lib";
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert str::ends_with(res, #env("CFG_PREFIX")
                              + "/lib/rustc/triple/lib");
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert fs::path_is_absolute(res);
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]);
        assert res == ["rpath1", "rpath2"];
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths(["1a", "2", "2", "1a", "4a",
                                   "1a", "2", "3", "4a", "3"]);
        assert res == ["1a", "2", "4a", "3"];
    }

    #[test]
    fn test_relative_to1() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to2() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/bin/../lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to3() {
        let p1 = "/usr/bin/whatever/rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../../lib/whatever";
    }

    #[test]
    fn test_relative_to4() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib/whatever";
    }

    #[test]
    fn test_relative_to5() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/../mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to6() {
        let p1 = "/1";
        let p2 = "/2/3";
        let res = get_relative_to(p1, p2);
        assert res == "2";
    }

    #[test]
    fn test_relative_to7() {
        let p1 = "/1/2";
        let p2 = "/3";
        let res = get_relative_to(p1, p2);
        assert res == "..";
    }

    #[test]
    fn test_relative_to8() {
        let p1 = "/home/brian/Dev/rust/build/"
            + "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
        let p2 = "/home/brian/Dev/rust/build/stage2/bin/.."
            + "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
        let res = get_relative_to(p1, p2);
        assert res == ".";
    }

    #[test]
    #[cfg(target_os = "linux")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_linux,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_freebsd,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_macos,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "@executable_path/../lib";
    }

    #[test]
    fn test_get_absolute_rpath() {
        let res = get_absolute_rpath("/usr", "lib/libstd.so");
        assert res == "/usr/lib";
    }
}
<commit_msg>rustc: Stop exported back::rpath::test<commit_after>import std::os;
import std::fs;
import std::os_fs;
import vec;
import std::map;
import str;
import uint;
import metadata::cstore;
import driver::session;
import util::filesearch;

export get_rpath_flags;

fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
    let os = sess.get_targ_cfg().os;

    // No rpath on windows
    if os == session::os_win32 {
        ret [];
    }

    #debug("preparing the RPATH!");

    let cwd = os::getcwd();
    let sysroot = sess.filesearch().sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.get_cstore());
    // We don't currently rpath native libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = libs + [get_sysroot_absolute_rt_lib(sess)];

    let target_triple = sess.get_opts().target_triple;
    let rpaths = get_rpaths(os, cwd, sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path {
    let path = [sess.filesearch().sysroot()]
        + filesearch::relative_target_lib_path(
            sess.get_opts().target_triple)
        + [os::dylib_filename("rustrt")];
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn rpaths_to_flags(rpaths: [str]) -> [str] {
    vec::map(rpaths, { |rpath| #fmt("-Wl,-rpath,%s",rpath)})
}

fn get_rpaths(os: session::os, cwd: fs::path, sysroot: fs::path,
              output: fs::path, libs: [fs::path],
              target_triple: str) -> [str] {
    #debug("cwd: %s", cwd);
    #debug("sysroot: %s", sysroot);
    #debug("output: %s", output);
    #debug("libs:");
    for libpath in libs {
        #debug("    %s", libpath);
    }
    #debug("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, cwd, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(cwd, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = [get_install_prefix_rpath(cwd, target_triple)];

    fn log_rpaths(desc: str, rpaths: [str]) {
        #debug("%s rpaths:", desc);
        for rpath in rpaths {
            #debug("    %s", rpath);
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("absolute", abs_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths;

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    ret rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 cwd: fs::path,
                                 output: fs::path,
                                 libs: [fs::path]) -> [str] {
    vec::map(libs, bind get_rpath_relative_to_output(os, cwd, output, _))
}

fn get_rpath_relative_to_output(os: session::os,
                                cwd: fs::path,
                                output: fs::path,
                                &&lib: fs::path) -> str {
    // Mac doesn't appear to support $ORIGIN
    let prefix = alt os {
        session::os_linux. { "$ORIGIN" + fs::path_sep() }
        session::os_freebsd. { "$ORIGIN" + fs::path_sep() }
        session::os_macos. { "@executable_path" + fs::path_sep() }
    };

    prefix + get_relative_to(
        get_absolute(cwd, output),
        get_absolute(cwd, lib))
}

// Find the relative path from one file to another
fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path {
    assert fs::path_is_absolute(abs1);
    assert fs::path_is_absolute(abs2);
    #debug("finding relative path from %s to %s",
           abs1, abs2);
    let normal1 = fs::normalize(abs1);
    let normal2 = fs::normalize(abs2);
    let split1 = str::split(normal1, os_fs::path_sep as u8);
    let split2 = str::split(normal2, os_fs::path_sep as u8);
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0u;
    assert len2 > 0u;

    let max_common_path = math::min(len1, len2) - 1u;
    let start_idx = 0u;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1u;
    }

    let path = [];

    uint::range(start_idx, len1 - 1u) {|_i| path += [".."]; };

    path += vec::slice(split2, start_idx, len2 - 1u);

    if check vec::is_not_empty(path) {
        ret fs::connect_many(path);
    } else {
        ret ".";
    }
}

fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] {
    vec::map(libs, bind get_absolute_rpath(cwd, _))
}

fn get_absolute_rpath(cwd: fs::path, &&lib: fs::path) -> str {
    fs::dirname(get_absolute(cwd, lib))
}

fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path {
    if fs::path_is_absolute(lib) {
        lib
    } else {
        fs::connect(cwd, lib)
    }
}

fn get_install_prefix_rpath(cwd: fs::path, target_triple: str) -> str {
    let install_prefix = #env("CFG_PREFIX");

    if install_prefix == "" {
        fail "rustc compiled without CFG_PREFIX environment variable";
    }

    let path = [install_prefix]
        + filesearch::relative_target_lib_path(target_triple);
    check vec::is_not_empty(path);
    get_absolute(cwd, fs::connect_many(path))
}

fn minimize_rpaths(rpaths: [str]) -> [str] {
    let set = map::new_str_hash::<()>();
    let minimized = [];
    for rpath in rpaths {
        if !set.contains_key(rpath) {
            minimized += [rpath];
            set.insert(rpath, ());
        }
    }
    ret minimized;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
#[cfg(test)]
mod test {
    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(["path1", "path2"]);
        assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"];
    }

    #[test]
    fn test_get_absolute1() {
        let cwd = "/dir";
        let lib = "some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/dir/some/path/lib";
    }

    #[test]
    fn test_get_absolute2() {
        let cwd = "/dir";
        let lib = "/some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/some/path/lib";
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert str::ends_with(res, #env("CFG_PREFIX")
                              + "/lib/rustc/triple/lib");
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert fs::path_is_absolute(res);
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]);
        assert res == ["rpath1", "rpath2"];
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths(["1a", "2", "2", "1a", "4a",
                                   "1a", "2", "3", "4a", "3"]);
        assert res == ["1a", "2", "4a", "3"];
    }

    #[test]
    fn test_relative_to1() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to2() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/bin/../lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to3() {
        let p1 = "/usr/bin/whatever/rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../../lib/whatever";
    }

    #[test]
    fn test_relative_to4() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib/whatever";
    }

    #[test]
    fn test_relative_to5() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/../mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to6() {
        let p1 = "/1";
        let p2 = "/2/3";
        let res = get_relative_to(p1, p2);
        assert res == "2";
    }

    #[test]
    fn test_relative_to7() {
        let p1 = "/1/2";
        let p2 = "/3";
        let res = get_relative_to(p1, p2);
        assert res == "..";
    }

    #[test]
    fn test_relative_to8() {
        let p1 = "/home/brian/Dev/rust/build/"
            + "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
        let p2 = "/home/brian/Dev/rust/build/stage2/bin/.."
            + "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
        let res = get_relative_to(p1, p2);
        assert res == ".";
    }

    #[test]
    #[cfg(target_os = "linux")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_linux,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "freebsd")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_freebsd,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_macos,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "@executable_path/../lib";
    }

    #[test]
    fn test_get_absolute_rpath() {
        let res = get_absolute_rpath("/usr", "lib/libstd.so");
        assert res == "/usr/lib";
    }
}
<|endoftext|>


<commit_before><commit_msg>parser: strings values are more likely to occur<commit_after><|endoftext|>


<commit_before><commit_msg>Change default colours a bit<commit_after><|endoftext|>