<commit_before>//! AwesomeWM Keygrabber
use ::lua::LUA;
use rlua::{self, Lua, Table, Function, Value};
use rustwlc::*;
#[allow(deprecated)]
use rustwlc::xkb::Keysym;

const AWESOME_TABLE: &str = "keygrabber";
const SECRET_CALLBACK: &str = "__callback";

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

#[allow(deprecated)]
/// Given the current input, handle calling the Lua defined callback if it is
/// defined with the input.
pub fn keygrabber_handle(mods: KeyboardModifiers, sym: Keysym, state: KeyState)
                         -> rlua::Result<()> {
    let lua = LUA.lock().expect("LUA was poisoned");
    let lua_state = if state == KeyState::Pressed {
        "press"
    } else {
        "release"
    }.into();
    let lua_sym = sym.get_name().expect("Key symbol did not have a defined name");
    let lua_mods = ::lua::mods_to_lua(&lua.0, mods.mods)
        .expect("Could not convert mods to lua representation");
    let res = call_keygrabber(&lua.0, (lua_mods, lua_sym, lua_state));
    match res {
        Ok(_) | Err(rlua::Error::FromLuaConversionError { .. }) => {Ok(())},
        err => {
            err
        }
    }

}

/// Call the Lua callback function for when a key is pressed.
fn call_keygrabber(lua: &Lua,
                   (mods, key, event): (Table, String, String))
                   -> rlua::Result<()> {
    let globals = lua.globals();
    let lua_callback = globals
        .get::<_, Table>(AWESOME_TABLE).expect("keygrabber table not defined")
        .get::<_, Function>(SECRET_CALLBACK)?;
    lua_callback.call((mods, key, event))
}

fn run(lua: &Lua, function: rlua::Function) -> rlua::Result<()> {
    let keygrabber_table = lua.globals().get::<_, Table>(AWESOME_TABLE)?;
    keygrabber_table.set(SECRET_CALLBACK, function)
}

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

fn isrunning(lua: &Lua, _: ()) -> rlua::Result<bool> {
    let keygrabber_table = lua.globals().get::<_, Table>(AWESOME_TABLE)?;
    match keygrabber_table.get::<_, Value>(SECRET_CALLBACK)? {
        Value::Function(_) => Ok(true),
        _ => Ok(false)
    }
}
<commit_msg>Return RuntimeError if setting keygrabber > 1<commit_after>//! AwesomeWM Keygrabber
use ::lua::LUA;
use rlua::{self, Lua, Table, Function, Value};
use rustwlc::*;
#[allow(deprecated)]
use rustwlc::xkb::Keysym;

const AWESOME_TABLE: &str = "keygrabber";
const SECRET_CALLBACK: &str = "__callback";

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

#[allow(deprecated)]
/// Given the current input, handle calling the Lua defined callback if it is
/// defined with the input.
pub fn keygrabber_handle(mods: KeyboardModifiers, sym: Keysym, state: KeyState)
                         -> rlua::Result<()> {
    let lua = LUA.lock().expect("LUA was poisoned");
    let lua_state = if state == KeyState::Pressed {
        "press"
    } else {
        "release"
    }.into();
    let lua_sym = sym.get_name().expect("Key symbol did not have a defined name");
    let lua_mods = ::lua::mods_to_lua(&lua.0, mods.mods)
        .expect("Could not convert mods to lua representation");
    let res = call_keygrabber(&lua.0, (lua_mods, lua_sym, lua_state));
    match res {
        Ok(_) | Err(rlua::Error::FromLuaConversionError { .. }) => {Ok(())},
        err => {
            err
        }
    }

}

/// Call the Lua callback function for when a key is pressed.
fn call_keygrabber(lua: &Lua,
                   (mods, key, event): (Table, String, String))
                   -> rlua::Result<()> {
    let globals = lua.globals();
    let lua_callback = globals
        .get::<_, Table>(AWESOME_TABLE).expect("keygrabber table not defined")
        .get::<_, Function>(SECRET_CALLBACK)?;
    lua_callback.call((mods, key, event))
}

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

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

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


<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! ## Summary
//!
//! One of the CITA's core components is used to implement the peer-to-peer network
//! and provide point-to-point connection interaction.
//!
//! ### Message queuing situation
//!
//! 1. Subscribe channel
//!
//!     |       Queue       | PubModule | Message Type   |
//!     | ----------------- | --------- | -------------- |
//!     | network_tx        | Auth      | Request        |
//!     | network_consensus | Consensus | SignedProposal |
//!     | network_consensus | Consensus | RawBytes       |
//!     | network           | Chain     | Status         |
//!     | network           | Chain     | syncResponse   |
//!     | network           | Jonsonrpc | RequestNet     |
//!
//! 2. Publish channel
//!
//!     |       Queue       | PubModule | SubModule           | Message Type   |
//!     | ----------------- | --------- | ------------------- | -------------- |
//!     | network           | Net       | Chain, Executor     | SyncResponse   |
//!     | network           | Net       | Snapshot            | SnapshotResp   |
//!     | network           | Net       | Jsonrpc             | Response       |
//!     | network_tx        | Net       | Auth                | Request        |
//!     | network_consensus | Net       | Executor, Consensus | SignedProposal |
//!     | network_consensus | Net       | Consensus           | RawBytes       |
//!
//! ### p2p binary protocol
//! | Start      | Full length | Key length | Key value      | Message value    |
//! | ---------- | ----------- | ---------- | -------------- | ---------------- |
//! | \xDEADBEEF | u32         | u8(byte)   | bytes of a str | a serialize data |
//!
//! full_len = 1 + key_len + body_len
//!
//! ### Key behavoir
//!
//! the key struct:
//!
//! - [`Connection`]
//! - [`NetWork`]
//! - [`Synchronizer`]
//!
//! In addition to the `tokio_server`, there is an `Arc<Connection>` for
//! this structure in almost all the threads of this module to confirm that the node is alive,
//! increase or decrease nodes, consensus message broadcasts, authentication message broadcasts,
//! node status broadcasts, synchronization node blocks Height and so on.
//!
//! About binary protocol encoding and decoding, please look at module `citaprotocol`, the fuction
//! [`pubsub_message_to_network_message`] and [`network_message_to_pubsub_message`].
//!
//! [`Connection`]: ./connection/struct.Connection.html
//! [`NetWork`]: ./network/struct.NetWork.html
//! [`Synchronizer`]: ./synchronizer/struct.Synchronizer.html
//! [`pubsub_message_to_network_message`]: ./citaprotocol/fn.pubsub_message_to_network_message.html
//! [`network_message_to_pubsub_message`]: ./citaprotocol/fn.network_message_to_pubsub_message.html
//!

#![feature(try_from)]
#![feature(tool_lints)]

extern crate byteorder;
extern crate bytes;
extern crate clap;
extern crate dotenv;
extern crate futures;
extern crate native_tls;
extern crate tokio_tls;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate notify;
extern crate pubsub;
extern crate rand;
#[cfg(test)]
extern crate tempfile;
extern crate tokio;
#[macro_use]
extern crate util;

#[macro_use]
extern crate serde_derive;

pub mod citaprotocol;
pub mod config;
pub mod connection;
pub mod netserver;
pub mod synchronizer;
//pub mod sync_vec;
pub mod network;

use clap::App;
use config::NetConfig;
use connection::{manage_connect, Connections, Task};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::Message;
use netserver::NetServer;
use network::NetWork;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use pubsub::start_pubsub;
use std::convert::TryFrom;
use std::net::SocketAddr;
use std::sync::mpsc::channel;
use std::thread;
use std::time::Duration;
use synchronizer::Synchronizer;
use util::set_panic_handler;

include!(concat!(env!("OUT_DIR"), "/build_info.rs"));

fn main() {
    micro_service_init!("cita-network", "CITA:network");
    info!("Version: {}", get_build_info_str(true));

    // init app
    // todo load config
    let matches = App::new("network")
        .version(get_build_info_str(true))
        .long_version(get_build_info_str(false))
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .args_from_usage("-c, --config=[FILE] 'Sets a custom config file'")
        .get_matches();

    let config_path = matches.value_of("config").unwrap_or("config");

    let config = NetConfig::new(config_path);

    // init pubsub

    // split new_tx with other msg
    let (ctx_sub_tx, crx_sub_tx) = channel();
    let (ctx_pub_tx, crx_pub_tx) = channel();
    start_pubsub(
        "network_tx",
        routing_key!([Auth >> Request]),
        ctx_sub_tx,
        crx_pub_tx,
    );

    let (ctx_sub_consensus, crx_sub_consensus) = channel();
    let (ctx_pub_consensus, crx_pub_consensus) = channel();
    start_pubsub(
        "network_consensus",
        routing_key!([Consensus >> SignedProposal, Consensus >> RawBytes]),
        ctx_sub_consensus,
        crx_pub_consensus,
    );

    let (ctx_sub, crx_sub) = channel();
    let (ctx_pub, crx_pub) = channel();
    start_pubsub(
        "network",
        routing_key!([
            Chain >> Status,
            Chain >> SyncResponse,
            Jsonrpc >> RequestNet,
            Snapshot >> SnapshotReq,
        ]),
        ctx_sub,
        crx_pub,
    );

    let (net_work_tx, net_work_rx) = channel();
    // start server
    // This brings up our server.
    // all server recv msg directly publish to mq
    let address_str = format!("0.0.0.0:{}", config.port.unwrap());
    let address = address_str.parse::<SocketAddr>().unwrap();
    let net_server = NetServer::new(net_work_tx.clone(), config.enable_tls.unwrap_or(false));

    //network server listener
    thread::spawn(move || net_server.server(address));

    //connections manage to loop
    let (tx, rx) = channel();
    let (mut con, task_sender) = Connections::new(&config);
    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(1)).unwrap();
    let _ = watcher.watch(".", RecursiveMode::NonRecursive);

    let (sync_tx, sync_rx) = channel();
    let net_work = NetWork::new(
        task_sender.clone(),
        ctx_pub.clone(),
        sync_tx,
        ctx_pub_tx,
        ctx_pub_consensus,
        con.is_pause.clone(),
        con.connect_number.clone(),
    );
    manage_connect(config_path, rx, task_sender.clone());

    thread::spawn(move || con.run());

    // loop deal data
    thread::spawn(move || loop {
        if let Ok((source, cita_req)) = net_work_rx.recv() {
            net_work.receiver(source, cita_req);
        }
    });

    // Sync loop
    let mut synchronizer = Synchronizer::new(ctx_pub, task_sender.clone());
    thread::spawn(move || loop {
        if let Ok((source, payload)) = sync_rx.recv() {
            synchronizer.receive(source, payload);
        }
    });

    // Subscribe Auth Tx
    let tx_task_sender = task_sender.clone();
    thread::spawn(move || loop {
        let (key, body) = crx_sub_tx.recv().unwrap();
        let msg = Message::try_from(&body).unwrap();
        trace!("Auth Tx from Local");
        tx_task_sender.send(Task::Broadcast((key, msg))).unwrap();
    });

    // Subscribe Consensus Msg
    thread::spawn(move || loop {
        let (key, body) = crx_sub_consensus.recv().unwrap();
        let msg = Message::try_from(&body).unwrap();
        trace!("Consensus Msg from Local");
        task_sender.send(Task::Broadcast((key, msg))).unwrap();
    });

    loop {
        // Msg from MQ need proc before broadcast
        let (key, body) = crx_sub.recv().unwrap();
        trace!("handle delivery from {} payload {:?}", key, body);
        net_work_tx.send((Source::LOCAL, (key, body))).unwrap();
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Source {
    LOCAL,
    REMOTE,
}
<commit_msg>Instead syncResponse to SyncResponse<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! ## Summary
//!
//! One of the CITA's core components is used to implement the peer-to-peer network
//! and provide point-to-point connection interaction.
//!
//! ### Message queuing situation
//!
//! 1. Subscribe channel
//!
//!     |       Queue       | PubModule | Message Type   |
//!     | ----------------- | --------- | -------------- |
//!     | network_tx        | Auth      | Request        |
//!     | network_consensus | Consensus | SignedProposal |
//!     | network_consensus | Consensus | RawBytes       |
//!     | network           | Chain     | Status         |
//!     | network           | Chain     | SyncResponse   |
//!     | network           | Jonsonrpc | RequestNet     |
//!
//! 2. Publish channel
//!
//!     |       Queue       | PubModule | SubModule           | Message Type   |
//!     | ----------------- | --------- | ------------------- | -------------- |
//!     | network           | Net       | Chain, Executor     | SyncResponse   |
//!     | network           | Net       | Snapshot            | SnapshotResp   |
//!     | network           | Net       | Jsonrpc             | Response       |
//!     | network_tx        | Net       | Auth                | Request        |
//!     | network_consensus | Net       | Executor, Consensus | SignedProposal |
//!     | network_consensus | Net       | Consensus           | RawBytes       |
//!
//! ### p2p binary protocol
//! | Start      | Full length | Key length | Key value      | Message value    |
//! | ---------- | ----------- | ---------- | -------------- | ---------------- |
//! | \xDEADBEEF | u32         | u8(byte)   | bytes of a str | a serialize data |
//!
//! full_len = 1 + key_len + body_len
//!
//! ### Key behavoir
//!
//! the key struct:
//!
//! - [`Connection`]
//! - [`NetWork`]
//! - [`Synchronizer`]
//!
//! In addition to the `tokio_server`, there is an `Arc<Connection>` for
//! this structure in almost all the threads of this module to confirm that the node is alive,
//! increase or decrease nodes, consensus message broadcasts, authentication message broadcasts,
//! node status broadcasts, synchronization node blocks Height and so on.
//!
//! About binary protocol encoding and decoding, please look at module `citaprotocol`, the fuction
//! [`pubsub_message_to_network_message`] and [`network_message_to_pubsub_message`].
//!
//! [`Connection`]: ./connection/struct.Connection.html
//! [`NetWork`]: ./network/struct.NetWork.html
//! [`Synchronizer`]: ./synchronizer/struct.Synchronizer.html
//! [`pubsub_message_to_network_message`]: ./citaprotocol/fn.pubsub_message_to_network_message.html
//! [`network_message_to_pubsub_message`]: ./citaprotocol/fn.network_message_to_pubsub_message.html
//!

#![feature(try_from)]
#![feature(tool_lints)]

extern crate byteorder;
extern crate bytes;
extern crate clap;
extern crate dotenv;
extern crate futures;
extern crate native_tls;
extern crate tokio_tls;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate notify;
extern crate pubsub;
extern crate rand;
#[cfg(test)]
extern crate tempfile;
extern crate tokio;
#[macro_use]
extern crate util;

#[macro_use]
extern crate serde_derive;

pub mod citaprotocol;
pub mod config;
pub mod connection;
pub mod netserver;
pub mod synchronizer;
//pub mod sync_vec;
pub mod network;

use clap::App;
use config::NetConfig;
use connection::{manage_connect, Connections, Task};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::Message;
use netserver::NetServer;
use network::NetWork;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use pubsub::start_pubsub;
use std::convert::TryFrom;
use std::net::SocketAddr;
use std::sync::mpsc::channel;
use std::thread;
use std::time::Duration;
use synchronizer::Synchronizer;
use util::set_panic_handler;

include!(concat!(env!("OUT_DIR"), "/build_info.rs"));

fn main() {
    micro_service_init!("cita-network", "CITA:network");
    info!("Version: {}", get_build_info_str(true));

    // init app
    // todo load config
    let matches = App::new("network")
        .version(get_build_info_str(true))
        .long_version(get_build_info_str(false))
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .args_from_usage("-c, --config=[FILE] 'Sets a custom config file'")
        .get_matches();

    let config_path = matches.value_of("config").unwrap_or("config");

    let config = NetConfig::new(config_path);

    // init pubsub

    // split new_tx with other msg
    let (ctx_sub_tx, crx_sub_tx) = channel();
    let (ctx_pub_tx, crx_pub_tx) = channel();
    start_pubsub(
        "network_tx",
        routing_key!([Auth >> Request]),
        ctx_sub_tx,
        crx_pub_tx,
    );

    let (ctx_sub_consensus, crx_sub_consensus) = channel();
    let (ctx_pub_consensus, crx_pub_consensus) = channel();
    start_pubsub(
        "network_consensus",
        routing_key!([Consensus >> SignedProposal, Consensus >> RawBytes]),
        ctx_sub_consensus,
        crx_pub_consensus,
    );

    let (ctx_sub, crx_sub) = channel();
    let (ctx_pub, crx_pub) = channel();
    start_pubsub(
        "network",
        routing_key!([
            Chain >> Status,
            Chain >> SyncResponse,
            Jsonrpc >> RequestNet,
            Snapshot >> SnapshotReq,
        ]),
        ctx_sub,
        crx_pub,
    );

    let (net_work_tx, net_work_rx) = channel();
    // start server
    // This brings up our server.
    // all server recv msg directly publish to mq
    let address_str = format!("0.0.0.0:{}", config.port.unwrap());
    let address = address_str.parse::<SocketAddr>().unwrap();
    let net_server = NetServer::new(net_work_tx.clone(), config.enable_tls.unwrap_or(false));

    //network server listener
    thread::spawn(move || net_server.server(address));

    //connections manage to loop
    let (tx, rx) = channel();
    let (mut con, task_sender) = Connections::new(&config);
    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(1)).unwrap();
    let _ = watcher.watch(".", RecursiveMode::NonRecursive);

    let (sync_tx, sync_rx) = channel();
    let net_work = NetWork::new(
        task_sender.clone(),
        ctx_pub.clone(),
        sync_tx,
        ctx_pub_tx,
        ctx_pub_consensus,
        con.is_pause.clone(),
        con.connect_number.clone(),
    );
    manage_connect(config_path, rx, task_sender.clone());

    thread::spawn(move || con.run());

    // loop deal data
    thread::spawn(move || loop {
        if let Ok((source, cita_req)) = net_work_rx.recv() {
            net_work.receiver(source, cita_req);
        }
    });

    // Sync loop
    let mut synchronizer = Synchronizer::new(ctx_pub, task_sender.clone());
    thread::spawn(move || loop {
        if let Ok((source, payload)) = sync_rx.recv() {
            synchronizer.receive(source, payload);
        }
    });

    // Subscribe Auth Tx
    let tx_task_sender = task_sender.clone();
    thread::spawn(move || loop {
        let (key, body) = crx_sub_tx.recv().unwrap();
        let msg = Message::try_from(&body).unwrap();
        trace!("Auth Tx from Local");
        tx_task_sender.send(Task::Broadcast((key, msg))).unwrap();
    });

    // Subscribe Consensus Msg
    thread::spawn(move || loop {
        let (key, body) = crx_sub_consensus.recv().unwrap();
        let msg = Message::try_from(&body).unwrap();
        trace!("Consensus Msg from Local");
        task_sender.send(Task::Broadcast((key, msg))).unwrap();
    });

    loop {
        // Msg from MQ need proc before broadcast
        let (key, body) = crx_sub.recv().unwrap();
        trace!("handle delivery from {} payload {:?}", key, body);
        net_work_tx.send((Source::LOCAL, (key, body))).unwrap();
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Source {
    LOCAL,
    REMOTE,
}
<|endoftext|>


<commit_before>use luminance::tessellation;
use luminance_gl::gl33::Tessellation;
use std::collections::BTreeMap;
//use std::fs::File;
//use std::io::Read;
use std::path::{Path, PathBuf};
use wavefront_obj::{self, obj};

// FIXME: implement materials
pub type Material = ();

pub type Vertex = (VertexPos, VertexNor, VertexTexCoord);
pub type VertexPos = [f32; 3];
pub type VertexNor = [f32; 3];
pub type VertexTexCoord = [f32; 2];

pub struct Model<'a> {
  parts: Vec<Part<'a>>
}

impl<'a> Model<'a> {
  pub fn from_parts(parts: Vec<Part<'a>>) -> Self {
    Model {
      parts: parts
    }
  }
}

pub struct Part<'a> {
  tess: Tessellation,
  mat: Option<&'a Material>
}

impl<'a> Part<'a> {
  pub fn new(tess: Tessellation, mat: Option<&'a Material>) -> Self {
    Part {
      tess: tess,
      mat: mat
    }
  }

  pub fn tessellation(&self) -> &Tessellation {
    &self.tess
  }

  pub fn material(&self) -> Option<&Material> {
    self.mat.clone()
  }
}

// FIXME: review all the code bellow
////pub fn load<P>(path: P, mode: tessellation::Mode) -> Result<gl33::Tessellation, TessellationError> where P: AsRef<Path> {
////  let path = path.as_ref();
////
////  info!("loading model: \x1b[35m{:?}", path);
////
////  let mut input = String::new();
////
////  // load the data directly into memory; no buffering nor streaming
////  {
////    let mut file = try!(File::open(path).map_err(|e| TessellationError::FileNotFound(path.to_path_buf(), format!("{:?}", e))));
////    let _ = file.read_to_string(&mut input);
////  }
////
////  // parse the obj file and convert it
////  let obj_set = try!(obj::parse(input).map_err(TessellationError::ParseFailed));
////
////  convert_obj(obj_set, mode)
////}
////
// Turn a loaded wavefront obj object into a `Model`
//fn convert_obj(obj_set: obj::ObjSet) -> Result<Model, ModelError> {
//  if obj_set.objects.len() != 1 {
//    return Err(ModelError::MultiObjects);
//  }
//
//  let obj = &obj_set.objects[0];
//  info!("  converting object \x1b[35m{}", obj.name);
//
//  // convert all the geometries
//  let parts = Vec::with_capacity(obj.geometries.len());
//
//  Err(TessellationError::Error)
//}

// Convert wavefront_obj’s Geometry into a pair of vertices and indices.
//
// This function will regenerate the indices on the fly based on which are used in the shapes in the
// geometry. It’s used to create independent tessellation.
fn convert_geometry(geo: &obj::Geometry, positions: &[obj::Vertex], normals: &[obj::Normal], tvertices: &[obj::TVertex]) -> Result<(Vec<Vertex>, Vec<u32>, tessellation::Mode), ModelError> {
  let mut vertices = Vec::new(); // FIXME: better allocation scheme?
  let mut indices = Vec::new();
  let mut index_map = BTreeMap::new();

  info!("    converting geometry");

  // TODO: error if no shapes?

  let mode = guess_mode(geo.shapes[0].primitive);

  for prim in geo.shapes.iter().map(|s| s.primitive) {
    let keys = try!(create_keys_from_primitive(prim));

    for key in keys {
      match index_map.get(&key).map(|&i| i) {
        Some(index) => {
          // that triplet already exists; just append the index in the indices buffer
          indices.push(index);
        },
        None => {
          // this is a new, not yet discovered triplet; create the corresponding vertex and add it
          // to the vertices buffer, and map the triplet to the index in the indices buffer
          let vertex = interleave_vertex(&positions[key.0], &normals[key.1], &tvertices[key.2]);
          let index = vertices.len() as u32;

          vertices.push(vertex);
          indices.push(index);
          index_map.insert(key, index);
        }
      }
    }
  }

  Ok((vertices, indices, mode))
}

// Create triplet keys from wavefront_obj primitives. If any primitive doesn’t have all the triplet
// information (position, normal, tex), a ModelError::UnsupportedVertex error is returned instead.
fn create_keys_from_primitive(prim: obj::Primitive) -> Result<Vec<(usize, usize, usize)>, ModelError> {
  match prim {
    obj::Primitive::Point(i) => {
      let a = try!(vtnindex_to_key(i));
      Ok(vec![a])
    },
    obj::Primitive::Line(i, j) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      Ok(vec![a, b])
    },
    obj::Primitive::Triangle(i, j, k) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      let c = try!(vtnindex_to_key(k));
      Ok(vec![a, b, c])
    }
  }
}

// Convert from a wavefront_obj VTNIndex into our triplet, raising error if not possible.
fn vtnindex_to_key(i: obj::VTNIndex) -> Result<(usize, usize, usize), ModelError> {
  match i {
    (pi, Some(ti), Some(ni)) => Ok((pi, ni, ti)),
    _ => Err(ModelError::UnsupportedVertex)
  }
}

fn interleave_vertex(p: &obj::Vertex, n: &obj::Normal, t: &obj::TVertex) -> Vertex {
  (convert_vertex(p), convert_nor(n), convert_tvertex(t))
}

fn convert_vertex(v: &obj::Vertex) -> VertexPos {
  [v.x as f32, v.y as f32, v.z as f32]
}

fn convert_nor(n: &obj::Normal) -> VertexNor {
  convert_vertex(n)
}

fn convert_tvertex(t: &obj::TVertex) -> VertexTexCoord {
  [t.x as f32, t.y as f32]
}

fn guess_mode(prim: obj::Primitive) -> tessellation::Mode {
  match prim {
    obj::Primitive::Point(_) => tessellation::Mode::Point,
    obj::Primitive::Line(_, _) => tessellation::Mode::Line,
    obj::Primitive::Triangle(_, _, _) => tessellation::Mode::Triangle
  }
}

////mod hot {
////  use super::{TessellationError, Vertex};
////
////  use luminance::tessellation;
////  use luminance_gl::gl33;
////  use resource::ResourceManager;
////  use std::ops::Deref;
////  use std::path::{Path, PathBuf};
////
////  pub struct Tessellation {
////    path: PathBuf,
////    mode: tessellation::Mode,
////    tess: gl33::Tessellation
////  }
////
////  impl Tessellation {
////    fn load<P>(manager: &mut ResourceManager, path: P, mode: tessellation::Mode) -> Result<Self, TessellationError> where P: AsRef<Path> {
////      Err(TessellationError::Error)
////    }
////  }
////
////  impl Deref for Tessellation {
////    type Target = gl33::Tessellation;
////
////    fn deref(&self) -> &Self::Target {
////      &self.tess
////    }
////  }
////}
////
pub enum ModelError {
  FileNotFound(PathBuf, String),
  ParseFailed(wavefront_obj::ParseError),
  MultiObjects,
  UnsupportedVertex
}
<commit_msg>Added model::load! (#3, #9)<commit_after>use luminance::tessellation;
use luminance_gl::gl33::Tessellation;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::iter::IntoIterator;
use std::path::{Path, PathBuf};
use std::vec;
use wavefront_obj::{self, obj};

// FIXME: implement materials
pub type Material = ();

pub type Vertex = (VertexPos, VertexNor, VertexTexCoord);
pub type VertexPos = [f32; 3];
pub type VertexNor = [f32; 3];
pub type VertexTexCoord = [f32; 2];

pub struct Model<'a> {
  parts: Vec<Part<'a>>
}

impl<'a> Model<'a> {
  pub fn from_parts(parts: Vec<Part<'a>>) -> Self {
    Model {
      parts: parts
    }
  }
}

impl<'a> IntoIterator for Model<'a> {
  type Item = Part<'a>;
  type IntoIter = vec::IntoIter<Part<'a>>;

  fn into_iter(self) -> Self::IntoIter {
    self.parts.into_iter()
  }
}

pub struct Part<'a> {
  tess: Tessellation,
  mat: Option<&'a Material>
}

impl<'a> Part<'a> {
  pub fn new(tess: Tessellation, mat: Option<&'a Material>) -> Self {
    Part {
      tess: tess,
      mat: mat
    }
  }

  pub fn tessellation(&self) -> &Tessellation {
    &self.tess
  }

  pub fn material(&self) -> Option<&Material> {
    self.mat.clone()
  }
}

pub fn load<'a, P>(path: P) -> Result<Model<'a>, ModelError> where P: AsRef<Path> {
  let path = path.as_ref();

  info!("loading model: \x1b[35m{:?}", path);

  let mut input = String::new();

  // load the data directly into memory; no buffering nor streaming
  {
    let mut file = try!(File::open(path).map_err(|e| ModelError::FileNotFound(path.to_path_buf(), format!("{:?}", e))));
    let _ = file.read_to_string(&mut input);
  }

  // parse the obj file and convert it
  let obj_set = try!(obj::parse(input).map_err(ModelError::ParseFailed));

  convert_obj(obj_set)
}

// Turn a wavefront obj object into a `Model`
fn convert_obj<'a>(obj_set: obj::ObjSet) -> Result<Model<'a>, ModelError> {
  if obj_set.objects.len() != 1 {
    return Err(ModelError::MultiObjects);
  }

  let obj = &obj_set.objects[0];
  info!("  converting object \x1b[35m{}", obj.name);

  // convert all the geometries
  let mut parts = Vec::with_capacity(obj.geometry.len());

  for geometry in &obj.geometry {
    let (vertices, indices, mode) = try!(convert_geometry(geometry, &obj.vertices, &obj.normals, &obj.tex_vertices));
    let part = Part::new(Tessellation::new(mode, &vertices, Some(&indices)), None); // FIXME: material
    parts.push(part);
  }

  Ok(Model::from_parts(parts))
}

// Convert wavefront_obj’s Geometry into a pair of vertices and indices.
//
// This function will regenerate the indices on the fly based on which are used in the shapes in the
// geometry. It’s used to create independent tessellation.
fn convert_geometry(geo: &obj::Geometry, positions: &[obj::Vertex], normals: &[obj::Normal], tvertices: &[obj::TVertex]) -> Result<(Vec<Vertex>, Vec<u32>, tessellation::Mode), ModelError> {
  if geo.shapes.is_empty() {
    return Err(ModelError::NoShape);
  }

  let mut vertices = Vec::new(); // FIXME: better allocation scheme?
  let mut indices = Vec::new();
  let mut index_map = BTreeMap::new();

  info!("    converting geometry");

  let mode = guess_mode(geo.shapes[0].primitive);

  for prim in geo.shapes.iter().map(|s| s.primitive) {
    let keys = try!(create_keys_from_primitive(prim));

    for key in keys {
      match index_map.get(&key).map(|&i| i) {
        Some(index) => {
          // that triplet already exists; just append the index in the indices buffer
          indices.push(index);
        },
        None => {
          // this is a new, not yet discovered triplet; create the corresponding vertex and add it
          // to the vertices buffer, and map the triplet to the index in the indices buffer
          let vertex = interleave_vertex(&positions[key.0], &normals[key.1], &tvertices[key.2]);
          let index = vertices.len() as u32;

          vertices.push(vertex);
          indices.push(index);
          index_map.insert(key, index);
        }
      }
    }
  }

  Ok((vertices, indices, mode))
}

// Create triplet keys from wavefront_obj primitives. If any primitive doesn’t have all the triplet
// information (position, normal, tex), a ModelError::UnsupportedVertex error is returned instead.
fn create_keys_from_primitive(prim: obj::Primitive) -> Result<Vec<(usize, usize, usize)>, ModelError> {
  match prim {
    obj::Primitive::Point(i) => {
      let a = try!(vtnindex_to_key(i));
      Ok(vec![a])
    },
    obj::Primitive::Line(i, j) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      Ok(vec![a, b])
    },
    obj::Primitive::Triangle(i, j, k) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      let c = try!(vtnindex_to_key(k));
      Ok(vec![a, b, c])
    }
  }
}

// Convert from a wavefront_obj VTNIndex into our triplet, raising error if not possible.
fn vtnindex_to_key(i: obj::VTNIndex) -> Result<(usize, usize, usize), ModelError> {
  match i {
    (pi, Some(ti), Some(ni)) => Ok((pi, ni, ti)),
    _ => Err(ModelError::UnsupportedVertex)
  }
}

fn interleave_vertex(p: &obj::Vertex, n: &obj::Normal, t: &obj::TVertex) -> Vertex {
  (convert_vertex(p), convert_nor(n), convert_tvertex(t))
}

fn convert_vertex(v: &obj::Vertex) -> VertexPos {
  [v.x as f32, v.y as f32, v.z as f32]
}

fn convert_nor(n: &obj::Normal) -> VertexNor {
  convert_vertex(n)
}

fn convert_tvertex(t: &obj::TVertex) -> VertexTexCoord {
  [t.x as f32, t.y as f32]
}

fn guess_mode(prim: obj::Primitive) -> tessellation::Mode {
  match prim {
    obj::Primitive::Point(_) => tessellation::Mode::Point,
    obj::Primitive::Line(_, _) => tessellation::Mode::Line,
    obj::Primitive::Triangle(_, _, _) => tessellation::Mode::Triangle
  }
}

////mod hot {
////  use super::{TessellationError, Vertex};
////
////  use luminance::tessellation;
////  use luminance_gl::gl33;
////  use resource::ResourceManager;
////  use std::ops::Deref;
////  use std::path::{Path, PathBuf};
////
////  pub struct Tessellation {
////    path: PathBuf,
////    mode: tessellation::Mode,
////    tess: gl33::Tessellation
////  }
////
////  impl Tessellation {
////    fn load<P>(manager: &mut ResourceManager, path: P, mode: tessellation::Mode) -> Result<Self, TessellationError> where P: AsRef<Path> {
////      Err(TessellationError::Error)
////    }
////  }
////
////  impl Deref for Tessellation {
////    type Target = gl33::Tessellation;
////
////    fn deref(&self) -> &Self::Target {
////      &self.tess
////    }
////  }
////}
////
pub enum ModelError {
  FileNotFound(PathBuf, String),
  ParseFailed(wavefront_obj::ParseError),
  MultiObjects,
  UnsupportedVertex,
  NoShape
}
<|endoftext|>


<commit_before>use std::io::{Read};
use byteorder::{LittleEndian as E, ReadBytesExt};
use gfx;
use gfx::format::I8Norm;
use render::{ObjectVertex, NUM_COLOR_IDS, COLOR_ID_BODY};

const SCALE: f32 = 1.0 / 4.0;

pub struct Mesh<R: gfx::Resources> {
    pub slice: gfx::Slice<R>,
    pub buffer: gfx::handle::Buffer<R, ObjectVertex>,
}

pub struct Wheel<R: gfx::Resources> {
    pub mesh: Option<Mesh<R>>,
    pub steer: u32,
    pub width: f32,
    pub radius: f32,
}

pub struct Debrie<R: gfx::Resources> {
    pub mesh: Mesh<R>,
}

pub struct Model<R: gfx::Resources> {
    pub body: Mesh<R>,
    pub color: [u32; 2],
    pub wheels: Vec<Wheel<R>>,
    pub debris: Vec<Debrie<R>>,
}

pub fn load_c3d<I, R, F>(source: &mut I, factory: &mut F) -> Mesh<R> where
    I: ReadBytesExt,
    R: gfx::Resources,
    F: gfx::traits::FactoryExt<R>,
{
    let version = source.read_u32::<E>().unwrap();
    assert_eq!(version, 8);
    let num_positions = source.read_u32::<E>().unwrap();
    let num_normals   = source.read_u32::<E>().unwrap();
    let num_polygons  = source.read_u32::<E>().unwrap();
    let _total_verts  = source.read_u32::<E>().unwrap();

    let coord_max  = [
        source.read_i32::<E>().unwrap() as f32 * SCALE,
        source.read_i32::<E>().unwrap() as f32 * SCALE,
        source.read_i32::<E>().unwrap() as f32 * SCALE,
    ];
    let coord_min  = [
        source.read_i32::<E>().unwrap() as f32 * SCALE,
        source.read_i32::<E>().unwrap() as f32 * SCALE,
        source.read_i32::<E>().unwrap() as f32 * SCALE,
    ];
    info!("\tBound {:?} to {:?}", coord_min, coord_max);
    let _parent_off = [
        source.read_i32::<E>().unwrap(),
        source.read_i32::<E>().unwrap(),
        source.read_i32::<E>().unwrap(),
    ];
    let _max_radius = source.read_u32::<E>().unwrap();
    let _parent_rot = [source.read_u32::<E>().unwrap(), source.read_u32::<E>().unwrap(), source.read_u32::<E>().unwrap()];
	for _ in 0 .. (1+3+9) {
		source.read_f64::<E>().unwrap();
	}

    info!("\tReading {} positions...", num_positions);
    let mut positions = Vec::with_capacity(num_positions as usize);
    for _ in 0 .. num_positions {
        for _ in 0..3 {
            source.read_u32::<E>().unwrap(); //unknown
        }
        let mut pos = [0u8; 3];
        source.read_exact(&mut pos).unwrap();
        let _sort_info = source.read_u32::<E>().unwrap();
        positions.push(pos);
    }

    info!("\tReading {} normals...", num_normals);
    let mut normals = Vec::with_capacity(num_normals as usize);
    for _ in 0 .. num_normals {
        let mut norm = [0u8; 4];
        source.read_exact(&mut norm).unwrap();
        let _sort_info = source.read_u32::<E>().unwrap();
        normals.push(norm);
    }

    info!("\tReading {} polygons...", num_polygons);
    let mut vertices = Vec::with_capacity(num_polygons as usize * 3);
    for i in 0 .. num_polygons {
        let num_corners = source.read_u32::<E>().unwrap();
        //assert_eq!(num_corners, 3);
		assert!(3 <= num_corners && num_corners <= 4);
        let _sort_info = source.read_u32::<E>().unwrap();
        let color = [source.read_u32::<E>().unwrap(), source.read_u32::<E>().unwrap()];
        let mut dummy = [0; 4];
        source.read_exact(&mut dummy[..4]).unwrap(); //skip flat normal
        source.read_exact(&mut dummy[..3]).unwrap(); //skip middle point
        for k in 0..num_corners {
            let pid = source.read_u32::<E>().unwrap();
            let nid = source.read_u32::<E>().unwrap();
            let v = (i*3+k, (positions[pid as usize], normals[nid as usize], color));
            vertices.push(v);
        }
    }

	// sorted variable polygons
	for _ in 0 .. 3 {
		for _ in 0 .. num_polygons {
			let _poly_ind = source.read_u32::<E>().unwrap();
		}
	}

    let convert = |(p, n, c): ([u8; 3], [u8; 4], [u32; 2])| ObjectVertex {
        pos: [
            coord_min[0] + p[0] as f32 * (coord_max[0] - coord_min[0]) / 255.0,
            coord_min[1] + p[1] as f32 * (coord_max[1] - coord_min[1]) / 255.0,
            coord_min[2] + p[2] as f32 * (coord_max[2] - coord_min[2]) / 255.0,
            1.0],
        color: if c[0] < NUM_COLOR_IDS { c[0] } else { COLOR_ID_BODY },
        normal: [
            I8Norm(n[0] as i8), I8Norm(n[1] as i8),
            I8Norm(n[2] as i8), I8Norm(n[3] as i8),
            ],
    };
    let do_compact = false;

    let mut gpu_verts = Vec::new();
    let (vbuf, slice) = if do_compact {
        info!("\tCompacting...");
        vertices.sort_by_key(|v| v.1);
        //vertices.dedup();
        let mut indices = vec![0; vertices.len()];
        let mut last = vertices[0].1;
        last.2[0] ^= 1; //change something
        let mut v_id = 0;
        for v in vertices.into_iter() {
            if v.1 != last {
                last = v.1;
                v_id = gpu_verts.len() as u16;
                gpu_verts.push(convert(v.1));
            }
            indices[v.0 as usize] = v_id;
        }
        factory.create_vertex_buffer_with_slice(&gpu_verts, &indices[..])
    }else {
        for v in vertices.into_iter() {
            gpu_verts.push(convert(v.1));
        }
        factory.create_vertex_buffer_with_slice(&gpu_verts, ())
    };

    info!("\tGot {} GPU vertices...", gpu_verts.len());
    Mesh {
        slice: slice,
        buffer: vbuf,
    }
}

pub fn load_m3d<I, R, F>(source: &mut I, factory: &mut F) -> Model<R> where
    I: ReadBytesExt,
    R: gfx::Resources,
    F: gfx::traits::FactoryExt<R>,
{
    info!("\tReading the body...");
    let mut model = Model {
        body: load_c3d(source, factory),
        color: [0, 0],
        wheels: Vec::new(),
        debris: Vec::new(),
    };
    let _bounds = [
        source.read_u32::<E>().unwrap(),
        source.read_u32::<E>().unwrap(),
        source.read_u32::<E>().unwrap(),
    ];
    let _max_radius = source.read_u32::<E>().unwrap();
    let num_wheels = source.read_u32::<E>().unwrap();
    let num_debris = source.read_u32::<E>().unwrap();
    model.color = [source.read_u32::<E>().unwrap(), source.read_u32::<E>().unwrap()];
    model.wheels.reserve_exact(num_wheels as usize);
    model.debris.reserve_exact(num_debris as usize);

    info!("\tReading {} wheels...", num_wheels);
    for _ in 0 .. num_wheels {
        let steer = source.read_u32::<E>().unwrap();
		for _ in 0..3 {
			source.read_f64::<E>().unwrap();
		}
        let width = source.read_u32::<E>().unwrap() as f32 * SCALE;
        let radius = source.read_u32::<E>().unwrap() as f32 * SCALE;
        let _bound_index = source.read_u32::<E>().unwrap();
		info!("\tSteer {}, width {}, radius {}", steer, width, radius);
        model.wheels.push(Wheel {
            mesh: if steer != 0 {
                Some(load_c3d(source, factory))
            } else {None},
            steer: steer,
            width: width,
            radius: radius,
        })
    }

    info!("\tReading {} debris...", num_debris);
    for _ in 0 .. num_debris {
        let mesh = load_c3d(source, factory);
        let _phys_bound = load_c3d(source, factory);
        model.debris.push(Debrie {
            mesh: mesh,
        })
    }

    //let _phys_bound = load_c3d(source, factory);
    model
}
<commit_msg>Fixed C3D positions parsing<commit_after>use std::io::{Read};
use byteorder::{LittleEndian as E, ReadBytesExt};
use gfx;
use gfx::format::I8Norm;
use render::{ObjectVertex, NUM_COLOR_IDS, COLOR_ID_BODY};

const SCALE: f32 = 1.0 / 4.0;

pub struct Mesh<R: gfx::Resources> {
    pub slice: gfx::Slice<R>,
    pub buffer: gfx::handle::Buffer<R, ObjectVertex>,
}

pub struct Wheel<R: gfx::Resources> {
    pub mesh: Option<Mesh<R>>,
    pub steer: u32,
    pub width: f32,
    pub radius: f32,
}

pub struct Debrie<R: gfx::Resources> {
    pub mesh: Mesh<R>,
}

pub struct Model<R: gfx::Resources> {
    pub body: Mesh<R>,
    pub color: [u32; 2],
    pub wheels: Vec<Wheel<R>>,
    pub debris: Vec<Debrie<R>>,
}

pub fn load_c3d<I, R, F>(source: &mut I, factory: &mut F) -> Mesh<R> where
    I: ReadBytesExt,
    R: gfx::Resources,
    F: gfx::traits::FactoryExt<R>,
{
    let version = source.read_u32::<E>().unwrap();
    assert_eq!(version, 8);
    let num_positions = source.read_u32::<E>().unwrap();
    let num_normals   = source.read_u32::<E>().unwrap();
    let num_polygons  = source.read_u32::<E>().unwrap();
    let _total_verts  = source.read_u32::<E>().unwrap();

    let coord_max  = [
        source.read_i32::<E>().unwrap() as f32 * SCALE,
        source.read_i32::<E>().unwrap() as f32 * SCALE,
        source.read_i32::<E>().unwrap() as f32 * SCALE,
    ];
    let coord_min  = [
        source.read_i32::<E>().unwrap() as f32 * SCALE,
        source.read_i32::<E>().unwrap() as f32 * SCALE,
        source.read_i32::<E>().unwrap() as f32 * SCALE,
    ];
    info!("\tBound {:?} to {:?}", coord_min, coord_max);
    let _parent_off = [
        source.read_i32::<E>().unwrap(),
        source.read_i32::<E>().unwrap(),
        source.read_i32::<E>().unwrap(),
    ];
    let _max_radius = source.read_u32::<E>().unwrap();
    let _parent_rot = [source.read_u32::<E>().unwrap(), source.read_u32::<E>().unwrap(), source.read_u32::<E>().unwrap()];
	for _ in 0 .. (1+3+9) {
		source.read_f64::<E>().unwrap();
	}

    info!("\tReading {} positions...", num_positions);
    let mut positions = Vec::with_capacity(num_positions as usize);
    for _ in 0 .. num_positions {
        for _ in 0..3 {
            source.read_u32::<E>().unwrap(); //unknown
        }
        let pos = [
            source.read_i8().unwrap(),
            source.read_i8().unwrap(),
            source.read_i8().unwrap(),
        ];
        let _sort_info = source.read_u32::<E>().unwrap();
        positions.push(pos);
    }

    info!("\tReading {} normals...", num_normals);
    let mut normals = Vec::with_capacity(num_normals as usize);
    for _ in 0 .. num_normals {
        let mut norm = [0u8; 4];
        source.read_exact(&mut norm).unwrap();
        let _sort_info = source.read_u32::<E>().unwrap();
        normals.push(norm);
    }

    info!("\tReading {} polygons...", num_polygons);
    let mut vertices = Vec::with_capacity(num_polygons as usize * 3);
    for i in 0 .. num_polygons {
        let num_corners = source.read_u32::<E>().unwrap();
        //assert_eq!(num_corners, 3);
		assert!(3 <= num_corners && num_corners <= 4);
        let _sort_info = source.read_u32::<E>().unwrap();
        let color = [source.read_u32::<E>().unwrap(), source.read_u32::<E>().unwrap()];
        let mut dummy = [0; 4];
        source.read_exact(&mut dummy[..4]).unwrap(); //skip flat normal
        source.read_exact(&mut dummy[..3]).unwrap(); //skip middle point
        for k in 0..num_corners {
            let pid = source.read_u32::<E>().unwrap();
            let nid = source.read_u32::<E>().unwrap();
            let v = (i*3+k, (positions[pid as usize], normals[nid as usize], color));
            vertices.push(v);
        }
    }

	// sorted variable polygons
	for _ in 0 .. 3 {
		for _ in 0 .. num_polygons {
			let _poly_ind = source.read_u32::<E>().unwrap();
		}
	}

    let convert = |(p, n, c): ([i8; 3], [u8; 4], [u32; 2])| ObjectVertex {
        pos: [
            coord_min[0] + (p[0] as f32 + 128.0) * (coord_max[0] - coord_min[0]) / 255.0,
            coord_min[1] + (p[1] as f32 + 128.0) * (coord_max[1] - coord_min[1]) / 255.0,
            coord_min[2] + (p[2] as f32 + 128.0) * (coord_max[2] - coord_min[2]) / 255.0,
            1.0],
        color: if c[0] < NUM_COLOR_IDS { c[0] } else { COLOR_ID_BODY },
        normal: [
            I8Norm(n[0] as i8), I8Norm(n[1] as i8),
            I8Norm(n[2] as i8), I8Norm(n[3] as i8),
            ],
    };
    let do_compact = false;

    let mut gpu_verts = Vec::new();
    let (vbuf, slice) = if do_compact {
        info!("\tCompacting...");
        vertices.sort_by_key(|v| v.1);
        //vertices.dedup();
        let mut indices = vec![0; vertices.len()];
        let mut last = vertices[0].1;
        last.2[0] ^= 1; //change something
        let mut v_id = 0;
        for v in vertices.into_iter() {
            if v.1 != last {
                last = v.1;
                v_id = gpu_verts.len() as u16;
                gpu_verts.push(convert(v.1));
            }
            indices[v.0 as usize] = v_id;
        }
        factory.create_vertex_buffer_with_slice(&gpu_verts, &indices[..])
    }else {
        for v in vertices.into_iter() {
            gpu_verts.push(convert(v.1));
        }
        factory.create_vertex_buffer_with_slice(&gpu_verts, ())
    };

    info!("\tGot {} GPU vertices...", gpu_verts.len());
    Mesh {
        slice: slice,
        buffer: vbuf,
    }
}

pub fn load_m3d<I, R, F>(source: &mut I, factory: &mut F) -> Model<R> where
    I: ReadBytesExt,
    R: gfx::Resources,
    F: gfx::traits::FactoryExt<R>,
{
    info!("\tReading the body...");
    let mut model = Model {
        body: load_c3d(source, factory),
        color: [0, 0],
        wheels: Vec::new(),
        debris: Vec::new(),
    };
    let _bounds = [
        source.read_u32::<E>().unwrap(),
        source.read_u32::<E>().unwrap(),
        source.read_u32::<E>().unwrap(),
    ];
    let _max_radius = source.read_u32::<E>().unwrap();
    let num_wheels = source.read_u32::<E>().unwrap();
    let num_debris = source.read_u32::<E>().unwrap();
    model.color = [source.read_u32::<E>().unwrap(), source.read_u32::<E>().unwrap()];
    model.wheels.reserve_exact(num_wheels as usize);
    model.debris.reserve_exact(num_debris as usize);

    info!("\tReading {} wheels...", num_wheels);
    for _ in 0 .. num_wheels {
        let steer = source.read_u32::<E>().unwrap();
		for _ in 0..3 {
			source.read_f64::<E>().unwrap();
		}
        let width = source.read_u32::<E>().unwrap() as f32 * SCALE;
        let radius = source.read_u32::<E>().unwrap() as f32 * SCALE;
        let _bound_index = source.read_u32::<E>().unwrap();
		info!("\tSteer {}, width {}, radius {}", steer, width, radius);
        model.wheels.push(Wheel {
            mesh: if steer != 0 {
                Some(load_c3d(source, factory))
            } else {None},
            steer: steer,
            width: width,
            radius: radius,
        })
    }

    info!("\tReading {} debris...", num_debris);
    for _ in 0 .. num_debris {
        let mesh = load_c3d(source, factory);
        let _phys_bound = load_c3d(source, factory);
        model.debris.push(Debrie {
            mesh: mesh,
        })
    }

    //let _phys_bound = load_c3d(source, factory);
    model
}
<|endoftext|>


<commit_before>
use std::io::{self, Read, Write, Seek, SeekFrom};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::ops::{Deref, DerefMut};
use std::error;
use std::fmt;
use std::env;
use std;

use super::imp;
use super::util;

/// A named temporary file.
///
/// This variant is *NOT* secure/reliable in the presence of a pathological temporary file cleaner.
///
/// NamedTempFiles are deleted on drop. As rust doesn't guarantee that a struct will ever be
/// dropped, these temporary files will not be deleted on abort, resource leak, early exit, etc.
///
/// Please use TempFile unless you absolutely need a named file.
///
pub struct NamedTempFile(Option<NamedTempFileInner>);

struct NamedTempFileInner {
    file: File,
    path: PathBuf,
}

impl fmt::Debug for NamedTempFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NamedTempFile({:?})", self.0.as_ref().unwrap().path)
    }
}

impl Deref for NamedTempFile {
    type Target = File;
    #[inline]
    fn deref(&self) -> &File {
        &self.inner().file
    }
}

impl DerefMut for NamedTempFile {
    #[inline]
    fn deref_mut(&mut self) -> &mut File {
        &mut self.inner_mut().file
    }
}

/// Error returned when persisting a temporary file fails
#[derive(Debug)]
pub struct PersistError {
    /// The underlying IO error.
    pub error: io::Error,
    /// The temporary file that couldn't be persisted.
    pub file: NamedTempFile,
}

impl From<PersistError> for io::Error {
    #[inline]
    fn from(error: PersistError) -> io::Error {
        error.error
    }
}

impl fmt::Display for PersistError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "failed to persist temporary file: {}", self.error)
    }
}

impl error::Error for PersistError {
    fn description(&self) -> &str {
        "failed to persist temporary file"
    }
    fn cause(&self) -> Option<&error::Error> {
        Some(&self.error)
    }
}

impl NamedTempFile {
    #[inline]
    fn inner(&self) -> &NamedTempFileInner {
        self.0.as_ref().unwrap()
    }

    #[inline]
    fn inner_mut(&mut self) -> &mut NamedTempFileInner {
        self.0.as_mut().unwrap()
    }

    /// Create a new temporary file.
    ///
    /// *SECURITY WARNING:* This will create a temporary file in the default temporary file
    /// directory (platform dependent). These directories are often patrolled by temporary file
    /// cleaners so only use this method if you're *positive* that the temporary file cleaner won't
    /// delete your file.
    ///
    /// Reasons to use this method:
    ///   1. The file has a short lifetime and your temporary file cleaner is sane (doesn't delete
    ///      recently accessed files).
    ///   2. You trust every user on your system (i.e. you are the only user).
    ///   3. You have disabled your system's temporary file cleaner or verified that your system
    ///      doesn't have a temporary file cleaner.
    ///
    /// Reasons not to use this method:
    ///   1. You'll fix it later. No you won't.
    ///   2. You don't care about the security of the temporary file. If none of the "reasons to
    ///      use this method" apply, referring to a temporary file by name may allow an attacker
    ///      to create/overwrite your non-temporary files. There are exceptions but if you don't
    ///      already know them, don't use this method.
    pub fn new() -> io::Result<NamedTempFile> {
        Self::new_in(&env::temp_dir())
    }

    /// Create a new temporary file in the specified directory.
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
        for _ in 0..::NUM_RETRIES {
            let path = dir.as_ref().join(&util::tmpname());
            return match imp::create_named(&path) {
                Ok(file) => Ok(NamedTempFile(Some(NamedTempFileInner { path: path, file: file, }))),
                Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
                Err(e) => Err(e),
            }
        }
        Err(io::Error::new(io::ErrorKind::AlreadyExists,
                           "too many temporary directories already exist"))
    }

    /// Get the temporary file's path.
    ///
    /// *SECURITY WARNING:* Only use this method if you're positive that a temporary file cleaner
    /// won't have deleted your file. Otherwise, the path returned by this method may refer to an
    /// attacker controlled file.
    #[inline]
    pub fn path(&self) -> &Path {
        &self.inner().path
    }

    /// Close and remove the temporary file.
    ///
    /// Use this if you want to detect errors in deleting the file.
    pub fn close(mut self) -> io::Result<()> {
        let NamedTempFileInner { path, file } = self.0.take().unwrap();
        drop(file);
        fs::remove_file(path)
    }

    /// Persist the temporary file at the target path.
    ///
    /// If a file exists at the target path, persist will atomically replace it. If this method
    /// fails, it will return `self` in the resulting PersistError.
    ///
    /// Note: Temporary files cannot be persisted across filesystems.
    ///
    /// *SECURITY WARNING:* Only use this method if you're positive that a temporary file cleaner
    /// won't have deleted your file. Otherwise, you might end up persisting an attacker controlled
    /// file.
    pub fn persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<File, PersistError> {
        match imp::persist(&self.inner().path, new_path.as_ref()) {
            Ok(_) => Ok(self.0.take().unwrap().file),
            Err(e) => Err(PersistError { file: self, error: e }),
        }
    }
}

impl Drop for NamedTempFile {
    fn drop(&mut self) {
        if let Some(NamedTempFileInner { file, path }) = self.0.take() {
            drop(file);
            let _ = fs::remove_file(path);
        }
    }
}

impl Read for NamedTempFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }
}

impl Write for NamedTempFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        (**self).write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        (**self).flush()
    }
}

impl Seek for NamedTempFile {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        (**self).seek(pos)
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for NamedTempFile {
    #[inline]
    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
        (**self).as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for NamedTempFile {
    #[inline]
    fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
        (**self).as_raw_handle()
    }
}
<commit_msg>impl From for converting PersistError to NamedTempFile<commit_after>
use std::io::{self, Read, Write, Seek, SeekFrom};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::ops::{Deref, DerefMut};
use std::error;
use std::fmt;
use std::env;
use std;

use super::imp;
use super::util;

/// A named temporary file.
///
/// This variant is *NOT* secure/reliable in the presence of a pathological temporary file cleaner.
///
/// NamedTempFiles are deleted on drop. As rust doesn't guarantee that a struct will ever be
/// dropped, these temporary files will not be deleted on abort, resource leak, early exit, etc.
///
/// Please use TempFile unless you absolutely need a named file.
///
pub struct NamedTempFile(Option<NamedTempFileInner>);

struct NamedTempFileInner {
    file: File,
    path: PathBuf,
}

impl fmt::Debug for NamedTempFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NamedTempFile({:?})", self.0.as_ref().unwrap().path)
    }
}

impl Deref for NamedTempFile {
    type Target = File;
    #[inline]
    fn deref(&self) -> &File {
        &self.inner().file
    }
}

impl DerefMut for NamedTempFile {
    #[inline]
    fn deref_mut(&mut self) -> &mut File {
        &mut self.inner_mut().file
    }
}

/// Error returned when persisting a temporary file fails
#[derive(Debug)]
pub struct PersistError {
    /// The underlying IO error.
    pub error: io::Error,
    /// The temporary file that couldn't be persisted.
    pub file: NamedTempFile,
}

impl From<PersistError> for io::Error {
    #[inline]
    fn from(error: PersistError) -> io::Error {
        error.error
    }
}

impl From<PersistError> for NamedTempFile {
    #[inline]
    fn from(error: PersistError) -> NamedTempFile {
        error.file
    }
}

impl fmt::Display for PersistError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "failed to persist temporary file: {}", self.error)
    }
}

impl error::Error for PersistError {
    fn description(&self) -> &str {
        "failed to persist temporary file"
    }
    fn cause(&self) -> Option<&error::Error> {
        Some(&self.error)
    }
}

impl NamedTempFile {
    #[inline]
    fn inner(&self) -> &NamedTempFileInner {
        self.0.as_ref().unwrap()
    }

    #[inline]
    fn inner_mut(&mut self) -> &mut NamedTempFileInner {
        self.0.as_mut().unwrap()
    }

    /// Create a new temporary file.
    ///
    /// *SECURITY WARNING:* This will create a temporary file in the default temporary file
    /// directory (platform dependent). These directories are often patrolled by temporary file
    /// cleaners so only use this method if you're *positive* that the temporary file cleaner won't
    /// delete your file.
    ///
    /// Reasons to use this method:
    ///   1. The file has a short lifetime and your temporary file cleaner is sane (doesn't delete
    ///      recently accessed files).
    ///   2. You trust every user on your system (i.e. you are the only user).
    ///   3. You have disabled your system's temporary file cleaner or verified that your system
    ///      doesn't have a temporary file cleaner.
    ///
    /// Reasons not to use this method:
    ///   1. You'll fix it later. No you won't.
    ///   2. You don't care about the security of the temporary file. If none of the "reasons to
    ///      use this method" apply, referring to a temporary file by name may allow an attacker
    ///      to create/overwrite your non-temporary files. There are exceptions but if you don't
    ///      already know them, don't use this method.
    pub fn new() -> io::Result<NamedTempFile> {
        Self::new_in(&env::temp_dir())
    }

    /// Create a new temporary file in the specified directory.
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
        for _ in 0..::NUM_RETRIES {
            let path = dir.as_ref().join(&util::tmpname());
            return match imp::create_named(&path) {
                Ok(file) => Ok(NamedTempFile(Some(NamedTempFileInner { path: path, file: file, }))),
                Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
                Err(e) => Err(e),
            }
        }
        Err(io::Error::new(io::ErrorKind::AlreadyExists,
                           "too many temporary directories already exist"))
    }

    /// Get the temporary file's path.
    ///
    /// *SECURITY WARNING:* Only use this method if you're positive that a temporary file cleaner
    /// won't have deleted your file. Otherwise, the path returned by this method may refer to an
    /// attacker controlled file.
    #[inline]
    pub fn path(&self) -> &Path {
        &self.inner().path
    }

    /// Close and remove the temporary file.
    ///
    /// Use this if you want to detect errors in deleting the file.
    pub fn close(mut self) -> io::Result<()> {
        let NamedTempFileInner { path, file } = self.0.take().unwrap();
        drop(file);
        fs::remove_file(path)
    }

    /// Persist the temporary file at the target path.
    ///
    /// If a file exists at the target path, persist will atomically replace it. If this method
    /// fails, it will return `self` in the resulting PersistError.
    ///
    /// Note: Temporary files cannot be persisted across filesystems.
    ///
    /// *SECURITY WARNING:* Only use this method if you're positive that a temporary file cleaner
    /// won't have deleted your file. Otherwise, you might end up persisting an attacker controlled
    /// file.
    pub fn persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<File, PersistError> {
        match imp::persist(&self.inner().path, new_path.as_ref()) {
            Ok(_) => Ok(self.0.take().unwrap().file),
            Err(e) => Err(PersistError { file: self, error: e }),
        }
    }
}

impl Drop for NamedTempFile {
    fn drop(&mut self) {
        if let Some(NamedTempFileInner { file, path }) = self.0.take() {
            drop(file);
            let _ = fs::remove_file(path);
        }
    }
}

impl Read for NamedTempFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }
}

impl Write for NamedTempFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        (**self).write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        (**self).flush()
    }
}

impl Seek for NamedTempFile {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        (**self).seek(pos)
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for NamedTempFile {
    #[inline]
    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
        (**self).as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for NamedTempFile {
    #[inline]
    fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
        (**self).as_raw_handle()
    }
}
<|endoftext|>


<commit_before>// https://github.com/serde-rs/serde/issues/927

use std::collections::HashMap;

extern crate yaml_rust;
extern crate argparse;
#[macro_use] extern crate log;
#[macro_use] extern crate from_variants;

extern crate serde;
extern crate serde_json;
extern crate serde_yaml;

#[macro_use] extern crate serde_derive;

#[derive(Clone, Serialize, Deserialize)]
enum ArgValue {
    None,
    Str(String),
    Bool(bool),
    Byte(u8),
    Int16(i16),
    Int32(i32),
    Int64(i64),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),
    Double(f64),
}

#[derive(Serialize, Deserialize)]
enum DbusMessageType {
    Method,
    Signal,
}

type NamedArgs<'a> = HashMap<&'a str, ArgValue>;

#[derive(Serialize, Deserialize)]
struct DbusMessage<'a> {
    api_name: String,
    dbus_name: String,
    message_type: DbusMessageType,
    #[serde(borrow)]
    args: NamedArgs<'a>,
}

#[derive(Serialize, Deserialize)]
struct DbusMessageRouting<'a>(String, String, String, #[serde(borrow)] Vec<DbusMessage<'a>>);

#[derive(Serialize, Deserialize)]
struct ConfYaml<'a>(#[serde(borrow)] Vec<DbusMessageRouting<'a>>);

#[derive(Serialize, Deserialize)]
struct ClientRequest<'a>(DbusMessageType, String, #[serde(borrow)] NamedArgs<'a>);

#[derive(Serialize, Deserialize)]
struct ClientRequestBody<'a>(DbusMessageType, #[serde(borrow)] NamedArgs<'a>);

type CRequest<'a> = HashMap<&'a str, ClientRequestBody<'a>>;

fn main()
{
    let conf = vec![
        DbusMessageRouting(
            "com.a.b.servicetest".to_string(),
            "/com/a/b/servicetest".to_string(),
            "com.a.b.IServiceTest".to_string(),
            vec![ DbusMessage { api_name: "api_name".to_string(),
                                dbus_name: "dbus_name".to_string(),
                                message_type: DbusMessageType::Method,
                                args: [
                                    ("param1", ArgValue::Str("Hi".to_string())),
                                    ("param2", ArgValue::Bool(true)),
                                    ("param3", ArgValue::Int64(17i64)),
                                    ("param4", ArgValue::Double(2.718281828f64)),
                                ].iter().cloned().collect()
                              }
            ]
        )
    ];

    let s = serde_yaml::to_string(&conf).unwrap();
    println!("s : {}", s);

    let r = ClientRequest(DbusMessageType::Method, "api_name".to_string(), [
                                        ("param1", ArgValue::Str("Hi".to_string())),
                                        ("param2", ArgValue::Bool(true)),
                                        ("param3", ArgValue::Int64(17i64)),
                                        ("param4", ArgValue::Double(2.718281828f64)),
                                ].iter().cloned().collect()
                          );
    let rs = serde_json::to_string(&r).unwrap();
    println!("rs : {}", rs);

    let rb = ClientRequestBody(DbusMessageType::Method, [
                                        ("param1", ArgValue::Str("Hi".to_string())),
                                        ("param2", ArgValue::Bool(true)),
                                        ("param3", ArgValue::Int64(17i64)),
                                        ("param4", ArgValue::Double(2.718281828f64)),
                                ].iter().cloned().collect()
                          );

    let mut a_request: CRequest = HashMap::new();
    a_request.insert("api_name", rb);

    let rsq = serde_json::to_string(&a_request).unwrap();
    println!("rsq : {}", rsq);

    let de: CRequest = serde_json::from_str(&rsq).expect("json deserialization error");

    let rsq2 = serde_json::to_string(&de).expect("json serialization error");
    println!("rsq2 : {}", rsq2);

    for key in de.keys() {
        println!("key {}", key);
    }
    println!("key[0] : {}", de.keys().nth(0).unwrap());

}
<commit_msg>slightly changed format for request.<commit_after>// https://github.com/serde-rs/serde/issues/927

use std::collections::HashMap;

extern crate yaml_rust;
extern crate argparse;
#[macro_use] extern crate log;
#[macro_use] extern crate from_variants;

extern crate serde;
extern crate serde_json;
extern crate serde_yaml;

#[macro_use] extern crate serde_derive;

#[derive(Clone, Serialize, Deserialize)]
enum ArgValue {
    None,
    Str(String),
    Bool(bool),
    Byte(u8),
    Int16(i16),
    Int32(i32),
    Int64(i64),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),
    Double(f64),
}

#[derive(Serialize, Deserialize)]
enum DbusMessageType {
    Method,
    Signal,
}

type NamedArgs<'a> = HashMap<&'a str, ArgValue>;

#[derive(Serialize, Deserialize)]
struct DbusMessage<'a> {
    api_name: String,
    dbus_name: String,
    message_type: DbusMessageType,
    #[serde(borrow)]
    args: NamedArgs<'a>,
}

#[derive(Serialize, Deserialize)]
struct DbusMessageRouting<'a>(String, String, String, #[serde(borrow)] Vec<DbusMessage<'a>>);

#[derive(Serialize, Deserialize)]
struct ConfYaml<'a>(#[serde(borrow)] Vec<DbusMessageRouting<'a>>);

#[derive(Serialize, Deserialize)]
struct ClientRequest<'a> {
    tp: DbusMessageType,
    name: String,
    #[serde(borrow)]
    args: NamedArgs<'a>,
}

#[derive(Serialize, Deserialize)]
struct ClientRequestBody<'a>(DbusMessageType, #[serde(borrow)] NamedArgs<'a>);

type CRequest<'a> = HashMap<&'a str, ClientRequestBody<'a>>;

fn main()
{
    let conf = vec![
        DbusMessageRouting(
            "com.a.b.servicetest".to_string(),
            "/com/a/b/servicetest".to_string(),
            "com.a.b.IServiceTest".to_string(),
            vec![ DbusMessage { api_name: "api_name".to_string(),
                                dbus_name: "dbus_name".to_string(),
                                message_type: DbusMessageType::Method,
                                args: [
                                    ("param1", ArgValue::Str("Hi".to_string())),
                                    ("param2", ArgValue::Bool(true)),
                                    ("param3", ArgValue::Int64(17i64)),
                                    ("param4", ArgValue::Double(2.718281828f64)),
                                ].iter().cloned().collect()
                              }
            ]
        )
    ];

    let s = serde_yaml::to_string(&conf).unwrap();
    println!("s : {}", s);

    let r = ClientRequest { tp: DbusMessageType::Method, nm: "api_name".to_string(), args:
                                [       ("param1", ArgValue::Str("Hi".to_string())),
                                        ("param2", ArgValue::Bool(true)),
                                        ("param3", ArgValue::Int64(17i64)),
                                        ("param4", ArgValue::Double(2.718281828f64)),
                                ].iter().cloned().collect()
                          };
    let rs = serde_json::to_string(&r).unwrap();
    println!("rs : {}", rs);

    let rb = ClientRequestBody(DbusMessageType::Method, [
                                        ("param1", ArgValue::Str("Hi".to_string())),
                                        ("param2", ArgValue::Bool(true)),
                                        ("param3", ArgValue::Int64(17i64)),
                                        ("param4", ArgValue::Double(2.718281828f64)),
                                ].iter().cloned().collect()
                          );

    let mut a_request: CRequest = HashMap::new();
    a_request.insert("api_name", rb);

    let rsq = serde_json::to_string(&a_request).unwrap();
    println!("rsq : {}", rsq);

    let de: CRequest = serde_json::from_str(&rsq).expect("json deserialization error");

    let rsq2 = serde_json::to_string(&de).expect("json serialization error");
    println!("rsq2 : {}", rsq2);

    for key in de.keys() {
        println!("key {}", key);
    }
    println!("key[0] : {}", de.keys().nth(0).unwrap());

}
<|endoftext|>