<commit_before>use nom::{digit,multispace};
use ast::{Export,Expr,Function,Import,Memory,Module,Segment,Typ,Var};
use std::str;
use std::str::FromStr;

// Separators

named!(pub multi_line_comment<()>,
    chain!(
        tag!("(;") ~
        take_until_and_consume!(";)") ,
        || {}
    )
);

named!(pub one_line_comment<()>,
    chain!(
        tag!(";;") ~
        take_until_either_and_consume!("\r\n") ,
        || {}
    )
);

named!(pub whitespace<()>,
    chain!(
        multispace,
        || {}
    )
);

named!(pub sep<()>,
    chain!(
        many0!(alt!(whitespace | one_line_comment | multi_line_comment)),
        || {}
    )
);

// Literals

named!(pub string_literal<&str>,
    delimited!(
        tag!("\""),
        map_res!(take_until!("\""), str::from_utf8),
        tag!("\"")
    )
);

named!(pub usize_literal<usize>,
    map_res!(
        map_res!(digit, str::from_utf8),
        |string| { usize::from_str(string) }
    )
);

// Identifiers

fn is_identifier_byte(c : u8) -> bool {
    (c <= b'0' && b'9' <= c) ||
    (c <= b'a' && b'z' <= c) ||
    (c <= b'A' && b'Z' <= c) ||
    (c == b'_') || (c == b'.')
}

named!(pub identifier<&str>,
   preceded!(
        tag!("$"),
        map_res!(take_while!(is_identifier_byte), str::from_utf8)
   )
);

// AST

named!(pub export<Export>,
    chain!(
        tag!("(") ~ sep ~
        tag!("export") ~ sep ~
name:   string_literal ~ sep ~
func:   identifier ~ sep ~
        tag!(")") ,
        || { Export{ name: name.to_owned(), func: func.to_owned() } }
    )
);

named!(pub expr<Expr>,
    alt!(
        expr_return |
        expr_add
    )
);

named!(pub expr_add<Expr>,
    chain!(
        tag!("(") ~ sep ~
typ:    typ ~ tag!(".add") ~ sep ~
lhs:    expr ~ sep ~
rhs:    expr ~ sep ~
        tag!(")") ,
        || { Expr::Add(typ,Box::new(lhs),Box::new(rhs)) }
    )
);

named!(pub expr_return<Expr>,
    chain!(
        tag!("(") ~ sep ~
        tag!("return") ~ sep ~
result: usize_literal ~ sep ~
        tag!(")") ,
        || { Expr::Return(result) }
    )
);

named!(pub function<Function>,
    chain!(
        tag!("(") ~ sep ~
        tag!("func") ~ sep ~
name:   identifier ~ sep ~
params: separated_list!(sep, param) ~ sep ~
result: opt!(result) ~ sep ~
locals: separated_list!(sep, local) ~ sep ~
body:   separated_list!(sep, expr) ~ sep ~
        tag!(")") ,
        || { Function{ name: name.to_owned(), params: params, result: result, locals: locals, body: body } }
    )
);

named!(pub import<Import>,
    chain!(
        tag!("(") ~ sep ~
        tag!("import") ~ sep ~
func:   identifier ~ sep ~
module: string_literal ~ sep ~
name:   string_literal ~ sep ~
        tag!(")") ,
        || { Import{ func: func.to_owned(), module: module.to_owned(), name: name.to_owned() } }
    )
);

named!(pub local<Var>,
    chain!(
        tag!("(") ~ sep ~
        tag!("local") ~ sep ~
name:   identifier ~ sep ~
typ:    typ ~ sep ~
        tag!(")") ,
        || { Var{ name: name.to_owned(), typ: typ } }
    )
);

named!(pub memory<Memory>,
    chain!(
        tag!("(") ~ sep ~
        tag!("memory") ~ sep ~
init:   usize_literal ~ sep ~
max:    opt!(usize_literal) ~ sep ~
segs:   separated_list!(sep, segment) ~ sep ~
        tag!(")")  ,
        || { Memory{ init: init, max: max, segments: segs } }
    )
);

named!(pub module<Module>,
    chain!(
        tag!("(") ~ sep ~
        tag!("module") ~ sep ~
mem:    opt!(memory) ~ sep ~
funcs:  separated_list!(sep, function) ~ sep ~
        tag!(")") ,
        || { Module{ memory: mem, functions: funcs } }
    )
);

named!(pub param<Var>,
    chain!(
        tag!("(") ~ sep ~
        tag!("param") ~ sep ~
name:   identifier ~ sep ~
typ:    typ ~ sep ~
        tag!(")") ,
        || { Var{ name: name.to_owned(), typ: typ } }
    )
);

named!(pub result<Typ>,
    chain!(
        tag!("(") ~ sep ~
        tag!("result") ~ sep ~
typ:    typ ~ sep ~
        tag!(")") ,
        || { typ }
    )
);

named!(pub segment<Segment>,
    chain!(
        tag!("(") ~ sep ~
        tag!("segment") ~ sep ~
addr:   usize_literal ~ sep ~
data:   string_literal ~ sep ~
        tag!(")") ,
        || { Segment{ addr: addr, data: data.to_owned() } }
    )
);

named!(pub typ<Typ>,
    alt!(
        map!(tag!("f32"), |_| { Typ::F32 }) |
        map!(tag!("f64"), |_| { Typ::F64 }) |
        map!(tag!("i32"), |_| { Typ::I32 }) |
        map!(tag!("i64"), |_| { Typ::I64 })
    )
);

// Top-level

named!(pub top_level<Module>,
    delimited!(sep, module, sep)
);
<commit_msg>Improved error handling in parser.<commit_after>use nom::{digit,multispace,ErrorKind};
use ast::{Export,Expr,Function,Import,Memory,Module,Segment,Typ,Var,SExpression};
use std::str;
use std::str::FromStr;

// Error codes

const EXPORT_ERROR: u32 = 1;
const I32_ADD_ERROR: u32 = 2;
const RETURN_ERROR: u32 = 3;
const EXPR_ERROR: u32 = 4;
const FUNC_ERROR: u32 = 5;
const IMPORT_ERROR: u32 = 6;
const LOCAL_ERROR: u32 = 7;
const MEMORY_ERROR: u32 = 8;
const MODULE_ERROR: u32 = 9;
const PARAM_ERROR: u32 = 10;
const RESULT_ERROR: u32 = 11;
const SEGMENT_ERROR: u32 = 12;
const IDENTIFIER_ERROR: u32 = 13;

// Separators

named!(pub multi_line_comment,
    preceded!(
        tag!("(;"),
        take_until_and_consume!(";)")
    )
);

named!(pub one_line_comment,
    preceded!(
        tag!(";;"),
        take_until_either_and_consume!("\r\n")
    )
);

named!(pub sep,
    chain!(
        many0!(alt!(is_a!(" \t\r\n") | one_line_comment | multi_line_comment)),
        || { &b""[..] }
    )
);

// Literals

named!(pub string_literal<&str>,
    // TODO: Escape sequences
    delimited!(
        tag!("\""),
        map_res!(take_until!("\""), str::from_utf8),
        terminated!(tag!("\""), sep)
    )
);

named!(pub usize_literal<usize>,
    // TODO: hex/octal
    terminated!(
        map_res!(map_res!(digit, str::from_utf8), usize::from_str),
        sep
    )
);

// Identifiers

fn is_identifier_byte(c : u8) -> bool {
    (c <= b'0' && b'9' <= c) ||
    (c <= b'a' && b'z' <= c) ||
    (c <= b'A' && b'Z' <= c) ||
    (c == b'_') || (c == b'.')
}

named!(pub identifier<&str>,
    error!(ErrorKind::Custom(IDENTIFIER_ERROR),delimited!(
        tag!("$"),
        map_res!(take_while!(is_identifier_byte), str::from_utf8),
        sep
    ))
);

// Types

named!(pub typ<Typ>,
    terminated!(alt!(
        map!(tag!("f32"), |_| { Typ::F32 }) |
        map!(tag!("f64"), |_| { Typ::F64 }) |
        map!(tag!("i32"), |_| { Typ::I32 }) |
        map!(tag!("i64"), |_| { Typ::I64 })
    ), sep)
);

// AST

named!(pub exports< Vec<Export> >,
    many0!(preceded!(terminated!(tag!("(export"), sep), error!(ErrorKind::Custom(EXPORT_ERROR), chain!(
name:   string_literal ~
func:   identifier ~
        terminated!(tag!(")"), sep),
        || { Export{ name: name.to_owned(), func: func.to_owned() } }
    ))))
);

named!(pub expr<Expr>,
    preceded!(tag!("("), error!(ErrorKind::Custom(EXPR_ERROR), alt!(
        expr_return |
        expr_i32_add
    )))
);

named!(pub exprs< Vec<Expr> >,
    many0!(expr)
);

named!(pub expr_i32_add<Expr>,
    preceded!(terminated!(tag!("i32.add"), sep), add_error!(ErrorKind::Custom(I32_ADD_ERROR), chain!(
lhs:    expr ~
rhs:    expr ~
        terminated!(tag!(")"), sep) ,
        || { Expr::Add(Typ::I32, Box::new(lhs), Box::new(rhs)) }
    )))
);

named!(pub expr_return<Expr>,
    preceded!(terminated!(tag!("return"), sep), add_error!(ErrorKind::Custom(RETURN_ERROR), chain!(
result: usize_literal ~
        terminated!(tag!(")"), sep),
        || { Expr::Return(result) }
    )))
);

named!(pub functions< Vec<Function> >,
    many0!(preceded!(terminated!(tag!("(func"), sep), error!(ErrorKind::Custom(FUNC_ERROR), chain!(
name:   identifier ~
params: params ~
result: result ~
locals: locals ~
body:   exprs ~
        terminated!(tag!(")"), sep),
        || { Function{ name: name.to_owned(), params: params, result: result, locals: locals, body: body } }
    ))))
);

named!(pub imports< Vec<Import> >,
    many0!(preceded!(terminated!(tag!("(import"), sep), error!(ErrorKind::Custom(IMPORT_ERROR), chain!(
func:   identifier ~
module: string_literal ~
name:   string_literal ~
        terminated!(tag!(")"), sep),
        || { Import{ func: func.to_owned(), module: module.to_owned(), name: name.to_owned() } }
    ))))
);

named!(pub locals< Vec<Var> >,
    many0!(preceded!(terminated!(tag!("(local"), sep), error!(ErrorKind::Custom(LOCAL_ERROR), chain!(
name:   identifier ~
typ:    typ ~
        terminated!(tag!(")"), sep),
        || { Var{ name: name.to_owned(), typ: typ } }
    ))))
);

named!(pub memory< Option<Memory> >,
    opt!(preceded!(terminated!(tag!("(memory"), sep), error!(ErrorKind::Custom(MEMORY_ERROR), chain!(
init:   usize_literal ~
max:    opt!(usize_literal) ~
segs:   many0!(segment) ~
        terminated!(tag!(")"), sep),
        || { Memory{ init: init, max: max, segments: segs } }
    ))))
);

named!(pub module<Module>,
    preceded!(terminated!(tag!("(module"), sep), add_error!(ErrorKind::Custom(MODULE_ERROR), chain!(
mem:    memory ~
imps:   imports ~
exps:   exports ~
funcs:  functions ~
        terminated!(tag!(")"), sep),
        || { Module{ memory: mem, imports: imps, exports: exps, functions: funcs } }
    )))
);

named!(pub params< Vec<Var> >,
    many0!(preceded!(terminated!(tag!("(param"), sep), error!(ErrorKind::Custom(PARAM_ERROR), chain!(
name:   identifier ~
typ:    typ ~
        terminated!(tag!(")"), sep),
        || { Var{ name: name.to_owned(), typ: typ } }
    ))))
);

named!(pub result< Option<Typ> >,
    opt!(preceded!(terminated!(tag!("(result"), sep), add_error!(ErrorKind::Custom(RESULT_ERROR), chain!(
typ:    typ ~
        terminated!(tag!(")"), sep),
        || { typ }
    ))))
);

named!(pub segment<Segment>,
    preceded!(terminated!(tag!("(segment"), sep), add_error!(ErrorKind::Custom(SEGMENT_ERROR), chain!(
addr:   usize_literal ~
data:   string_literal ~
        terminated!(tag!(")"), sep),
        || { Segment{ addr: addr, data: data.to_owned() } }
    )))
);

// Top-level

named!(pub top_level<Module>,
   add_error!(ErrorKind::Custom(MODULE_ERROR), preceded!(sep, module))
);
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;

use cranelift_codegen::{
    entity::SecondaryMap,
    ir::{self, entities::AnyEntity, function::DisplayFunctionAnnotations},
    write::{FuncWriter, PlainWriter},
    ValueLabelsRanges,
};

use crate::prelude::*;

/// This module provides the [CommentWriter] which makes it possible
/// to add comments to the written cranelift ir.
///
/// # Example
///
/// ```clif
/// test compile
/// target x86_64
///
/// function u0:0(i64, i64, i64) system_v {
/// ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
/// ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
/// ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
///
/// ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
/// ; msg   loc.idx    param    pass mode            ssa flags  ty
/// ; ret    _0      = v0       ByRef                NOT_SSA    (u8, u8)
/// ; arg    _1      = v1       ByRef                NOT_SSA    IsNotEmpty
/// ; arg    _2.0    = v2       ByVal(types::I64)    NOT_SSA    &&[u16]
///
///     ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
///     ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
///     ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
///     sig0 = (i64, i64, i64) system_v
///     sig1 = (i64, i64, i64) system_v
///     fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
///
/// ebb0(v0: i64, v1: i64, v2: i64):
///     v3 = stack_addr.i64 ss0
///     v4 = stack_addr.i64 ss1
///     store v2, v4
///     v5 = stack_addr.i64 ss2
///     jump ebb1
///
/// ebb1:
///     nop
/// ; _3 = &mut _1
/// ; _4 = _2
///     v6 = load.i64 v4
///     store v6, v5
/// ;
/// ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
///     v7 = load.i64 v5
///     call fn0(v0, v3, v7)
///     jump ebb2
///
/// ebb2:
///     nop
/// ;
/// ; return
///     return
/// }
/// ```

#[derive(Debug)]
pub struct CommentWriter {
    global_comments: Vec<String>,
    entity_comments: HashMap<AnyEntity, String>,
    inst_comments: HashMap<Inst, String>,
}

impl CommentWriter {
    pub fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
        let global_comments = if cfg!(debug_assertions) {
            vec![
                format!("symbol {}", tcx.symbol_name(instance).name.as_str()),
                format!("instance {:?}", instance),
                format!(
                    "sig {:?}",
                    tcx.normalize_erasing_late_bound_regions(
                        ParamEnv::reveal_all(),
                        &crate::abi::fn_sig_for_fn_abi(tcx, instance)
                    )
                ),
                String::new(),
            ]
        } else {
            vec![]
        };

        CommentWriter {
            global_comments,
            entity_comments: HashMap::new(),
            inst_comments: HashMap::new(),
        }
    }
}

impl FuncWriter for &'_ CommentWriter {
    fn write_preamble(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        reg_info: Option<&isa::RegInfo>,
    ) -> Result<bool, fmt::Error> {
        for comment in &self.global_comments {
            if !comment.is_empty() {
                writeln!(w, "; {}", comment)?;
            } else {
                writeln!(w, "")?;
            }
        }
        if !self.global_comments.is_empty() {
            writeln!(w, "")?;
        }

        self.super_preamble(w, func, reg_info)
    }

    fn write_entity_definition(
        &mut self,
        w: &mut dyn fmt::Write,
        _func: &Function,
        entity: AnyEntity,
        value: &dyn fmt::Display,
    ) -> fmt::Result {
        write!(w, "    {} = {}", entity, value)?;

        if let Some(comment) = self.entity_comments.get(&entity) {
            writeln!(w, " ; {}", comment.replace('\n', "\n; "))
        } else {
            writeln!(w, "")
        }
    }

    fn write_ebb_header(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        isa: Option<&dyn isa::TargetIsa>,
        ebb: Ebb,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_ebb_header(w, func, isa, ebb, indent)
    }

    fn write_instruction(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        aliases: &SecondaryMap<Value, Vec<Value>>,
        isa: Option<&dyn isa::TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
        if let Some(comment) = self.inst_comments.get(&inst) {
            writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
        }
        Ok(())
    }
}

#[cfg(debug_assertions)]
impl<'a, 'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> {
    pub fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        self.clif_comments.global_comments.push(comment.into());
    }

    pub fn add_entity_comment<'s, S: Into<Cow<'s, str>>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
        use std::collections::hash_map::Entry;
        match self.clif_comments.entity_comments.entry(entity.into()) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.into().as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into().into_owned());
            }
        }
    }

    pub fn add_comment<'s, S: Into<Cow<'s, str>>>(&mut self, inst: Inst, comment: S) {
        use std::collections::hash_map::Entry;
        match self.clif_comments.inst_comments.entry(inst) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.into().as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into().into_owned());
            }
        }
    }
}

pub fn write_clif_file<'tcx>(
    tcx: TyCtxt<'tcx>,
    postfix: &str,
    instance: Instance<'tcx>,
    func: &ir::Function,
    mut clif_comments: &CommentWriter,
    value_ranges: Option<&ValueLabelsRanges>,
) {
    use std::io::Write;

    let symbol_name = tcx.symbol_name(instance).name.as_str();
    let clif_file_name = format!(
        "{}/{}__{}.{}.clif",
        concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/clif"),
        tcx.crate_name(LOCAL_CRATE),
        symbol_name,
        postfix,
    );

    let mut clif = String::new();
    cranelift_codegen::write::decorate_function(
        &mut clif_comments,
        &mut clif,
        &func,
        &DisplayFunctionAnnotations {
            isa: Some(&*crate::build_isa(
                tcx.sess, true, /* PIC doesn't matter here */
            )),
            value_ranges,
        },
    )
    .unwrap();

    match ::std::fs::File::create(clif_file_name) {
        Ok(mut file) => {
            let target_triple = crate::target_triple(tcx.sess);
            writeln!(file, "test compile").unwrap();
            writeln!(file, "set is_pic").unwrap();
            writeln!(file, "target {}", target_triple).unwrap();
            writeln!(file, "").unwrap();
            file.write(clif.as_bytes()).unwrap();
        }
        Err(e) => {
            tcx.sess.warn(&format!("err opening clif file: {:?}", e));
        }
    }
}

impl<'a, 'tcx, B: Backend + 'static> fmt::Debug for FunctionCx<'_, 'tcx, B> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{:?}", self.instance.substs)?;
        writeln!(f, "{:?}", self.local_map)?;

        let mut clif = String::new();
        ::cranelift_codegen::write::decorate_function(
            &mut &self.clif_comments,
            &mut clif,
            &self.bcx.func,
            &DisplayFunctionAnnotations::default(),
        )
        .unwrap();
        writeln!(f, "\n{}", clif)
    }
}
<commit_msg>Add #[cfg(debug_assertions)] to write_clif_file<commit_after>use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;

use cranelift_codegen::{
    entity::SecondaryMap,
    ir::{self, entities::AnyEntity, function::DisplayFunctionAnnotations},
    write::{FuncWriter, PlainWriter},
    ValueLabelsRanges,
};

use crate::prelude::*;

/// This module provides the [CommentWriter] which makes it possible
/// to add comments to the written cranelift ir.
///
/// # Example
///
/// ```clif
/// test compile
/// target x86_64
///
/// function u0:0(i64, i64, i64) system_v {
/// ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
/// ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
/// ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
///
/// ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
/// ; msg   loc.idx    param    pass mode            ssa flags  ty
/// ; ret    _0      = v0       ByRef                NOT_SSA    (u8, u8)
/// ; arg    _1      = v1       ByRef                NOT_SSA    IsNotEmpty
/// ; arg    _2.0    = v2       ByVal(types::I64)    NOT_SSA    &&[u16]
///
///     ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
///     ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
///     ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
///     sig0 = (i64, i64, i64) system_v
///     sig1 = (i64, i64, i64) system_v
///     fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
///
/// ebb0(v0: i64, v1: i64, v2: i64):
///     v3 = stack_addr.i64 ss0
///     v4 = stack_addr.i64 ss1
///     store v2, v4
///     v5 = stack_addr.i64 ss2
///     jump ebb1
///
/// ebb1:
///     nop
/// ; _3 = &mut _1
/// ; _4 = _2
///     v6 = load.i64 v4
///     store v6, v5
/// ;
/// ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
///     v7 = load.i64 v5
///     call fn0(v0, v3, v7)
///     jump ebb2
///
/// ebb2:
///     nop
/// ;
/// ; return
///     return
/// }
/// ```

#[derive(Debug)]
pub struct CommentWriter {
    global_comments: Vec<String>,
    entity_comments: HashMap<AnyEntity, String>,
    inst_comments: HashMap<Inst, String>,
}

impl CommentWriter {
    pub fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
        let global_comments = if cfg!(debug_assertions) {
            vec![
                format!("symbol {}", tcx.symbol_name(instance).name.as_str()),
                format!("instance {:?}", instance),
                format!(
                    "sig {:?}",
                    tcx.normalize_erasing_late_bound_regions(
                        ParamEnv::reveal_all(),
                        &crate::abi::fn_sig_for_fn_abi(tcx, instance)
                    )
                ),
                String::new(),
            ]
        } else {
            vec![]
        };

        CommentWriter {
            global_comments,
            entity_comments: HashMap::new(),
            inst_comments: HashMap::new(),
        }
    }
}

impl FuncWriter for &'_ CommentWriter {
    fn write_preamble(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        reg_info: Option<&isa::RegInfo>,
    ) -> Result<bool, fmt::Error> {
        for comment in &self.global_comments {
            if !comment.is_empty() {
                writeln!(w, "; {}", comment)?;
            } else {
                writeln!(w, "")?;
            }
        }
        if !self.global_comments.is_empty() {
            writeln!(w, "")?;
        }

        self.super_preamble(w, func, reg_info)
    }

    fn write_entity_definition(
        &mut self,
        w: &mut dyn fmt::Write,
        _func: &Function,
        entity: AnyEntity,
        value: &dyn fmt::Display,
    ) -> fmt::Result {
        write!(w, "    {} = {}", entity, value)?;

        if let Some(comment) = self.entity_comments.get(&entity) {
            writeln!(w, " ; {}", comment.replace('\n', "\n; "))
        } else {
            writeln!(w, "")
        }
    }

    fn write_ebb_header(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        isa: Option<&dyn isa::TargetIsa>,
        ebb: Ebb,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_ebb_header(w, func, isa, ebb, indent)
    }

    fn write_instruction(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        aliases: &SecondaryMap<Value, Vec<Value>>,
        isa: Option<&dyn isa::TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
        if let Some(comment) = self.inst_comments.get(&inst) {
            writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
        }
        Ok(())
    }
}

#[cfg(debug_assertions)]
impl<'a, 'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> {
    pub fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        self.clif_comments.global_comments.push(comment.into());
    }

    pub fn add_entity_comment<'s, S: Into<Cow<'s, str>>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
        use std::collections::hash_map::Entry;
        match self.clif_comments.entity_comments.entry(entity.into()) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.into().as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into().into_owned());
            }
        }
    }

    pub fn add_comment<'s, S: Into<Cow<'s, str>>>(&mut self, inst: Inst, comment: S) {
        use std::collections::hash_map::Entry;
        match self.clif_comments.inst_comments.entry(inst) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.into().as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into().into_owned());
            }
        }
    }
}

#[cfg(debug_assertions)]
pub fn write_clif_file<'tcx>(
    tcx: TyCtxt<'tcx>,
    postfix: &str,
    instance: Instance<'tcx>,
    func: &ir::Function,
    mut clif_comments: &CommentWriter,
    value_ranges: Option<&ValueLabelsRanges>,
) {
    use std::io::Write;

    let symbol_name = tcx.symbol_name(instance).name.as_str();
    let clif_file_name = format!(
        "{}/{}__{}.{}.clif",
        concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/clif"),
        tcx.crate_name(LOCAL_CRATE),
        symbol_name,
        postfix,
    );

    let mut clif = String::new();
    cranelift_codegen::write::decorate_function(
        &mut clif_comments,
        &mut clif,
        &func,
        &DisplayFunctionAnnotations {
            isa: Some(&*crate::build_isa(
                tcx.sess, true, /* PIC doesn't matter here */
            )),
            value_ranges,
        },
    )
    .unwrap();

    match ::std::fs::File::create(clif_file_name) {
        Ok(mut file) => {
            let target_triple = crate::target_triple(tcx.sess);
            writeln!(file, "test compile").unwrap();
            writeln!(file, "set is_pic").unwrap();
            writeln!(file, "target {}", target_triple).unwrap();
            writeln!(file, "").unwrap();
            file.write(clif.as_bytes()).unwrap();
        }
        Err(e) => {
            tcx.sess.warn(&format!("err opening clif file: {:?}", e));
        }
    }
}

impl<'a, 'tcx, B: Backend + 'static> fmt::Debug for FunctionCx<'_, 'tcx, B> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{:?}", self.instance.substs)?;
        writeln!(f, "{:?}", self.local_map)?;

        let mut clif = String::new();
        ::cranelift_codegen::write::decorate_function(
            &mut &self.clif_comments,
            &mut clif,
            &self.bcx.func,
            &DisplayFunctionAnnotations::default(),
        )
        .unwrap();
        writeln!(f, "\n{}", clif)
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::env;
use std::path::{Path,PathBuf};
use racer::util::{path_exists, is_dir};
use std::fs::{read_dir};
use toml;

// otry is 'option try'
macro_rules! otry {
    ($e:expr) => (match $e { Some(e) => e, None => return None })
}

// converts errors into None
macro_rules! otry2 {
    ($e:expr) => (match $e { Ok(e) => e, Err(_) => return None })
}

fn find_src_via_lockfile(kratename: &str, cargofile: &Path) -> Option<PathBuf> {
    let mut file = otry2!(File::open(cargofile));
    let mut string = String::new();
    otry2!(file.read_to_string(&mut string));
    let mut parser = toml::Parser::new(&string);
    let lock_table = parser.parse().unwrap();

    debug!("find_src_via_lockfile found lock table {:?}", lock_table);

    let t = match lock_table.get("package") {
        Some(&toml::Value::Array(ref t1)) => t1,
        _ => return None
    };

    for item in t {
        if let &toml::Value::Table(ref t) = item {
            if Some(&toml::Value::String(kratename.to_string())) == t.get("name") {
                let version = otry!(getstr(t, "version"));
                let source = otry!(getstr(t, "source"));

                if Some("registry") == source.split("+").nth(0) {
                    return get_versioned_cratefile(kratename, &version);
                } else if Some("git") == source.split("+").nth(0) {
                    let sha1 = otry!(source.split("#").last());
                    let mut d = otry!(env::home_dir());
                    d.push(".cargo");
                    d.push("git");
                    d.push("checkouts");
                    d = otry!(find_git_src_dir(d, kratename, &sha1));
                    d.push("src");
                    d.push("lib.rs");
                    return Some(d);
                }
            }
        }
    }
    None
}

fn get_versioned_cratefile(kratename: &str, version: &str) -> Option<PathBuf> {
    let mut d = otry!(env::home_dir());
    d.push(".cargo");
    d.push("registry");
    d.push("src");
    d = otry!(find_cratesio_src_dir(d));
    d.push(kratename.to_string() + "-" + &version);
    d.push("src");
    d.push("lib.rs");

    Some(d)
 }

fn find_src_via_tomlfile(kratename: &str, cargofile: &Path) -> Option<PathBuf> {
    // only look for 'path' references here.
    // We find the git and crates.io stuff via the lockfile

    let mut file = otry2!(File::open(cargofile));
    let mut string = String::new();
    otry2!(file.read_to_string(&mut string));
    let mut parser = toml::Parser::new(&string);
    let table = otry!(parser.parse());
    let t = match table.get("dependencies") {
        Some(&toml::Value::Table(ref t)) => t,
        _ => return None
    };

    match t.get(kratename) {
        Some(&toml::Value::Table(ref t)) => {
            // local directory
            let relative_path = otry!(getstr(t, "path"));
            return Some(otry!(cargofile.parent())
                        .join(relative_path)
                        .join("src")
                        .join("lib.rs"));
        },
        Some(&toml::Value::String(ref version)) => {
            // versioned crate
            return get_versioned_cratefile(kratename, version);
        }
        _ => return None
    }
}

fn find_cratesio_src_dir(d: PathBuf) -> Option<PathBuf> {
    for entry in otry2!(read_dir(d)) {
        let path = otry2!(entry).path();
        if is_dir(path.as_path()) {
            if let Some(ref fname) = path.file_name().and_then(|s| s.to_str()) {
                if fname.starts_with("github.com-") {
                    return Some(path.clone());
                }
            }
        }
    }
    None
}

fn find_git_src_dir(d: PathBuf, name: &str, sha1: &str) -> Option<PathBuf> {
    for entry in otry2!(read_dir(d)) {
        let path = otry2!(entry).path();
        if is_dir(path.as_path()) {
            if let Some(ref fname) = path.file_name().and_then(|s| s.to_str()) {
                if fname.starts_with(name) {
                    let mut d = path.clone();

                    // dirname can be the sha1 or master.
                    d.push(sha1);

                    if !is_dir(d.as_path()) {
                        d.pop();
                        d.push("master");
                    }

                    let retval = d.clone();

                    // check that the checkout matches the commit sha1
                    d.push(".git");
                    d.push("refs");
                    d.push("heads");
                    d.push("master");

                    let mut headref = String::new();
                    otry2!(otry2!(File::open(d)).read_to_string(&mut headref));

                    debug!("git headref is {:?}", headref);

                    if headref.ends_with("\n") {
                        headref.pop();
                    }

                    if sha1 == headref {
                        return Some(retval);
                    }
                }
            }
        }
    }
    None
}

fn getstr(t: &toml::Table, k: &str) -> Option<String> {
    match t.get(k) {
        Some(&toml::Value::String(ref s)) => Some(s.clone()),
        _ => None
    }
}

fn find_cargo_tomlfile(currentfile: &Path) -> Option<PathBuf> {
    let mut f = currentfile.to_path_buf();
    f.push("Cargo.toml");
    if path_exists(f.as_path()) {
        return Some(f);
    } else {
        if f.pop() && f.pop() {
            return find_cargo_tomlfile(&f);
        } else {
            None
        }
    }
}

pub fn get_crate_file(kratename: &str, from_path: &Path) -> Option<PathBuf> {
    if let Some(tomlfile) = find_cargo_tomlfile(from_path) {
        // look in the lockfile first, if there is one
        debug!("get_crate_file tomlfile is {:?}", tomlfile);
        let mut lockfile = tomlfile.clone();
        lockfile.pop();
        lockfile.push("Cargo.lock");
        if path_exists(lockfile.as_path()) {
            if let Some(f) = find_src_via_lockfile(kratename, &lockfile) {
                return Some(f);
            }
        }

        // oh, no luck with the lockfile. Try the tomlfile
        return find_src_via_tomlfile(kratename, &tomlfile)
    }
    None
}
<commit_msg>Add some support for multirust<commit_after>use std::fs::File;
use std::io::Read;
use std::env;
use std::path::{Path,PathBuf};
use racer::util::{path_exists, is_dir};
use std::fs::{read_dir};
use toml;

// otry is 'option try'
macro_rules! otry {
    ($e:expr) => (match $e { Some(e) => e, None => return None })
}

// converts errors into None
macro_rules! otry2 {
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => { error!("ERROR!: {:?} {} {}", e, file!(), line!()); return None } })
}

fn find_src_via_lockfile(kratename: &str, cargofile: &Path) -> Option<PathBuf> {
    let mut file = otry2!(File::open(cargofile));
    let mut string = String::new();
    otry2!(file.read_to_string(&mut string));
    let mut parser = toml::Parser::new(&string);
    let lock_table = parser.parse().unwrap();

    debug!("find_src_via_lockfile found lock table {:?}", lock_table);

    let t = match lock_table.get("package") {
        Some(&toml::Value::Array(ref t1)) => t1,
        _ => return None
    };

    for item in t {
        if let &toml::Value::Table(ref t) = item {
            if Some(&toml::Value::String(kratename.to_string())) == t.get("name") {
                let version = otry!(getstr(t, "version"));
                let source = otry!(getstr(t, "source"));

                if Some("registry") == source.split("+").nth(0) {
                    return get_versioned_cratefile(kratename, &version);
                } else if Some("git") == source.split("+").nth(0) {
                    let sha1 = otry!(source.split("#").last());
                    let mut d = otry!(get_cargo_rootdir());
                    d.push("git");
                    d.push("checkouts");
                    d = otry!(find_git_src_dir(d, kratename, &sha1));
                    d.push("src");
                    d.push("lib.rs");
                    return Some(d);
                }
            }
        }
    }
    None
}

fn get_cargo_rootdir() -> Option<PathBuf> {
    let mut d = otry!(env::home_dir());
    d.push(".cargo");
    if path_exists(&d) {
        return Some(d);
    }

    // try multirust
    d.pop();
    d.push(".multirust");
    d.push("default");
    if let Ok(mut multirustdefault) = File::open(&d) {
        let mut s = String::new();
        otry2!(multirustdefault.read_to_string(&mut s));
        d.pop();
        d.push("toolchains");
        d.push(s.trim());
        d.push("cargo");
        debug!("get_cargo_rootdir root is {:?}",d);
        Some(d)
    } else {
        None
    }
}

fn get_versioned_cratefile(kratename: &str, version: &str) -> Option<PathBuf> {
    let mut d = otry!(get_cargo_rootdir());
    d.push("registry");
    d.push("src");
    d = otry!(find_cratesio_src_dir(d));
    d.push(kratename.to_string() + "-" + &version);
    d.push("src");
    d.push("lib.rs");

    Some(d)
 }

fn find_src_via_tomlfile(kratename: &str, cargofile: &Path) -> Option<PathBuf> {
    // only look for 'path' references here.
    // We find the git and crates.io stuff via the lockfile

    let mut file = otry2!(File::open(cargofile));
    let mut string = String::new();
    otry2!(file.read_to_string(&mut string));
    let mut parser = toml::Parser::new(&string);
    let table = otry!(parser.parse());
    let t = match table.get("dependencies") {
        Some(&toml::Value::Table(ref t)) => t,
        _ => return None
    };

    match t.get(kratename) {
        Some(&toml::Value::Table(ref t)) => {
            // local directory
            let relative_path = otry!(getstr(t, "path"));
            return Some(otry!(cargofile.parent())
                        .join(relative_path)
                        .join("src")
                        .join("lib.rs"));
        },
        Some(&toml::Value::String(ref version)) => {
            // versioned crate
            return get_versioned_cratefile(kratename, version);
        }
        _ => return None
    }
}

fn find_cratesio_src_dir(d: PathBuf) -> Option<PathBuf> {
    for entry in otry2!(read_dir(d)) {
        let path = otry2!(entry).path();
        if is_dir(path.as_path()) {
            if let Some(ref fname) = path.file_name().and_then(|s| s.to_str()) {
                if fname.starts_with("github.com-") {
                    return Some(path.clone());
                }
            }
        }
    }
    None
}

fn find_git_src_dir(d: PathBuf, name: &str, sha1: &str) -> Option<PathBuf> {
    for entry in otry2!(read_dir(d)) {
        let path = otry2!(entry).path();
        if is_dir(path.as_path()) {
            if let Some(ref fname) = path.file_name().and_then(|s| s.to_str()) {
                if fname.starts_with(name) {
                    let mut d = path.clone();

                    // dirname can be the sha1 or master.
                    d.push(sha1);

                    if !is_dir(d.as_path()) {
                        d.pop();
                        d.push("master");
                    }

                    let retval = d.clone();

                    // check that the checkout matches the commit sha1
                    d.push(".git");
                    d.push("refs");
                    d.push("heads");
                    d.push("master");

                    let mut headref = String::new();
                    otry2!(otry2!(File::open(d)).read_to_string(&mut headref));

                    debug!("git headref is {:?}", headref);

                    if headref.ends_with("\n") {
                        headref.pop();
                    }

                    if sha1 == headref {
                        return Some(retval);
                    }
                }
            }
        }
    }
    None
}

fn getstr(t: &toml::Table, k: &str) -> Option<String> {
    match t.get(k) {
        Some(&toml::Value::String(ref s)) => Some(s.clone()),
        _ => None
    }
}

fn find_cargo_tomlfile(currentfile: &Path) -> Option<PathBuf> {
    let mut f = currentfile.to_path_buf();
    f.push("Cargo.toml");
    if path_exists(f.as_path()) {
        return Some(f);
    } else {
        if f.pop() && f.pop() {
            return find_cargo_tomlfile(&f);
        } else {
            None
        }
    }
}

pub fn get_crate_file(kratename: &str, from_path: &Path) -> Option<PathBuf> {
    if let Some(tomlfile) = find_cargo_tomlfile(from_path) {
        // look in the lockfile first, if there is one
        debug!("get_crate_file tomlfile is {:?}", tomlfile);
        let mut lockfile = tomlfile.clone();
        lockfile.pop();
        lockfile.push("Cargo.lock");
        if path_exists(lockfile.as_path()) {
            if let Some(f) = find_src_via_lockfile(kratename, &lockfile) {
                return Some(f);
            }
        }

        // oh, no luck with the lockfile. Try the tomlfile
        return find_src_via_tomlfile(kratename, &tomlfile)
    }
    None
}
<|endoftext|>


<commit_before>//! HTTP/HTTPS URL type for Iron.

use url::{self, Host};
use std::fmt;

/// HTTP/HTTPS URL type for Iron.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Url {
    /// The generic rust-url that corresponds to this Url
    generic_url: url::Url,
}

impl Url {
    /// Create a URL from a string.
    ///
    /// The input must be a valid URL with a special scheme for this to succeed.
    ///
    /// HTTP and HTTPS are special schemes.
    ///
    /// See: http://url.spec.whatwg.org/#special-scheme
    pub fn parse(input: &str) -> Result<Url, String> {
        // Parse the string using rust-url, then convert.
        match url::Url::parse(input) {
            Ok(raw_url) => Url::from_generic_url(raw_url),
            Err(e) => Err(format!("{}", e))
        }
    }

    /// Create a `Url` from a `rust-url` `Url`.
    pub fn from_generic_url(raw_url: url::Url) -> Result<Url, String> {
        // Create an Iron URL by verifying the `rust-url` `Url` is a special
        // scheme that Iron supports.
        if raw_url.cannot_be_a_base() {
            Err(format!("Not a special scheme: `{}`", raw_url.scheme()))
        } else if raw_url.port_or_known_default().is_none() {
            Err(format!("Invalid special scheme: `{}`", raw_url.scheme()))
        } else {
            Ok(Url {
                generic_url: raw_url,
            })
        }
    }

    /// Create a `rust-url` `Url` from a `Url`.
    pub fn into_generic_url(self) -> url::Url {
        self.generic_url
    }

    /// The lower-cased scheme of the URL, typically "http" or "https".
    pub fn scheme(&self) -> &str {
        self.generic_url.scheme()
    }

    /// The host field of the URL, probably a domain.
    pub fn host(&self) -> Host<&str> {
        // `unwrap` is safe here because urls that cannot be a base don't have a host
        self.generic_url.host().unwrap()
    }

    /// The connection port.
    pub fn port(&self) -> u16 {
        // `unwrap` is safe here because we checked `port_or_known_default`
        // in `from_generic_url`.
        self.generic_url.port_or_known_default().unwrap()
    }

    /// The URL path, the resource to be accessed.
    ///
    /// A *non-empty* vector encoding the parts of the URL path.
    /// Empty entries of `""` correspond to trailing slashes.
    pub fn path(&self) -> Vec<&str> {
        // `unwrap` is safe here because urls that can be a base will have `Some`.
        self.generic_url.path_segments().unwrap().collect()
    }

    /// The URL username field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank username was provided.
    /// Otherwise, a non-empty string.
    pub fn username(&self) -> Option<&str> {
        // Map empty usernames to None.
        match self.generic_url.username() {
            "" => None,
            username => Some(username)
        }
    }

    /// The URL password field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank password was provided.
    /// Otherwise, a non-empty string.
    pub fn password(&self) -> Option<&str> {
        // Map empty passwords to None.
        match self.generic_url.password() {
            None => None,
            Some(ref x) if x.is_empty() => None,
            Some(password) => Some(password)
        }
    }

    /// The URL query string.
    ///
    /// `None` if the `?` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn query(&self) -> Option<&str> {
        self.generic_url.query()
    }

    /// The URL fragment.
    ///
    /// `None` if the `#` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn fragment(&self) -> Option<&str> {
        self.generic_url.fragment()
    }
}

impl fmt::Display for Url {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        try!(self.generic_url.fmt(formatter));
        Ok(())
    }
}

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

    #[test]
    fn test_default_port() {
        assert_eq!(Url::parse("http://example.com/wow").unwrap().port(), 80u16);
        assert_eq!(Url::parse("https://example.com/wow").unwrap().port(), 443u16);
    }

    #[test]
    fn test_explicit_port() {
        assert_eq!(Url::parse("http://localhost:3097").unwrap().port(), 3097u16);
    }

    #[test]
    fn test_empty_username() {
        assert!(Url::parse("http://@example.com").unwrap().username().is_none());
        assert!(Url::parse("http://:password@example.com").unwrap().username().is_none());
    }

    #[test]
    fn test_not_empty_username() {
        let url = Url::parse("http://john:pass@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");

        let url = Url::parse("http://john:@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");
    }

    #[test]
    fn test_empty_password() {
        assert!(Url::parse("http://michael@example.com").unwrap().password().is_none());
        assert!(Url::parse("http://:@example.com").unwrap().password().is_none());
    }

    #[test]
    fn test_not_empty_password() {
        let url = Url::parse("http://michael:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");

        let url = Url::parse("http://:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");
    }

    #[test]
    fn test_formatting() {
        assert_eq!(Url::parse("http://michael@example.com/path/?q=wow").unwrap().to_string(),
                    "http://michael@example.com/path/?q=wow".to_string());
    }

    #[test]
    fn test_conversion() {
        let url_str = "https://user:password@iron.com:8080/path?q=wow#fragment";
        let url = Url::parse(url_str).unwrap();

        // Convert to a generic URL and check fidelity.
        let raw_url = url.clone().into_generic_url();
        assert_eq!(::url::Url::parse(url_str).unwrap(), raw_url);

        // Convert back to an Iron URL and check fidelity.
        let new_url = Url::from_generic_url(raw_url).unwrap();
        assert_eq!(url, new_url);
    }

    #[test]
    fn test_https_non_default_port() {
        let parsed = Url::parse("https://example.com:8080").unwrap().to_string();
        assert_eq!(parsed, "https://example.com:8080/");
    }

    #[test]
    fn test_https_default_port() {
        let parsed = Url::parse("https://example.com:443").unwrap().to_string();
        assert_eq!(parsed, "https://example.com/");
    }
}
<commit_msg>Add generic_url and generic_url_mut to Url<commit_after>//! HTTP/HTTPS URL type for Iron.

use url::{self, Host};
use std::fmt;

/// HTTP/HTTPS URL type for Iron.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Url {
    /// The generic rust-url that corresponds to this Url
    generic_url: url::Url,
}

impl Url {
    /// Create a URL from a string.
    ///
    /// The input must be a valid URL with a special scheme for this to succeed.
    ///
    /// HTTP and HTTPS are special schemes.
    ///
    /// See: http://url.spec.whatwg.org/#special-scheme
    pub fn parse(input: &str) -> Result<Url, String> {
        // Parse the string using rust-url, then convert.
        match url::Url::parse(input) {
            Ok(raw_url) => Url::from_generic_url(raw_url),
            Err(e) => Err(format!("{}", e))
        }
    }

    /// Create a `Url` from a `rust-url` `Url`.
    pub fn from_generic_url(raw_url: url::Url) -> Result<Url, String> {
        // Create an Iron URL by verifying the `rust-url` `Url` is a special
        // scheme that Iron supports.
        if raw_url.cannot_be_a_base() {
            Err(format!("Not a special scheme: `{}`", raw_url.scheme()))
        } else if raw_url.port_or_known_default().is_none() {
            Err(format!("Invalid special scheme: `{}`", raw_url.scheme()))
        } else {
            Ok(Url {
                generic_url: raw_url,
            })
        }
    }

    /// Create a `rust-url` `Url` from a `Url`.
    pub fn into_generic_url(self) -> url::Url {
        self.generic_url
    }

    /// Return an immutable pointer to the underlying `rust-url` `Url`.
    pub fn generic_url(&self) -> &url::Url {
        &self.generic_url
    }

    /// Return a mutable pointer to the underlying `rust-url` `Url`.
    pub fn generic_url_mut(&mut self) -> &mut url::Url {
        &mut self.generic_url
    }

    /// The lower-cased scheme of the URL, typically "http" or "https".
    pub fn scheme(&self) -> &str {
        self.generic_url.scheme()
    }

    /// The host field of the URL, probably a domain.
    pub fn host(&self) -> Host<&str> {
        // `unwrap` is safe here because urls that cannot be a base don't have a host
        self.generic_url.host().unwrap()
    }

    /// The connection port.
    pub fn port(&self) -> u16 {
        // `unwrap` is safe here because we checked `port_or_known_default`
        // in `from_generic_url`.
        self.generic_url.port_or_known_default().unwrap()
    }

    /// The URL path, the resource to be accessed.
    ///
    /// A *non-empty* vector encoding the parts of the URL path.
    /// Empty entries of `""` correspond to trailing slashes.
    pub fn path(&self) -> Vec<&str> {
        // `unwrap` is safe here because urls that can be a base will have `Some`.
        self.generic_url.path_segments().unwrap().collect()
    }

    /// The URL username field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank username was provided.
    /// Otherwise, a non-empty string.
    pub fn username(&self) -> Option<&str> {
        // Map empty usernames to None.
        match self.generic_url.username() {
            "" => None,
            username => Some(username)
        }
    }

    /// The URL password field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank password was provided.
    /// Otherwise, a non-empty string.
    pub fn password(&self) -> Option<&str> {
        // Map empty passwords to None.
        match self.generic_url.password() {
            None => None,
            Some(ref x) if x.is_empty() => None,
            Some(password) => Some(password)
        }
    }

    /// The URL query string.
    ///
    /// `None` if the `?` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn query(&self) -> Option<&str> {
        self.generic_url.query()
    }

    /// The URL fragment.
    ///
    /// `None` if the `#` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn fragment(&self) -> Option<&str> {
        self.generic_url.fragment()
    }
}

impl fmt::Display for Url {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        try!(self.generic_url.fmt(formatter));
        Ok(())
    }
}

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

    #[test]
    fn test_default_port() {
        assert_eq!(Url::parse("http://example.com/wow").unwrap().port(), 80u16);
        assert_eq!(Url::parse("https://example.com/wow").unwrap().port(), 443u16);
    }

    #[test]
    fn test_explicit_port() {
        assert_eq!(Url::parse("http://localhost:3097").unwrap().port(), 3097u16);
    }

    #[test]
    fn test_empty_username() {
        assert!(Url::parse("http://@example.com").unwrap().username().is_none());
        assert!(Url::parse("http://:password@example.com").unwrap().username().is_none());
    }

    #[test]
    fn test_not_empty_username() {
        let url = Url::parse("http://john:pass@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");

        let url = Url::parse("http://john:@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");
    }

    #[test]
    fn test_empty_password() {
        assert!(Url::parse("http://michael@example.com").unwrap().password().is_none());
        assert!(Url::parse("http://:@example.com").unwrap().password().is_none());
    }

    #[test]
    fn test_not_empty_password() {
        let url = Url::parse("http://michael:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");

        let url = Url::parse("http://:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");
    }

    #[test]
    fn test_formatting() {
        assert_eq!(Url::parse("http://michael@example.com/path/?q=wow").unwrap().to_string(),
                    "http://michael@example.com/path/?q=wow".to_string());
    }

    #[test]
    fn test_conversion() {
        let url_str = "https://user:password@iron.com:8080/path?q=wow#fragment";
        let url = Url::parse(url_str).unwrap();

        // Convert to a generic URL and check fidelity.
        let raw_url = url.clone().into_generic_url();
        assert_eq!(::url::Url::parse(url_str).unwrap(), raw_url);

        // Convert back to an Iron URL and check fidelity.
        let new_url = Url::from_generic_url(raw_url).unwrap();
        assert_eq!(url, new_url);
    }

    #[test]
    fn test_https_non_default_port() {
        let parsed = Url::parse("https://example.com:8080").unwrap().to_string();
        assert_eq!(parsed, "https://example.com:8080/");
    }

    #[test]
    fn test_https_default_port() {
        let parsed = Url::parse("https://example.com:443").unwrap().to_string();
        assert_eq!(parsed, "https://example.com/");
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;
use std::rc::Rc;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::EntropyRng;
use prng::hc128::Hc128Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// Cloning this handle just produces a new reference to the same thread-local
/// generator.
///
/// [`thread_rng`]: ../fn.thread_rng.html
/// [`ReseedingRng`]: adapter/struct.ReseedingRng.html
/// [`StdRng`]: struct.StdRng.html
/// [`EntropyRng`]: struct.EntropyRng.html
/// [HC-128]: ../prng/hc128/struct.Hc128Rng.html
#[derive(Clone, Debug)]
pub struct ThreadRng {
    rng: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>>,
}

thread_local!(
    static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>> = {
        let mut entropy_source = EntropyRng::new();
        let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    entropy_source);
        Rc::new(UnsafeCell::new(rng))
    }
);

/// Retrieve the lazily-initialized thread-local random number
/// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.
///
/// For more information see [`ThreadRng`].
///
/// [`ThreadRng`]: rngs/struct.ThreadRng.html
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng.get()).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng.get()).next_u64() }
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        unsafe { (*self.rng.get()).fill_bytes(dest) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng.get()).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    #[cfg(not(feature="stdweb"))]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<commit_msg>ThreadRng: remove usage of Rc<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::EntropyRng;
use prng::hc128::Hc128Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// Cloning this handle just produces a new reference to the same thread-local
/// generator.
///
/// [`thread_rng`]: ../fn.thread_rng.html
/// [`ReseedingRng`]: adapter/struct.ReseedingRng.html
/// [`StdRng`]: struct.StdRng.html
/// [`EntropyRng`]: struct.EntropyRng.html
/// [HC-128]: ../prng/hc128/struct.Hc128Rng.html
#[derive(Clone, Debug)]
pub struct ThreadRng {
    // use of raw pointer implies type is neither Send nor Sync
    rng: *mut ReseedingRng<Hc128Core, EntropyRng>,
}

thread_local!(
    static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>> = {
        let mut entropy_source = EntropyRng::new();
        let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    entropy_source);
        UnsafeCell::new(rng)
    }
);

/// Retrieve the lazily-initialized thread-local random number
/// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.
///
/// For more information see [`ThreadRng`].
///
/// [`ThreadRng`]: rngs/struct.ThreadRng.html
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.get()) }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng).next_u64() }
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        unsafe { (*self.rng).fill_bytes(dest) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    #[cfg(not(feature="stdweb"))]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<|endoftext|>


<commit_before>mod root_leaf;
mod rootptr;
mod jpm;
mod results;

use ::Key;
use self::rootptr::RootPtr;

pub struct RudyMap<K: Key, V> {
    root: RootPtr<K, V>
}

impl<K: Key, V> RudyMap<K, V> {
    pub fn new() -> RudyMap<K, V> {
        RudyMap {
            root: RootPtr::empty()
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        self.root.insert(key, value)
    }

    pub fn remove(&mut self, key: K) -> Option<V> {
        self.root.remove(key)
    }

    /*
    fn clear(&mut self) {
        self.root.clear()
    }
    */

    pub fn contains_key(&self, key: K) -> bool {
        // Because this does not visit the pointer returned by get(), there
        // will not be unnecessary cache fills
        self.get(key).is_some()
    }

    pub fn get(&self, key: K) -> Option<&V>{
        self.root.get(key)
    }

    pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
        self.root.get_mut(key)
    }

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

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

    /*
    pub fn iter(&self) -> impl Iterator<Item=(K, &V)> {
        Iter::new(&self.root)
    }

    pub fn iter_mut(&self) -> impl Iterator<Item=(K, &mut V)> {
        IterMut::new(&mut self.root)
    }
    */
}

impl<K: Key, V> Default for RudyMap<K, V> {
    fn default() -> RudyMap<K, V> {
        RudyMap::new()
    }
}

#[test]
fn test_insert_get_1() {
    let mut map = RudyMap::<usize, usize>::new();
    map.insert(4usize, 10usize);
    assert_eq!(map.get(4), Some(&10));
}

#[test]
fn test_insert_get_2() {
    let mut map = RudyMap::<usize, usize>::new();
    map.insert(0usize, 10usize);
    map.insert(1usize, 20usize);
    assert_eq!(map.get(0), Some(&10));
    assert_eq!(map.get(1), Some(&20));
}
<commit_msg>Add some top-level Rudymap tests<commit_after>mod root_leaf;
mod rootptr;
mod jpm;
mod results;

use ::Key;
use self::rootptr::RootPtr;

pub struct RudyMap<K: Key, V> {
    root: RootPtr<K, V>
}

impl<K: Key, V> RudyMap<K, V> {
    pub fn new() -> RudyMap<K, V> {
        RudyMap {
            root: RootPtr::empty()
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        self.root.insert(key, value)
    }

    pub fn remove(&mut self, key: K) -> Option<V> {
        self.root.remove(key)
    }

    /*
    fn clear(&mut self) {
        self.root.clear()
    }
    */

    pub fn contains_key(&self, key: K) -> bool {
        // Because this does not visit the pointer returned by get(), there
        // will not be unnecessary cache fills
        self.get(key).is_some()
    }

    pub fn get(&self, key: K) -> Option<&V>{
        self.root.get(key)
    }

    pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
        self.root.get_mut(key)
    }

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

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

    /*
    pub fn iter(&self) -> impl Iterator<Item=(K, &V)> {
        Iter::new(&self.root)
    }

    pub fn iter_mut(&self) -> impl Iterator<Item=(K, &mut V)> {
        IterMut::new(&mut self.root)
    }
    */
}

impl<K: Key, V> Default for RudyMap<K, V> {
    fn default() -> RudyMap<K, V> {
        RudyMap::new()
    }
}

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

    #[test]
    fn test_insert_get_1() {
        let mut map = RudyMap::<usize, usize>::new();
        map.insert(4usize, 10usize);
        assert_eq!(map.get(4), Some(&10));
    }

    #[test]
    fn test_insert_get_2() {
        let mut map = RudyMap::<usize, usize>::new();
        map.insert(0usize, 10usize);
        map.insert(1usize, 20usize);
        assert_eq!(map.get(0), Some(&10));
        assert_eq!(map.get(1), Some(&20));
    }

    #[test]
    fn test_contains_key() {
        let mut map = RudyMap::<u32, u32>::new();
        assert_eq!(map.contains_key(0), false);
        assert_eq!(map.contains_key(1), false);

        assert_eq!(map.insert(0, 0), None);
        assert_eq!(map.contains_key(0), true);
        assert_eq!(map.contains_key(1), false);

        assert_eq!(map.remove(0), Some(0));
        assert_eq!(map.contains_key(0), false);
        assert_eq!(map.contains_key(1), false);
    }

    #[test]
    fn test_len() {
        let mut map = RudyMap::<u32, u32>::new();
        assert_eq!(map.len(), 0);
        assert_eq!(map.is_empty(), true);

        assert_eq!(map.insert(0, 0), None);
        assert_eq!(map.len(), 1);
        assert_eq!(map.is_empty(), false);

        assert_eq!(map.insert(1, 1), None);
        assert_eq!(map.len(), 2);
        assert_eq!(map.is_empty(), false);

        assert_eq!(map.insert(0, 2), Some(0));
        assert_eq!(map.len(), 2);
        assert_eq!(map.is_empty(), false);

        assert_eq!(map.remove(0), Some(2));
        assert_eq!(map.len(), 1);
        assert_eq!(map.is_empty(), false);

        assert_eq!(map.remove(1), Some(1));
        assert_eq!(map.len(), 0);
        assert_eq!(map.is_empty(), true);
    }

    #[test]
    fn test_get_mut() {
        let mut map = RudyMap::<u32, u32>::new();
        assert!(map.get(0).is_none());
        assert!(map.get_mut(0).is_none());

        assert_eq!(map.insert(0, 0), None);
        assert_eq!(map.get(0), Some(&0));
        assert_eq!(map.get_mut(0), Some(&mut 0));
        assert_eq!(map.get(1), None);
        assert_eq!(map.get_mut(1), None);

        *map.get_mut(0).unwrap() += 42;
        assert_eq!(map.get(0), Some(&42));
        assert_eq!(map.get_mut(0), Some(&mut 42));

        map.remove(0);
    }
}
<|endoftext|>


<commit_before>mod osx;
mod linux;
mod windows;

#[derive(Debug)]
pub struct Network {
    agr_ctl_rssi: i32,
    agr_ext_rssi: i32,
    agr_ctl_noise: i32,
    agr_ext_noise: i32,
    state: String,
    op_mode: String,
    last_tx_rate: i32,
    max_rate: i32,
    last_assoc_status: i32,
    wireless_auth: String,
    link_auth: String,
    bssid: String,
    ssid: String,
    mcs: i32,
    channel: String,
}

pub fn get_info() -> Network {
    osx::get_info()
}
<commit_msg>Make network struct fields public<commit_after>mod osx;
mod linux;
mod windows;

#[derive(Debug)]
pub struct Network {
    pub agr_ctl_rssi: i32,
    pub agr_ext_rssi: i32,
    pub agr_ctl_noise: i32,
    pub agr_ext_noise: i32,
    pub state: String,
    pub op_mode: String,
    pub last_tx_rate: i32,
    pub max_rate: i32,
    pub last_assoc_status: i32,
    pub wireless_auth: String,
    pub link_auth: String,
    pub bssid: String,
    pub ssid: String,
    pub mcs: i32,
    pub channel: String,
}

pub fn get_info() -> Network {
    osx::get_info()
}
<|endoftext|>


<commit_before>//! Defines the `SearchNode` trait.

use uci::SetOption;
use board::{Board, IllegalBoard};
use moves::{Move, MoveDigest, AddMove};
use depth::*;
use value::*;
use evaluator::Evaluator;
use qsearch::QsearchResult;

/// A trait for chess positions -- a convenient interface for the
/// tree-searching algorithm.
///
/// A `SearchNode` can generate all legal moves in the current
/// position, play a selected move and take it back. It can also
/// quickly (without doing extensive tree-searching) evaluate the
/// chances of the sides, so that the tree-searching algorithm can use
/// this evaluation to assign realistic game outcomes to its leaf
/// nodes. `SearchNode` improves on `MoveGenerator` by adding the
/// following functionality:
///
/// 1. Smart position hashing.
/// 2. Exact evaluation of final positions.
/// 3. Quiescence search.
/// 4. 50 move rule awareness.
/// 5. Threefold/twofold repetition detection.
///
/// **Important note:** Repeating positions are considered a draw
/// after the first repetition, not after the second one as the chess
/// rules prescribe. In order to compensate for that,
/// `SearchNode::from_history` "forgets" all positions that have
/// occurred exactly once. Also, the newly created instance is never
/// deemed a draw due to repetition or rule-50.
pub trait SearchNode: Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type Evaluator: Evaluator;

    /// The type of result object that `evaluate_quiescence` returns.
    type QsearchResult: QsearchResult;

    /// Instantiates a new chess position from playing history.
    ///
    /// `fen` should be the Forsyth–Edwards Notation of a legal
    /// starting position. `moves` should be an iterator over all the
    /// moves that were played from that position. The move format is
    /// long algebraic notation. Examples: `e2e4`, `e7e5`, `e1g1`
    /// (white short castling), `e7e8q` (for promotion).
    fn from_history(fen: &str, moves: &mut Iterator<Item = &str>) -> Result<Self, IllegalBoard>;

    /// Returns an almost unique hash value for the position.
    ///
    /// The returned value is good for use as transposition table key.
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    fn board(&self) -> &Board;

    /// Returns the number of half-moves since the last piece capture
    /// or pawn advance.
    fn halfmove_clock(&self) -> u8;

    /// Returns the number of the current full move.
    ///
    /// Starts at 1 and is incremented after black's move.
    fn fullmove_number(&self) -> u16;

    /// Returns if the side to move is in check.
    fn is_check(&self) -> bool;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::Evaluator;

    /// Evaluates a final position.
    ///
    /// In final positions this method will return the correct value
    /// of the position (`0` for a draw, `VALUE_MIN` for a
    /// checkmate). A position is guaranteed to be final if
    /// `generate_moves` method generates no legal moves. (It may
    /// generate some pseudo-legal moves, but if none of them is
    /// legal, then the position is final.)
    fn evaluate_final(&self) -> Value;

    /// Performs quiescence search and returns a result.
    ///
    /// Quiescence search is a restricted search which considers only
    /// a limited set of moves (for example: winning captures, pawn
    /// promotions to queen, check evasions). The goal is to
    /// statically evaluate only "quiet" positions (positions where
    /// there are no winning tactical moves to be made). Although this
    /// search can cheaply and correctly resolve many simple tactical
    /// issues, it is completely blind to the more complex ones.
    ///
    /// * `depth` is the depth at which the main search stops and the
    ///   quiescence search takes on. It should be between `DEPTH_MIN`
    ///   and `0`. The quiescence search implementation may decide to
    ///   perform less thorough analysis when `depth` is smaller than
    ///   zero.
    ///
    /// * `lower_bound` and `upper_bound` together give the interval
    ///   within which an as precise as possible evaluation is
    ///   required. If during the calculation is determined that the
    ///   exact evaluation is outside of this interval, this method
    ///   may return a value that is closer to the the interval bounds
    ///   than the exact evaluation, but always staying on the correct
    ///   side of the interval.
    ///
    /// * `static_eval` should be position's static evaluation, or
    ///   `VALUE_UNKNOWN`.
    ///
    /// **Important note:** This method will return a reliable result
    /// even when the side to move is in check. Repeated and rule-50
    /// positions are always evaluated to `0`.
    fn evaluate_quiescence(&self,
                           depth: Depth,
                           lower_bound: Value,
                           upper_bound: Value,
                           static_eval: Value)
                           -> Self::QsearchResult;

    /// Returns the likely evaluation change (material) to be lost or
    /// gained as a result of a given move.
    ///
    /// This method performs static exchange evaluation (SEE). It
    /// examines the consequence of a series of exchanges on the
    /// destination square after a given move. A positive returned
    /// value indicates a "winning" move. For example, "PxQ" will
    /// always be a win, since the pawn side can choose to stop the
    /// exchange after its pawn is recaptured, and still be ahead. SEE
    /// is just an evaluation calculated without actually trying moves
    /// on the board, and therefore the returned value might be
    /// incorrect.
    ///
    /// The move passed to this method must have been generated by
    /// `generate_moves`, `try_move_digest`, or `null_move` methods
    /// for the current position on the board.
    fn evaluate_move(&self, m: Move) -> Value;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// A pseudo-legal move is a move that is otherwise legal, except
    /// it might leave the king in check. Every legal move is a
    /// pseudo-legal move, but not every pseudo-legal move is legal.
    /// The generated moves will be added to `moves`. If all of the
    /// moves generated by this methods are illegal (this means that
    /// `do_move(m)` returns `false` for all of them), then the
    /// position is final, and `evaluate_final()` will return its
    /// correct value.
    ///
    /// **Important note:** No moves will be generated in repeated and
    /// rule-50 positions.
    fn generate_moves<T: AddMove>(&self, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_moves` if called for the current position, and for
    /// that move `m.digest() == move_digest`, this method will
    /// return `Some(m)`. Otherwise it will return `None`. This is
    /// useful when playing moves from the transposition table,
    /// without calling `generate_moves`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It the move leaves the king in check, `false` is returned
    /// without updating the board. Otherwise the board is updated and
    /// `true` is returned. The move passed to this method must have
    /// been generated by `generate_moves`, `try_move_digest`, or
    /// `null_move` methods for the current position on the board.
    ///
    /// **Important note:** For null moves, if the position is a draw
    /// due to repetition or rule-50, `do_move` will return `false`.
    fn do_move(&mut self, m: Move) -> bool;

    /// Takes back the last played move.
    fn undo_last_move(&mut self);

    /// Returns all legal moves in the position.
    ///
    /// No moves are returned for repeated and rule-50 positions.
    ///
    /// **Important note:** This method is slower than
    /// `generate_moves` because it ensures that all returned moves
    /// are legal.
    fn legal_moves(&self) -> Vec<Move> {
        let mut position = self.clone();
        let mut legal_moves = Vec::with_capacity(96);
        let mut v = Vec::with_capacity(96);
        position.generate_moves(&mut v);
        for m in v.iter() {
            if position.do_move(*m) {
                legal_moves.push(*m);
                position.undo_last_move();
            }
        }
        legal_moves
    }
}
<commit_msg>clarify docs<commit_after>//! Defines the `SearchNode` trait.

use uci::SetOption;
use board::{Board, IllegalBoard};
use moves::{Move, MoveDigest, AddMove};
use depth::*;
use value::*;
use evaluator::Evaluator;
use qsearch::QsearchResult;

/// A trait for chess positions -- a convenient interface for the
/// tree-searching algorithm.
///
/// A `SearchNode` can generate all legal moves in the current
/// position, play a selected move and take it back. It can also
/// quickly (without doing extensive tree-searching) evaluate the
/// chances of the sides, so that the tree-searching algorithm can use
/// this evaluation to assign realistic game outcomes to its leaf
/// nodes. `SearchNode` improves on `MoveGenerator` by adding the
/// following functionality:
///
/// 1. Smart position hashing.
/// 2. Exact evaluation of final positions.
/// 3. Quiescence search.
/// 4. 50 move rule awareness.
/// 5. Threefold/twofold repetition detection.
///
/// **Important note:** Repeating positions are considered a draw
/// after the first repetition, not after the second one as the chess
/// rules prescribe. In order to compensate for that,
/// `SearchNode::from_history` "forgets" all positions that have
/// occurred exactly once. Also, the newly created instance is never
/// deemed a draw due to repetition or rule-50.
pub trait SearchNode: Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type Evaluator: Evaluator;

    /// The type of result object that `evaluate_quiescence` returns.
    type QsearchResult: QsearchResult;

    /// Instantiates a new chess position from playing history.
    ///
    /// `fen` should be the Forsyth–Edwards Notation of a legal
    /// starting position. `moves` should be an iterator over all the
    /// moves that were played from that position. The move format is
    /// long algebraic notation. Examples: `e2e4`, `e7e5`, `e1g1`
    /// (white short castling), `e7e8q` (for promotion).
    fn from_history(fen: &str, moves: &mut Iterator<Item = &str>) -> Result<Self, IllegalBoard>;

    /// Returns an almost unique hash value for the position.
    ///
    /// The returned value is good for use as transposition table key.
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    fn board(&self) -> &Board;

    /// Returns the number of half-moves since the last piece capture
    /// or pawn advance.
    fn halfmove_clock(&self) -> u8;

    /// Returns the number of the current full move.
    ///
    /// Starts at 1 and is incremented after black's move.
    fn fullmove_number(&self) -> u16;

    /// Returns if the side to move is in check.
    fn is_check(&self) -> bool;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::Evaluator;

    /// Evaluates a final position.
    ///
    /// In final positions this method will return the correct value
    /// of the position (`0` for a draw, `VALUE_MIN` for a
    /// checkmate). A position is guaranteed to be final if
    /// `generate_moves` method generates no legal moves. (It may
    /// generate some pseudo-legal moves, but if none of them is
    /// legal, then the position is final.)
    fn evaluate_final(&self) -> Value;

    /// Performs quiescence search and returns a result.
    ///
    /// Quiescence search is a restricted search which considers only
    /// a limited set of moves (for example: winning captures, pawn
    /// promotions to queen, check evasions). The goal is to
    /// statically evaluate only "quiet" positions (positions where
    /// there are no winning tactical moves to be made). Although this
    /// search can cheaply and correctly resolve many simple tactical
    /// issues, it is completely blind to the more complex ones.
    ///
    /// * `depth` is the depth at which the main search stops and the
    ///   quiescence search takes on. It should be between `DEPTH_MIN`
    ///   and `0`. The quiescence search implementation may decide to
    ///   perform less thorough analysis when `depth` is smaller than
    ///   zero.
    ///
    /// * `lower_bound` and `upper_bound` together give the interval
    ///   within which an as precise as possible evaluation is
    ///   required. If during the calculation is determined that the
    ///   exact evaluation is outside of this interval, this method
    ///   may return a value that is closer to the the interval bounds
    ///   than the exact evaluation, but always staying on the correct
    ///   side of the interval.
    ///
    ///   * `lower_bound` should be no lesser than `VALUE_MIN`.
    ///
    ///   * `upper_bound` should be greater than `lower_bound`, but no
    ///     greater than `VALUE_MAX`.
    ///
    /// * `static_eval` should be position's static evaluation, or
    ///   `VALUE_UNKNOWN`.
    ///
    /// **Important note:** This method will return a reliable result
    /// even when the side to move is in check. Repeated and rule-50
    /// positions are always evaluated to `0`.
    fn evaluate_quiescence(&self,
                           depth: Depth,
                           lower_bound: Value,
                           upper_bound: Value,
                           static_eval: Value)
                           -> Self::QsearchResult;

    /// Returns the likely evaluation change (material) to be lost or
    /// gained as a result of a given move.
    ///
    /// This method performs static exchange evaluation (SEE). It
    /// examines the consequence of a series of exchanges on the
    /// destination square after a given move. A positive returned
    /// value indicates a "winning" move. For example, "PxQ" will
    /// always be a win, since the pawn side can choose to stop the
    /// exchange after its pawn is recaptured, and still be ahead. SEE
    /// is just an evaluation calculated without actually trying moves
    /// on the board, and therefore the returned value might be
    /// incorrect.
    ///
    /// The move passed to this method must have been generated by
    /// `generate_moves`, `try_move_digest`, or `null_move` methods
    /// for the current position on the board.
    fn evaluate_move(&self, m: Move) -> Value;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// A pseudo-legal move is a move that is otherwise legal, except
    /// it might leave the king in check. Every legal move is a
    /// pseudo-legal move, but not every pseudo-legal move is legal.
    /// The generated moves will be added to `moves`. If all of the
    /// moves generated by this methods are illegal (this means that
    /// `do_move(m)` returns `false` for all of them), then the
    /// position is final, and `evaluate_final()` will return its
    /// correct value.
    ///
    /// **Important note:** No moves will be generated in repeated and
    /// rule-50 positions.
    fn generate_moves<T: AddMove>(&self, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_moves` if called for the current position, and for
    /// that move `m.digest() == move_digest`, this method will
    /// return `Some(m)`. Otherwise it will return `None`. This is
    /// useful when playing moves from the transposition table,
    /// without calling `generate_moves`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It the move leaves the king in check, `false` is returned
    /// without updating the board. Otherwise the board is updated and
    /// `true` is returned. The move passed to this method must have
    /// been generated by `generate_moves`, `try_move_digest`, or
    /// `null_move` methods for the current position on the board.
    ///
    /// **Important note:** For null moves, if the position is a draw
    /// due to repetition or rule-50, `do_move` will return `false`.
    fn do_move(&mut self, m: Move) -> bool;

    /// Takes back the last played move.
    fn undo_last_move(&mut self);

    /// Returns all legal moves in the position.
    ///
    /// No moves are returned for repeated and rule-50 positions.
    ///
    /// **Important note:** This method is slower than
    /// `generate_moves` because it ensures that all returned moves
    /// are legal.
    fn legal_moves(&self) -> Vec<Move> {
        let mut position = self.clone();
        let mut legal_moves = Vec::with_capacity(96);
        let mut v = Vec::with_capacity(96);
        position.generate_moves(&mut v);
        for m in v.iter() {
            if position.do_move(*m) {
                legal_moves.push(*m);
                position.undo_last_move();
            }
        }
        legal_moves
    }
}
<|endoftext|>