<commit_before>use std::string::CowString;
use std::fmt;
use std::collections::HashMap;
use std::rc::Rc;
use std::ops::Deref;

use error::{CompileError, CompileErrorKind, RuntimeError};
use datum::Datum;
use runtime::{Inst, MemRef, RDatum, RuntimeData, Closure};

/// Syntax variables
#[derive(Copy, Clone, PartialEq)]
pub enum Syntax {
    /// `lambda` syntax
    Lambda
}

/// Environment variables in the global environment
pub enum EnvVar {
    /// Syntax variables
    Syntax(Syntax),

    /// Primitive functions
    PrimFunc(&'static str, Rc<fn(&[RDatum]) -> Result<RDatum, RuntimeError>>),

    /// Compiled library functions
    Procedure(Rc<Vec<Inst>>)
}

/// Compiler compiles Datum into a bytecode evaluates it
pub struct Compiler<'g> {
    /// Global environment
    global_env: &'g HashMap<CowString<'static>, EnvVar>
}

struct CodeGenContext {
    link_size: usize,
}

impl<'g> Compiler<'g> {
    /// Creates a new compiler with given environment
    pub fn new<'a>(global_env: &'a HashMap<CowString<'static>, EnvVar>) -> Compiler<'a> {
        Compiler {
            global_env: global_env
        }
    }

    /// Compiles the datum into a bytecode evaluates it
    pub fn compile(&mut self, datum: &RDatum) -> Result<Vec<Inst>, CompileError> {
        let mut ctx = CodeGenContext {
            link_size: 0,
        };
        let mut code = try!(self.compile_expr(&[], &[], &mut ctx, datum));
        code.push(Inst::Return);
        return Ok(code);
    }

    fn compile_call(&mut self, static_scope: &[Vec<CowString<'static>>], args: &[CowString<'static>],
                    ctx: &mut CodeGenContext, datum: &RDatum)
            -> Result<Vec<Inst>, CompileError>
    {
        let mut code = Vec::new();
        let mut arg_count = 0;
        for d in datum.iter() {
            match d {
                Ok(d) => {
                    code.push_all(try!(self.compile_expr(static_scope, args, ctx, &d)).as_slice());
                    arg_count += 1;
                },
                Err(()) => return Err(CompileError { kind: CompileErrorKind::DottedEval })
            }
        }

        if arg_count == 0 {
            Err(CompileError { kind: CompileErrorKind::NullEval })
        } else {
            code.push(Inst::Call(arg_count - 1));
            Ok(code)
        }
    }

    fn compile_block(&mut self, static_scope: &[Vec<CowString<'static>>],
                      args: &[CowString<'static>], body: &RDatum)
            -> Result<(Vec<Inst>, usize), CompileError>
    {
        let mut ctx = CodeGenContext {
            link_size: 0,
        };
        let mut code = Vec::new();
        for expr in body.iter() {
            if let Ok(e) = expr {
                let piece = try!(self.compile_expr(
                        static_scope,
                        args,
                        &mut ctx,
                        &e));
                code.push_all(piece.as_slice());
            } else {
                return Err(CompileError { kind: CompileErrorKind::DottedBody });
            }
        }

        code.push(Inst::Return);

        return Ok((code, ctx.link_size));
    }

    fn compile_expr(&mut self, static_scope: &[Vec<CowString<'static>>], args: &[CowString<'static>],
                    ctx: &mut CodeGenContext, datum: &RDatum)
            -> Result<Vec<Inst>, CompileError>
    {
        match datum {
            &Datum::Cons(ref h, ref t) =>
                if let &Datum::Sym(ref n) = h.borrow().deref() {
                    if let Some(&EnvVar::Syntax(Syntax::Lambda)) = self.global_env.get(n) {
                        if let &Datum::Cons(ref cur_args, ref body) = t.borrow().deref() {
                            let new_scope = {
                                let mut nenv = static_scope.to_vec();
                                nenv.push(args.to_vec());
                                nenv
                            };

                            let new_args = {
                                let mut nargs = Vec::new();
                                for arg in cur_args.borrow().iter() {
                                    if let Ok(Datum::Sym(s)) = arg {
                                        nargs.push(s)
                                    } else {
                                        return Err(CompileError { kind: CompileErrorKind::BadLambdaSyntax });
                                    }
                                }
                                nargs
                            };

                            let (code, link_size) = try!(self.compile_block(
                                    new_scope.as_slice(), new_args.as_slice(), &*body.borrow()
                            ));

                            return Ok(vec![Inst::PushArg(MemRef::Closure(Rc::new(code), link_size))]);
                        } else {
                            return Err(CompileError { kind: CompileErrorKind::BadLambdaSyntax })
                        }
                    } else {
                        self.compile_call(static_scope, args, ctx, datum)
                    }
                } else {
                    self.compile_call(static_scope, args, ctx, datum)
                },
            &Datum::Nil => Err(CompileError { kind: CompileErrorKind::NullEval }),
            &Datum::Sym(ref sym) => {
                if let Some(i) = range(0, args.len()).find(|&i| args[i] == *sym) {
                    return Ok(vec![Inst::PushArg(MemRef::Arg(i))])
                }

                // (0, static_scope[-1]), (1, static_scope[-2]), (2, static_scope[-3]), ...
                for (i, up_args) in static_scope.iter().rev().enumerate() {
                    for (j, arg) in up_args.iter().enumerate() {
                        if *arg == *sym {
                            if ctx.link_size < i+1 {
                                ctx.link_size = i+1;
                            }
                            return Ok(vec![Inst::PushArg(MemRef::UpValue(i, j))]);
                        }
                    }
                }

                match self.global_env.get(sym) {
                    Some(data) => match data {
                        &EnvVar::Syntax(_) =>
                            Err(CompileError { kind: CompileErrorKind::SyntaxReference }),
                        &EnvVar::PrimFunc(ref name, ref func) =>
                            Ok(vec![Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc(name.clone(), func.clone()))))]),
                        &EnvVar::Procedure(ref code) =>
                            Ok(vec![Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::Closure(Closure::new(code.clone(), None)))))]),
                    },
                    None =>
                        Err(CompileError { kind: CompileErrorKind::UnboundVariable })
                }
            },
            _ => Ok(vec![Inst::PushArg(MemRef::Const(datum.clone()))])
        }
    }
}

impl fmt::Show for Syntax {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "lambda")
    }
}

#[cfg(test)]
mod test {
    use std::borrow::Cow;
    use std::rc::Rc;
    use datum::Datum;
    use runtime::{Inst, MemRef, RuntimeData};
    use base::libbase;
    use primitive::PRIM_ADD;
    use super::Compiler;

    #[test]
    fn test_simple_expr() {
        let env = libbase();
        let mut compiler = Compiler::new(&env);
        let expected = Ok(vec![
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::Const(Datum::Num(1))),
            Inst::PushArg(MemRef::Const(Datum::Num(2))),
            Inst::Call(2),
            Inst::Return
        ]);
        let code = compiler.compile(&list![sym!("+"), num!(1), num!(2)]);
        assert_eq!(expected, code);
    }

    #[test]
    fn test_nested_expr() {
        let env = libbase();
        let mut compiler = Compiler::new(&env);
        let expected = Ok(vec![
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::Const(Datum::Num(3))),
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::Const(Datum::Num(1))),
            Inst::PushArg(MemRef::Const(Datum::Num(2))),
            Inst::Call(2),
            Inst::Call(2),
            Inst::Return
        ]);
        let code = compiler.compile(&list![sym!("+"), num!(3), list![sym!("+"), num!(1), num!(2)]]);
        assert_eq!(expected, code);
    }

    #[test]
    fn test_lambda() {
        let env = libbase();
        let mut compiler = Compiler::new(&env);

        let f = vec![
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::Arg(0)),
            Inst::PushArg(MemRef::Const(Datum::Num(2))),
            Inst::Call(2),
            Inst::Return
        ];
        let expected = Ok(vec![
            Inst::PushArg(MemRef::Closure(Rc::new(f), 0)),
            Inst::PushArg(MemRef::Const(Datum::Num(1))),
            Inst::Call(1),
            Inst::Return
        ]);
        let code = compiler.compile(&list![
                           list![sym!("lambda"), list![sym!("x")],
                                list![sym!("+"), sym!("x"), num!(2)]],
                            num!(1)]);
        assert_eq!(expected, code);
    }

    #[test]
    fn test_upvalue() {
        let env = libbase();
        let mut compiler = Compiler::new(&env);

        let f = vec![
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::UpValue(0, 0)),
            Inst::PushArg(MemRef::Arg(0)),
            Inst::Call(2),
            Inst::Return
        ];
        let g = vec![
            Inst::PushArg(MemRef::Closure(Rc::new(f), 1)),
            Inst::Return
        ];
        let expected = Ok(vec![
            Inst::PushArg(MemRef::Closure(Rc::new(g), 0)),
            Inst::PushArg(MemRef::Const(Datum::Num(2))),
            Inst::Call(1),
            Inst::PushArg(MemRef::Const(Datum::Num(3))),
            Inst::Call(1),
            Inst::Return
        ]);

        // ((
        //   (lambda (x)            # = g
        //     (lambda (y) (+ x y)) # = f
        //   ) 2) 3)
        let code = compiler.compile(&list![
            list![
                list![sym!("lambda"), list![sym!("x")],
                    list![sym!("lambda"), list![sym!("y")],
                        list![sym!("+"), sym!("x"), sym!("y")]]],
                num!(2)],
            num!(3)
        ]);
        assert_eq!(expected, code)
    }
}
<commit_msg>Move codegen into CodeGenContext<commit_after>use std::string::CowString;
use std::fmt;
use std::collections::HashMap;
use std::rc::Rc;
use std::ops::Deref;

use error::{CompileError, CompileErrorKind, RuntimeError};
use datum::Datum;
use runtime::{Inst, MemRef, RDatum, RuntimeData, Closure};

/// Syntax variables
#[derive(Copy, Clone, PartialEq)]
pub enum Syntax {
    /// `lambda` syntax
    Lambda
}

/// Environment variables in the global environment
pub enum EnvVar {
    /// Syntax variables
    Syntax(Syntax),

    /// Primitive functions
    PrimFunc(&'static str, Rc<fn(&[RDatum]) -> Result<RDatum, RuntimeError>>),

    /// Compiled library functions
    Procedure(Rc<Vec<Inst>>)
}

/// Compiler compiles Datum into a bytecode evaluates it
pub struct Compiler<'g> {
    /// Global environment
    global_env: &'g HashMap<CowString<'static>, EnvVar>
}

struct CodeGenContext {
    code: Vec<Inst>,
    link_size: usize
}

impl<'g> Compiler<'g> {
    /// Creates a new compiler with given environment
    pub fn new<'a>(global_env: &'a HashMap<CowString<'static>, EnvVar>) -> Compiler<'a> {
        Compiler {
            global_env: global_env
        }
    }

    /// Compiles the datum into a bytecode evaluates it
    pub fn compile(&mut self, datum: &RDatum) -> Result<Vec<Inst>, CompileError> {
        let mut ctx = CodeGenContext {
            code: Vec::new(),
            link_size: 0
        };
        try!(self.compile_expr(&[], &[], &mut ctx, datum));
        ctx.code.push(Inst::Return);
        return Ok(ctx.code);
    }

    fn compile_call(&mut self, static_scope: &[Vec<CowString<'static>>], args: &[CowString<'static>],
                    ctx: &mut CodeGenContext, datum: &RDatum)
            -> Result<(), CompileError>
    {
        let mut arg_count = 0;
        for d in datum.iter() {
            match d {
                Ok(d) => {
                    try!(self.compile_expr(static_scope, args, ctx, &d));
                    arg_count += 1;
                },
                Err(()) => return Err(CompileError { kind: CompileErrorKind::DottedEval })
            }
        }

        if arg_count == 0 {
            Err(CompileError { kind: CompileErrorKind::NullEval })
        } else {
            ctx.code.push(Inst::Call(arg_count - 1));
            Ok(())
        }
    }

    fn compile_block(&mut self, static_scope: &[Vec<CowString<'static>>],
                      args: &[CowString<'static>], body: &RDatum)
            -> Result<CodeGenContext, CompileError>
    {
        let mut ctx = CodeGenContext {
            code: Vec::new(),
            link_size: 0
        };
        for expr in body.iter() {
            if let Ok(e) = expr {
                try!(self.compile_expr(static_scope, args, &mut ctx, &e));
            } else {
                return Err(CompileError { kind: CompileErrorKind::DottedBody });
            }
        }

        ctx.code.push(Inst::Return);

        return Ok(ctx);
    }

    fn compile_expr(&mut self, static_scope: &[Vec<CowString<'static>>], args: &[CowString<'static>],
                    ctx: &mut CodeGenContext, datum: &RDatum)
            -> Result<(), CompileError>
    {
        match datum {
            &Datum::Cons(ref h, ref t) =>
                if let &Datum::Sym(ref n) = h.borrow().deref() {
                    if let Some(&EnvVar::Syntax(Syntax::Lambda)) = self.global_env.get(n) {
                        if let &Datum::Cons(ref cur_args, ref body) = t.borrow().deref() {
                            let new_scope = {
                                let mut nenv = static_scope.to_vec();
                                nenv.push(args.to_vec());
                                nenv
                            };

                            let new_args = {
                                let mut nargs = Vec::new();
                                for arg in cur_args.borrow().iter() {
                                    if let Ok(Datum::Sym(s)) = arg {
                                        nargs.push(s)
                                    } else {
                                        return Err(CompileError { kind: CompileErrorKind::BadLambdaSyntax });
                                    }
                                }
                                nargs
                            };

                            let block_ctx = try!(self.compile_block(
                                    new_scope.as_slice(), new_args.as_slice(), &*body.borrow()
                            ));

                            ctx.code.push(Inst::PushArg(MemRef::Closure(
                                        Rc::new(block_ctx.code),
                                        block_ctx.link_size
                            )));
                            return Ok(());
                        } else {
                            return Err(CompileError { kind: CompileErrorKind::BadLambdaSyntax })
                        }
                    } else {
                        self.compile_call(static_scope, args, ctx, datum)
                    }
                } else {
                    self.compile_call(static_scope, args, ctx, datum)
                },
            &Datum::Nil => Err(CompileError { kind: CompileErrorKind::NullEval }),
            &Datum::Sym(ref sym) => {
                if let Some(i) = range(0, args.len()).find(|&i| args[i] == *sym) {
                    ctx.code.push(Inst::PushArg(MemRef::Arg(i)));
                    return Ok(());
                }

                // (0, static_scope[-1]), (1, static_scope[-2]), (2, static_scope[-3]), ...
                for (i, up_args) in static_scope.iter().rev().enumerate() {
                    for (j, arg) in up_args.iter().enumerate() {
                        if *arg == *sym {
                            if ctx.link_size < i+1 {
                                ctx.link_size = i+1;
                            }
                            ctx.code.push(Inst::PushArg(MemRef::UpValue(i, j)));
                            return Ok(());
                        }
                    }
                }

                match self.global_env.get(sym) {
                    Some(data) => match data {
                        &EnvVar::Syntax(_) =>
                            Err(CompileError { kind: CompileErrorKind::SyntaxReference }),
                        &EnvVar::PrimFunc(ref name, ref func) => {
                            ctx.code.push(Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc(
                                                name.clone(),
                                                func.clone()
                            )))));
                            Ok(())
                        },
                        &EnvVar::Procedure(ref code) => {
                            ctx.code.push(Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::Closure(Closure::new(
                                                code.clone(),
                                                None
                            ))))));
                            Ok(())
                        }
                    },
                    None =>
                        Err(CompileError { kind: CompileErrorKind::UnboundVariable })
                }
            },
            _ => {
                ctx.code.push(Inst::PushArg(MemRef::Const(datum.clone())));
                Ok(())
            }
        }
    }
}

impl fmt::Show for Syntax {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "lambda")
    }
}

#[cfg(test)]
mod test {
    use std::borrow::Cow;
    use std::rc::Rc;
    use datum::Datum;
    use runtime::{Inst, MemRef, RuntimeData};
    use base::libbase;
    use primitive::PRIM_ADD;
    use super::Compiler;

    #[test]
    fn test_simple_expr() {
        let env = libbase();
        let mut compiler = Compiler::new(&env);
        let expected = Ok(vec![
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::Const(Datum::Num(1))),
            Inst::PushArg(MemRef::Const(Datum::Num(2))),
            Inst::Call(2),
            Inst::Return
        ]);
        let code = compiler.compile(&list![sym!("+"), num!(1), num!(2)]);
        assert_eq!(expected, code);
    }

    #[test]
    fn test_nested_expr() {
        let env = libbase();
        let mut compiler = Compiler::new(&env);
        let expected = Ok(vec![
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::Const(Datum::Num(3))),
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::Const(Datum::Num(1))),
            Inst::PushArg(MemRef::Const(Datum::Num(2))),
            Inst::Call(2),
            Inst::Call(2),
            Inst::Return
        ]);
        let code = compiler.compile(&list![sym!("+"), num!(3), list![sym!("+"), num!(1), num!(2)]]);
        assert_eq!(expected, code);
    }

    #[test]
    fn test_lambda() {
        let env = libbase();
        let mut compiler = Compiler::new(&env);

        let f = vec![
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::Arg(0)),
            Inst::PushArg(MemRef::Const(Datum::Num(2))),
            Inst::Call(2),
            Inst::Return
        ];
        let expected = Ok(vec![
            Inst::PushArg(MemRef::Closure(Rc::new(f), 0)),
            Inst::PushArg(MemRef::Const(Datum::Num(1))),
            Inst::Call(1),
            Inst::Return
        ]);
        let code = compiler.compile(&list![
                           list![sym!("lambda"), list![sym!("x")],
                                list![sym!("+"), sym!("x"), num!(2)]],
                            num!(1)]);
        assert_eq!(expected, code);
    }

    #[test]
    fn test_upvalue() {
        let env = libbase();
        let mut compiler = Compiler::new(&env);

        let f = vec![
            Inst::PushArg(MemRef::Const(Datum::Ext(RuntimeData::PrimFunc("+", Rc::new(PRIM_ADD))))),
            Inst::PushArg(MemRef::UpValue(0, 0)),
            Inst::PushArg(MemRef::Arg(0)),
            Inst::Call(2),
            Inst::Return
        ];
        let g = vec![
            Inst::PushArg(MemRef::Closure(Rc::new(f), 1)),
            Inst::Return
        ];
        let expected = Ok(vec![
            Inst::PushArg(MemRef::Closure(Rc::new(g), 0)),
            Inst::PushArg(MemRef::Const(Datum::Num(2))),
            Inst::Call(1),
            Inst::PushArg(MemRef::Const(Datum::Num(3))),
            Inst::Call(1),
            Inst::Return
        ]);

        // ((
        //   (lambda (x)            # = g
        //     (lambda (y) (+ x y)) # = f
        //   ) 2) 3)
        let code = compiler.compile(&list![
            list![
                list![sym!("lambda"), list![sym!("x")],
                    list![sym!("lambda"), list![sym!("y")],
                        list![sym!("+"), sym!("x"), sym!("y")]]],
                num!(2)],
            num!(3)
        ]);
        assert_eq!(expected, code)
    }
}
<|endoftext|>


<commit_before>use self::Kind::*;

use std::error;
use std::fmt;

/// Errors encountered by the timer implementation.
#[derive(Debug)]
pub struct Error(Kind);

#[derive(Debug)]
enum Kind {
    Shutdown,
    AtCapacity,
}

impl Error {
    /// Create an error representing a shutdown timer.
    pub fn shutdown() -> Error {
        Error(Shutdown)
    }

    /// Returns `true` if the error was caused by the timer being shutdown.
    pub fn is_shutdown(&self) -> bool {
        match self.0 {
            Kind::Shutdown => true,
            _ => false,
        }
    }

    /// Create an error representing a timer at capacity.
    pub fn at_capacity() -> Error {
        Error(AtCapacity)
    }

    /// Returns `true` if the error was caused by the timer being at capacity.
    pub fn is_at_capacity(&self) -> bool {
        match self.0 {
            Kind::AtCapacity => true,
            _ => false,
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Kind::*;

        match self.0 {
            Shutdown => "timer is shutdown",
            AtCapacity => "timer is at capacity and cannot create a new entry",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        self.description().fmt(fmt)
    }
}
<commit_msg>Add additional timer::Error docs. (#311)<commit_after>use self::Kind::*;

use std::error;
use std::fmt;

/// Errors encountered by the timer implementation.
///
/// Currently, there are two different errors that can occur:
///
/// * `shutdown` occurs when a timer operation is attempted, but the timer
///   instance has been dropped. In this case, the operation will never be able
///   to complete and the `shutdown` error is returned. This is a permanent
///   error, i.e., once this error is observed, timer operations will never
///   succeed in the future.
///
/// * `at_capacity` occurs when a timer operation is attempted, but the timer
///   instance is currently handling its maximum number of outstanding delays.
///   In this case, the operation is not able to be performed at the current
///   moment, and `at_capacity` is returned. This is a transient error, i.e., at
///   some point in the future, if the operation is attempted again, it might
///   succeed. Callers that observe this error should attempt to [shed load]. One
///   way to do this would be dropping the future that issued the timer operation.
///
/// [shed load]: https://en.wikipedia.org/wiki/Load_Shedding
#[derive(Debug)]
pub struct Error(Kind);

#[derive(Debug)]
enum Kind {
    Shutdown,
    AtCapacity,
}

impl Error {
    /// Create an error representing a shutdown timer.
    pub fn shutdown() -> Error {
        Error(Shutdown)
    }

    /// Returns `true` if the error was caused by the timer being shutdown.
    pub fn is_shutdown(&self) -> bool {
        match self.0 {
            Kind::Shutdown => true,
            _ => false,
        }
    }

    /// Create an error representing a timer at capacity.
    pub fn at_capacity() -> Error {
        Error(AtCapacity)
    }

    /// Returns `true` if the error was caused by the timer being at capacity.
    pub fn is_at_capacity(&self) -> bool {
        match self.0 {
            Kind::AtCapacity => true,
            _ => false,
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Kind::*;

        match self.0 {
            Shutdown => "timer is shutdown",
            AtCapacity => "timer is at capacity and cannot create a new entry",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        self.description().fmt(fmt)
    }
}
<|endoftext|>


<commit_before>//! This iterator emits `BlockPositions` in cube-shaped layers outward around a point.

use cube_shell::cube_shell;
use std::collections::RingBuf;
use block_position::BlockPosition;

#[cfg(test)]
use std::iter::range_inclusive;
#[cfg(test)]
use cube_shell::cube_shell_area;
#[cfg(test)]
use surroundings_loader::radius_between;

/// This iterator emits `BlockPositions` in cube-shaped layers outward around a point.
pub struct SurroundingsIter {
  center: BlockPosition,
  next_distance: i32,
  max_distance: i32,
  to_load_buffer: RingBuf<BlockPosition>,
}

impl SurroundingsIter {
  #[allow(missing_docs)]
  pub fn new(center: BlockPosition, max_distance: i32) -> SurroundingsIter {
    let mut to_load_buffer = RingBuf::new();
    to_load_buffer.push_back(center);

    SurroundingsIter {
      center: center,
      next_distance: 0,
      max_distance: max_distance,
      to_load_buffer: to_load_buffer,
    }
  }
}

impl Iterator for SurroundingsIter {
  type Item = (BlockPosition, i32);

  #[inline]
  fn next(&mut self) -> Option<(BlockPosition, i32)> {
    let distance = self.next_distance;
    self.to_load_buffer.pop_front().map(|x| {
      if self.to_load_buffer.is_empty() {
        debug!("Done loading surroundings at distance {}", self.next_distance);
        if self.next_distance < self.max_distance {
          self.next_distance += 1;
          self.to_load_buffer.extend(
            cube_shell(&self.center, self.next_distance).into_iter()
          );
        } else {
          info!("Done loading surroundings");
        }
      }
      (x, distance)
    })
  }
}

#[test]
fn shell_ordering() {
  let center = BlockPosition::new(-1, 2, 3);
  let max_distance = 4;
  let mut iter = SurroundingsIter::new(center, max_distance);

  for distance in range_inclusive(0, max_distance) {
    for _ in range(0, cube_shell_area(distance)) {
      let block_posn = iter.next().unwrap();
      assert_eq!(radius_between(&center, &block_posn), distance);
    }
  }

  assert!(iter.next().is_none());
}
<commit_msg>Fix "common" tests again.<commit_after>//! This iterator emits `BlockPositions` in cube-shaped layers outward around a point.

use cube_shell::cube_shell;
use std::collections::RingBuf;
use block_position::BlockPosition;

#[cfg(test)]
use std::iter::range_inclusive;
#[cfg(test)]
use cube_shell::cube_shell_area;
#[cfg(test)]
use surroundings_loader::radius_between;

/// This iterator emits `BlockPositions` in cube-shaped layers outward around a point.
pub struct SurroundingsIter {
  center: BlockPosition,
  next_distance: i32,
  max_distance: i32,
  to_load_buffer: RingBuf<BlockPosition>,
}

impl SurroundingsIter {
  #[allow(missing_docs)]
  pub fn new(center: BlockPosition, max_distance: i32) -> SurroundingsIter {
    let mut to_load_buffer = RingBuf::new();
    to_load_buffer.push_back(center);

    SurroundingsIter {
      center: center,
      next_distance: 0,
      max_distance: max_distance,
      to_load_buffer: to_load_buffer,
    }
  }
}

impl Iterator for SurroundingsIter {
  type Item = (BlockPosition, i32);

  #[inline]
  fn next(&mut self) -> Option<(BlockPosition, i32)> {
    let distance = self.next_distance;
    self.to_load_buffer.pop_front().map(|x| {
      if self.to_load_buffer.is_empty() {
        debug!("Done loading surroundings at distance {}", self.next_distance);
        if self.next_distance < self.max_distance {
          self.next_distance += 1;
          self.to_load_buffer.extend(
            cube_shell(&self.center, self.next_distance).into_iter()
          );
        } else {
          info!("Done loading surroundings");
        }
      }
      (x, distance)
    })
  }
}

#[test]
fn shell_ordering() {
  let center = BlockPosition::new(-1, 2, 3);
  let max_distance = 4;
  let mut iter = SurroundingsIter::new(center, max_distance);

  for distance in range_inclusive(0, max_distance) {
    for _ in range(0, cube_shell_area(distance)) {
      let (block_posn, d) = iter.next().unwrap();
      assert_eq!(d, distance);
      assert_eq!(radius_between(&center, &block_posn), distance);
    }
  }

  assert!(iter.next().is_none());
}
<|endoftext|>


<commit_before>use screen::*;
use piston_window;

pub struct MainMenuScreen;

impl Screen for MainMenuScreen {
    fn on_input(&mut self, input: &piston_window::Input) -> InputResults {
        use piston_window::{Input, Button, Key};

        let mut result = Vec::new();

        match input {
            &Input::Press(_) => {
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new())));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0., 0., 1., 1.0], graphics);
        });
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
    }
}
<commit_msg>TODO comment<commit_after>use screen::*;
use piston_window;

pub struct MainMenuScreen;

impl Screen for MainMenuScreen {
    fn on_input(&mut self, input: &piston_window::Input) -> InputResults {
        // TODO: FIXME:
        use piston_window::{Input, Button, Key};

        let mut result = Vec::new();

        match input {
            &Input::Press(_) => {
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new())));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0., 0., 1., 1.0], graphics);
        });
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
    }
}
<|endoftext|>


<commit_before>extern crate rust_base58;
extern crate sodiumoxide;

use errors::crypto::CryptoError;
use self::rust_base58::{ToBase58, FromBase58};
use self::sodiumoxide::crypto::box_;
use self::sodiumoxide::crypto::secretbox;
use self::sodiumoxide::crypto::sign;
use self::sodiumoxide::randombytes;
use std::convert::AsMut;

pub struct ED25519 {}

impl ED25519 {
    pub fn new() -> ED25519 {
        ED25519 {}
    }

    pub fn sodium_symmetric_create_key(&self) -> Vec<u8> {
        secretbox::gen_key()[..].to_vec()
    }

    pub fn sodium_symmetric_create_nonce(&self) -> Vec<u8> {
        secretbox::gen_nonce()[..].to_vec()
    }

    pub fn sodium_symmetric_encrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Vec<u8> {
        let sodium = ED25519::new();
        secretbox::seal(
            doc,
            &secretbox::Nonce(sodium.clone_into_array(nonce)),
            &secretbox::Key(sodium.clone_into_array(key))
        )
    }

    pub fn sodium_symmetric_decrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Result<Vec<u8>, CryptoError> {
        let sodium = ED25519::new();
        secretbox::open(
            doc,
            &secretbox::Nonce(sodium.clone_into_array(nonce)),
            &secretbox::Key(sodium.clone_into_array(key))
        )
            .map_err(|_| CryptoError::CryptoInvalidStructure("Unable to decrypt data".to_string()))
    }

    pub fn sodium_box_create_key_pair(&self) -> (Vec<u8>, Vec<u8>) {
        let (public_key, private_key) = box_::gen_keypair();
        (public_key[..].to_vec(), private_key[..].to_vec())
    }

    pub fn sodium_encrypt(&self, private_key: &[u8], public_key: &[u8], doc: &[u8], nonce: &[u8]) -> Vec<u8> {
        let sodium = ED25519::new();
        box_::seal(
            doc,
            &box_::Nonce(sodium.clone_into_array(nonce)),
            &box_::PublicKey(sodium.clone_into_array(public_key)),
            &box_::SecretKey(sodium.clone_into_array(private_key))
        )
    }

    pub fn sodium_decrypt(&self, private_key: &[u8], public_key: &[u8], doc: &[u8], nonce: &[u8]) -> Result<Vec<u8>, CryptoError> {
        let sodium = ED25519::new();
        box_::open(
            doc,
            &box_::Nonce(sodium.clone_into_array(nonce)),
            &box_::PublicKey(sodium.clone_into_array(public_key)),
            &box_::SecretKey(sodium.clone_into_array(private_key))
        )
            .map_err(|_| CryptoError::CryptoInvalidStructure("Unable to decrypt data".to_string()))
    }

    pub fn get_nonce(&self) -> Vec<u8> {
        box_::gen_nonce()[..].to_vec()
    }

    pub fn sodium_create_key_pair_for_signature(&self, seed: Option<&[u8]>) -> (Vec<u8>, Vec<u8>) {
        let sodium = ED25519::new();
        let (public_key, private_key) =
            sign::keypair_from_seed(
                &sign::Seed(
                    sodium.clone_into_array(
                        seed.unwrap_or(&randombytes::randombytes(32)[..])
                    )
                )
            );

        (public_key[..].to_vec(), private_key[..].to_vec())
    }

    pub fn sodium_sign(&self, private_key: &[u8], doc: &[u8]) -> Vec<u8> {
        let mut pr_key: [u8; 64] = [0; 64];
        pr_key.clone_from_slice(private_key);

        sign::sign(
            doc,
            &sign::SecretKey(pr_key)
        )
    }

    pub fn sodium_verify(&self, public_key: &[u8], doc: &[u8]) -> Result<Vec<u8>, CryptoError> {
        let sodium = ED25519::new();
        sign::verify(
            doc,
            &sign::PublicKey(sodium.clone_into_array(public_key))
        )
            .map_err(|_| CryptoError::CryptoInvalidStructure("Unable to decrypt data".to_string()))
    }

    pub fn base58_encode(&self, doc: &[u8]) -> String {
        doc.to_base58()
    }

    pub fn base58_decode(&self, doc: &String) -> Result<Vec<u8>, CryptoError> {
        doc.from_base58()
            .map_err(|err| CryptoError::CryptoInvalidStructure(format!("{}", err)))
    }

    fn clone_into_array<A, T>(&self, slice: &[T]) -> A
        where A: Sized + Default + AsMut<[T]>, T: Clone
    {
        let mut a = Default::default();
        <A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
        a
    }
}

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

    #[test]
    fn crypto_service_can_encode_decode_string() {
        let sodium = ED25519::new();
        let data = &[1, 2, 3];

        let encode_result = sodium.base58_encode(&data[..]);
        assert_eq!("Ldp", &encode_result, "Success encrypt data");

        let decrypted_data = sodium.base58_decode(&encode_result);
        assert!(decrypted_data.is_ok(), "Success decrypt data");
        assert_eq!(data, &decrypted_data.unwrap()[..], "Get correct data");
    }

    #[test]
    fn crypto_service_encode_decode_test() {
        let sodium = ED25519::new();
        let (alice_pk, alice_sk) = sodium.sodium_box_create_key_pair();
        let (bob_pk, bob_sk) = sodium.sodium_box_create_key_pair();

        let text = randombytes::randombytes(16);
        let nonce = sodium.get_nonce();

        let bob_encrypted_text = sodium.sodium_encrypt(&bob_sk, &alice_pk, &text[..], &nonce);
        let bob_decrypt_result = sodium.sodium_decrypt(&alice_sk, &bob_pk, &bob_encrypted_text, &nonce);
        assert!(bob_decrypt_result.is_ok());
        assert_eq!(text, bob_decrypt_result.unwrap());

        let alice_encrypted_text = sodium.sodium_encrypt(&alice_sk, &bob_pk, &text[..], &nonce);
        let alice_decrypted_text = sodium.sodium_decrypt(&bob_sk, &alice_pk, &alice_encrypted_text, &nonce);
        assert!(alice_decrypted_text.is_ok());
        assert_eq!(text, alice_decrypted_text.unwrap());
    }

    #[test]
    fn crypto_service_signin_verify_test() {
        let sodium = ED25519::new();
        let seed = randombytes::randombytes(32);

        let (public_key, secret_key) = sodium.sodium_create_key_pair_for_signature(Some(&seed[..]));

        let text = randombytes::randombytes(16);

        let alice_signed_text = sodium.sodium_sign(&secret_key, &text[..]);

        let verified_data = sodium.sodium_verify(&public_key, &alice_signed_text);
        assert!(verified_data.is_ok());

        assert_eq!(text, verified_data.unwrap());
    }
}<commit_msg>removed prefix<commit_after>extern crate rust_base58;
extern crate sodiumoxide;

use errors::crypto::CryptoError;
use self::rust_base58::{ToBase58, FromBase58};
use self::sodiumoxide::crypto::box_;
use self::sodiumoxide::crypto::secretbox;
use self::sodiumoxide::crypto::sign;
use self::sodiumoxide::randombytes;
use std::convert::AsMut;

pub struct ED25519 {}

impl ED25519 {
    pub fn new() -> ED25519 {
        ED25519 {}
    }

    pub fn symmetric_create_key(&self) -> Vec<u8> {
        secretbox::gen_key()[..].to_vec()
    }

    pub fn symmetric_create_nonce(&self) -> Vec<u8> {
        secretbox::gen_nonce()[..].to_vec()
    }

    pub fn symmetric_encrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Vec<u8> {
        let sodium = ED25519::new();
        secretbox::seal(
            doc,
            &secretbox::Nonce(sodium.clone_into_array(nonce)),
            &secretbox::Key(sodium.clone_into_array(key))
        )
    }

    pub fn symmetric_decrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Result<Vec<u8>, CryptoError> {
        let sodium = ED25519::new();
        secretbox::open(
            doc,
            &secretbox::Nonce(sodium.clone_into_array(nonce)),
            &secretbox::Key(sodium.clone_into_array(key))
        )
            .map_err(|_| CryptoError::CryptoInvalidStructure("Unable to decrypt data".to_string()))
    }

    pub fn box_create_key_pair(&self) -> (Vec<u8>, Vec<u8>) {
        let (public_key, private_key) = box_::gen_keypair();
        (public_key[..].to_vec(), private_key[..].to_vec())
    }

    pub fn encrypt(&self, private_key: &[u8], public_key: &[u8], doc: &[u8], nonce: &[u8]) -> Vec<u8> {
        let sodium = ED25519::new();
        box_::seal(
            doc,
            &box_::Nonce(sodium.clone_into_array(nonce)),
            &box_::PublicKey(sodium.clone_into_array(public_key)),
            &box_::SecretKey(sodium.clone_into_array(private_key))
        )
    }

    pub fn decrypt(&self, private_key: &[u8], public_key: &[u8], doc: &[u8], nonce: &[u8]) -> Result<Vec<u8>, CryptoError> {
        let sodium = ED25519::new();
        box_::open(
            doc,
            &box_::Nonce(sodium.clone_into_array(nonce)),
            &box_::PublicKey(sodium.clone_into_array(public_key)),
            &box_::SecretKey(sodium.clone_into_array(private_key))
        )
            .map_err(|_| CryptoError::CryptoInvalidStructure("Unable to decrypt data".to_string()))
    }

    pub fn get_nonce(&self) -> Vec<u8> {
        box_::gen_nonce()[..].to_vec()
    }

    pub fn create_key_pair_for_signature(&self, seed: Option<&[u8]>) -> (Vec<u8>, Vec<u8>) {
        let sodium = ED25519::new();
        let (public_key, private_key) =
            sign::keypair_from_seed(
                &sign::Seed(
                    sodium.clone_into_array(
                        seed.unwrap_or(&randombytes::randombytes(32)[..])
                    )
                )
            );

        (public_key[..].to_vec(), private_key[..].to_vec())
    }

    pub fn sign(&self, private_key: &[u8], doc: &[u8]) -> Vec<u8> {
        let mut pr_key: [u8; 64] = [0; 64];
        pr_key.clone_from_slice(private_key);

        sign::sign(
            doc,
            &sign::SecretKey(pr_key)
        )
    }

    pub fn verify(&self, public_key: &[u8], doc: &[u8]) -> Result<Vec<u8>, CryptoError> {
        let sodium = ED25519::new();
        sign::verify(
            doc,
            &sign::PublicKey(sodium.clone_into_array(public_key))
        )
            .map_err(|_| CryptoError::CryptoInvalidStructure("Unable to decrypt data".to_string()))
    }

    pub fn base58_encode(&self, doc: &[u8]) -> String {
        doc.to_base58()
    }

    pub fn base58_decode(&self, doc: &String) -> Result<Vec<u8>, CryptoError> {
        doc.from_base58()
            .map_err(|err| CryptoError::CryptoInvalidStructure(format!("{}", err)))
    }

    fn clone_into_array<A, T>(&self, slice: &[T]) -> A
        where A: Sized + Default + AsMut<[T]>, T: Clone
    {
        let mut a = Default::default();
        <A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
        a
    }
}

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

    #[test]
    fn crypto_service_can_encode_decode_string() {
        let sodium = ED25519::new();
        let data = &[1, 2, 3];

        let encode_result = sodium.base58_encode(&data[..]);
        assert_eq!("Ldp", &encode_result, "Success encrypt data");

        let decrypted_data = sodium.base58_decode(&encode_result);
        assert!(decrypted_data.is_ok(), "Success decrypt data");
        assert_eq!(data, &decrypted_data.unwrap()[..], "Get correct data");
    }

    #[test]
    fn crypto_service_encode_decode_test() {
        let sodium = ED25519::new();
        let (alice_pk, alice_sk) = sodium.box_create_key_pair();
        let (bob_pk, bob_sk) = sodium.box_create_key_pair();

        let text = randombytes::randombytes(16);
        let nonce = sodium.get_nonce();

        let bob_encrypted_text = sodium.encrypt(&bob_sk, &alice_pk, &text[..], &nonce);
        let bob_decrypt_result = sodium.decrypt(&alice_sk, &bob_pk, &bob_encrypted_text, &nonce);
        assert!(bob_decrypt_result.is_ok());
        assert_eq!(text, bob_decrypt_result.unwrap());

        let alice_encrypted_text = sodium.encrypt(&alice_sk, &bob_pk, &text[..], &nonce);
        let alice_decrypted_text = sodium.decrypt(&bob_sk, &alice_pk, &alice_encrypted_text, &nonce);
        assert!(alice_decrypted_text.is_ok());
        assert_eq!(text, alice_decrypted_text.unwrap());
    }

    #[test]
    fn crypto_service_signin_verify_test() {
        let sodium = ED25519::new();
        let seed = randombytes::randombytes(32);

        let (public_key, secret_key) = sodium.create_key_pair_for_signature(Some(&seed[..]));

        let text = randombytes::randombytes(16);

        let alice_signed_text = sodium.sign(&secret_key, &text[..]);

        let verified_data = sodium.verify(&public_key, &alice_signed_text);
        assert!(verified_data.is_ok());

        assert_eq!(text, verified_data.unwrap());
    }
}<|endoftext|>


<commit_before>//! ARMv6K Nintendo 3DS C Newlib definitions

pub type c_char = u8;
pub type c_long = i32;
pub type c_ulong = u32;

pub type wchar_t = ::c_uint;

pub type in_port_t = ::c_ushort;
pub type u_register_t = ::c_uint;
pub type u_char = ::c_uchar;
pub type u_short = ::c_ushort;
pub type u_int = ::c_uint;
pub type u_long = c_ulong;
pub type ushort = ::c_ushort;
pub type uint = ::c_uint;
pub type ulong = c_ulong;
pub type clock_t = c_ulong;
pub type daddr_t = c_long;
pub type caddr_t = *mut c_char;
pub type sbintime_t = ::c_longlong;

// External implementations are needed to use networking and threading.
s! {
    pub struct sockaddr {
        pub sa_family: ::sa_family_t,
        pub sa_data: [::c_char; 26usize],
    }

    pub struct sockaddr_storage {
        pub ss_family: ::sa_family_t,
        pub __ss_padding: [::c_char; 26usize],
    }

    pub struct sockaddr_in {
        pub sin_family: ::sa_family_t,
        pub sin_port: in_port_t,
        pub sin_addr: ::in_addr,
    }

    pub struct sockaddr_in6 {
        pub sin6_family: ::sa_family_t,
        pub sin6_port: ::in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }

    pub struct sockaddr_un {
        pub sun_len: ::c_uchar,
        pub sun_family: ::sa_family_t,
        pub sun_path: [::c_char; 104usize],
    }

    pub struct sched_param {
        pub sched_priority: ::c_int,
    }
}

pub const SIGEV_NONE: ::c_int = 1;
pub const SIGEV_SIGNAL: ::c_int = 2;
pub const SIGEV_THREAD: ::c_int = 3;
pub const SA_NOCLDSTOP: ::c_int = 1;
pub const MINSIGSTKSZ: ::c_int = 2048;
pub const SIGSTKSZ: ::c_int = 8192;
pub const SS_ONSTACK: ::c_int = 1;
pub const SS_DISABLE: ::c_int = 2;
pub const SIG_SETMASK: ::c_int = 0;
pub const SIG_BLOCK: ::c_int = 1;
pub const SIG_UNBLOCK: ::c_int = 2;
pub const SIGHUP: ::c_int = 1;
pub const SIGINT: ::c_int = 2;
pub const SIGQUIT: ::c_int = 3;
pub const SIGILL: ::c_int = 4;
pub const SIGTRAP: ::c_int = 5;
pub const SIGABRT: ::c_int = 6;
pub const SIGEMT: ::c_int = 7;
pub const SIGFPE: ::c_int = 8;
pub const SIGKILL: ::c_int = 9;
pub const SIGBUS: ::c_int = 10;
pub const SIGSEGV: ::c_int = 11;
pub const SIGSYS: ::c_int = 12;
pub const SIGPIPE: ::c_int = 13;
pub const SIGALRM: ::c_int = 14;
pub const SIGTERM: ::c_int = 15;
pub const SIGURG: ::c_int = 16;
pub const SIGSTOP: ::c_int = 17;
pub const SIGTSTP: ::c_int = 18;
pub const SIGCONT: ::c_int = 19;
pub const SIGCHLD: ::c_int = 20;
pub const SIGCLD: ::c_int = 20;
pub const SIGTTIN: ::c_int = 21;
pub const SIGTTOU: ::c_int = 22;
pub const SIGIO: ::c_int = 23;
pub const SIGPOLL: ::c_int = 23;
pub const SIGXCPU: ::c_int = 24;
pub const SIGXFSZ: ::c_int = 25;
pub const SIGVTALRM: ::c_int = 26;
pub const SIGPROF: ::c_int = 27;
pub const SIGWINCH: ::c_int = 28;
pub const SIGLOST: ::c_int = 29;
pub const SIGUSR1: ::c_int = 30;
pub const SIGUSR2: ::c_int = 31;
pub const NSIG: ::c_int = 32;
pub const CLOCK_ENABLED: ::c_uint = 1;
pub const CLOCK_DISABLED: ::c_uint = 0;
pub const CLOCK_ALLOWED: ::c_uint = 1;
pub const CLOCK_DISALLOWED: ::c_uint = 0;
pub const TIMER_ABSTIME: ::c_uint = 4;
pub const SOL_SOCKET: ::c_int = 65535;
pub const MSG_OOB: ::c_int = 1;
pub const MSG_PEEK: ::c_int = 2;
pub const MSG_DONTWAIT: ::c_int = 4;
pub const MSG_DONTROUTE: ::c_int = 0;
pub const MSG_WAITALL: ::c_int = 0;
pub const MSG_MORE: ::c_int = 0;
pub const MSG_NOSIGNAL: ::c_int = 0;
pub const SOL_CONFIG: ::c_uint = 65534;

pub const _SC_PAGESIZE: ::c_int = 8;
pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 51;

pub const PTHREAD_STACK_MIN: ::size_t = 4096;
pub const WNOHANG: ::c_int = 1;

pub const POLLIN: ::c_short = 0x0001;
pub const POLLPRI: ::c_short = 0x0002;
pub const POLLOUT: ::c_short = 0x0004;
pub const POLLRDNORM: ::c_short = 0x0040;
pub const POLLWRNORM: ::c_short = POLLOUT;
pub const POLLRDBAND: ::c_short = 0x0080;
pub const POLLWRBAND: ::c_short = 0x0100;
pub const POLLERR: ::c_short = 0x0008;
pub const POLLHUP: ::c_short = 0x0010;
pub const POLLNVAL: ::c_short = 0x0020;

pub const EAI_AGAIN: ::c_int = 2;
pub const EAI_BADFLAGS: ::c_int = 3;
pub const EAI_FAIL: ::c_int = 4;
pub const EAI_SERVICE: ::c_int = 9;
pub const EAI_SYSTEM: ::c_int = 11;
pub const EAI_BADHINTS: ::c_int = 12;
pub const EAI_PROTOCOL: ::c_int = 13;
pub const EAI_OVERFLOW: ::c_int = 14;
pub const EAI_MAX: ::c_int = 15;

pub const AF_UNIX: ::c_int = 1;
pub const AF_INET6: ::c_int = 23;

pub const FIONBIO: ::c_ulong = 1;

pub const RTLD_DEFAULT: *mut ::c_void = 0 as *mut ::c_void;

// Horizon OS works doesn't or can't hold any of this information
safe_f! {
    pub {const} fn WIFSTOPPED(_status: ::c_int) -> bool {
        false
    }

    pub {const} fn WSTOPSIG(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WIFCONTINUED(_status: ::c_int) -> bool {
        true
    }

    pub {const} fn WIFSIGNALED(_status: ::c_int) -> bool {
        false
    }

    pub {const} fn WTERMSIG(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WIFEXITED(_status: ::c_int) -> bool {
        true
    }

    pub {const} fn WEXITSTATUS(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WCOREDUMP(_status: ::c_int) -> bool {
        false
    }
}

extern "C" {
    pub fn pthread_create(
        native: *mut ::pthread_t,
        attr: *const ::pthread_attr_t,
        f: extern "C" fn(_: *mut ::c_void) -> *mut ::c_void,
        value: *mut ::c_void,
    ) -> ::c_int;

    pub fn pthread_attr_getschedparam(
        attr: *const ::pthread_attr_t,
        param: *mut sched_param,
    ) -> ::c_int;

    pub fn pthread_attr_setschedparam(
        attr: *mut ::pthread_attr_t,
        param: *const sched_param,
    ) -> ::c_int;

    pub fn pthread_attr_setaffinity(attr: *mut ::pthread_attr_t, affinity: ::c_int) -> ::c_int;

    pub fn pthread_getpriority() -> ::c_int;

    pub fn gethostid() -> ::c_long;
}
<commit_msg>Change wording to "ideal processor" and use "np" suffix<commit_after>//! ARMv6K Nintendo 3DS C Newlib definitions

pub type c_char = u8;
pub type c_long = i32;
pub type c_ulong = u32;

pub type wchar_t = ::c_uint;

pub type in_port_t = ::c_ushort;
pub type u_register_t = ::c_uint;
pub type u_char = ::c_uchar;
pub type u_short = ::c_ushort;
pub type u_int = ::c_uint;
pub type u_long = c_ulong;
pub type ushort = ::c_ushort;
pub type uint = ::c_uint;
pub type ulong = c_ulong;
pub type clock_t = c_ulong;
pub type daddr_t = c_long;
pub type caddr_t = *mut c_char;
pub type sbintime_t = ::c_longlong;

// External implementations are needed to use networking and threading.
s! {
    pub struct sockaddr {
        pub sa_family: ::sa_family_t,
        pub sa_data: [::c_char; 26usize],
    }

    pub struct sockaddr_storage {
        pub ss_family: ::sa_family_t,
        pub __ss_padding: [::c_char; 26usize],
    }

    pub struct sockaddr_in {
        pub sin_family: ::sa_family_t,
        pub sin_port: in_port_t,
        pub sin_addr: ::in_addr,
    }

    pub struct sockaddr_in6 {
        pub sin6_family: ::sa_family_t,
        pub sin6_port: ::in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }

    pub struct sockaddr_un {
        pub sun_len: ::c_uchar,
        pub sun_family: ::sa_family_t,
        pub sun_path: [::c_char; 104usize],
    }

    pub struct sched_param {
        pub sched_priority: ::c_int,
    }
}

pub const SIGEV_NONE: ::c_int = 1;
pub const SIGEV_SIGNAL: ::c_int = 2;
pub const SIGEV_THREAD: ::c_int = 3;
pub const SA_NOCLDSTOP: ::c_int = 1;
pub const MINSIGSTKSZ: ::c_int = 2048;
pub const SIGSTKSZ: ::c_int = 8192;
pub const SS_ONSTACK: ::c_int = 1;
pub const SS_DISABLE: ::c_int = 2;
pub const SIG_SETMASK: ::c_int = 0;
pub const SIG_BLOCK: ::c_int = 1;
pub const SIG_UNBLOCK: ::c_int = 2;
pub const SIGHUP: ::c_int = 1;
pub const SIGINT: ::c_int = 2;
pub const SIGQUIT: ::c_int = 3;
pub const SIGILL: ::c_int = 4;
pub const SIGTRAP: ::c_int = 5;
pub const SIGABRT: ::c_int = 6;
pub const SIGEMT: ::c_int = 7;
pub const SIGFPE: ::c_int = 8;
pub const SIGKILL: ::c_int = 9;
pub const SIGBUS: ::c_int = 10;
pub const SIGSEGV: ::c_int = 11;
pub const SIGSYS: ::c_int = 12;
pub const SIGPIPE: ::c_int = 13;
pub const SIGALRM: ::c_int = 14;
pub const SIGTERM: ::c_int = 15;
pub const SIGURG: ::c_int = 16;
pub const SIGSTOP: ::c_int = 17;
pub const SIGTSTP: ::c_int = 18;
pub const SIGCONT: ::c_int = 19;
pub const SIGCHLD: ::c_int = 20;
pub const SIGCLD: ::c_int = 20;
pub const SIGTTIN: ::c_int = 21;
pub const SIGTTOU: ::c_int = 22;
pub const SIGIO: ::c_int = 23;
pub const SIGPOLL: ::c_int = 23;
pub const SIGXCPU: ::c_int = 24;
pub const SIGXFSZ: ::c_int = 25;
pub const SIGVTALRM: ::c_int = 26;
pub const SIGPROF: ::c_int = 27;
pub const SIGWINCH: ::c_int = 28;
pub const SIGLOST: ::c_int = 29;
pub const SIGUSR1: ::c_int = 30;
pub const SIGUSR2: ::c_int = 31;
pub const NSIG: ::c_int = 32;
pub const CLOCK_ENABLED: ::c_uint = 1;
pub const CLOCK_DISABLED: ::c_uint = 0;
pub const CLOCK_ALLOWED: ::c_uint = 1;
pub const CLOCK_DISALLOWED: ::c_uint = 0;
pub const TIMER_ABSTIME: ::c_uint = 4;
pub const SOL_SOCKET: ::c_int = 65535;
pub const MSG_OOB: ::c_int = 1;
pub const MSG_PEEK: ::c_int = 2;
pub const MSG_DONTWAIT: ::c_int = 4;
pub const MSG_DONTROUTE: ::c_int = 0;
pub const MSG_WAITALL: ::c_int = 0;
pub const MSG_MORE: ::c_int = 0;
pub const MSG_NOSIGNAL: ::c_int = 0;
pub const SOL_CONFIG: ::c_uint = 65534;

pub const _SC_PAGESIZE: ::c_int = 8;
pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 51;

pub const PTHREAD_STACK_MIN: ::size_t = 4096;
pub const WNOHANG: ::c_int = 1;

pub const POLLIN: ::c_short = 0x0001;
pub const POLLPRI: ::c_short = 0x0002;
pub const POLLOUT: ::c_short = 0x0004;
pub const POLLRDNORM: ::c_short = 0x0040;
pub const POLLWRNORM: ::c_short = POLLOUT;
pub const POLLRDBAND: ::c_short = 0x0080;
pub const POLLWRBAND: ::c_short = 0x0100;
pub const POLLERR: ::c_short = 0x0008;
pub const POLLHUP: ::c_short = 0x0010;
pub const POLLNVAL: ::c_short = 0x0020;

pub const EAI_AGAIN: ::c_int = 2;
pub const EAI_BADFLAGS: ::c_int = 3;
pub const EAI_FAIL: ::c_int = 4;
pub const EAI_SERVICE: ::c_int = 9;
pub const EAI_SYSTEM: ::c_int = 11;
pub const EAI_BADHINTS: ::c_int = 12;
pub const EAI_PROTOCOL: ::c_int = 13;
pub const EAI_OVERFLOW: ::c_int = 14;
pub const EAI_MAX: ::c_int = 15;

pub const AF_UNIX: ::c_int = 1;
pub const AF_INET6: ::c_int = 23;

pub const FIONBIO: ::c_ulong = 1;

pub const RTLD_DEFAULT: *mut ::c_void = 0 as *mut ::c_void;

// Horizon OS works doesn't or can't hold any of this information
safe_f! {
    pub {const} fn WIFSTOPPED(_status: ::c_int) -> bool {
        false
    }

    pub {const} fn WSTOPSIG(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WIFCONTINUED(_status: ::c_int) -> bool {
        true
    }

    pub {const} fn WIFSIGNALED(_status: ::c_int) -> bool {
        false
    }

    pub {const} fn WTERMSIG(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WIFEXITED(_status: ::c_int) -> bool {
        true
    }

    pub {const} fn WEXITSTATUS(_status: ::c_int) -> ::c_int {
        0
    }

    pub {const} fn WCOREDUMP(_status: ::c_int) -> bool {
        false
    }
}

extern "C" {
    pub fn pthread_create(
        native: *mut ::pthread_t,
        attr: *const ::pthread_attr_t,
        f: extern "C" fn(_: *mut ::c_void) -> *mut ::c_void,
        value: *mut ::c_void,
    ) -> ::c_int;

    pub fn pthread_attr_getschedparam(
        attr: *const ::pthread_attr_t,
        param: *mut sched_param,
    ) -> ::c_int;

    pub fn pthread_attr_setschedparam(
        attr: *mut ::pthread_attr_t,
        param: *const sched_param,
    ) -> ::c_int;

    pub fn pthread_attr_getidealprocessor_np(
        attr: *const ::pthread_attr_t,
        ideal_processor: *mut ::c_int,
    ) -> ::c_int;

    pub fn pthread_attr_setidealprocessor_np(
        attr: *mut ::pthread_attr_t,
        ideal_processor: ::c_int,
    ) -> ::c_int;

    pub fn pthread_getpriority() -> ::c_int;

    pub fn gethostid() -> ::c_long;
}
<|endoftext|>


<commit_before>//! Paths and Unix shells
//!
//! MacOS, Linux, FreeBSD, and many other OS model their design on Unix,
//! so handling them is relatively consistent. But only relatively.
//! POSIX postdates Unix by 20 years, and each "Unix-like" shell develops
//! unique quirks over time.

// TODO: Nushell, PowerShell
// Cross-platform non-POSIX shells were not assessed for integration yet.

use super::*;
use std::env;
use std::path::PathBuf;

pub type Shell = Box<dyn UnixShell>;

macro_rules! support_shells {
    ( $($shell:ident,)* ) => {
        fn enumerate_shells() -> Vec<Shell> {
            vec![$( Box::new($shell), )*]
        }
    }
}

support_shells! {
    Posix,
    Bash,
    Zsh,
}

pub fn get_available_shells() -> impl Iterator<Item = Shell> {
    enumerate_shells().into_iter().filter(|sh| sh.does_exist())
}

pub trait UnixShell {
    fn does_exist(&self) -> bool;

    fn rcfile(&self) -> Option<PathBuf>;

    fn export_string(&self) -> Result<String> {
        // The path is *prepended* in case there are system-installed
        // rustc's that need to be overridden.
        Ok(format!(
            r#"export PATH="{}/bin:$PATH""#,
            canonical_cargo_home()?
        ))
    }
}

struct Posix;
impl UnixShell for Posix {
    fn does_exist(&self) -> bool {
        true
    }

    fn rcfile(&self) -> Option<PathBuf> {
        utils::home_dir().map(|dir| dir.join(".profile"))
    }
}

struct Bash;
impl UnixShell for Bash {
    fn does_exist(&self) -> bool {
        self.rcfile().map_or(false, |rc| rc.is_file())
            || matches!(utils::find_cmd(&["bash"]), Some(_))
    }

    fn rcfile(&self) -> Option<PathBuf> {
        // .bashrc is normative, in spite of a few weird Mac versions.
        utils::home_dir().map(|dir| dir.join(".bashrc"))
    }
}

struct Zsh;
impl UnixShell for Zsh {
    fn does_exist(&self) -> bool {
        self.rcfile().map_or(false, |rc| rc.is_file())
            || matches!(utils::find_cmd(&["zsh"]), Some(_))
    }

    fn rcfile(&self) -> Option<PathBuf> {
        let zdotdir = match env::var("ZDOTDIR") {
            Ok(dir) => Some(PathBuf::from(dir)),
            _ => utils::home_dir(),
        };

        // .zshenv is preferred for path mods but not all zshers use it,
        // zsh always loads .zshrc on interactive, unlike bash's weirdness.
        zdotdir.map(|dir| match dir.join(".zshenv") {
            rc if rc.is_file() => rc,
            _ => dir.join(".zshrc"),
        })
    }
}
<commit_msg>std::env::var() -> rustup::process().var()<commit_after>//! Paths and Unix shells
//!
//! MacOS, Linux, FreeBSD, and many other OS model their design on Unix,
//! so handling them is relatively consistent. But only relatively.
//! POSIX postdates Unix by 20 years, and each "Unix-like" shell develops
//! unique quirks over time.

// TODO: Nushell, PowerShell
// Cross-platform non-POSIX shells were not assessed for integration yet.

use super::*;
use crate::process;
use std::path::PathBuf;

pub type Shell = Box<dyn UnixShell>;

macro_rules! support_shells {
    ( $($shell:ident,)* ) => {
        fn enumerate_shells() -> Vec<Shell> {
            vec![$( Box::new($shell), )*]
        }
    }
}

support_shells! {
    Posix,
    Bash,
    Zsh,
}

pub fn get_available_shells() -> impl Iterator<Item = Shell> {
    enumerate_shells().into_iter().filter(|sh| sh.does_exist())
}

pub trait UnixShell {
    fn does_exist(&self) -> bool;

    fn rcfile(&self) -> Option<PathBuf>;

    fn export_string(&self) -> Result<String> {
        // The path is *prepended* in case there are system-installed
        // rustc's that need to be overridden.
        Ok(format!(
            r#"export PATH="{}/bin:$PATH""#,
            canonical_cargo_home()?
        ))
    }
}

struct Posix;
impl UnixShell for Posix {
    fn does_exist(&self) -> bool {
        true
    }

    fn rcfile(&self) -> Option<PathBuf> {
        utils::home_dir().map(|dir| dir.join(".profile"))
    }
}

struct Bash;
impl UnixShell for Bash {
    fn does_exist(&self) -> bool {
        self.rcfile().map_or(false, |rc| rc.is_file())
            || matches!(utils::find_cmd(&["bash"]), Some(_))
    }

    fn rcfile(&self) -> Option<PathBuf> {
        // .bashrc is normative, in spite of a few weird Mac versions.
        utils::home_dir().map(|dir| dir.join(".bashrc"))
    }
}

struct Zsh;
impl UnixShell for Zsh {
    fn does_exist(&self) -> bool {
        self.rcfile().map_or(false, |rc| rc.is_file())
            || matches!(utils::find_cmd(&["zsh"]), Some(_))
    }

    fn rcfile(&self) -> Option<PathBuf> {
        let zdotdir = match process().var("ZDOTDIR") {
            Ok(dir) => Some(PathBuf::from(dir)),
            _ => utils::home_dir(),
        };

        // .zshenv is preferred for path mods but not all zshers use it,
        // zsh always loads .zshrc on interactive, unlike bash's weirdness.
        zdotdir.map(|dir| match dir.join(".zshenv") {
            rc if rc.is_file() => rc,
            _ => dir.join(".zshrc"),
        })
    }
}
<|endoftext|>


<commit_before>use super::ffi_type::*;
use crate::{
    codegen::general::{cfg_condition, version_condition},
    config::{functions::Function, gobjects::GObject},
    env::Env,
    library, nameutil,
    traits::*,
};
use once_cell::sync::Lazy;
use std::io::{Result, Write};

//used as glib:get-type in GLib-2.0.gir
const INTERN: &str = "intern";

static DEFAULT_OBJ: Lazy<GObject> = Lazy::new(|| Default::default());

pub fn generate_records_funcs(
    w: &mut dyn Write,
    env: &Env,
    records: &[&library::Record],
) -> Result<()> {
    let intern_str = INTERN.to_string();
    for record in records {
        let name = format!("{}.{}", env.config.library_name, record.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        let glib_get_type = record.glib_get_type.as_ref().unwrap_or(&intern_str);
        generate_object_funcs(
            w,
            env,
            obj,
            &record.c_type,
            glib_get_type,
            &record.functions,
        )?;
    }

    Ok(())
}

pub fn generate_classes_funcs(
    w: &mut dyn Write,
    env: &Env,
    classes: &[&library::Class],
) -> Result<()> {
    for klass in classes {
        let name = format!("{}.{}", env.config.library_name, klass.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        generate_object_funcs(
            w,
            env,
            obj,
            &klass.c_type,
            &klass.glib_get_type,
            &klass.functions,
        )?;
    }

    Ok(())
}

pub fn generate_bitfields_funcs(
    w: &mut dyn Write,
    env: &Env,
    bitfields: &[&library::Bitfield],
) -> Result<()> {
    let intern_str = INTERN.to_string();
    for bitfield in bitfields {
        let name = format!("{}.{}", env.config.library_name, bitfield.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        let glib_get_type = bitfield.glib_get_type.as_ref().unwrap_or(&intern_str);
        generate_object_funcs(
            w,
            env,
            obj,
            &bitfield.c_type,
            glib_get_type,
            &bitfield.functions,
        )?;
    }

    Ok(())
}

pub fn generate_enums_funcs(
    w: &mut dyn Write,
    env: &Env,
    enums: &[&library::Enumeration],
) -> Result<()> {
    let intern_str = INTERN.to_string();
    for en in enums {
        let name = format!("{}.{}", env.config.library_name, en.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        let glib_get_type = en.glib_get_type.as_ref().unwrap_or(&intern_str);
        generate_object_funcs(w, env, obj, &en.c_type, glib_get_type, &en.functions)?;
    }

    Ok(())
}

pub fn generate_unions_funcs(
    w: &mut dyn Write,
    env: &Env,
    unions: &[&library::Union],
) -> Result<()> {
    let intern_str = INTERN.to_string();
    for union in unions {
        let c_type = match union.c_type {
            Some(ref x) => x,
            None => return Ok(()),
        };
        let name = format!("{}.{}", env.config.library_name, union.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        let glib_get_type = union.glib_get_type.as_ref().unwrap_or(&intern_str);
        generate_object_funcs(w, env, obj, c_type, glib_get_type, &union.functions)?;
    }

    Ok(())
}

pub fn generate_interfaces_funcs(
    w: &mut dyn Write,
    env: &Env,
    interfaces: &[&library::Interface],
) -> Result<()> {
    for interface in interfaces {
        let name = format!("{}.{}", env.config.library_name, interface.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        generate_object_funcs(
            w,
            env,
            obj,
            &interface.c_type,
            &interface.glib_get_type,
            &interface.functions,
        )?;
    }

    Ok(())
}

pub fn generate_other_funcs(
    w: &mut dyn Write,
    env: &Env,
    functions: &[library::Function],
) -> Result<()> {
    let name = format!("{}.*", env.config.library_name);
    let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
    generate_object_funcs(w, env, obj, "Other functions", INTERN, functions)
}

fn generate_cfg_configure(
    w: &mut dyn Write,
    configured_functions: &[&Function],
    commented: bool,
) -> Result<()> {
    let cfg_condition_ = configured_functions
        .iter()
        .filter_map(|f| f.cfg_condition.clone())
        .next();
    cfg_condition(w, &cfg_condition_, commented, 1)?;
    Ok(())
}

fn generate_object_funcs(
    w: &mut dyn Write,
    env: &Env,
    obj: &GObject,
    c_type: &str,
    glib_get_type: &str,
    functions: &[library::Function],
) -> Result<()> {
    let write_get_type = glib_get_type != INTERN;
    if write_get_type || !functions.is_empty() {
        writeln!(w)?;
        writeln!(
            w,
            "    //========================================================================="
        )?;
        writeln!(w, "    // {}", c_type)?;
        writeln!(
            w,
            "    //========================================================================="
        )?;
    }
    if write_get_type {
        let configured_functions = obj.functions.matched(&glib_get_type);
        generate_cfg_configure(w, &configured_functions, false)?;
        writeln!(w, "    pub fn {}() -> GType;", glib_get_type)?;
    }

    for func in functions {
        let configured_functions = obj.functions.matched(&func.name);
        if configured_functions.iter().any(|f| f.ignore) {
            continue;
        }
        let is_windows_utf8 = configured_functions.iter().any(|f| f.is_windows_utf8);

        let (commented, sig) = function_signature(env, func, false);
        let comment = if commented { "//" } else { "" };
        version_condition(w, env, func.version, commented, 1)?;
        let name = func.c_identifier.as_ref().unwrap();
        // since we work with gir-files from Linux, some function names need to be adjusted
        if is_windows_utf8 {
            writeln!(w, "    {}#[cfg(any(windows, feature = \"dox\"))]", comment)?;
            writeln!(w, "    {}pub fn {}_utf8{};", comment, name, sig)?;
            version_condition(w, env, func.version, commented, 1)?;
        }
        generate_cfg_configure(w, &configured_functions, commented)?;
        writeln!(w, "    {}pub fn {}{};", comment, name, sig)?;
    }

    Ok(())
}

pub fn generate_callbacks(
    w: &mut dyn Write,
    env: &Env,
    callbacks: &[&library::Function],
) -> Result<()> {
    if !callbacks.is_empty() {
        writeln!(w, "// Callbacks")?;
    }
    for func in callbacks {
        let (commented, sig) = function_signature(env, func, true);
        let comment = if commented { "//" } else { "" };
        writeln!(
            w,
            "{}pub type {} = Option<unsafe extern \"C\" fn{}>;",
            comment,
            func.c_identifier.as_ref().unwrap(),
            sig
        )?;
    }
    if !callbacks.is_empty() {
        writeln!(w)?;
    }

    Ok(())
}

pub fn function_signature(env: &Env, func: &library::Function, bare: bool) -> (bool, String) {
    let (mut commented, ret_str) = function_return_value(env, func);

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &func.parameters {
        let (c, par_str) = function_parameter(env, par, bare);
        parameter_strs.push(par_str);
        if c {
            commented = true;
        }
    }

    (
        commented,
        format!("({}){}", parameter_strs.join(", "), ret_str),
    )
}

fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) {
    if func.ret.typ == Default::default() {
        return (false, String::new());
    }
    let ffi_type = ffi_type(env, func.ret.typ, &func.ret.c_type);
    let commented = ffi_type.is_err();
    (commented, format!(" -> {}", ffi_type.into_string()))
}

fn function_parameter(env: &Env, par: &library::Parameter, bare: bool) -> (bool, String) {
    if let library::Type::Fundamental(library::Fundamental::VarArgs) = *env.library.type_(par.typ) {
        return (false, "...".into());
    }
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    let commented = ffi_type.is_err();
    let res = if bare {
        ffi_type.into_string()
    } else {
        format!(
            "{}: {}",
            nameutil::mangle_keywords(&*par.name),
            ffi_type.into_string()
        )
    };
    (commented, res)
}
<commit_msg>Remove unneeded closure<commit_after>use super::ffi_type::*;
use crate::{
    codegen::general::{cfg_condition, version_condition},
    config::{functions::Function, gobjects::GObject},
    env::Env,
    library, nameutil,
    traits::*,
};
use once_cell::sync::Lazy;
use std::io::{Result, Write};

//used as glib:get-type in GLib-2.0.gir
const INTERN: &str = "intern";

static DEFAULT_OBJ: Lazy<GObject> = Lazy::new(Default::default);

pub fn generate_records_funcs(
    w: &mut dyn Write,
    env: &Env,
    records: &[&library::Record],
) -> Result<()> {
    let intern_str = INTERN.to_string();
    for record in records {
        let name = format!("{}.{}", env.config.library_name, record.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        let glib_get_type = record.glib_get_type.as_ref().unwrap_or(&intern_str);
        generate_object_funcs(
            w,
            env,
            obj,
            &record.c_type,
            glib_get_type,
            &record.functions,
        )?;
    }

    Ok(())
}

pub fn generate_classes_funcs(
    w: &mut dyn Write,
    env: &Env,
    classes: &[&library::Class],
) -> Result<()> {
    for klass in classes {
        let name = format!("{}.{}", env.config.library_name, klass.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        generate_object_funcs(
            w,
            env,
            obj,
            &klass.c_type,
            &klass.glib_get_type,
            &klass.functions,
        )?;
    }

    Ok(())
}

pub fn generate_bitfields_funcs(
    w: &mut dyn Write,
    env: &Env,
    bitfields: &[&library::Bitfield],
) -> Result<()> {
    let intern_str = INTERN.to_string();
    for bitfield in bitfields {
        let name = format!("{}.{}", env.config.library_name, bitfield.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        let glib_get_type = bitfield.glib_get_type.as_ref().unwrap_or(&intern_str);
        generate_object_funcs(
            w,
            env,
            obj,
            &bitfield.c_type,
            glib_get_type,
            &bitfield.functions,
        )?;
    }

    Ok(())
}

pub fn generate_enums_funcs(
    w: &mut dyn Write,
    env: &Env,
    enums: &[&library::Enumeration],
) -> Result<()> {
    let intern_str = INTERN.to_string();
    for en in enums {
        let name = format!("{}.{}", env.config.library_name, en.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        let glib_get_type = en.glib_get_type.as_ref().unwrap_or(&intern_str);
        generate_object_funcs(w, env, obj, &en.c_type, glib_get_type, &en.functions)?;
    }

    Ok(())
}

pub fn generate_unions_funcs(
    w: &mut dyn Write,
    env: &Env,
    unions: &[&library::Union],
) -> Result<()> {
    let intern_str = INTERN.to_string();
    for union in unions {
        let c_type = match union.c_type {
            Some(ref x) => x,
            None => return Ok(()),
        };
        let name = format!("{}.{}", env.config.library_name, union.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        let glib_get_type = union.glib_get_type.as_ref().unwrap_or(&intern_str);
        generate_object_funcs(w, env, obj, c_type, glib_get_type, &union.functions)?;
    }

    Ok(())
}

pub fn generate_interfaces_funcs(
    w: &mut dyn Write,
    env: &Env,
    interfaces: &[&library::Interface],
) -> Result<()> {
    for interface in interfaces {
        let name = format!("{}.{}", env.config.library_name, interface.name);
        let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
        generate_object_funcs(
            w,
            env,
            obj,
            &interface.c_type,
            &interface.glib_get_type,
            &interface.functions,
        )?;
    }

    Ok(())
}

pub fn generate_other_funcs(
    w: &mut dyn Write,
    env: &Env,
    functions: &[library::Function],
) -> Result<()> {
    let name = format!("{}.*", env.config.library_name);
    let obj = env.config.objects.get(&name).unwrap_or(&DEFAULT_OBJ);
    generate_object_funcs(w, env, obj, "Other functions", INTERN, functions)
}

fn generate_cfg_configure(
    w: &mut dyn Write,
    configured_functions: &[&Function],
    commented: bool,
) -> Result<()> {
    let cfg_condition_ = configured_functions
        .iter()
        .filter_map(|f| f.cfg_condition.clone())
        .next();
    cfg_condition(w, &cfg_condition_, commented, 1)?;
    Ok(())
}

fn generate_object_funcs(
    w: &mut dyn Write,
    env: &Env,
    obj: &GObject,
    c_type: &str,
    glib_get_type: &str,
    functions: &[library::Function],
) -> Result<()> {
    let write_get_type = glib_get_type != INTERN;
    if write_get_type || !functions.is_empty() {
        writeln!(w)?;
        writeln!(
            w,
            "    //========================================================================="
        )?;
        writeln!(w, "    // {}", c_type)?;
        writeln!(
            w,
            "    //========================================================================="
        )?;
    }
    if write_get_type {
        let configured_functions = obj.functions.matched(&glib_get_type);
        generate_cfg_configure(w, &configured_functions, false)?;
        writeln!(w, "    pub fn {}() -> GType;", glib_get_type)?;
    }

    for func in functions {
        let configured_functions = obj.functions.matched(&func.name);
        if configured_functions.iter().any(|f| f.ignore) {
            continue;
        }
        let is_windows_utf8 = configured_functions.iter().any(|f| f.is_windows_utf8);

        let (commented, sig) = function_signature(env, func, false);
        let comment = if commented { "//" } else { "" };
        version_condition(w, env, func.version, commented, 1)?;
        let name = func.c_identifier.as_ref().unwrap();
        // since we work with gir-files from Linux, some function names need to be adjusted
        if is_windows_utf8 {
            writeln!(w, "    {}#[cfg(any(windows, feature = \"dox\"))]", comment)?;
            writeln!(w, "    {}pub fn {}_utf8{};", comment, name, sig)?;
            version_condition(w, env, func.version, commented, 1)?;
        }
        generate_cfg_configure(w, &configured_functions, commented)?;
        writeln!(w, "    {}pub fn {}{};", comment, name, sig)?;
    }

    Ok(())
}

pub fn generate_callbacks(
    w: &mut dyn Write,
    env: &Env,
    callbacks: &[&library::Function],
) -> Result<()> {
    if !callbacks.is_empty() {
        writeln!(w, "// Callbacks")?;
    }
    for func in callbacks {
        let (commented, sig) = function_signature(env, func, true);
        let comment = if commented { "//" } else { "" };
        writeln!(
            w,
            "{}pub type {} = Option<unsafe extern \"C\" fn{}>;",
            comment,
            func.c_identifier.as_ref().unwrap(),
            sig
        )?;
    }
    if !callbacks.is_empty() {
        writeln!(w)?;
    }

    Ok(())
}

pub fn function_signature(env: &Env, func: &library::Function, bare: bool) -> (bool, String) {
    let (mut commented, ret_str) = function_return_value(env, func);

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &func.parameters {
        let (c, par_str) = function_parameter(env, par, bare);
        parameter_strs.push(par_str);
        if c {
            commented = true;
        }
    }

    (
        commented,
        format!("({}){}", parameter_strs.join(", "), ret_str),
    )
}

fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) {
    if func.ret.typ == Default::default() {
        return (false, String::new());
    }
    let ffi_type = ffi_type(env, func.ret.typ, &func.ret.c_type);
    let commented = ffi_type.is_err();
    (commented, format!(" -> {}", ffi_type.into_string()))
}

fn function_parameter(env: &Env, par: &library::Parameter, bare: bool) -> (bool, String) {
    if let library::Type::Fundamental(library::Fundamental::VarArgs) = *env.library.type_(par.typ) {
        return (false, "...".into());
    }
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    let commented = ffi_type.is_err();
    let res = if bare {
        ffi_type.into_string()
    } else {
        format!(
            "{}: {}",
            nameutil::mangle_keywords(&*par.name),
            ffi_type.into_string()
        )
    };
    (commented, res)
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use collections::HashMap;
use rand;
use rand::Rng;
use std::hash::{Hash, sip};
use std::slice;
use std::slice::Items;

#[cfg(test)]
use std::cell::Cell;

pub trait Cache<K: Eq, V: Clone> {
    fn insert(&mut self, key: K, value: V);
    fn find(&mut self, key: &K) -> Option<V>;
    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V;
    fn evict_all(&mut self);
}

pub struct MonoCache<K, V> {
    entry: Option<(K,V)>,
}

impl<K: Clone + Eq, V: Clone> MonoCache<K,V> {
    pub fn new(_size: uint) -> MonoCache<K,V> {
        MonoCache { entry: None }
    }
}

impl<K: Clone + Eq, V: Clone> Cache<K,V> for MonoCache<K,V> {
    fn insert(&mut self, key: K, value: V) {
        self.entry = Some((key, value));
    }

    fn find(&mut self, key: &K) -> Option<V> {
        match self.entry {
            None => None,
            Some((ref k, ref v)) => if *k == *key { Some(v.clone()) } else { None }
        }
    }

    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
        match self.find(key) {
            Some(value) => value,
            None => {
                let value = blk(key);
                self.entry = Some((key.clone(), value.clone()));
                value
            }
        }
    }

    fn evict_all(&mut self) {
        self.entry = None;
    }
}

#[test]
fn test_monocache() {
    let mut cache = MonoCache::new(10);
    let one = Cell::new("one");
    let two = Cell::new("two");
    cache.insert(1, one);

    assert!(cache.find(&1).is_some());
    assert!(cache.find(&2).is_none());
    cache.find_or_create(&2, |_v| { two });
    assert!(cache.find(&2).is_some());
    assert!(cache.find(&1).is_none());
}

pub struct HashCache<K, V> {
    entries: HashMap<K, V>,
}

impl<K: Clone + Eq + TotalEq + Hash, V: Clone> HashCache<K,V> {
    pub fn new() -> HashCache<K, V> {
        HashCache {
          entries: HashMap::new(),
        }
    }
}

impl<K: Clone + Eq + TotalEq + Hash, V: Clone> Cache<K,V> for HashCache<K,V> {
    fn insert(&mut self, key: K, value: V) {
        self.entries.insert(key, value);
    }

    fn find(&mut self, key: &K) -> Option<V> {
        match self.entries.find(key) {
            Some(v) => Some(v.clone()),
            None    => None,
        }
    }

    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
        self.entries.find_or_insert_with(key.clone(), blk).clone()
    }

    fn evict_all(&mut self) {
        self.entries.clear();
    }
}

#[test]
fn test_hashcache() {
    let mut cache = HashCache::new();
    let one = Cell::new("one");
    let two = Cell::new("two");

    cache.insert(1, one);
    assert!(cache.find(&1).is_some());
    assert!(cache.find(&2).is_none());

    cache.find_or_create(&2, |_v| { two });
    assert!(cache.find(&1).is_some());
    assert!(cache.find(&2).is_some());
}

pub struct LRUCache<K, V> {
    entries: ~[(K, V)],
    cache_size: uint,
}

impl<K: Clone + Eq, V: Clone> LRUCache<K,V> {
    pub fn new(size: uint) -> LRUCache<K, V> {
        LRUCache {
          entries: ~[],
          cache_size: size,
        }
    }

    #[inline]
    pub fn touch(&mut self, pos: uint) -> V {
        let last_index = self.entries.len() - 1;
        if pos != last_index {
            let entry = self.entries.remove(pos);
            self.entries.push(entry.unwrap());
        }
        self.entries[last_index].ref1().clone()
    }

    pub fn iter<'a>(&'a self) -> Items<'a,(K,V)> {
        self.entries.iter()
    }
}

impl<K: Clone + Eq, V: Clone> Cache<K,V> for LRUCache<K,V> {
    fn insert(&mut self, key: K, val: V) {
        if self.entries.len() == self.cache_size {
            self.entries.remove(0);
        }
        self.entries.push((key, val));
    }

    fn find(&mut self, key: &K) -> Option<V> {
        match self.entries.iter().position(|&(ref k, _)| *k == *key) {
            Some(pos) => Some(self.touch(pos)),
            None      => None,
        }
    }

    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
        match self.entries.iter().position(|&(ref k, _)| *k == *key) {
            Some(pos) => self.touch(pos),
            None => {
                let val = blk(key);
                self.insert(key.clone(), val.clone());
                val
            }
        }
    }

    fn evict_all(&mut self) {
        self.entries.clear();
    }
}

pub struct SimpleHashCache<K,V> {
    entries: ~[Option<(K,V)>],
    k0: u64,
    k1: u64,
}

impl<K:Clone+Eq+Hash,V:Clone> SimpleHashCache<K,V> {
    pub fn new(cache_size: uint) -> SimpleHashCache<K,V> {
        let mut r = rand::task_rng();
        SimpleHashCache {
            entries: slice::from_elem(cache_size, None),
            k0: r.gen(),
            k1: r.gen(),
        }
    }

    #[inline]
    fn to_bucket(&self, h: uint) -> uint {
        h % self.entries.len()
    }

    #[inline]
    fn bucket_for_key<Q:Hash>(&self, key: &Q) -> uint {
        self.to_bucket(sip::hash_with_keys(self.k0, self.k1, key) as uint)
    }

    #[inline]
    pub fn find_equiv<'a,Q:Hash+Equiv<K>>(&'a self, key: &Q) -> Option<&'a V> {
        let bucket_index = self.bucket_for_key(key);
        match self.entries[bucket_index] {
            Some((ref existing_key, ref value)) if key.equiv(existing_key) => Some(value),
            _ => None,
        }
    }
}

impl<K:Clone+Eq+Hash,V:Clone> Cache<K,V> for SimpleHashCache<K,V> {
    fn insert(&mut self, key: K, value: V) {
        let bucket_index = self.bucket_for_key(&key);
        self.entries[bucket_index] = Some((key, value))
    }

    fn find(&mut self, key: &K) -> Option<V> {
        let bucket_index = self.bucket_for_key(key);
        match self.entries[bucket_index] {
            Some((ref existing_key, ref value)) if existing_key == key => Some((*value).clone()),
            _ => None,
        }
    }

    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
        match self.find(key) {
            Some(value) => return value,
            None => {}
        }
        let value = blk(key);
        self.insert((*key).clone(), value.clone());
        value
    }

    fn evict_all(&mut self) {
        for slot in self.entries.mut_iter() {
            *slot = None
        }
    }
}

#[test]
fn test_lru_cache() {
    let one = Cell::new("one");
    let two = Cell::new("two");
    let three = Cell::new("three");
    let four = Cell::new("four");

    // Test normal insertion.
    let mut cache = LRUCache::new(2); // (_, _) (cache is empty)
    cache.insert(1, one);    // (1, _)
    cache.insert(2, two);    // (1, 2)
    cache.insert(3, three);  // (2, 3)

    assert!(cache.find(&1).is_none());  // (2, 3) (no change)
    assert!(cache.find(&3).is_some());  // (2, 3)
    assert!(cache.find(&2).is_some());  // (3, 2)

    // Test that LRU works (this insertion should replace 3, not 2).
    cache.insert(4, four); // (2, 4)

    assert!(cache.find(&1).is_none());  // (2, 4) (no change)
    assert!(cache.find(&2).is_some());  // (4, 2)
    assert!(cache.find(&3).is_none());  // (4, 2) (no change)
    assert!(cache.find(&4).is_some());  // (2, 4) (no change)

    // Test find_or_create.
    cache.find_or_create(&1, |_| { one }); // (4, 1)

    assert!(cache.find(&1).is_some()); // (4, 1) (no change)
    assert!(cache.find(&2).is_none()); // (4, 1) (no change)
    assert!(cache.find(&3).is_none()); // (4, 1) (no change)
    assert!(cache.find(&4).is_some()); // (1, 4)
}
<commit_msg>~[] to Vec in util/cache.rs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use collections::HashMap;
use rand;
use rand::Rng;
use std::hash::{Hash, sip};
use std::slice;
use std::slice::Items;

#[cfg(test)]
use std::cell::Cell;

pub trait Cache<K: Eq, V: Clone> {
    fn insert(&mut self, key: K, value: V);
    fn find(&mut self, key: &K) -> Option<V>;
    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V;
    fn evict_all(&mut self);
}

pub struct MonoCache<K, V> {
    entry: Option<(K,V)>,
}

impl<K: Clone + Eq, V: Clone> MonoCache<K,V> {
    pub fn new(_size: uint) -> MonoCache<K,V> {
        MonoCache { entry: None }
    }
}

impl<K: Clone + Eq, V: Clone> Cache<K,V> for MonoCache<K,V> {
    fn insert(&mut self, key: K, value: V) {
        self.entry = Some((key, value));
    }

    fn find(&mut self, key: &K) -> Option<V> {
        match self.entry {
            None => None,
            Some((ref k, ref v)) => if *k == *key { Some(v.clone()) } else { None }
        }
    }

    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
        match self.find(key) {
            Some(value) => value,
            None => {
                let value = blk(key);
                self.entry = Some((key.clone(), value.clone()));
                value
            }
        }
    }

    fn evict_all(&mut self) {
        self.entry = None;
    }
}

#[test]
fn test_monocache() {
    let mut cache = MonoCache::new(10);
    let one = Cell::new("one");
    let two = Cell::new("two");
    cache.insert(1, one);

    assert!(cache.find(&1).is_some());
    assert!(cache.find(&2).is_none());
    cache.find_or_create(&2, |_v| { two });
    assert!(cache.find(&2).is_some());
    assert!(cache.find(&1).is_none());
}

pub struct HashCache<K, V> {
    entries: HashMap<K, V>,
}

impl<K: Clone + Eq + TotalEq + Hash, V: Clone> HashCache<K,V> {
    pub fn new() -> HashCache<K, V> {
        HashCache {
          entries: HashMap::new(),
        }
    }
}

impl<K: Clone + Eq + TotalEq + Hash, V: Clone> Cache<K,V> for HashCache<K,V> {
    fn insert(&mut self, key: K, value: V) {
        self.entries.insert(key, value);
    }

    fn find(&mut self, key: &K) -> Option<V> {
        match self.entries.find(key) {
            Some(v) => Some(v.clone()),
            None    => None,
        }
    }

    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
        self.entries.find_or_insert_with(key.clone(), blk).clone()
    }

    fn evict_all(&mut self) {
        self.entries.clear();
    }
}

#[test]
fn test_hashcache() {
    let mut cache = HashCache::new();
    let one = Cell::new("one");
    let two = Cell::new("two");

    cache.insert(1, one);
    assert!(cache.find(&1).is_some());
    assert!(cache.find(&2).is_none());

    cache.find_or_create(&2, |_v| { two });
    assert!(cache.find(&1).is_some());
    assert!(cache.find(&2).is_some());
}

pub struct LRUCache<K, V> {
    entries: Vec<(K, V)>,
    cache_size: uint,
}

impl<K: Clone + Eq, V: Clone> LRUCache<K,V> {
    pub fn new(size: uint) -> LRUCache<K, V> {
        LRUCache {
          entries: Vec::new(),
          cache_size: size,
        }
    }

    #[inline]
    pub fn touch(&mut self, pos: uint) -> V {
        let last_index = self.entries.len() - 1;
        if pos != last_index {
            let entry = self.entries.remove(pos);
            self.entries.push(entry.unwrap());
        }
        self.entries.get(last_index).ref1().clone()
    }

    pub fn iter<'a>(&'a self) -> Items<'a,(K,V)> {
        self.entries.iter()
    }
}

impl<K: Clone + Eq, V: Clone> Cache<K,V> for LRUCache<K,V> {
    fn insert(&mut self, key: K, val: V) {
        if self.entries.len() == self.cache_size {
            self.entries.remove(0);
        }
        self.entries.push((key, val));
    }

    fn find(&mut self, key: &K) -> Option<V> {
        match self.entries.iter().position(|&(ref k, _)| *k == *key) {
            Some(pos) => Some(self.touch(pos)),
            None      => None,
        }
    }

    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
        match self.entries.iter().position(|&(ref k, _)| *k == *key) {
            Some(pos) => self.touch(pos),
            None => {
                let val = blk(key);
                self.insert(key.clone(), val.clone());
                val
            }
        }
    }

    fn evict_all(&mut self) {
        self.entries.clear();
    }
}

pub struct SimpleHashCache<K,V> {
    entries: ~[Option<(K,V)>],
    k0: u64,
    k1: u64,
}

impl<K:Clone+Eq+Hash,V:Clone> SimpleHashCache<K,V> {
    pub fn new(cache_size: uint) -> SimpleHashCache<K,V> {
        let mut r = rand::task_rng();
        SimpleHashCache {
            entries: slice::from_elem(cache_size, None),
            k0: r.gen(),
            k1: r.gen(),
        }
    }

    #[inline]
    fn to_bucket(&self, h: uint) -> uint {
        h % self.entries.len()
    }

    #[inline]
    fn bucket_for_key<Q:Hash>(&self, key: &Q) -> uint {
        self.to_bucket(sip::hash_with_keys(self.k0, self.k1, key) as uint)
    }

    #[inline]
    pub fn find_equiv<'a,Q:Hash+Equiv<K>>(&'a self, key: &Q) -> Option<&'a V> {
        let bucket_index = self.bucket_for_key(key);
        match self.entries[bucket_index] {
            Some((ref existing_key, ref value)) if key.equiv(existing_key) => Some(value),
            _ => None,
        }
    }
}

impl<K:Clone+Eq+Hash,V:Clone> Cache<K,V> for SimpleHashCache<K,V> {
    fn insert(&mut self, key: K, value: V) {
        let bucket_index = self.bucket_for_key(&key);
        self.entries[bucket_index] = Some((key, value))
    }

    fn find(&mut self, key: &K) -> Option<V> {
        let bucket_index = self.bucket_for_key(key);
        match self.entries[bucket_index] {
            Some((ref existing_key, ref value)) if existing_key == key => Some((*value).clone()),
            _ => None,
        }
    }

    fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
        match self.find(key) {
            Some(value) => return value,
            None => {}
        }
        let value = blk(key);
        self.insert((*key).clone(), value.clone());
        value
    }

    fn evict_all(&mut self) {
        for slot in self.entries.mut_iter() {
            *slot = None
        }
    }
}

#[test]
fn test_lru_cache() {
    let one = Cell::new("one");
    let two = Cell::new("two");
    let three = Cell::new("three");
    let four = Cell::new("four");

    // Test normal insertion.
    let mut cache = LRUCache::new(2); // (_, _) (cache is empty)
    cache.insert(1, one);    // (1, _)
    cache.insert(2, two);    // (1, 2)
    cache.insert(3, three);  // (2, 3)

    assert!(cache.find(&1).is_none());  // (2, 3) (no change)
    assert!(cache.find(&3).is_some());  // (2, 3)
    assert!(cache.find(&2).is_some());  // (3, 2)

    // Test that LRU works (this insertion should replace 3, not 2).
    cache.insert(4, four); // (2, 4)

    assert!(cache.find(&1).is_none());  // (2, 4) (no change)
    assert!(cache.find(&2).is_some());  // (4, 2)
    assert!(cache.find(&3).is_none());  // (4, 2) (no change)
    assert!(cache.find(&4).is_some());  // (2, 4) (no change)

    // Test find_or_create.
    cache.find_or_create(&1, |_| { one }); // (4, 1)

    assert!(cache.find(&1).is_some()); // (4, 1) (no change)
    assert!(cache.find(&2).is_none()); // (4, 1) (no change)
    assert!(cache.find(&3).is_none()); // (4, 1) (no change)
    assert!(cache.find(&4).is_some()); // (1, 4)
}
<|endoftext|>