<commit_before>use IndyContext;
use command_executor::{Command, CommandMetadata, Group as GroupTrait, GroupMetadata};
use commands::{get_opt_i64_param, get_str_param, get_opt_str_param};

use libindy::ErrorCode;
use libindy::wallet::Wallet;

use serde_json::Value as JSONValue;
use serde_json::Map as JSONMap;

use std::collections::HashMap;
use std::rc::Rc;

pub struct Group {
    metadata: GroupMetadata
}

impl Group {
    pub fn new() -> Group {
        Group {
            metadata: GroupMetadata::new("wallet", "Wallet management commands")
        }
    }
}

impl GroupTrait for Group {
    fn metadata(&self) -> &GroupMetadata {
        &self.metadata
    }
}

#[derive(Debug)]
pub struct CreateCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct OpenCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct ListCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct CloseCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct DeleteCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

impl CreateCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CreateCommand {
        CreateCommand {
            ctx,
            metadata: CommandMetadata::build("create", "Create new wallet with specified name")
                .add_main_param("name", "The name of new wallet")
                .add_param("pool_name", false, "The name of associated Indy pool")
                .add_param("key", true, "Auth key for the wallet")
                .finalize()
        }
    }
}

impl Command for CreateCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("CreateCommand::execute >> self {:?} params {:?}", self, params);

        let pool_name = get_str_param("pool_name", params).map_err(log_err!())?;
        let name = get_str_param("name", params).map_err(log_err!())?;
        let key = get_opt_str_param("key", params).map_err(log_err!())?;

        let config: Option<String> = key.map(|key| json!({ "key": key }).to_string());

        trace!(r#"Wallet::create_wallet try: name {}, pool_name {}, config {:?}"#, name, pool_name, config);

        let res = Wallet::create_wallet(pool_name,
                                        name,
                                        None,
                                        config.as_ref().map(String::as_str));

        trace!(r#"Wallet::create_wallet return: {:?}"#, res);

        let res = match res {
            Ok(()) => Ok(println_succ!("Wallet \"{}\" has been created", name)),
            Err(ErrorCode::WalletAlreadyExistsError) => Err(println_err!("Wallet \"{}\" already exists", name)),
            Err(err) => Err(println_err!("Wallet \"{}\" create failed with unexpected Indy SDK error {:?}", name, err)),
        };

        trace!("CreateCommand::execute << {:?}", res);
        res
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}

impl OpenCommand {
    pub fn new(ctx: Rc<IndyContext>) -> OpenCommand {
        OpenCommand {
            ctx,
            metadata: CommandMetadata::build("open", "Open wallet with specified name. Also close previously opened.")
                .add_main_param("name", "The name of wallet")
                .finalize()
        }
    }
}

impl Command for OpenCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("OpenCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(log_err!())?;
        let key = get_opt_str_param("key", params).map_err(log_err!())?;
        let rekey = get_opt_str_param("rekey", params).map_err(log_err!())?;
        let freshness_time = get_opt_i64_param("freshness_time", params).map_err(log_err!())?;

        let config = {
            let mut json = JSONMap::new();

            if let Some(key) = key {
                json.insert("key".to_string(), JSONValue::from(key));
            }

            if let Some(rekey) = rekey {
                json.insert("rekey".to_string(), JSONValue::from(rekey));
            }

            if let Some(freshness_time) = freshness_time {
                json.insert("freshness_time".to_string(), JSONValue::from(freshness_time));
            }

            if !json.is_empty() {
                Some(JSONValue::from(json).to_string())
            } else {
                None
            }
        };

        //TODO close previously opened wallet
        let res = match Wallet::open_wallet(name, config.as_ref().map(String::as_str)) {
            Ok(handle) => {
                self.ctx.set_opened_wallet(name, handle);
                Ok(println_succ!("Wallet \"{}\" has been opened", name))
            }
            Err(ErrorCode::WalletAlreadyOpenedError) => Err(println_err!("Wallet \"{}\" already opened", name)),
            Err(err) => Err(println_err!("Wallet \"{}\" open failed with unexpected Indy SDK error {:?}", name, err)),
        };

        trace!("CreateCommand::execute << {:?}", res);
        Ok(())
    }
}

impl ListCommand {
    pub fn new(ctx: Rc<IndyContext>) -> ListCommand {
        ListCommand {
            ctx,
            metadata: CommandMetadata::build("list", "List existing wallets.")
                .finalize()
        }
    }
}

impl Command for ListCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("ListCommand::execute >> self {:?} params {:?}", self, params);

        let res = match Wallet::list_wallets() {
            Ok(wallets) => {
                let wallets = wallets.replace("},{", "}\n{").replace("]", "").replace("[", "");
                //TODO parse JSON and print table
                if wallets.trim().len() > 0 {
                    println_succ!("Existing wallets: \n{}", wallets.trim());
                } else {
                    println_succ!("There are no wallets");
                }
                if let Some(cur_wallet) = self.ctx.get_opened_wallet_name() {
                    println_succ!("Current wallet \"{}\"", cur_wallet);
                }
                Ok(())
            }
            Err(err) => Err(println_err!("List wallets failed with unexpected Indy SDK error {:?}", err)),
        };

        trace!("ListCommand::execute << {:?}", res);
        res
    }
}

impl CloseCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CloseCommand {
        CloseCommand {
            ctx,
            metadata: CommandMetadata::build("close", "Close wallet with specified handle.")
                .finalize()
        }
    }
}

impl Command for CloseCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("OpenCommand::execute >> self {:?} params {:?}", self, params);

        let (name, wallet_handle) = if let Some(opened_wallet) = self.ctx.get_opened_wallet() {
            opened_wallet
        } else {
            return Err(println_err!("There is no opened wallet now"));
        };

        let res = match Wallet::close_wallet(wallet_handle) {
            Ok(()) => {
                self.ctx.unset_opened_wallet();
                Ok(println_succ!("Wallet \"{}\" has been closed", name))
            }
            Err(err) => Err(println_err!("Wallet \"{}\" close failed with unexpected Indy SDK error {:?}", name, err)),
        };

        trace!("CloseCommand::execute << {:?}", res);
        res
    }
}

impl DeleteCommand {
    pub fn new(ctx: Rc<IndyContext>) -> DeleteCommand {
        DeleteCommand {
            ctx,
            metadata: CommandMetadata::build("delete", "Delete wallet with specified name")
                .add_main_param("name", "The name of deleted wallet")
                .finalize()
        }
    }
}

impl Command for DeleteCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("DeleteCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(log_err!())?;

        trace!(r#"Wallet::delete_wallet try: name {}"#, name);

        let res = Wallet::delete_wallet(name);

        trace!(r#"Wallet::delete_wallet return: {:?}"#, res);

        let res = match res {
            Ok(()) => Ok(println_succ!("Wallet \"{}\" has been deleted", name)),
            Err(err) => Err(println_err!("Wallet \"{}\" delete failed with unexpected Indy SDK error {:?}", name, err)),
        };

        trace!("DeleteCommand::execute << {:?}", res);
        res
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}

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

    use std::cell::RefCell;

    mod create {
        use super::*;

        #[test]
        pub fn exec_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));
            let cmd = CreateCommand::new(ctx);
            cmd.metadata().help();
            let mut params = HashMap::new();
            params.insert("name", "wallet");
            params.insert("pool_name", "pool");
            cmd.execute(&params).unwrap();
            TestUtils::cleanup_storage();
        }
    }

    mod open {
        use super::*;

        #[test]
        pub fn exec_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));
            let cmd = OpenCommand::new(ctx);
            let mut params = HashMap::new();
            cmd.metadata().help();
            params.insert("name", "wallet");
            cmd.execute(&params).unwrap_err(); //open not created wallet
            TestUtils::cleanup_storage();
        }

        //TODO add open_for_created_works
    }

    mod close {
        use super::*;

        #[test]
        pub fn exec_for_opened_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));

            {
                let cmd = CreateCommand::new(ctx.clone());
                let mut params = HashMap::new();
                params.insert("name", "wallet");
                params.insert("pool_name", "pool");
                cmd.execute(&params).unwrap();
            }
            {
                let cmd = OpenCommand::new(ctx.clone());
                let mut params = HashMap::new();
                params.insert("name", "wallet");
                cmd.execute(&params).unwrap();
            }

            let cmd = CloseCommand::new(ctx.clone());
            let params = HashMap::new();
            cmd.execute(&params).unwrap();

            TestUtils::cleanup_storage();
        }
    }
}<commit_msg>[cli] Add missed command params for wallet.<commit_after>use indy_context::IndyContext;
use command_executor::{Command, CommandMetadata, Group as GroupTrait, GroupMetadata};
use commands::{get_opt_i64_param, get_str_param, get_opt_str_param};

use libindy::ErrorCode;
use libindy::wallet::Wallet;

use serde_json::Value as JSONValue;
use serde_json::Map as JSONMap;

use std::collections::HashMap;
use std::rc::Rc;

pub struct Group {
    metadata: GroupMetadata
}

impl Group {
    pub fn new() -> Group {
        Group {
            metadata: GroupMetadata::new("wallet", "Wallet management commands")
        }
    }
}

impl GroupTrait for Group {
    fn metadata(&self) -> &GroupMetadata {
        &self.metadata
    }
}

#[derive(Debug)]
pub struct CreateCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct OpenCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct ListCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct CloseCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

#[derive(Debug)]
pub struct DeleteCommand {
    ctx: Rc<IndyContext>,
    metadata: CommandMetadata,
}

impl CreateCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CreateCommand {
        CreateCommand {
            ctx,
            metadata: CommandMetadata::build("create", "Create new wallet with specified name")
                .add_main_param("name", "The name of new wallet")
                .add_param("pool_name", false, "The name of associated Indy pool")
                .add_param("key", true, "Auth key for the wallet")
                .finalize()
        }
    }
}

impl Command for CreateCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("CreateCommand::execute >> self {:?} params {:?}", self, params);

        let pool_name = get_str_param("pool_name", params).map_err(log_err!())?;
        let name = get_str_param("name", params).map_err(log_err!())?;
        let key = get_opt_str_param("key", params).map_err(log_err!())?;

        let config: Option<String> = key.map(|key| json!({ "key": key }).to_string());

        trace!(r#"Wallet::create_wallet try: name {}, pool_name {}, config {:?}"#, name, pool_name, config);

        let res = Wallet::create_wallet(pool_name,
                                        name,
                                        None,
                                        config.as_ref().map(String::as_str));

        trace!(r#"Wallet::create_wallet return: {:?}"#, res);

        let res = match res {
            Ok(()) => Ok(println_succ!("Wallet \"{}\" has been created", name)),
            Err(ErrorCode::WalletAlreadyExistsError) => Err(println_err!("Wallet \"{}\" already exists", name)),
            Err(err) => Err(println_err!("Wallet \"{}\" create failed with unexpected Indy SDK error {:?}", name, err)),
        };

        trace!("CreateCommand::execute << {:?}", res);
        res
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}

impl OpenCommand {
    pub fn new(ctx: Rc<IndyContext>) -> OpenCommand {
        OpenCommand {
            ctx,
            metadata: CommandMetadata::build("open", "Open wallet with specified name. Also close previously opened.")
                .add_main_param("name", "The name of wallet")
                .add_param("key", true, "Auth key for the wallet")
                .add_param("rekey", true, "New auth key for the wallet (will replace previous one).")
                .add_param("freshness_time", true, "Freshness time for entities in the wallet")
                .finalize()
        }
    }
}

impl Command for OpenCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("OpenCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(log_err!())?;
        let key = get_opt_str_param("key", params).map_err(log_err!())?;
        let rekey = get_opt_str_param("rekey", params).map_err(log_err!())?;
        let freshness_time = get_opt_i64_param("freshness_time", params).map_err(log_err!())?;

        let config = {
            let mut json = JSONMap::new();

            if let Some(key) = key {
                json.insert("key".to_string(), JSONValue::from(key));
            }

            if let Some(rekey) = rekey {
                json.insert("rekey".to_string(), JSONValue::from(rekey));
            }

            if let Some(freshness_time) = freshness_time {
                json.insert("freshness_time".to_string(), JSONValue::from(freshness_time));
            }

            if !json.is_empty() {
                Some(JSONValue::from(json).to_string())
            } else {
                None
            }
        };

        //TODO close previously opened wallet
        let res = match Wallet::open_wallet(name, config.as_ref().map(String::as_str)) {
            Ok(handle) => {
                self.ctx.set_opened_wallet(name, handle);
                Ok(println_succ!("Wallet \"{}\" has been opened", name))
            }
            Err(ErrorCode::WalletAlreadyOpenedError) => Err(println_err!("Wallet \"{}\" already opened", name)),
            Err(err) => Err(println_err!("Wallet \"{}\" open failed with unexpected Indy SDK error {:?}", name, err)),
        };

        trace!("CreateCommand::execute << {:?}", res);
        Ok(())
    }
}

impl ListCommand {
    pub fn new(ctx: Rc<IndyContext>) -> ListCommand {
        ListCommand {
            ctx,
            metadata: CommandMetadata::build("list", "List existing wallets.")
                .finalize()
        }
    }
}

impl Command for ListCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("ListCommand::execute >> self {:?} params {:?}", self, params);

        let res = match Wallet::list_wallets() {
            Ok(wallets) => {
                let wallets = wallets.replace("},{", "}\n{").replace("]", "").replace("[", "");
                //TODO parse JSON and print table
                if wallets.trim().len() > 0 {
                    println_succ!("Existing wallets: \n{}", wallets.trim());
                } else {
                    println_succ!("There are no wallets");
                }
                if let Some(cur_wallet) = self.ctx.get_opened_wallet_name() {
                    println_succ!("Current wallet \"{}\"", cur_wallet);
                }
                Ok(())
            }
            Err(err) => Err(println_err!("List wallets failed with unexpected Indy SDK error {:?}", err)),
        };

        trace!("ListCommand::execute << {:?}", res);
        res
    }
}

impl CloseCommand {
    pub fn new(ctx: Rc<IndyContext>) -> CloseCommand {
        CloseCommand {
            ctx,
            metadata: CommandMetadata::build("close", "Close opened wallet.")
                .finalize()
        }
    }
}

impl Command for CloseCommand {
    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }

    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("OpenCommand::execute >> self {:?} params {:?}", self, params);

        let (name, wallet_handle) = if let Some(opened_wallet) = self.ctx.get_opened_wallet() {
            opened_wallet
        } else {
            return Err(println_err!("There is no opened wallet now"));
        };

        let res = match Wallet::close_wallet(wallet_handle) {
            Ok(()) => {
                self.ctx.unset_opened_wallet();
                Ok(println_succ!("Wallet \"{}\" has been closed", name))
            }
            Err(err) => Err(println_err!("Wallet \"{}\" close failed with unexpected Indy SDK error {:?}", name, err)),
        };

        trace!("CloseCommand::execute << {:?}", res);
        res
    }
}

impl DeleteCommand {
    pub fn new(ctx: Rc<IndyContext>) -> DeleteCommand {
        DeleteCommand {
            ctx,
            metadata: CommandMetadata::build("delete", "Delete wallet with specified name")
                .add_main_param("name", "The name of deleted wallet")
                .finalize()
        }
    }
}

impl Command for DeleteCommand {
    fn execute(&self, params: &HashMap<&'static str, &str>) -> Result<(), ()> {
        trace!("DeleteCommand::execute >> self {:?} params {:?}", self, params);

        let name = get_str_param("name", params).map_err(log_err!())?;

        trace!(r#"Wallet::delete_wallet try: name {}"#, name);

        let res = Wallet::delete_wallet(name);

        trace!(r#"Wallet::delete_wallet return: {:?}"#, res);

        let res = match res {
            Ok(()) => Ok(println_succ!("Wallet \"{}\" has been deleted", name)),
            Err(err) => Err(println_err!("Wallet \"{}\" delete failed with unexpected Indy SDK error {:?}", name, err)),
        };

        trace!("DeleteCommand::execute << {:?}", res);
        res
    }

    fn metadata(&self) -> &CommandMetadata {
        &self.metadata
    }
}

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

    use std::cell::RefCell;

    mod create {
        use super::*;

        #[test]
        pub fn exec_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));
            let cmd = CreateCommand::new(ctx);
            cmd.metadata().help();
            let mut params = HashMap::new();
            params.insert("name", "wallet");
            params.insert("pool_name", "pool");
            cmd.execute(&params).unwrap();
            TestUtils::cleanup_storage();
        }
    }

    mod open {
        use super::*;

        #[test]
        pub fn exec_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));
            let cmd = OpenCommand::new(ctx);
            let mut params = HashMap::new();
            cmd.metadata().help();
            params.insert("name", "wallet");
            cmd.execute(&params).unwrap_err(); //open not created wallet
            TestUtils::cleanup_storage();
        }

        //TODO add open_for_created_works
    }

    mod close {
        use super::*;

        #[test]
        pub fn exec_for_opened_works() {
            TestUtils::cleanup_storage();
            let ctx = Rc::new((IndyContext { cur_wallet: RefCell::new(None) }));

            {
                let cmd = CreateCommand::new(ctx.clone());
                let mut params = HashMap::new();
                params.insert("name", "wallet");
                params.insert("pool_name", "pool");
                cmd.execute(&params).unwrap();
            }
            {
                let cmd = OpenCommand::new(ctx.clone());
                let mut params = HashMap::new();
                params.insert("name", "wallet");
                cmd.execute(&params).unwrap();
            }

            let cmd = CloseCommand::new(ctx.clone());
            let params = HashMap::new();
            cmd.execute(&params).unwrap();

            TestUtils::cleanup_storage();
        }
    }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate getopts;
extern crate rustc_serialize;
extern crate wtftw_core;
extern crate wtftw_xlib;
extern crate zombie;

use std::env;
use std::rc::Rc;
use std::ops::Deref;
use getopts::Options;
use rustc_serialize::json;
use wtftw_core::config::Config;
use wtftw_core::window_manager::WindowManager;
use wtftw_core::window_system::*;
use wtftw_xlib::XlibWindowSystem;

pub fn parse_window_ids(ids: &str) -> Vec<(Window, u32)> {
    match json::decode(ids) {
        Ok(x) => x,
        _     => Vec::new()
    }
}

fn main() {
    // Parse command line arguments
    let args : Vec<String> = env::args().collect();

    let mut options = Options::new();
    options.optopt("r", "resume", "list of window IDs to capture in resume", "WINDOW");
    let matches = match options.parse(args.into_iter().skip(1).collect::<Vec<_>>()) {
        Ok(m)  => m,
        Err(f) => panic!(f.to_string())
    };

    // Create a default config.generaluration
    let mut config = Config::initialize();
    // Initialize window system. Use xlib here for now
    debug!("initialize window system");
    let xlib = XlibWindowSystem::new();
    let window_system : Rc<WindowSystem> = Rc::new(xlib);
    // Create the actual window manager
    debug!("create window manager");
    let mut window_manager = WindowManager::new(window_system.deref(), &config.general);

    // If available, compile the config.general file at ~/.wtftw/config.general.rs
    // and call the config.generalure method
    config.compile_and_call(&mut window_manager, window_system.deref());
    window_manager = WindowManager::new(window_system.deref(), &config.general);

    // Output some initial information
    info!("WTFTW - Window Tiling For The Win");
    info!("Starting wtftw on {} screen(s)", window_system.get_screen_infos().len());

    // Output information about displays
    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
    }

    debug!("Size of keyhandlers after config.generaluration: {}", config.internal.key_handlers.len());

    for (command, _) in config.internal.key_handlers.iter() {
        window_system.grab_keys(vec!(command.clone()));
    }

    for (&command, _) in config.internal.mouse_handlers.iter() {
        window_system.grab_button(command);
    }

    let window_ids = if matches.opt_present("r") {
        debug!("trying to manage pre-existing windows");
        debug!("found {}", matches.opt_str("r").unwrap());
        parse_window_ids(&matches.opt_str("r").unwrap())
    } else {
        Vec::new()
    };

    for (window, workspace) in window_ids {
        debug!("re-inserting window {}", window);
        window_manager = window_manager.view(window_system.deref(), workspace, &config.general)
            .manage(window_system.deref(), window, &config.general);
    }

    // Enter the event loop and just listen for events
    while window_manager.running {
        let event = window_system.clone().get_event();
        match event {
            WindowSystemEvent::ClientMessageEvent(_, _, _, _) => {
            },
            WindowSystemEvent::PropertyMessageEvent(process, window, atom) => {
                if process {
                    window_manager = window_system.process_message(&window_manager, &config.general, window, atom);
                }
            },
            // The X11/Wayland configuration changed, so we need to readjust the
            // screen configurations.
            WindowSystemEvent::ConfigurationNotification(window) => {
                if window_system.get_root() == window {
                    debug!("screen configuration changed. rescreen");
                    window_manager = window_manager.rescreen(window_system.deref());
                }
            },
            // A window asked to be reconfigured (i.e. resized, border change, etc.)
            WindowSystemEvent::ConfigurationRequest(window, window_changes, mask) => {
                let floating = window_manager.workspaces.floating.iter().any(|(&x, _)| x == window) ||
                    !window_manager.workspaces.contains(window);
                window_system.configure_window(window, window_changes, mask, floating);
                window_manager = window_manager.windows(window_system.deref(), &config.general, &|x| x.clone());
            },
            // A new window was created, so we need to manage
            // it unless it is already managed by us.
            WindowSystemEvent::WindowCreated(window) => {
                if window_manager.is_window_managed(window) || window_system.overrides_redirect(window) {
                    continue;
                }

                window_manager = window_manager.manage(window_system.deref(), window, &config.general)
                                               .windows(window_system.deref(), &config.general,
                                                        &|x| (config.internal.manage_hook)(x.clone(),
                                                        window_system.clone(), window));
            },
            WindowSystemEvent::WindowUnmapped(window, synthetic) => {
                if synthetic && window_manager.is_window_managed(window) {
                    window_manager = if synthetic || !window_manager.is_waiting_unmap(window) {
                        window_manager.unmanage(window_system.deref(), window, &config.general)
                    } else {
                        window_manager.update_unmap(window)
                    };
                }
                zombie::collect_zombies();
            },
            WindowSystemEvent::WindowDestroyed(window) => {
                if window_manager.is_window_managed(window) {
                    window_manager = window_manager.unmanage(window_system.deref(), window, &config.general)
                        .remove_from_unmap(window);
                }
            },
            // The mouse pointer entered a window's region. If focus following
            // is enabled, we need to set focus to it.
            WindowSystemEvent::Enter(window) => {
                if config.general.focus_follows_mouse && window_manager.is_window_managed(window) {
                    window_manager = window_manager.focus(window, window_system.deref(), &config.general);
                }
            },
            // Mouse button has been pressed. We need to check if there is a mouse handler
            // associated and if necessary, call it. Otherwise it results in a focus action.
            WindowSystemEvent::ButtonPressed(window, subwindow, button, _, _) => {
                let is_root = window_system.get_root() == window;
                let is_sub_root = window_system.get_root() == subwindow || subwindow == 0;
                let act = config.internal.mouse_handlers.get(&button);

                match act {
                    Some(ref action) => {
                        // If it's a root window, then it's an event we grabbed
                        if is_root && !is_sub_root {
                            let local_window_manager = window_manager.clone();
                            window_manager = action(local_window_manager, window_system.clone(),
                                                          &config.general, subwindow);
                        }
                    }
                    None => {
                        // Otherwise just clock to focus
                        if !is_root {
                            window_manager = window_manager.focus(window, window_system.deref(), &config.general);
                        }
                    }
                }
            },
            WindowSystemEvent::ButtonReleased => {
                // If we were dragging, release the pointer and
                // reset the dragging closure
                if let Some(_) = window_manager.dragging {
                    window_system.ungrab_pointer();
                    window_manager.dragging = None;
                }
            }
            WindowSystemEvent::KeyPressed(_, key) => {
                if config.internal.key_handlers.contains_key(&key) {
                    let local_window_manager = window_manager.clone();
                    window_manager = config.internal.key_handlers[&key](local_window_manager,
                        window_system.clone(), &config.general);
                }
            },
            WindowSystemEvent::MouseMotion(x, y) => {
                let local_window_manager = window_manager.clone();
                if let Some(drag) = window_manager.dragging {
                    window_manager = drag(x, y, local_window_manager, window_system.deref());
                    window_system.remove_motion_events();
                }
            },
            _ => ()
        };

        if let Some(ref mut loghook) = config.internal.loghook {
            loghook(window_manager.clone(), window_system.clone());
        }

        window_system.update_server_state(&window_manager);
    }
}
<commit_msg>enable startup hook<commit_after>#[macro_use]
extern crate log;
extern crate getopts;
extern crate rustc_serialize;
extern crate wtftw_core;
extern crate wtftw_xlib;
extern crate zombie;

use std::env;
use std::rc::Rc;
use std::ops::Deref;
use getopts::Options;
use rustc_serialize::json;
use wtftw_core::config::Config;
use wtftw_core::window_manager::WindowManager;
use wtftw_core::window_system::*;
use wtftw_xlib::XlibWindowSystem;

pub fn parse_window_ids(ids: &str) -> Vec<(Window, u32)> {
    match json::decode(ids) {
        Ok(x) => x,
        _     => Vec::new()
    }
}

fn main() {
    // Parse command line arguments
    let args : Vec<String> = env::args().collect();

    let mut options = Options::new();
    options.optopt("r", "resume", "list of window IDs to capture in resume", "WINDOW");
    let matches = match options.parse(args.into_iter().skip(1).collect::<Vec<_>>()) {
        Ok(m)  => m,
        Err(f) => panic!(f.to_string())
    };

    // Create a default config.generaluration
    let mut config = Config::initialize();
    // Initialize window system. Use xlib here for now
    debug!("initialize window system");
    let xlib = XlibWindowSystem::new();
    let window_system : Rc<WindowSystem> = Rc::new(xlib);
    // Create the actual window manager
    debug!("create window manager");
    let mut window_manager = WindowManager::new(window_system.deref(), &config.general);

    // If available, compile the config.general file at ~/.wtftw/config.general.rs
    // and call the config.generalure method
    config.compile_and_call(&mut window_manager, window_system.deref());
    window_manager = WindowManager::new(window_system.deref(), &config.general);

    // Output some initial information
    info!("WTFTW - Window Tiling For The Win");
    info!("Starting wtftw on {} screen(s)", window_system.get_screen_infos().len());

    // Output information about displays
    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
    }

    debug!("Size of keyhandlers after config.generaluration: {}", config.internal.key_handlers.len());

    for (command, _) in config.internal.key_handlers.iter() {
        window_system.grab_keys(vec!(command.clone()));
    }

    for (&command, _) in config.internal.mouse_handlers.iter() {
        window_system.grab_button(command);
    }

    let window_ids = if matches.opt_present("r") {
        debug!("trying to manage pre-existing windows");
        debug!("found {}", matches.opt_str("r").unwrap());
        parse_window_ids(&matches.opt_str("r").unwrap())
    } else {
        Vec::new()
    };

    for (window, workspace) in window_ids {
        debug!("re-inserting window {}", window);
        window_manager = window_manager.view(window_system.deref(), workspace, &config.general)
            .manage(window_system.deref(), window, &config.general);
    }

    window_manager = (*config.internal.startup_hook)(window_manager, window_system.clone(), &config);

    // Enter the event loop and just listen for events
    while window_manager.running {
        let event = window_system.clone().get_event();
        match event {
            WindowSystemEvent::ClientMessageEvent(_, _, _, _) => {
            },
            WindowSystemEvent::PropertyMessageEvent(process, window, atom) => {
                if process {
                    window_manager = window_system.process_message(&window_manager, &config.general, window, atom);
                }
            },
            // The X11/Wayland configuration changed, so we need to readjust the
            // screen configurations.
            WindowSystemEvent::ConfigurationNotification(window) => {
                if window_system.get_root() == window {
                    debug!("screen configuration changed. rescreen");
                    window_manager = window_manager.rescreen(window_system.deref());
                }
            },
            // A window asked to be reconfigured (i.e. resized, border change, etc.)
            WindowSystemEvent::ConfigurationRequest(window, window_changes, mask) => {
                let floating = window_manager.workspaces.floating.iter().any(|(&x, _)| x == window) ||
                    !window_manager.workspaces.contains(window);
                window_system.configure_window(window, window_changes, mask, floating);
                window_manager = window_manager.windows(window_system.deref(), &config.general, &|x| x.clone());
            },
            // A new window was created, so we need to manage
            // it unless it is already managed by us.
            WindowSystemEvent::WindowCreated(window) => {
                if window_manager.is_window_managed(window) || window_system.overrides_redirect(window) {
                    continue;
                }

                window_manager = window_manager.manage(window_system.deref(), window, &config.general)
                                               .windows(window_system.deref(), &config.general,
                                                        &|x| (config.internal.manage_hook)(x.clone(),
                                                        window_system.clone(), window));
            },
            WindowSystemEvent::WindowUnmapped(window, synthetic) => {
                if synthetic && window_manager.is_window_managed(window) {
                    window_manager = if synthetic || !window_manager.is_waiting_unmap(window) {
                        window_manager.unmanage(window_system.deref(), window, &config.general)
                    } else {
                        window_manager.update_unmap(window)
                    };
                }
                zombie::collect_zombies();
            },
            WindowSystemEvent::WindowDestroyed(window) => {
                if window_manager.is_window_managed(window) {
                    window_manager = window_manager.unmanage(window_system.deref(), window, &config.general)
                        .remove_from_unmap(window);
                }
            },
            // The mouse pointer entered a window's region. If focus following
            // is enabled, we need to set focus to it.
            WindowSystemEvent::Enter(window) => {
                if config.general.focus_follows_mouse && window_manager.is_window_managed(window) {
                    window_manager = window_manager.focus(window, window_system.deref(), &config.general);
                }
            },
            // Mouse button has been pressed. We need to check if there is a mouse handler
            // associated and if necessary, call it. Otherwise it results in a focus action.
            WindowSystemEvent::ButtonPressed(window, subwindow, button, _, _) => {
                let is_root = window_system.get_root() == window;
                let is_sub_root = window_system.get_root() == subwindow || subwindow == 0;
                let act = config.internal.mouse_handlers.get(&button);

                match act {
                    Some(ref action) => {
                        // If it's a root window, then it's an event we grabbed
                        if is_root && !is_sub_root {
                            let local_window_manager = window_manager.clone();
                            window_manager = action(local_window_manager, window_system.clone(),
                                                          &config.general, subwindow);
                        }
                    }
                    None => {
                        // Otherwise just clock to focus
                        if !is_root {
                            window_manager = window_manager.focus(window, window_system.deref(), &config.general);
                        }
                    }
                }
            },
            WindowSystemEvent::ButtonReleased => {
                // If we were dragging, release the pointer and
                // reset the dragging closure
                if let Some(_) = window_manager.dragging {
                    window_system.ungrab_pointer();
                    window_manager.dragging = None;
                }
            }
            WindowSystemEvent::KeyPressed(_, key) => {
                if config.internal.key_handlers.contains_key(&key) {
                    let local_window_manager = window_manager.clone();
                    window_manager = config.internal.key_handlers[&key](local_window_manager,
                        window_system.clone(), &config.general);
                }
            },
            WindowSystemEvent::MouseMotion(x, y) => {
                let local_window_manager = window_manager.clone();
                if let Some(drag) = window_manager.dragging {
                    window_manager = drag(x, y, local_window_manager, window_system.deref());
                    window_system.remove_motion_events();
                }
            },
            _ => ()
        };

        if let Some(ref mut loghook) = config.internal.loghook {
            loghook(window_manager.clone(), window_system.clone());
        }

        window_system.update_server_state(&window_manager);
    }
}
<|endoftext|>


<commit_before>//! Demonstrates using OpenTelemetry to instrument `async` functions.
//!
//! This is based on the [`hello_world`] example from `tokio`. and implements a
//! simple client that opens a TCP stream, writes "hello world\n", and closes
//! the connection.
//!
//! You can test this out by running:
//!
//!     ncat -l 6142
//!
//! And then in a second terminal run:
//!
//!     ncat -l 6143
//!
//! And then in a third terminal run:
//!
//!     cargo run --example async_fn
//!
//! [`hello_world`]: https://github.com/tokio-rs/tokio/blob/132e9f1da5965530b63554d7a1c59824c3de4e30/tokio/examples/hello_world.rs
use opentelemetry::{
    api::{trace::futures::FutureExt, Context, TraceContextExt, Tracer},
    global, sdk,
};
use std::time::Duration;
use std::{error::Error, io, net::SocketAddr, thread};
use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;

async fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
    let tracer = global::tracer("connector");
    let span = tracer.start("Connecting");
    let cx = Context::current_with_value(span);

    TcpStream::connect(&addr).with_context(cx).await
}

async fn write(stream: &mut TcpStream) -> io::Result<usize> {
    let tracer = global::tracer("writer");
    let span = tracer.start("Writing");
    let cx = Context::current_with_span(span);

    stream.write(b"hello world\n").with_context(cx).await
}

async fn run(addr: &SocketAddr) -> io::Result<usize> {
    let tracer = global::tracer("runner");
    let span = tracer.start(&format!("running: {}", addr));
    let cx = Context::current_with_span(span);

    let mut stream = connect(addr).with_context(cx.clone()).await?;
    write(&mut stream).with_context(cx).await
}

fn init_tracer() -> thrift::Result<()> {
    let exporter = opentelemetry_jaeger::Exporter::builder()
        .with_agent_endpoint("127.0.0.1:6831".parse().unwrap())
        .with_process(opentelemetry_jaeger::Process {
            service_name: "trace-demo".to_string(),
            tags: vec![],
        })
        .init()?;

    // Configure your async library of choice. E.g. `async_std::spawn` or similar function can be
    // used here in place of `tokio::spawn`, etc.
    let batch = sdk::BatchSpanProcessor::builder(exporter, tokio::spawn, tokio::time::interval)
        .with_scheduled_delay(Duration::from_millis(100))
        .build();

    // For the demonstration, use `Sampler::AlwaysOn` sampler to sample all traces. In a production
    // application, use `Sampler::ParentOrElse` or `Sampler::Probability` with a desired probability.
    let provider = sdk::Provider::builder()
        .with_batch_exporter(batch)
        .with_config(sdk::Config {
            default_sampler: Box::new(sdk::Sampler::AlwaysOn),
            ..Default::default()
        })
        .build();
    global::set_provider(provider);

    Ok(())
}

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn Error>> {
    init_tracer()?;
    let addr = "127.0.0.1:6142".parse()?;
    let addr2 = "127.0.0.1:6143".parse()?;
    let tracer = global::tracer("async_example");
    let span = tracer.start("root");
    let cx = Context::current_with_span(span);

    let (run1, run2) = futures::future::join(run(&addr), run(&addr2))
        .with_context(cx)
        .await;
    run1?;
    run2?;

    thread::sleep(Duration::from_millis(250));

    Ok(())
}
<commit_msg>examples/async: fix problem with thread::sleep (#130)<commit_after>//! Demonstrates using OpenTelemetry to instrument `async` functions.
//!
//! This is based on the [`hello_world`] example from `tokio`. and implements a
//! simple client that opens a TCP stream, writes "hello world\n", and closes
//! the connection.
//!
//! You can test this out by running:
//!
//!     ncat -l 6142
//!
//! And then in a second terminal run:
//!
//!     ncat -l 6143
//!
//! And then in a third terminal run:
//!
//!     cargo run --example async_fn
//!
//! [`hello_world`]: https://github.com/tokio-rs/tokio/blob/132e9f1da5965530b63554d7a1c59824c3de4e30/tokio/examples/hello_world.rs
use opentelemetry::{
    api::{trace::futures::FutureExt, Context, TraceContextExt, Tracer},
    global, sdk,
};
use std::time::Duration;
use std::{error::Error, io, net::SocketAddr};
use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;

async fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
    let tracer = global::tracer("connector");
    let span = tracer.start("Connecting");
    let cx = Context::current_with_value(span);

    TcpStream::connect(&addr).with_context(cx).await
}

async fn write(stream: &mut TcpStream) -> io::Result<usize> {
    let tracer = global::tracer("writer");
    let span = tracer.start("Writing");
    let cx = Context::current_with_span(span);

    stream.write(b"hello world\n").with_context(cx).await
}

async fn run(addr: &SocketAddr) -> io::Result<usize> {
    let tracer = global::tracer("runner");
    let span = tracer.start(&format!("running: {}", addr));
    let cx = Context::current_with_span(span);

    let mut stream = connect(addr).with_context(cx.clone()).await?;
    write(&mut stream).with_context(cx).await
}

fn init_tracer() -> thrift::Result<()> {
    let exporter = opentelemetry_jaeger::Exporter::builder()
        .with_agent_endpoint("127.0.0.1:6831".parse().unwrap())
        .with_process(opentelemetry_jaeger::Process {
            service_name: "trace-demo".to_string(),
            tags: vec![],
        })
        .init()?;

    // Configure your async library of choice. E.g. `async_std::spawn` or similar function can be
    // used here in place of `tokio::spawn`, etc.
    let batch = sdk::BatchSpanProcessor::builder(exporter, tokio::spawn, tokio::time::interval)
        .with_scheduled_delay(Duration::from_millis(100))
        .build();

    // For the demonstration, use `Sampler::AlwaysOn` sampler to sample all traces. In a production
    // application, use `Sampler::ParentOrElse` or `Sampler::Probability` with a desired probability.
    let provider = sdk::Provider::builder()
        .with_batch_exporter(batch)
        .with_config(sdk::Config {
            default_sampler: Box::new(sdk::Sampler::AlwaysOn),
            ..Default::default()
        })
        .build();
    global::set_provider(provider);

    Ok(())
}

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn Error>> {
    init_tracer()?;
    let addr = "127.0.0.1:6142".parse()?;
    let addr2 = "127.0.0.1:6143".parse()?;
    let tracer = global::tracer("async_example");
    let span = tracer.start("root");
    let cx = Context::current_with_span(span);

    let (run1, run2) = futures::future::join(run(&addr), run(&addr2))
        .with_context(cx)
        .await;
    run1?;
    run2?;

    tokio::time::delay_for(Duration::from_millis(250)).await;
    // or async_std::task::sleep(Duration::from_millis(250)).await;

    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate time_steward;

#[macro_use]
extern crate glium;

extern crate nalgebra;
extern crate docopt;

extern crate serde;
#[macro_use]
extern crate serde_derive;

use docopt::Docopt;

const USAGE: &'static str = "
Bouncy Circles, a simple TimeSteward test case.

Usage:
  bouncy_circles
  bouncy_circles (-l | --listen) <host> <port>
  bouncy_circles (-c | --connect) <host> <port>

Options:
  -l, --listen   Start a synchronized simulation by listening for TCP connections.
  -c, --connect  Start a synchronized simulation by making a TCP connection.
";

#[derive(Debug, Deserialize)]
struct Args {
  flag_listen: bool,
  flag_connect: bool,

  arg_host: Option <String>,
  arg_port: Option <u16>,
}

//use time_steward::stewards::crossverified as s;
use time_steward::{TimeSteward, TimeStewardFromConstants, IncrementalTimeSteward, DeterministicRandomId, Accessor,
     MomentaryAccessor};
use std::time::{Instant, Duration};
use glium::{DisplayBuild, Surface};
use time_steward::stewards::{amortized, simply_synchronized};

#[path = "../dev-shared/bouncy_circles.rs"] mod bouncy_circles;
use bouncy_circles::*;
#[path = "../dev-shared/emscripten_compatibility.rs"] mod emscripten_compatibility;
pub use emscripten_compatibility::canvas_click;

#[derive(Copy, Clone)]

struct Vertex {
  direction: [f32; 2],
  center: [f32; 2],
  radius: f32,
}
implement_vertex!(Vertex, direction, center, radius);

use std::net::{TcpListener, TcpStream};
use std::io::{BufReader, BufWriter};

fn main() {
  // For some reason, docopt checking the arguments caused build_glium() to fail in emscripten.
  if !cfg!(target_os = "emscripten") {
    let arguments: Args = Docopt::new(USAGE)
                            .and_then(|d| d.deserialize())
                            .unwrap_or_else(|e| e.exit());

    if arguments.flag_listen {
      let listener = TcpListener::bind ((arguments.arg_host.as_ref().map_or("localhost", | string | string as & str), arguments.arg_port.unwrap())).unwrap();
      let stream = listener.accept().unwrap().0;
      let mut steward: simply_synchronized::Steward<Basics, amortized::Steward<Basics>> = simply_synchronized::Steward::new(DeterministicRandomId::new (& 0u32), 0, SECOND>>3,(), BufReader::new (stream.try_clone().unwrap()), BufWriter::new (stream));
      steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
      run (steward, |a,b| (a.settle_before (b)));
      return;
    }
    else if arguments.flag_connect {
      let stream = TcpStream::connect ((arguments.arg_host.as_ref().map_or("localhost", | string | string as & str), arguments.arg_port.unwrap())).unwrap();
      let steward: simply_synchronized::Steward<Basics, amortized::Steward<Basics>> = simply_synchronized::Steward::new(DeterministicRandomId::new (& 1u32), 0, SECOND>>3,(), BufReader::new (stream.try_clone().unwrap()), BufWriter::new (stream));
      run (steward, |a,b| (a.settle_before (b)));
      return;
    }
  }
  {
    //let mut steward: s::Steward<Basics,
                                //inefficient_flat::Steward<Basics>,
                                //memoized_flat::Steward<Basics>> = s::Steward::from_constants(());
    let mut steward: amortized::Steward<Basics> = amortized::Steward::from_constants(());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
    run (steward, |_,_|());
  }
}

fn run <Steward: IncrementalTimeSteward <Basics = Basics>,F: Fn (&mut Steward, Time)>(mut stew: Steward, settle:F) {

  let vertex_shader_source = r#"
#version 100
attribute lowp vec2 direction;
attribute lowp vec2 center;
attribute lowp float radius;
varying lowp vec2 direction_transfer;

void main() {
direction_transfer = direction*1.5;
gl_Position = vec4 ( center + direction*1.5*radius, 0.0, 1.0);
}

"#;

  let fragment_shader_source = r#"
#version 100
varying lowp vec2 direction_transfer;

void main() {
if (dot (direction_transfer,direction_transfer) <1.0) {
gl_FragColor = vec4 (1.0, 0.0, 0.0, 1.0);
} else {
gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0);

}
}

"#;

  //let mut snapshots = Vec::new();

  let mut event_index = 0u64;
  let mut mouse_coordinates = [0,0];

  if true {
    let display = glium::glutin::WindowBuilder::new()
      .with_dimensions(600, 600)
      .build_glium()
      .expect("failed to create window");
    let program =
      glium::Program::from_source(&display, vertex_shader_source, fragment_shader_source, None)
        .expect("glium program generation failed");
    let parameters = glium::DrawParameters {
      blend: glium::draw_parameters::Blend::alpha_blending(),
      ..Default::default()
    };
    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    // take care of the expensive initial predictions before starting the timer
    stew.snapshot_before(&1);
    let start = Instant::now();

    let frame = || {
      let frame_begin = Instant::now();
      let time =((start.elapsed().as_secs() as i64 * 1000000000i64) +
                            start.elapsed().subsec_nanos() as i64) *
                           SECOND / 1000000000i64;
      for ev in display.poll_events() {
        match ev {
          glium::glutin::Event::Closed => return true,
          glium::glutin::Event::MouseMoved (x,y) => {
            mouse_coordinates [0] = ((x as SpaceCoordinate) - 150) * ARENA_SIZE / 300;
            mouse_coordinates [1] = (450-(y as SpaceCoordinate)) * ARENA_SIZE / 300;
            //println!("mouse {} {} {:?}", x,y,mouse_coordinates);
          },
          glium::glutin::Event::MouseInput (_,_) => {
            event_index += 1;
            stew.insert_fiat_event (time, DeterministicRandomId::new (& event_index), Disturb::new ([mouse_coordinates [0], mouse_coordinates [1]])).unwrap();
          },
          _ => (),
        }
      }
      while let Some ((x,y)) = emscripten_compatibility::pop_click() {
        // TODO duplicate code
        mouse_coordinates [0] = (((x*600.0) as SpaceCoordinate) - 150) * ARENA_SIZE / 300;
        mouse_coordinates [1] = (450-((y*600.0) as SpaceCoordinate)) * ARENA_SIZE / 300;
        event_index += 1;
        stew.insert_fiat_event (time, DeterministicRandomId::new (& event_index), Disturb::new ([mouse_coordinates [0], mouse_coordinates [1]])).unwrap();
      }

      let mut target = display.draw();
      target.clear_color(0.0, 0.0, 0.0, 1.0);
      let mut vertices = Vec::<Vertex>::new();

      let snapshot = stew.snapshot_before(& time)
        .expect("steward failed to provide snapshot");
      stew.forget_before(& time);

      settle (&mut stew, time);
      for index in 0..HOW_MANY_CIRCLES {
        if let Some ((circle, time)) = snapshot.data_and_last_change::<Circle>(get_circle_id(index)){
        let position = circle.position.updated_by(snapshot.now() - time).unwrap().evaluate();
        let center = [position[0] as f32 / ARENA_SIZE as f32 - 0.5,
                      position[1] as f32 / ARENA_SIZE as f32 - 0.5];
        let radius = circle.radius as f32 / ARENA_SIZE as f32;
        // println!("drawing circ at {}, {}", center[0],center[1]);
        vertices.extend(&[Vertex {
                            center: center,
                            radius: radius,
                            direction: [1.0, 0.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [-1.0, 0.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [0.0, 1.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [1.0, 0.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [-1.0, 0.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [0.0, -1.0],
                          }]);
}
      }
      target.draw(&glium::VertexBuffer::new(&display, &vertices)
                .expect("failed to generate glium Vertex buffer"),
              &indices,
              &program,
              &glium::uniforms::EmptyUniforms,
              &parameters)
        .expect("failed target.draw");

      target.finish().expect("failed to finish drawing");

      while frame_begin.elapsed() < Duration::from_millis (10) && stew.updated_until_before().map_or (false, | limitation | limitation < time + SECOND) {
        for _ in 0..8 {stew.step();}
      }
      false
    };

    emscripten_compatibility::main_loop (frame);
  }

  /*
  for increment in 1..21 {
    snapshots.push(stew.snapshot_before(&(increment * SECOND * 2)));
  }
  for snapshot in snapshots.iter_mut()
    .map(|option| option.as_mut().expect("all these snapshots should have been valid")) {
    println!("snapshot for {}", snapshot.now());
    // for index in 0..HOW_MANY_CIRCLES {
    // println!("{}", snapshot.get::<Circle> (get_circle_id (index)).expect("missing circle").position);
    // }
  }*/
  // panic!("anyway")
}
<commit_msg>Fix accidental change to the wrong file from a while back<commit_after>#[macro_use]
extern crate time_steward;

#[macro_use]
extern crate glium;

extern crate nalgebra;
extern crate docopt;

extern crate serde;
#[macro_use]
extern crate serde_derive;

use docopt::Docopt;

const USAGE: &'static str = "
Bouncy Circles, a simple TimeSteward test case.

Usage:
  bouncy_circles
  bouncy_circles (-l | --listen) <host> <port>
  bouncy_circles (-c | --connect) <host> <port>

Options:
  -l, --listen   Start a synchronized simulation by listening for TCP connections.
  -c, --connect  Start a synchronized simulation by making a TCP connection.
";

#[derive(Debug, Deserialize)]
struct Args {
  flag_listen: bool,
  flag_connect: bool,

  arg_host: Option <String>,
  arg_port: Option <u16>,
}

//use time_steward::stewards::crossverified as s;
use time_steward::{TimeSteward, TimeStewardFromConstants, IncrementalTimeSteward, DeterministicRandomId, Accessor,
     MomentaryAccessor};
use std::time::{Instant, Duration};
use glium::{DisplayBuild, Surface};
use time_steward::stewards::{amortized, simply_synchronized};

#[path = "../dev-shared/bouncy_circles.rs"] mod bouncy_circles;
use bouncy_circles::*;
#[path = "../dev-shared/emscripten_compatibility.rs"] mod emscripten_compatibility;
pub use emscripten_compatibility::canvas_click;

#[derive(Copy, Clone)]

struct Vertex {
  direction: [f32; 2],
  center: [f32; 2],
  radius: f32,
}
implement_vertex!(Vertex, direction, center, radius);

use std::net::{TcpListener, TcpStream};
use std::io::{BufReader, BufWriter};

fn main() {
  // For some reason, docopt checking the arguments caused build_glium() to fail in emscripten.
  if !cfg!(target_os = "emscripten") {
    let arguments: Args = Docopt::new(USAGE)
                            .and_then(|d| d.deserialize())
                            .unwrap_or_else(|e| e.exit());

    if arguments.flag_listen {
      let listener = TcpListener::bind ((arguments.arg_host.as_ref().map_or("localhost", | string | string as & str), arguments.arg_port.unwrap())).unwrap();
      let stream = listener.accept().unwrap().0;
      let mut steward: simply_synchronized::Steward<Basics, amortized::Steward<Basics>> = simply_synchronized::Steward::new(DeterministicRandomId::new (& 0u32), 0, SECOND>>3,(), BufReader::new (stream.try_clone().unwrap()), BufWriter::new (stream));
      steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
      run (steward, |a,b| (a.settle_before (b)));
      return;
    }
    else if arguments.flag_connect {
      let stream = TcpStream::connect ((arguments.arg_host.as_ref().map_or("localhost", | string | string as & str), arguments.arg_port.unwrap())).unwrap();
      let steward: simply_synchronized::Steward<Basics, amortized::Steward<Basics>> = simply_synchronized::Steward::new(DeterministicRandomId::new (& 1u32), 0, SECOND>>3,(), BufReader::new (stream.try_clone().unwrap()), BufWriter::new (stream));
      run (steward, |a,b| (a.settle_before (b)));
      return;
    }
  }
  {
    //let mut steward: s::Steward<Basics,
                                //inefficient_flat::Steward<Basics>,
                                //memoized_flat::Steward<Basics>> = s::Steward::from_constants(());
    let mut steward: amortized::Steward<Basics> = amortized::Steward::from_constants(());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
    run (steward, |_,_|());
  }
}

fn run <Steward: IncrementalTimeSteward <Basics = Basics>,F: Fn (&mut Steward, Time)>(mut stew: Steward, settle:F) {

  let vertex_shader_source = r#"
#version 100
attribute lowp vec2 direction;
attribute lowp vec2 center;
attribute lowp float radius;
varying lowp vec2 direction_transfer;

void main() {
direction_transfer = direction*1.5;
gl_Position = vec4 ( center + direction*1.5*radius, 0.0, 1.0);
}

"#;

  let fragment_shader_source = r#"
#version 100
varying lowp vec2 direction_transfer;

void main() {
if (dot (direction_transfer,direction_transfer) <1.0) {
gl_FragColor = vec4 (1.0, 0.0, 0.0, 1.0);
} else {
gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0);

}
}

"#;

  //let mut snapshots = Vec::new();

  let mut event_index = 0u64;
  let mut mouse_coordinates = [0,0];

  if true {
    let display = glium::glutin::WindowBuilder::new()
      .with_dimensions(600, 600)
      .build_glium()
      .expect("failed to create window");
    let program =
      glium::Program::from_source(&display, vertex_shader_source, fragment_shader_source, None)
        .expect("glium program generation failed");
    let parameters = glium::DrawParameters {
      blend: glium::draw_parameters::Blend::alpha_blending(),
      ..Default::default()
    };
    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    // take care of the expensive initial predictions before starting the timer
    stew.snapshot_before(&1);
    let start = Instant::now();

    let frame = || {
      let frame_begin = Instant::now();
      let time =((start.elapsed().as_secs() as i64 * 1000000000i64) +
                            start.elapsed().subsec_nanos() as i64) *
                           SECOND / 1000000000i64;
      for ev in display.poll_events() {
        match ev {
          glium::glutin::Event::Closed => return true,
          glium::glutin::Event::MouseMoved (x,y) => {
            mouse_coordinates [0] = ((x as SpaceCoordinate) - 150) * ARENA_SIZE / 300;
            mouse_coordinates [1] = (450-(y as SpaceCoordinate)) * ARENA_SIZE / 300;
            //println!("mouse {} {} {:?}", x,y,mouse_coordinates);
          },
          glium::glutin::Event::MouseInput (_,_) => {
            event_index += 1;
            stew.insert_fiat_event (time, DeterministicRandomId::new (& event_index), Disturb::new ([mouse_coordinates [0], mouse_coordinates [1]])).unwrap();
          },
          _ => (),
        }
      }
      while let Some ((x,y)) = emscripten_compatibility::pop_click() {
        // TODO duplicate code
        mouse_coordinates [0] = (((x*600.0) as SpaceCoordinate) - 150) * ARENA_SIZE / 300;
        mouse_coordinates [1] = (450-((y*600.0) as SpaceCoordinate)) * ARENA_SIZE / 300;
        event_index += 1;
        stew.insert_fiat_event (time, DeterministicRandomId::new (& event_index), Disturb::new ([mouse_coordinates [0], mouse_coordinates [1]])).unwrap();
      }

      let mut target = display.draw();
      target.clear_color(0.0, 0.0, 0.0, 1.0);
      let mut vertices = Vec::<Vertex>::new();

      let snapshot = stew.snapshot_before(& time)
        .expect("steward failed to provide snapshot");

      settle (&mut stew, time);
      for index in 0..HOW_MANY_CIRCLES {
        if let Some ((circle, time)) = snapshot.data_and_last_change::<Circle>(get_circle_id(index)){
        let position = circle.position.updated_by(snapshot.now() - time).unwrap().evaluate();
        let center = [position[0] as f32 / ARENA_SIZE as f32 - 0.5,
                      position[1] as f32 / ARENA_SIZE as f32 - 0.5];
        let radius = circle.radius as f32 / ARENA_SIZE as f32;
        // println!("drawing circ at {}, {}", center[0],center[1]);
        vertices.extend(&[Vertex {
                            center: center,
                            radius: radius,
                            direction: [1.0, 0.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [-1.0, 0.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [0.0, 1.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [1.0, 0.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [-1.0, 0.0],
                          },
                          Vertex {
                            center: center,
                            radius: radius,
                            direction: [0.0, -1.0],
                          }]);
}
      }
      target.draw(&glium::VertexBuffer::new(&display, &vertices)
                .expect("failed to generate glium Vertex buffer"),
              &indices,
              &program,
              &glium::uniforms::EmptyUniforms,
              &parameters)
        .expect("failed target.draw");

      target.finish().expect("failed to finish drawing");

      while frame_begin.elapsed() < Duration::from_millis (10) && stew.updated_until_before().map_or (false, | limitation | limitation < time + SECOND) {
        for _ in 0..8 {stew.step();}
      }
      false
    };

    emscripten_compatibility::main_loop (frame);
  }

  /*
  for increment in 1..21 {
    snapshots.push(stew.snapshot_before(&(increment * SECOND * 2)));
  }
  for snapshot in snapshots.iter_mut()
    .map(|option| option.as_mut().expect("all these snapshots should have been valid")) {
    println!("snapshot for {}", snapshot.now());
    // for index in 0..HOW_MANY_CIRCLES {
    // println!("{}", snapshot.get::<Circle> (get_circle_id (index)).expect("missing circle").position);
    // }
  }*/
  // panic!("anyway")
}
<|endoftext|>


<commit_before>use turtle::{Angle, Color, Distance, Drawing, Point, Size, Turtle};

trait CubicBezier {
    const DEFAULT_SAMPLES: usize = 100;

    fn bezier_abs_pr(&mut self, samples: usize, points: [Point; 4]);
    fn bezier_rel_pr(&mut self, samples: usize, rel_points: [Point; 3]);

    fn bezier_abs(&mut self, points: [Point; 4]) {
        self.bezier_abs_pr(Self::DEFAULT_SAMPLES, points)
    }

    fn bezier_rel(&mut self, rel_points: [Point; 3]) {
        self.bezier_rel_pr(Self::DEFAULT_SAMPLES, rel_points)
    }

    fn curve_at(t: f64, points: [Point; 4]) -> Point {
        (1.0 - t).powi(3) * points[0]
            + 3.0 * (1.0 - t).powi(2) * t * points[1]
            + 3.0 * (1.0 - t) * t.powi(2) * points[2]
            + t.powi(3) * points[3]
    }
}

impl CubicBezier for Turtle {
    fn bezier_abs_pr(&mut self, samples: usize, points: [Point; 4]) {
        (0..=samples)
            .map(|i| i as f64 / samples as f64)
            .map(|t| Self::curve_at(t, points))
            .for_each(|point| {
                self.turn_towards(point);
                self.go_to(point);
            })
    }

    fn bezier_rel_pr(&mut self, samples: usize, rel_points: [Point; 3]) {
        let pos = self.position();
        self.bezier_abs_pr(
            samples,
            [
                pos,
                pos + rel_points[0],
                pos + rel_points[1],
                pos + rel_points[2],
            ],
        )
    }
}

const FRONT_SHELL_COLOR: &str = "#f74c00";
const BACK_SHELL_COLOR: &str = "#a52b00";
const PUPIL_COLOR: &str = "#ffffff";
const MOUTH_COLOR: &str = "#000000";
const ORIGINAL_SIZE: Size = Size {
    width: 1200,
    height: 800,
};

fn adapt_point(point: impl Into<Point>, size: Size) -> Point {
    let point = point.into();
    Point {
        x: size.width as f64 * point.x / ORIGINAL_SIZE.width as f64,
        y: -(size.height as f64) * point.y / ORIGINAL_SIZE.height as f64,
    }
}

fn rel_points(abs_points: [Point; 4]) -> [Point; 3] {
    [
        abs_points[1] - abs_points[0],
        abs_points[2] - abs_points[0],
        abs_points[3] - abs_points[0],
    ]
}

fn adapt_distance(distance: Distance, angle: Angle, size: Size) -> Distance {
    ((distance * angle.cos() * size.width as f64 / ORIGINAL_SIZE.width as f64).powi(2)
        + (distance * angle.sin() * size.height as f64 / ORIGINAL_SIZE.height as f64).powi(2))
    .sqrt()
}

fn main() {
    let mut drawing = Drawing::new();
    let size = drawing.size();
    drawing.set_center([size.width as f64 / 2.0, -(size.height as f64) / 2.0]);

    let mut turtle = drawing.add_turtle();
    turtle.use_radians();
    turtle.pen_up();

    let rp = rel_points;
    let ap = |point| adapt_point(point, size);
    let ad = |distance, angle| adapt_distance(distance, angle, size);

    let start_point = ap([240.0, 504.0]);
    turtle.set_fill_color(BACK_SHELL_COLOR);
    turtle.set_speed("instant");
    turtle.turn_towards(start_point);
    turtle.go_to(start_point);
    turtle.set_speed("faster");
    turtle.begin_fill();

    let start_heading = (180.0 + 32.01f64).to_radians();
    turtle.set_heading(start_heading);
    turtle.forward(ad(18.9, start_heading));
    turtle.bezier_rel(rp([
        ap([223.64, 514.18]),
        ap([222.18, 525.09]),
        ap([288.00, 597.09]),
        ap([323.94, 645.06]),
    ]));
    turtle.bezier_rel(rp([
        ap([323.91, 645.18]),
        ap([324.00, 623.09]),
        ap([283.27, 565.27]),
        ap([270.69, 529.94]),
    ]));
    turtle.bezier_rel(rp([
        ap([270.75, 529.94]),
        ap([444.75, 621.50]),
        ap([826.25, 622.50]),
        ap([973.09, 515.22]),
    ]));
    turtle.bezier_rel(rp([
        ap([973.12, 515.25]),
        ap([965.45, 552.18]),
        ap([923.09, 619.45]),
        ap([922.09, 646.52]),
    ]));
    turtle.bezier_rel(rp([
        ap([922.38, 647.00]),
        ap([931.09, 631.09]),
        ap([988.91, 554.55]),
        ap([1008.00, 517.12]),
    ]));
    let middle_curve_part1 = rp([
        ap([1008.12, 517.06]),
        ap([979.25, 500.88]),
        ap([960.12, 507.19]),
        ap([946.69, 510.31]),
    ]);
    turtle.bezier_rel(middle_curve_part1);
    let middle_curve_part2 = rp([
        ap([946.66, 510.41]),
        ap([750.73, 606.91]),
        ap([472.55, 603.45]),
        ap([239.57, 505.39]),
    ]);
    turtle.bezier_rel(middle_curve_part2);

    turtle.end_fill();
    turtle.set_fill_color(FRONT_SHELL_COLOR);
    turtle.begin_fill();

    turtle.bezier_rel(rp([
        ap([239.45, 504.36]),
        ap([233.00, 508.18]),
        ap([213.45, 519.82]),
        ap([212.50, 524.44]),
    ]));
    turtle.bezier_rel(rp([
        ap([212.25, 524.44]),
        ap([215.00, 570.50]),
        ap([300.00, 657.50]),
        ap([304.52, 700.83]),
    ]));
    turtle.bezier_rel(rp([
        ap([303.56, 702.56]),
        ap([206.50, 599.75]),
        ap([133.25, 541.75]),
        ap([138.00, 522.82]),
    ]));
    turtle.bezier_rel(rp([
        ap([138.00, 523.18]),
        ap([137.82, 511.73]),
        ap([145.55, 510.64]),
        ap([176.00, 476.00]),
    ]));
    turtle.bezier_rel(rp([
        ap([175.64, 475.55]),
        ap([138.73, 455.36]),
        ap([111.09, 430.55]),
        ap([103.73, 408.91]),
    ]));
    turtle.bezier_rel(rp([
        ap([103.91, 409.55]),
        ap([-21.00, 349.50]),
        ap([5.00, 282.50]),
        ap([52.00, 244.12]),
    ]));
    turtle.bezier_rel(rp([
        ap([52.69, 244.19]),
        ap([59.00, 289.00]),
        ap([83.12, 323.00]),
        ap([109.56, 344.59]),
    ]));
    let left_claw_heading = (180.0 - 82.13f64).to_radians();
    turtle.set_heading(left_claw_heading);
    turtle.forward(ad(124.2, turtle.heading()));
    turtle.bezier_rel(rp([
        ap([93.13, 221.13]),
        ap([163.25, 250.75]),
        ap([216.25, 316.75]),
        ap([148.35, 405.39]),
    ]));
    turtle.bezier_rel(rp([
        ap([148.52, 405.43]),
        ap([160.27, 422.64]),
        ap([185.00, 435.45]),
        ap([207.04, 443.65]),
    ]));
    let left_claw_heading = 45f64.to_radians();
    turtle.set_heading(left_claw_heading);
    turtle.forward(ad(12.7, turtle.heading()));
}
<commit_msg>Implement 2D rotation for Point in Ferris example<commit_after>use turtle::{Angle, Distance, Drawing, Point, Size, Turtle};

trait Rotate {
    fn rot(&self, angle: Angle) -> Self;
}

impl Rotate for Point {
    fn rot(&self, angle: Angle) -> Self {
        let (sin_angle, cos_angle) = angle.sin_cos();
        [
            self.x * cos_angle - self.y * sin_angle,
            self.x * sin_angle + self.y * cos_angle,
        ]
        .into()
    }
}

trait CubicBezier {
    const DEFAULT_SAMPLES: usize = 100;

    fn bezier_abs_pr(&mut self, samples: usize, points: [Point; 4]);
    fn bezier_rel_pr(&mut self, samples: usize, rel_points: [Point; 3]);

    fn bezier_abs(&mut self, points: [Point; 4]) {
        self.bezier_abs_pr(Self::DEFAULT_SAMPLES, points)
    }

    fn bezier_rel(&mut self, rel_points: [Point; 3]) {
        self.bezier_rel_pr(Self::DEFAULT_SAMPLES, rel_points)
    }

    fn curve_at(t: f64, points: [Point; 4]) -> Point {
        (1.0 - t).powi(3) * points[0]
            + 3.0 * (1.0 - t).powi(2) * t * points[1]
            + 3.0 * (1.0 - t) * t.powi(2) * points[2]
            + t.powi(3) * points[3]
    }
}

impl CubicBezier for Turtle {
    fn bezier_abs_pr(&mut self, samples: usize, points: [Point; 4]) {
        (0..=samples)
            .map(|i| i as f64 / samples as f64)
            .map(|t| Self::curve_at(t, points))
            .for_each(|point| {
                self.turn_towards(point);
                self.go_to(point);
            })
    }

    fn bezier_rel_pr(&mut self, samples: usize, rel_points: [Point; 3]) {
        let pos = self.position();
        self.bezier_abs_pr(
            samples,
            [
                pos,
                pos + rel_points[0],
                pos + rel_points[1],
                pos + rel_points[2],
            ],
        )
    }
}

const FRONT_SHELL_COLOR: &str = "#f74c00";
const BACK_SHELL_COLOR: &str = "#a52b00";
const PUPIL_COLOR: &str = "#ffffff";
const MOUTH_COLOR: &str = "#000000";
const ORIGINAL_SIZE: Size = Size {
    width: 1200,
    height: 800,
};

fn adapt_point(point: impl Into<Point>, size: Size) -> Point {
    let point = point.into();
    Point {
        x: size.width as f64 * point.x / ORIGINAL_SIZE.width as f64,
        y: -(size.height as f64) * point.y / ORIGINAL_SIZE.height as f64,
    }
}

fn rel_points(abs_points: [Point; 4]) -> [Point; 3] {
    [
        abs_points[1] - abs_points[0],
        abs_points[2] - abs_points[0],
        abs_points[3] - abs_points[0],
    ]
}

fn adapt_distance(distance: Distance, angle: Angle, size: Size) -> Distance {
    ((distance * angle.cos() * size.width as f64 / ORIGINAL_SIZE.width as f64).powi(2)
        + (distance * angle.sin() * size.height as f64 / ORIGINAL_SIZE.height as f64).powi(2))
    .sqrt()
}

fn main() {
    let mut drawing = Drawing::new();
    let size = drawing.size();
    drawing.set_center([size.width as f64 / 2.0, -(size.height as f64) / 2.0]);

    let mut turtle = drawing.add_turtle();
    turtle.use_radians();
    turtle.pen_up();

    let rp = rel_points;
    let ap = |point| adapt_point(point, size);
    let ad = |distance, angle| adapt_distance(distance, angle, size);

    let start_point = ap([240.0, 504.0]);
    turtle.set_fill_color(BACK_SHELL_COLOR);
    turtle.set_speed("instant");
    turtle.turn_towards(start_point);
    turtle.go_to(start_point);
    turtle.set_speed("faster");
    turtle.begin_fill();

    let start_heading = (180.0 + 32.01f64).to_radians();
    turtle.set_heading(start_heading);
    turtle.forward(ad(18.9, start_heading));
    turtle.bezier_rel(rp([
        ap([223.64, 514.18]),
        ap([222.18, 525.09]),
        ap([288.00, 597.09]),
        ap([323.94, 645.06]),
    ]));
    turtle.bezier_rel(rp([
        ap([323.91, 645.18]),
        ap([324.00, 623.09]),
        ap([283.27, 565.27]),
        ap([270.69, 529.94]),
    ]));
    turtle.bezier_rel(rp([
        ap([270.75, 529.94]),
        ap([444.75, 621.50]),
        ap([826.25, 622.50]),
        ap([973.09, 515.22]),
    ]));
    turtle.bezier_rel(rp([
        ap([973.12, 515.25]),
        ap([965.45, 552.18]),
        ap([923.09, 619.45]),
        ap([922.09, 646.52]),
    ]));
    turtle.bezier_rel(rp([
        ap([922.38, 647.00]),
        ap([931.09, 631.09]),
        ap([988.91, 554.55]),
        ap([1008.00, 517.12]),
    ]));
    let middle_curve_part1 = rp([
        ap([1008.12, 517.06]),
        ap([979.25, 500.88]),
        ap([960.12, 507.19]),
        ap([946.69, 510.31]),
    ]);
    turtle.bezier_rel(middle_curve_part1);
    let middle_curve_part2 = rp([
        ap([946.66, 510.41]),
        ap([750.73, 606.91]),
        ap([472.55, 603.45]),
        ap([239.57, 505.39]),
    ]);
    turtle.bezier_rel(middle_curve_part2);

    turtle.end_fill();
    turtle.set_fill_color(FRONT_SHELL_COLOR);
    turtle.begin_fill();

    turtle.bezier_rel(rp([
        ap([239.45, 504.36]),
        ap([233.00, 508.18]),
        ap([213.45, 519.82]),
        ap([212.50, 524.44]),
    ]));
    turtle.bezier_rel(rp([
        ap([212.25, 524.44]),
        ap([215.00, 570.50]),
        ap([300.00, 657.50]),
        ap([304.52, 700.83]),
    ]));
    turtle.bezier_rel(rp([
        ap([303.56, 702.56]),
        ap([206.50, 599.75]),
        ap([133.25, 541.75]),
        ap([138.00, 522.82]),
    ]));
    turtle.bezier_rel(rp([
        ap([138.00, 523.18]),
        ap([137.82, 511.73]),
        ap([145.55, 510.64]),
        ap([176.00, 476.00]),
    ]));
    turtle.bezier_rel(rp([
        ap([175.64, 475.55]),
        ap([138.73, 455.36]),
        ap([111.09, 430.55]),
        ap([103.73, 408.91]),
    ]));
    turtle.bezier_rel(rp([
        ap([103.91, 409.55]),
        ap([-21.00, 349.50]),
        ap([5.00, 282.50]),
        ap([52.00, 244.12]),
    ]));
    turtle.bezier_rel(rp([
        ap([52.69, 244.19]),
        ap([59.00, 289.00]),
        ap([83.12, 323.00]),
        ap([109.56, 344.59]),
    ]));
    let left_claw_heading = (180.0 - 82.13f64).to_radians();
    turtle.set_heading(left_claw_heading);
    turtle.forward(ad(124.2, turtle.heading()));
    turtle.bezier_rel(rp([
        ap([93.13, 221.13]),
        ap([163.25, 250.75]),
        ap([216.25, 316.75]),
        ap([148.35, 405.39]),
    ]));
    turtle.bezier_rel(rp([
        ap([148.52, 405.43]),
        ap([160.27, 422.64]),
        ap([185.00, 435.45]),
        ap([207.04, 443.65]),
    ]));
    let left_claw_heading = 45f64.to_radians();
    turtle.set_heading(left_claw_heading);
    turtle.forward(ad(12.7, turtle.heading()));
}
<|endoftext|>


<commit_before>use lsp_types::{
    DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
    DocumentFilter, FoldingRange, FoldingRangeParams, InitializeParams, InitializeResult,
    InitializedParams, MessageType, Registration, ServerCapabilities, ServerInfo,
    TextDocumentChangeRegistrationOptions, TextDocumentRegistrationOptions, Url,
};
use lspower::{jsonrpc, Client, LanguageServer};
use tokio::{fs, sync::Mutex};

use self::{folding_range::compute_folding_ranges, open_file_manager::OpenFileManager};

mod folding_range;
mod open_file_manager;
mod utils;

#[derive(Debug)]
pub struct CandyLanguageServer {
    pub client: Client,
    pub open_file_manager: Mutex<OpenFileManager>,
}
impl CandyLanguageServer {
    pub fn from_client(client: Client) -> Self {
        Self {
            client,
            open_file_manager: Mutex::new(OpenFileManager::new()),
        }
    }
}

#[lspower::async_trait]
impl LanguageServer for CandyLanguageServer {
    async fn initialize(&self, _: InitializeParams) -> jsonrpc::Result<InitializeResult> {
        log::info!("LSP: initialize");
        self.client
            .log_message(MessageType::INFO, "Initializing!")
            .await;
        Ok(InitializeResult {
            // We only support dynamic registration for now.
            capabilities: ServerCapabilities::default(),
            server_info: Some(ServerInfo {
                name: "🍭 Candy Language Server".to_owned(),
                version: None,
            }),
        })
    }

    async fn initialized(&self, _: InitializedParams) {
        log::info!("LSP: initialized");
        let candy_files = DocumentFilter {
            language: Some("candy".to_owned()),
            scheme: Some("file".to_owned()),
            pattern: None,
        };
        let text_document_registration_options = TextDocumentRegistrationOptions {
            document_selector: Some(vec![candy_files.clone()]),
        };
        self.client
            .register_capability(vec![
                Registration {
                    id: "0".to_owned(),
                    method: "textDocument/didOpen".to_owned(),
                    register_options: Some(
                        serde_json::to_value(text_document_registration_options.clone()).unwrap(),
                    ),
                },
                Registration {
                    id: "1".to_owned(),
                    method: "textDocument/didOpen".to_owned(),
                    register_options: Some(
                        serde_json::to_value(text_document_registration_options.clone()).unwrap(),
                    ),
                },
                Registration {
                    id: "2".to_owned(),
                    method: "textDocument/didChange".to_owned(),
                    register_options: Some(
                        serde_json::to_value(TextDocumentChangeRegistrationOptions {
                            document_selector: Some(vec![candy_files]),
                            sync_kind: 2, // incremental
                        })
                        .unwrap(),
                    ),
                },
                Registration {
                    id: "3".to_owned(),
                    method: "textDocument/foldingRange".to_owned(),
                    register_options: Some(
                        serde_json::to_value(text_document_registration_options).unwrap(),
                    ),
                },
            ])
            .await
            .expect("Dynamic capability registration failed.");
        self.client
            .log_message(MessageType::INFO, "server initialized!")
            .await;
    }

    async fn shutdown(&self) -> jsonrpc::Result<()> {
        Ok(())
    }

    async fn did_open(&self, params: DidOpenTextDocumentParams) {
        self.open_file_manager.lock().await.did_open(params).await;
    }
    async fn did_change(&self, params: DidChangeTextDocumentParams) {
        self.open_file_manager.lock().await.did_change(params).await;
    }
    async fn did_close(&self, params: DidCloseTextDocumentParams) {
        self.open_file_manager.lock().await.did_close(params).await;
    }

    async fn folding_range(
        &self,
        params: FoldingRangeParams,
    ) -> jsonrpc::Result<Option<Vec<FoldingRange>>> {
        let source = self.get_file_content(params.text_document.uri).await?;
        Ok(Some(compute_folding_ranges(&source)))
    }
}

impl CandyLanguageServer {
    async fn get_file_content(&self, uri: Url) -> jsonrpc::Result<String> {
        match self.open_file_manager.lock().await.get(&uri) {
            Some(text) => Ok(text.to_owned()),
            None => {
                let file_path = uri.to_file_path().unwrap();
                fs::read_to_string(&file_path)
                    .await
                    .map_err(|it| jsonrpc::Error {
                        code: jsonrpc::ErrorCode::InternalError,
                        message: it.to_string(),
                        data: None,
                    })
            }
        }
    }
}
<commit_msg>feat(compiler): publish CST to AST errors via LSP<commit_after>use lsp_types::{
    Diagnostic, DiagnosticSeverity, DidChangeTextDocumentParams, DidCloseTextDocumentParams,
    DidOpenTextDocumentParams, DocumentFilter, FoldingRange, FoldingRangeParams, InitializeParams,
    InitializeResult, InitializedParams, MessageType, Registration, ServerCapabilities, ServerInfo,
    TextDocumentChangeRegistrationOptions, TextDocumentRegistrationOptions, Url,
};
use lspower::{jsonrpc, Client, LanguageServer};
use tokio::{fs, sync::Mutex};

use crate::compiler::{cst_to_ast::LowerCstToAst, string_to_cst::StringToCst};

use self::{
    folding_range::compute_folding_ranges, open_file_manager::OpenFileManager, utils::RangeToLsp,
};

mod folding_range;
mod open_file_manager;
mod utils;

#[derive(Debug)]
pub struct CandyLanguageServer {
    pub client: Client,
    pub open_file_manager: Mutex<OpenFileManager>,
}
impl CandyLanguageServer {
    pub fn from_client(client: Client) -> Self {
        Self {
            client,
            open_file_manager: Mutex::new(OpenFileManager::new()),
        }
    }
}

#[lspower::async_trait]
impl LanguageServer for CandyLanguageServer {
    async fn initialize(&self, _: InitializeParams) -> jsonrpc::Result<InitializeResult> {
        log::info!("LSP: initialize");
        self.client
            .log_message(MessageType::INFO, "Initializing!")
            .await;
        Ok(InitializeResult {
            // We only support dynamic registration for now.
            capabilities: ServerCapabilities::default(),
            server_info: Some(ServerInfo {
                name: "🍭 Candy Language Server".to_owned(),
                version: None,
            }),
        })
    }

    async fn initialized(&self, _: InitializedParams) {
        log::info!("LSP: initialized");
        let candy_files = DocumentFilter {
            language: Some("candy".to_owned()),
            scheme: Some("file".to_owned()),
            pattern: None,
        };
        let text_document_registration_options = TextDocumentRegistrationOptions {
            document_selector: Some(vec![candy_files.clone()]),
        };
        self.client
            .register_capability(vec![
                Registration {
                    id: "0".to_owned(),
                    method: "textDocument/didOpen".to_owned(),
                    register_options: Some(
                        serde_json::to_value(text_document_registration_options.clone()).unwrap(),
                    ),
                },
                Registration {
                    id: "1".to_owned(),
                    method: "textDocument/didOpen".to_owned(),
                    register_options: Some(
                        serde_json::to_value(text_document_registration_options.clone()).unwrap(),
                    ),
                },
                Registration {
                    id: "2".to_owned(),
                    method: "textDocument/didChange".to_owned(),
                    register_options: Some(
                        serde_json::to_value(TextDocumentChangeRegistrationOptions {
                            document_selector: Some(vec![candy_files]),
                            sync_kind: 2, // incremental
                        })
                        .unwrap(),
                    ),
                },
                Registration {
                    id: "3".to_owned(),
                    method: "textDocument/foldingRange".to_owned(),
                    register_options: Some(
                        serde_json::to_value(text_document_registration_options).unwrap(),
                    ),
                },
            ])
            .await
            .expect("Dynamic capability registration failed.");
        self.client
            .log_message(MessageType::INFO, "server initialized!")
            .await;
    }

    async fn shutdown(&self) -> jsonrpc::Result<()> {
        Ok(())
    }

    async fn did_open(&self, params: DidOpenTextDocumentParams) {
        self.open_file_manager
            .lock()
            .await
            .did_open(params.clone())
            .await;
        self.analyze_file(params.text_document.uri).await;
    }
    async fn did_change(&self, params: DidChangeTextDocumentParams) {
        self.open_file_manager
            .lock()
            .await
            .did_change(params.clone())
            .await;
        self.analyze_file(params.text_document.uri).await;
    }
    async fn did_close(&self, params: DidCloseTextDocumentParams) {
        self.open_file_manager.lock().await.did_close(params).await;
    }

    async fn folding_range(
        &self,
        params: FoldingRangeParams,
    ) -> jsonrpc::Result<Option<Vec<FoldingRange>>> {
        let source = self.get_file_content(params.text_document.uri).await?;
        Ok(Some(compute_folding_ranges(&source)))
    }
}

impl CandyLanguageServer {
    async fn analyze_file(&self, uri: Url) {
        let source = match self.get_file_content(uri.clone()).await {
            Ok(source) => source,
            Err(error) => {
                log::error!("{:?}", error);
                return;
            }
        };
        let (_, _, errors) = source.parse_cst().into_ast();

        let diagnostics = errors
            .into_iter()
            .map(|it| Diagnostic {
                range: it.span.to_lsp(&source),
                severity: Some(DiagnosticSeverity::ERROR),
                code: None,
                code_description: None,
                source: Some("🍭 Candy".to_owned()),
                message: it.message,
                related_information: None,
                tags: None,
                data: None,
            })
            .collect();
        self.client
            .publish_diagnostics(uri, diagnostics, None)
            .await;
    }
    async fn get_file_content(&self, uri: Url) -> jsonrpc::Result<String> {
        match self.open_file_manager.lock().await.get(&uri) {
            Some(text) => Ok(text.to_owned()),
            None => {
                let file_path = uri.to_file_path().unwrap();
                fs::read_to_string(&file_path)
                    .await
                    .map_err(|it| jsonrpc::Error {
                        code: jsonrpc::ErrorCode::InternalError,
                        message: it.to_string(),
                        data: None,
                    })
            }
        }
    }
}
<|endoftext|>


<commit_before>// See erts-6.1/doc/html/erl_ext_dist.html

#![feature(struct_variant)]     // this is for enum Eterm
#![allow(non_camel_case_types)] // this is for enum ErlTermTag

extern crate num;
extern crate collections;
extern crate debug;

use std::string::String;
use std::vec::Vec;
use std::num::FromPrimitive;
use num::bigint::BigInt;
use collections::bitv::Bitv;
use std::collections::TreeMap;

#[deriving(FromPrimitive)]
enum ErlTermTag {
    // ATOM_CACHE_REF = 82,
    SMALL_INTEGER_EXT = 97,
    INTEGER_EXT = 98,
    FLOAT_EXT = 99,
    ATOM_EXT = 100,
    REFERENCE_EXT = 101,
    PORT_EXT = 102,
    PID_EXT = 103,
    SMALL_TUPLE_EXT = 104,
    LARGE_TUPLE_EXT = 105,
    MAP_EXT = 116,
    NIL_EXT = 106,
    STRING_EXT = 107,
    LIST_EXT = 108,
    BINARY_EXT = 109,
    SMALL_BIG_EXT = 110,
    LARGE_BIG_EXT = 111,
    NEW_REFERENCE_EXT = 114,
    SMALL_ATOM_EXT = 115,
    FUN_EXT = 117,
    NEW_FUN_EXT = 112,
    EXPORT_EXT = 113,
    BIT_BINARY_EXT = 77,
    NEW_FLOAT_EXT = 70,
    ATOM_UTF8_EXT = 118,
    SMALL_ATOM_UTF8_EXT = 119,
}

pub enum Eterm {
    SmallInteger(u8),           // small_integer
    Integer(int),               // integer
    Float(f64),                 // float, new_float
    Atom(Atom),                 // atom, small_atom, atom_utf8, small_atom_utf8
    Reference {                 // reference, new_reference
        node: Atom,
        id: Vec<u8>,
        creation: u8},
    Port {                      // poort
        node: Atom,
        id: u8,
        creation: u8},
    Pid(Pid),                   // pid
    Tuple(Tuple),               // small_tuple, large_tuple
    Nil,                        // nil
    String(String),             // string
    List(List),                 // list
    Binary(Vec<u8>),            // binary
    BigNum(BigInt),             // small_big, large_big
    Fun {                       // fun
        pid: Pid,
        module: Atom,
        index: u32,
        uniq: u32,
        free_vars: Vec<Eterm>},
    NewFun {                    // new_fun
        arity: u8,
        uniq: u16,
        index: u32,
        module: Atom,
        old_index: u32,
        old_uniq: u16,
        pid: Pid,
        free_vars: Vec<Eterm>},
    Export {                    // export
        module: Atom,
        function: Atom,
        arity: u8,
    },
    BitBinary(Bitv),            // bit_binary; XXX: maybe choose some other representation?
}
pub type Atom = String;
pub type Tuple = Vec<Eterm>;
pub type EMap = TreeMap<Eterm, Eterm>;
pub type List = Vec<Eterm>;
pub struct Pid {
    node: Atom,
    id: u8,
    serial: u32,
    creation: u8,
}

fn main() {
    for i in range(70, 120) {
        let tag: Option<ErlTermTag> = FromPrimitive::from_int(i);
        println!("{} => {:?}", i, tag);
    }
}
<commit_msg>Example term<commit_after>// See erts-6.1/doc/html/erl_ext_dist.html

#![feature(struct_variant)]     // this is for enum Eterm
#![allow(non_camel_case_types)] // this is for enum ErlTermTag

extern crate num;
extern crate collections;
extern crate debug;

use std::string::String;
use std::vec::Vec;
use std::num::FromPrimitive;
use num::bigint::BigInt;
use collections::bitv::Bitv;
use std::collections::TreeMap;

#[deriving(FromPrimitive)]
enum ErlTermTag {
    // ATOM_CACHE_REF = 82,
    SMALL_INTEGER_EXT = 97,
    INTEGER_EXT = 98,
    FLOAT_EXT = 99,
    ATOM_EXT = 100,
    REFERENCE_EXT = 101,
    PORT_EXT = 102,
    PID_EXT = 103,
    SMALL_TUPLE_EXT = 104,
    LARGE_TUPLE_EXT = 105,
    MAP_EXT = 116,
    NIL_EXT = 106,
    STRING_EXT = 107,
    LIST_EXT = 108,
    BINARY_EXT = 109,
    SMALL_BIG_EXT = 110,
    LARGE_BIG_EXT = 111,
    NEW_REFERENCE_EXT = 114,
    SMALL_ATOM_EXT = 115,
    FUN_EXT = 117,
    NEW_FUN_EXT = 112,
    EXPORT_EXT = 113,
    BIT_BINARY_EXT = 77,
    NEW_FLOAT_EXT = 70,
    ATOM_UTF8_EXT = 118,
    SMALL_ATOM_UTF8_EXT = 119,
}

//#[deriving(PartialOrd, PartialEq, Ord, Eq)]
pub enum Eterm {
    SmallInteger(u8),           // small_integer
    Integer(int),               // integer
    // Float(f64),                 // float, new_float
    Atom(Atom),                 // atom, small_atom, atom_utf8, small_atom_utf8
    Reference {                 // reference, new_reference
        node: Atom,
        id: Vec<u8>,
        creation: u8},
    Port {                      // poort
        node: Atom,
        id: u8,
        creation: u8},
    Pid(Pid),                   // pid
    Tuple(Tuple),               // small_tuple, large_tuple
    Map(EMap),                  // map
    Nil,                        // nil
    String(String),             // string
    List(List),                 // list
    Binary(Vec<u8>),            // binary
    BigNum(BigInt),             // small_big, large_big
    Fun {                       // fun
        pid: Pid,
        module: Atom,
        index: u32,
        uniq: u32,
        free_vars: Vec<Eterm>},
    NewFun {                    // new_fun
        arity: u8,
        uniq: u16,
        index: u32,
        module: Atom,
        old_index: u32,
        old_uniq: u16,
        pid: Pid,
        free_vars: Vec<Eterm>},
    Export {                    // export
        module: Atom,
        function: Atom,
        arity: u8,
    },
    BitBinary(Bitv),            // bit_binary; XXX: maybe choose some other representation?
}
pub type Atom = String;
pub type Tuple = Vec<Eterm>;
pub type EMap = Vec<(Eterm, Eterm)>; // k-v pairs //TreeMap<Eterm, Eterm>;
pub type List = Vec<Eterm>;

//#[deriving(PartialOrd, PartialEq, Ord, Eq)]
pub struct Pid {                // moved out from enum because it used in Eterm::{Fun,NewFun}
    node: Atom,
    id: u8,
    serial: u32,
    creation: u8,
}

fn main() {
    for i in range(70, 120) {
        let tag: Option<ErlTermTag> = FromPrimitive::from_int(i);
        println!("{} => {:?}", i, tag);
    }

    let map = vec!( (Atom("my_map_key".to_string()), Nil) );

    let term: Eterm = NewFun {
        arity: 3,
        uniq: 1234,
        index: 10,
        module: "my_mod".to_string(),
        old_index: 1212,
        old_uniq: 1234,
        pid: Pid {node: "wasd".to_string(), id: 1, serial: 123, creation: 2},
        free_vars: vec!(//Float(3.14),
                        Nil,
                        Binary(vec!(1, 2, 3, 4)),
                        Export {
                            module: "my_mod".to_string(),
                            function: "my_func".to_string(),
                            arity: 4},
                        List(vec!(SmallInteger(1), Integer(1000000), Nil)),
                        Tuple(vec!(Atom("record".to_string()), Map(map))),
                        ),
    };
    println!("{:?}", term);
    match term {
        NewFun {free_vars: vars, ..} =>
            println!("{:?}", vars.as_slice()),
        _ => ()
    }
}
<|endoftext|>