<commit_before>extern crate specs;
extern crate futures;
extern crate serde;
extern crate serde_json;
extern crate websocket_server;

use self::specs::{Join, ReadStorage, WriteStorage, System, Entities, EntitiesRes};
use self::futures::{Future, Sink};
use self::websocket_server::Message;
use self::serde::ser::Serialize;

use model::comp::{Pos, Vel, Connect, Disconnect, Player as PlayerComp, Actor};
use model::client::{Message as ClientMessage, OpCode};

use std::collections::HashMap;
use std::fmt::Debug;

pub struct Sending;
impl<'a> System<'a> for Sending {
    #[allow(type_complexity)]
    type SystemData = (ReadStorage<'a, Pos>,
     ReadStorage<'a, Vel>,
     ReadStorage<'a, PlayerComp>,
     ReadStorage<'a, Actor>,
     WriteStorage<'a, Connect>,
     ReadStorage<'a, Disconnect>,
     Entities<'a>);

    fn run(
        &mut self,
        (pos, vel, player, actor, mut connect, disconnect, entities): Self::SystemData,
    ) {

        handle_new_connections(&player, &*entities, &actor, &mut connect);
        handle_disconnects(&player, &actor, &disconnect);

        send_world_updates(&player, &actor, &pos, &vel);
    }
}

fn send<T>(player: &PlayerComp, msg: &ClientMessage<T>)
where
    T: Serialize,
{
    let msg = serde_json::to_string(&msg).unwrap();
    let send_channel = player.send_channel.clone();
    send_channel.send(Message::Text(msg)).wait().expect(
        "Failed to send message",
    );
}

fn serialize<T>(t: &T) -> String
where
    T: Serialize + Debug,
{
    serde_json::to_string(t).expect(&format!("Failed to serialize object {:?}", t))
}

fn handle_new_connections(player: &ReadStorage<PlayerComp>, entities: &EntitiesRes, actor: &ReadStorage<Actor>, connect: &mut WriteStorage<Connect>) {
    let mut new_connections = Vec::new();
    for (new_player, entity, new_actor, _) in
        (player, entities, actor, &mut *connect).join()
        {
            new_connections.push((entity.clone(), new_actor.clone()));
            let mut payload = Vec::new();
            payload.push(serialize(&new_actor.id));
            let mut id_actor_kind = HashMap::new();
            for actor in (&actor).join() {
                id_actor_kind.insert(actor.id, actor.kind.clone());
            }
            payload.push(serialize(&id_actor_kind));
            let greeting = ClientMessage {
                opcode: OpCode::Greeting,
                payload: payload,
            };
            send(new_player, &greeting);
        }

    for new_connection in new_connections {
        let (new_entity, new_actor) = new_connection;
        connect.remove(new_entity);
        let connection = ClientMessage {
            opcode: OpCode::Connect,
            payload: new_actor.clone(),
        };
        for (player, entity) in (player, entities).join() {
            if entity != new_entity {
                send(player, &connection);
            }
        }
    }
}

fn handle_disconnects(player: &ReadStorage<PlayerComp>, actor: &ReadStorage<Actor>, disconnect: &ReadStorage<Disconnect>) {
    for (actor, _) in (actor, disconnect).join() {
        let disconnect = ClientMessage {
            opcode: OpCode::Disconnect,
            payload: actor.id.clone(),
        };
        for player in (player).join() {
            send(player, &disconnect);
        }
    }

}

fn send_world_updates(player: &ReadStorage<PlayerComp>, actor: &ReadStorage<Actor>, pos: &ReadStorage<Pos>, vel: &ReadStorage<Vel>) {
    let mut serialized_actors = HashMap::new();
    for actor in (actor).join() {
        serialized_actors.insert(actor.id, HashMap::new());
    }

    for (pos, vel, actor) in (pos, vel, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.insert("pos", serialize(&pos));
        actor.insert("vel", serialize(&vel));
    }

    for (player, actor) in (player, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.insert("delay", serialize(&player.delay));
    }
    let world_state = ClientMessage {
        opcode: OpCode::WorldUpdate,
        payload: serialized_actors,
    };
    for player in (player).join() {
        send(player, &world_state);
    }
}<commit_msg>Core: Run rustfmt<commit_after>extern crate specs;
extern crate futures;
extern crate serde;
extern crate serde_json;
extern crate websocket_server;

use self::specs::{Join, ReadStorage, WriteStorage, System, Entities, EntitiesRes};
use self::futures::{Future, Sink};
use self::websocket_server::Message;
use self::serde::ser::Serialize;

use model::comp::{Pos, Vel, Connect, Disconnect, Player as PlayerComp, Actor};
use model::client::{Message as ClientMessage, OpCode};

use std::collections::HashMap;
use std::fmt::Debug;

pub struct Sending;
impl<'a> System<'a> for Sending {
    #[allow(type_complexity)]
    type SystemData = (ReadStorage<'a, Pos>,
     ReadStorage<'a, Vel>,
     ReadStorage<'a, PlayerComp>,
     ReadStorage<'a, Actor>,
     WriteStorage<'a, Connect>,
     ReadStorage<'a, Disconnect>,
     Entities<'a>);

    fn run(
        &mut self,
        (pos, vel, player, actor, mut connect, disconnect, entities): Self::SystemData,
    ) {

        handle_new_connections(&player, &*entities, &actor, &mut connect);
        handle_disconnects(&player, &actor, &disconnect);

        send_world_updates(&player, &actor, &pos, &vel);
    }
}

fn send<T>(player: &PlayerComp, msg: &ClientMessage<T>)
where
    T: Serialize,
{
    let msg = serde_json::to_string(&msg).unwrap();
    let send_channel = player.send_channel.clone();
    send_channel.send(Message::Text(msg)).wait().expect(
        "Failed to send message",
    );
}

fn serialize<T>(t: &T) -> String
where
    T: Serialize + Debug,
{
    serde_json::to_string(t).expect(&format!("Failed to serialize object {:?}", t))
}

fn handle_new_connections(
    player: &ReadStorage<PlayerComp>,
    entities: &EntitiesRes,
    actor: &ReadStorage<Actor>,
    connect: &mut WriteStorage<Connect>,
) {
    let mut new_connections = Vec::new();
    for (new_player, entity, new_actor, _) in (player, entities, actor, &mut *connect).join() {
        new_connections.push((entity.clone(), new_actor.clone()));
        let mut payload = Vec::new();
        payload.push(serialize(&new_actor.id));
        let mut id_actor_kind = HashMap::new();
        for actor in (&actor).join() {
            id_actor_kind.insert(actor.id, actor.kind.clone());
        }
        payload.push(serialize(&id_actor_kind));
        let greeting = ClientMessage {
            opcode: OpCode::Greeting,
            payload: payload,
        };
        send(new_player, &greeting);
    }

    for new_connection in new_connections {
        let (new_entity, new_actor) = new_connection;
        connect.remove(new_entity);
        let connection = ClientMessage {
            opcode: OpCode::Connect,
            payload: new_actor.clone(),
        };
        for (player, entity) in (player, entities).join() {
            if entity != new_entity {
                send(player, &connection);
            }
        }
    }
}

fn handle_disconnects(
    player: &ReadStorage<PlayerComp>,
    actor: &ReadStorage<Actor>,
    disconnect: &ReadStorage<Disconnect>,
) {
    for (actor, _) in (actor, disconnect).join() {
        let disconnect = ClientMessage {
            opcode: OpCode::Disconnect,
            payload: actor.id.clone(),
        };
        for player in (player).join() {
            send(player, &disconnect);
        }
    }

}

fn send_world_updates(
    player: &ReadStorage<PlayerComp>,
    actor: &ReadStorage<Actor>,
    pos: &ReadStorage<Pos>,
    vel: &ReadStorage<Vel>,
) {
    let mut serialized_actors = HashMap::new();
    for actor in (actor).join() {
        serialized_actors.insert(actor.id, HashMap::new());
    }

    for (pos, vel, actor) in (pos, vel, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.insert("pos", serialize(&pos));
        actor.insert("vel", serialize(&vel));
    }

    for (player, actor) in (player, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.insert("delay", serialize(&player.delay));
    }
    let world_state = ClientMessage {
        opcode: OpCode::WorldUpdate,
        payload: serialized_actors,
    };
    for player in (player).join() {
        send(player, &world_state);
    }
}
<|endoftext|>


<commit_before>extern crate specs;
extern crate futures;
extern crate serde;
extern crate serde_json;
extern crate websocket_server;

use self::specs::{Join, ReadStorage, WriteStorage, System, Entities};
use self::futures::{Future, Sink};
use self::websocket_server::Message;
use self::serde::ser::Serialize;

use model::comp::{Pos, Vel, Connect, Disconnect, Player as PlayerComp, Actor};
use model::client::{Message as ClientMessage, OpCode};

use std::collections::HashMap;
use std::fmt::Debug;

pub struct Sending;
impl<'a> System<'a> for Sending {
    #[allow(type_complexity)]
    type SystemData = (ReadStorage<'a, Pos>,
     ReadStorage<'a, Vel>,
     ReadStorage<'a, PlayerComp>,
     ReadStorage<'a, Actor>,
     WriteStorage<'a, Connect>,
     ReadStorage<'a, Disconnect>,
     Entities<'a>);

    fn run(
        &mut self,
        (pos, vel, player, actor, mut connect, disconnect, entities): Self::SystemData,
    ) {
        let mut serialized_actors = HashMap::new();
        for actor in (&actor).join() {
            serialized_actors.insert(actor.id, HashMap::new());
        }

        for (pos, vel, actor) in (&pos, &vel, &actor).join() {
            let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
            actor.insert("pos", serialize(&pos));
            actor.insert("vel", serialize(&vel));
        }

        for (player, actor) in (&player, &actor).join() {
            let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
            actor.insert("delay", serialize(&player.delay));
        }

        let mut new_connections = Vec::new();
        for (new_player, entity, new_actor, _) in
            (&player, &*entities, &actor, &mut connect).join()
        {
            new_connections.push((entity.clone(), new_actor.clone()));
            let mut payload = Vec::new();
            payload.push(serialize(&new_actor.id));
            let mut id_actor_kind = HashMap::new();
            for actor in (&actor).join() {
                id_actor_kind.insert(actor.id, actor.kind.clone());
            }
            payload.push(serialize(&id_actor_kind));
            let greeting = ClientMessage {
                opcode: OpCode::Greeting,
                payload: payload,
            };
            send(new_player, &greeting);
        }

        for new_connection in new_connections {
            let (new_entity, new_actor) = new_connection;
            connect.remove(new_entity);
            let connection = ClientMessage {
                opcode: OpCode::Connect,
                payload: new_actor.clone(),
            };
            for (player, entity) in (&player, &*entities).join() {
                if entity != new_entity {
                    send(player, &connection);
                }
            }
        }

        for (actor, _) in (&actor, &disconnect).join() {
            let disconnect = ClientMessage {
                opcode: OpCode::Disconnect,
                payload: actor.id.clone(),
            };
            for player in (&player).join() {
                send(player, &disconnect);
            }
        }

        let world_state = ClientMessage {
            opcode: OpCode::WorldUpdate,
            payload: serialized_actors,
        };
        for player in (&player).join() {
            send(player, &world_state);
        }
    }
}

fn send<T>(player: &PlayerComp, msg: &ClientMessage<T>)
where
    T: Serialize,
{
    let msg = serde_json::to_string(&msg).unwrap();
    let send_channel = player.send_channel.clone();
    send_channel.send(Message::Text(msg)).wait().expect(
        "Failed to send message",
    );
}

fn serialize<T>(t: &T) -> String
where
    T: Serialize + Debug,
{
    serde_json::to_string(t).expect(&format!("Failed to serialize object {:?}", t))
}
<commit_msg>Core: Refactor functionality into own functions<commit_after>extern crate specs;
extern crate futures;
extern crate serde;
extern crate serde_json;
extern crate websocket_server;

use self::specs::{Join, ReadStorage, WriteStorage, System, Entities};
use self::futures::{Future, Sink};
use self::websocket_server::Message;
use self::serde::ser::Serialize;

use model::comp::{Pos, Vel, Connect, Disconnect, Player as PlayerComp, Actor};
use model::client::{Message as ClientMessage, OpCode};

use std::collections::HashMap;
use std::fmt::Debug;

pub struct Sending;
impl<'a> System<'a> for Sending {
    #[allow(type_complexity)]
    type SystemData = (ReadStorage<'a, Pos>,
     ReadStorage<'a, Vel>,
     ReadStorage<'a, PlayerComp>,
     ReadStorage<'a, Actor>,
     WriteStorage<'a, Connect>,
     ReadStorage<'a, Disconnect>,
     Entities<'a>);

    fn run(
        &mut self,
        (pos, vel, player, actor, mut connect, disconnect, entities): Self::SystemData,
    ) {

        handle_new_connections(&player, &entities, &actor, &mut connect);
        handle_disconnects(&player, &actor, &disconnect);

        send_world_updates(&player, &actor, &pos, &vel);
    }
}

fn send<T>(player: &PlayerComp, msg: &ClientMessage<T>)
where
    T: Serialize,
{
    let msg = serde_json::to_string(&msg).unwrap();
    let send_channel = player.send_channel.clone();
    send_channel.send(Message::Text(msg)).wait().expect(
        "Failed to send message",
    );
}

fn serialize<T>(t: &T) -> String
where
    T: Serialize + Debug,
{
    serde_json::to_string(t).expect(&format!("Failed to serialize object {:?}", t))
}

fn handle_new_connections(player: &ReadStorage<PlayerComp>, entities: &Entities, actor: &ReadStorage<Actor>, connect: &mut WriteStorage<Connect>) {
    let mut new_connections = Vec::new();
    for (new_player, entity, new_actor, _) in
        (player, &**entities, actor, &mut *connect).join()
        {
            new_connections.push((entity.clone(), new_actor.clone()));
            let mut payload = Vec::new();
            payload.push(serialize(&new_actor.id));
            let mut id_actor_kind = HashMap::new();
            for actor in (&actor).join() {
                id_actor_kind.insert(actor.id, actor.kind.clone());
            }
            payload.push(serialize(&id_actor_kind));
            let greeting = ClientMessage {
                opcode: OpCode::Greeting,
                payload: payload,
            };
            send(new_player, &greeting);
        }

    for new_connection in new_connections {
        let (new_entity, new_actor) = new_connection;
        connect.remove(new_entity);
        let connection = ClientMessage {
            opcode: OpCode::Connect,
            payload: new_actor.clone(),
        };
        for (player, entity) in (player, &**entities).join() {
            if entity != new_entity {
                send(player, &connection);
            }
        }
    }
}

fn handle_disconnects(player: &ReadStorage<PlayerComp>, actor: &ReadStorage<Actor>, disconnect: &ReadStorage<Disconnect>) {
    for (actor, _) in (actor, disconnect).join() {
        let disconnect = ClientMessage {
            opcode: OpCode::Disconnect,
            payload: actor.id.clone(),
        };
        for player in (player).join() {
            send(player, &disconnect);
        }
    }

}

fn send_world_updates(player: &ReadStorage<PlayerComp>, actor: &ReadStorage<Actor>, pos: &ReadStorage<Pos>, vel: &ReadStorage<Vel>) {
    let mut serialized_actors = HashMap::new();
    for actor in (actor).join() {
        serialized_actors.insert(actor.id, HashMap::new());
    }

    for (pos, vel, actor) in (pos, vel, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.insert("pos", serialize(&pos));
        actor.insert("vel", serialize(&vel));
    }

    for (player, actor) in (player, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.insert("delay", serialize(&player.delay));
    }
    let world_state = ClientMessage {
        opcode: OpCode::WorldUpdate,
        payload: serialized_actors,
    };
    for player in (player).join() {
        send(player, &world_state);
    }
}<|endoftext|>


<commit_before>//! The nodes.

use std::collections::HashMap;
use std::fmt;

mod comment;
mod text;
mod value;

pub use self::comment::Comment;
pub use self::text::Text;
pub use self::value::Value;

/// Attributes.
pub type Attributes = HashMap<String, Value>;

/// Child nodes.
pub type Children = Vec<Box<dyn Node>>;

/// A node.
pub trait Node: 'static + fmt::Debug + fmt::Display + NodeClone {
    /// Append a child node.
    fn append<T>(&mut self, _: T)
    where
        Self: Sized,
        T: Node;

    /// Assign an attribute.
    fn assign<T, U>(&mut self, _: T, _: U)
    where
        Self: Sized,
        T: Into<String>,
        U: Into<Value>;
}

#[doc(hidden)]
pub trait NodeClone {
    fn clone(&self) -> Box<dyn Node>;
}

impl<T> NodeClone for T
where
    T: Node + Clone,
{
    #[inline]
    fn clone(&self) -> Box<dyn Node> {
        Box::new(Clone::clone(self))
    }
}

impl Clone for Box<dyn Node> {
    #[inline]
    fn clone(&self) -> Self {
        NodeClone::clone(&**self)
    }
}

macro_rules! node(
    ($struct_name:ident::$field_name:ident) => (
        impl $struct_name {
            /// Append a node.
            pub fn add<T>(mut self, node: T) -> Self
            where
                T: crate::node::Node,
            {
                crate::node::Node::append(&mut self, node);
                self
            }

            /// Assign an attribute.
            #[inline]
            pub fn set<T, U>(mut self, name: T, value: U) -> Self
            where
                T: Into<String>,
                U: Into<crate::node::Value>,
            {
                crate::node::Node::assign(&mut self, name, value);
                self
            }
        }

        impl crate::node::Node for $struct_name {
            #[inline]
            fn append<T>(&mut self, node: T)
            where
                T: crate::node::Node
            {
                self.$field_name.append(node);
            }

            #[inline]
            fn assign<T, U>(&mut self, name: T, value: U)
            where
                T: Into<String>,
                U: Into<crate::node::Value>,
            {
                self.$field_name.assign(name, value);
            }
        }

        impl ::std::fmt::Display for $struct_name {
            #[inline]
            fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                self.$field_name.fmt(formatter)
            }
        }
    );
);

pub mod element;
<commit_msg>Make a cosmetic adjustment<commit_after>//! The nodes.

use std::collections::HashMap;
use std::fmt;

mod comment;
mod text;
mod value;

pub use self::comment::Comment;
pub use self::text::Text;
pub use self::value::Value;

/// Attributes.
pub type Attributes = HashMap<String, Value>;

/// Child nodes.
pub type Children = Vec<Box<dyn Node>>;

/// A node.
pub trait Node: 'static + fmt::Debug + fmt::Display + NodeClone {
    /// Append a child node.
    fn append<T>(&mut self, _: T)
    where
        Self: Sized,
        T: Node;

    /// Assign an attribute.
    fn assign<T, U>(&mut self, _: T, _: U)
    where
        Self: Sized,
        T: Into<String>,
        U: Into<Value>;
}

#[doc(hidden)]
pub trait NodeClone {
    fn clone(&self) -> Box<dyn Node>;
}

impl<T> NodeClone for T
where
    T: Node + Clone,
{
    #[inline]
    fn clone(&self) -> Box<dyn Node> {
        Box::new(Clone::clone(self))
    }
}

impl Clone for Box<dyn Node> {
    #[inline]
    fn clone(&self) -> Self {
        NodeClone::clone(&**self)
    }
}

macro_rules! node(
    ($struct_name:ident::$field_name:ident) => (
        impl $struct_name {
            /// Append a node.
            pub fn add<T>(mut self, node: T) -> Self
            where
                T: crate::node::Node,
            {
                crate::node::Node::append(&mut self, node);
                self
            }

            /// Assign an attribute.
            #[inline]
            pub fn set<T, U>(mut self, name: T, value: U) -> Self
            where
                T: Into<String>,
                U: Into<crate::node::Value>,
            {
                crate::node::Node::assign(&mut self, name, value);
                self
            }
        }

        impl crate::node::Node for $struct_name {
            #[inline]
            fn append<T>(&mut self, node: T)
            where
                T: crate::node::Node,
            {
                self.$field_name.append(node);
            }

            #[inline]
            fn assign<T, U>(&mut self, name: T, value: U)
            where
                T: Into<String>,
                U: Into<crate::node::Value>,
            {
                self.$field_name.assign(name, value);
            }
        }

        impl ::std::fmt::Display for $struct_name {
            #[inline]
            fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                self.$field_name.fmt(formatter)
            }
        }
    );
);

pub mod element;
<|endoftext|>


<commit_before>#![feature(rustc_private)]
#![deny(warnings)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use std::any::Any;

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        Box::new(CodegenResults {
            modules: vec![],
            allocator_module: None,
            metadata_module: None,
            metadata,
            linker_info: LinkerInfo::new(tcx, "fake_target_cpu".to_string()),
            crate_info: CrateInfo::new(tcx),
        })
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let codegen_results = ongoing_codegen
            .downcast::<CodegenResults>()
            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
        Ok((*codegen_results, FxHashMap::default()))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name = codegen_results.crate_info.local_crate_name;
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<commit_msg>Fix test<commit_after>#![feature(rustc_private)]
#![deny(warnings)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use std::any::Any;

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        Box::new(CodegenResults {
            modules: vec![],
            allocator_module: None,
            metadata_module: None,
            metadata,
            crate_info: CrateInfo::new(tcx, "fake_target_cpu".to_string()),
        })
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let codegen_results = ongoing_codegen
            .downcast::<CodegenResults>()
            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
        Ok((*codegen_results, FxHashMap::default()))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name = codegen_results.crate_info.local_crate_name;
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<|endoftext|>


<commit_before>// FIXME: add the support of transient objects

use notify::{self, RecommendedWatcher, Watcher};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use time::precise_time_s;

use id::Id;
use model::Model;
use object::Object;
use shader::Program;

/// Class of types that can be loaded.
pub trait Load<'a>: Sized {
  /// Arguments passed at loading.
  type Args;

  // TODO: see whether we can use something with From/Into instead, so that we can use lambdas.
  fn load<P>(path: P, cache: &mut Cache<'a>, args: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path>;
}

/// Class of types that can be reloaded.
///
/// The idea is to simply recover the arguments used in `Load::load`.
pub trait Reload<'a>: Load<'a> {
  fn reload_args(&self) -> Self::Args;
}

/// Default implementation for types which are loaded without any arguments.
impl<'a, T> Reload<'a> for T where T: Load<'a, Args=()> {
  fn reload_args(&self) -> Self::Args {
    ()
  }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

type Timestamp = f64;

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME: Timestamp = 0.1; // 100ms

struct CacheBlock<'a, T> where T: 'a {
  data: Vec<(T, PathBuf, (Receiver<Timestamp>, f64))>,
  ids: HashMap<String, Id<'a, T>>,
}

impl<'a, T> CacheBlock<'a, T> {
  pub fn new() -> Self {
    CacheBlock {
      data: Vec::new(),
      ids: HashMap::new(),
    }
  }
}

macro_rules! cache_struct {
  ($l:tt, $($n:ident : $t:ty),*) => {
    pub struct Cache<$l> {
      senders: Arc<Mutex<HashMap<PathBuf, Sender<Timestamp>>>>,
      $(
        $n: CacheBlock<$l, $t>
      ),*
    }

    impl<$l> Cache<$l> {
      pub fn new<P>(root:P) -> Self where P: AsRef<Path> {
        let senders: Arc<Mutex<HashMap<PathBuf, Sender<Timestamp>>>> = Arc::new(Mutex::new(HashMap::new()));

        // start watcher thread
        {
          let senders = senders.clone();
          let root = root.as_ref().to_path_buf();
          let (wsx, wrx) = channel();
          let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

          let _ = thread::spawn(move || {
            let _ = watcher.watch(root);

            for event in wrx.iter() {
              match event {
                notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } => {
                  if let Some(sx) = senders.lock().unwrap().get(&path) {
                    sx.send(precise_time_s()).unwrap();
                  }
                },
                _ => {}
              }
            }
          });
        }

        Cache {
          senders: senders,
          $(
            $n: CacheBlock::new()
          ),*
        }
      }
    }
  }
}

pub trait Get<'a, T> where T: 'a + Reload<'a> {
  fn get_id(&mut self, name: &str, args: T::Args) -> Option<Id<'a, T>>;
  fn get_by_id(&mut self, id: &Id<'a, T>) -> Option<&T>;
  fn get(&mut self, name: &str, args: T::Args) -> Option<&T> {
    self.get_id(name, args).and_then(move |i| self.get_by_id(&i))
  }
}

macro_rules! impl_get_id {
  ($n:ident : $t:ty, $this:ident, $name:ident, $args: ident) => {{
    let path_str = format!("data/{}/{}", stringify!($n), $name);
    let path = Path::new(&path_str);

    match $this.$n.ids.get($name).cloned() {
      id@Some(..) => {
        deb!("cache hit for {}", path_str);
        id
      },
      None => {
        deb!("cache miss for {}", path_str);

        // specific loading
        if path.exists() {
          match <$t as Load>::load(&path, $this, $args) {
            Ok(resource) => {
              let path_buf = path.to_owned();

              // create the id if we have loaded the resource
              let id: Id<$t> = ($this.$n.data.len() as u32).into();

              // create a channel to notify any update later and register the sender for the
              // given path
              let (sx, rx) = channel();
              {
                let mut senders = $this.senders.lock().unwrap();
                senders.insert(path_buf.clone(), sx);
              }

              // add the resource to the list of loaded ones
              $this.$n.data.push((resource, path_buf.clone(), (rx, precise_time_s())));
              // cache the resource
              $this.$n.ids.insert($name.to_owned(), id.clone());

              Some(id)
            },
            Err(e) => {
              err!("unable to load resource from {}: {:?}", path_str, e);
              None
            }
          }
        } else { // path doesn’t exist
          err!("ressource at {} cannot be found", path_str);
          None
        }
      }
    }
  }}
}

macro_rules! impl_get_by_id {
  ($n:ident : $t:ty, $this:ident, $id:ident) => {{
    // synchronization
    let mut reload_args = None;

    if let Some(data) = $this.$n.data.get($id.id as usize) {
      match (data.2).0.try_recv() {
        Ok(timestamp) if timestamp - (data.2).1 >= UPDATE_AWAIT_TIME => {
          reload_args = Some((data.1.to_owned(), data.0.reload_args()));
        },
        _ => {}
      }
    } else {
      return None;
    }

    if let Some((path, args)) = reload_args {
      match <$t as Load>::load(&path, $this, args) {
        Ok(new_resource) => {
          // replace the current resource with the freshly loaded one
          deb!("reloaded resource from {:?}", path);
          $this.$n.data[$id.id as usize].0 = new_resource;
        },
        Err(e) => {
          warn!("reloading resource from {:?} has failed: {:?}", path, e);
        }
      }
    }

    $this.$n.data.get($id.id as usize).map(|r| &r.0)
  }}
}

cache_struct!('a,
              models: Model,
              objects: Object<'a>,
              shader_programs: Program);

impl<'a> Get<'a, Model> for Cache<'a> {
  fn get_id(&mut self, name: &str, args: <Model as Load<'a>>::Args) -> Option<Id<'a, Model>> {
    impl_get_id!(models: Model, self, name, args)
  }

  fn get_by_id(&mut self, id: &Id<'a, Model>) -> Option<&Model> {
    impl_get_by_id!(models: Model, self, id)
  }
}

<commit_msg>YAY! Object is now cachable, for fuck’s sake!<commit_after>// FIXME: add the support of transient objects

use notify::{self, RecommendedWatcher, Watcher};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use time::precise_time_s;

use id::Id;
use model::Model;
use object::Object;
use shader::Program;

/// Class of types that can be loaded.
pub trait Load<'a>: Sized {
  /// Arguments passed at loading.
  type Args;

  // TODO: see whether we can use something with From/Into instead, so that we can use lambdas.
  fn load<P>(path: P, cache: &mut Cache<'a>, args: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path>;
}

/// Class of types that can be reloaded.
///
/// The idea is to simply recover the arguments used in `Load::load`.
pub trait Reload<'a>: Load<'a> {
  fn reload_args(&self) -> Self::Args;
}

/// Default implementation for types which are loaded without any arguments.
impl<'a, T> Reload<'a> for T where T: Load<'a, Args=()> {
  fn reload_args(&self) -> Self::Args {
    ()
  }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

type Timestamp = f64;

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME: Timestamp = 0.1; // 100ms

struct CacheBlock<'a, T> where T: 'a {
  data: Vec<(T, PathBuf, (Receiver<Timestamp>, f64))>,
  ids: HashMap<String, Id<'a, T>>,
}

impl<'a, T> CacheBlock<'a, T> {
  pub fn new() -> Self {
    CacheBlock {
      data: Vec::new(),
      ids: HashMap::new(),
    }
  }
}

macro_rules! cache_struct {
  ($l:tt, $($n:ident : $t:ty),*) => {
    pub struct Cache<$l> {
      senders: Arc<Mutex<HashMap<PathBuf, Sender<Timestamp>>>>,
      $(
        $n: CacheBlock<$l, $t>
      ),*
    }

    impl<$l> Cache<$l> {
      pub fn new<P>(root:P) -> Self where P: AsRef<Path> {
        let senders: Arc<Mutex<HashMap<PathBuf, Sender<Timestamp>>>> = Arc::new(Mutex::new(HashMap::new()));

        // start watcher thread
        {
          let senders = senders.clone();
          let root = root.as_ref().to_path_buf();
          let (wsx, wrx) = channel();
          let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

          let _ = thread::spawn(move || {
            let _ = watcher.watch(root);

            for event in wrx.iter() {
              match event {
                notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } => {
                  if let Some(sx) = senders.lock().unwrap().get(&path) {
                    sx.send(precise_time_s()).unwrap();
                  }
                },
                _ => {}
              }
            }
          });
        }

        Cache {
          senders: senders,
          $(
            $n: CacheBlock::new()
          ),*
        }
      }
    }
  }
}

pub trait Get<'a, T> where T: 'a + Reload<'a> {
  fn get_id(&mut self, name: &str, args: T::Args) -> Option<Id<'a, T>>;
  fn get_by_id(&mut self, id: &Id<'a, T>) -> Option<&T>;
  fn get(&mut self, name: &str, args: T::Args) -> Option<&T> {
    self.get_id(name, args).and_then(move |i| self.get_by_id(&i))
  }
}

macro_rules! impl_get_id {
  ($n:ident : $t:ty, $this:ident, $name:ident, $args: ident) => {{
    let path_str = format!("data/{}/{}", stringify!($n), $name);
    let path = Path::new(&path_str);

    match $this.$n.ids.get($name).cloned() {
      id@Some(..) => {
        deb!("cache hit for {}", path_str);
        id
      },
      None => {
        deb!("cache miss for {}", path_str);

        // specific loading
        if path.exists() {
          match <$t as Load>::load(&path, $this, $args) {
            Ok(resource) => {
              let path_buf = path.to_owned();

              // create the id if we have loaded the resource
              let id: Id<$t> = ($this.$n.data.len() as u32).into();

              // create a channel to notify any update later and register the sender for the
              // given path
              let (sx, rx) = channel();
              {
                let mut senders = $this.senders.lock().unwrap();
                senders.insert(path_buf.clone(), sx);
              }

              // add the resource to the list of loaded ones
              $this.$n.data.push((resource, path_buf.clone(), (rx, precise_time_s())));
              // cache the resource
              $this.$n.ids.insert($name.to_owned(), id.clone());

              Some(id)
            },
            Err(e) => {
              err!("unable to load resource from {}: {:?}", path_str, e);
              None
            }
          }
        } else { // path doesn’t exist
          err!("ressource at {} cannot be found", path_str);
          None
        }
      }
    }
  }}
}

macro_rules! impl_get_by_id {
  ($n:ident : $t:ty, $this:ident, $id:ident) => {{
    // synchronization
    let mut reload_args = None;

    if let Some(data) = $this.$n.data.get($id.id as usize) {
      match (data.2).0.try_recv() {
        Ok(timestamp) if timestamp - (data.2).1 >= UPDATE_AWAIT_TIME => {
          reload_args = Some((data.1.to_owned(), data.0.reload_args()));
        },
        _ => {}
      }
    } else {
      return None;
    }

    if let Some((path, args)) = reload_args {
      match <$t as Load>::load(&path, $this, args) {
        Ok(new_resource) => {
          // replace the current resource with the freshly loaded one
          deb!("reloaded resource from {:?}", path);
          $this.$n.data[$id.id as usize].0 = new_resource;
        },
        Err(e) => {
          warn!("reloading resource from {:?} has failed: {:?}", path, e);
        }
      }
    }

    $this.$n.data.get($id.id as usize).map(|r| &r.0)
  }}
}

macro_rules! impl_get_no_lifetime {
  ($n:ident : $t:ty) => {
    impl<'a> Get<'a, $t> for Cache<'a> {
      fn get_id(&mut self, name: &str, args: <$t as Load<'a>>::Args) -> Option<Id<'a, $t>> {
        impl_get_id!($n: $t, self, name, args)
      }

      fn get_by_id(&mut self, id: &Id<'a, $t>) -> Option<&$t> {
        impl_get_by_id!($n: $t, self, id)
      }
    }
  }
}

cache_struct!('a,
              models: Model,
              objects: Object<'a>,
              shader_programs: Program);

impl_get_no_lifetime!(models: Model);
impl_get_no_lifetime!(shader_programs: Program);

impl<'a> Get<'a, Object<'a>> for Cache<'a> {
  fn get_id(&mut self, name: &str, args: <Object<'a> as Load<'a>>::Args) -> Option<Id<'a, Object<'a>>> {
    impl_get_id!(objects: Object<'a>, self, name, args)
  }

  fn get_by_id(&mut self, id: &Id<'a, Object<'a>>) -> Option<&Object<'a>> {
    impl_get_by_id!(objects: Object<'a>, self, id)
  }
}
<|endoftext|>


<commit_before>use common::{HTTPDate, HTTPVersion, Header, StatusCode};

use std::cmp::Ordering;
use std::sync::mpsc::Receiver;

use std::io::Result as IoResult;
use std::io::{self, Cursor, Read, Write};

use std::fs::File;

use std::str::FromStr;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
/// of one of these will have no effect:
///
///  - `Connection`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///     will assume that the data from the `Read` object has the specified encoding
///     and will just pass-through.
///
///  - `Content-Length`: The length of the data should be set manually
///     using the `Reponse` object's API. Attempting to set the value of this
///     header will be equivalent to modifying the size of the data but the header
///     itself may not be present in the final result.
///
pub struct Response<R>
where
    R: Read,
{
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<usize>,
    chunked_threshold: Option<usize>,
}

/// A `Response` without a template parameter.
pub type ResponseBox = Response<Box<dyn Read + Send>>;

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
#[derive(Copy, Clone)]
enum TransferEncoding {
    Identity,
    Chunked,
}

impl FromStr for TransferEncoding {
    type Err = ();

    fn from_str(input: &str) -> Result<TransferEncoding, ()> {
        if input.eq_ignore_ascii_case("identity") {
            Ok(TransferEncoding::Identity)
        } else if input.eq_ignore_ascii_case("chunked") {
            Ok(TransferEncoding::Chunked)
        } else {
            Err(())
        }
    }
}

/// Builds a Date: header with the current date.
fn build_date_header() -> Header {
    let d = HTTPDate::new();
    Header::from_bytes(&b"Date"[..], &d.to_string().into_bytes()[..]).unwrap()
}

fn write_message_header<W>(
    mut writer: W,
    http_version: &HTTPVersion,
    status_code: &StatusCode,
    headers: &[Header],
) -> IoResult<()>
where
    W: Write,
{
    // writing status line
    write!(
        &mut writer,
        "HTTP/{}.{} {} {}\r\n",
        http_version.0,
        http_version.1,
        status_code.0,
        status_code.default_reason_phrase()
    )?;

    // writing headers
    for header in headers.iter() {
        writer.write_all(header.field.as_str().as_ref())?;
        write!(&mut writer, ": ")?;
        writer.write_all(header.value.as_str().as_ref())?;
        write!(&mut writer, "\r\n")?;
    }

    // separator between header and data
    write!(&mut writer, "\r\n")?;

    Ok(())
}

fn choose_transfer_encoding(
    request_headers: &[Header],
    http_version: &HTTPVersion,
    entity_length: &Option<usize>,
    has_additional_headers: bool,
    chunked_threshold: usize,
) -> TransferEncoding {
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= (1, 0) {
        return TransferEncoding::Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers
        .iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))
        // getting its value
        .map(|h| h.value.clone())
        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value.as_str()); // TODO: remove conversion

            // sorting elements by most priority
            parse.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                // q=0 are ignored
                if value.1 <= 0.0 {
                    continue;
                }

                if let Ok(te) = TransferEncoding::from_str(value.0) {
                    return Some(te);
                }
            }

            // encoding not found
            None
        });

    //
    if let Some(user_request) = user_request {
        return user_request;
    }

    // if we have additional headers, using chunked
    if has_additional_headers {
        return TransferEncoding::Chunked;
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    if entity_length
        .as_ref()
        .map_or(true, |val| *val >= chunked_threshold)
    {
        return TransferEncoding::Chunked;
    }

    // Identity by default
    TransferEncoding::Identity
}

impl<R> Response<R>
where
    R: Read,
{
    /// Creates a new Response object.
    ///
    /// The `additional_headers` argument is a receiver that
    ///  may provide headers even after the response has been sent.
    ///
    /// All the other arguments are straight-forward.
    pub fn new(
        status_code: StatusCode,
        headers: Vec<Header>,
        data: R,
        data_length: Option<usize>,
        additional_headers: Option<Receiver<Header>>,
    ) -> Response<R> {
        let mut response = Response {
            reader: data,
            status_code,
            headers: Vec::with_capacity(16),
            data_length,
            chunked_threshold: None,
        };

        for h in headers {
            response.add_header(h)
        }

        // dummy implementation
        if let Some(additional_headers) = additional_headers {
            for h in additional_headers.iter() {
                response.add_header(h)
            }
        }

        response
    }

    /// Set a threshold for `Content-Length` where we chose chunked
    /// transfer. Notice that chunked transfer might happen regardless of
    /// this threshold, for instance when the request headers indicate
    /// it is wanted or when there is no `Content-Length`.
    pub fn with_chunked_threshold(mut self, length: usize) -> Response<R> {
        self.chunked_threshold = Some(length);
        self
    }

    /// The current `Content-Length` threshold for switching over to
    /// chunked transfer. The default is 32768 bytes. Notice that
    /// chunked transfer is mutually exclusive with sending a
    /// `Content-Length` header as per the HTTP spec.
    pub fn chunked_threshold(&self) -> usize {
        self.chunked_threshold.unwrap_or(32768)
    }

    /// Adds a header to the list.
    /// Does all the checks.
    pub fn add_header<H>(&mut self, header: H)
    where
        H: Into<Header>,
    {
        let header = header.into();

        // ignoring forbidden headers
        if header.field.equiv(&"Connection")
            || header.field.equiv(&"Trailer")
            || header.field.equiv(&"Transfer-Encoding")
            || header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            if let Ok(val) = usize::from_str(header.value.as_str()) {
                self.data_length = Some(val)
            }

            return;
        }

        self.headers.push(header);
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[inline]
    pub fn with_header<H>(mut self, header: H) -> Response<R>
    where
        H: Into<Header>,
    {
        self.add_header(header.into());
        self
    }

    /// Returns the same request, but with a different status code.
    #[inline]
    pub fn with_status_code<S>(mut self, code: S) -> Response<R>
    where
        S: Into<StatusCode>,
    {
        self.status_code = code.into();
        self
    }

    /// Returns the same request, but with different data.
    pub fn with_data<S>(self, reader: S, data_length: Option<usize>) -> Response<S>
    where
        S: Read,
    {
        Response {
            reader,
            headers: self.headers,
            status_code: self.status_code,
            data_length,
            chunked_threshold: self.chunked_threshold,
        }
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    ///
    /// Note: does not flush the writer.
    pub fn raw_print<W: Write>(
        mut self,
        mut writer: W,
        http_version: HTTPVersion,
        request_headers: &[Header],
        do_not_send_body: bool,
        upgrade: Option<&str>,
    ) -> IoResult<()> {
        let mut transfer_encoding = Some(choose_transfer_encoding(
            request_headers,
            &http_version,
            &self.data_length,
            false, /* TODO */
            self.chunked_threshold(),
        ));

        // add `Date` if not in the headers
        if self
            .headers
            .iter()
            .find(|h| h.field.equiv(&"Date"))
            .is_none()
        {
            self.headers.insert(0, build_date_header());
        }

        // add `Server` if not in the headers
        if self
            .headers
            .iter()
            .find(|h| h.field.equiv(&"Server"))
            .is_none()
        {
            self.headers.insert(
                0,
                Header::from_bytes(&b"Server"[..], &b"tiny-http (Rust)"[..]).unwrap(),
            );
        }

        // handling upgrade
        if let Some(upgrade) = upgrade {
            self.headers.insert(
                0,
                Header::from_bytes(&b"Upgrade"[..], upgrade.as_bytes()).unwrap(),
            );
            self.headers.insert(
                0,
                Header::from_bytes(&b"Connection"[..], &b"upgrade"[..]).unwrap(),
            );
            transfer_encoding = None;
        }

        // if the transfer encoding is identity, the content length must be known ; therefore if
        // we don't know it, we buffer the entire response first here
        // while this is an expensive operation, it is only ever needed for clients using HTTP 1.0
        let (mut reader, data_length) = match (self.data_length, transfer_encoding) {
            (Some(l), _) => (Box::new(self.reader) as Box<dyn Read>, Some(l)),
            (None, Some(TransferEncoding::Identity)) => {
                let mut buf = Vec::new();
                self.reader.read_to_end(&mut buf)?;
                let l = buf.len();
                (Box::new(Cursor::new(buf)) as Box<dyn Read>, Some(l))
            }
            _ => (Box::new(self.reader) as Box<dyn Read>, None),
        };

        // checking whether to ignore the body of the response
        let do_not_send_body = do_not_send_body
            || match self.status_code.0 {
                // status code 1xx, 204 and 304 MUST not include a body
                100..=199 | 204 | 304 => true,
                _ => false,
            };

        // preparing headers for transfer
        match transfer_encoding {
            Some(TransferEncoding::Chunked) => self
                .headers
                .push(Header::from_bytes(&b"Transfer-Encoding"[..], &b"chunked"[..]).unwrap()),

            Some(TransferEncoding::Identity) => {
                assert!(data_length.is_some());
                let data_length = data_length.unwrap();

                self.headers.push(
                    Header::from_bytes(
                        &b"Content-Length"[..],
                        format!("{}", data_length).as_bytes(),
                    )
                    .unwrap(),
                )
            }

            _ => (),
        };

        // sending headers
        write_message_header(
            writer.by_ref(),
            &http_version,
            &self.status_code,
            &self.headers,
        )?;

        // sending the body
        if !do_not_send_body {
            match transfer_encoding {
                Some(TransferEncoding::Chunked) => {
                    use chunked_transfer::Encoder;

                    let mut writer = Encoder::new(writer);
                    io::copy(&mut reader, &mut writer)?;
                }

                Some(TransferEncoding::Identity) => {
                    use util::EqualReader;

                    assert!(data_length.is_some());
                    let data_length = data_length.unwrap();

                    if data_length >= 1 {
                        let (mut equ_reader, _) = EqualReader::new(reader.by_ref(), data_length);
                        io::copy(&mut equ_reader, &mut writer)?;
                    }
                }

                _ => (),
            }
        }

        Ok(())
    }
}

impl<R> Response<R>
where
    R: Read + Send + 'static,
{
    /// Turns this response into a `Response<Box<Read + Send>>`.
    pub fn boxed(self) -> ResponseBox {
        Response {
            reader: Box::new(self.reader) as Box<dyn Read + Send>,
            status_code: self.status_code,
            headers: self.headers,
            data_length: self.data_length,
            chunked_threshold: self.chunked_threshold,
        }
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    pub fn from_file(file: File) -> Response<File> {
        let file_size = file.metadata().ok().map(|v| v.len() as usize);

        Response::new(
            StatusCode(200),
            Vec::with_capacity(0),
            file,
            file_size,
            None,
        )
    }
}

impl Response<Cursor<Vec<u8>>> {
    pub fn from_data<D>(data: D) -> Response<Cursor<Vec<u8>>>
    where
        D: Into<Vec<u8>>,
    {
        let data = data.into();
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::with_capacity(0),
            Cursor::new(data),
            Some(data_len),
            None,
        )
    }

    pub fn from_string<S>(data: S) -> Response<Cursor<Vec<u8>>>
    where
        S: Into<String>,
    {
        let data = data.into();
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec![
                Header::from_bytes(&b"Content-Type"[..], &b"text/plain; charset=UTF-8"[..])
                    .unwrap(),
            ],
            Cursor::new(data.into_bytes()),
            Some(data_len),
            None,
        )
    }
}

impl Response<io::Empty> {
    /// Builds an empty `Response` with the given status code.
    pub fn empty<S>(status_code: S) -> Response<io::Empty>
    where
        S: Into<StatusCode>,
    {
        Response::new(
            status_code.into(),
            Vec::with_capacity(0),
            io::empty(),
            Some(0),
            None,
        )
    }

    /// DEPRECATED. Use `empty` instead.
    pub fn new_empty(status_code: StatusCode) -> Response<io::Empty> {
        Response::empty(status_code)
    }
}

impl Clone for Response<io::Empty> {
    fn clone(&self) -> Response<io::Empty> {
        Response {
            reader: io::empty(),
            status_code: self.status_code.clone(),
            headers: self.headers.clone(),
            data_length: self.data_length,
            chunked_threshold: self.chunked_threshold,
        }
    }
}
<commit_msg>feat: getters for Status Code & Data Length<commit_after>use common::{HTTPDate, HTTPVersion, Header, StatusCode};

use std::cmp::Ordering;
use std::sync::mpsc::Receiver;

use std::io::Result as IoResult;
use std::io::{self, Cursor, Read, Write};

use std::fs::File;

use std::str::FromStr;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
/// of one of these will have no effect:
///
///  - `Connection`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///     will assume that the data from the `Read` object has the specified encoding
///     and will just pass-through.
///
///  - `Content-Length`: The length of the data should be set manually
///     using the `Reponse` object's API. Attempting to set the value of this
///     header will be equivalent to modifying the size of the data but the header
///     itself may not be present in the final result.
///
pub struct Response<R>
where
    R: Read,
{
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<usize>,
    chunked_threshold: Option<usize>,
}

/// A `Response` without a template parameter.
pub type ResponseBox = Response<Box<dyn Read + Send>>;

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
#[derive(Copy, Clone)]
enum TransferEncoding {
    Identity,
    Chunked,
}

impl FromStr for TransferEncoding {
    type Err = ();

    fn from_str(input: &str) -> Result<TransferEncoding, ()> {
        if input.eq_ignore_ascii_case("identity") {
            Ok(TransferEncoding::Identity)
        } else if input.eq_ignore_ascii_case("chunked") {
            Ok(TransferEncoding::Chunked)
        } else {
            Err(())
        }
    }
}

/// Builds a Date: header with the current date.
fn build_date_header() -> Header {
    let d = HTTPDate::new();
    Header::from_bytes(&b"Date"[..], &d.to_string().into_bytes()[..]).unwrap()
}

fn write_message_header<W>(
    mut writer: W,
    http_version: &HTTPVersion,
    status_code: &StatusCode,
    headers: &[Header],
) -> IoResult<()>
where
    W: Write,
{
    // writing status line
    write!(
        &mut writer,
        "HTTP/{}.{} {} {}\r\n",
        http_version.0,
        http_version.1,
        status_code.0,
        status_code.default_reason_phrase()
    )?;

    // writing headers
    for header in headers.iter() {
        writer.write_all(header.field.as_str().as_ref())?;
        write!(&mut writer, ": ")?;
        writer.write_all(header.value.as_str().as_ref())?;
        write!(&mut writer, "\r\n")?;
    }

    // separator between header and data
    write!(&mut writer, "\r\n")?;

    Ok(())
}

fn choose_transfer_encoding(
    request_headers: &[Header],
    http_version: &HTTPVersion,
    entity_length: &Option<usize>,
    has_additional_headers: bool,
    chunked_threshold: usize,
) -> TransferEncoding {
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= (1, 0) {
        return TransferEncoding::Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers
        .iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))
        // getting its value
        .map(|h| h.value.clone())
        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value.as_str()); // TODO: remove conversion

            // sorting elements by most priority
            parse.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                // q=0 are ignored
                if value.1 <= 0.0 {
                    continue;
                }

                if let Ok(te) = TransferEncoding::from_str(value.0) {
                    return Some(te);
                }
            }

            // encoding not found
            None
        });

    //
    if let Some(user_request) = user_request {
        return user_request;
    }

    // if we have additional headers, using chunked
    if has_additional_headers {
        return TransferEncoding::Chunked;
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    if entity_length
        .as_ref()
        .map_or(true, |val| *val >= chunked_threshold)
    {
        return TransferEncoding::Chunked;
    }

    // Identity by default
    TransferEncoding::Identity
}

impl<R> Response<R>
where
    R: Read,
{
    /// Creates a new Response object.
    ///
    /// The `additional_headers` argument is a receiver that
    ///  may provide headers even after the response has been sent.
    ///
    /// All the other arguments are straight-forward.
    pub fn new(
        status_code: StatusCode,
        headers: Vec<Header>,
        data: R,
        data_length: Option<usize>,
        additional_headers: Option<Receiver<Header>>,
    ) -> Response<R> {
        let mut response = Response {
            reader: data,
            status_code,
            headers: Vec::with_capacity(16),
            data_length,
            chunked_threshold: None,
        };

        for h in headers {
            response.add_header(h)
        }

        // dummy implementation
        if let Some(additional_headers) = additional_headers {
            for h in additional_headers.iter() {
                response.add_header(h)
            }
        }

        response
    }

    /// Set a threshold for `Content-Length` where we chose chunked
    /// transfer. Notice that chunked transfer might happen regardless of
    /// this threshold, for instance when the request headers indicate
    /// it is wanted or when there is no `Content-Length`.
    pub fn with_chunked_threshold(mut self, length: usize) -> Response<R> {
        self.chunked_threshold = Some(length);
        self
    }

    /// The current `Content-Length` threshold for switching over to
    /// chunked transfer. The default is 32768 bytes. Notice that
    /// chunked transfer is mutually exclusive with sending a
    /// `Content-Length` header as per the HTTP spec.
    pub fn chunked_threshold(&self) -> usize {
        self.chunked_threshold.unwrap_or(32768)
    }

    /// Adds a header to the list.
    /// Does all the checks.
    pub fn add_header<H>(&mut self, header: H)
    where
        H: Into<Header>,
    {
        let header = header.into();

        // ignoring forbidden headers
        if header.field.equiv(&"Connection")
            || header.field.equiv(&"Trailer")
            || header.field.equiv(&"Transfer-Encoding")
            || header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            if let Ok(val) = usize::from_str(header.value.as_str()) {
                self.data_length = Some(val)
            }

            return;
        }

        self.headers.push(header);
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[inline]
    pub fn with_header<H>(mut self, header: H) -> Response<R>
    where
        H: Into<Header>,
    {
        self.add_header(header.into());
        self
    }

    /// Returns the same request, but with a different status code.
    #[inline]
    pub fn with_status_code<S>(mut self, code: S) -> Response<R>
    where
        S: Into<StatusCode>,
    {
        self.status_code = code.into();
        self
    }

    /// Returns the same request, but with different data.
    pub fn with_data<S>(self, reader: S, data_length: Option<usize>) -> Response<S>
    where
        S: Read,
    {
        Response {
            reader,
            headers: self.headers,
            status_code: self.status_code,
            data_length,
            chunked_threshold: self.chunked_threshold,
        }
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    ///
    /// Note: does not flush the writer.
    pub fn raw_print<W: Write>(
        mut self,
        mut writer: W,
        http_version: HTTPVersion,
        request_headers: &[Header],
        do_not_send_body: bool,
        upgrade: Option<&str>,
    ) -> IoResult<()> {
        let mut transfer_encoding = Some(choose_transfer_encoding(
            request_headers,
            &http_version,
            &self.data_length,
            false, /* TODO */
            self.chunked_threshold(),
        ));

        // add `Date` if not in the headers
        if self
            .headers
            .iter()
            .find(|h| h.field.equiv(&"Date"))
            .is_none()
        {
            self.headers.insert(0, build_date_header());
        }

        // add `Server` if not in the headers
        if self
            .headers
            .iter()
            .find(|h| h.field.equiv(&"Server"))
            .is_none()
        {
            self.headers.insert(
                0,
                Header::from_bytes(&b"Server"[..], &b"tiny-http (Rust)"[..]).unwrap(),
            );
        }

        // handling upgrade
        if let Some(upgrade) = upgrade {
            self.headers.insert(
                0,
                Header::from_bytes(&b"Upgrade"[..], upgrade.as_bytes()).unwrap(),
            );
            self.headers.insert(
                0,
                Header::from_bytes(&b"Connection"[..], &b"upgrade"[..]).unwrap(),
            );
            transfer_encoding = None;
        }

        // if the transfer encoding is identity, the content length must be known ; therefore if
        // we don't know it, we buffer the entire response first here
        // while this is an expensive operation, it is only ever needed for clients using HTTP 1.0
        let (mut reader, data_length) = match (self.data_length, transfer_encoding) {
            (Some(l), _) => (Box::new(self.reader) as Box<dyn Read>, Some(l)),
            (None, Some(TransferEncoding::Identity)) => {
                let mut buf = Vec::new();
                self.reader.read_to_end(&mut buf)?;
                let l = buf.len();
                (Box::new(Cursor::new(buf)) as Box<dyn Read>, Some(l))
            }
            _ => (Box::new(self.reader) as Box<dyn Read>, None),
        };

        // checking whether to ignore the body of the response
        let do_not_send_body = do_not_send_body
            || match self.status_code.0 {
                // status code 1xx, 204 and 304 MUST not include a body
                100..=199 | 204 | 304 => true,
                _ => false,
            };

        // preparing headers for transfer
        match transfer_encoding {
            Some(TransferEncoding::Chunked) => self
                .headers
                .push(Header::from_bytes(&b"Transfer-Encoding"[..], &b"chunked"[..]).unwrap()),

            Some(TransferEncoding::Identity) => {
                assert!(data_length.is_some());
                let data_length = data_length.unwrap();

                self.headers.push(
                    Header::from_bytes(
                        &b"Content-Length"[..],
                        format!("{}", data_length).as_bytes(),
                    )
                    .unwrap(),
                )
            }

            _ => (),
        };

        // sending headers
        write_message_header(
            writer.by_ref(),
            &http_version,
            &self.status_code,
            &self.headers,
        )?;

        // sending the body
        if !do_not_send_body {
            match transfer_encoding {
                Some(TransferEncoding::Chunked) => {
                    use chunked_transfer::Encoder;

                    let mut writer = Encoder::new(writer);
                    io::copy(&mut reader, &mut writer)?;
                }

                Some(TransferEncoding::Identity) => {
                    use util::EqualReader;

                    assert!(data_length.is_some());
                    let data_length = data_length.unwrap();

                    if data_length >= 1 {
                        let (mut equ_reader, _) = EqualReader::new(reader.by_ref(), data_length);
                        io::copy(&mut equ_reader, &mut writer)?;
                    }
                }

                _ => (),
            }
        }

        Ok(())
    }

    /// Retrieves the current value of the `Response` status code
    pub fn status_code(&self) -> StatusCode {
        self.status_code.clone()
    }

    /// Retrieves the current value of the `Response` data length
    pub fn data_length(&self) -> Option<usize> {
        self.data_length
    }
}

impl<R> Response<R>
where
    R: Read + Send + 'static,
{
    /// Turns this response into a `Response<Box<Read + Send>>`.
    pub fn boxed(self) -> ResponseBox {
        Response {
            reader: Box::new(self.reader) as Box<dyn Read + Send>,
            status_code: self.status_code,
            headers: self.headers,
            data_length: self.data_length,
            chunked_threshold: self.chunked_threshold,
        }
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    pub fn from_file(file: File) -> Response<File> {
        let file_size = file.metadata().ok().map(|v| v.len() as usize);

        Response::new(
            StatusCode(200),
            Vec::with_capacity(0),
            file,
            file_size,
            None,
        )
    }
}

impl Response<Cursor<Vec<u8>>> {
    pub fn from_data<D>(data: D) -> Response<Cursor<Vec<u8>>>
    where
        D: Into<Vec<u8>>,
    {
        let data = data.into();
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::with_capacity(0),
            Cursor::new(data),
            Some(data_len),
            None,
        )
    }

    pub fn from_string<S>(data: S) -> Response<Cursor<Vec<u8>>>
    where
        S: Into<String>,
    {
        let data = data.into();
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec![
                Header::from_bytes(&b"Content-Type"[..], &b"text/plain; charset=UTF-8"[..])
                    .unwrap(),
            ],
            Cursor::new(data.into_bytes()),
            Some(data_len),
            None,
        )
    }
}

impl Response<io::Empty> {
    /// Builds an empty `Response` with the given status code.
    pub fn empty<S>(status_code: S) -> Response<io::Empty>
    where
        S: Into<StatusCode>,
    {
        Response::new(
            status_code.into(),
            Vec::with_capacity(0),
            io::empty(),
            Some(0),
            None,
        )
    }

    /// DEPRECATED. Use `empty` instead.
    pub fn new_empty(status_code: StatusCode) -> Response<io::Empty> {
        Response::empty(status_code)
    }
}

impl Clone for Response<io::Empty> {
    fn clone(&self) -> Response<io::Empty> {
        Response {
            reader: io::empty(),
            status_code: self.status_code.clone(),
            headers: self.headers.clone(),
            data_length: self.data_length,
            chunked_threshold: self.chunked_threshold,
        }
    }
}
<|endoftext|>


<commit_before>//! The grid-details view lists several details views side-by-side.

use std::io::{Write, Result as IOResult};

use ansi_term::ANSIStrings;
use term_grid as grid;

use fs::{Dir, File};
use fs::feature::xattr::FileAttributes;
use fs::filter::FileFilter;

use output::cell::TextCell;
use output::colours::Colours;
use output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
use output::grid::Options as GridOptions;
use output::file_name::FileStyle;
use output::table::{Table, Row as TableRow, Options as TableOptions};
use output::tree::{TreeParams, TreeDepth};

pub struct Render<'a> {

    /// The directory that’s being rendered here.
    /// We need this to know which columns to put in the output.
    pub dir: Option<&'a Dir>,

    /// The files that have been read from the directory. They should all
    /// hold a reference to it.
    pub files: Vec<File<'a>>,

    /// How to colour various pieces of text.
    pub colours: &'a Colours,

    /// How to format filenames.
    pub style: &'a FileStyle,

    /// The grid part of the grid-details view.
    pub grid: &'a GridOptions,

    /// The details part of the grid-details view.
    pub details: &'a DetailsOptions,

    /// How to filter files after listing a directory. The files in this
    /// render will already have been filtered and sorted, but any directories
    /// that we recurse into will have to have this applied.
    pub filter: &'a FileFilter,
}

impl<'a> Render<'a> {
    pub fn details(&self) -> DetailsRender<'a> {
        DetailsRender {
            dir: self.dir.clone(),
            files: Vec::new(),
            colours: self.colours,
            style: self.style,
            opts: self.details,
            recurse: None,
            filter: self.filter,
        }
    }

    pub fn render<W: Write>(&self, w: &mut W) -> IOResult<()> {

        let options = self.details.table.as_ref().expect("Details table options not given!");

        let drender = self.details();

        let (first_table, _) = self.make_table(options, &drender);

        let rows = self.files.iter()
                       .map(|file| first_table.row_for_file(file, file_has_xattrs(file)))
                       .collect::<Vec<TableRow>>();

        let file_names = self.files.iter()
                             .map(|file| self.style.for_file(file, self.colours).paint().promote())
                             .collect::<Vec<TextCell>>();

        let mut last_working_table = self.make_grid(1, options, &file_names, rows.clone(), &drender);

        for column_count in 2.. {
            let grid = self.make_grid(column_count, options, &file_names, rows.clone(), &drender);

            let the_grid_fits = {
                let d = grid.fit_into_columns(column_count);
                d.is_complete() && d.width() <= self.grid.console_width
            };

            if the_grid_fits {
                last_working_table = grid;
            }
            else {
                return write!(w, "{}", last_working_table.fit_into_columns(column_count - 1));
            }
        }

        Ok(())
    }

    fn make_table<'t>(&'a self, options: &'a TableOptions, drender: &DetailsRender) -> (Table<'a>, Vec<DetailsRow>) {
        let mut table = Table::new(options, self.dir, self.colours);
        let mut rows = Vec::new();

        if self.details.header {
            let row = table.header_row();
            table.add_widths(&row);
            rows.push(drender.render_header(row));
        }

        (table, rows)
    }

    fn make_grid(&'a self, column_count: usize, options: &'a TableOptions, file_names: &[TextCell], rows: Vec<TableRow>, drender: &DetailsRender) -> grid::Grid {

        let mut tables = Vec::new();
        for _ in 0 .. column_count {
            tables.push(self.make_table(options, drender));
        }

        let mut num_cells = rows.len();
        if self.details.header {
            num_cells += column_count;
        }

        let original_height = divide_rounding_up(rows.len(), column_count);
        let height = divide_rounding_up(num_cells, column_count);

        for (i, (file_name, row)) in file_names.iter().zip(rows.into_iter()).enumerate() {
            let index = if self.grid.across {
                    i % column_count
                }
                else {
                    i / original_height
                };

            let (ref mut table, ref mut rows) = tables[index];
            table.add_widths(&row);
            let details_row = drender.render_file(row, file_name.clone(), TreeParams::new(TreeDepth::root(), false));
            rows.push(details_row);
        }

        let columns: Vec<_> = tables.into_iter().map(|(table, details_rows)| {
            drender.iterate_with_table(table, details_rows).collect::<Vec<_>>()
        }).collect();

        let direction = if self.grid.across { grid::Direction::LeftToRight }
                                       else { grid::Direction::TopToBottom };

        let mut grid = grid::Grid::new(grid::GridOptions {
            direction:  direction,
            filling:    grid::Filling::Spaces(4),
        });

        if self.grid.across {
            for row in 0 .. height {
                for column in &columns {
                    if row < column.len() {
                        let cell = grid::Cell {
                            contents: ANSIStrings(&column[row].contents).to_string(),
                            width:    *column[row].width,
                        };

                        grid.add(cell);
                    }
                }
            }
        }
        else {
            for column in &columns {
                for cell in column.iter() {
                    let cell = grid::Cell {
                        contents: ANSIStrings(&cell.contents).to_string(),
                        width:    *cell.width,
                    };

                    grid.add(cell);
                }
            }
        }

        grid
    }
}

fn divide_rounding_up(a: usize, b: usize) -> usize {
    let mut result = a / b;
    if a % b != 0 { result += 1; }
    result
}

fn file_has_xattrs(file: &File) -> bool {
    match file.path.attributes() {
        Ok(attrs) => !attrs.is_empty(),
        Err(_) => false,
    }
}
<commit_msg>Have grid-details turn into lines if it won’t fit<commit_after>//! The grid-details view lists several details views side-by-side.

use std::io::{Write, Result as IOResult};

use ansi_term::ANSIStrings;
use term_grid as grid;

use fs::{Dir, File};
use fs::feature::xattr::FileAttributes;
use fs::filter::FileFilter;

use output::cell::TextCell;
use output::colours::Colours;
use output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
use output::grid::Options as GridOptions;
use output::lines::Render as LinesRender;
use output::file_name::FileStyle;
use output::table::{Table, Row as TableRow, Options as TableOptions};
use output::tree::{TreeParams, TreeDepth};

pub struct Render<'a> {

    /// The directory that’s being rendered here.
    /// We need this to know which columns to put in the output.
    pub dir: Option<&'a Dir>,

    /// The files that have been read from the directory. They should all
    /// hold a reference to it.
    pub files: Vec<File<'a>>,

    /// How to colour various pieces of text.
    pub colours: &'a Colours,

    /// How to format filenames.
    pub style: &'a FileStyle,

    /// The grid part of the grid-details view.
    pub grid: &'a GridOptions,

    /// The details part of the grid-details view.
    pub details: &'a DetailsOptions,

    /// How to filter files after listing a directory. The files in this
    /// render will already have been filtered and sorted, but any directories
    /// that we recurse into will have to have this applied.
    pub filter: &'a FileFilter,
}

impl<'a> Render<'a> {

    /// Create a temporary Details render that gets used for the columns of
    /// the grid-details render that's being generated.
    ///
    /// This includes an empty files vector because the files get added to
    /// the table in *this* file, not in details: we only want to insert every
    /// *n* files into each column’s table, not all of them.
    pub fn details(&self) -> DetailsRender<'a> {
        DetailsRender {
            dir: self.dir.clone(),
            files: Vec::new(),
            colours: self.colours,
            style: self.style,
            opts: self.details,
            recurse: None,
            filter: self.filter,
        }
    }

    /// Create a Lines render for when this grid-details render doesn’t fit
    /// in the terminal (or something has gone wrong) and we have given up.
    pub fn lines(self) -> LinesRender<'a> {
        LinesRender {
            files: self.files,
            colours: self.colours,
            style: self.style,
        }
    }

    pub fn render<W: Write>(self, w: &mut W) -> IOResult<()> {
        if let Some((grid, width)) = self.find_fitting_grid() {
            write!(w, "{}", grid.fit_into_columns(width))
        }
        else {
            self.lines().render(w)
        }
    }

    pub fn find_fitting_grid(&self) -> Option<(grid::Grid, grid::Width)> {
        let options = self.details.table.as_ref().expect("Details table options not given!");

        let drender = self.details();

        let (first_table, _) = self.make_table(options, &drender);

        let rows = self.files.iter()
                       .map(|file| first_table.row_for_file(file, file_has_xattrs(file)))
                       .collect::<Vec<TableRow>>();

        let file_names = self.files.iter()
                             .map(|file| self.style.for_file(file, self.colours).paint().promote())
                             .collect::<Vec<TextCell>>();

        let mut last_working_table = self.make_grid(1, options, &file_names, rows.clone(), &drender);

        // If we can’t fit everything in a grid 100 columns wide, then
        // something has gone seriously awry
        for column_count in 2..100 {
            let grid = self.make_grid(column_count, options, &file_names, rows.clone(), &drender);

            let the_grid_fits = {
                let d = grid.fit_into_columns(column_count);
                d.is_complete() && d.width() <= self.grid.console_width
            };

            if the_grid_fits {
                last_working_table = grid;
            }
            else {
                return Some((last_working_table, column_count - 1));
            }
        }

        None
    }

    fn make_table<'t>(&'a self, options: &'a TableOptions, drender: &DetailsRender) -> (Table<'a>, Vec<DetailsRow>) {
        let mut table = Table::new(options, self.dir, self.colours);
        let mut rows = Vec::new();

        if self.details.header {
            let row = table.header_row();
            table.add_widths(&row);
            rows.push(drender.render_header(row));
        }

        (table, rows)
    }

    fn make_grid(&'a self, column_count: usize, options: &'a TableOptions, file_names: &[TextCell], rows: Vec<TableRow>, drender: &DetailsRender) -> grid::Grid {

        let mut tables = Vec::new();
        for _ in 0 .. column_count {
            tables.push(self.make_table(options, drender));
        }

        let mut num_cells = rows.len();
        if self.details.header {
            num_cells += column_count;
        }

        let original_height = divide_rounding_up(rows.len(), column_count);
        let height = divide_rounding_up(num_cells, column_count);

        for (i, (file_name, row)) in file_names.iter().zip(rows.into_iter()).enumerate() {
            let index = if self.grid.across {
                    i % column_count
                }
                else {
                    i / original_height
                };

            let (ref mut table, ref mut rows) = tables[index];
            table.add_widths(&row);
            let details_row = drender.render_file(row, file_name.clone(), TreeParams::new(TreeDepth::root(), false));
            rows.push(details_row);
        }

        let columns: Vec<_> = tables.into_iter().map(|(table, details_rows)| {
            drender.iterate_with_table(table, details_rows).collect::<Vec<_>>()
        }).collect();

        let direction = if self.grid.across { grid::Direction::LeftToRight }
                                       else { grid::Direction::TopToBottom };

        let mut grid = grid::Grid::new(grid::GridOptions {
            direction:  direction,
            filling:    grid::Filling::Spaces(4),
        });

        if self.grid.across {
            for row in 0 .. height {
                for column in &columns {
                    if row < column.len() {
                        let cell = grid::Cell {
                            contents: ANSIStrings(&column[row].contents).to_string(),
                            width:    *column[row].width,
                        };

                        grid.add(cell);
                    }
                }
            }
        }
        else {
            for column in &columns {
                for cell in column.iter() {
                    let cell = grid::Cell {
                        contents: ANSIStrings(&cell.contents).to_string(),
                        width:    *cell.width,
                    };

                    grid.add(cell);
                }
            }
        }

        grid
    }
}

fn divide_rounding_up(a: usize, b: usize) -> usize {
    let mut result = a / b;
    if a % b != 0 { result += 1; }
    result
}

fn file_has_xattrs(file: &File) -> bool {
    match file.path.attributes() {
        Ok(attrs) => !attrs.is_empty(),
        Err(_) => false,
    }
}
<|endoftext|>


<commit_before>
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use GameWindow = piston::game_window::GameWindow;
use piston::gl::Gl;
use graphics;
use graphics::*;
use rand::random;

fn load_vertices() -> Vec<f32> {
    vec!(
         0.0,  0.5,
        -0.5, -0.5,
         0.5, -0.5,
    )
}

fn load_colors() -> Vec<f32> {
    vec!(
        1.0, 0.0, 0.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
    )
}

pub struct SnakeApp {
    vertices: Vec<f32>,
    colors: Vec<f32>,
    settings: Settings,
    game_window: GameWindow,
}

impl Game for SnakeApp {
    fn get_game_window<'a>(&'a self) -> &'a GameWindow { &self.game_window }
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }
    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        let polygon = [
            0.0, 0.0,
            0.5, 0.0,
            0.5, 0.5
        ];
        c.polygon(polygon.as_slice()).rgba(0.0, 0.0, 1.0, 1.0).fill(gl);
    }
    fn update(&mut self) {
    }
    fn load(&mut self) {
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            game_window: GameWindow::window("Snake", 512, 512),
            vertices: load_vertices(),
            colors: load_colors(),
            settings: Settings::new(exit_on_esc, background_color),
        }
    }
}

<commit_msg>Drawing an ellipse<commit_after>
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use GameWindow = piston::game_window::GameWindow;
use piston::gl::Gl;
use graphics;
use graphics::*;
use rand::random;

fn load_vertices() -> Vec<f32> {
    vec!(
         0.0,  0.5,
        -0.5, -0.5,
         0.5, -0.5,
    )
}

fn load_colors() -> Vec<f32> {
    vec!(
        1.0, 0.0, 0.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
    )
}

pub struct SnakeApp {
    vertices: Vec<f32>,
    colors: Vec<f32>,
    settings: Settings,
    game_window: GameWindow,
}

impl Game for SnakeApp {
    fn get_game_window<'a>(&'a self) -> &'a GameWindow { &self.game_window }
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }
    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        c.ellipse(0.0, 0.0, 0.5, 0.5).rgba(0.0, 1.0, 0.0, 1.0).fill(gl);
    }
    fn update(&mut self) {
    }
    fn load(&mut self) {
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            game_window: GameWindow::window("Snake", 512, 512),
            vertices: load_vertices(),
            colors: load_colors(),
            settings: Settings::new(exit_on_esc, background_color),
        }
    }
}

<|endoftext|>


<commit_before>use rustty::{Terminal, Event, Color};
use editor;

#[derive(Copy, Clone)]
struct Position {
    x: usize,
    y: usize,
}

struct Cursor {
    pos: Position,
    lpos: Position,
    color: Color,
}

pub fn run(editor: &mut editor::Editor) {
    let mut cursor = Cursor {
        pos: Position {x: 0, y: 0},
        lpos: Position {x: 0, y: 0},
        color: Color::Red,
    };

    let mut term = Terminal::new().unwrap();
    term[(cursor.pos.x, cursor.pos.y)].set_bg(cursor.color);
    term.swap_buffers().unwrap();

    loop {
        let evt = term.get_event(100).unwrap();
        if let Some(Event::Key(ch)) = evt {
            if editor.command_mode() {
                match ch {
                    'i' => {
                        editor.switch_mode();
                    }
                    'q' => {
                        break;
                    }
                    _ => { }
                }
            } else {
                match ch {
                    '\x1b' => {
                        editor.switch_mode();
                    }
                    '\x7f' => {
                        cursor.lpos = cursor.pos;
                        if cursor.pos.x == 0 {
                            cursor.pos.y = cursor.pos.y.saturating_sub(1);
                        } else {
                            cursor.pos.x -= 1;
                        }
                        term[(cursor.pos.x, cursor.pos.y)].set_ch(' ');
                    }
                    '\r' => {
                        cursor.lpos = cursor.pos;
                        cursor.pos.x = 0;
                        cursor.pos.y += 1;
                    }
                    c @ _ => {
                        term[(cursor.pos.x, cursor.pos.y)].set_ch(c);
                        cursor.lpos = cursor.pos;
                        cursor.pos.x += 1;
                    }
                }
            }

            if cursor.pos.x >= term.cols() - 1 {
                term[(cursor.lpos.x, cursor.lpos.y)].set_bg(Color::Default);
                cursor.lpos = cursor.pos;
                cursor.pos.x = 0;
                cursor.pos.y += 1;
            }
            if cursor.pos.y >= term.rows() - 1 {
                term[(cursor.lpos.x, cursor.lpos.y)].set_bg(Color::Default);
                cursor.lpos = cursor.pos;
                cursor.pos.x = 0;
                cursor.pos.y = 0;
            }

            term[(cursor.lpos.x, cursor.lpos.y)].set_bg(Color::Default);
            term[(cursor.pos.x, cursor.pos.y)].set_bg(cursor.color);
            term.swap_buffers().unwrap();
        }
    }
}
<commit_msg>Basic movement in cmd mode, tabs insert 4 spaces<commit_after>use rustty::{Terminal, Event, Color};
use editor;

#[derive(Copy, Clone)]
struct Position {
    x: usize,
    y: usize,
}

struct Cursor {
    pos: Position,
    lpos: Position,
    color: Color,
}

pub fn run(editor: &mut editor::Editor) {
    let mut cursor = Cursor {
        pos: Position {x: 0, y: 0},
        lpos: Position {x: 0, y: 0},
        color: Color::Red,
    };

    let mut term = Terminal::new().unwrap();
    term[(cursor.pos.x, cursor.pos.y)].set_bg(cursor.color);
    term.swap_buffers().unwrap();

    loop {
        let evt = term.get_event(100).unwrap();
        if let Some(Event::Key(ch)) = evt {
            if editor.command_mode() {
                match ch {
                    'i' => {
                        editor.switch_mode();
                    }
                    'h' => {
                        if cursor.pos.x != 0 {
                            cursor.pos.x -= 1;
                        }
                    }
                    'j' => {
                        // TODO(nokaa): We don't want to go beyond
                        // the working area here.
                        cursor.pos.y += 1;

                    }
                    'k' => {
                        if cursor.pos.y != 0 {
                            cursor.pos.y -= 1;
                        }
                    }
                    'l' => {
                        // TODO(nokaa): We don't want to extend beyond the
                        // line length here, but we first need a way to
                        // determine a given line's length.
                        cursor.pos.x += 1;
                    }
                    'q' => {
                        break;
                    }
                    _ => { }
                }
            } else {
                match ch {
                    '\x1b' => {
                        editor.switch_mode();
                    }
                    '\x7f' => {
                        cursor.lpos = cursor.pos;
                        if cursor.pos.x == 0 {
                            cursor.pos.y = cursor.pos.y.saturating_sub(1);
                        } else {
                            cursor.pos.x -= 1;
                        }
                        term[(cursor.pos.x, cursor.pos.y)].set_ch(' ');
                    }
                    '\r' => {
                        cursor.lpos = cursor.pos;
                        cursor.pos.x = 0;
                        cursor.pos.y += 1;
                    }
                    '\t' => {
                        term[(cursor.pos.x, cursor.pos.y)].set_ch(' ');
                        term[(cursor.pos.x + 1, cursor.pos.y)].set_ch(' ');
                        term[(cursor.pos.x + 2, cursor.pos.y)].set_ch(' ');
                        term[(cursor.pos.x + 3, cursor.pos.y)].set_ch(' ');
                        cursor.lpos = cursor.pos;
                        cursor.pos.x += 4;
                    }
                    c @ _ => {
                        term[(cursor.pos.x, cursor.pos.y)].set_ch(c);
                        cursor.lpos = cursor.pos;
                        cursor.pos.x += 1;
                    }
                }
            }

            if cursor.pos.x >= term.cols() - 1 {
                term[(cursor.lpos.x, cursor.lpos.y)].set_bg(Color::Default);
                cursor.lpos = cursor.pos;
                cursor.pos.x = 0;
                cursor.pos.y += 1;
            }
            if cursor.pos.y >= term.rows() - 1 {
                term[(cursor.lpos.x, cursor.lpos.y)].set_bg(Color::Default);
                cursor.lpos = cursor.pos;
                cursor.pos.x = 0;
                cursor.pos.y = 0;
            }

            term[(cursor.lpos.x, cursor.lpos.y)].set_bg(Color::Default);
            term[(cursor.pos.x, cursor.pos.y)].set_bg(cursor.color);
            term.swap_buffers().unwrap();
        }
    }
}
<|endoftext|>