<commit_before>#![crate_name = "rust-hl-lua"]
#![crate_type = "lib"]
#![comment = "Lua bindings for Rust"]
#![license = "MIT"]
#![allow(visible_private_types)]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]

extern crate libc;

use std::kinds::marker::ContravariantLifetime;

pub use lua_tables::LuaTable;

pub mod any;
pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod ffi;
mod functions_write;
mod rust_tables;
mod tuples;
mod values;

/// Main object of the library.
/// The lifetime parameter corresponds to the lifetime of the Lua object itself.
#[unstable]
pub struct Lua<'lua> {
    lua: *mut ffi::lua_State,
    marker: ContravariantLifetime<'lua>,
    must_be_closed: bool,
    inside_callback: bool           // if true, we are inside a callback
}

/// Object which allows access to a Lua variable.
struct LoadedVariable<'var, 'lua> {
    lua: &'var mut Lua<'lua>,
    size: uint       // number of elements at the top of the stack
}

/// Should be implemented by whatever type is pushable on the Lua stack
#[unstable]
pub trait Pushable<'lua>: ::std::any::Any {
    /// Pushes the value on the top of the stack.
    /// Must return the number of elements pushed.
    ///
    /// You can implement this for any type you want by redirecting to call to
    /// another implementation (for example 5.push_to_lua) or by calling userdata::push_userdata
    fn push_to_lua(self, lua: &mut Lua<'lua>) -> uint;
}

/// Should be implemented by types that can be read by consomming a LoadedVariable
#[unstable]
pub trait ConsumeReadable<'a, 'lua> {
    /// Returns the LoadedVariable in case of failure.
    fn read_from_variable(var: LoadedVariable<'a, 'lua>) -> Result<Self, LoadedVariable<'a, 'lua>>;
}

/// Should be implemented by whatever type can be read by copy from the Lua stack
#[unstable]
pub trait CopyReadable : Clone + ::std::any::Any {
    /// Reads an object from the Lua stack.
    ///
    /// Similar to Pushable, you can implement this trait for your own types either by
    /// redirecting the calls to another implementation or by calling userdata::read_copy_userdata
    ///
    /// # Arguments
    ///  * `lua` - The Lua object to read from
    ///  * `index` - The index on the stack to read from
    fn read_from_lua<'lua>(lua: &mut Lua<'lua>, index: i32) -> Option<Self> {
        userdata::read_copy_userdata(lua, index)
    }
}

/// Types that can be indices in Lua tables
#[unstable]
pub trait Index<'lua>: Pushable<'lua> + CopyReadable {
}

/// Error that can happen when executing Lua code
#[deriving(Show)]
#[unstable]
pub enum LuaError {
    /// There was a syntax error when parsing the Lua code
    SyntaxError(String),

    /// There was an error during execution of the Lua code (for example not enough parameters for a function call)
    ExecutionError(String),

    /// The call to `execute` has requested the wrong type of data
    WrongType
}

// this alloc function is required to create a lua state
extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t, nsize: libc::size_t) -> *mut libc::c_void {
    unsafe {
        if nsize == 0 {
            libc::free(ptr as *mut libc::c_void);
            std::ptr::mut_null()
        } else {
            libc::realloc(ptr, nsize)
        }
    }
}

// called whenever lua encounters an unexpected error
extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
    let err = unsafe { ffi::lua_tostring(lua, -1) };
    fail!("PANIC: unprotected error in call to Lua API ({})\n", err);
}

impl<'lua> Lua<'lua> {
    /// Builds a new Lua context
    /// # Failure
    /// The function fails if lua_newstate fails (which indicates lack of memory)
    #[stable]
    pub fn new() -> Lua {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::mut_null()) };
        if lua.is_null() {
            fail!("lua_newstate failed");
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: lua,
            marker: ContravariantLifetime,
            must_be_closed: true,
            inside_callback: false
        }
    }

    /// Takes an existing lua_State and build a Lua object from it
    /// # Arguments
    ///  * close_at_the_end: if true, lua_close will be called on the lua_State on the destructor
    #[unstable]
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua {
        Lua {
            lua: std::mem::transmute(lua),
            marker: ContravariantLifetime,
            must_be_closed: close_at_the_end,
            inside_callback: false
        }
    }

    /// Opens all standard Lua libraries
    /// This is done by calling `luaL_openlibs`
    #[unstable]
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua) }
    }

    /// Executes some Lua code on the context
    #[unstable]
    pub fn execute<T: CopyReadable>(&mut self, code: &str) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /// Executes some Lua code on the context
    #[unstable]
    pub fn execute_from_reader<T: CopyReadable, R: std::io::Reader + 'static>(&mut self, code: R) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /// Loads the value of a global variable
    #[unstable]
    pub fn load<'a, I: Str, V: ConsumeReadable<'a, 'lua>>(&'a mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        ConsumeReadable::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok()
    }

    /// Reads the value of a global variable by copying it
    #[unstable]
    pub fn get<I: Str, V: CopyReadable>(&mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        CopyReadable::read_from_lua(self, -1)
    }

    /// Modifies the value of a global variable
    #[unstable]
    pub fn set<I: Str, V: Pushable<'lua>>(&mut self, index: I, value: V) {
        value.push_to_lua(self);
        unsafe { ffi::lua_setglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
    }

    #[unstable]
    pub fn load_new_table<'var>(&'var mut self) -> LuaTable<'var, 'lua> {
        unsafe { ffi::lua_newtable(self.lua) };
        ConsumeReadable::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok().unwrap()
    }
}

#[unsafe_destructor]
impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua) }
        }
    }
}

#[unsafe_destructor]
impl<'a, 'lua> Drop for LoadedVariable<'a, 'lua> {
    fn drop(&mut self) {
        unsafe { ffi::lua_pop(self.lua.lua, self.size as libc::c_int) }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn globals_readwrite() {
        let mut lua = super::Lua::new();

        lua.set("a", 2i);
        let x: int = lua.get("a").unwrap();
        assert_eq!(x, 2)
    }

    #[test]
    fn execute() {
        let mut lua = super::Lua::new();

        let val: int = lua.execute("return 5").unwrap();
        assert_eq!(val, 5);
    }

    // TODO: doesn't compile, have absolutely NO IDEA why
    /*#[test]
    fn table_readwrite() {
        let mut lua = super::Lua::new();

        lua.execute("a = { foo = 5 }");

        assert_eq!(lua.access("a").get(&"foo").unwrap(), 2);

        {   let access = lua.access("a");
            access.set(5, 3);
            assert_eq!(access.get(5), 3);
        }
    }*/
}
<commit_msg>Minor style fixes in doc<commit_after>#![crate_name = "rust-hl-lua"]
#![crate_type = "lib"]
#![comment = "Lua bindings for Rust"]
#![license = "MIT"]
#![allow(visible_private_types)]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]

extern crate libc;

use std::kinds::marker::ContravariantLifetime;

pub use lua_tables::LuaTable;

pub mod any;
pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod ffi;
mod functions_write;
mod rust_tables;
mod tuples;
mod values;

/// Main object of the library.
/// The lifetime parameter corresponds to the lifetime of the Lua object itself.
#[unstable]
pub struct Lua<'lua> {
    lua: *mut ffi::lua_State,
    marker: ContravariantLifetime<'lua>,
    must_be_closed: bool,
    inside_callback: bool           // if true, we are inside a callback
}

/// Object which allows access to a Lua variable.
struct LoadedVariable<'var, 'lua> {
    lua: &'var mut Lua<'lua>,
    size: uint       // number of elements at the top of the stack
}

/// Should be implemented by whatever type is pushable on the Lua stack.
#[unstable]
pub trait Pushable<'lua>: ::std::any::Any {
    /// Pushes the value on the top of the stack.
    /// Must return the number of elements pushed.
    ///
    /// You can implement this for any type you want by redirecting to call to
    /// another implementation (for example `5.push_to_lua`) or by calling `userdata::push_userdata`
    fn push_to_lua(self, lua: &mut Lua<'lua>) -> uint;
}

/// Should be implemented by types that can be read by consomming a LoadedVariable.
#[unstable]
pub trait ConsumeReadable<'a, 'lua> {
    /// Returns the LoadedVariable in case of failure.
    fn read_from_variable(var: LoadedVariable<'a, 'lua>) -> Result<Self, LoadedVariable<'a, 'lua>>;
}

/// Should be implemented by whatever type can be read by copy from the Lua stack.
#[unstable]
pub trait CopyReadable : Clone + ::std::any::Any {
    /// Reads an object from the Lua stack.
    ///
    /// Similar to Pushable, you can implement this trait for your own types either by
    /// redirecting the calls to another implementation or by calling userdata::read_copy_userdata
    ///
    /// # Arguments
    ///  * `lua` - The Lua object to read from
    ///  * `index` - The index on the stack to read from
    fn read_from_lua<'lua>(lua: &mut Lua<'lua>, index: i32) -> Option<Self> {
        userdata::read_copy_userdata(lua, index)
    }
}

/// Types that can be indices in Lua tables.
#[unstable]
pub trait Index<'lua>: Pushable<'lua> + CopyReadable {
}

/// Error that can happen when executing Lua code.
#[deriving(Show)]
#[unstable]
pub enum LuaError {
    /// There was a syntax error when parsing the Lua code.
    SyntaxError(String),

    /// There was an error during execution of the Lua code
    /// (for example not enough parameters for a function call).
    ExecutionError(String),

    /// The call to `execute` has requested the wrong type of data.
    WrongType
}

// this alloc function is required to create a lua state.
extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t, nsize: libc::size_t) -> *mut libc::c_void {
    unsafe {
        if nsize == 0 {
            libc::free(ptr as *mut libc::c_void);
            std::ptr::mut_null()
        } else {
            libc::realloc(ptr, nsize)
        }
    }
}

// called whenever lua encounters an unexpected error.
extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
    let err = unsafe { ffi::lua_tostring(lua, -1) };
    fail!("PANIC: unprotected error in call to Lua API ({})\n", err);
}

impl<'lua> Lua<'lua> {
    /// Builds a new Lua context.
    ///
    /// # Failure
    /// The function fails if lua_newstate fails (which indicates lack of memory).
    #[stable]
    pub fn new() -> Lua {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::mut_null()) };
        if lua.is_null() {
            fail!("lua_newstate failed");
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: lua,
            marker: ContravariantLifetime,
            must_be_closed: true,
            inside_callback: false
        }
    }

    /// Takes an existing lua_State and build a Lua object from it.
    ///
    /// # Arguments
    ///  * close_at_the_end: if true, lua_close will be called on the lua_State on the destructor
    #[unstable]
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua {
        Lua {
            lua: std::mem::transmute(lua),
            marker: ContravariantLifetime,
            must_be_closed: close_at_the_end,
            inside_callback: false
        }
    }

    /// Opens all standard Lua libraries.
    /// This is done by calling `luaL_openlibs`.
    #[unstable]
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua) }
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute<T: CopyReadable>(&mut self, code: &str) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute_from_reader<T: CopyReadable, R: std::io::Reader + 'static>(&mut self, code: R) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /// Loads the value of a global variable.
    #[unstable]
    pub fn load<'a, I: Str, V: ConsumeReadable<'a, 'lua>>(&'a mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        ConsumeReadable::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok()
    }

    /// Reads the value of a global variable by copying it.
    #[unstable]
    pub fn get<I: Str, V: CopyReadable>(&mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        CopyReadable::read_from_lua(self, -1)
    }

    /// Modifies the value of a global variable.
    #[unstable]
    pub fn set<I: Str, V: Pushable<'lua>>(&mut self, index: I, value: V) {
        value.push_to_lua(self);
        unsafe { ffi::lua_setglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
    }

    #[unstable]
    pub fn load_new_table<'var>(&'var mut self) -> LuaTable<'var, 'lua> {
        unsafe { ffi::lua_newtable(self.lua) };
        ConsumeReadable::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok().unwrap()
    }
}

#[unsafe_destructor]
impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua) }
        }
    }
}

#[unsafe_destructor]
impl<'a, 'lua> Drop for LoadedVariable<'a, 'lua> {
    fn drop(&mut self) {
        unsafe { ffi::lua_pop(self.lua.lua, self.size as libc::c_int) }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn globals_readwrite() {
        let mut lua = super::Lua::new();

        lua.set("a", 2i);
        let x: int = lua.get("a").unwrap();
        assert_eq!(x, 2)
    }

    #[test]
    fn execute() {
        let mut lua = super::Lua::new();

        let val: int = lua.execute("return 5").unwrap();
        assert_eq!(val, 5);
    }

    // TODO: doesn't compile, have absolutely NO IDEA why
    /*#[test]
    fn table_readwrite() {
        let mut lua = super::Lua::new();

        lua.execute("a = { foo = 5 }");

        assert_eq!(lua.access("a").get(&"foo").unwrap(), 2);

        {   let access = lua.access("a");
            access.set(5, 3);
            assert_eq!(access.get(5), 3);
        }
    }*/
}
<|endoftext|>


<commit_before>//! AwesomeWM Mousegrabber interface

use ::lua::LUA;
use rlua::{self, Lua, Table, Function, Value};
use rustwlc::ButtonState;

pub const MOUSEGRABBER_TABLE: &str = "mousegrabber";
const SECRET_CALLBACK: &str = "__callback";
const SECRET_CURSOR: &str = "__cursor";

/// Init the methods defined on this interface
pub fn init(lua: &Lua) -> rlua::Result<()> {
    let mousegrabber_table = lua.create_table();
    mousegrabber_table.set("run", lua.create_function(run))?;
    mousegrabber_table.set("stop", lua.create_function(stop))?;
    mousegrabber_table.set("isrunning", lua.create_function(isrunning))?;
    let globals = lua.globals();
    globals.set(MOUSEGRABBER_TABLE, mousegrabber_table)
}

pub fn mousegrabber_handle(x: i32, y: i32, button: Option<(u32, ButtonState)>)
                         -> rlua::Result<()> {
    let lua = LUA.lock()
        .map_err(|err| rlua::Error::RuntimeError(
            format!("Lua lock was poisoned {:#?}", err)))?;
    let button_events = button.map(|(button, button_state)|
                                   ::lua::mouse_events_to_lua(&lua.0, button, button_state))
        .unwrap_or_else(|| Ok(vec![false, false, false, false, false]))?;
    call_mousegrabber(&lua.0, (x, y, button_events))
}

fn call_mousegrabber(lua: &Lua,
                     (x, y, button_events):
                     (i32, i32, Vec<bool>)) -> rlua::Result<()> {
    let globals = lua.globals();
    let lua_callback = globals
        .get::<_, Table>(MOUSEGRABBER_TABLE)?
        .get::<_, Function>(SECRET_CALLBACK)?;
    let res_table = lua.create_table();
    res_table.set("x", x)?;
    res_table.set("y", y)?;
    res_table.set("buttons", button_events)?;
    match lua_callback.call(res_table)? {
        Value::Boolean(true) => {Ok(())},
        _ => stop(lua, ())
    }
}

fn run(lua: &Lua, (function, cursor): (Function, String)) -> rlua::Result<()> {
    let mousegrabber_table = lua.globals().get::<_, Table>(MOUSEGRABBER_TABLE)?;
    match mousegrabber_table.get::<_, Value>(SECRET_CALLBACK)? {
        Value::Function(_) =>
            Err(rlua::Error::RuntimeError("mousegrabber callback already set!"
                                          .into())),
        _ => {
            mousegrabber_table.set(SECRET_CALLBACK, function)?;
            mousegrabber_table.set(SECRET_CURSOR, cursor)
        }
    }
}

fn stop(lua: &Lua, _: ()) -> rlua::Result<()> {
    let mousegrabber_table = lua.globals().get::<_, Table>(MOUSEGRABBER_TABLE)?;
    mousegrabber_table.set(SECRET_CALLBACK, Value::Nil)
}

fn isrunning(lua: &Lua, _: ()) -> rlua::Result<bool> {
    let mousegrabber_table = lua.globals().get::<_, Table>(MOUSEGRABBER_TABLE)?;
    match mousegrabber_table.get::<_, Value>(SECRET_CALLBACK)? {
        Value::Function(_) => Ok(true),
        _ => Ok(false)
    }
}
<commit_msg>Don't return error if secret callback is nil<commit_after>//! AwesomeWM Mousegrabber interface

use ::lua::LUA;
use rlua::{self, Lua, Table, Function, Value};
use rustwlc::ButtonState;

pub const MOUSEGRABBER_TABLE: &str = "mousegrabber";
const SECRET_CALLBACK: &str = "__callback";
const SECRET_CURSOR: &str = "__cursor";

/// Init the methods defined on this interface
pub fn init(lua: &Lua) -> rlua::Result<()> {
    let mousegrabber_table = lua.create_table();
    mousegrabber_table.set("run", lua.create_function(run))?;
    mousegrabber_table.set("stop", lua.create_function(stop))?;
    mousegrabber_table.set("isrunning", lua.create_function(isrunning))?;
    let globals = lua.globals();
    globals.set(MOUSEGRABBER_TABLE, mousegrabber_table)
}

pub fn mousegrabber_handle(x: i32, y: i32, button: Option<(u32, ButtonState)>)
                         -> rlua::Result<()> {
    let lua = LUA.lock()
        .map_err(|err| rlua::Error::RuntimeError(
            format!("Lua lock was poisoned {:#?}", err)))?;
    let button_events = button.map(|(button, button_state)|
                                   ::lua::mouse_events_to_lua(&lua.0, button, button_state))
        .unwrap_or_else(|| Ok(vec![false, false, false, false, false]))?;
    call_mousegrabber(&lua.0, (x, y, button_events))
}

fn call_mousegrabber(lua: &Lua,
                     (x, y, button_events):
                     (i32, i32, Vec<bool>)) -> rlua::Result<()> {
    let globals = lua.globals();
    let lua_callback = match globals
        .get::<_, Table>(MOUSEGRABBER_TABLE)?
        .get::<_, Function>(SECRET_CALLBACK) {
        Ok(function) => function,
        _ => return Ok(())
    };
    let res_table = lua.create_table();
    res_table.set("x", x)?;
    res_table.set("y", y)?;
    res_table.set("buttons", button_events)?;
    match lua_callback.call(res_table)? {
        Value::Boolean(true) => {Ok(())},
        _ => stop(lua, ())
    }
}

fn run(lua: &Lua, (function, cursor): (Function, String)) -> rlua::Result<()> {
    let mousegrabber_table = lua.globals().get::<_, Table>(MOUSEGRABBER_TABLE)?;
    match mousegrabber_table.get::<_, Value>(SECRET_CALLBACK)? {
        Value::Function(_) =>
            Err(rlua::Error::RuntimeError("mousegrabber callback already set!"
                                          .into())),
        _ => {
            mousegrabber_table.set(SECRET_CALLBACK, function)?;
            mousegrabber_table.set(SECRET_CURSOR, cursor)
        }
    }
}

fn stop(lua: &Lua, _: ()) -> rlua::Result<()> {
    let mousegrabber_table = lua.globals().get::<_, Table>(MOUSEGRABBER_TABLE)?;
    mousegrabber_table.set(SECRET_CALLBACK, Value::Nil)
}

fn isrunning(lua: &Lua, _: ()) -> rlua::Result<bool> {
    let mousegrabber_table = lua.globals().get::<_, Table>(MOUSEGRABBER_TABLE)?;
    match mousegrabber_table.get::<_, Value>(SECRET_CALLBACK)? {
        Value::Function(_) => Ok(true),
        _ => Ok(false)
    }
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Word_wrap

// Implements the minimum length greedy algorithm
// http://en.wikipedia.org/wiki/Word_wrap#Minimum_length
fn word_wrap(text: &str, line_length: uint) -> String {
    let mut wrapped = String::new();
    let mut space_left = line_length;
    let space_width = 1u;

    for word in text.words() {
        let word_length = word.char_len();

        if space_left != line_length {
            if word_length + space_width > space_left {
                wrapped.push('\n');
                space_left = line_length;
            }
            else {
                wrapped.push(' ');
                space_left -= space_width;
            }
        }

        wrapped.push_str(word);
        space_left =
            if word_length > line_length { 0 } else { space_left - word_length }
    }

    wrapped
}

#[cfg(not(test))]
fn main () {
    let text =
        "In olden times when wishing still helped one, there lived a king \
         whose daughters were all beautiful, but the youngest was so beautiful \
         that the sun itself, which has seen so much, was astonished whenever \
         it shone in her face.  Close by the king's castle lay a great dark \
         forest, and under an old lime tree in the forest was a well, and when \
         the day was very warm, the king's child went out into the forest and \
         sat down by the side of the cool fountain, and when she was bored she \
         took a golden ball, and threw it up on high and caught it, and this \
         ball was her favorite plaything.";

    for &length in [72u, 80u].iter() {
        println!("Text wrapped at {}:\n{}\n", length, word_wrap(text, length));
    }
}

#[test]
fn test_empty_string() {
    assert_eq!(word_wrap("", 80).as_slice(), "");
}

#[test]
fn test_single_word_shorter_than_line() {
    assert_eq!(word_wrap("Hello", 80).as_slice(), "Hello");
}

#[test]
fn test_two_words_shorter_than_line() {
    assert_eq!(word_wrap("Hello world", 80).as_slice(), "Hello world");
}

#[test]
fn test_single_word_longer_than_line() {
    assert_eq!(word_wrap("Hello", 4).as_slice(), "Hello");
}

#[test]
fn test_wrap_second_word() {
    assert_eq!(word_wrap("Hello world", 10).as_slice(), "Hello\nworld");
}

#[test]
fn test_wrap_all_as_words_shorter_than_line_length() {
    assert_eq!(word_wrap("Words frequently wrapped", 4).as_slice(),
               "Words\nfrequently\nwrapped");
}

#[test]
fn test_wrap_punctuation() {
    assert_eq!(word_wrap("Hello, world", 6).as_slice(), "Hello,\nworld");
}

#[test]
fn test_squash_multiple_spaces() {
    assert_eq!(word_wrap(" Hello  to the    world    ", 10).as_slice(),
               "Hello to\nthe world");
}

#[test]
fn test_unicode() {
    assert_eq!(word_wrap("Nous étions à l'Étude, quand le Proviseur entra",
                         11).as_slice(),
               "Nous étions\nà l'Étude,\nquand le\nProviseur\nentra");
}
<commit_msg>Changed word_wrap implementation to be an iterator<commit_after>// http://rosettacode.org/wiki/Word_wrap

// Using the minimum length greedy algorithm
// http://en.wikipedia.org/wiki/Word_wrap#Minimum_length

// Implemented as a lazy String iterator, returning a wrapped line each time

use std::str::Words;
use std::mem::swap;

pub struct WordWrap<'a> {
    words: Words<'a>,
    line_length: uint,
    next_line: String
}

impl<'a> WordWrap<'a> {
    fn new(text: &'a str, line_length: uint) -> WordWrap {
        WordWrap {
            words : text.words(),
            line_length : line_length,
            next_line: String::new(),
        }
    }
}

impl<'a> Iterator<String> for WordWrap<'a> {
    fn next(&mut self) -> Option<String> {
        // Move anything left over from last run to this_line
        let mut this_line = String::new();
        swap(&mut self.next_line, &mut this_line);

        let mut space_left = self.line_length - this_line.as_slice().char_len();
        let space_width = 1u;

        // Loop, adding words until we run out of words or hit the line length
        loop {
            match self.words.next() {
                None => break,
                Some(word) => {
                    let word_length = word.char_len();

                    // If not the first word for this line
                    if space_left != self.line_length {
                        if word_length + space_width > space_left {
                            // Out of space, save word for next line
                            self.next_line.push_str(word);
                            break;
                        }
                        else {
                            // Add a space and keep going
                            this_line.push(' ');
                            space_left -= space_width;
                        }
                    }

                    // Add word to this line
                    this_line.push_str(word);
                    space_left -= word_length;
                }
            }
        }

        match this_line.is_empty() { true => None, false => Some(this_line) }
    }
}

#[cfg(not(test))]
fn main () {
    let text =
        "In olden times when wishing still helped one, there lived a king \
         whose daughters were all beautiful, but the youngest was so beautiful \
         that the sun itself, which has seen so much, was astonished whenever \
         it shone in her face.  Close by the king's castle lay a great dark \
         forest, and under an old lime tree in the forest was a well, and when \
         the day was very warm, the king's child went out into the forest and \
         sat down by the side of the cool fountain, and when she was bored she \
         took a golden ball, and threw it up on high and caught it, and this \
         ball was her favorite plaything.";

    for &length in [72u, 80u].iter() {
        println!("Text wrapped at {}", length);
        for line in WordWrap::new(text, length) {
            println!("{}", line);
        }
        println!("");
    }

}

#[test]
fn test_empty_string() {
    assert_eq!(WordWrap::new("", 80).next(), None);
}

#[test]
fn test_single_word_shorter_than_line() {
    assert_eq!(WordWrap::new("Hello", 80).next().unwrap().as_slice(), "Hello");
}

#[test]
fn test_two_words_shorter_than_line() {
    assert_eq!(WordWrap::new("Hello world", 80).next().unwrap().as_slice(),
               "Hello world");
}

#[test]
fn test_wrap_second_word() {
    let mut w = WordWrap::new("Hello world", 10);
    assert_eq!(w.next().unwrap().as_slice(), "Hello");
    assert_eq!(w.next().unwrap().as_slice(), "world");
}

#[test]
fn test_wrap_punctuation() {
    let mut w = WordWrap::new("Hello, world", 6);
    assert_eq!(w.next().unwrap().as_slice(), "Hello,");
    assert_eq!(w.next().unwrap().as_slice(), "world");
}

#[test]
fn test_squash_multiple_spaces() {
    let mut w = WordWrap::new(" Hello  to the    world    ", 10);
    assert_eq!(w.next().unwrap().as_slice(), "Hello to");
    assert_eq!(w.next().unwrap().as_slice(), "the world");
    assert_eq!(w.next(), None);
}

#[test]
fn test_unicode() {
    let mut w =
        WordWrap::new("Nous étions à l'Étude, quand le Proviseur entra", 11);
    assert_eq!(w.next().unwrap().as_slice(), "Nous étions");
    assert_eq!(w.next().unwrap().as_slice(), "à l'Étude,");
    assert_eq!(w.next().unwrap().as_slice(), "quand le");
    assert_eq!(w.next().unwrap().as_slice(), "Proviseur");
    assert_eq!(w.next().unwrap().as_slice(), "entra");
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use super::CreateEmbed;
use crate::internal::prelude::*;
use crate::utils;

/// A builder to specify the fields to edit in an existing message.
///
/// # Examples
///
/// Editing the content of a [`Message`] to `"hello"`:
///
/// ```rust,no_run
/// # use serenity::model::id::{ChannelId, MessageId};
/// # #[cfg(feature = "client")]
/// # use serenity::client::Context;
/// # #[cfg(feature = "framework")]
/// # use serenity::framework::standard::{CommandResult, macros::command};
/// #
/// # #[cfg(all(feature = "model", feature = "utils", feature = "framework"))]
/// # #[command]
/// # async fn example(ctx: &Context) -> CommandResult {
/// # let mut message = ChannelId(7).message(&ctx, MessageId(8)).await?;
/// message.edit(ctx, |m| {
///     m.content("hello")
/// })
/// .await?;
/// # Ok(())
/// # }
/// ```
///
/// [`Message`]: crate::model::channel::Message
#[derive(Clone, Debug, Default)]
pub struct EditMessage(pub HashMap<&'static str, Value>);

impl EditMessage {
    /// Set the content of the message.
    ///
    /// **Note**: Message contents must be under 2000 unicode code points.
    #[inline]
    pub fn content<D: ToString>(&mut self, content: D) -> &mut Self {
        self.0.insert("content", Value::String(content.to_string()));
        self
    }

    /// Set an embed for the message.
    pub fn embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut create_embed = CreateEmbed::default();
        f(&mut create_embed);
        let map = utils::hashmap_to_json_map(create_embed.0);
        let embed = Value::Object(map);

        self.0.insert("embed", embed);
        self
    }

    /// Delete all embeds in the message, this includes those generated by Discord themselves
    pub fn suppress_embeds(&mut self, suppress: bool) -> &mut Self {
        // `1 << 2` is defined by the API to be the SUPPRESS_EMBEDS flag.
        // At the time of writing, the only accepted value in "flags" is `SUPPRESS_EMBEDS` for editing messages.
        if suppress {
            self.0.insert("flags", serde_json::Value::Number(serde_json::Number::from(1 << 2)));
        } else {
            self.0.remove("flags");
        }

        self
    }
}
<commit_msg>Add `set_embed` to `EditMessage` (#1382)<commit_after>use std::collections::HashMap;

use super::CreateEmbed;
use crate::internal::prelude::*;
use crate::utils;

/// A builder to specify the fields to edit in an existing message.
///
/// # Examples
///
/// Editing the content of a [`Message`] to `"hello"`:
///
/// ```rust,no_run
/// # use serenity::model::id::{ChannelId, MessageId};
/// # #[cfg(feature = "client")]
/// # use serenity::client::Context;
/// # #[cfg(feature = "framework")]
/// # use serenity::framework::standard::{CommandResult, macros::command};
/// #
/// # #[cfg(all(feature = "model", feature = "utils", feature = "framework"))]
/// # #[command]
/// # async fn example(ctx: &Context) -> CommandResult {
/// # let mut message = ChannelId(7).message(&ctx, MessageId(8)).await?;
/// message.edit(ctx, |m| {
///     m.content("hello")
/// })
/// .await?;
/// # Ok(())
/// # }
/// ```
///
/// [`Message`]: crate::model::channel::Message
#[derive(Clone, Debug, Default)]
pub struct EditMessage(pub HashMap<&'static str, Value>);

impl EditMessage {
    /// Set the content of the message.
    ///
    /// **Note**: Message contents must be under 2000 unicode code points.
    #[inline]
    pub fn content<D: ToString>(&mut self, content: D) -> &mut Self {
        self.0.insert("content", Value::String(content.to_string()));
        self
    }

    /// Set an embed for the message.
    pub fn embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut create_embed = CreateEmbed::default();
        f(&mut create_embed);
        let map = utils::hashmap_to_json_map(create_embed.0);
        let embed = Value::Object(map);

        self.0.insert("embed", embed);
        self
    }

    /// Set an embed for the message.
    pub fn set_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        let map = utils::hashmap_to_json_map(embed.0);
        let embed = Value::Object(map);

        self.0.insert("embed", embed);
        self
    }

    /// Delete all embeds in the message, this includes those generated by Discord themselves
    pub fn suppress_embeds(&mut self, suppress: bool) -> &mut Self {
        // `1 << 2` is defined by the API to be the SUPPRESS_EMBEDS flag.
        // At the time of writing, the only accepted value in "flags" is `SUPPRESS_EMBEDS` for editing messages.
        if suppress {
            self.0.insert("flags", serde_json::Value::Number(serde_json::Number::from(1 << 2)));
        } else {
            self.0.remove("flags");
        }

        self
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! select_loop {
    {$($method:ident($($args:tt)*) => $body:expr$(,)*)*} => {
        #[allow(unused_mut)]
        {
            $(select_loop!(@make_mut $method($($args)*));)*

            let mut state = $crate::Select::new();

            #[allow(unreachable_code)]
            'select: loop {
                let _dont_use_an_unlabeled_continue_or_break_in_select_loop;
                loop {
                    $(
                        select_loop! {
                            @impl(
                                'select,
                                state,
                                _dont_use_an_unlabeled_continue_or_break_in_select_loop
                            )
                            $method($($args)*) => $body
                        }
                    )*
                    continue 'select;
                }
                _dont_use_an_unlabeled_continue_or_break_in_select_loop = ();
            }
        }
    };

    {@impl($select:tt, $state:ident, $guard:ident) send($tx:expr, $val:ident) => $body:expr} => {
        match $state.send(&*&$tx, $val) {
            Ok(()) => {
                $guard = ();
                break $select $body;
            }
            Err($crate::SelectSendError(val)) => {
                $val = val;
            }
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) send($tx:expr, mut $val:expr) => $body:expr} => {
        match $state.send(&*&$tx, $val) {
            Ok(()) => {
                $guard = ();
                break $select $body;
            }
            Err($crate::SelectSendError(val)) => {
                $val = val;
            }
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) send($tx:expr, eval $val:expr) => $body:expr} => {
        if let Ok(()) = $state.send(&*&$tx, $val) {
            $guard = ();
            break $select $body;
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) recv($rx:expr, $val:ident) => $body:expr} => {
        if let Ok($val) = $state.recv(&*&$rx) {
            $guard = ();
            break $select $body;
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) disconnected() => $body:expr} => {
        if $state.disconnected() {
            $guard = ();
            break $select $body;
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) would_block() => $body:expr} => {
        if $state.would_block() {
            $guard = ();
            break $select $body;
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) timed_out() => $body:expr} => {
        if $state.timed_out() {
            $guard = ();
            break $select $body;
        }
    };

    {@make_mut send($tx:expr, $val:ident)} => {
        let mut $val = $val;
    };
    {@make_mut $($tail:tt)*} => {};
}

#[cfg(test)]
mod tests {
    use ::{Receiver, Sender};

    struct _Foo(String);

    fn _it_compiles(
        mut struct_val: _Foo,
        immutable_var: String,
        eval_var: String,
        rx0: Receiver<String>,
        rx1: &Receiver<u32>,
        tx0: &mut Sender<String>,
        tx1: Sender<String>,
        tx2: Sender<String>,
        tx3: Sender<String>,
        tx4: Sender<String>,
        tx5: Sender<u32>,
    ) -> Option<String> {
        select_loop! {
            recv(rx0, val) => Some(val),
            recv(rx1, val) => Some(val.to_string()),
            send(tx0, mut struct_val.0) => Some(immutable_var),
            send(tx1, immutable_var) => Some(struct_val.0),
            send(tx2, eval struct_val.0.clone()) => Some(struct_val.0),
            send(tx3, immutable_var) => Some(eval_var),
            send(tx4, eval eval_var.clone()) => Some(eval_var),
            send(tx5, eval 42) => None,
            disconnected() => Some("disconnected".into()),
            would_block() => Some("would_block".into()),
            timed_out() => Some("timed_out".into()),
        }
    }
}
<commit_msg>timeout, docs<commit_after>/// This macro provides a more user-friendly wrapper around the `Select` struct.
///
/// It is similar in syntax to a `match` expression: It takes a list of cases,
/// each of the form `operation(arguments) => expression`. Note that
/// `expression` may be a block as well. The individual cases may optionally be
/// separated by commas. As with `match`, the whole macro invocation is treated
/// as an expression, so values can be returned from the individual cases.
///
/// A simple example to illustrate:
///
/// ```
/// select_loop! {
///     send(tx0, value) => println!("Sent value to tx0!"),
///     send(tx1, value) => { println!("Sent value to tx1!") }
/// }
/// ```
///
/// Please keep in mind the standard rules of the `Select`:
///
/// 1. No two cases may use the same end of the same channel. In the example
///    above this means that even if `tx0` and `tx1` are different `Sender`
///    instances, they must not belong to the same channel.
///
/// The following operations are supported by the macro:
///
/// * **`send($tx:expr, $variable:ident) => ...`:** Attempt to `send` the value of
///   `$variable` with `$tx`. If sending fails, the value of `$variable` is
///   automatically recovered. For convenience, `$variable` is automatically
///   made mutable by the macro.
/// * **`send($tx:expr, mut $field:expr) => ...`:** Attempt to `send` the value of
///   `$variable` with `$tx`. If sending fails, the value of `$variable` is
///   automatically recovered. Different from the previous version, this version
///   assumes that `$field` is mutable. And while the macro accepts any
///   expression for `$field`, it only really makes sense to specify plain
///   variables or direct field references (e.g. `some_struct.some_field`).
/// * **`send($tx:expr, eval $expr:expr) => ...`:** Attempt to `send` the result of
///   evaluating `$expr` with `$tx`. *Warning:* $expr is evaluated once in every
///   loop iteration. In some iterations, its result may simply be discarded
///   with no actual attempt at sending it.
/// * **`recv($rx:expr, $variable:ident) => ...`:** Attempt to receive a value from
///   `$rx`. If successful, the received value will be available in `$variable`
///    for the expression of this case.
/// * **`disconnected() => ...`:** This case is triggered when all channels in the
///   loop have disconnected.
/// * **`would_block() => ...`:** This case is triggered when all channels in the
///   loop would block.
/// * **`timed_out($duration:expr) => ...`:** Enables a timeout for the select loop.
///   If the timeout is reached without any of the other cases triggering, this
///   case is triggered. If there are multiple `timed_out` cases, only the
///   duration from the last case is registered.
///
#[macro_export]
macro_rules! select_loop {
    // The main entrypoint
    {$($method:ident($($args:tt)*) => $body:expr$(,)*)*} => {
        #[allow(unused_mut, unused_variables)]
        {
            let mut state = $crate::Select::new();

            // Build the prelude.
            //
            // This currently performs two tasks:
            //
            // 1) Make all variables used in send(_, $ident) mutable (the
            //    variable will move into the loop anyway, so we can move it
            //    here as well).
            // 2) If a timeout was specified, overwrite the above state with one
            //    which has the timeout set.
            $(select_loop!(@prelude(state) $method($($args)*));)*

            // The actual select loop which a user would write manually
            #[allow(unreachable_code)]
            'select: loop {
                // This double-loop construct is used to guard against the user
                // using unlabeled breaks / continues in their code.
                //
                // It works by abusing rustc's control flow analysis:
                //
                // 1) The _guard variable is declared
                // 2) The generated code will assign a value to _guard [A0]
                //    immediately after an operation was successful (before
                //    running any user code)
                // 3) There is another assignment to _guard [A1] directly after
                //    the inner loop.
                // 4) If the user has an unlabeled break in their code, rustc
                //    will complain because both [A0] and [A1] assign to guard.
                //    If the user has an unlabeled continue in their code, rustc
                //    will complain because [A0] may assign to guard twice.
                // 5) Directly after executing the user code, we break the
                //    outer loop, so we don't trigger the error ourselves.
                // 6) To avoid an infinite loop, we manually continue to the
                //    outer loop at the very end of the inner loop.
                let _dont_use_an_unlabeled_continue_or_break_in_select_loop;
                loop {
                    $(
                        // Build the actual method invocations.
                        select_loop! {
                            @impl(
                                'select,
                                state,
                                _dont_use_an_unlabeled_continue_or_break_in_select_loop
                            )
                            $method($($args)*) => $body
                        }
                    )*
                    continue 'select;
                }
                _dont_use_an_unlabeled_continue_or_break_in_select_loop = ();
            }
        }
    };

    //The individual method invocations
    {@impl($select:tt, $state:ident, $guard:ident) send($tx:expr, $val:ident) => $body:expr} => {
        match $state.send(&*&$tx, $val) {
            Ok(()) => {
                $guard = ();
                break $select $body;
            }
            Err($crate::SelectSendError(val)) => {
                $val = val;
            }
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) send($tx:expr, mut $val:expr) => $body:expr} => {
        match $state.send(&*&$tx, $val) {
            Ok(()) => {
                $guard = ();
                break $select $body;
            }
            Err($crate::SelectSendError(val)) => {
                $val = val;
            }
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) send($tx:expr, eval $val:expr) => $body:expr} => {
        if let Ok(()) = $state.send(&*&$tx, $val) {
            $guard = ();
            break $select $body;
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) recv($rx:expr, $val:ident) => $body:expr} => {
        if let Ok($val) = $state.recv(&*&$rx) {
            $guard = ();
            break $select $body;
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) disconnected() => $body:expr} => {
        if $state.disconnected() {
            $guard = ();
            break $select $body;
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) would_block() => $body:expr} => {
        if $state.would_block() {
            $guard = ();
            break $select $body;
        }
    };
    {@impl($select:tt, $state:ident, $guard:ident) timed_out($_timeout:expr) => $body:expr} => {
        if $state.timed_out() {
            $guard = ();
            break $select $body;
        }
    };

    // The prelude helpers
    {@prelude($state:ident) send($tx:expr, $val:ident)} => {
        let mut $val = $val;
    };
    {@prelude($state:ident) timed_out($timeout:expr)} => {
        let mut $state = $crate::Select::with_timeout($timeout);
    };
    {@prelude($state:ident) $($tail:tt)*} => {};
}

#[cfg(test)]
mod tests {
    use ::{Receiver, Sender};
    use std::time::Duration;

    struct _Foo(String);

    fn _it_compiles(
        mut struct_val: _Foo,
        immutable_var: String,
        eval_var: String,
        rx0: Receiver<String>,
        rx1: &Receiver<u32>,
        tx0: &mut Sender<String>,
        tx1: Sender<String>,
        tx2: Sender<String>,
        tx3: Sender<String>,
        tx4: Sender<String>,
        tx5: Sender<u32>,
    ) -> Option<String> {
        select_loop! {
            recv(rx0, val) => Some(val),
            recv(rx1, val) => Some(val.to_string()),
            send(tx0, mut struct_val.0) => Some(immutable_var),
            send(tx1, immutable_var) => Some(struct_val.0),
            send(tx2, eval struct_val.0.clone()) => Some(struct_val.0),
            send(tx3, immutable_var) => Some(eval_var),
            send(tx4, eval eval_var.clone()) => Some(eval_var),
            send(tx5, eval 42) => None,
            disconnected() => Some("disconnected".into()),
            would_block() => Some("would_block".into()),
            timed_out(Duration::from_secs(1)) => Some("timed_out".into()),
            //The previous timeout duration is overwritten
            timed_out(Duration::from_secs(2)) => Some("timet_out".into()),
        }
    }
}
<|endoftext|>


<commit_before>const LARGE_MASTER_SECRET: i32 = 256;
const LARGE_PRIME: i32 = 1024;
const LARGE_VPRIME: i32 = 2128;
const LARGE_E_START: i32 = 596;
const LARGE_E_END_RANGE: i32 = 119;
extern crate openssl;
extern crate int_traits;
use self::int_traits::IntTraits;
use self::openssl::bn::{BigNum, BigNumRef, BigNumContext, MSB_MAYBE_ZERO};
use self::openssl::hash::{hash, MessageDigest};
pub struct AnoncredsService {
    dummy: String
}

impl AnoncredsService {
    pub fn new() -> AnoncredsService {
        trace!(target: "AnoncredsService", "new");
        AnoncredsService { dummy: "anoncreds_dummy".to_string() }
    }
    fn generate_master_secret() -> BigNum {
        let mut ms = BigNum::new().unwrap();
        ms.rand(LARGE_MASTER_SECRET, MSB_MAYBE_ZERO, false);
        ms
    }
    fn generate_public_key() -> PublicKey {
        //let (p_prime, q_prime) = (AnoncredsService::generate_prime(), AnoncredsService::generate_prime());
        let p_prime = BigNum::from_dec_str("147210949676505370022291901638323344651935110597590993130806944871698104433042968489453214046274983960765508724336420649095413993801340223096499490318385863961435462627523137938481776395548210420546733337321351064531462114552738775282293300556323029911674068388889455348206728016707243243859948314986927502343").unwrap();
        let q_prime = BigNum::from_dec_str("135780746061008989066681842882411968289578365330121870655195830818464118363874946689390282395824911410416094765498522070170715656164604448597511036312331994824492100665472180363433381994083327828179950784236529457340933711810709515143629906739084420423785456874473704622664344722021987863690561674302204741259").unwrap();
        //println!("p: {}\nq: {}", p_prime, q_prime);

        let (mut p, mut q, mut ctx, mut n, mut s, mut rms) = (
            BigNum::new().unwrap(),
            BigNum::new().unwrap(),
            BigNumContext::new().unwrap(),
            BigNum::new().unwrap(),
            BigNum::new().unwrap(),
            BigNum::new().unwrap()
        );

        p.checked_mul(&p_prime, &BigNum::from_u32(2).unwrap(), &mut ctx);
        p.add_word(1);
        q.checked_mul(&q_prime, &BigNum::from_u32(2).unwrap(), &mut ctx);
        q.add_word(1);
        //println!("p: {}\nq: {}", p, q);

        let mut n = BigNum::new().unwrap();
        n.checked_mul(&p, &q, &mut ctx);
        //println!("n: {}", n);

        s = AnoncredsService::random_qr(&n);
        //println!("s: {}", s);

        rms.mod_exp(&s, &AnoncredsService::gen_x(&p_prime, &q_prime), &n, &mut ctx);
        //println!("rms: {}", rms);

        PublicKey {n: n, s: s, rms: rms}
    }
    fn gen_x(p: &BigNum, q: &BigNum) -> BigNum {
        let mut ctx = BigNumContext::new().unwrap();
        let mut value = BigNum::new().unwrap();
        let mut result = BigNum::new().unwrap();

        value.checked_mul(&p, &q, &mut ctx);
        value.sub_word(3);

        result = AnoncredsService::random_in_range(&BigNum::from_u32(0).unwrap(), &value);
        result.add_word(2);
        result
    }
    fn gen_u(public_key: PublicKey, ms: BigNum) -> BigNum {
        let mut ctx = BigNumContext::new().unwrap();
        let mut vprime = BigNum::new().unwrap();
        vprime.rand(LARGE_VPRIME, MSB_MAYBE_ZERO, false);

        let mut result_mul_one = BigNum::new().unwrap();
        result_mul_one.mod_exp(&public_key.s, &vprime, &public_key.n, &mut ctx);

        let mut result_mul_two = BigNum::new().unwrap();
        result_mul_two.mod_exp(&public_key.rms, &ms, &public_key.n, &mut ctx);

        let mut u = &result_mul_one * &result_mul_two;
        u = &u % &public_key.n;
        u
    }
    fn random_in_range(start: &BigNum, end: &BigNum) -> BigNum {
        let mut random_number = BigNum::new().unwrap();
        let sub = end - start;

        random_number.rand(sub.num_bits(), MSB_MAYBE_ZERO, false).unwrap();
        while (&random_number + start) > *end {
            random_number.rand(sub.num_bits(), MSB_MAYBE_ZERO, false).unwrap();
        }

        &random_number + start
    }
    fn random_qr(n: &BigNum) -> BigNum {
        let (mut ctx, mut random_qr) = (BigNumContext::new().unwrap(), BigNum::new().unwrap());
        random_qr.sqr(&AnoncredsService::random_in_range(&BigNum::from_u32(0).unwrap(), &n), &mut ctx);
        random_qr
    }
    fn count_rounds_for_prime_check(prime: &BigNum) -> i32 {
        let prime_len = prime.to_dec_str().unwrap().len();
        prime_len.log2() as i32
    }
    fn generate_prime() -> BigNum {
        let mut ctx = BigNumContext::new().unwrap();
        let mut prime = BigNum::new().unwrap();
        let (mut is_prime, mut iteration) = (false, 0);

        while !is_prime {
            iteration += 1;
            prime.generate_prime(LARGE_PRIME, false, None, None);
            let checks = AnoncredsService::count_rounds_for_prime_check(&prime);
            let mut prime_for_check = BigNum::new().unwrap();
            prime_for_check.checked_mul(&prime, &BigNum::from_u32(2).unwrap(), &mut ctx).unwrap();
            prime_for_check.add_word(1);
            is_prime = prime_for_check.is_prime(checks, &mut ctx).unwrap();
            println!("Iteration: {}\nFound prime: {}\nis_prime: {}\n", iteration, prime, is_prime);
        }

        //println!("Generated prime: {}", prime);
        prime
    }
    fn generate_prime_in_range(start: &BigNum, end: &BigNum) -> Result<BigNum, &'static str>{
        let (mut iteration, max_iterations, mut prime_is_found, mut prime, mut ctx) = (
            0,
            100000,
            false,
            BigNum::new().unwrap(),
            BigNumContext::new().unwrap()
        );

        while (iteration < max_iterations) && !prime_is_found {
            prime = AnoncredsService::random_in_range(&start, &end);
            let checks = AnoncredsService::count_rounds_for_prime_check(&prime);

            if prime.is_prime(checks, &mut ctx).unwrap() {
                prime_is_found = true;
                println!("Found prime in {} iteration", iteration);
            }
            iteration += 1;
        }

        if !prime_is_found {
            println!("Cannot find prime in {} iterations", max_iterations);
            Err("Prime is not found")
        } else {
            Ok(prime)
        }
    }
    fn create_claim_request() -> ClaimRequest {
        let public_key = AnoncredsService::generate_public_key();
        let master_secret = AnoncredsService::generate_master_secret();
        let u = AnoncredsService::gen_u(public_key, master_secret);
        let claim_request = ClaimRequest {u: u};
        claim_request
    }
    fn issue_primary_claim(attributes: &Vec<AttributeType>, u: &BigNum) {
        let mut ctx = BigNumContext::new().unwrap();
        println!("{}\n{:?}", u, attributes);
        //calc vprimeprime
        let (mut e_start, mut e_end) = (BigNum::new().unwrap(), BigNum::new().unwrap());
        e_start.exp(&BigNum::from_u32(2).unwrap(), &BigNum::from_u32(LARGE_E_START as u32).unwrap(), &mut ctx);
        e_end.exp(&BigNum::from_u32(2).unwrap(), &BigNum::from_u32(LARGE_E_END_RANGE as u32).unwrap(), &mut ctx);
        e_end = &e_start + &e_end;
        let e = AnoncredsService::generate_prime_in_range(&e_start, &e_end).unwrap();
    }
    fn encode_attribute() {

    }
}

#[derive(Debug)]
struct PublicKey {
    n: BigNum,
    s: BigNum,
    rms: BigNum
}

#[derive(Debug)]
struct ClaimRequest {
    u: BigNum
}

#[derive(Debug)]
struct AttributeType {
    name: String,
    encode: bool
}

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

    #[test]
    fn service_creation_is_possible() {
        let anoncreds_service = AnoncredsService::new();
        assert_eq!("anoncreds_dummy", anoncreds_service.dummy, "Dummy field is filled by constructor");
    }
    #[test]
    fn master_secret_generator_works() {
        let ms: BigNum = AnoncredsService::generate_master_secret();
        assert_eq!(LARGE_MASTER_SECRET/8, ms.num_bytes());
    }
    #[test]
    fn random_in_range_works() {
        let (mut start, mut end) = (BigNum::new().unwrap(), BigNum::new().unwrap());

        start.rand(LARGE_PRIME, MSB_MAYBE_ZERO, false).unwrap();
        end.rand(LARGE_PRIME, MSB_MAYBE_ZERO, false).unwrap();

        while end < start {
            end.rand(LARGE_PRIME, MSB_MAYBE_ZERO, false).unwrap();
        }

        let random_in_range = AnoncredsService::random_in_range(&start, &end);
        assert!((random_in_range > start) && (random_in_range < end));
    }
//    #[test]
//    fn generate_prime_works() {
//        let prime = AnoncredsService::generate_prime();
//        let mut ctx = BigNumContext::new().unwrap();
//        let checks = AnoncredsService::count_rounds_for_prime_check(&prime);
//        let is_prime = prime.is_prime(checks, &mut ctx).unwrap();
//        assert_eq!(is_prime, true);
//    }
    #[test]
    fn anoncreds_works() {
        let mut attributes = vec![
            AttributeType {name: "name".to_string(), encode: true},
            AttributeType {name: "age".to_string(), encode: false},
            AttributeType {name: "height".to_string(), encode: false},
            AttributeType {name: "sex".to_string(), encode: true}
        ];
        let claim_request = AnoncredsService::create_claim_request();
        let claim = AnoncredsService::issue_primary_claim(&attributes, &claim_request.u);
        let str = "Alexer".as_bytes();
        let res = hash(MessageDigest::sha256(), str).unwrap();
        println!("{:?}", res);
//        let data = [b"Alex"];
//        let mut h = Hasher::new(MessageDigest::sha256()).unwrap();
//        h.update(data[0]).unwrap();
//        let res = h.finish().unwrap();
        //println!("{:?}", res);
        //assert_eq!(res, spec);
//        let input = "Alexer5435";
//        let mut asd = vec![0;32];
//        let mut sha = Sha256::new();
//        sha.input_str(input);
//        println!("ob {}", sha.output_bytes());
//        sha.result(asd.as_mut_slice());
//        let b = sha.result_str();
//        //let c = String::from_utf8(asd);
//        //println!("utf8 {:?}",c);
//        println!("{:?}", &asd);
        let a = BigNum::from_dec_str("93838255634171043313693932530283701522875554780708470423762684802192372035729").unwrap();
        println!("{:?}", a.to_vec());
    }
}<commit_msg>draft for encode attribute function<commit_after>const LARGE_MASTER_SECRET: i32 = 256;
const LARGE_PRIME: i32 = 1024;
const LARGE_VPRIME: i32 = 2128;
const LARGE_E_START: i32 = 596;
const LARGE_E_END_RANGE: i32 = 119;
extern crate openssl;
extern crate int_traits;
use self::int_traits::IntTraits;
use self::openssl::bn::{BigNum, BigNumRef, BigNumContext, MSB_MAYBE_ZERO};
use self::openssl::hash::{hash, MessageDigest};
pub struct AnoncredsService {
    dummy: String
}

impl AnoncredsService {
    pub fn new() -> AnoncredsService {
        trace!(target: "AnoncredsService", "new");
        AnoncredsService { dummy: "anoncreds_dummy".to_string() }
    }
    fn generate_master_secret() -> BigNum {
        let mut ms = BigNum::new().unwrap();
        ms.rand(LARGE_MASTER_SECRET, MSB_MAYBE_ZERO, false);
        ms
    }
    fn generate_public_key() -> PublicKey {
        //let (p_prime, q_prime) = (AnoncredsService::generate_prime(), AnoncredsService::generate_prime());
        let p_prime = BigNum::from_dec_str("147210949676505370022291901638323344651935110597590993130806944871698104433042968489453214046274983960765508724336420649095413993801340223096499490318385863961435462627523137938481776395548210420546733337321351064531462114552738775282293300556323029911674068388889455348206728016707243243859948314986927502343").unwrap();
        let q_prime = BigNum::from_dec_str("135780746061008989066681842882411968289578365330121870655195830818464118363874946689390282395824911410416094765498522070170715656164604448597511036312331994824492100665472180363433381994083327828179950784236529457340933711810709515143629906739084420423785456874473704622664344722021987863690561674302204741259").unwrap();
        //println!("p: {}\nq: {}", p_prime, q_prime);

        let (mut p, mut q, mut ctx, mut n, mut s, mut rms) = (
            BigNum::new().unwrap(),
            BigNum::new().unwrap(),
            BigNumContext::new().unwrap(),
            BigNum::new().unwrap(),
            BigNum::new().unwrap(),
            BigNum::new().unwrap()
        );

        p.checked_mul(&p_prime, &BigNum::from_u32(2).unwrap(), &mut ctx);
        p.add_word(1);
        q.checked_mul(&q_prime, &BigNum::from_u32(2).unwrap(), &mut ctx);
        q.add_word(1);
        //println!("p: {}\nq: {}", p, q);

        let mut n = BigNum::new().unwrap();
        n.checked_mul(&p, &q, &mut ctx);
        //println!("n: {}", n);

        s = AnoncredsService::random_qr(&n);
        //println!("s: {}", s);

        rms.mod_exp(&s, &AnoncredsService::gen_x(&p_prime, &q_prime), &n, &mut ctx);
        //println!("rms: {}", rms);

        PublicKey {n: n, s: s, rms: rms}
    }
    fn gen_x(p: &BigNum, q: &BigNum) -> BigNum {
        let mut ctx = BigNumContext::new().unwrap();
        let mut value = BigNum::new().unwrap();
        let mut result = BigNum::new().unwrap();

        value.checked_mul(&p, &q, &mut ctx);
        value.sub_word(3);

        result = AnoncredsService::random_in_range(&BigNum::from_u32(0).unwrap(), &value);
        result.add_word(2);
        result
    }
    fn gen_u(public_key: PublicKey, ms: BigNum) -> BigNum {
        let mut ctx = BigNumContext::new().unwrap();
        let mut vprime = BigNum::new().unwrap();
        vprime.rand(LARGE_VPRIME, MSB_MAYBE_ZERO, false);

        let mut result_mul_one = BigNum::new().unwrap();
        result_mul_one.mod_exp(&public_key.s, &vprime, &public_key.n, &mut ctx);

        let mut result_mul_two = BigNum::new().unwrap();
        result_mul_two.mod_exp(&public_key.rms, &ms, &public_key.n, &mut ctx);

        let mut u = &result_mul_one * &result_mul_two;
        u = &u % &public_key.n;
        u
    }
    fn random_in_range(start: &BigNum, end: &BigNum) -> BigNum {
        let mut random_number = BigNum::new().unwrap();
        let sub = end - start;

        random_number.rand(sub.num_bits(), MSB_MAYBE_ZERO, false).unwrap();
        while (&random_number + start) > *end {
            random_number.rand(sub.num_bits(), MSB_MAYBE_ZERO, false).unwrap();
        }

        &random_number + start
    }
    fn random_qr(n: &BigNum) -> BigNum {
        let (mut ctx, mut random_qr) = (BigNumContext::new().unwrap(), BigNum::new().unwrap());
        random_qr.sqr(&AnoncredsService::random_in_range(&BigNum::from_u32(0).unwrap(), &n), &mut ctx);
        random_qr
    }
    fn count_rounds_for_prime_check(prime: &BigNum) -> i32 {
        let prime_len = prime.to_dec_str().unwrap().len();
        prime_len.log2() as i32
    }
    fn generate_prime() -> BigNum {
        let mut ctx = BigNumContext::new().unwrap();
        let mut prime = BigNum::new().unwrap();
        let (mut is_prime, mut iteration) = (false, 0);

        while !is_prime {
            iteration += 1;
            prime.generate_prime(LARGE_PRIME, false, None, None);
            let checks = AnoncredsService::count_rounds_for_prime_check(&prime);
            let mut prime_for_check = BigNum::new().unwrap();
            prime_for_check.checked_mul(&prime, &BigNum::from_u32(2).unwrap(), &mut ctx).unwrap();
            prime_for_check.add_word(1);
            is_prime = prime_for_check.is_prime(checks, &mut ctx).unwrap();
            println!("Iteration: {}\nFound prime: {}\nis_prime: {}\n", iteration, prime, is_prime);
        }

        //println!("Generated prime: {}", prime);
        prime
    }
    fn generate_prime_in_range(start: &BigNum, end: &BigNum) -> Result<BigNum, &'static str>{
        let (mut iteration, max_iterations, mut prime_is_found, mut prime, mut ctx) = (
            0,
            100000,
            false,
            BigNum::new().unwrap(),
            BigNumContext::new().unwrap()
        );

        while (iteration < max_iterations) && !prime_is_found {
            prime = AnoncredsService::random_in_range(&start, &end);
            let checks = AnoncredsService::count_rounds_for_prime_check(&prime);

            if prime.is_prime(checks, &mut ctx).unwrap() {
                prime_is_found = true;
                println!("Found prime in {} iteration", iteration);
            }
            iteration += 1;
        }

        if !prime_is_found {
            println!("Cannot find prime in {} iterations", max_iterations);
            Err("Prime is not found")
        } else {
            Ok(prime)
        }
    }
    fn create_claim_request() -> ClaimRequest {
        let public_key = AnoncredsService::generate_public_key();
        let master_secret = AnoncredsService::generate_master_secret();
        let u = AnoncredsService::gen_u(public_key, master_secret);
        let claim_request = ClaimRequest {u: u};
        claim_request
    }
    fn issue_primary_claim(attributes: &Vec<AttributeType>, u: &BigNum) {
        let mut ctx = BigNumContext::new().unwrap();
        println!("{}\n{:?}", u, attributes);
        //calc vprimeprime
        let (mut e_start, mut e_end) = (BigNum::new().unwrap(), BigNum::new().unwrap());
        e_start.exp(&BigNum::from_u32(2).unwrap(), &BigNum::from_u32(LARGE_E_START as u32).unwrap(), &mut ctx);
        e_end.exp(&BigNum::from_u32(2).unwrap(), &BigNum::from_u32(LARGE_E_END_RANGE as u32).unwrap(), &mut ctx);
        e_end = &e_start + &e_end;
        let e = AnoncredsService::generate_prime_in_range(&e_start, &e_end).unwrap();
    }
    fn transform_bytes_array_into_integer(vec: &Vec<u8>) {
        let mut ctx = BigNumContext::new().unwrap();
        let mut result = BigNum::from_u32(0).unwrap();
        for i in (0..vec.len()).rev() {
            let mut pow256 = BigNum::new().unwrap();
            pow256.exp(&BigNum::from_u32(256).unwrap(), &BigNum::from_u32(i as u32).unwrap(), &mut ctx);
            println!("pow: {}", pow256);
            println!("aaa{}", &BigNum::from_u32(vec[i] as u32).unwrap());
            pow256 = &pow256 * &BigNum::from_u32(vec[i] as u32).unwrap();
            result = &result + &pow256;
        }
        println!("reverse: {:?}", &result);
    }
    fn encode_attribute(attribute: &str) {
        let mut result = hash(MessageDigest::sha256(), attribute.as_bytes()).unwrap();
        let index = result.iter().position(|&value| value == 0);
        match index {
            Some(index) => {
                result.truncate(index);
                println!("{:?}, {:?}", result, index);
                AnoncredsService::transform_bytes_array_into_integer(&result);
            },
            None => println!("{:?}, 0", result)
        }

    }
}

#[derive(Debug)]
struct PublicKey {
    n: BigNum,
    s: BigNum,
    rms: BigNum
}

#[derive(Debug)]
struct ClaimRequest {
    u: BigNum
}

#[derive(Debug)]
struct AttributeType {
    name: String,
    encode: bool
}

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

    #[test]
    fn service_creation_is_possible() {
        let anoncreds_service = AnoncredsService::new();
        assert_eq!("anoncreds_dummy", anoncreds_service.dummy, "Dummy field is filled by constructor");
    }
    #[test]
    fn master_secret_generator_works() {
        let ms: BigNum = AnoncredsService::generate_master_secret();
        assert_eq!(LARGE_MASTER_SECRET/8, ms.num_bytes());
    }
    #[test]
    fn random_in_range_works() {
        let (mut start, mut end) = (BigNum::new().unwrap(), BigNum::new().unwrap());

        start.rand(LARGE_PRIME, MSB_MAYBE_ZERO, false).unwrap();
        end.rand(LARGE_PRIME, MSB_MAYBE_ZERO, false).unwrap();

        while end < start {
            end.rand(LARGE_PRIME, MSB_MAYBE_ZERO, false).unwrap();
        }

        let random_in_range = AnoncredsService::random_in_range(&start, &end);
        assert!((random_in_range > start) && (random_in_range < end));
    }
//    #[test]
//    fn generate_prime_works() {
//        let prime = AnoncredsService::generate_prime();
//        let mut ctx = BigNumContext::new().unwrap();
//        let checks = AnoncredsService::count_rounds_for_prime_check(&prime);
//        let is_prime = prime.is_prime(checks, &mut ctx).unwrap();
//        assert_eq!(is_prime, true);
//    }
    #[test]
    fn anoncreds_works() {
        let mut attributes = vec![
            AttributeType {name: "name".to_string(), encode: true},
            AttributeType {name: "age".to_string(), encode: false},
            AttributeType {name: "height".to_string(), encode: false},
            AttributeType {name: "sex".to_string(), encode: true}
        ];
        let claim_request = AnoncredsService::create_claim_request();
        let claim = AnoncredsService::issue_primary_claim(&attributes, &claim_request.u);
        let encoded_attribute = AnoncredsService::encode_attribute("Alexer5435");
        println!("encoded: {:?}", encoded_attribute);
        let str = "Alexer5435".as_bytes();
//        let res = hash(MessageDigest::sha256(), str).unwrap();
//        println!("{:?}", res);
//        let data = [b"Alex"];
//        let mut h = Hasher::new(MessageDigest::sha256()).unwrap();
//        h.update(data[0]).unwrap();
//        let res = h.finish().unwrap();
        //println!("{:?}", res);
        //assert_eq!(res, spec);
//        let input = "Alexer5435";
//        let mut asd = vec![0;32];
//        let mut sha = Sha256::new();
//        sha.input_str(input);
//        println!("ob {}", sha.output_bytes());
//        sha.result(asd.as_mut_slice());
//        let b = sha.result_str();
//        //let c = String::from_utf8(asd);
//        //println!("utf8 {:?}",c);
//        println!("{:?}", &asd);
        let a = BigNum::from_dec_str("93838255634171043313693932530283701522875554780708470423762684802192372035729").unwrap();
        println!("{:?}", a.to_vec());
    }
}<|endoftext|>


<commit_before>//! If you use enough force, you can actually use this GC to implement a toy VM.

use builtins;
use cell_gc::{GcHeapSession, GcLeaf};
use cell_gc::collections::VecRef;
use parser;
use value::{BuiltinFnPtr, InternedString, Pair, Value};
use value::Value::*;

/// A potentially partially evaluated value.
pub enum Trampoline<'h> {
    /// A completely evaluated value.
    Value(Value<'h>),
    /// The continuation of a partial evaluation in tail position. The stack
    /// should be unwound before resumption of its evaluation.
    TailCall {
        func: Value<'h>,
        args: Vec<Value<'h>>,
    },
}

impl<'h> Trampoline<'h> {
    /// Complete the evaluation of this value. Avoids recursion to implement
    /// proper tail calls and keep from blowing the stack.
    pub fn eval(mut self, hs: &mut GcHeapSession<'h>) -> Result<Value<'h>, String> {
        while let Trampoline::TailCall { func, args } = self {
            self = apply(hs, func, args)?;
        }
        match self {
            Trampoline::Value(v) => Ok(v),
            Trampoline::TailCall { .. } => unreachable!(),
        }
    }
}

#[derive(Clone, Debug, PartialEq, IntoHeap)]
pub struct Environment<'h> {
    parent: Option<EnvironmentRef<'h>>,
    names: VecRef<'h, GcLeaf<InternedString>>,
    values: VecRef<'h, Value<'h>>,
}

impl<'h> Environment<'h> {
    pub fn default_env(hs: &mut GcHeapSession<'h>) -> EnvironmentRef<'h> {
        let env = Environment {
            parent: None,
            names: hs.alloc(vec![]),
            values: hs.alloc(vec![]),
        };

        macro_rules! builtin {
            ( $lisp_ident:expr , $func:expr ) => {
                env.names.push(GcLeaf::new(InternedString::get($lisp_ident)));
                env.values.push(Builtin(GcLeaf::new(BuiltinFnPtr($func))));
            }
        }

        builtin!("+", builtins::add);
        builtin!("-", builtins::sub);
        builtin!("*", builtins::mul);
        builtin!("=", builtins::numeric_eq);
        builtin!("<", builtins::numeric_lt);
        builtin!(">", builtins::numeric_gt);
        builtin!("<=", builtins::numeric_le);
        builtin!(">=", builtins::numeric_ge);
        builtin!("apply", builtins::apply);
        builtin!("assert", builtins::assert);
        builtin!("car", builtins::car);
        builtin!("cdr", builtins::cdr);
        builtin!("cons", builtins::cons);
        builtin!("eqv?", builtins::eqv_question);
        builtin!("eq?", builtins::eq_question);
        builtin!("print", builtins::print);
        builtin!("boolean?", builtins::boolean_question);
        builtin!("null?", builtins::null_question);
        builtin!("pair?", builtins::pair_question);
        builtin!("procedure?", builtins::procedure_question);
        builtin!("vector?", builtins::vector_question);
        builtin!("vector", builtins::vector);
        builtin!("vector-length", builtins::vector_length);
        builtin!("vector-ref", builtins::vector_ref);

        const PRELUDE: &'static str = include_str!("prelude.sch");
        let prelude = match parser::parse(hs, PRELUDE) {
            Ok(forms) => forms,
            Err(err) => panic!("unexpected error parsing prelude: {}", err),
        };

        let env = hs.alloc(env);
        for expr in prelude {
            if let Err(err) = eval(hs, expr, env.clone()) {
                panic!("unexpected error evaluating prelude: {}", err);
            }
        }
        env
    }
}

impl<'h> EnvironmentRef<'h> {
    pub fn push(&self, key: InternedString, value: Value<'h>) {
        self.names().push(GcLeaf::new(key));
        self.values().push(value);
    }

    pub fn lookup(&self, name: InternedString) -> Result<(EnvironmentRef<'h>, usize), String> {
        let mut next = Some(self.clone());
        while let Some(env) = next {
            let names = env.names();
            for i in (0..names.len()).rev() {
                if name == *names.get(i) {
                    return Ok((env, i));
                }
            }
            next = env.parent();
        }
        Err(format!("undefined symbol: {:?}", name.as_str()))
    }

    pub fn get(&self, name: InternedString) -> Result<Value<'h>, String> {
        let (env, i) = self.lookup(name)?;
        Ok(env.values().get(i))
    }

    pub fn set(&self, name: InternedString, value: Value<'h>) -> Result<(), String> {
        let (env, i) = self.lookup(name)?;
        env.values().set(i, value);
        Ok(())
    }
}

#[macro_export]
macro_rules! lisp {
    { ( ) , $_hs:expr } => {
        Nil
    };
    { ( $h:tt $($t:tt)* ) , $hs:expr } => {
        {
            let h = lisp!($h, $hs);
            let t = lisp!(($($t)*), $hs);
            Cons($hs.alloc(Pair { car: h, cdr: t }))
        }
    };
    { $s:tt , $_hs:expr } => {
        {
            let s = stringify!($s);  // lame, but nothing else matches after an `ident` match fails
            if s.starts_with(|c: char| c.is_digit(10)) {
                Int(s.parse().expect("invalid numeric literal in `lisp!`"))
            } else {
                Symbol(Arc::new(s.to_string()))
            }
        }
    };
}

fn parse_pair<'h>(v: Value<'h>, msg: &'static str) -> Result<(Value<'h>, Value<'h>), String> {
    match v {
        Cons(r) => Ok((r.car(), r.cdr())),
        _ => Err(msg.to_string()),
    }
}

fn map_eval<'h>(
    hs: &mut GcHeapSession<'h>,
    exprs: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Vec<Value<'h>>, String> {
    exprs
        .into_iter()
        .map(|expr_res| eval(hs, expr_res?, env.clone()))
        .collect()
}

pub fn eval_block_body<'h>(
    hs: &mut GcHeapSession<'h>,
    exprs: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Trampoline<'h>, String> {
    let mut it = exprs.into_iter().peekable();
    while let Some(expr_res) = it.next() {
        let expr = expr_res?;
        if it.peek().is_some() {
            let _ = eval(hs, expr, env.clone());
        } else {
            return eval_to_tail_call(hs, expr, env);
        }
    }
    return Ok(Trampoline::Value(Nil));
}

pub fn apply<'h>(
    hs: &mut GcHeapSession<'h>,
    fval: Value<'h>,
    mut args: Vec<Value<'h>>,
) -> Result<Trampoline<'h>, String> {
    match fval {
        Builtin(f) => (f.0)(hs, args),
        Lambda(pair) => {
            let parent = Some(match pair.cdr() {
                Environment(pe) => pe,
                _ => panic!("internal error: bad lambda"),
            });
            let (mut params, body) = parse_pair(pair.car(), "syntax error in lambda")?;
            let names = hs.alloc(Vec::<GcLeaf<InternedString>>::new());
            let values = hs.alloc(Vec::<Value<'h>>::new());
            let env = hs.alloc(Environment {
                parent,
                names,
                values,
            });

            let mut i = 0;
            while let Cons(pair) = params {
                if i > args.len() {
                    return Err("apply: not enough arguments".to_string());
                }
                if let Symbol(s) = pair.car() {
                    env.push(s.unwrap(), args[i].clone());
                } else {
                    return Err("syntax error in lambda arguments".to_string());
                }
                params = pair.cdr();
                i += 1;
            }
            if let Symbol(rest_name) = params {
                let mut rest_list = Nil;
                for v in args.drain(i..).rev() {
                    rest_list = Cons(hs.alloc(Pair {
                        car: v,
                        cdr: rest_list,
                    }));
                }
                env.push(rest_name.unwrap(), rest_list);
            } else if i < args.len() {
                return Err("apply: too many arguments".to_string());
            }
            let result = eval_block_body(hs, body, env)?;
            Ok(result)
        }
        _ => Err("apply: not a function".to_string()),
    }
}

/// Evaluate `expr` until we reach a tail call, at which point it is packaged up
/// as a `Trampoline::TailCall` and returned so we can unwind the stack before
/// continuing evaluation.
fn eval_to_tail_call<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Trampoline<'h>, String> {
    match expr {
        Symbol(s) => env.get(s.unwrap()).map(Trampoline::Value),
        Cons(p) => {
            let f = p.car();
            if let Symbol(ref s) = f {
                if s.as_str() == "lambda" {
                    return Ok(Trampoline::Value(Lambda(hs.alloc(Pair {
                        car: p.cdr(),
                        cdr: Value::Environment(env.clone()),
                    }))));
                } else if s.as_str() == "quote" {
                    let (datum, rest) = parse_pair(p.cdr(), "(quote) with no arguments")?;
                    if !rest.is_nil() {
                        return Err("too many arguments to (quote)".to_string());
                    }
                    return Ok(Trampoline::Value(datum));
                } else if s.as_str() == "if" {
                    let (cond, rest) = parse_pair(p.cdr(), "(if) with no arguments")?;
                    let (t_expr, rest) = parse_pair(rest, "missing arguments after (if COND)")?;
                    let (f_expr, rest) =
                        parse_pair(rest, "missing 'else' argument after (if COND X)")?;
                    if !rest.is_nil() {
                        return Err("too many arguments in (if) expression".to_string());
                    }
                    let cond_result = eval(hs, cond, env.clone())?;
                    let selected_expr = if cond_result.to_bool() {
                        t_expr
                    } else {
                        f_expr
                    };
                    return eval_to_tail_call(hs, selected_expr, env);
                } else if s.as_str() == "begin" {
                    return eval_block_body(hs, p.cdr(), env.clone());
                } else if s.as_str() == "define" {
                    let (name, rest) = parse_pair(p.cdr(), "(define) with no name")?;
                    match name {
                        Symbol(s) => {
                            let (expr, rest) = parse_pair(rest, "(define) with no value")?;
                            match rest {
                                Nil => {}
                                _ => {
                                    return Err(
                                        "too many items in (define) special form".to_string(),
                                    )
                                }
                            };

                            let val = eval(hs, expr, env.clone())?;
                            env.push(s.unwrap(), val);
                            return Ok(Trampoline::Value(Nil));
                        }
                        Cons(pair) => {
                            let name = match pair.car() {
                                Symbol(s) => s,
                                _ => return Err("(define) with no name".to_string()),
                            };
                            let code = Cons(hs.alloc(Pair {
                                car: pair.cdr(), // formals
                                cdr: rest,
                            }));
                            let f = Lambda(hs.alloc(Pair {
                                car: code,
                                cdr: Value::Environment(env.clone()),
                            }));
                            env.push(name.unwrap(), f);
                            return Ok(Trampoline::Value(Nil));
                        }
                        _ => {
                            return Err("(define) with a non-symbol name".to_string());
                        }
                    }
                } else if s.as_str() == "set!" {
                    let (first, rest) = parse_pair(p.cdr(), "(set!) with no name")?;
                    let name = first.as_symbol("(set!) first argument must be a name")?;
                    let (expr, rest) = parse_pair(rest, "(set!) with no value")?;
                    if !rest.is_nil() {
                        return Err("(set!): too many arguments".to_string());
                    }
                    let val = eval(hs, expr, env.clone())?;
                    env.set(name, val)?;
                    return Ok(Trampoline::Value(Nil));
                }
            }
            let func = eval(hs, f, env.clone())?;
            let args = map_eval(hs, p.cdr(), env)?;
            Ok(Trampoline::TailCall { func, args })
        }
        Builtin(_) => Err(format!("builtin function found in source code")),
        Vector(_) => Err(format!("vectors are not expressions")),
        _ => Ok(Trampoline::Value(expr)),  // nil and numbers are self-evaluating
    }
}

/// Evaluate the give expression in the given environment, and return the
/// resulting value.
pub fn eval<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Value<'h>, String> {
    let tail = eval_to_tail_call(hs, expr, env)?;
    tail.eval(hs)
}

#[cfg(test)]
include!("tests.rs");
<commit_msg>lisp: Fix `lisp!` macro which I busted a minute ago<commit_after>//! If you use enough force, you can actually use this GC to implement a toy VM.

use builtins;
use cell_gc::{GcHeapSession, GcLeaf};
use cell_gc::collections::VecRef;
use parser;
use value::{BuiltinFnPtr, InternedString, Pair, Value};
use value::Value::*;

/// A potentially partially evaluated value.
pub enum Trampoline<'h> {
    /// A completely evaluated value.
    Value(Value<'h>),
    /// The continuation of a partial evaluation in tail position. The stack
    /// should be unwound before resumption of its evaluation.
    TailCall {
        func: Value<'h>,
        args: Vec<Value<'h>>,
    },
}

impl<'h> Trampoline<'h> {
    /// Complete the evaluation of this value. Avoids recursion to implement
    /// proper tail calls and keep from blowing the stack.
    pub fn eval(mut self, hs: &mut GcHeapSession<'h>) -> Result<Value<'h>, String> {
        while let Trampoline::TailCall { func, args } = self {
            self = apply(hs, func, args)?;
        }
        match self {
            Trampoline::Value(v) => Ok(v),
            Trampoline::TailCall { .. } => unreachable!(),
        }
    }
}

#[derive(Clone, Debug, PartialEq, IntoHeap)]
pub struct Environment<'h> {
    parent: Option<EnvironmentRef<'h>>,
    names: VecRef<'h, GcLeaf<InternedString>>,
    values: VecRef<'h, Value<'h>>,
}

impl<'h> Environment<'h> {
    pub fn default_env(hs: &mut GcHeapSession<'h>) -> EnvironmentRef<'h> {
        let env = Environment {
            parent: None,
            names: hs.alloc(vec![]),
            values: hs.alloc(vec![]),
        };

        macro_rules! builtin {
            ( $lisp_ident:expr , $func:expr ) => {
                env.names.push(GcLeaf::new(InternedString::get($lisp_ident)));
                env.values.push(Builtin(GcLeaf::new(BuiltinFnPtr($func))));
            }
        }

        builtin!("+", builtins::add);
        builtin!("-", builtins::sub);
        builtin!("*", builtins::mul);
        builtin!("=", builtins::numeric_eq);
        builtin!("<", builtins::numeric_lt);
        builtin!(">", builtins::numeric_gt);
        builtin!("<=", builtins::numeric_le);
        builtin!(">=", builtins::numeric_ge);
        builtin!("apply", builtins::apply);
        builtin!("assert", builtins::assert);
        builtin!("car", builtins::car);
        builtin!("cdr", builtins::cdr);
        builtin!("cons", builtins::cons);
        builtin!("eqv?", builtins::eqv_question);
        builtin!("eq?", builtins::eq_question);
        builtin!("print", builtins::print);
        builtin!("boolean?", builtins::boolean_question);
        builtin!("null?", builtins::null_question);
        builtin!("pair?", builtins::pair_question);
        builtin!("procedure?", builtins::procedure_question);
        builtin!("vector?", builtins::vector_question);
        builtin!("vector", builtins::vector);
        builtin!("vector-length", builtins::vector_length);
        builtin!("vector-ref", builtins::vector_ref);

        const PRELUDE: &'static str = include_str!("prelude.sch");
        let prelude = match parser::parse(hs, PRELUDE) {
            Ok(forms) => forms,
            Err(err) => panic!("unexpected error parsing prelude: {}", err),
        };

        let env = hs.alloc(env);
        for expr in prelude {
            if let Err(err) = eval(hs, expr, env.clone()) {
                panic!("unexpected error evaluating prelude: {}", err);
            }
        }
        env
    }
}

impl<'h> EnvironmentRef<'h> {
    pub fn push(&self, key: InternedString, value: Value<'h>) {
        self.names().push(GcLeaf::new(key));
        self.values().push(value);
    }

    pub fn lookup(&self, name: InternedString) -> Result<(EnvironmentRef<'h>, usize), String> {
        let mut next = Some(self.clone());
        while let Some(env) = next {
            let names = env.names();
            for i in (0..names.len()).rev() {
                if name == *names.get(i) {
                    return Ok((env, i));
                }
            }
            next = env.parent();
        }
        Err(format!("undefined symbol: {:?}", name.as_str()))
    }

    pub fn get(&self, name: InternedString) -> Result<Value<'h>, String> {
        let (env, i) = self.lookup(name)?;
        Ok(env.values().get(i))
    }

    pub fn set(&self, name: InternedString, value: Value<'h>) -> Result<(), String> {
        let (env, i) = self.lookup(name)?;
        env.values().set(i, value);
        Ok(())
    }
}

#[macro_export]
macro_rules! lisp {
    { ( ) , $_hs:expr } => {
        Nil
    };
    { ( $h:tt $($t:tt)* ) , $hs:expr } => {
        {
            let h = lisp!($h, $hs);
            let t = lisp!(($($t)*), $hs);
            Cons($hs.alloc(Pair { car: h, cdr: t }))
        }
    };
    { $s:tt , $_hs:expr } => {
        {
            let s = stringify!($s);  // lame, but nothing else matches after an `ident` match fails
            if s.starts_with(|c: char| c.is_digit(10)) {
                Int(s.parse().expect("invalid numeric literal in `lisp!`"))
            } else {
                Symbol($crate::cell_gc::GcLeaf::new($crate::value::InternedString::get(s)))
            }
        }
    };
}

fn parse_pair<'h>(v: Value<'h>, msg: &'static str) -> Result<(Value<'h>, Value<'h>), String> {
    match v {
        Cons(r) => Ok((r.car(), r.cdr())),
        _ => Err(msg.to_string()),
    }
}

fn map_eval<'h>(
    hs: &mut GcHeapSession<'h>,
    exprs: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Vec<Value<'h>>, String> {
    exprs
        .into_iter()
        .map(|expr_res| eval(hs, expr_res?, env.clone()))
        .collect()
}

pub fn eval_block_body<'h>(
    hs: &mut GcHeapSession<'h>,
    exprs: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Trampoline<'h>, String> {
    let mut it = exprs.into_iter().peekable();
    while let Some(expr_res) = it.next() {
        let expr = expr_res?;
        if it.peek().is_some() {
            let _ = eval(hs, expr, env.clone());
        } else {
            return eval_to_tail_call(hs, expr, env);
        }
    }
    return Ok(Trampoline::Value(Nil));
}

pub fn apply<'h>(
    hs: &mut GcHeapSession<'h>,
    fval: Value<'h>,
    mut args: Vec<Value<'h>>,
) -> Result<Trampoline<'h>, String> {
    match fval {
        Builtin(f) => (f.0)(hs, args),
        Lambda(pair) => {
            let parent = Some(match pair.cdr() {
                Environment(pe) => pe,
                _ => panic!("internal error: bad lambda"),
            });
            let (mut params, body) = parse_pair(pair.car(), "syntax error in lambda")?;
            let names = hs.alloc(Vec::<GcLeaf<InternedString>>::new());
            let values = hs.alloc(Vec::<Value<'h>>::new());
            let env = hs.alloc(Environment {
                parent,
                names,
                values,
            });

            let mut i = 0;
            while let Cons(pair) = params {
                if i > args.len() {
                    return Err("apply: not enough arguments".to_string());
                }
                if let Symbol(s) = pair.car() {
                    env.push(s.unwrap(), args[i].clone());
                } else {
                    return Err("syntax error in lambda arguments".to_string());
                }
                params = pair.cdr();
                i += 1;
            }
            if let Symbol(rest_name) = params {
                let mut rest_list = Nil;
                for v in args.drain(i..).rev() {
                    rest_list = Cons(hs.alloc(Pair {
                        car: v,
                        cdr: rest_list,
                    }));
                }
                env.push(rest_name.unwrap(), rest_list);
            } else if i < args.len() {
                return Err("apply: too many arguments".to_string());
            }
            let result = eval_block_body(hs, body, env)?;
            Ok(result)
        }
        _ => Err("apply: not a function".to_string()),
    }
}

/// Evaluate `expr` until we reach a tail call, at which point it is packaged up
/// as a `Trampoline::TailCall` and returned so we can unwind the stack before
/// continuing evaluation.
fn eval_to_tail_call<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Trampoline<'h>, String> {
    match expr {
        Symbol(s) => env.get(s.unwrap()).map(Trampoline::Value),
        Cons(p) => {
            let f = p.car();
            if let Symbol(ref s) = f {
                if s.as_str() == "lambda" {
                    return Ok(Trampoline::Value(Lambda(hs.alloc(Pair {
                        car: p.cdr(),
                        cdr: Value::Environment(env.clone()),
                    }))));
                } else if s.as_str() == "quote" {
                    let (datum, rest) = parse_pair(p.cdr(), "(quote) with no arguments")?;
                    if !rest.is_nil() {
                        return Err("too many arguments to (quote)".to_string());
                    }
                    return Ok(Trampoline::Value(datum));
                } else if s.as_str() == "if" {
                    let (cond, rest) = parse_pair(p.cdr(), "(if) with no arguments")?;
                    let (t_expr, rest) = parse_pair(rest, "missing arguments after (if COND)")?;
                    let (f_expr, rest) =
                        parse_pair(rest, "missing 'else' argument after (if COND X)")?;
                    if !rest.is_nil() {
                        return Err("too many arguments in (if) expression".to_string());
                    }
                    let cond_result = eval(hs, cond, env.clone())?;
                    let selected_expr = if cond_result.to_bool() {
                        t_expr
                    } else {
                        f_expr
                    };
                    return eval_to_tail_call(hs, selected_expr, env);
                } else if s.as_str() == "begin" {
                    return eval_block_body(hs, p.cdr(), env.clone());
                } else if s.as_str() == "define" {
                    let (name, rest) = parse_pair(p.cdr(), "(define) with no name")?;
                    match name {
                        Symbol(s) => {
                            let (expr, rest) = parse_pair(rest, "(define) with no value")?;
                            match rest {
                                Nil => {}
                                _ => {
                                    return Err(
                                        "too many items in (define) special form".to_string(),
                                    )
                                }
                            };

                            let val = eval(hs, expr, env.clone())?;
                            env.push(s.unwrap(), val);
                            return Ok(Trampoline::Value(Nil));
                        }
                        Cons(pair) => {
                            let name = match pair.car() {
                                Symbol(s) => s,
                                _ => return Err("(define) with no name".to_string()),
                            };
                            let code = Cons(hs.alloc(Pair {
                                car: pair.cdr(), // formals
                                cdr: rest,
                            }));
                            let f = Lambda(hs.alloc(Pair {
                                car: code,
                                cdr: Value::Environment(env.clone()),
                            }));
                            env.push(name.unwrap(), f);
                            return Ok(Trampoline::Value(Nil));
                        }
                        _ => {
                            return Err("(define) with a non-symbol name".to_string());
                        }
                    }
                } else if s.as_str() == "set!" {
                    let (first, rest) = parse_pair(p.cdr(), "(set!) with no name")?;
                    let name = first.as_symbol("(set!) first argument must be a name")?;
                    let (expr, rest) = parse_pair(rest, "(set!) with no value")?;
                    if !rest.is_nil() {
                        return Err("(set!): too many arguments".to_string());
                    }
                    let val = eval(hs, expr, env.clone())?;
                    env.set(name, val)?;
                    return Ok(Trampoline::Value(Nil));
                }
            }
            let func = eval(hs, f, env.clone())?;
            let args = map_eval(hs, p.cdr(), env)?;
            Ok(Trampoline::TailCall { func, args })
        }
        Builtin(_) => Err(format!("builtin function found in source code")),
        Vector(_) => Err(format!("vectors are not expressions")),
        _ => Ok(Trampoline::Value(expr)),  // nil and numbers are self-evaluating
    }
}

/// Evaluate the give expression in the given environment, and return the
/// resulting value.
pub fn eval<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
    env: EnvironmentRef<'h>,
) -> Result<Value<'h>, String> {
    let tail = eval_to_tail_call(hs, expr, env)?;
    tail.eval(hs)
}

#[cfg(test)]
include!("tests.rs");
<|endoftext|>