<commit_before>use std::rc::Rc;
use std::ops::Deref;

use ::expr::{Expr,Kint,  Kfloat, Type, Proc, Error as E, Result};
use ::env::Env;

pub fn kint(i: Kint) -> Expr {
    Expr::Int(i)
}

pub fn kfloat(f: Kfloat) -> Expr {
    Expr::Float(f)
}

pub fn kcons(car: Expr, cdr: Expr) -> Expr {
    Expr::Cons(Rc::new(car), Rc::new(cdr))
}

pub fn knil() -> Expr {
    Expr::Nil
}

pub fn ksym<S: Into<String>>(s: S) -> Expr {
    Expr::Sym(s.into())
}

pub fn kstr<S: Into<String>>(s: S) -> Expr {
    Expr::Str(s.into())
}

pub fn kproc(p: Proc) -> Expr {
    Expr::Proc(p)
}

pub fn klambda(param: Expr, body: Expr) -> Proc {
    Proc::Lambda(Rc::new(param), Rc::new(body))
}

pub fn kprim<S: Into<String>, F:'static + Fn(&mut Env, &Expr) -> Result<Expr> + Sized>(name: S, f: F) -> Proc{
    Proc::Prim(name.into(), Rc::new(f))
}

pub fn car(cons: &Expr) -> Result<Expr> {
    match cons {
        &Expr::Cons(ref car, _) => Ok(car.deref().clone()),
        arg => Err(E::Type(Type::Cons, arg.clone()))
    }
}

pub fn cdr(cons: &Expr) -> Result<Expr> {
    match cons {
        &Expr::Cons(_, ref cdr) => Ok(cdr.deref().clone()),
        arg => Err(E::Type(Type::Cons, arg.clone()))
    }
}

#[macro_export]
macro_rules! klist {
    ($car: expr, $($cdr: expr), *) => (
        kcons($crate::expr::Expr::from($car), klist!($($cdr),*))
    );
    ($car: expr) => (
        kcons($crate::expr::Expr::from($car), knil())
    );
    () => (
        knil()
    );
}

macro_rules! get_args_one {
    ($v:expr, Int) => (
        match $v {
            &Expr::Int(x) => Ok(x),
            hd => Err(E::Type(Type::Int, hd.clone()))
        }
    );

    ($v:expr, Float) => {
        match $v {
            &Expr::Float(x) => Ok(x),
            hd => Err(E::Type(Type::Float, hd.clone()))
        }
    };
    ($v:expr, Str) => (
        match $v {
            &Expr::Str(ref x) => Ok(x),
            hd => Err(E::Type(Type::Str, hd.clone()))

        }
    );
    ($v:expr, Sym) => (
        match $v {
            &Expr::Sym(ref x) => Ok(x),
            hd => Err(E::Type(Type::Sym, hd.clone()))
        }
    );
    ($v:expr, Nil) => (
        match $v {
            &Expr::Nil => Ok(()),
            hd => Err(E::Type(Type::Nil, hd.clone()))
        }
    );
    ($v:expr, Cons) => (
        match $v {
            &Expr::Cons(ref car, ref cdr) => Ok((car.deref(), cdr.deref())),
            hd => Err(E::Type(Type::Cons, hd.clone()))
        }
    );
    ($v:expr, Proc) => (
        match $v {
            &Expr::Proc(ref p) => Ok(p),
            hd => Err(E::Type(Type::Proc, hd.clone()))
        }
    );
    ($v:expr, Any) => (
        match $v {
            hd => if true {
                Ok(hd)
            } else {
                unreachable!()
            }
        };
    )
}

macro_rules! gen_pattern {
    (($var: pat, $ident: tt) $($other:tt) *) => (
        ($var, gen_pattern!($($other)*))
            );
    (&optional ($var: pat, $ident: tt) $($other:tt) *) => (
        ($var, gen_pattern!($($other)*))
            );
    () => (())
}

macro_rules! gen_match {
    ($args: expr, ($var: pat, $ident: tt) $($other:tt) *) =>
        (
            match $args {
                &Expr::Cons(ref hd, ref tl) => {
                    let v = try!(get_args_one!(hd.deref(), $ident));
                    (v, gen_match!(tl.deref(), $($other)*))
                },
                &Expr::Nil => return Err(E::ArityShort),
                args => return Err(E::InvalidArgument(args.clone()))
            };
            );
    ($args: expr, &optional ($var: pat, $ident: tt) $($other:tt) *) =>
        (
            match $args {
                &Expr::Cons(ref hd, ref tl) => {
                    let v = try!(get_args_one!(hd.deref(), $ident));
                    (Some(v), gen_match!(tl.deref(), &optional $($other)*))
                },
                &Expr::Nil => {
                    (None, gen_match!($args, &optional $($other)*))

                },
                args => return Err(E::InvalidArgument(args.clone()))
            };
            );
    ($args: expr, &optional) => (
        match $args {
            &Expr::Nil => (),
            _ => return Err(E::ArityExceed)
        }
        );
    ($args: expr, ) => (
        match $args {
            &Expr::Nil => (),
            _ => return Err(E::ArityExceed)
        }
        );
}

#[macro_export]
macro_rules! get_args {
    ($args: expr, $($other:tt) *) =>
        (
            let gen_pattern!($($other)*) = gen_match!($args, $($other)*)
            ) ;
    ($args: expr, ) => (
        let () = gen_match!($args,)
        );
    ($args: expr) => (
        let () = gen_match!($args,)
        );
}

pub fn f_foldl<F>(mut env: &mut Env, f: &F, init: &Expr, args: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr, &Expr) -> Result<Expr>{
    let mut res = init.clone();
    let mut head = args;
    let nil = &Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = try!(f(env, &res, car));
                head = cdr;
            }
            _ => return Err(E::InvalidArgument(args.clone()))
        }
    }
    Ok(res)
}

// fn f_reverse(mut env: &mut Env, args: &Expr) -> Result<Expr> {
//     f_foldl(env, &|_, acc, x| Ok(Expr::Cons(Rc::new(x.clone()), Rc::new(acc))), Expr::Nil, args)
// }

pub fn f_foldr<F>(mut env: &mut Env, f: &F, init: &Expr, args: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr, &Expr) -> Result<Expr>{
    match args {
        &Expr::Nil => Ok(init.clone()),
        &Expr::Cons(ref car, ref cdr) => {
            let v = try!(f_foldr(env, f, init, cdr));
            f(env, &v, car)
        }
        args => Err(E::InvalidArgument(args.clone()))
    }
}

pub fn f_map<F>(mut env: &mut Env, f: &F, list: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr) -> Result<Expr>{
    f_foldr(env, &|env, acc, x| Ok(kcons(try!(f(env, x)), acc.clone()))
                 , &Expr::Nil, list)
}

// fn f_iter<F>(mut env: &mut Env, f: &F, list: &Expr) -> Result<Expr>
//     where F: Fn(&mut Env, Expr) -> Result<()>{
//     f_foldr(env, &|env, _, x| {try!(f(env,x.clone())); Ok(Expr::Nil)}
//                  , Expr::Nil, list)
// }

<commit_msg>introduce bool arg<commit_after>use std::rc::Rc;
use std::ops::Deref;

use ::expr::{Expr,Kint,  Kfloat, Type, Proc, Error as E, Result};
use ::env::Env;

pub fn kint(i: Kint) -> Expr {
    Expr::Int(i)
}

pub fn kfloat(f: Kfloat) -> Expr {
    Expr::Float(f)
}

pub fn kcons(car: Expr, cdr: Expr) -> Expr {
    Expr::Cons(Rc::new(car), Rc::new(cdr))
}

pub fn knil() -> Expr {
    Expr::Nil
}

pub fn ksym<S: Into<String>>(s: S) -> Expr {
    Expr::Sym(s.into())
}

pub fn kstr<S: Into<String>>(s: S) -> Expr {
    Expr::Str(s.into())
}

pub fn kproc(p: Proc) -> Expr {
    Expr::Proc(p)
}

pub fn klambda(param: Expr, body: Expr) -> Proc {
    Proc::Lambda(Rc::new(param), Rc::new(body))
}

pub fn kprim<S: Into<String>, F:'static + Fn(&mut Env, &Expr) -> Result<Expr> + Sized>(name: S, f: F) -> Proc{
    Proc::Prim(name.into(), Rc::new(f))
}

pub fn car(cons: &Expr) -> Result<Expr> {
    match cons {
        &Expr::Cons(ref car, _) => Ok(car.deref().clone()),
        arg => Err(E::Type(Type::Cons, arg.clone()))
    }
}

pub fn cdr(cons: &Expr) -> Result<Expr> {
    match cons {
        &Expr::Cons(_, ref cdr) => Ok(cdr.deref().clone()),
        arg => Err(E::Type(Type::Cons, arg.clone()))
    }
}

#[macro_export]
macro_rules! klist {
    ($car: expr, $($cdr: expr), *) => (
        kcons($crate::expr::Expr::from($car), klist!($($cdr),*))
    );
    ($car: expr) => (
        kcons($crate::expr::Expr::from($car), knil())
    );
    () => (
        knil()
    );
}

macro_rules! get_args_one {
    ($v:expr, Int) => (
        match $v {
            &Expr::Int(x) => Ok(x),
            hd => Err(E::Type(Type::Int, hd.clone()))
        }
    );

    ($v:expr, Float) => {
        match $v {
            &Expr::Float(x) => Ok(x),
            hd => Err(E::Type(Type::Float, hd.clone()))
        }
    };
    ($v:expr, Str) => (
        match $v {
            &Expr::Str(ref x) => Ok(x),
            hd => Err(E::Type(Type::Str, hd.clone()))

        }
    );
    ($v:expr, Sym) => (
        match $v {
            &Expr::Sym(ref x) => Ok(x),
            hd => Err(E::Type(Type::Sym, hd.clone()))
        }
    );
    ($v:expr, Nil) => (
        match $v {
            &Expr::Nil => Ok(()),
            hd => Err(E::Type(Type::Nil, hd.clone()))
        }
    );
    ($v:expr, Bool) => (
        match $v {
            &Expr::Nil => Ok(false),
            _ => Ok(true)
        }
    );
    ($v:expr, Cons) => (
        match $v {
            &Expr::Cons(ref car, ref cdr) => Ok((car.deref(), cdr.deref())),
            hd => Err(E::Type(Type::Cons, hd.clone()))
        }
    );
    ($v:expr, Proc) => (
        match $v {
            &Expr::Proc(ref p) => Ok(p),
            hd => Err(E::Type(Type::Proc, hd.clone()))
        }
    );
    ($v:expr, Any) => (
        match $v {
            hd => if true {
                Ok(hd)
            } else {
                unreachable!()
            }
        };
    )
}

macro_rules! gen_pattern {
    (($var: pat, $ident: tt) $($other:tt) *) => (
        ($var, gen_pattern!($($other)*))
            );
    (&optional ($var: pat, $ident: tt) $($other:tt) *) => (
        ($var, gen_pattern!($($other)*))
            );
    () => (())
}

macro_rules! gen_match {
    ($args: expr, ($var: pat, $ident: tt) $($other:tt) *) =>
        (
            match $args {
                &Expr::Cons(ref hd, ref tl) => {
                    let v = try!(get_args_one!(hd.deref(), $ident));
                    (v, gen_match!(tl.deref(), $($other)*))
                },
                &Expr::Nil => return Err(E::ArityShort),
                args => return Err(E::InvalidArgument(args.clone()))
            };
            );
    ($args: expr, &optional ($var: pat, $ident: tt) $($other:tt) *) =>
        (
            match $args {
                &Expr::Cons(ref hd, ref tl) => {
                    let v = try!(get_args_one!(hd.deref(), $ident));
                    (Some(v), gen_match!(tl.deref(), &optional $($other)*))
                },
                &Expr::Nil => {
                    (None, gen_match!($args, &optional $($other)*))

                },
                args => return Err(E::InvalidArgument(args.clone()))
            };
            );
    ($args: expr, &optional) => (
        match $args {
            &Expr::Nil => (),
            _ => return Err(E::ArityExceed)
        }
        );
    ($args: expr, ) => (
        match $args {
            &Expr::Nil => (),
            _ => return Err(E::ArityExceed)
        }
        );
}

#[macro_export]
macro_rules! get_args {
    ($args: expr, $($other:tt) *) =>
        (
            let gen_pattern!($($other)*) = gen_match!($args, $($other)*)
            ) ;
    ($args: expr, ) => (
        let () = gen_match!($args,)
        );
    ($args: expr) => (
        let () = gen_match!($args,)
        );
}

pub fn f_foldl<F>(mut env: &mut Env, f: &F, init: &Expr, args: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr, &Expr) -> Result<Expr>{
    let mut res = init.clone();
    let mut head = args;
    let nil = &Expr::Nil;
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = try!(f(env, &res, car));
                head = cdr;
            }
            _ => return Err(E::InvalidArgument(args.clone()))
        }
    }
    Ok(res)
}

// fn f_reverse(mut env: &mut Env, args: &Expr) -> Result<Expr> {
//     f_foldl(env, &|_, acc, x| Ok(Expr::Cons(Rc::new(x.clone()), Rc::new(acc))), Expr::Nil, args)
// }

pub fn f_foldr<F>(mut env: &mut Env, f: &F, init: &Expr, args: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr, &Expr) -> Result<Expr>{
    match args {
        &Expr::Nil => Ok(init.clone()),
        &Expr::Cons(ref car, ref cdr) => {
            let v = try!(f_foldr(env, f, init, cdr));
            f(env, &v, car)
        }
        args => Err(E::InvalidArgument(args.clone()))
    }
}

pub fn f_map<F>(mut env: &mut Env, f: &F, list: &Expr) -> Result<Expr>
    where F: Fn(&mut Env, &Expr) -> Result<Expr>{
    f_foldr(env, &|env, acc, x| Ok(kcons(try!(f(env, x)), acc.clone()))
                 , &Expr::Nil, list)
}

// fn f_iter<F>(mut env: &mut Env, f: &F, list: &Expr) -> Result<Expr>
//     where F: Fn(&mut Env, Expr) -> Result<()>{
//     f_foldr(env, &|env, _, x| {try!(f(env,x.clone())); Ok(Expr::Nil)}
//                  , Expr::Nil, list)
// }

<|endoftext|>


<commit_before>
use crypto::sha2::Sha256;
use crypto::digest::Digest;
use super::SHA256_SIZE;
use std::ascii::AsciiExt;
use std::io;
use std::path::{PathBuf,Path};
use std::env::current_dir;
use std::io::Error as IoError;

/**
 * Generate the SHA-256 value of a password after several rounds of stretching.
 * [KEYSTRETCH Section 4.1] http://www.schneier.com/paper-low-entropy.pdf
 */
pub fn stretch_pass(salt: &[u8], pass: &[u8], iter: u32) -> Option<[u8; SHA256_SIZE]> {

    if salt.len() < SHA256_SIZE || iter < 2048{
        return None
    }

    let mut sha = Sha256::new();
    sha.input(pass);
    sha.input(salt);
    let mut hash: [u8; SHA256_SIZE] = [0; SHA256_SIZE];
    sha.result(&mut hash);

    for _ in 0..iter {
        sha = Sha256::new();
        sha.input(&hash);
        sha.result(&mut hash);
    }
    Some(hash)
}

/**Convert 4 byte slice into u32 (from little endian)*/
pub fn from_le32(b: &[u8]) -> Option<u32> {
    if b.len() < 4 {
        return None
    }
    Some(((b[3] as u32) << 24)
            + ((b[2] as u32) << 16)
            + ((b[1] as u32) << 8)
            + ((b[0] as u32)))
}

/**Convert 8 byte slice into u64 (from little endian)*/
pub fn from_le64(b: &[u8]) -> Option<u64> {
    if b.len() < 8 {
        return None
    }
    Some(((b[7] as u64) << 56)
            + ((b[6] as u64) << 48)
            + ((b[5] as u64) << 40)
            + ((b[4] as u64) << 32)
            + ((b[3] as u64) << 24)
            + ((b[2] as u64) << 16)
            + ((b[1] as u64) << 8)
            + ((b[0] as u64)))
}

/**
 * Matching function for filters - this behaves as
 * a case insensitive substring find. Except it
 * returns false if any of the arguments is empty.
 */
pub fn fuzzy_eq(needle: &str, hay: &str) -> bool
{
    if needle.is_empty() || hay.is_empty() {
        return false;
    }

    // FIXME: unicode?
    let h = hay.to_ascii_lowercase();
    let n = needle.to_ascii_lowercase();
    h.find(&n).is_some()
}

/**
 * Read binary data as time_t, i.e. decode 32bit or 64bit sequences
 * as unsigned little endian. [sec. 3.1.3]
 */
pub fn from_time_t(b: &[u8]) -> Option<u64> {
    if b.len() == 4 {
        from_le32(b).map(|val| val as u64)
    } else if b.len() == 8 {
        from_le64(b)
    } else {
        None
    }
}

/**
 * Fill buffer with data from file or fail
 */
pub fn read_all(r: &mut io::Read, buf: &mut [u8]) -> io::Result<usize> {
    let mut count = 0;

    while count < buf.len() {
        let res = r.read(&mut buf[count..]);
        match res {
            Ok(0) => break,
            Ok(done) => count += done,
            Err(err) => return Err(err),
        }
    }

    if count == buf.len() {
        Ok(count)
    } else {
        Err(io::Error::new(io::ErrorKind::Other, "Unexpected end of file"))
    }
}

/** Convert path to absolute path */
pub fn abspath(p: &PathBuf) -> Result<PathBuf,IoError> {
    if p.is_absolute() {
        return Ok(p.to_owned())
    } else {
        match current_dir() {
            Ok(mut cd) => {
                cd.push(p);
                Ok(cd)
            },
            Err(err) => Err(err),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::from_le32;
    use super::from_le64;
    use super::fuzzy_eq;

    #[test]
    fn test_from_le32() {
        assert_eq!(from_le32(b"\x00\x00\x00\x00").unwrap(), 0);
        assert_eq!(from_le32(b"\x01\x00\x00\x00").unwrap(), 0x01);
        assert_eq!(from_le32(b"\x00\x01\x00\x00").unwrap(), 0x0100);
        assert_eq!(from_le32(b"\x00\x00\x01\x00").unwrap(), 0x010000);
        assert_eq!(from_le32(b"\x00\x00\x00\x01").unwrap(), 0x01000000);
        assert_eq!(from_le32(b"\xff\xff\xff\xff").unwrap(), 0xffffffff);

        assert_eq!(from_le32(b""), None);
        assert_eq!(from_le32(b"\xff"), None);
        assert_eq!(from_le32(b"\xff\xff"), None);
        assert_eq!(from_le32(b"\xff\xff\xff"), None);
    }

    #[test]
    fn test_from_le64() {
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x00\x00\x00\x00").unwrap(), 0);
        assert_eq!(from_le64(b"\x01\x00\x00\x00\x00\x00\x00\x00").unwrap(), 0x01);
        assert_eq!(from_le64(b"\x00\x01\x00\x00\x00\x00\x00\x00").unwrap(), 0x0100);
        assert_eq!(from_le64(b"\x00\x00\x01\x00\x00\x00\x00\x00").unwrap(), 0x010000);
        assert_eq!(from_le64(b"\x00\x00\x00\x01\x00\x00\x00\x00").unwrap(), 0x01000000);
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x01\x00\x00\x00").unwrap(), 0x0100000000);
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x00\x01\x00\x00").unwrap(), 0x010000000000);
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x00\x00\x01\x00").unwrap(), 0x01000000000000);
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x00\x00\x00\x01").unwrap(), 0x0100000000000000);
        assert_eq!(from_le64(b"\xff\xff\xff\xff\xff\xff\xff\xff").unwrap(), 0xffffffffffffffff);

        assert_eq!(from_le64(b""), None);
        assert_eq!(from_le64(b"\xff"), None);
        assert_eq!(from_le64(b"\xff\xff"), None);
        assert_eq!(from_le64(b"\xff\xff\xff"), None);
        assert_eq!(from_le64(b"\xff\xff\xff\xff"), None);
        assert_eq!(from_le64(b"\xff\xff\xff\xff\xff"), None);
        assert_eq!(from_le64(b"\xff\xff\xff\xff\xff\xff"), None);
    }

    #[test]
    fn test_fuzzy_eq() {
        assert_eq!(fuzzy_eq("", ""), false);
        assert_eq!(fuzzy_eq("needle", ""), false);
        assert_eq!(fuzzy_eq("", "hay"), false);
        assert_eq!(fuzzy_eq("Needle", "needle"), true);
        assert_eq!(fuzzy_eq("needle", "http://nEedle"), true);
    }

}

<commit_msg>Cleanup: remove unnecessary use of Path<commit_after>
use crypto::sha2::Sha256;
use crypto::digest::Digest;
use super::SHA256_SIZE;
use std::ascii::AsciiExt;
use std::io;
use std::path::PathBuf;
use std::env::current_dir;
use std::io::Error as IoError;

/**
 * Generate the SHA-256 value of a password after several rounds of stretching.
 * [KEYSTRETCH Section 4.1] http://www.schneier.com/paper-low-entropy.pdf
 */
pub fn stretch_pass(salt: &[u8], pass: &[u8], iter: u32) -> Option<[u8; SHA256_SIZE]> {

    if salt.len() < SHA256_SIZE || iter < 2048{
        return None
    }

    let mut sha = Sha256::new();
    sha.input(pass);
    sha.input(salt);
    let mut hash: [u8; SHA256_SIZE] = [0; SHA256_SIZE];
    sha.result(&mut hash);

    for _ in 0..iter {
        sha = Sha256::new();
        sha.input(&hash);
        sha.result(&mut hash);
    }
    Some(hash)
}

/**Convert 4 byte slice into u32 (from little endian)*/
pub fn from_le32(b: &[u8]) -> Option<u32> {
    if b.len() < 4 {
        return None
    }
    Some(((b[3] as u32) << 24)
            + ((b[2] as u32) << 16)
            + ((b[1] as u32) << 8)
            + ((b[0] as u32)))
}

/**Convert 8 byte slice into u64 (from little endian)*/
pub fn from_le64(b: &[u8]) -> Option<u64> {
    if b.len() < 8 {
        return None
    }
    Some(((b[7] as u64) << 56)
            + ((b[6] as u64) << 48)
            + ((b[5] as u64) << 40)
            + ((b[4] as u64) << 32)
            + ((b[3] as u64) << 24)
            + ((b[2] as u64) << 16)
            + ((b[1] as u64) << 8)
            + ((b[0] as u64)))
}

/**
 * Matching function for filters - this behaves as
 * a case insensitive substring find. Except it
 * returns false if any of the arguments is empty.
 */
pub fn fuzzy_eq(needle: &str, hay: &str) -> bool
{
    if needle.is_empty() || hay.is_empty() {
        return false;
    }

    // FIXME: unicode?
    let h = hay.to_ascii_lowercase();
    let n = needle.to_ascii_lowercase();
    h.find(&n).is_some()
}

/**
 * Read binary data as time_t, i.e. decode 32bit or 64bit sequences
 * as unsigned little endian. [sec. 3.1.3]
 */
pub fn from_time_t(b: &[u8]) -> Option<u64> {
    if b.len() == 4 {
        from_le32(b).map(|val| val as u64)
    } else if b.len() == 8 {
        from_le64(b)
    } else {
        None
    }
}

/**
 * Fill buffer with data from file or fail
 */
pub fn read_all(r: &mut io::Read, buf: &mut [u8]) -> io::Result<usize> {
    let mut count = 0;

    while count < buf.len() {
        let res = r.read(&mut buf[count..]);
        match res {
            Ok(0) => break,
            Ok(done) => count += done,
            Err(err) => return Err(err),
        }
    }

    if count == buf.len() {
        Ok(count)
    } else {
        Err(io::Error::new(io::ErrorKind::Other, "Unexpected end of file"))
    }
}

/** Convert path to absolute path */
pub fn abspath(p: &PathBuf) -> Result<PathBuf,IoError> {
    if p.is_absolute() {
        return Ok(p.to_owned())
    } else {
        match current_dir() {
            Ok(mut cd) => {
                cd.push(p);
                Ok(cd)
            },
            Err(err) => Err(err),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::from_le32;
    use super::from_le64;
    use super::fuzzy_eq;

    #[test]
    fn test_from_le32() {
        assert_eq!(from_le32(b"\x00\x00\x00\x00").unwrap(), 0);
        assert_eq!(from_le32(b"\x01\x00\x00\x00").unwrap(), 0x01);
        assert_eq!(from_le32(b"\x00\x01\x00\x00").unwrap(), 0x0100);
        assert_eq!(from_le32(b"\x00\x00\x01\x00").unwrap(), 0x010000);
        assert_eq!(from_le32(b"\x00\x00\x00\x01").unwrap(), 0x01000000);
        assert_eq!(from_le32(b"\xff\xff\xff\xff").unwrap(), 0xffffffff);

        assert_eq!(from_le32(b""), None);
        assert_eq!(from_le32(b"\xff"), None);
        assert_eq!(from_le32(b"\xff\xff"), None);
        assert_eq!(from_le32(b"\xff\xff\xff"), None);
    }

    #[test]
    fn test_from_le64() {
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x00\x00\x00\x00").unwrap(), 0);
        assert_eq!(from_le64(b"\x01\x00\x00\x00\x00\x00\x00\x00").unwrap(), 0x01);
        assert_eq!(from_le64(b"\x00\x01\x00\x00\x00\x00\x00\x00").unwrap(), 0x0100);
        assert_eq!(from_le64(b"\x00\x00\x01\x00\x00\x00\x00\x00").unwrap(), 0x010000);
        assert_eq!(from_le64(b"\x00\x00\x00\x01\x00\x00\x00\x00").unwrap(), 0x01000000);
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x01\x00\x00\x00").unwrap(), 0x0100000000);
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x00\x01\x00\x00").unwrap(), 0x010000000000);
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x00\x00\x01\x00").unwrap(), 0x01000000000000);
        assert_eq!(from_le64(b"\x00\x00\x00\x00\x00\x00\x00\x01").unwrap(), 0x0100000000000000);
        assert_eq!(from_le64(b"\xff\xff\xff\xff\xff\xff\xff\xff").unwrap(), 0xffffffffffffffff);

        assert_eq!(from_le64(b""), None);
        assert_eq!(from_le64(b"\xff"), None);
        assert_eq!(from_le64(b"\xff\xff"), None);
        assert_eq!(from_le64(b"\xff\xff\xff"), None);
        assert_eq!(from_le64(b"\xff\xff\xff\xff"), None);
        assert_eq!(from_le64(b"\xff\xff\xff\xff\xff"), None);
        assert_eq!(from_le64(b"\xff\xff\xff\xff\xff\xff"), None);
    }

    #[test]
    fn test_fuzzy_eq() {
        assert_eq!(fuzzy_eq("", ""), false);
        assert_eq!(fuzzy_eq("needle", ""), false);
        assert_eq!(fuzzy_eq("", "hay"), false);
        assert_eq!(fuzzy_eq("Needle", "needle"), true);
        assert_eq!(fuzzy_eq("needle", "http://nEedle"), true);
    }

}

<|endoftext|>


<commit_before>use crate::args::SortBy;
use crate::Affected;

use std::cmp;

pub fn cmp_by_severity(a: &&Affected, b: &&Affected) -> cmp::Ordering {
    (a.severity as u64).cmp(&(b.severity as u64)).reverse()
}

pub fn cmp_by_pkgname(a: &&Affected, b: &&Affected) -> cmp::Ordering {
    a.package.cmp(&b.package)
}

pub fn cmp_by_upgradable(a: &&Affected, b: &&Affected) -> cmp::Ordering {
    a.fixed.is_some().cmp(&b.fixed.is_some())
}

pub fn sort_affected(affected: &mut Vec<&Affected>, sort_by: &[SortBy]) {
    for sort in sort_by.iter().rev() {
        match sort {
            SortBy::Severity => affected.sort_by(cmp_by_severity),
            SortBy::Pkgname => affected.sort_by(cmp_by_pkgname),
            SortBy::Upgradable => affected.sort_by(cmp_by_upgradable),
            SortBy::Reverse => affected.reverse(),
        }
    }
}
<commit_msg>opt: sort upgradable field reversed to show up at the top<commit_after>use crate::args::SortBy;
use crate::Affected;

use std::cmp;

pub fn cmp_by_severity(a: &&Affected, b: &&Affected) -> cmp::Ordering {
    (a.severity as u64).cmp(&(b.severity as u64)).reverse()
}

pub fn cmp_by_pkgname(a: &&Affected, b: &&Affected) -> cmp::Ordering {
    a.package.cmp(&b.package)
}

pub fn cmp_by_upgradable(a: &&Affected, b: &&Affected) -> cmp::Ordering {
    a.fixed.is_some().cmp(&b.fixed.is_some()).reverse()
}

pub fn sort_affected(affected: &mut Vec<&Affected>, sort_by: &[SortBy]) {
    for sort in sort_by.iter().rev() {
        match sort {
            SortBy::Severity => affected.sort_by(cmp_by_severity),
            SortBy::Pkgname => affected.sort_by(cmp_by_pkgname),
            SortBy::Upgradable => affected.sort_by(cmp_by_upgradable),
            SortBy::Reverse => affected.reverse(),
        }
    }
}
<|endoftext|>


<commit_before>//! Utility functions.

use crate::Month;

/// Whether to adjust the date, and in which direction. Useful when implementing arithmetic.
pub(crate) enum DateAdjustment {
    /// The previous day should be used.
    Previous,
    /// The next day should be used.
    Next,
    /// The date should be used as-is.
    None,
}

/// Get the number of days in the month of a given year.
///
/// ```rust
/// # use time::{Month, util};
/// assert_eq!(util::days_in_year_month(2020, Month::February), 29);
/// ```
pub const fn days_in_year_month(year: i32, month: Month) -> u8 {
    use Month::*;
    match month {
        January | March | May | July | August | October | December => 31,
        April | June | September | November => 30,
        February if is_leap_year(year) => 29,
        February => 28,
    }
}

/// Returns if the provided year is a leap year in the proleptic Gregorian calendar. Uses
/// [astronomical year numbering](https://en.wikipedia.org/wiki/Astronomical_year_numbering).
///
/// ```rust
/// # use time::util::is_leap_year;
/// assert!(!is_leap_year(1900));
/// assert!(is_leap_year(2000));
/// assert!(is_leap_year(2004));
/// assert!(!is_leap_year(2005));
/// assert!(!is_leap_year(2100));
/// ```
pub const fn is_leap_year(year: i32) -> bool {
    year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
}

/// Get the number of calendar days in a given year.
///
/// The returned value will always be either 365 or 366.
///
/// ```rust
/// # use time::util::days_in_year;
/// assert_eq!(days_in_year(1900), 365);
/// assert_eq!(days_in_year(2000), 366);
/// assert_eq!(days_in_year(2004), 366);
/// assert_eq!(days_in_year(2005), 365);
/// assert_eq!(days_in_year(2100), 365);
/// ```
pub const fn days_in_year(year: i32) -> u16 {
    if is_leap_year(year) { 366 } else { 365 }
}

/// Get the number of weeks in the ISO year.
///
/// The returned value will always be either 52 or 53.
///
/// ```rust
/// # use time::util::weeks_in_year;
/// assert_eq!(weeks_in_year(2019), 52);
/// assert_eq!(weeks_in_year(2020), 53);
/// ```
pub const fn weeks_in_year(year: i32) -> u8 {
    match year.rem_euclid(400) {
        4 | 9 | 15 | 20 | 26 | 32 | 37 | 43 | 48 | 54 | 60 | 65 | 71 | 76 | 82 | 88 | 93 | 99
        | 105 | 111 | 116 | 122 | 128 | 133 | 139 | 144 | 150 | 156 | 161 | 167 | 172 | 178
        | 184 | 189 | 195 | 201 | 207 | 212 | 218 | 224 | 229 | 235 | 240 | 246 | 252 | 257
        | 263 | 268 | 274 | 280 | 285 | 291 | 296 | 303 | 308 | 314 | 320 | 325 | 331 | 336
        | 342 | 348 | 353 | 359 | 364 | 370 | 376 | 381 | 387 | 392 | 398 => 53,
        _ => 52,
    }
}
<commit_msg>Optimize `is_leap_year`<commit_after>//! Utility functions.

use crate::Month;

/// Whether to adjust the date, and in which direction. Useful when implementing arithmetic.
pub(crate) enum DateAdjustment {
    /// The previous day should be used.
    Previous,
    /// The next day should be used.
    Next,
    /// The date should be used as-is.
    None,
}

/// Get the number of days in the month of a given year.
///
/// ```rust
/// # use time::{Month, util};
/// assert_eq!(util::days_in_year_month(2020, Month::February), 29);
/// ```
pub const fn days_in_year_month(year: i32, month: Month) -> u8 {
    use Month::*;
    match month {
        January | March | May | July | August | October | December => 31,
        April | June | September | November => 30,
        February if is_leap_year(year) => 29,
        February => 28,
    }
}

/// Returns if the provided year is a leap year in the proleptic Gregorian calendar. Uses
/// [astronomical year numbering](https://en.wikipedia.org/wiki/Astronomical_year_numbering).
///
/// ```rust
/// # use time::util::is_leap_year;
/// assert!(!is_leap_year(1900));
/// assert!(is_leap_year(2000));
/// assert!(is_leap_year(2004));
/// assert!(!is_leap_year(2005));
/// assert!(!is_leap_year(2100));
/// ```
pub const fn is_leap_year(year: i32) -> bool {
    year % 4 == 0 && (year % 25 != 0 || year % 16 == 0)
}

/// Get the number of calendar days in a given year.
///
/// The returned value will always be either 365 or 366.
///
/// ```rust
/// # use time::util::days_in_year;
/// assert_eq!(days_in_year(1900), 365);
/// assert_eq!(days_in_year(2000), 366);
/// assert_eq!(days_in_year(2004), 366);
/// assert_eq!(days_in_year(2005), 365);
/// assert_eq!(days_in_year(2100), 365);
/// ```
pub const fn days_in_year(year: i32) -> u16 {
    if is_leap_year(year) { 366 } else { 365 }
}

/// Get the number of weeks in the ISO year.
///
/// The returned value will always be either 52 or 53.
///
/// ```rust
/// # use time::util::weeks_in_year;
/// assert_eq!(weeks_in_year(2019), 52);
/// assert_eq!(weeks_in_year(2020), 53);
/// ```
pub const fn weeks_in_year(year: i32) -> u8 {
    match year.rem_euclid(400) {
        4 | 9 | 15 | 20 | 26 | 32 | 37 | 43 | 48 | 54 | 60 | 65 | 71 | 76 | 82 | 88 | 93 | 99
        | 105 | 111 | 116 | 122 | 128 | 133 | 139 | 144 | 150 | 156 | 161 | 167 | 172 | 178
        | 184 | 189 | 195 | 201 | 207 | 212 | 218 | 224 | 229 | 235 | 240 | 246 | 252 | 257
        | 263 | 268 | 274 | 280 | 285 | 291 | 296 | 303 | 308 | 314 | 320 | 325 | 331 | 336
        | 342 | 348 | 353 | 359 | 364 | 370 | 376 | 381 | 387 | 392 | 398 => 53,
        _ => 52,
    }
}
<|endoftext|>


<commit_before>use crate::ptr;
use crate::ops::{Deref, DerefMut};

/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
///
/// This wrapper is 0-cost.
///
/// `ManuallyDrop<T>` is subject to the same layout optimizations as `T`.
/// As a consequence, it has *no effect* on the assumptions that the compiler makes
/// about all values being initialized at their type.  In particular, initializing
/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior.
/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
///
/// # Examples
///
/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
/// the type:
///
/// ```rust
/// use std::mem::ManuallyDrop;
/// struct Peach;
/// struct Banana;
/// struct Melon;
/// struct FruitBox {
///     // Immediately clear there’s something non-trivial going on with these fields.
///     peach: ManuallyDrop<Peach>,
///     melon: Melon, // Field that’s independent of the other two.
///     banana: ManuallyDrop<Banana>,
/// }
///
/// impl Drop for FruitBox {
///     fn drop(&mut self) {
///         unsafe {
///             // Explicit ordering in which field destructors are run specified in the intuitive
///             // location – the destructor of the structure containing the fields.
///             // Moreover, one can now reorder fields within the struct however much they want.
///             ManuallyDrop::drop(&mut self.peach);
///             ManuallyDrop::drop(&mut self.banana);
///         }
///         // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
///         // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
///     }
/// }
/// ```
///
/// [`mem::zeroed`]: fn.zeroed.html
/// [`MaybeUninit<T>`]: union.MaybeUninit.html
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ManuallyDrop<T: ?Sized> {
    value: T,
}

impl<T> ManuallyDrop<T> {
    /// Wrap a value to be manually dropped.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::mem::ManuallyDrop;
    /// ManuallyDrop::new(Box::new(()));
    /// ```
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[inline(always)]
    pub const fn new(value: T) -> ManuallyDrop<T> {
        ManuallyDrop { value }
    }

    /// Extracts the value from the `ManuallyDrop` container.
    ///
    /// This allows the value to be dropped again.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::mem::ManuallyDrop;
    /// let x = ManuallyDrop::new(Box::new(()));
    /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`.
    /// ```
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[inline(always)]
    pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
        slot.value
    }

    /// Takes the contained value out.
    ///
    /// This method is primarily intended for moving out values in drop.
    /// Instead of using [`ManuallyDrop::drop`] to manually drop the value,
    /// you can use this method to take the value and use it however desired.
    /// `Drop` will be invoked on the returned value following normal end-of-scope rules.
    ///
    /// If you have ownership of the container, you can use [`ManuallyDrop::into_inner`] instead.
    ///
    /// # Safety
    ///
    /// This function semantically moves out the contained value without preventing further usage.
    /// It is up to the user of this method to ensure that this container is not used again.
    ///
    /// [`ManuallyDrop::drop`]: #method.drop
    /// [`ManuallyDrop::into_inner`]: #method.into_inner
    #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"]
    #[unstable(feature = "manually_drop_take", issue = "55422")]
    #[inline]
    pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
        ManuallyDrop::into_inner(ptr::read(slot))
    }
}

impl<T: ?Sized> ManuallyDrop<T> {
    /// Manually drops the contained value.
    ///
    /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead.
    ///
    /// # Safety
    ///
    /// This function runs the destructor of the contained value and thus the wrapped value
    /// now represents uninitialized data. It is up to the user of this method to ensure the
    /// uninitialized data is not actually used.
    ///
    /// [`ManuallyDrop::into_inner`]: #method.into_inner
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[inline]
    pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
        ptr::drop_in_place(&mut slot.value)
    }
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized> Deref for ManuallyDrop<T> {
    type Target = T;
    #[inline(always)]
    fn deref(&self) -> &T {
        &self.value
    }
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
    #[inline(always)]
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}
<commit_msg>Rollup merge of #62360 - Aaron1011:patch-2, r=RalfJung<commit_after>use crate::ptr;
use crate::ops::{Deref, DerefMut};

/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
///
/// This wrapper is 0-cost.
///
/// `ManuallyDrop<T>` is subject to the same layout optimizations as `T`.
/// As a consequence, it has *no effect* on the assumptions that the compiler makes
/// about all values being initialized at their type.  In particular, initializing
/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior.
/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
///
/// # Examples
///
/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
/// the type:
///
/// ```rust
/// use std::mem::ManuallyDrop;
/// struct Peach;
/// struct Banana;
/// struct Melon;
/// struct FruitBox {
///     // Immediately clear there’s something non-trivial going on with these fields.
///     peach: ManuallyDrop<Peach>,
///     melon: Melon, // Field that’s independent of the other two.
///     banana: ManuallyDrop<Banana>,
/// }
///
/// impl Drop for FruitBox {
///     fn drop(&mut self) {
///         unsafe {
///             // Explicit ordering in which field destructors are run specified in the intuitive
///             // location – the destructor of the structure containing the fields.
///             // Moreover, one can now reorder fields within the struct however much they want.
///             ManuallyDrop::drop(&mut self.peach);
///             ManuallyDrop::drop(&mut self.banana);
///         }
///         // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
///         // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
///     }
/// }
/// ```
///
/// [`mem::zeroed`]: fn.zeroed.html
/// [`MaybeUninit<T>`]: union.MaybeUninit.html
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ManuallyDrop<T: ?Sized> {
    value: T,
}

impl<T> ManuallyDrop<T> {
    /// Wrap a value to be manually dropped.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::mem::ManuallyDrop;
    /// ManuallyDrop::new(Box::new(()));
    /// ```
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[inline(always)]
    pub const fn new(value: T) -> ManuallyDrop<T> {
        ManuallyDrop { value }
    }

    /// Extracts the value from the `ManuallyDrop` container.
    ///
    /// This allows the value to be dropped again.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::mem::ManuallyDrop;
    /// let x = ManuallyDrop::new(Box::new(()));
    /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`.
    /// ```
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[inline(always)]
    pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
        slot.value
    }

    /// Takes the contained value out.
    ///
    /// This method is primarily intended for moving out values in drop.
    /// Instead of using [`ManuallyDrop::drop`] to manually drop the value,
    /// you can use this method to take the value and use it however desired.
    /// `Drop` will be invoked on the returned value following normal end-of-scope rules.
    ///
    /// If you have ownership of the container, you can use [`ManuallyDrop::into_inner`] instead.
    ///
    /// # Safety
    ///
    /// This function semantically moves out the contained value without preventing further usage.
    /// It is up to the user of this method to ensure that this container is not used again.
    ///
    /// [`ManuallyDrop::drop`]: #method.drop
    /// [`ManuallyDrop::into_inner`]: #method.into_inner
    #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"]
    #[unstable(feature = "manually_drop_take", issue = "55422")]
    #[inline]
    pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
        ManuallyDrop::into_inner(ptr::read(slot))
    }
}

impl<T: ?Sized> ManuallyDrop<T> {
    /// Manually drops the contained value.
    ///
    /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead.
    ///
    /// # Safety
    ///
    /// This function runs the destructor of the contained value and thus the wrapped value
    /// now represents uninitialized data. It is up to the user of this method to ensure the
    /// uninitialized data is not actually used.
    /// In particular, this function can only be called called at most once
    /// for a given instance of `ManuallyDrop<T>`.
    ///
    /// [`ManuallyDrop::into_inner`]: #method.into_inner
    #[stable(feature = "manually_drop", since = "1.20.0")]
    #[inline]
    pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
        ptr::drop_in_place(&mut slot.value)
    }
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized> Deref for ManuallyDrop<T> {
    type Target = T;
    #[inline(always)]
    fn deref(&self) -> &T {
        &self.value
    }
}

#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
    #[inline(always)]
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::borrow::Borrow;

#[derive(Debug,Clone)]
pub struct ForkTable<K: Eq + Hash,V>  {
    table: HashMap<K, V>,
    whiteouts: HashSet<K>,
    parent: Option<Box<ForkTable<K,V>>>
}

impl<K,V> ForkTable<K, V> where K: Eq + Hash {

    /// Returns a reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
        where K: Borrow<Q>, Q: Hash + Eq {
            unimplemented!()
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
        where K: Borrow<Q>, Q: Hash + Eq {
            unimplemented!()
    }

    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if self.whiteouts.contains(&k) { self.whiteouts.remove(&k); };
        self.table.insert(k, v)
    }

    /// Returns true if the map contains a value for the specified key.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    pub fn contains_key(&self, key: &K) -> bool  {
        self.table.contains_key(key)
    }

    /// Returns true if the key is defined in this level of the table, or
    /// in any of its' parents and is not whited out.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    pub fn chain_contains_key(&self, key: &K) -> bool {
        self.table.contains_key(key) ||
        (self.whiteouts.contains(key) &&
            match self.parent {
                Some(box ref p) => p.chain_contains_key(key),
                None    => false
            })
    }

    pub fn fork(self) -> ForkTable<K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: Some(box self)
        }
    }
}<commit_msg>Start on ForkTable tests<commit_after>use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::borrow::Borrow;

#[derive(Debug,Clone)]
pub struct ForkTable<K: Eq + Hash,V>  {
    table: HashMap<K, V>,
    whiteouts: HashSet<K>,
    parent: Option<Box<ForkTable<K,V>>>
}

impl<K,V> ForkTable<K, V> where K: Eq + Hash {

    /// Returns a reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
        where K: Borrow<Q>, Q: Hash + Eq {
            unimplemented!()
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
        where K: Borrow<Q>, Q: Hash + Eq {
            unimplemented!()
    }

    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if self.whiteouts.contains(&k) { self.whiteouts.remove(&k); };
        self.table.insert(k, v)
    }

    /// Returns true if the map contains a value for the specified key.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.contains_key(&1isize), true);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,String> = level_1.fork();
    /// assert_eq!(level_2.contains_key(&1isize), false);
    pub fn contains_key(&self, key: &K) -> bool  {
        self.table.contains_key(key)
    }

    /// Returns true if the key is defined in this level of the table, or
    /// in any of its' parents and is not whited out.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.chain_contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.chain_contains_key(&1isize), true);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.chain_contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(level_1.chain_contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,String> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// ```
    pub fn chain_contains_key(&self, key: &K) -> bool {
        self.table.contains_key(key) ||
        (self.whiteouts.contains(key) &&
            match self.parent {
                Some(box ref p) => p.chain_contains_key(key),
                None    => false
            })
    }

    pub fn fork(self) -> ForkTable<K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: Some(box self)
        }
    }

    pub fn new() -> ForkTable<K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: None
        }
    }
}<|endoftext|>


<commit_before>//! Completes keywords.

use syntax::{SyntaxKind, T};

use crate::{
    context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, CompletionItem,
    CompletionItemKind, CompletionKind, Completions,
};

pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    if ctx.token.kind() == SyntaxKind::COMMENT {
        cov_mark::hit!(no_keyword_completion_in_comments);
        return;
    }
    if matches!(ctx.completion_location, Some(ImmediateLocation::RecordExpr(_))) {
        cov_mark::hit!(no_keyword_completion_in_record_lit);
        return;
    }
    if ctx.attribute_under_caret.is_some() {
        cov_mark::hit!(no_keyword_completion_in_attr_of_expr);
        return;
    }

    // Suggest .await syntax for types that implement Future trait
    if let Some(receiver) = ctx.dot_receiver() {
        if let Some(ty) = ctx.sema.type_of_expr(receiver) {
            if ty.impls_future(ctx.db) {
                let mut item =
                    CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await");
                item.kind(CompletionItemKind::Keyword).detail("expr.await");
                item.add_to(acc);
            }
        };
    }

    let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet);

    let expects_assoc_item = ctx.expects_assoc_item();
    let has_block_expr_parent = ctx.has_block_expr_parent();
    let expects_item = ctx.expects_item();

    if ctx.has_impl_or_trait_prev_sibling() {
        add_keyword("where", "where ");
        if ctx.has_impl_prev_sibling() {
            add_keyword("for", "for ");
        }
        return;
    }
    if ctx.previous_token_is(T![unsafe]) {
        if expects_item || expects_assoc_item || has_block_expr_parent {
            add_keyword("fn", "fn $1($2) {\n    $0\n}")
        }

        if expects_item || has_block_expr_parent {
            add_keyword("trait", "trait $1 {\n    $0\n}");
            add_keyword("impl", "impl $1 {\n    $0\n}");
        }

        return;
    }

    if !ctx.has_visibility_prev_sibling()
        && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field())
    {
        add_keyword("pub(crate)", "pub(crate) ");
        add_keyword("pub", "pub ");
    }

    if expects_item || expects_assoc_item || has_block_expr_parent {
        add_keyword("unsafe", "unsafe ");
        add_keyword("fn", "fn $1($2) {\n    $0\n}");
        add_keyword("const", "const $0");
        add_keyword("type", "type $0");
    }

    if expects_item || has_block_expr_parent {
        if !ctx.has_visibility_prev_sibling() {
            add_keyword("impl", "impl $1 {\n    $0\n}");
            add_keyword("extern", "extern $0");
        }
        add_keyword("use", "use $0");
        add_keyword("trait", "trait $1 {\n    $0\n}");
        add_keyword("static", "static $0");
        add_keyword("mod", "mod $0");
    }

    if expects_item {
        add_keyword("enum", "enum $1 {\n    $0\n}");
        add_keyword("struct", "struct $0");
        add_keyword("union", "union $1 {\n    $0\n}");
    }

    if ctx.expects_type() {
        return;
    }

    if ctx.expects_expression() {
        if !has_block_expr_parent {
            add_keyword("unsafe", "unsafe {\n    $0\n}");
        }
        add_keyword("match", "match $1 {\n    $0\n}");
        add_keyword("while", "while $1 {\n    $0\n}");
        add_keyword("while let", "while let $1 = $2 {\n    $0\n}");
        add_keyword("loop", "loop {\n    $0\n}");
        add_keyword("if", "if $1 {\n    $0\n}");
        add_keyword("if let", "if let $1 = $2 {\n    $0\n}");
        add_keyword("for", "for $1 in $2 {\n    $0\n}");
        add_keyword("true", "true");
        add_keyword("false", "false");
    }

    if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent {
        add_keyword("let", "let ");
    }

    if ctx.after_if() {
        add_keyword("else", "else {\n    $0\n}");
        add_keyword("else if", "else if $1 {\n    $0\n}");
    }

    if ctx.expects_ident_pat_or_ref_expr() {
        add_keyword("mut", "mut ");
    }

    let (can_be_stmt, in_loop_body) = match ctx.path_context {
        Some(PathCompletionContext {
            is_trivial_path: true, can_be_stmt, in_loop_body, ..
        }) => (can_be_stmt, in_loop_body),
        _ => return,
    };

    if in_loop_body {
        if can_be_stmt {
            add_keyword("continue", "continue;");
            add_keyword("break", "break;");
        } else {
            add_keyword("continue", "continue");
            add_keyword("break", "break");
        }
    }

    let fn_def = match &ctx.function_def {
        Some(it) => it,
        None => return,
    };

    add_keyword(
        "return",
        match (can_be_stmt, fn_def.ret_type().is_some()) {
            (true, true) => "return $0;",
            (true, false) => "return;",
            (false, true) => "return $0",
            (false, false) => "return",
        },
    )
}

fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
    let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw);
    item.kind(CompletionItemKind::Keyword);

    match ctx.config.snippet_cap {
        Some(cap) => {
            if snippet.ends_with('}') && ctx.incomplete_let {
                cov_mark::hit!(let_semi);
                item.insert_snippet(cap, format!("{};", snippet));
            } else {
                item.insert_snippet(cap, snippet);
            }
        }
        None => {
            item.insert_text(if snippet.contains('$') { kw } else { snippet });
        }
    };
    item.add_to(acc);
}

#[cfg(test)]
mod tests {
    use expect_test::{expect, Expect};

    use crate::{
        tests::{check_edit, filtered_completion_list},
        CompletionKind,
    };

    fn check(ra_fixture: &str, expect: Expect) {
        let actual = filtered_completion_list(ra_fixture, CompletionKind::Keyword);
        expect.assert_eq(&actual)
    }

    #[test]
    fn test_keywords_in_function() {
        check(
            r"fn quux() { $0 }",
            expect![[r#"
                kw unsafe
                kw fn
                kw const
                kw type
                kw impl
                kw extern
                kw use
                kw trait
                kw static
                kw mod
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw let
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn test_keywords_inside_block() {
        check(
            r"fn quux() { if true { $0 } }",
            expect![[r#"
                kw unsafe
                kw fn
                kw const
                kw type
                kw impl
                kw extern
                kw use
                kw trait
                kw static
                kw mod
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw let
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_if() {
        check(
            r#"fn quux() { if true { () } $0 }"#,
            expect![[r#"
                kw unsafe
                kw fn
                kw const
                kw type
                kw impl
                kw extern
                kw use
                kw trait
                kw static
                kw mod
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw let
                kw else
                kw else if
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
        check_edit(
            "else",
            r#"fn quux() { if true { () } $0 }"#,
            r#"fn quux() { if true { () } else {
    $0
} }"#,
        );
    }

    #[test]
    fn test_keywords_in_match_arm() {
        check(
            r#"
fn quux() -> i32 {
    match () { () => $0 }
}
"#,
            expect![[r#"
                kw unsafe
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_loop() {
        check(
            r"fn my() { loop { $0 } }",
            expect![[r#"
                kw unsafe
                kw fn
                kw const
                kw type
                kw impl
                kw extern
                kw use
                kw trait
                kw static
                kw mod
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw let
                kw continue
                kw break
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_block_expr() {
        check(
            r"fn my_fn() { unsafe $0 }",
            expect![[r#"
                kw fn
                kw trait
                kw impl
            "#]],
        );
    }

    #[test]
    fn no_keyword_completion_in_comments() {
        cov_mark::check!(no_keyword_completion_in_comments);
        check(
            r#"
fn test() {
    let x = 2; // A comment$0
}
"#,
            expect![[""]],
        );
        check(
            r#"
/*
Some multi-line comment$0
*/
"#,
            expect![[""]],
        );
        check(
            r#"
/// Some doc comment
/// let test$0 = 1
"#,
            expect![[""]],
        );
    }

    #[test]
    fn test_completion_await_impls_future() {
        check(
            r#"
//- minicore: future
use core::future::*;
struct A {}
impl Future for A {}
fn foo(a: A) { a.$0 }
"#,
            expect![[r#"
                kw await expr.await
            "#]],
        );

        check(
            r#"
//- minicore: future
use std::future::*;
fn foo() {
    let a = async {};
    a.$0
}
"#,
            expect![[r#"
                kw await expr.await
            "#]],
        )
    }

    #[test]
    fn after_let() {
        check(
            r#"fn main() { let _ = $0 }"#,
            expect![[r#"
                kw unsafe
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw return
                kw self
                kw super
                kw crate
            "#]],
        )
    }

    #[test]
    fn skip_struct_initializer() {
        cov_mark::check!(no_keyword_completion_in_record_lit);
        check(
            r#"
struct Foo {
    pub f: i32,
}
fn foo() {
    Foo {
        $0
    }
}
"#,
            expect![[r#""#]],
        );
    }

    #[test]
    fn struct_initializer_field_expr() {
        check(
            r#"
struct Foo {
    pub f: i32,
}
fn foo() {
    Foo {
        f: $0
    }
}
"#,
            expect![[r#"
                kw unsafe
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn let_semi() {
        cov_mark::check!(let_semi);
        check_edit(
            "match",
            r#"
fn main() { let x = $0 }
"#,
            r#"
fn main() { let x = match $1 {
    $0
}; }
"#,
        );

        check_edit(
            "if",
            r#"
fn main() {
    let x = $0
    let y = 92;
}
"#,
            r#"
fn main() {
    let x = if $1 {
    $0
};
    let y = 92;
}
"#,
        );

        check_edit(
            "loop",
            r#"
fn main() {
    let x = $0
    bar();
}
"#,
            r#"
fn main() {
    let x = loop {
    $0
};
    bar();
}
"#,
        );
    }
}
<commit_msg>Update tests<commit_after>//! Completes keywords.

use syntax::{SyntaxKind, T};

use crate::{
    context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, CompletionItem,
    CompletionItemKind, CompletionKind, Completions,
};

pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    if ctx.token.kind() == SyntaxKind::COMMENT {
        cov_mark::hit!(no_keyword_completion_in_comments);
        return;
    }
    if matches!(ctx.completion_location, Some(ImmediateLocation::RecordExpr(_))) {
        cov_mark::hit!(no_keyword_completion_in_record_lit);
        return;
    }
    if ctx.attribute_under_caret.is_some() {
        cov_mark::hit!(no_keyword_completion_in_attr_of_expr);
        return;
    }

    // Suggest .await syntax for types that implement Future trait
    if let Some(receiver) = ctx.dot_receiver() {
        if let Some(ty) = ctx.sema.type_of_expr(receiver) {
            if ty.impls_future(ctx.db) {
                let mut item =
                    CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await");
                item.kind(CompletionItemKind::Keyword).detail("expr.await");
                item.add_to(acc);
            }
        };
    }

    let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet);

    let expects_assoc_item = ctx.expects_assoc_item();
    let has_block_expr_parent = ctx.has_block_expr_parent();
    let expects_item = ctx.expects_item();

    if ctx.has_impl_or_trait_prev_sibling() {
        add_keyword("where", "where ");
        if ctx.has_impl_prev_sibling() {
            add_keyword("for", "for ");
        }
        return;
    }
    if ctx.previous_token_is(T![unsafe]) {
        if expects_item || expects_assoc_item || has_block_expr_parent {
            add_keyword("fn", "fn $1($2) {\n    $0\n}")
        }

        if expects_item || has_block_expr_parent {
            add_keyword("trait", "trait $1 {\n    $0\n}");
            add_keyword("impl", "impl $1 {\n    $0\n}");
        }

        return;
    }

    if !ctx.has_visibility_prev_sibling()
        && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field())
    {
        add_keyword("pub(crate)", "pub(crate) ");
        add_keyword("pub", "pub ");
    }

    if expects_item || expects_assoc_item || has_block_expr_parent {
        add_keyword("unsafe", "unsafe ");
        add_keyword("fn", "fn $1($2) {\n    $0\n}");
        add_keyword("const", "const $0");
        add_keyword("type", "type $0");
    }

    if expects_item || has_block_expr_parent {
        if !ctx.has_visibility_prev_sibling() {
            add_keyword("impl", "impl $1 {\n    $0\n}");
            add_keyword("extern", "extern $0");
        }
        add_keyword("use", "use $0");
        add_keyword("trait", "trait $1 {\n    $0\n}");
        add_keyword("static", "static $0");
        add_keyword("mod", "mod $0");
    }

    if expects_item {
        add_keyword("enum", "enum $1 {\n    $0\n}");
        add_keyword("struct", "struct $0");
        add_keyword("union", "union $1 {\n    $0\n}");
    }

    if ctx.expects_type() {
        return;
    }

    if ctx.expects_expression() {
        if !has_block_expr_parent {
            add_keyword("unsafe", "unsafe {\n    $0\n}");
        }
        add_keyword("match", "match $1 {\n    $0\n}");
        add_keyword("while", "while $1 {\n    $0\n}");
        add_keyword("while let", "while let $1 = $2 {\n    $0\n}");
        add_keyword("loop", "loop {\n    $0\n}");
        add_keyword("if", "if $1 {\n    $0\n}");
        add_keyword("if let", "if let $1 = $2 {\n    $0\n}");
        add_keyword("for", "for $1 in $2 {\n    $0\n}");
        add_keyword("true", "true");
        add_keyword("false", "false");
    }

    if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent {
        add_keyword("let", "let ");
    }

    if ctx.after_if() {
        add_keyword("else", "else {\n    $0\n}");
        add_keyword("else if", "else if $1 {\n    $0\n}");
    }

    if ctx.expects_ident_pat_or_ref_expr() {
        add_keyword("mut", "mut ");
    }

    let (can_be_stmt, in_loop_body) = match ctx.path_context {
        Some(PathCompletionContext {
            is_trivial_path: true, can_be_stmt, in_loop_body, ..
        }) => (can_be_stmt, in_loop_body),
        _ => return,
    };

    if in_loop_body {
        if can_be_stmt {
            add_keyword("continue", "continue;");
            add_keyword("break", "break;");
        } else {
            add_keyword("continue", "continue");
            add_keyword("break", "break");
        }
    }

    let fn_def = match &ctx.function_def {
        Some(it) => it,
        None => return,
    };

    add_keyword(
        "return",
        match (can_be_stmt, fn_def.ret_type().is_some()) {
            (true, true) => "return $0;",
            (true, false) => "return;",
            (false, true) => "return $0",
            (false, false) => "return",
        },
    )
}

fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
    let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw);
    item.kind(CompletionItemKind::Keyword);

    match ctx.config.snippet_cap {
        Some(cap) => {
            if snippet.ends_with('}') && ctx.incomplete_let {
                cov_mark::hit!(let_semi);
                item.insert_snippet(cap, format!("{};", snippet));
            } else {
                item.insert_snippet(cap, snippet);
            }
        }
        None => {
            item.insert_text(if snippet.contains('$') { kw } else { snippet });
        }
    };
    item.add_to(acc);
}

#[cfg(test)]
mod tests {
    use expect_test::{expect, Expect};

    use crate::{
        tests::{check_edit, filtered_completion_list},
        CompletionKind,
    };

    fn check(ra_fixture: &str, expect: Expect) {
        let actual = filtered_completion_list(ra_fixture, CompletionKind::Keyword);
        expect.assert_eq(&actual)
    }

    #[test]
    fn test_keywords_in_function() {
        check(
            r"fn quux() { $0 }",
            expect![[r#"
                kw unsafe
                kw fn
                kw const
                kw type
                kw impl
                kw extern
                kw use
                kw trait
                kw static
                kw mod
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw true
                kw false
                kw let
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn test_keywords_inside_block() {
        check(
            r"fn quux() { if true { $0 } }",
            expect![[r#"
                kw unsafe
                kw fn
                kw const
                kw type
                kw impl
                kw extern
                kw use
                kw trait
                kw static
                kw mod
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw true
                kw false
                kw let
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_if() {
        check(
            r#"fn quux() { if true { () } $0 }"#,
            expect![[r#"
                kw unsafe
                kw fn
                kw const
                kw type
                kw impl
                kw extern
                kw use
                kw trait
                kw static
                kw mod
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw true
                kw false
                kw let
                kw else
                kw else if
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
        check_edit(
            "else",
            r#"fn quux() { if true { () } $0 }"#,
            r#"fn quux() { if true { () } else {
    $0
} }"#,
        );
    }

    #[test]
    fn test_keywords_in_match_arm() {
        check(
            r#"
fn quux() -> i32 {
    match () { () => $0 }
}
"#,
            expect![[r#"
                kw unsafe
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw true
                kw false
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_loop() {
        check(
            r"fn my() { loop { $0 } }",
            expect![[r#"
                kw unsafe
                kw fn
                kw const
                kw type
                kw impl
                kw extern
                kw use
                kw trait
                kw static
                kw mod
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw true
                kw false
                kw let
                kw continue
                kw break
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_block_expr() {
        check(
            r"fn my_fn() { unsafe $0 }",
            expect![[r#"
                kw fn
                kw trait
                kw impl
            "#]],
        );
    }

    #[test]
    fn no_keyword_completion_in_comments() {
        cov_mark::check!(no_keyword_completion_in_comments);
        check(
            r#"
fn test() {
    let x = 2; // A comment$0
}
"#,
            expect![[""]],
        );
        check(
            r#"
/*
Some multi-line comment$0
*/
"#,
            expect![[""]],
        );
        check(
            r#"
/// Some doc comment
/// let test$0 = 1
"#,
            expect![[""]],
        );
    }

    #[test]
    fn test_completion_await_impls_future() {
        check(
            r#"
//- minicore: future
use core::future::*;
struct A {}
impl Future for A {}
fn foo(a: A) { a.$0 }
"#,
            expect![[r#"
                kw await expr.await
            "#]],
        );

        check(
            r#"
//- minicore: future
use std::future::*;
fn foo() {
    let a = async {};
    a.$0
}
"#,
            expect![[r#"
                kw await expr.await
            "#]],
        )
    }

    #[test]
    fn after_let() {
        check(
            r#"fn main() { let _ = $0 }"#,
            expect![[r#"
                kw unsafe
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw true
                kw false
                kw return
                kw self
                kw super
                kw crate
            "#]],
        )
    }

    #[test]
    fn skip_struct_initializer() {
        cov_mark::check!(no_keyword_completion_in_record_lit);
        check(
            r#"
struct Foo {
    pub f: i32,
}
fn foo() {
    Foo {
        $0
    }
}
"#,
            expect![[r#""#]],
        );
    }

    #[test]
    fn struct_initializer_field_expr() {
        check(
            r#"
struct Foo {
    pub f: i32,
}
fn foo() {
    Foo {
        f: $0
    }
}
"#,
            expect![[r#"
                kw unsafe
                kw match
                kw while
                kw while let
                kw loop
                kw if
                kw if let
                kw for
                kw true
                kw false
                kw return
                kw self
                kw super
                kw crate
            "#]],
        );
    }

    #[test]
    fn let_semi() {
        cov_mark::check!(let_semi);
        check_edit(
            "match",
            r#"
fn main() { let x = $0 }
"#,
            r#"
fn main() { let x = match $1 {
    $0
}; }
"#,
        );

        check_edit(
            "if",
            r#"
fn main() {
    let x = $0
    let y = 92;
}
"#,
            r#"
fn main() {
    let x = if $1 {
    $0
};
    let y = 92;
}
"#,
        );

        check_edit(
            "loop",
            r#"
fn main() {
    let x = $0
    bar();
}
"#,
            r#"
fn main() {
    let x = loop {
    $0
};
    bar();
}
"#,
        );
    }
}
<|endoftext|>


<commit_before>

// https://github.com/rust-lang/getopts
extern crate getopts;

// https://github.com/Kimundi/lazy-static.rs
#[macro_use]
extern crate lazy_static;

use getopts::Options;
use std::env;
use std::io::{self,Write};
use std::process;

// https://doc.rust-lang.org/1.0.0/book/ffi.html
extern crate libc;
use libc::{int32_t};

#[allow(non_camel_case_types)]
enum krb5_context {}            // internal/opaque

// typedef krb5_int32 krb5_error_code
// typedef int32_t krb5_int32

#[link(name="krb5")]
extern {
    fn krb5_init_context(context: *mut krb5_context) -> int32_t;
}

lazy_static! {
    static ref PROGNAME: String = env::current_exe().unwrap() // PathBuf
        .file_name().unwrap()                                 // &OsStr
        .to_string_lossy().into_owned();                      // Cow<str> -> String
}

fn error(err: getopts::Fail) -> ! {
    let mut stderr = io::stderr();
    writeln!(&mut stderr, "Error: {}", err).unwrap();
    writeln!(&mut stderr, "Try '{} --help' for more information.", *PROGNAME).unwrap();
    process::exit(1);
}

fn usage(opts: &Options) -> ! {
    let brief = opts.short_usage(&*PROGNAME);
    println!("{}", opts.usage(&brief));
    process::exit(0);
}

fn main() {
// Debugging code:
//    println!("Progname is {}", *PROGNAME);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optopt("c", "", "specifies credential cache", "CCNAME");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { error(f) }
    };

    if matches.opt_present("h") {
        usage(&opts);
    }

    let ccache: Option<String> = matches.opt_str("c");
// Debugging code:
    if ccache.is_some() {
        println!("ccache is {}", ccache.clone().unwrap());
    }

    let kcontext = krb5_context;
    let rv = krb5_init_context(kcontext);
    println!("rv is {}", rv);
}
<commit_msg>Working on the rust version... still doesn't work.<commit_after>

// https://github.com/rust-lang/getopts
extern crate getopts;

use getopts::Options;
use std::env;
use std::io::{self,Write};
use std::process;

// https://doc.rust-lang.org/1.0.0/book/ffi.html
extern crate libc;

#[allow(non_camel_case_types)]
pub mod ffi {
    use libc::{int32_t};

    pub type krb5_int32 = int32_t;
    pub type krb5_error_code = krb5_int32;

    pub enum krb5_context {}            // internal/opaque

    #[link(name="krb5")]
    extern "C" {
        pub fn krb5_init_context(context: *mut krb5_context) -> krb5_error_code;
    }
}

#[derive(Debug)]
pub struct Krb5Context {
    ptr: *mut ffi::krb5_context,
}

impl Krb5Context {
    pub fn new() -> Krb5Context {
        Krb5Context {
            "need to figure out how to pass a pointer to krb5_init_context "
        }
    }
}

// This is a silly amount of work, but I wanted to learn how to
// get the progname into a global variable.
//
// https://github.com/Kimundi/lazy-static.rs
#[macro_use]
extern crate lazy_static;
lazy_static! {
    static ref PROGNAME: String = env::current_exe().unwrap() // PathBuf
        .file_name().unwrap()                                 // &OsStr
        .to_string_lossy().into_owned();                      // Cow<str> -> String
}

fn error(err: getopts::Fail) -> ! {
    let mut stderr = io::stderr();
    writeln!(&mut stderr, "Error: {}", err).unwrap();
    writeln!(&mut stderr, "Try '{} --help' for more information.", *PROGNAME).unwrap();
    process::exit(1);
}

fn usage(opts: &Options) -> ! {
    let brief = opts.short_usage(&*PROGNAME);
    println!("{}", opts.usage(&brief));
    process::exit(0);
}

// use libc::c_int;
// // krb5_context from krb5-1.8.2/src/include/k5-int.h
// #[repr(C)]
// pub struct _krb5_context {
//     // ...etc...
//     pub ser_ctx_count: c_int,
//     // ...etc...
// }

fn main() {
// Debugging code:
//    println!("Progname is {}", *PROGNAME);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optopt("c", "", "specifies credential cache", "CCNAME");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { error(f) }
    };

    if matches.opt_present("h") {
        usage(&opts);
    }

    let ccache: Option<String> = matches.opt_str("c");
// Debugging code:
    if ccache.is_some() {
        println!("ccache is {}", ccache.clone().unwrap());
    }

    let kcontext = Krb5Context::new();
    println!("code is {:?}", kcontext);
}
<|endoftext|>


<commit_before>//! Parser example for INI files.
#[macro_use]
extern crate combine;

use std::collections::HashMap;
use std::fmt;
use std::env;
use std::fs::File;
use std::io::{self, Read};

use combine::*;
use combine::char::space;
use combine::state::State;

#[cfg(feature = "std")]
use combine::state::SourcePosition;
#[cfg(feature = "std")]
use combine::easy;

enum Error<E> {
    Io(io::Error),
    Parse(E),
}

impl<E> fmt::Display for Error<E>
where
    E: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref err) => write!(f, "{}", err),
            Error::Parse(ref err) => write!(f, "{}", err),
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct Ini {
    pub global: HashMap<String, String>,
    pub sections: HashMap<String, HashMap<String, String>>,
}

parser!{
    fn property[I]()(I) -> (String, String)
        where [I: Stream<Item = char>]
    {
        (
            many1(satisfy(|c| c != '=' && c != '[' && c != ';')),
            token('='),
            many1(satisfy(|c| c != '\n' && c != ';')),
        ).map(|(key, _, value)| (key, value))
            .message("while parsing property")
    }
}
parser!{
    fn whitespace[I]()(I) -> ()
    where
        [I: Stream<Item = char>,]
    {
        let comment = (token(';'), skip_many(satisfy(|c| c != '\n'))).map(|_| ());
        // Wrap the `spaces().or(comment)` in `skip_many` so that it skips alternating whitespace and
        // comments
        skip_many(skip_many1(space()).or(comment))
    }
}

parser!{
    fn properties[I]()(I) -> HashMap<String, String>
    where
        [I: Stream<Item = char>,]
    {
        // After each property we skip any whitespace that followed it
        many(property().skip(whitespace()))
    }
}

parser!{
    fn section[I]()(I) -> (String, HashMap<String, String>)
    where
        [I: Stream<Item = char>,]
    {
        (
            between(token('['), token(']'), many(satisfy(|c| c != ']'))),
            whitespace(),
            properties(),
        ).map(|(name, _, properties)| (name, properties))
            .message("while parsing section")
    }
}

parser!{
    fn ini[I]()(I) -> Ini
    where
        [I: Stream<Item = char>,]
    {
        (
            whitespace(),
            properties(),
            many(section()),
        ).map(|(_, global, sections)| {
                Ini {
                    global: global,
                    sections: sections,
                }
            })
    }
}

#[test]
fn ini_ok() {
    let text = r#"
language=rust

[section]
name=combine; Comment
type=LL(1)

"#;
    let mut expected = Ini {
        global: HashMap::new(),
        sections: HashMap::new(),
    };
    expected
        .global
        .insert(String::from("language"), String::from("rust"));

    let mut section = HashMap::new();
    section.insert(String::from("name"), String::from("combine"));
    section.insert(String::from("type"), String::from("LL(1)"));
    expected.sections.insert(String::from("section"), section);

    let result = ini().parse(text).map(|t| t.0);
    assert_eq!(result, Ok(expected));
}

#[test]
fn ini_error() {
    let text = "[error";
    let result = ini().easy_parse(State::new(text)).map(|t| t.0);
    assert_eq!(
        result,
        Err(easy::Errors {
            position: SourcePosition { line: 1, column: 7 },
            errors: vec![
                Error::end_of_input(),
                Error::Expected(']'.into()),
                Error::Message("while parsing section".into()),
            ],
        })
    );
}

fn main() {
    let result = match env::args().nth(1) {
        Some(file) => File::open(file).map_err(Error::Io).and_then(main_),
        None => main_(io::stdin()),
    };
    match result {
        Ok(_) => println!("OK"),
        Err(err) => println!("{}", err),
    }
}

#[cfg(feature = "std")]
fn main_<R>(mut read: R) -> Result<(), Error<easy::Errors<SourcePosition, char, String>>>
where
    R: Read,
{
    let mut text = String::new();
    read.read_to_string(&mut text).map_err(Error::Io)?;
    ini()
        .easy_parse(State::new(&*text))
        .map_err(|err| Error::Parse(err.map_range(|s| s.to_string())))?;
    Ok(())
}

#[cfg(not(feature = "std"))]
fn main_<R>(mut read: R) -> Result<(), Error<::combine::primitives::StringStreamError>>
where
    R: Read,
{
    let mut text = String::new();
    read.read_to_string(&mut text).map_err(Error::Io)?;
    ini().parse(State::new(&*text)).map_err(Error::Parse)?;
    Ok(())
}
<commit_msg>chore: Fix build error in the ini example due to globs<commit_after>//! Parser example for INI files.
#[macro_use]
extern crate combine;

use std::collections::HashMap;
use std::fmt;
use std::env;
use std::fs::File;
use std::io::{self, Read};

use combine::*;
use combine::char::space;
use combine::state::State;

#[cfg(feature = "std")]
use combine::state::SourcePosition;
#[cfg(feature = "std")]
use combine::easy;

enum Error<E> {
    Io(io::Error),
    Parse(E),
}

impl<E> fmt::Display for Error<E>
where
    E: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref err) => write!(f, "{}", err),
            Error::Parse(ref err) => write!(f, "{}", err),
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct Ini {
    pub global: HashMap<String, String>,
    pub sections: HashMap<String, HashMap<String, String>>,
}

parser!{
    fn property[I]()(I) -> (String, String)
        where [I: Stream<Item = char>]
    {
        (
            many1(satisfy(|c| c != '=' && c != '[' && c != ';')),
            token('='),
            many1(satisfy(|c| c != '\n' && c != ';')),
        ).map(|(key, _, value)| (key, value))
            .message("while parsing property")
    }
}
parser!{
    fn whitespace[I]()(I) -> ()
    where
        [I: Stream<Item = char>,]
    {
        let comment = (token(';'), skip_many(satisfy(|c| c != '\n'))).map(|_| ());
        // Wrap the `spaces().or(comment)` in `skip_many` so that it skips alternating whitespace and
        // comments
        skip_many(skip_many1(space()).or(comment))
    }
}

parser!{
    fn properties[I]()(I) -> HashMap<String, String>
    where
        [I: Stream<Item = char>,]
    {
        // After each property we skip any whitespace that followed it
        many(property().skip(whitespace()))
    }
}

parser!{
    fn section[I]()(I) -> (String, HashMap<String, String>)
    where
        [I: Stream<Item = char>,]
    {
        (
            between(token('['), token(']'), many(satisfy(|c| c != ']'))),
            whitespace(),
            properties(),
        ).map(|(name, _, properties)| (name, properties))
            .message("while parsing section")
    }
}

parser!{
    fn ini[I]()(I) -> Ini
    where
        [I: Stream<Item = char>,]
    {
        (
            whitespace(),
            properties(),
            many(section()),
        ).map(|(_, global, sections)| {
                Ini {
                    global: global,
                    sections: sections,
                }
            })
    }
}

#[test]
fn ini_ok() {
    let text = r#"
language=rust

[section]
name=combine; Comment
type=LL(1)

"#;
    let mut expected = Ini {
        global: HashMap::new(),
        sections: HashMap::new(),
    };
    expected
        .global
        .insert(String::from("language"), String::from("rust"));

    let mut section = HashMap::new();
    section.insert(String::from("name"), String::from("combine"));
    section.insert(String::from("type"), String::from("LL(1)"));
    expected.sections.insert(String::from("section"), section);

    let result = ini().parse(text).map(|t| t.0);
    assert_eq!(result, Ok(expected));
}

#[cfg(feature = "std")]
#[test]
fn ini_error() {
    let text = "[error";
    let result = ini().easy_parse(State::new(text)).map(|t| t.0);
    assert_eq!(
        result,
        Err(easy::Errors {
            position: SourcePosition { line: 1, column: 7 },
            errors: vec![
                easy::Error::end_of_input(),
                easy::Error::Expected(']'.into()),
                easy::Error::Message("while parsing section".into()),
            ],
        })
    );
}

fn main() {
    let result = match env::args().nth(1) {
        Some(file) => File::open(file).map_err(Error::Io).and_then(main_),
        None => main_(io::stdin()),
    };
    match result {
        Ok(_) => println!("OK"),
        Err(err) => println!("{}", err),
    }
}

#[cfg(feature = "std")]
fn main_<R>(mut read: R) -> Result<(), Error<easy::Errors<SourcePosition, char, String>>>
where
    R: Read,
{
    let mut text = String::new();
    read.read_to_string(&mut text).map_err(Error::Io)?;
    ini()
        .easy_parse(State::new(&*text))
        .map_err(|err| Error::Parse(err.map_range(|s| s.to_string())))?;
    Ok(())
}

#[cfg(not(feature = "std"))]
fn main_<R>(mut read: R) -> Result<(), Error<::combine::primitives::StringStreamError>>
where
    R: Read,
{
    let mut text = String::new();
    read.read_to_string(&mut text).map_err(Error::Io)?;
    ini().parse(State::new(&*text)).map_err(Error::Parse)?;
    Ok(())
}
<|endoftext|>


<commit_before>/*!
 * Helpers for headers
 */

pub mod tags;

/**
 * Utility helpers for header data
 */
pub mod data {
    use std::ops::Deref;
    use storage::file::header::data::FileHeaderData as FHD;

    /**
     * Get an URL from a header, whereas the header has to have the following format:
     *
     *   { ..., "URL": "<URL>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_url_from_header(header: &FHD) -> Option<String> {
        get_named_text_from_header("URL", header)
    }

    /**
     * Get an NAME from a header, whereas the header has to have the following format:
     *
     *   { ..., "NAME": "<NAME>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_name_from_header(header: &FHD) -> Option<String> {
        get_named_text_from_header("NAME", header)
    }

    /**
     * Get a named field from the header, which has to be of this format
     *
     *   { ..., "<name of field>": "<content as string>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_named_text_from_header(name: &'static str, header: &FHD) -> Option<String> {
        match header {
            &FHD::Map{keys: ref ks} => {
                let mut keys : Vec<FHD> = ks.clone();
                keys.iter().find(|k| {
                    match k.deref() {
                        &FHD::Key{name: ref n, value: ref v} => n == name,
                        _ => false
                    }
                }).and_then(|urlkey| {
                    match urlkey.deref().clone() {
                        FHD::Key{name: _, value: ref v} => {
                            match v.deref().clone() {
                                FHD::Text(s) => Some(s),
                                _ => {
                                    warn!("Malformed Header Data: Expected Text, found non-Text");
                                    None
                                },
                            }
                        }
                        _ => {
                            warn!("Malformed Header Data: Expected Text, found non-Text");
                            None
                        },
                    }
                })
            },
            _ => {
                warn!("Malformed Header Data: Expected Map, found non-Map");
                None
            }
        }
    }

}

<commit_msg>Add debug output to text-from-header fetcher function<commit_after>/*!
 * Helpers for headers
 */

pub mod tags;

/**
 * Utility helpers for header data
 */
pub mod data {
    use std::ops::Deref;
    use storage::file::header::data::FileHeaderData as FHD;

    /**
     * Get an URL from a header, whereas the header has to have the following format:
     *
     *   { ..., "URL": "<URL>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_url_from_header(header: &FHD) -> Option<String> {
        get_named_text_from_header("URL", header)
    }

    /**
     * Get an NAME from a header, whereas the header has to have the following format:
     *
     *   { ..., "NAME": "<NAME>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_name_from_header(header: &FHD) -> Option<String> {
        get_named_text_from_header("NAME", header)
    }

    /**
     * Get a named field from the header, which has to be of this format
     *
     *   { ..., "<name of field>": "<content as string>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_named_text_from_header(name: &'static str, header: &FHD) -> Option<String> {
        match header {
            &FHD::Map{keys: ref ks} => {
                let mut keys : Vec<FHD> = ks.clone();
                keys.iter().find(|k| {
                    match k.deref() {
                        &FHD::Key{name: ref n, value: ref v} => n == name,
                        _ => false
                    }
                }).and_then(|urlkey| {
                    match urlkey.deref().clone() {
                        FHD::Key{name: ref n, value: ref v} => {
                            match v.deref().clone() {
                                FHD::Text(s) => Some(s),
                                _ => {
                                    warn!("Malformed Header Data: Expected Text, found non-Text");
                                    debug!("    in {}", n);
                                    None
                                },
                            }
                        }
                        _ => {
                            warn!("Malformed Header Data: Expected Text, found non-Text");
                            None
                        },
                    }
                })
            },
            _ => {
                warn!("Malformed Header Data: Expected Map, found non-Map");
                None
            }
        }
    }

}

<|endoftext|>