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

use interpreter::InterpretResult;
use variable::Variable;

/// Handles the dispatching of named functions using an array of arguments.
pub trait FnDispatcher {
    /// Dispatches and interprets a function by name.
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>) -> InterpretResult;
}

/// Built-in function implementations.
#[derive(Clone)]
pub struct BuiltinFunctions;

impl BuiltinFunctions {
    /// Creates a new Builtins function dispatcher.
    pub fn new() -> BuiltinFunctions {
        BuiltinFunctions
    }
}

/// Validates the arity of a function.
#[inline]
fn arity(fn_name: &str, arity: usize, args: &Vec<Rc<Variable>>) -> Result<(), String> {
    if args.len() != arity {
        Err(format!("{} arity error: expected {} args, found {}", fn_name, arity, args.len()))
    } else {
        Ok(())
    }
}

/// Macro used to format a type error.
macro_rules! type_err {
    ($f:expr, $position:expr, $expected:expr, $given:expr) => {
        format!("{} expects arg {} to be {}. Given {:?}", $f, $position, $expected, $given)
    }
}

/// Macro used to variadically validate validate Variable and argument arity.
macro_rules! validate {
    // Validate positional arguments only.
    ($name:expr, $args:expr, $($x:expr),*) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            try!(arity($name, validators.len(), $args));
            for (k, v) in $args.iter().enumerate() {
                if let Err(e) = validators[k](v) {
                    return Err(format!("{} error at argument {}: {}", $name, k, e));
                }
            }
        }
    );
    // Validate positional arguments with a variadic validator.
    ($name:expr, $args:expr, $($x:expr),* ...$variadic:expr ) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            if $args.len() < validators.len() {
                return Err(format!("{} arity error: expected at least {} args, found {}",
                                   $name, validators.len(), $args.len()));
            }
            for (k, v) in $args.iter().enumerate() {
                try!((match validators.get(k) {
                    Some(validator) => validator(v),
                    None => $variadic(v)
                }).or_else(|e| Err(format!("{} error at argument {}: {}", $name, k, e))));
            }
        }
    );
}

/// Creates a closure used to validate the type of the given variable.
macro_rules! jptype {
    // Validate a type against a single acceptable type.
    ($type_name:ident) => [
        Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
            let arg_type = arg.get_type();
            if arg_type != "any" && arg_type != stringify!($type_name) {
                Err(format!("type {}", stringify!($type_name)))
            } else {
                Ok(())
            }
        })
    ];
    // Validate a type against multiple acceptable types
    ($($x:ident)|*) => [
        {
            Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
                let valid_types = vec![$(stringify!($x)), *];
                let arg_type = arg.get_type();
                if arg_type != "any" && !valid_types.contains(&arg_type) {
                    Err(format!("type {}", valid_types.join("|")))
                } else {
                    Ok(())
                }
            })
        }
    ];
}

impl FnDispatcher for BuiltinFunctions {
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>) -> InterpretResult {
        match fn_name {
            "abs" => {
                validate!("abs", args, jptype![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().abs())))
            },
            "avg" => {
                try!(arity("avg", 1, args));
                args[0].as_array()
                    .and_then(|array| {
                        let mut total = 0f64;
                        for value in array {
                            match **value {
                                Variable::I64(n) => total += n as f64,
                                Variable::U64(n) => total += n as f64,
                                Variable::F64(n) => total += n,
                                _ => return None
                            }
                        }
                        Some(Rc::new(Variable::F64(total / array.len() as f64)))
                    })
                    .ok_or(type_err!("avg", 0, "array[number]", args[0]))
            },
            "ceil" => {
                validate!("ceil", args, jptype![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().ceil())))
            },
            "contains" => {
                validate!("contains", args, jptype![array|string], jptype![any]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::Boolean(a.contains(&args[1])))),
                    Variable::String(ref subj) => {
                        match args[1].as_string() {
                            Some(search) => Ok(Rc::new(Variable::Boolean(subj.contains(search)))),
                            None => Err(format!("contains found {:?} for string search arg",
                                                args[1]))
                        }
                    },
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "ends_with" => {
                validate!("ends_with", args, jptype![string], jptype![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.ends_with(search))))
            },
            "floor" => {
                validate!("floor", args, jptype![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().floor())))
            },
            "keys" => {
                validate!("keys", args, jptype![object]);
                Ok(Rc::new(args[0].object_keys_to_array().unwrap()))
            },
            "length" => {
                validate!("length", args, jptype![array|object|string]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::U64(a.len() as u64))),
                    Variable::Object(ref m) => Ok(Rc::new(Variable::U64(m.len() as u64))),
                    Variable::String(ref s) => Ok(Rc::new(Variable::U64(s.len() as u64))),
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "not_null" => {
                validate!("not_null", args, jptype![any] ...jptype![any]);
                for arg in args {
                    if **arg != Variable::Null {
                        return Ok(arg.clone());
                    }
                }
                Ok(Rc::new(Variable::Null))
            },
            "starts_with" => {
                validate!("starts_with", args, jptype![string], jptype![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.starts_with(search))))
            },
            "to_array" => {
                try!(arity("to_array", 1, args));
                match *args[0] {
                    Variable::Array(_) => Ok(args[0].clone()),
                    _ => Ok(Rc::new(Variable::Array(vec![args[0].clone()])))
                }
            },
            "to_number" => {
                try!(arity("to_number", 1, args));
                match *args[0] {
                    Variable::I64(_) | Variable::F64(_) | Variable::U64(_) => Ok(args[0].clone()),
                    Variable::String(ref s) => {
                        match s.parse::<f64>() {
                            Ok(f)  => Ok(Rc::new(Variable::F64(f))),
                            Err(_) => Ok(Rc::new(Variable::Null))
                        }
                    },
                    _ => Ok(Rc::new(Variable::Null))
                }
            },
            "type" => {
                try!(arity("type", 1, args));
                Ok(Rc::new(Variable::String(args[0].get_type().to_string())))
            },
            "values" => {
                validate!("values", args, jptype![object]);
                Ok(Rc::new(args[0].object_values_to_array().unwrap()))
            },
            _ => Err(format!("Unknown function: {}", fn_name))
        }
    }
}
<commit_msg>Adding more functions<commit_after>use std::rc::Rc;

use std::cmp::{max, min, Ordering};
use interpreter::InterpretResult;
use variable::Variable;

/// Handles the dispatching of named functions using an array of arguments.
pub trait FnDispatcher {
    /// Dispatches and interprets a function by name.
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>) -> InterpretResult;
}

/// Built-in function implementations.
#[derive(Clone)]
pub struct BuiltinFunctions;

impl BuiltinFunctions {
    /// Creates a new Builtins function dispatcher.
    pub fn new() -> BuiltinFunctions {
        BuiltinFunctions
    }
}

/// Validates the arity of a function.
#[inline]
fn arity(fn_name: &str, arity: usize, args: &Vec<Rc<Variable>>) -> Result<(), String> {
    if args.len() != arity {
        Err(format!("{} arity error: expected {} args, found {}", fn_name, arity, args.len()))
    } else {
        Ok(())
    }
}

fn homogeneous_array(valid_types: Vec<&str>, array: &Vec<Rc<Variable>>) -> bool {
    let matched_type = array[0].get_type();
    if !valid_types.contains(&matched_type) {
        return false;
    }
    for a in array {
        if a.get_type() != matched_type {
            return false;
        }
    }
    return true;
}

/// Macro used to format a type error.
macro_rules! type_err {
    ($f:expr, $position:expr, $expected:expr, $given:expr) => {
        format!("{} expects arg {} to be {}. Given {:?}", $f, $position, $expected, $given)
    }
}

/// Macro used to variadically validate validate Variable and argument arity.
macro_rules! validate {
    // Validate positional arguments only.
    ($name:expr, $args:expr, $($x:expr),*) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            try!(arity($name, validators.len(), $args));
            for (k, v) in $args.iter().enumerate() {
                if let Err(e) = validators[k](v) {
                    return Err(format!("{} error at argument {}: {}", $name, k, e));
                }
            }
        }
    );
    // Validate positional arguments with a variadic validator.
    ($name:expr, $args:expr, $($x:expr),* ...$variadic:expr ) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            if $args.len() < validators.len() {
                return Err(format!("{} arity error: expected at least {} args, found {}",
                                   $name, validators.len(), $args.len()));
            }
            for (k, v) in $args.iter().enumerate() {
                try!((match validators.get(k) {
                    Some(validator) => validator(v),
                    None => $variadic(v)
                }).or_else(|e| Err(format!("{} error at argument {}: {}", $name, k, e))));
            }
        }
    );
}

macro_rules! homogeneous {
    ($($x:ident)|*) => [
        Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
            let valid_types = vec![$(stringify!($x)), *];
            match **arg {
                Variable::Array(ref array) if array.is_empty() => Ok(()),
                Variable::Array(ref array) if homogeneous_array(valid_types, array) => Ok(()),
                _ => Err(format!("type array[{}]", valid_types.join("|")))
            }
        })
    ];
}

/// Creates a closure used to validate the type of the given variable.
macro_rules! jptype {
    // Validate a type against a single acceptable type.
    ($type_name:ident) => [
        Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
            let arg_type = arg.get_type();
            if arg_type != "any" && arg_type != stringify!($type_name) {
                Err(format!("type {}", stringify!($type_name)))
            } else {
                Ok(())
            }
        })
    ];
    // Validate a type against multiple acceptable types
    ($($x:ident)|*) => [
        {
            Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
                let valid_types = vec![$(stringify!($x)), *];
                let arg_type = arg.get_type();
                if arg_type != "any" && !valid_types.contains(&arg_type) {
                    Err(format!("type {}", valid_types.join("|")))
                } else {
                    Ok(())
                }
            })
        }
    ];
}

/// Macro used to implement min and max functions.
macro_rules! min_max {
    ($operator:ident, $args:expr) => (
        match *$args[0] {
            Variable::Array(ref array) if array.is_empty() => Ok(Rc::new(Variable::Null)),
            Variable::Array(ref array) => {
                if array[0].is_string() {
                    Ok(Rc::new(Variable::String(array.iter().fold(
                        array[0].as_string().unwrap().clone(),
                        |acc, item| $operator(acc, item.as_string().unwrap().clone())))))
                } else {
                    Ok(Rc::new(Variable::F64(array.iter().fold(
                        array[0].as_f64().unwrap(),
                        |acc, item| acc.$operator(item.as_f64().unwrap())))))
                }
            },
            _ => panic!() // never encountered due to previous validation
        }
    )
}

impl FnDispatcher for BuiltinFunctions {
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>) -> InterpretResult {
        match fn_name {
            "abs" => {
                validate!("abs", args, jptype![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().abs())))
            },
            "avg" => {
                try!(arity("avg", 1, args));
                args[0].as_array()
                    .and_then(|array| {
                        let mut total = 0f64;
                        for value in array {
                            match **value {
                                Variable::I64(n) => total += n as f64,
                                Variable::U64(n) => total += n as f64,
                                Variable::F64(n) => total += n,
                                _ => return None
                            }
                        }
                        Some(Rc::new(Variable::F64(total / array.len() as f64)))
                    })
                    .ok_or(type_err!("avg", 0, "array[number]", args[0]))
            },
            "ceil" => {
                validate!("ceil", args, jptype![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().ceil())))
            },
            "contains" => {
                validate!("contains", args, jptype![array|string], jptype![any]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::Boolean(a.contains(&args[1])))),
                    Variable::String(ref subj) => {
                        match args[1].as_string() {
                            Some(search) => Ok(Rc::new(Variable::Boolean(subj.contains(search)))),
                            None => Err(format!("contains found {:?} for string search arg",
                                                args[1]))
                        }
                    },
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "ends_with" => {
                validate!("ends_with", args, jptype![string], jptype![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.ends_with(search))))
            },
            "floor" => {
                validate!("floor", args, jptype![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().floor())))
            },
            "keys" => {
                validate!("keys", args, jptype![object]);
                Ok(Rc::new(args[0].object_keys_to_array().unwrap()))
            },
            "length" => {
                validate!("length", args, jptype![array|object|string]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::U64(a.len() as u64))),
                    Variable::Object(ref m) => Ok(Rc::new(Variable::U64(m.len() as u64))),
                    Variable::String(ref s) => Ok(Rc::new(Variable::U64(s.len() as u64))),
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "max" => {
                validate!("max", args, homogeneous![string|number]);
                min_max!(max, args)
            },
            "min" => {
                validate!("min", args, homogeneous![string|number]);
                min_max!(min, args)
            },
            "not_null" => {
                validate!("not_null", args, jptype![any] ...jptype![any]);
                for arg in args {
                    if **arg != Variable::Null {
                        return Ok(arg.clone());
                    }
                }
                Ok(Rc::new(Variable::Null))
            },
            "sort" => {
                validate!("sort", args, homogeneous![string|number]);
                let mut values: Vec<Rc<Variable>> = args[0].as_array().unwrap().clone();
                if values[0].is_string() {
                    values.sort_by(|a, b| a.as_string().unwrap().cmp(b.as_string().unwrap()));
                } else {
                    values.sort_by(|a, b| a.as_f64().unwrap()
                        .partial_cmp(&b.as_f64().unwrap())
                        .unwrap_or(Ordering::Equal));
                }
                Ok(Rc::new(Variable::Array(values)))
            },
            "starts_with" => {
                validate!("starts_with", args, jptype![string], jptype![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.starts_with(search))))
            },
            "sum" => {
                validate!("sum", args, homogeneous![number]);
                let array = args[0].as_array().unwrap();
                Ok(Rc::new(Variable::F64(array.iter().fold(
                    array[0].as_f64().unwrap().clone(),
                    |acc, item| acc.max(item.as_f64().unwrap())))))
            },
            "to_array" => {
                try!(arity("to_array", 1, args));
                match *args[0] {
                    Variable::Array(_) => Ok(args[0].clone()),
                    _ => Ok(Rc::new(Variable::Array(vec![args[0].clone()])))
                }
            },
            "to_number" => {
                try!(arity("to_number", 1, args));
                match *args[0] {
                    Variable::I64(_) | Variable::F64(_) | Variable::U64(_) => Ok(args[0].clone()),
                    Variable::String(ref s) => {
                        match s.parse::<f64>() {
                            Ok(f)  => Ok(Rc::new(Variable::F64(f))),
                            Err(_) => Ok(Rc::new(Variable::Null))
                        }
                    },
                    _ => Ok(Rc::new(Variable::Null))
                }
            },
            "type" => {
                try!(arity("type", 1, args));
                Ok(Rc::new(Variable::String(args[0].get_type().to_string())))
            },
            "values" => {
                validate!("values", args, jptype![object]);
                Ok(Rc::new(args[0].object_values_to_array().unwrap()))
            },
            _ => Err(format!("Unknown function: {}", fn_name))
        }
    }
}
<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// See the LICENSE file included in this distribution.

//! Generators.
//!
//! Generators allow repeatedly suspending the execution of a function,
//! returning a value to the caller, and resuming the suspended function
//! afterwards.

use core::marker::PhantomData;
use core::iter::Iterator;
use core::{ptr, mem};

use stack;
use context;

#[derive(Debug, Clone, Copy)]
pub enum State {
  /// Generator can be resumed. This is the initial state.
  Suspended,
  /// Generator cannot be resumed. This is the state of the generator after
  /// the generator function has returned.
  Finished
}

/// Generator wraps a function and allows suspending its execution more than
/// once, return a value each time.
///
/// It implements the Iterator trait. The first time `next()` is called,
/// the function is called as `f(yielder)`; every time `next()` is called afterwards,
/// the function is resumed. In either case, it runs until it suspends its execution
/// through `yielder.generate(val)`), in which case `next()` returns `Some(val)`, or
/// returns, in which case `next()` returns `None`. `next()` will return `None`
/// every time after that.
///
/// After the generator function returns, it is safe to reclaim the generator
/// stack using `unwrap()`.
///
/// `state()` can be used to determine whether the generator function has returned;
/// the state is `State::Suspended` after creation and suspension, and `State::Finished`
/// once the generator function returns.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut gen = Generator::new(stack, move |yielder| {
///   for i in 1..4 {
///     yielder.generate(i);
///   }
/// });
/// println!("{:?}", gen.next()); // prints Some(1)
/// println!("{:?}", gen.next()); // prints Some(2)
/// println!("{:?}", gen.next()); // prints Some(3)
/// println!("{:?}", gen.next()); // prints None
/// ```
#[derive(Debug)]
pub struct Generator<Item: Send, Stack: stack::Stack> {
  state:   State,
  context: context::Context<Stack>,
  phantom: PhantomData<Item>
}

impl<Item, Stack> Generator<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  /// Creates a new generator.
  pub fn new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
      where Stack: stack::GuardedStack, F: FnOnce(&mut Yielder<Item, Stack>) + Send {
    unsafe { Generator::unsafe_new(stack, f) }
  }

  /// Same as `new`, but does not require `stack` to have a guard page.
  ///
  /// This function is unsafe because the generator function can easily violate
  /// memory safety by overflowing the stack. It is useful in environments where
  /// guarded stacks do not exist, e.g. in absence of an MMU.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
      where F: FnOnce(&mut Yielder<Item, Stack>) + Send {
    unsafe extern "C" fn generator_wrapper<Item, Stack, F>(info: usize) -> !
        where Item: Send, Stack: stack::Stack, F: FnOnce(&mut Yielder<Item, Stack>) {
      // Retrieve our environment from the callee and return control to it.
      let (mut yielder, f) = ptr::read(info as *mut (Yielder<Item, Stack>, F));
      let new_context = context::Context::swap(yielder.context, yielder.context, 0);
      // See Yielder::return_.
      yielder.context = new_context as *mut context::Context<Stack>;
      // Run the body of the generator.
      f(&mut yielder);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.return_(None) }
    }

    let mut generator = Generator {
      state:   State::Suspended,
      context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>),
      phantom: PhantomData
    };

    // Transfer environment to the callee.
    let mut data = (Yielder::new(&mut generator.context), f);
    context::Context::swap(&mut generator.context, &generator.context,
                           &mut data as *mut (Yielder<Item, Stack>, F) as usize);
    mem::forget(data);

    generator
  }

  /// Returns the state of the generator.
  pub fn state(&self) -> State { self.state }

  /// Extracts the stack from a generator when the generator function has returned.
  /// If the generator function has not returned
  /// (i.e. `self.state() == State::Suspended`), panics.
  pub fn unwrap(self) -> Stack {
    match self.state {
      State::Suspended => panic!("Argh! Bastard! Don't touch that!"),
      State::Finished  => unsafe { self.context.unwrap() }
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Item: Send, Stack: stack::Stack> {
  context: *mut context::Context<Stack>,
  phantom: PhantomData<Item>
}

impl<Item, Stack> Yielder<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  fn new(context: *mut context::Context<Stack>) -> Yielder<Item, Stack> {
    Yielder {
      context: context,
      phantom: PhantomData
    }
  }

  #[inline(always)]
  fn return_(&mut self, mut val: Option<Item>) {
    unsafe {
      let new_context = context::Context::swap(self.context, self.context,
                                               &mut val as *mut Option<Item> as usize);
      // The generator can be moved (and with it, the context).
      // This changes the address of the context.
      // Thus, we update it after each swap.
      self.context = new_context as *mut context::Context<Stack>;
      // However, between this point and the next time we enter return_
      // the generator cannot be moved, as a &mut Generator is necessary
      // to resume the generator function.
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `next()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn generate(&mut self, item: Item) {
    self.return_(Some(item))
  }
}

impl<Item, Stack> Iterator for Generator<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  type Item = Item;

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  fn next(&mut self) -> Option<Self::Item> {
    match self.state {
      State::Suspended => {
        let new_context = &mut self.context as *mut context::Context<Stack> as usize;
        let val = unsafe {
          ptr::read(context::Context::swap(&mut self.context, &self.context, new_context)
                    as *mut Option<Item>)
        };
        if let None = val { self.state = State::Finished }
        val
      }
      State::Finished => None
    }
  }
}
<commit_msg>Add an inline hint on Generator::next().<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// See the LICENSE file included in this distribution.

//! Generators.
//!
//! Generators allow repeatedly suspending the execution of a function,
//! returning a value to the caller, and resuming the suspended function
//! afterwards.

use core::marker::PhantomData;
use core::iter::Iterator;
use core::{ptr, mem};

use stack;
use context;

#[derive(Debug, Clone, Copy)]
pub enum State {
  /// Generator can be resumed. This is the initial state.
  Suspended,
  /// Generator cannot be resumed. This is the state of the generator after
  /// the generator function has returned.
  Finished
}

/// Generator wraps a function and allows suspending its execution more than
/// once, return a value each time.
///
/// It implements the Iterator trait. The first time `next()` is called,
/// the function is called as `f(yielder)`; every time `next()` is called afterwards,
/// the function is resumed. In either case, it runs until it suspends its execution
/// through `yielder.generate(val)`), in which case `next()` returns `Some(val)`, or
/// returns, in which case `next()` returns `None`. `next()` will return `None`
/// every time after that.
///
/// After the generator function returns, it is safe to reclaim the generator
/// stack using `unwrap()`.
///
/// `state()` can be used to determine whether the generator function has returned;
/// the state is `State::Suspended` after creation and suspension, and `State::Finished`
/// once the generator function returns.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut gen = Generator::new(stack, move |yielder| {
///   for i in 1..4 {
///     yielder.generate(i);
///   }
/// });
/// println!("{:?}", gen.next()); // prints Some(1)
/// println!("{:?}", gen.next()); // prints Some(2)
/// println!("{:?}", gen.next()); // prints Some(3)
/// println!("{:?}", gen.next()); // prints None
/// ```
#[derive(Debug)]
pub struct Generator<Item: Send, Stack: stack::Stack> {
  state:   State,
  context: context::Context<Stack>,
  phantom: PhantomData<Item>
}

impl<Item, Stack> Generator<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  /// Creates a new generator.
  pub fn new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
      where Stack: stack::GuardedStack, F: FnOnce(&mut Yielder<Item, Stack>) + Send {
    unsafe { Generator::unsafe_new(stack, f) }
  }

  /// Same as `new`, but does not require `stack` to have a guard page.
  ///
  /// This function is unsafe because the generator function can easily violate
  /// memory safety by overflowing the stack. It is useful in environments where
  /// guarded stacks do not exist, e.g. in absence of an MMU.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
      where F: FnOnce(&mut Yielder<Item, Stack>) + Send {
    unsafe extern "C" fn generator_wrapper<Item, Stack, F>(info: usize) -> !
        where Item: Send, Stack: stack::Stack, F: FnOnce(&mut Yielder<Item, Stack>) {
      // Retrieve our environment from the callee and return control to it.
      let (mut yielder, f) = ptr::read(info as *mut (Yielder<Item, Stack>, F));
      let new_context = context::Context::swap(yielder.context, yielder.context, 0);
      // See Yielder::return_.
      yielder.context = new_context as *mut context::Context<Stack>;
      // Run the body of the generator.
      f(&mut yielder);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.return_(None) }
    }

    let mut generator = Generator {
      state:   State::Suspended,
      context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>),
      phantom: PhantomData
    };

    // Transfer environment to the callee.
    let mut data = (Yielder::new(&mut generator.context), f);
    context::Context::swap(&mut generator.context, &generator.context,
                           &mut data as *mut (Yielder<Item, Stack>, F) as usize);
    mem::forget(data);

    generator
  }

  /// Returns the state of the generator.
  pub fn state(&self) -> State { self.state }

  /// Extracts the stack from a generator when the generator function has returned.
  /// If the generator function has not returned
  /// (i.e. `self.state() == State::Suspended`), panics.
  pub fn unwrap(self) -> Stack {
    match self.state {
      State::Suspended => panic!("Argh! Bastard! Don't touch that!"),
      State::Finished  => unsafe { self.context.unwrap() }
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Item: Send, Stack: stack::Stack> {
  context: *mut context::Context<Stack>,
  phantom: PhantomData<Item>
}

impl<Item, Stack> Yielder<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  fn new(context: *mut context::Context<Stack>) -> Yielder<Item, Stack> {
    Yielder {
      context: context,
      phantom: PhantomData
    }
  }

  #[inline(always)]
  fn return_(&mut self, mut val: Option<Item>) {
    unsafe {
      let new_context = context::Context::swap(self.context, self.context,
                                               &mut val as *mut Option<Item> as usize);
      // The generator can be moved (and with it, the context).
      // This changes the address of the context.
      // Thus, we update it after each swap.
      self.context = new_context as *mut context::Context<Stack>;
      // However, between this point and the next time we enter return_
      // the generator cannot be moved, as a &mut Generator is necessary
      // to resume the generator function.
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `next()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn generate(&mut self, item: Item) {
    self.return_(Some(item))
  }
}

impl<Item, Stack> Iterator for Generator<Item, Stack>
    where Item: Send, Stack: stack::Stack {
  type Item = Item;

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  #[inline]
  fn next(&mut self) -> Option<Self::Item> {
    match self.state {
      State::Suspended => {
        let new_context = &mut self.context as *mut context::Context<Stack> as usize;
        let val = unsafe {
          ptr::read(context::Context::swap(&mut self.context, &self.context, new_context)
                    as *mut Option<Item>)
        };
        if let None = val { self.state = State::Finished }
        val
      }
      State::Finished => None
    }
  }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;

use moka::future::{Cache, CacheBuilder};
use serenity::http::Http;
use serenity::model::id::{ChannelId, GuildId, RoleId, UserId};
use serenity::model::Permissions;
use thiserror::Error;
use tokio::sync::RwLock;
use typemap_rev::TypeMapKey;

use crate::discord::util::get_permissions;

impl TypeMapKey for GuildService {
    type Value = GuildService;
}

pub struct CachedGuild {
    pub name: String,
    pub icon_url: Option<String>,
    pub owner_id: UserId,
}

pub struct CachedMember {
    pub roles: Vec<RoleId>,
}

pub struct CachedRole {
    pub name: String,
    pub permissions: Permissions,
}

pub struct CachedUser {
    pub tag: String,
    pub avatar_url: String,
}

pub struct CachedChannel {
    pub name: String,
}

pub struct GuildService {
    http: Arc<RwLock<Option<Arc<Http>>>>,
    guild_cache: Cache<GuildId, Arc<CachedGuild>>,
    role_cache: Cache<GuildId, Arc<HashMap<RoleId, CachedRole>>>,
    member_cache: Cache<(GuildId, UserId), Arc<CachedMember>>,
    user_cache: Cache<UserId, Arc<CachedUser>>,
    channel_cache: Cache<GuildId, Arc<HashMap<ChannelId, CachedChannel>>>,
}

pub enum GetPermissionsFailure {
    FetchFailed,
    Calculation,
}

#[derive(Error, Debug)]
pub enum GetGuildFailure {
    #[error("Fetch failed")]
    FetchFailed,
}

pub enum GetMemberFailure {
    FetchFailed,
}

#[derive(Error, Debug)]
pub enum GetUserFailure {
    #[error("Fetch failed")]
    FetchFailed,
}

pub enum GetRolesFailure {
    FetchFailed,
}

pub enum GetChannelsFailure {
    FetchFailed,
}

impl GuildService {
    pub fn new() -> GuildService {
        GuildService {
            http: Arc::new(RwLock::new(None)),
            guild_cache: CacheBuilder::new(100)
                .time_to_idle(Duration::from_secs(30))
                .time_to_live(Duration::from_secs(5 * 60))
                .build(),
            role_cache: CacheBuilder::new(100)
                .time_to_idle(Duration::from_secs(30))
                .time_to_live(Duration::from_secs(5 * 60))
                .build(),
            member_cache: CacheBuilder::new(500)
                .time_to_idle(Duration::from_secs(30))
                .time_to_live(Duration::from_secs(5 * 60))
                .build(),
            user_cache: CacheBuilder::new(500)
                .time_to_idle(Duration::from_secs(30))
                .time_to_live(Duration::from_secs(5 * 60))
                .build(),
            channel_cache: CacheBuilder::new(100)
                .time_to_idle(Duration::from_secs(30))
                .time_to_live(Duration::from_secs(60))
                .build(),
        }
    }

    pub async fn invalidate_cached_guild(&self, guild_id: GuildId) {
        self.guild_cache.invalidate(&guild_id).await;
    }

    pub async fn invalidate_cached_guild_roles(&self, guild_id: GuildId) {
        self.role_cache.invalidate(&guild_id).await;
    }

    pub async fn invalidate_cached_guild_member(&self, guild_id: GuildId, user_id: UserId) {
        self.member_cache.invalidate(&(guild_id, user_id)).await;
    }

    pub async fn invalidate_cached_user(&self, user_id: UserId) {
        self.user_cache.invalidate(&user_id).await;
    }

    pub async fn invalidate_cached_guild_channels(&self, guild_id: GuildId) {
        self.channel_cache.invalidate(&guild_id).await;
    }

    pub async fn http(&self) -> Arc<Http> {
        self.http
            .read()
            .await
            .as_ref()
            .expect("http client requested *before* it was inserted!")
            .clone()
    }

    pub async fn insert_http(&self, http: Arc<Http>) {
        self.http.write().await.replace(http);
    }

    pub async fn get_permissions(
        &self,
        member_id: UserId,
        member_roles: &[RoleId],
        guild_id: GuildId,
    ) -> Result<Permissions, GetPermissionsFailure> {
        let guild_roles = if let Ok(roles) = self.get_roles(guild_id).await {
            roles
        } else {
            return Err(GetPermissionsFailure::FetchFailed);
        };

        let guild_owner_id = match self.get_guild(guild_id).await {
            Ok(guild) => guild.owner_id,
            Err(_) => return Err(GetPermissionsFailure::FetchFailed),
        };

        get_permissions(
            member_id,
            member_roles,
            guild_id,
            &*guild_roles,
            guild_owner_id,
        )
        .ok_or(GetPermissionsFailure::Calculation)
    }

    pub async fn get_member(
        &self,
        guild_id: GuildId,
        user_id: UserId,
    ) -> Result<Arc<CachedMember>, GetMemberFailure> {
        let member = if let Some(cached_member) = self.member_cache.get(&(guild_id, user_id)) {
            cached_member
        } else if let Ok(fetched_member) = guild_id.member(&*self.http().await, user_id).await {
            let new_cached_member = Arc::new(CachedMember {
                roles: fetched_member.roles,
            });
            self.member_cache
                .insert((guild_id, user_id), new_cached_member.clone())
                .await;

            new_cached_member
        } else {
            return Err(GetMemberFailure::FetchFailed);
        };

        Ok(member)
    }

    pub async fn get_roles(
        &self,
        guild_id: GuildId,
    ) -> Result<Arc<HashMap<RoleId, CachedRole>>, GetRolesFailure> {
        let roles = if let Some(cached_roles) = self.role_cache.get(&guild_id) {
            cached_roles
        } else if let Ok(fetched_roles) = guild_id.roles(&*self.http().await).await {
            let new_cached_roles = Arc::new(
                fetched_roles
                    .into_iter()
                    .map(|(id, role)| {
                        (
                            id,
                            CachedRole {
                                name: role.name,
                                permissions: role.permissions,
                            },
                        )
                    })
                    .collect::<HashMap<RoleId, CachedRole>>(),
            );

            self.role_cache
                .insert(guild_id, new_cached_roles.clone())
                .await;
            new_cached_roles
        } else {
            return Err(GetRolesFailure::FetchFailed);
        };

        Ok(roles)
    }

    pub async fn get_channels(
        &self,
        guild_id: GuildId,
    ) -> Result<Arc<HashMap<ChannelId, CachedChannel>>, GetChannelsFailure> {
        let channels = if let Some(cached_channels) = self.channel_cache.get(&guild_id) {
            cached_channels
        } else if let Ok(fetched_channels) = guild_id.channels(&*self.http().await).await {
            let new_cached_channels = Arc::new(
                fetched_channels
                    .into_iter()
                    .map(|(id, channel)| (id, CachedChannel { name: channel.name }))
                    .collect::<HashMap<ChannelId, CachedChannel>>(),
            );
            self.channel_cache
                .insert(guild_id, new_cached_channels.clone())
                .await;
            new_cached_channels
        } else {
            return Err(GetChannelsFailure::FetchFailed);
        };

        Ok(channels)
    }

    pub async fn get_user(&self, user_id: UserId) -> Result<Arc<CachedUser>, GetUserFailure> {
        let user = if let Some(cached_user) = self.user_cache.get(&user_id) {
            cached_user
        } else if let Ok(fetched_user) = user_id.to_user(&*self.http().await).await {
            let new_cached_user = Arc::new(CachedUser {
                tag: fetched_user.tag(),
                avatar_url: fetched_user.face(),
            });
            self.user_cache
                .insert(user_id, new_cached_user.clone())
                .await;

            new_cached_user
        } else {
            return Err(GetUserFailure::FetchFailed);
        };

        Ok(user)
    }

    pub async fn get_guild(&self, guild_id: GuildId) -> Result<Arc<CachedGuild>, GetGuildFailure> {
        let guild = if let Some(cached_guild) = self.guild_cache.get(&guild_id) {
            cached_guild
        } else if let Ok(fetched_guild) = guild_id.to_partial_guild(&*self.http().await).await {
            let fetched_guild = Arc::new(CachedGuild {
                name: fetched_guild.name.clone(),
                icon_url: fetched_guild.icon_url(),
                owner_id: fetched_guild.owner_id,
            });

            self.guild_cache
                .insert(guild_id, fetched_guild.clone())
                .await;
            fetched_guild
        } else {
            return Err(GetGuildFailure::FetchFailed);
        };

        Ok(guild)
    }
}
<commit_msg>Cache more entities<commit_after>use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;

use moka::future::{Cache, CacheBuilder};
use serenity::http::Http;
use serenity::model::id::{ChannelId, GuildId, RoleId, UserId};
use serenity::model::Permissions;
use thiserror::Error;
use tokio::sync::RwLock;
use typemap_rev::TypeMapKey;

use crate::discord::util::get_permissions;

impl TypeMapKey for GuildService {
    type Value = GuildService;
}

pub struct CachedGuild {
    pub name: String,
    pub icon_url: Option<String>,
    pub owner_id: UserId,
}

pub struct CachedMember {
    pub roles: Vec<RoleId>,
}

pub struct CachedRole {
    pub name: String,
    pub permissions: Permissions,
}

pub struct CachedUser {
    pub tag: String,
    pub avatar_url: String,
}

pub struct CachedChannel {
    pub name: String,
}

pub struct GuildService {
    http: Arc<RwLock<Option<Arc<Http>>>>,
    guild_cache: Cache<GuildId, Arc<CachedGuild>>,
    role_cache: Cache<GuildId, Arc<HashMap<RoleId, CachedRole>>>,
    member_cache: Cache<(GuildId, UserId), Arc<CachedMember>>,
    user_cache: Cache<UserId, Arc<CachedUser>>,
    channel_cache: Cache<GuildId, Arc<HashMap<ChannelId, CachedChannel>>>,
}

pub enum GetPermissionsFailure {
    FetchFailed,
    Calculation,
}

#[derive(Error, Debug)]
pub enum GetGuildFailure {
    #[error("Fetch failed")]
    FetchFailed,
}

pub enum GetMemberFailure {
    FetchFailed,
}

#[derive(Error, Debug)]
pub enum GetUserFailure {
    #[error("Fetch failed")]
    FetchFailed,
}

pub enum GetRolesFailure {
    FetchFailed,
}

pub enum GetChannelsFailure {
    FetchFailed,
}

impl GuildService {
    pub fn new() -> GuildService {
        GuildService {
            http: Arc::new(RwLock::new(None)),
            guild_cache: CacheBuilder::new(1024)
                .time_to_idle(Duration::from_secs(2 * 60))
                .time_to_live(Duration::from_secs(5 * 60))
                .build(),
            role_cache: CacheBuilder::new(1024)
                .time_to_idle(Duration::from_secs(2 * 60))
                .time_to_live(Duration::from_secs(5 * 60))
                .build(),
            member_cache: CacheBuilder::new(2048)
                .time_to_idle(Duration::from_secs(2 * 60))
                .time_to_live(Duration::from_secs(5 * 60))
                .build(),
            user_cache: CacheBuilder::new(2048)
                .time_to_idle(Duration::from_secs(2 * 60))
                .time_to_live(Duration::from_secs(5 * 60))
                .build(),
            channel_cache: CacheBuilder::new(1024)
                .time_to_idle(Duration::from_secs(2 * 60))
                .time_to_live(Duration::from_secs(5 * 60))
                .build(),
        }
    }

    pub async fn invalidate_cached_guild(&self, guild_id: GuildId) {
        self.guild_cache.invalidate(&guild_id).await;
    }

    pub async fn invalidate_cached_guild_roles(&self, guild_id: GuildId) {
        self.role_cache.invalidate(&guild_id).await;
    }

    pub async fn invalidate_cached_guild_member(&self, guild_id: GuildId, user_id: UserId) {
        self.member_cache.invalidate(&(guild_id, user_id)).await;
    }

    pub async fn invalidate_cached_user(&self, user_id: UserId) {
        self.user_cache.invalidate(&user_id).await;
    }

    pub async fn invalidate_cached_guild_channels(&self, guild_id: GuildId) {
        self.channel_cache.invalidate(&guild_id).await;
    }

    pub async fn http(&self) -> Arc<Http> {
        self.http
            .read()
            .await
            .as_ref()
            .expect("http client requested *before* it was inserted!")
            .clone()
    }

    pub async fn insert_http(&self, http: Arc<Http>) {
        self.http.write().await.replace(http);
    }

    pub async fn get_permissions(
        &self,
        member_id: UserId,
        member_roles: &[RoleId],
        guild_id: GuildId,
    ) -> Result<Permissions, GetPermissionsFailure> {
        let guild_roles = if let Ok(roles) = self.get_roles(guild_id).await {
            roles
        } else {
            return Err(GetPermissionsFailure::FetchFailed);
        };

        let guild_owner_id = match self.get_guild(guild_id).await {
            Ok(guild) => guild.owner_id,
            Err(_) => return Err(GetPermissionsFailure::FetchFailed),
        };

        get_permissions(
            member_id,
            member_roles,
            guild_id,
            &*guild_roles,
            guild_owner_id,
        )
        .ok_or(GetPermissionsFailure::Calculation)
    }

    pub async fn get_member(
        &self,
        guild_id: GuildId,
        user_id: UserId,
    ) -> Result<Arc<CachedMember>, GetMemberFailure> {
        let member = if let Some(cached_member) = self.member_cache.get(&(guild_id, user_id)) {
            cached_member
        } else if let Ok(fetched_member) = guild_id.member(&*self.http().await, user_id).await {
            let new_cached_member = Arc::new(CachedMember {
                roles: fetched_member.roles,
            });
            self.member_cache
                .insert((guild_id, user_id), new_cached_member.clone())
                .await;

            new_cached_member
        } else {
            return Err(GetMemberFailure::FetchFailed);
        };

        Ok(member)
    }

    pub async fn get_roles(
        &self,
        guild_id: GuildId,
    ) -> Result<Arc<HashMap<RoleId, CachedRole>>, GetRolesFailure> {
        let roles = if let Some(cached_roles) = self.role_cache.get(&guild_id) {
            cached_roles
        } else if let Ok(fetched_roles) = guild_id.roles(&*self.http().await).await {
            let new_cached_roles = Arc::new(
                fetched_roles
                    .into_iter()
                    .map(|(id, role)| {
                        (
                            id,
                            CachedRole {
                                name: role.name,
                                permissions: role.permissions,
                            },
                        )
                    })
                    .collect::<HashMap<RoleId, CachedRole>>(),
            );

            self.role_cache
                .insert(guild_id, new_cached_roles.clone())
                .await;
            new_cached_roles
        } else {
            return Err(GetRolesFailure::FetchFailed);
        };

        Ok(roles)
    }

    pub async fn get_channels(
        &self,
        guild_id: GuildId,
    ) -> Result<Arc<HashMap<ChannelId, CachedChannel>>, GetChannelsFailure> {
        let channels = if let Some(cached_channels) = self.channel_cache.get(&guild_id) {
            cached_channels
        } else if let Ok(fetched_channels) = guild_id.channels(&*self.http().await).await {
            let new_cached_channels = Arc::new(
                fetched_channels
                    .into_iter()
                    .map(|(id, channel)| (id, CachedChannel { name: channel.name }))
                    .collect::<HashMap<ChannelId, CachedChannel>>(),
            );
            self.channel_cache
                .insert(guild_id, new_cached_channels.clone())
                .await;
            new_cached_channels
        } else {
            return Err(GetChannelsFailure::FetchFailed);
        };

        Ok(channels)
    }

    pub async fn get_user(&self, user_id: UserId) -> Result<Arc<CachedUser>, GetUserFailure> {
        let user = if let Some(cached_user) = self.user_cache.get(&user_id) {
            cached_user
        } else if let Ok(fetched_user) = user_id.to_user(&*self.http().await).await {
            let new_cached_user = Arc::new(CachedUser {
                tag: fetched_user.tag(),
                avatar_url: fetched_user.face(),
            });
            self.user_cache
                .insert(user_id, new_cached_user.clone())
                .await;

            new_cached_user
        } else {
            return Err(GetUserFailure::FetchFailed);
        };

        Ok(user)
    }

    pub async fn get_guild(&self, guild_id: GuildId) -> Result<Arc<CachedGuild>, GetGuildFailure> {
        let guild = if let Some(cached_guild) = self.guild_cache.get(&guild_id) {
            cached_guild
        } else if let Ok(fetched_guild) = guild_id.to_partial_guild(&*self.http().await).await {
            let fetched_guild = Arc::new(CachedGuild {
                name: fetched_guild.name.clone(),
                icon_url: fetched_guild.icon_url(),
                owner_id: fetched_guild.owner_id,
            });

            self.guild_cache
                .insert(guild_id, fetched_guild.clone())
                .await;
            fetched_guild
        } else {
            return Err(GetGuildFailure::FetchFailed);
        };

        Ok(guild)
    }
}
<|endoftext|>


<commit_before>use cranelift_module::*;
use crate::prelude::*;
use syntax::ast::Mutability as AstMutability;
use rustc::mir::interpret::{read_target_uint, AllocId, AllocType, ConstValue, GlobalId};
use rustc::ty::Const;
use rustc_mir::interpret::{CompileTimeEvaluator, Memory};

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        println!("done {:?}", self.done);
        for data_id in self.done.drain() {
            module.finalize_data(data_id);
        }
    }
}

pub fn codegen_static<'a, 'tcx: 'a, B: Backend>(cx: &mut CodegenCx<'a, 'tcx, B>, def_id: DefId) {
    cx.constants.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        })).unwrap();

    let const_ = force_eval_const(fx, const_);
    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx>,
    const_: &'tcx Const<'tcx>,
) -> &'tcx Const<'tcx> {
    match const_.val {
        ConstValue::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        _ => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    const_: &'tcx Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        TypeVariants::TyBool => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        TypeVariants::TyUint(_) => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        TypeVariants::TyInt(_) => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        TypeVariants::TyFnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(Instance::new(def_id, substs));
            CValue::Func(func_ref, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    const_: &'tcx Const<'tcx>,
) -> CPlace<'tcx> {
    let alloc = fx.tcx.const_value_to_allocation(const_);
    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&alloc_id.0.to_string(), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<B: Backend>(tcx: TyCtxt, module: &mut Module<B>, def_id: DefId) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    module
        .declare_data(&*symbol_name, Linkage::Export, false)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(types::I64, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    CPlace::Addr(global_ptr, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<CompileTimeEvaluator>::new(tcx.at(DUMMY_SP), ());

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id);
                (data_id, alloc)
            }
        };

        println!("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(
            alloc.bytes.to_vec().into_boxed_slice(),
            match alloc.runtime_mutability {
                AstMutability::Mutable => Writability::Writable,
                AstMutability::Immutable => Writability::Readonly,
            },
        );

        for &(offset, reloc) in alloc.relocations.iter() {
            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocType::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocType::Function(_) => unimplemented!("function static reference"),
                AllocType::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id)
                }
            };

            let reloc_offset = {
                let endianness = memory.endianness();
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}
<commit_msg>Rustfmt<commit_after>use cranelift_module::*;
use crate::prelude::*;
use rustc::mir::interpret::{read_target_uint, AllocId, AllocType, ConstValue, GlobalId};
use rustc::ty::Const;
use rustc_mir::interpret::{CompileTimeEvaluator, Memory};
use syntax::ast::Mutability as AstMutability;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        println!("done {:?}", self.done);
        for data_id in self.done.drain() {
            module.finalize_data(data_id);
        }
    }
}

pub fn codegen_static<'a, 'tcx: 'a, B: Backend>(cx: &mut CodegenCx<'a, 'tcx, B>, def_id: DefId) {
    cx.constants.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        })).unwrap();

    let const_ = force_eval_const(fx, const_);
    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx>,
    const_: &'tcx Const<'tcx>,
) -> &'tcx Const<'tcx> {
    match const_.val {
        ConstValue::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        _ => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    const_: &'tcx Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        TypeVariants::TyBool => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        TypeVariants::TyUint(_) => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        TypeVariants::TyInt(_) => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        TypeVariants::TyFnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(Instance::new(def_id, substs));
            CValue::Func(func_ref, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    const_: &'tcx Const<'tcx>,
) -> CPlace<'tcx> {
    let alloc = fx.tcx.const_value_to_allocation(const_);
    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&alloc_id.0.to_string(), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<B: Backend>(tcx: TyCtxt, module: &mut Module<B>, def_id: DefId) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    module
        .declare_data(&*symbol_name, Linkage::Export, false)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(types::I64, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    CPlace::Addr(global_ptr, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<CompileTimeEvaluator>::new(tcx.at(DUMMY_SP), ());

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id);
                (data_id, alloc)
            }
        };

        println!("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(
            alloc.bytes.to_vec().into_boxed_slice(),
            match alloc.runtime_mutability {
                AstMutability::Mutable => Writability::Writable,
                AstMutability::Immutable => Writability::Readonly,
            },
        );

        for &(offset, reloc) in alloc.relocations.iter() {
            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocType::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocType::Function(_) => unimplemented!("function static reference"),
                AllocType::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id)
                }
            };

            let reloc_offset = {
                let endianness = memory.endianness();
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}
<|endoftext|>


<commit_before>//use serde;
// use serde::de::Deserialize;
// #![feature(custom_derive, plugin)]
// #![plugin(serde_macros)]

extern crate serde_json;
extern crate serde;

use serde_json::Value;

use std::collections;
use std::collections::BTreeMap;
use std::fmt::Debug;

// --------------------------------------------------------
// root obj.  contains controls.
// --------------------------------------------------------

// root is not itself a Control!  although maybe it should be?
#[derive(Debug)]
pub struct Root {
  pub title: String,
  pub rootControl: Box<Control>,
}

pub fn deserializeRoot(data: &Value) -> Option<Box<Root>>
{
  let obj = data.as_object().unwrap();
  let title = obj.get("title").unwrap().as_string().unwrap();

  let rc = obj.get("rootControl").unwrap();

  let rootcontrol = deserializeControl(Vec::new(), rc).unwrap();

  Some(Box::new(Root { title: String::new() + title, rootControl: rootcontrol }))
}

// --------------------------------------------------------
// controls.
// --------------------------------------------------------

pub trait Control : Debug + Send {
  fn controlType(&self) -> &'static str;
  fn controlId(&self) -> &Vec<i32>;
  fn cloneTrol(&self) -> Box<Control>;
  fn subControls(&self) -> Option<&Vec<Box<Control>>>;
  fn update(&mut self, &UpdateMsg);
  fn oscname(&self) -> &str;
}

#[derive(Debug)]
pub struct Slider {
  controlId: Vec<i32>,
  name: String,
  pressed: bool,
  location: f32,
}

impl Control for Slider {
  fn controlType(&self) -> &'static str { "slider" }
  fn controlId(&self) -> &Vec<i32> { &self.controlId }
  fn cloneTrol(&self) -> Box<Control> {
    Box::new(
      Slider { controlId: self.controlId.clone(),
               name: self.name.clone(),
               pressed: self.pressed.clone(),
               location: self.location.clone() } ) }
  fn subControls(&self) -> Option<&Vec<Box<Control>>> { None }
  fn update(&mut self, um: &UpdateMsg) {
    match um {
      &UpdateMsg::Slider { controlId: _, updateType: ref ut, location: l} => {
        self.pressed = match ut { &SliderUpType::Moved => true, &SliderUpType::Pressed => true, &SliderUpType::Unpressed => false };
        self.location = l as f32;
        ()
        }
      _ => ()
      }
    }
  fn oscname(&self) -> &str { &self.name[..] }
}

#[derive(Debug)]
pub struct Button {
  controlId: Vec<i32>,
  name: String,
  pressed: bool,
}

impl Control for Button {
  fn controlType(&self) -> &'static str { "button" }
  fn controlId(&self) -> &Vec<i32> { &self.controlId }
  fn cloneTrol(&self) -> Box<Control> {
    Box::new(
      Button { controlId: self.controlId.clone(),
              name: self.name.clone(),
              pressed: self.pressed.clone() } ) }
  fn subControls(&self) -> Option<&Vec<Box<Control>>> { None }
  fn update(&mut self, um: &UpdateMsg) {
    match um {
      &UpdateMsg::Button { controlId: _, updateType: ref ut } => {
        self.pressed = match ut { &ButtonUpType::Pressed => true, &ButtonUpType::Unpressed => false };
        ()
        }
      _ => ()
      }
    }
  fn oscname(&self) -> &str { &self.name[..] }
}

//#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Sizer {
  controlId: Vec<i32>,
  controls: Vec<Box<Control>>,
}

impl Control for Sizer {
  fn controlType(&self) -> &'static str { "sizer" }
  fn controlId(&self) -> &Vec<i32> { &self.controlId }
  fn cloneTrol(&self) -> Box<Control> {
    Box::new(
      Sizer { controlId: self.controlId.clone(),
              controls: Vec::new() } ) }
  fn subControls(&self) -> Option<&Vec<Box<Control>>> { Some(&self.controls) }
  fn update(&mut self, um: &UpdateMsg) {}
  fn oscname(&self) -> &str { "" }
}

fn deserializeControl(aVId: Vec<i32>, data: &Value) -> Option<Box<Control>>
{
  // what's the type?
  let obj = data.as_object().unwrap();
  let objtype =
    obj.get("type").unwrap().as_string().unwrap();

  match objtype {
    "slider" => {
      let name = obj.get("name").unwrap().as_string().unwrap();
      Some(Box::new(Slider { controlId: aVId.clone(), name: String::new() + name, pressed: false, location: 0.5 }))
    },
    "button" => {
      let name = obj.get("name").unwrap().as_string().unwrap();
      Some(Box::new(Button { controlId: aVId.clone(), name: String::new() + name, pressed: false }))
    },
    "sizer" => {
      let name = obj.get("name").unwrap().as_string().unwrap();
      let controls = obj.get("controls").unwrap().as_array().unwrap();

      let mut controlv = Vec::new();

      for (i, v) in controls.into_iter().enumerate() {
          let mut id = aVId.clone();
          id.push(i as i32);
          let c = deserializeControl(id, v).unwrap();
          controlv.push(c);
          }
      // loop through controls, makin controls.
      Some(Box::new(Sizer { controlId: aVId.clone(), controls: controlv }))
    },
    _ => None,
  }
}

// --------------------------------------------------------
// control update messages.
// --------------------------------------------------------

/*

i  JE.object [ ("controlType", JE.string "button")
            , ("controlId", SvgThings.encodeControlId um.controlId)
            , ("updateType", encodeUpdateType um.updateType)
            ]

  JE.object [ ("controlType", JE.string "slider")
            , ("controlId", SvgThings.encodeControlId um.controlId)
            , ("updateType", encodeUpdateType um.updateType)
            , ("location", (JE.float um.location))

*/
macro_rules! try_opt {
  ($e: expr) => {
    match $e {
      Some(x) => x,
      None => return None
      }
  }
}

pub enum ButtonUpType {
  Pressed,
  Unpressed
  }

pub enum SliderUpType {
  Pressed,
  Moved,
  Unpressed
  }

pub enum UpdateMsg {
  Button  { controlId: Vec<i32>
          , updateType: ButtonUpType
          },
  Slider  { controlId: Vec<i32>
          , updateType: SliderUpType
          , location: f64
          }
}

pub fn getUmId(um: &UpdateMsg) -> &Vec<i32> {
  match um {
    &UpdateMsg::Button { controlId: ref cid, updateType: _ } => &cid,
    &UpdateMsg::Slider { controlId: ref cid, updateType: _, location: _ } => &cid,
    }
}

fn convi32array(inp: &Vec<i32>) -> Vec<Value> {
  inp.into_iter().map(|x|{Value::I64(*x as i64)}).collect()
}

fn convarrayi32(inp: &Vec<Value>) -> Vec<i32> {
  inp.into_iter().map(|x|{x.as_i64().unwrap() as i32}).collect()
}

pub fn encodeUpdateMessage(um: &UpdateMsg) -> Value {
  match um {
    &UpdateMsg::Button { controlId: ref cid, updateType: ref ut } => {
      let mut btv = BTreeMap::new();
      btv.insert(String::from("controlType"), Value::String(String::from("button")));
      btv.insert(String::from("controlId"), Value::Array(convi32array(cid)));
      btv.insert(String::from("updateType"),
        Value::String(String::from(
          (match ut { &ButtonUpType::Pressed => "Press",
                      &ButtonUpType::Unpressed => "Unpress" }))));
      Value::Object(btv)
    },
    &UpdateMsg::Slider { controlId: ref cid, updateType: ref ut, location: ref loc } => {
      let mut btv = BTreeMap::new();
      btv.insert(String::from("controlType"), Value::String(String::from("slider")));
      btv.insert(String::from("controlId"), Value::Array(convi32array(cid)));
      btv.insert(String::from("updateType"),
        Value::String(String::from(
          (match ut { &SliderUpType::Pressed => "Press",
                      &SliderUpType::Moved => "Move",
                      &SliderUpType::Unpressed => "Unpress" }))));
      btv.insert(String::from("location"), Value::F64(*loc));
      Value::Object(btv)
    },
  }
}

pub fn decodeUpdateMessage(data: &Value) -> Option<UpdateMsg> {
  let obj = try_opt!(data.as_object());

  let contype = try_opt!(try_opt!(obj.get("controlType")).as_string());
  let conid = convarrayi32(try_opt!(try_opt!(obj.get("controlId")).as_array()));
  let utstring = try_opt!(try_opt!(obj.get("updateType")).as_string());

  match contype {
    "slider" => {
      let location = try_opt!(try_opt!(obj.get("location")).as_f64());
      let ut = try_opt!(match utstring
        { "Press" => Some( SliderUpType::Pressed )
        , "Move" => Some( SliderUpType::Moved )
        , "Unpress" => Some( SliderUpType::Unpressed )
        , _ => None
        });
      Some( UpdateMsg::Slider { controlId: conid, updateType: ut, location: location } )
      },
    "button" => {
      let ut = try_opt!(match utstring
        { "Press" => Some( ButtonUpType::Pressed )
        , "Unpress" => Some( ButtonUpType::Unpressed )
        , _ => None
        });

      Some( UpdateMsg::Button { controlId: conid, updateType: ut } )
      },
    _ => None
    }
}

// --------------------------------------------------------
// control state map.  copies all the controls.
// --------------------------------------------------------

pub type controlMap = BTreeMap<Vec<i32>,Box<Control>>;

pub fn makeControlMap (control: &Control) -> controlMap {
  let mut btm = BTreeMap::new();

  makeControlMap_impl(control, btm)
}

fn makeControlMap_impl (control: &Control, mut map: controlMap)
  -> controlMap
{
  map.insert(control.controlId().clone(), control.cloneTrol());

  match control.subControls() {
    Some(trols) => {
      let mut item = trols.into_iter();

      loop {
          match item.next() {
            Some(x) => {
              map = makeControlMap_impl(&**x, map)
              },
            None => { break },
          }
        }
      }
    None => {}
    }

  map
}

pub type controlNameMap = BTreeMap<String, Vec<i32>>;

pub fn controlMapToNameMap(cmap: &controlMap) -> controlNameMap
{
  let mut iter = cmap.iter();
  let mut cnm = BTreeMap::new();

  loop {
    match iter.next() {
      Some((key,val)) => {
        let s = String::new() + &*val.oscname();
        cnm.insert(s, key.clone());
        ()
      },
      None => break
    }
  }

  cnm
}

<commit_msg>go with String::from<commit_after>//use serde;
// use serde::de::Deserialize;
// #![feature(custom_derive, plugin)]
// #![plugin(serde_macros)]

extern crate serde_json;
extern crate serde;

use serde_json::Value;

use std::collections;
use std::collections::BTreeMap;
use std::fmt::Debug;

// --------------------------------------------------------
// root obj.  contains controls.
// --------------------------------------------------------

// root is not itself a Control!  although maybe it should be?
#[derive(Debug)]
pub struct Root {
  pub title: String,
  pub rootControl: Box<Control>,
}

pub fn deserializeRoot(data: &Value) -> Option<Box<Root>>
{
  let obj = data.as_object().unwrap();
  let title = obj.get("title").unwrap().as_string().unwrap();

  let rc = obj.get("rootControl").unwrap();

  let rootcontrol = deserializeControl(Vec::new(), rc).unwrap();

  Some(Box::new(Root { title: String::from(title), rootControl: rootcontrol }))
}

// --------------------------------------------------------
// controls.
// --------------------------------------------------------

pub trait Control : Debug + Send {
  fn controlType(&self) -> &'static str;
  fn controlId(&self) -> &Vec<i32>;
  fn cloneTrol(&self) -> Box<Control>;
  fn subControls(&self) -> Option<&Vec<Box<Control>>>;
  fn update(&mut self, &UpdateMsg);
  fn oscname(&self) -> &str;
}

#[derive(Debug)]
pub struct Slider {
  controlId: Vec<i32>,
  name: String,
  pressed: bool,
  location: f32,
}

impl Control for Slider {
  fn controlType(&self) -> &'static str { "slider" }
  fn controlId(&self) -> &Vec<i32> { &self.controlId }
  fn cloneTrol(&self) -> Box<Control> {
    Box::new(
      Slider { controlId: self.controlId.clone(),
               name: self.name.clone(),
               pressed: self.pressed.clone(),
               location: self.location.clone() } ) }
  fn subControls(&self) -> Option<&Vec<Box<Control>>> { None }
  fn update(&mut self, um: &UpdateMsg) {
    match um {
      &UpdateMsg::Slider { controlId: _, updateType: ref ut, location: l} => {
        self.pressed = match ut { &SliderUpType::Moved => true, &SliderUpType::Pressed => true, &SliderUpType::Unpressed => false };
        self.location = l as f32;
        ()
        }
      _ => ()
      }
    }
  fn oscname(&self) -> &str { &self.name[..] }
}

#[derive(Debug)]
pub struct Button {
  controlId: Vec<i32>,
  name: String,
  pressed: bool,
}

impl Control for Button {
  fn controlType(&self) -> &'static str { "button" }
  fn controlId(&self) -> &Vec<i32> { &self.controlId }
  fn cloneTrol(&self) -> Box<Control> {
    Box::new(
      Button { controlId: self.controlId.clone(),
              name: self.name.clone(),
              pressed: self.pressed.clone() } ) }
  fn subControls(&self) -> Option<&Vec<Box<Control>>> { None }
  fn update(&mut self, um: &UpdateMsg) {
    match um {
      &UpdateMsg::Button { controlId: _, updateType: ref ut } => {
        self.pressed = match ut { &ButtonUpType::Pressed => true, &ButtonUpType::Unpressed => false };
        ()
        }
      _ => ()
      }
    }
  fn oscname(&self) -> &str { &self.name[..] }
}

//#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Sizer {
  controlId: Vec<i32>,
  controls: Vec<Box<Control>>,
}

impl Control for Sizer {
  fn controlType(&self) -> &'static str { "sizer" }
  fn controlId(&self) -> &Vec<i32> { &self.controlId }
  fn cloneTrol(&self) -> Box<Control> {
    Box::new(
      Sizer { controlId: self.controlId.clone(),
              controls: Vec::new() } ) }
  fn subControls(&self) -> Option<&Vec<Box<Control>>> { Some(&self.controls) }
  fn update(&mut self, um: &UpdateMsg) {}
  fn oscname(&self) -> &str { "" }
}

fn deserializeControl(aVId: Vec<i32>, data: &Value) -> Option<Box<Control>>
{
  // what's the type?
  let obj = data.as_object().unwrap();
  let objtype =
    obj.get("type").unwrap().as_string().unwrap();

  match objtype {
    "slider" => {
      let name = obj.get("name").unwrap().as_string().unwrap();
      Some(Box::new(Slider { controlId: aVId.clone(), name: String::from(name), pressed: false, location: 0.5 }))
    },
    "button" => {
      let name = obj.get("name").unwrap().as_string().unwrap();
      Some(Box::new(Button { controlId: aVId.clone(), name: String::from(name), pressed: false }))
    },
    "sizer" => {
      let name = obj.get("name").unwrap().as_string().unwrap();
      let controls = obj.get("controls").unwrap().as_array().unwrap();

      let mut controlv = Vec::new();

      for (i, v) in controls.into_iter().enumerate() {
          let mut id = aVId.clone();
          id.push(i as i32);
          let c = deserializeControl(id, v).unwrap();
          controlv.push(c);
          }
      // loop through controls, makin controls.
      Some(Box::new(Sizer { controlId: aVId.clone(), controls: controlv }))
    },
    _ => None,
  }
}

// --------------------------------------------------------
// control update messages.
// --------------------------------------------------------

/*

i  JE.object [ ("controlType", JE.string "button")
            , ("controlId", SvgThings.encodeControlId um.controlId)
            , ("updateType", encodeUpdateType um.updateType)
            ]

  JE.object [ ("controlType", JE.string "slider")
            , ("controlId", SvgThings.encodeControlId um.controlId)
            , ("updateType", encodeUpdateType um.updateType)
            , ("location", (JE.float um.location))

*/
macro_rules! try_opt {
  ($e: expr) => {
    match $e {
      Some(x) => x,
      None => return None
      }
  }
}

pub enum ButtonUpType {
  Pressed,
  Unpressed
  }

pub enum SliderUpType {
  Pressed,
  Moved,
  Unpressed
  }

pub enum UpdateMsg {
  Button  { controlId: Vec<i32>
          , updateType: ButtonUpType
          },
  Slider  { controlId: Vec<i32>
          , updateType: SliderUpType
          , location: f64
          }
}

pub fn getUmId(um: &UpdateMsg) -> &Vec<i32> {
  match um {
    &UpdateMsg::Button { controlId: ref cid, updateType: _ } => &cid,
    &UpdateMsg::Slider { controlId: ref cid, updateType: _, location: _ } => &cid,
    }
}

fn convi32array(inp: &Vec<i32>) -> Vec<Value> {
  inp.into_iter().map(|x|{Value::I64(*x as i64)}).collect()
}

fn convarrayi32(inp: &Vec<Value>) -> Vec<i32> {
  inp.into_iter().map(|x|{x.as_i64().unwrap() as i32}).collect()
}

pub fn encodeUpdateMessage(um: &UpdateMsg) -> Value {
  match um {
    &UpdateMsg::Button { controlId: ref cid, updateType: ref ut } => {
      let mut btv = BTreeMap::new();
      btv.insert(String::from("controlType"), Value::String(String::from("button")));
      btv.insert(String::from("controlId"), Value::Array(convi32array(cid)));
      btv.insert(String::from("updateType"),
        Value::String(String::from(
          (match ut { &ButtonUpType::Pressed => "Press",
                      &ButtonUpType::Unpressed => "Unpress" }))));
      Value::Object(btv)
    },
    &UpdateMsg::Slider { controlId: ref cid, updateType: ref ut, location: ref loc } => {
      let mut btv = BTreeMap::new();
      btv.insert(String::from("controlType"), Value::String(String::from("slider")));
      btv.insert(String::from("controlId"), Value::Array(convi32array(cid)));
      btv.insert(String::from("updateType"),
        Value::String(String::from(
          (match ut { &SliderUpType::Pressed => "Press",
                      &SliderUpType::Moved => "Move",
                      &SliderUpType::Unpressed => "Unpress" }))));
      btv.insert(String::from("location"), Value::F64(*loc));
      Value::Object(btv)
    },
  }
}

pub fn decodeUpdateMessage(data: &Value) -> Option<UpdateMsg> {
  let obj = try_opt!(data.as_object());

  let contype = try_opt!(try_opt!(obj.get("controlType")).as_string());
  let conid = convarrayi32(try_opt!(try_opt!(obj.get("controlId")).as_array()));
  let utstring = try_opt!(try_opt!(obj.get("updateType")).as_string());

  match contype {
    "slider" => {
      let location = try_opt!(try_opt!(obj.get("location")).as_f64());
      let ut = try_opt!(match utstring
        { "Press" => Some( SliderUpType::Pressed )
        , "Move" => Some( SliderUpType::Moved )
        , "Unpress" => Some( SliderUpType::Unpressed )
        , _ => None
        });
      Some( UpdateMsg::Slider { controlId: conid, updateType: ut, location: location } )
      },
    "button" => {
      let ut = try_opt!(match utstring
        { "Press" => Some( ButtonUpType::Pressed )
        , "Unpress" => Some( ButtonUpType::Unpressed )
        , _ => None
        });

      Some( UpdateMsg::Button { controlId: conid, updateType: ut } )
      },
    _ => None
    }
}

// --------------------------------------------------------
// control state map.  copies all the controls.
// --------------------------------------------------------

pub type controlMap = BTreeMap<Vec<i32>,Box<Control>>;

pub fn makeControlMap (control: &Control) -> controlMap {
  let mut btm = BTreeMap::new();

  makeControlMap_impl(control, btm)
}

fn makeControlMap_impl (control: &Control, mut map: controlMap)
  -> controlMap
{
  map.insert(control.controlId().clone(), control.cloneTrol());

  match control.subControls() {
    Some(trols) => {
      let mut item = trols.into_iter();

      loop {
          match item.next() {
            Some(x) => {
              map = makeControlMap_impl(&**x, map)
              },
            None => { break },
          }
        }
      }
    None => {}
    }

  map
}

pub type controlNameMap = BTreeMap<String, Vec<i32>>;

pub fn controlMapToNameMap(cmap: &controlMap) -> controlNameMap
{
  let mut iter = cmap.iter();
  let mut cnm = BTreeMap::new();

  loop {
    match iter.next() {
      Some((key,val)) => {
        let s = String::from(&*val.oscname());
        cnm.insert(s, key.clone());
        ()
      },
      None => break
    }
  }

  cnm
}

<|endoftext|>


<commit_before>use vec_map::VecMap;
use terrain::quadtree::{Node, NodeId};

#[derive(Clone, Copy, PartialEq, PartialOrd)]
pub struct Priority(f32);
impl Priority {
    pub fn cutoff() -> Self {
        Priority(1.0)
    }
    pub fn none() -> Self {
        Priority(-1.0)
    }
    pub fn from_f32(value: f32) -> Self {
        assert!(value.is_finite());
        Priority(value)
    }
}
impl Eq for Priority {}
impl Ord for Priority {
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

pub(crate) struct TileCache {
    /// Maximum number of slots in this `TileCache`.
    size: usize,
    /// Actually contents of the cache.
    slots: Vec<(Priority, NodeId)>,
    /// Which index each node is at in the cache (if any).
    reverse: VecMap<usize>,
    /// Nodes that should be added to the cache.
    missing: Vec<(Priority, NodeId)>,
    /// Smallest priority among all nodes in the cache.
    min_priority: Priority,
}
impl TileCache {
    pub fn new(size: usize) -> Self {
        Self {
            size,
            slots: Vec::new(),
            reverse: VecMap::new(),
            missing: Vec::new(),
            min_priority: Priority::none(),
        }
    }

    pub fn update_priorities(&mut self, nodes: &mut Vec<Node>) {
        for &mut (ref mut priority, id) in self.slots.iter_mut() {
            *priority = nodes[id].priority();
        }

        self.min_priority = self.slots.iter().map(|s| s.0).min().unwrap_or(
            Priority::none(),
        );
    }

    pub fn add_missing(&mut self, element: (Priority, NodeId)) {
        if element.0 > self.min_priority || self.slots.len() < self.size {
            self.missing.push(element);
        }
    }

    pub fn load_missing(&mut self, nodes: &mut Vec<Node>) {
        self.missing.sort();

        while self.slots.len() < self.size {
            if self.missing.is_empty() {
                return;
            }
            let index = self.slots.len();
            let id = self.missing.pop().unwrap().1;
            self.load(id, &mut nodes[id], index);
        }

        let mut index = 0;
        while let Some((priority, id)) = self.missing.pop() {
            while index < self.slots.len() && self.slots[index].0 >= priority {
                index += 1;
            }

            if self.slots[index].0 < priority {
                self.load(id, &mut nodes[id], index);
                index += 1;
            } else {
                // The cache is full and all the tiles in the cache have higher
                // priority than the remaining missing tiles. Give up loading the rest.
                self.missing.clear();
                return;
            }
        }
    }

    fn load(&mut self, id: NodeId, _node: &mut Node, slot: usize) {
        if slot < self.slots.len() {
            self.reverse.remove(self.slots[slot].1.index());
        }
        self.reverse.insert(id.index(), slot);
        unimplemented!()
    }

    pub fn contains(&self, id: NodeId) -> bool {
        self.reverse.contains_key(id.index())
    }
}
<commit_msg>Fix tile cache eviction<commit_after>use vec_map::VecMap;
use terrain::quadtree::{Node, NodeId};

#[derive(Clone, Copy, PartialEq, PartialOrd)]
pub struct Priority(f32);
impl Priority {
    pub fn cutoff() -> Self {
        Priority(1.0)
    }
    pub fn none() -> Self {
        Priority(-1.0)
    }
    pub fn from_f32(value: f32) -> Self {
        assert!(value.is_finite());
        Priority(value)
    }
}
impl Eq for Priority {}
impl Ord for Priority {
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

pub(crate) struct TileCache {
    /// Maximum number of slots in this `TileCache`.
    size: usize,
    /// Actually contents of the cache.
    slots: Vec<(Priority, NodeId)>,
    /// Which index each node is at in the cache (if any).
    reverse: VecMap<usize>,
    /// Nodes that should be added to the cache.
    missing: Vec<(Priority, NodeId)>,
    /// Smallest priority among all nodes in the cache.
    min_priority: Priority,
}
impl TileCache {
    pub fn new(size: usize) -> Self {
        Self {
            size,
            slots: Vec::new(),
            reverse: VecMap::new(),
            missing: Vec::new(),
            min_priority: Priority::none(),
        }
    }

    pub fn update_priorities(&mut self, nodes: &mut Vec<Node>) {
        for &mut (ref mut priority, id) in self.slots.iter_mut() {
            *priority = nodes[id].priority();
        }

        self.min_priority = self.slots.iter().map(|s| s.0).min().unwrap_or(
            Priority::none(),
        );
    }

    pub fn add_missing(&mut self, element: (Priority, NodeId)) {
        if element.0 > self.min_priority || self.slots.len() < self.size {
            self.missing.push(element);
        }
    }

    pub fn load_missing(&mut self, nodes: &mut Vec<Node>) {
        if self.slots.len() + self.missing.len() < self.size {
            while let Some(m) = self.missing.pop() {
                let index = self.slots.len();
                self.load(m.1, &mut nodes[m.1], index);
            }
        } else {
            let mut possible: Vec<_> = self.slots
                .iter()
                .cloned()
                .chain(self.missing.iter().cloned())
                .collect();
            possible.sort();

            // Anything >= to cutoff should be included.
            let cutoff = possible[possible.len() - self.size];

            let mut index = 0;
            while let Some(m) = self.missing.pop() {
                if cutoff >= m {
                    continue;
                }

                // Find the next element to evict.
                while self.slots[index] >= cutoff {
                    index += 1;
                }

                self.load(m.1, &mut nodes[m.1], index);
                index += 1;
            }
        }
    }

    fn load(&mut self, id: NodeId, _node: &mut Node, slot: usize) {
        if slot < self.slots.len() {
            self.reverse.remove(self.slots[slot].1.index());
        }
        self.reverse.insert(id.index(), slot);
        unimplemented!()
    }

    pub fn contains(&self, id: NodeId) -> bool {
        self.reverse.contains_key(id.index())
    }
}
<|endoftext|>