<commit_before>use std::thread;
use std::sync::mpsc;
use websocket::{Server, Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use std::collections::{HashMap, BitSet};
use std::io::prelude::*;
use std::num::ToPrimitive;
use rustc_serialize::json::{Json, ToJson};

use value::{Value, Tuple};
use index;
use flow::{Changes, FlowState, Flow};
use compiler::{compile, World};

trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Tuple(ref tuple) => tuple.to_json(),
            Value::Relation(ref relation) => Json::Object(vec![
                ("relation".to_string(), relation.iter().map(ToJson::to_json).collect::<Vec<_>>().to_json())
                ].into_iter().collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int.to_f64().unwrap()),
            Json::U64(uint) => Value::Float(uint.to_f64().unwrap()),
            Json::Array(ref array) => Value::Tuple(array.iter().map(|j| Value::from_json(j)).collect()),
            Json::Object(ref object) => {
                assert!(object.len() == 1);
                let relation: Vec<Tuple> = FromJson::from_json(&object["relation"]);
                Value::Relation(relation.into_iter().collect())
            },
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(FromJson::from_json).collect()
    }
}

pub struct Event {
    changes: Changes,
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Object(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    (view_id.to_string(), Json::Object(vec![
                        ("inserted".to_string(), view_changes.inserted.to_json()),
                        ("removed".to_string(), view_changes.removed.to_json()),
                        ].into_iter().collect()))
                }).collect()))].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_object().unwrap().iter().map(|(view_id, view_changes)| {
                (view_id.to_string(), index::Changes{
                    inserted: FromJson::from_json(&view_changes.as_object().unwrap()["inserted"]),
                    removed: FromJson::from_json(&view_changes.as_object().unwrap()["removed"]),
                })
            }).collect()
        }
    }
}

struct Instance {
    input: World,
    flow: Flow,
    output: FlowState,
}

impl Instance {
    pub fn change(&mut self, changes: Changes) -> Changes {
        self.input.change(changes);
        let mut input_clone = self.input.clone();
        let (flow, mut output) = compile(&mut input_clone);
        flow.run(&mut output);
        let changes = flow.changes_since(&output, &self.flow, &self.output);
        self.flow = flow;
        self.output = output;
        changes
    }
}

pub enum ServerEvent {
    Event(Event),
    NewClient(sender::Sender<WebSocketStream>),
}

// TODO holy crap why is everything blocking? this is a mess
pub fn serve() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = Server::bind("127.0.0.1:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();
                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over sender
                event_sender.send(ServerEvent::NewClient(sender)).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = message.unwrap();
                    match message {
                        Message::Text(text) => {
                            let json = Json::from_str(&text).unwrap();
                            let event = FromJson::from_json(&json);
                            event_sender.send(ServerEvent::Event(event)).unwrap();
                        }
                        _ => panic!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn run() {
    let empty_world = World{views: HashMap::new()};
    let empty_flow = Flow{nodes: Vec::new()};
    let empty_output = FlowState{outputs: Vec::new(), dirty: BitSet::new()};
    let mut instance = Instance{
        input: empty_world,
        flow: empty_flow.clone(),
        output: empty_output.clone(),
    };
    let mut senders: Vec<sender::Sender<_>> = Vec::new();
    let event_receiver = serve();
    for event in event_receiver.iter() {
        match event {
            ServerEvent::NewClient(mut sender) => {
                time!("sending initial state", {
                    let changes = instance.flow.changes_since(&instance.output, &empty_flow, &empty_output);
                    let text = format!("{}", Event{changes: changes}.to_json());
                    sender.send_message(Message::Text(text)).unwrap();
                    senders.push(sender)
                })
            }
            ServerEvent::Event(event) => {
                time!("sending update", {
                    let changes = instance.change(event.changes);
                    let text = format!("{}", Event{changes: changes}.to_json());
                    for sender in senders.iter_mut() {
                        sender.send_message(Message::Text(text.clone())).unwrap();
                    }
                })
            }
        }
    }
}<commit_msg>Dont die on close<commit_after>use std::thread;
use std::sync::mpsc;
use websocket::{Server, Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use std::collections::{HashMap, BitSet};
use std::io::prelude::*;
use std::num::ToPrimitive;
use rustc_serialize::json::{Json, ToJson};

use value::{Value, Tuple};
use index;
use flow::{Changes, FlowState, Flow};
use compiler::{compile, World};

trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Tuple(ref tuple) => tuple.to_json(),
            Value::Relation(ref relation) => Json::Object(vec![
                ("relation".to_string(), relation.iter().map(ToJson::to_json).collect::<Vec<_>>().to_json())
                ].into_iter().collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int.to_f64().unwrap()),
            Json::U64(uint) => Value::Float(uint.to_f64().unwrap()),
            Json::Array(ref array) => Value::Tuple(array.iter().map(|j| Value::from_json(j)).collect()),
            Json::Object(ref object) => {
                assert!(object.len() == 1);
                let relation: Vec<Tuple> = FromJson::from_json(&object["relation"]);
                Value::Relation(relation.into_iter().collect())
            },
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(FromJson::from_json).collect()
    }
}

pub struct Event {
    changes: Changes,
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Object(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    (view_id.to_string(), Json::Object(vec![
                        ("inserted".to_string(), view_changes.inserted.to_json()),
                        ("removed".to_string(), view_changes.removed.to_json()),
                        ].into_iter().collect()))
                }).collect()))].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_object().unwrap().iter().map(|(view_id, view_changes)| {
                (view_id.to_string(), index::Changes{
                    inserted: FromJson::from_json(&view_changes.as_object().unwrap()["inserted"]),
                    removed: FromJson::from_json(&view_changes.as_object().unwrap()["removed"]),
                })
            }).collect()
        }
    }
}

struct Instance {
    input: World,
    flow: Flow,
    output: FlowState,
}

impl Instance {
    pub fn change(&mut self, changes: Changes) -> Changes {
        self.input.change(changes);
        let mut input_clone = self.input.clone();
        let (flow, mut output) = compile(&mut input_clone);
        flow.run(&mut output);
        let changes = flow.changes_since(&output, &self.flow, &self.output);
        self.flow = flow;
        self.output = output;
        changes
    }
}

pub enum ServerEvent {
    Event(Event),
    NewClient(sender::Sender<WebSocketStream>),
}

// TODO holy crap why is everything blocking? this is a mess
pub fn serve() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = Server::bind("127.0.0.1:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();
                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over sender
                event_sender.send(ServerEvent::NewClient(sender)).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = message.unwrap();
                    match message {
                        Message::Text(text) => {
                            let json = Json::from_str(&text).unwrap();
                            let event = FromJson::from_json(&json);
                            event_sender.send(ServerEvent::Event(event)).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn run() {
    let empty_world = World{views: HashMap::new()};
    let empty_flow = Flow{nodes: Vec::new()};
    let empty_output = FlowState{outputs: Vec::new(), dirty: BitSet::new()};
    let mut instance = Instance{
        input: empty_world,
        flow: empty_flow.clone(),
        output: empty_output.clone(),
    };
    let mut senders: Vec<sender::Sender<_>> = Vec::new();
    let event_receiver = serve();
    for event in event_receiver.iter() {
        match event {
            ServerEvent::NewClient(mut sender) => {
                time!("sending initial state", {
                    let changes = instance.flow.changes_since(&instance.output, &empty_flow, &empty_output);
                    let text = format!("{}", Event{changes: changes}.to_json());
                    match sender.send_message(Message::Text(text)) {
                        Ok(_) => (),
                        Err(error) => println!("Send error: {}", error),
                    };
                    senders.push(sender)
                })
            }
            ServerEvent::Event(event) => {
                time!("sending update", {
                    let changes = instance.change(event.changes);
                    let text = format!("{}", Event{changes: changes}.to_json());
                    for sender in senders.iter_mut() {
                        match sender.send_message(Message::Text(text.clone())) {
                            Ok(_) => (),
                            Err(error) => println!("Send error: {}", error),
                        };
                    }
                })
            }
        }
    }
}<|endoftext|>


<commit_before>use engine::components::{
    Color, Death, Delete, FactionId, Hp, HpChange, MovedFlag, Pos, Shape, Spawned, UnitTypeTag,
};
use engine::resources::{CumReward, Skip};
use engine::{NeedsKeyInfo, Render};
use specs::prelude::*;

use scaii_defs::protos::Entity as ScaiiEntity;

#[derive(SystemData)]
pub struct RenderSystemData<'a> {
    complete_rerender: Fetch<'a, NeedsKeyInfo>,
    color: ReadStorage<'a, Color>,
    pos: ReadStorage<'a, Pos>,
    shape: ReadStorage<'a, Shape>,
    hp: ReadStorage<'a, Hp>,
    hp_change: ReadStorage<'a, HpChange>,
    faction: ReadStorage<'a, FactionId>,
    moved: ReadStorage<'a, MovedFlag>,
    death: ReadStorage<'a, Death>,
    delete: ReadStorage<'a, Delete>,
    u_type: ReadStorage<'a, UnitTypeTag>,
    ids: Entities<'a>,
    skip: Fetch<'a, Skip>,
    spawn: ReadStorage<'a, Spawned>,
    cum_reward: Fetch<'a, CumReward>,

    out: FetchMut<'a, Render>,
}

#[derive(Default, Copy, Clone, Debug)]
pub struct RenderSystem {}

impl<'a> System<'a> for RenderSystem {
    type SystemData = RenderSystemData<'a>;

    fn run(&mut self, mut sys_data: Self::SystemData) {
        if sys_data.skip.0 {
            return;
        }

        // Workaround, switch to HashMap<String,f64> when we can
        sys_data.out.0.cumulative_rewards = sys_data
            .cum_reward
            .0
            .iter()
            .map(|(k, v)| (k.clone(), format!("{}", v)))
            .collect();

        if sys_data.complete_rerender.0 {
            self.render_all(sys_data);
        } else {
            self.render_delta(sys_data);
        }
    }
}

impl RenderSystem {
    fn render_delta(&mut self, mut sys_data: RenderSystemData) {
        sys_data.out.0.entities.clear();

        for (pos, id) in (&sys_data.pos, &*sys_data.ids).join() {
            if !(sys_data.moved.get(id).is_some()
                || sys_data.death.get(id).is_some()
                || sys_data.delete.get(id).is_some()
                || sys_data.hp_change.get(id).is_some()
                || sys_data.spawn.get(id).is_some())
            {
                continue;
            }

            if sys_data.spawn.get(id).is_some() {
                let entity = self.render_new(
                    &sys_data,
                    id,
                    &*sys_data.color.get(id).unwrap(),
                    pos,
                    &*sys_data.shape.get(id).unwrap(),
                );

                sys_data.out.0.entities.push(entity);

                continue;
            }

            let mut entity = ScaiiEntity {
                id: id.id() as u64,
                pos: Some(pos.to_scaii_pos()),
                delete: sys_data.death.get(id).is_some() || sys_data.delete.get(id).is_some(),
                shapes: vec![],

                ..ScaiiEntity::default()
            };

            if sys_data.hp_change.get(id).is_some() {
                let hp_string = format!("{}", sys_data.hp.get(id).unwrap().curr_hp);
                entity
                    .float_string_metadata
                    .insert("Hitpoints".to_string(), hp_string);
            }

            sys_data.out.0.entities.push(entity);
        }
    }

    fn render_all(&mut self, mut sys_data: RenderSystemData) {
        sys_data.out.0.entities.clear();

        for (color, pos, shape, id) in (
            &sys_data.color,
            &sys_data.pos,
            &sys_data.shape,
            &*sys_data.ids,
        ).join()
        {
            let entity = self.render_new(&sys_data, id, color, pos, shape);
            sys_data.out.0.entities.push(entity);
        }
    }

    fn render_new(
        &mut self,
        sys_data: &RenderSystemData,
        id: Entity,
        color: &Color,
        pos: &Pos,
        shape: &Shape,
    ) -> ScaiiEntity {
        use std::collections::HashMap;

        let mut scaii_shape = shape.to_scaii_shape(0);

        scaii_shape.color = Some(color.to_scaii_color());
        scaii_shape.relative_pos = Some(Pos::new(0.0, 0.0).to_scaii_pos());

        // TODO: maybe keep these around in a pool to reduce allocations?
        //let float_metadata : HashMap<String, f32> = HashMap::with_capacity(1);
        //let mut bool_metadata : HashMap<String, bool> = HashMap::with_capacity(2);
        let mut string_metadata: HashMap<String, String> = HashMap::with_capacity(1);
        let mut bool_string_metadata: HashMap<String, String> = HashMap::with_capacity(2);
        let mut float_string_metadata: HashMap<String, String> = HashMap::with_capacity(2);

        // Special case for us = faction 0 for now, need to switch if we support multi-agent
        // or self-play later.
        let is_friend = sys_data.faction.get(id).unwrap().0 == 0;
        let hp = sys_data.hp.get(id).unwrap();
        let tag = sys_data.u_type.get(id).unwrap();

        /* There's some weirdness with the protobuf library so we need
        to use strings or we get weird undefined values. Hopefully fixable in
        the future.  */
        let hp_string = format!("{}", hp.curr_hp);
        let max_hp_string = format!("{}", hp.max_hp);
        float_string_metadata.insert("Hitpoints".to_string(), hp_string);
        float_string_metadata.insert("Max Hp".to_string(), max_hp_string);

        let enemy_string = format!("{}", !is_friend);
        let friend_string = format!("{}", is_friend);

        bool_string_metadata.insert("Enemy?".to_string(), enemy_string);
        bool_string_metadata.insert("Friend?".to_string(), friend_string);
        string_metadata.insert("Unit Type".to_string(), tag.0.clone());

        ScaiiEntity {
            shapes: vec![scaii_shape],
            id: id.id() as u64,
            delete: sys_data.death.get(id).is_some(),
            pos: Some(pos.to_scaii_pos()),
            float_string_metadata,
            string_metadata,
            bool_string_metadata,
            ..ScaiiEntity::default()
        }
    }
}

#[cfg(test)]
mod tests {
    use engine::components::{Color, MovedFlag, Pos, Shape};
    use engine::Render;

    use super::*;

    #[test]
    fn test_proto_render() {
        use engine::{components, resources};
        use scaii_defs::protos::Color as ScaiiColor;
        use scaii_defs::protos::Pos as ScaiiPos;
        use scaii_defs::protos::Triangle as ScaiiTriangle;

        let mut world = World::new();
        components::register_world_components(&mut world);
        resources::register_world_resources(&mut world);

        let test_target = world
            .create_entity()
            .with(Pos::new(3.0, 9.0))
            .with(Color {
                r: 23,
                b: 124,
                g: 255,
            })
            .with(Hp::default())
            .with(FactionId(0))
            .with(Shape::Triangle { base_len: 23.0 })
            .with(MovedFlag(1))
            .with(UnitTypeTag("Foo".to_string()))
            .build();

        let mut sys: Dispatcher = DispatcherBuilder::new()
            .add(RenderSystem {}, "render", &[])
            .build();

        sys.dispatch(&mut world.res);

        let read_render = world.read_resource::<Render>().0.clone();
        assert!(read_render.entities.len() == 1); // Check that exactly one entity is created

        assert!(read_render.entities[0].delete == false); // Check that entity is alive

        assert!(read_render.entities[0].id == test_target.id().into()); // Check that entity id matches test_target entity

        assert!(
            read_render.entities[0].clone().pos.unwrap() == ScaiiPos {
                x: Some(3.0),
                y: Some(9.0)
            }
        ); // Check that entity positon converted SCAIIPOS correctly

        assert!(read_render.entities[0].clone().shapes[0].id == test_target.id().into()); // Verify that shape entity ID is 0

        assert!(
            read_render.entities[0].shapes[0]
                .relative_pos
                .clone()
                .unwrap() == ScaiiPos {
                x: Some(0.0),
                y: Some(0.0)
            }
        ); // Verify that relative_pos offset is 0

        assert!(
            read_render.entities[0].shapes[0].color.clone().unwrap() == ScaiiColor {
                r: 23,
                g: 255,
                b: 124,
                a: 255
            }
        ); // Verify that entity shape is correct color

        assert!(
            read_render.entities[0].shapes[0].triangle.clone().unwrap() == ScaiiTriangle {
                base_len: Some(23.0)
            }
        ); // Verify entity created is a trangle with base length of 23

        assert!(read_render.entities[0].shapes[0].tag == None);

        assert!(read_render.entities[0].shapes[0].gradient_color == None);

        assert!(read_render.entities[0].shapes[0].delete == false);
    }
}
<commit_msg>Add small change that should fix sending no shape entities<commit_after>use engine::components::{
    Color, Death, Delete, FactionId, Hp, HpChange, MovedFlag, Pos, Shape, Spawned, UnitTypeTag,
};
use engine::resources::{CumReward, Skip};
use engine::{NeedsKeyInfo, Render};
use specs::prelude::*;

use scaii_defs::protos::Entity as ScaiiEntity;

#[derive(SystemData)]
pub struct RenderSystemData<'a> {
    complete_rerender: Fetch<'a, NeedsKeyInfo>,
    color: ReadStorage<'a, Color>,
    pos: ReadStorage<'a, Pos>,
    shape: ReadStorage<'a, Shape>,
    hp: ReadStorage<'a, Hp>,
    hp_change: ReadStorage<'a, HpChange>,
    faction: ReadStorage<'a, FactionId>,
    moved: ReadStorage<'a, MovedFlag>,
    death: ReadStorage<'a, Death>,
    delete: ReadStorage<'a, Delete>,
    u_type: ReadStorage<'a, UnitTypeTag>,
    ids: Entities<'a>,
    skip: Fetch<'a, Skip>,
    spawn: ReadStorage<'a, Spawned>,
    cum_reward: Fetch<'a, CumReward>,

    out: FetchMut<'a, Render>,
}

#[derive(Default, Copy, Clone, Debug)]
pub struct RenderSystem {}

impl<'a> System<'a> for RenderSystem {
    type SystemData = RenderSystemData<'a>;

    fn run(&mut self, mut sys_data: Self::SystemData) {
        if sys_data.skip.0 {
            return;
        }

        // Workaround, switch to HashMap<String,f64> when we can
        sys_data.out.0.cumulative_rewards = sys_data
            .cum_reward
            .0
            .iter()
            .map(|(k, v)| (k.clone(), format!("{}", v)))
            .collect();

        if sys_data.complete_rerender.0 {
            self.render_all(sys_data);
        } else {
            self.render_delta(sys_data);
        }
    }
}

impl RenderSystem {
    fn render_delta(&mut self, mut sys_data: RenderSystemData) {
        sys_data.out.0.entities.clear();

        for (pos, id, _) in (&sys_data.pos, &*sys_data.ids, &sys_data.shape).join() {
            if !(sys_data.moved.get(id).is_some()
                || sys_data.death.get(id).is_some()
                || sys_data.delete.get(id).is_some()
                || sys_data.hp_change.get(id).is_some()
                || sys_data.spawn.get(id).is_some())
            {
                continue;
            }

            if sys_data.spawn.get(id).is_some() {
                let entity = self.render_new(
                    &sys_data,
                    id,
                    &*sys_data.color.get(id).unwrap(),
                    pos,
                    &*sys_data.shape.get(id).unwrap(),
                );

                sys_data.out.0.entities.push(entity);

                continue;
            }

            let mut entity = ScaiiEntity {
                id: id.id() as u64,
                pos: Some(pos.to_scaii_pos()),
                delete: sys_data.death.get(id).is_some() || sys_data.delete.get(id).is_some(),
                shapes: vec![],

                ..ScaiiEntity::default()
            };

            if sys_data.hp_change.get(id).is_some() {
                let hp_string = format!("{}", sys_data.hp.get(id).unwrap().curr_hp);
                entity
                    .float_string_metadata
                    .insert("Hitpoints".to_string(), hp_string);
            }

            sys_data.out.0.entities.push(entity);
        }
    }

    fn render_all(&mut self, mut sys_data: RenderSystemData) {
        sys_data.out.0.entities.clear();

        for (color, pos, shape, id) in (
            &sys_data.color,
            &sys_data.pos,
            &sys_data.shape,
            &*sys_data.ids,
        ).join()
        {
            let entity = self.render_new(&sys_data, id, color, pos, shape);
            sys_data.out.0.entities.push(entity);
        }
    }

    fn render_new(
        &mut self,
        sys_data: &RenderSystemData,
        id: Entity,
        color: &Color,
        pos: &Pos,
        shape: &Shape,
    ) -> ScaiiEntity {
        use std::collections::HashMap;

        let mut scaii_shape = shape.to_scaii_shape(0);

        scaii_shape.color = Some(color.to_scaii_color());
        scaii_shape.relative_pos = Some(Pos::new(0.0, 0.0).to_scaii_pos());

        // TODO: maybe keep these around in a pool to reduce allocations?
        //let float_metadata : HashMap<String, f32> = HashMap::with_capacity(1);
        //let mut bool_metadata : HashMap<String, bool> = HashMap::with_capacity(2);
        let mut string_metadata: HashMap<String, String> = HashMap::with_capacity(1);
        let mut bool_string_metadata: HashMap<String, String> = HashMap::with_capacity(2);
        let mut float_string_metadata: HashMap<String, String> = HashMap::with_capacity(2);

        // Special case for us = faction 0 for now, need to switch if we support multi-agent
        // or self-play later.
        let is_friend = sys_data.faction.get(id).unwrap().0 == 0;
        let hp = sys_data.hp.get(id).unwrap();
        let tag = sys_data.u_type.get(id).unwrap();

        /* There's some weirdness with the protobuf library so we need
        to use strings or we get weird undefined values. Hopefully fixable in
        the future.  */
        let hp_string = format!("{}", hp.curr_hp);
        let max_hp_string = format!("{}", hp.max_hp);
        float_string_metadata.insert("Hitpoints".to_string(), hp_string);
        float_string_metadata.insert("Max Hp".to_string(), max_hp_string);

        let enemy_string = format!("{}", !is_friend);
        let friend_string = format!("{}", is_friend);

        bool_string_metadata.insert("Enemy?".to_string(), enemy_string);
        bool_string_metadata.insert("Friend?".to_string(), friend_string);
        string_metadata.insert("Unit Type".to_string(), tag.0.clone());

        ScaiiEntity {
            shapes: vec![scaii_shape],
            id: id.id() as u64,
            delete: sys_data.death.get(id).is_some(),
            pos: Some(pos.to_scaii_pos()),
            float_string_metadata,
            string_metadata,
            bool_string_metadata,
            ..ScaiiEntity::default()
        }
    }
}

#[cfg(test)]
mod tests {
    use engine::components::{Color, MovedFlag, Pos, Shape};
    use engine::Render;

    use super::*;

    #[test]
    fn test_proto_render() {
        use engine::{components, resources};
        use scaii_defs::protos::Color as ScaiiColor;
        use scaii_defs::protos::Pos as ScaiiPos;
        use scaii_defs::protos::Triangle as ScaiiTriangle;

        let mut world = World::new();
        components::register_world_components(&mut world);
        resources::register_world_resources(&mut world);

        let test_target = world
            .create_entity()
            .with(Pos::new(3.0, 9.0))
            .with(Color {
                r: 23,
                b: 124,
                g: 255,
            })
            .with(Hp::default())
            .with(FactionId(0))
            .with(Shape::Triangle { base_len: 23.0 })
            .with(MovedFlag(1))
            .with(UnitTypeTag("Foo".to_string()))
            .build();

        let mut sys: Dispatcher = DispatcherBuilder::new()
            .add(RenderSystem {}, "render", &[])
            .build();

        sys.dispatch(&mut world.res);

        let read_render = world.read_resource::<Render>().0.clone();
        assert!(read_render.entities.len() == 1); // Check that exactly one entity is created

        assert!(read_render.entities[0].delete == false); // Check that entity is alive

        assert!(read_render.entities[0].id == test_target.id().into()); // Check that entity id matches test_target entity

        assert!(
            read_render.entities[0].clone().pos.unwrap() == ScaiiPos {
                x: Some(3.0),
                y: Some(9.0)
            }
        ); // Check that entity positon converted SCAIIPOS correctly

        assert!(read_render.entities[0].clone().shapes[0].id == test_target.id().into()); // Verify that shape entity ID is 0

        assert!(
            read_render.entities[0].shapes[0]
                .relative_pos
                .clone()
                .unwrap() == ScaiiPos {
                x: Some(0.0),
                y: Some(0.0)
            }
        ); // Verify that relative_pos offset is 0

        assert!(
            read_render.entities[0].shapes[0].color.clone().unwrap() == ScaiiColor {
                r: 23,
                g: 255,
                b: 124,
                a: 255
            }
        ); // Verify that entity shape is correct color

        assert!(
            read_render.entities[0].shapes[0].triangle.clone().unwrap() == ScaiiTriangle {
                base_len: Some(23.0)
            }
        ); // Verify entity created is a trangle with base length of 23

        assert!(read_render.entities[0].shapes[0].tag == None);

        assert!(read_render.entities[0].shapes[0].gradient_color == None);

        assert!(read_render.entities[0].shapes[0].delete == false);
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The `ToStr` trait for converting to strings

*/

use str::OwnedStr;
use hashmap::HashMap;
use hashmap::HashSet;
use container::Map;
use hash::Hash;
use cmp::Eq;
use old_iter::BaseIter;

/// A generic trait for converting a value to a string
pub trait ToStr {
    /// Converts the value of `self` to an owned string
    fn to_str(&self) -> ~str;
}

/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
    /// Cosume and convert to a string.
    fn to_str_consume(self) -> ~str;
}

impl ToStr for () {
    #[inline(always)]
    fn to_str(&self) -> ~str { ~"()" }
}

impl<A:ToStr> ToStr for (A,) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        match *self {
            (ref a,) => {
                ~"(" + a.to_str() + ",)"
            }
        }
    }
}

impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |key, value| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(key.to_str());
            acc.push_str(": ");
            acc.push_str(value.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |element| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(element.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr,B:ToStr> ToStr for (A, B) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4760): this causes an llvm assertion
        //let &(ref a, ref b) = self;
        match *self {
            (ref a, ref b) => {
                ~"(" + a.to_str() + ", " + b.to_str() + ")"
            }
        }
    }
}

impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4760): this causes an llvm assertion
        //let &(ref a, ref b, ref c) = self;
        match *self {
            (ref a, ref b, ref c) => {
                fmt!("(%s, %s, %s)",
                    (*a).to_str(),
                    (*b).to_str(),
                    (*c).to_str()
                )
            }
        }
    }
}

impl<'self,A:ToStr> ToStr for &'self [A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for ~[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for @[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
    use hashmap::HashMap;
    use hashmap::HashSet;
    use container::Set;
    #[test]
    fn test_simple_types() {
        assert_eq!(1i.to_str(), ~"1");
        assert_eq!((-1i).to_str(), ~"-1");
        assert_eq!(200u.to_str(), ~"200");
        assert_eq!(2u8.to_str(), ~"2");
        assert_eq!(true.to_str(), ~"true");
        assert_eq!(false.to_str(), ~"false");
        assert_eq!(().to_str(), ~"()");
        assert_eq!((~"hi").to_str(), ~"hi");
        assert_eq!((@"hi").to_str(), ~"hi");
    }

    #[test]
    fn test_tuple_types() {
        assert_eq!((1, 2).to_str(), ~"(1, 2)");
        assert_eq!((~"a", ~"b", false).to_str(), ~"(a, b, false)");
        assert_eq!(((), ((), 100)).to_str(), ~"((), ((), 100))");
    }

    #[test]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert_eq!(x.to_str(), ~"[]");
        assert_eq!((~[1]).to_str(), ~"[1]");
        assert_eq!((~[1, 2, 3]).to_str(), ~"[1, 2, 3]");
        assert!((~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"[[], [1], [1, 1]]");
    }

    #[test]
    fn test_hashmap() {
        let mut table: HashMap<int, int> = HashMap::new();
        let empty: HashMap<int, int> = HashMap::new();

        table.insert(3, 4);
        table.insert(1, 2);

        let table_str = table.to_str();

        assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}");
        assert_eq!(empty.to_str(), ~"{}");
    }

    #[test]
    fn test_hashset() {
        let mut set: HashSet<int> = HashSet::new();
        let empty_set: HashSet<int> = HashSet::new();

        set.insert(1);
        set.insert(2);

        let set_str = set.to_str();

        assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}");
        assert_eq!(empty_set.to_str(), ~"{}");
    }
}
<commit_msg>auto merge of #6975 : artagnon/rust/tuple-tostr, r=bstrie<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The `ToStr` trait for converting to strings

*/

use str::OwnedStr;
use hashmap::HashMap;
use hashmap::HashSet;
use container::Map;
use hash::Hash;
use cmp::Eq;
use old_iter::BaseIter;

/// A generic trait for converting a value to a string
pub trait ToStr {
    /// Converts the value of `self` to an owned string
    fn to_str(&self) -> ~str;
}

/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
    /// Cosume and convert to a string.
    fn to_str_consume(self) -> ~str;
}

impl ToStr for () {
    #[inline(always)]
    fn to_str(&self) -> ~str { ~"()" }
}

impl<A:ToStr> ToStr for (A,) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        match *self {
            (ref a,) => {
                fmt!("(%s,)", (*a).to_str())
            }
        }
    }
}

impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |key, value| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(key.to_str());
            acc.push_str(": ");
            acc.push_str(value.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |element| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(element.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr,B:ToStr> ToStr for (A, B) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b) = self;
        match *self {
            (ref a, ref b) => {
                fmt!("(%s, %s)", (*a).to_str(), (*b).to_str())
            }
        }
    }
}

impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b, ref c) = self;
        match *self {
            (ref a, ref b, ref c) => {
                fmt!("(%s, %s, %s)",
                    (*a).to_str(),
                    (*b).to_str(),
                    (*c).to_str()
                )
            }
        }
    }
}

impl<'self,A:ToStr> ToStr for &'self [A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for ~[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for @[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
    use hashmap::HashMap;
    use hashmap::HashSet;
    use container::Set;
    #[test]
    fn test_simple_types() {
        assert_eq!(1i.to_str(), ~"1");
        assert_eq!((-1i).to_str(), ~"-1");
        assert_eq!(200u.to_str(), ~"200");
        assert_eq!(2u8.to_str(), ~"2");
        assert_eq!(true.to_str(), ~"true");
        assert_eq!(false.to_str(), ~"false");
        assert_eq!(().to_str(), ~"()");
        assert_eq!((~"hi").to_str(), ~"hi");
        assert_eq!((@"hi").to_str(), ~"hi");
    }

    #[test]
    fn test_tuple_types() {
        assert_eq!((1, 2).to_str(), ~"(1, 2)");
        assert_eq!((~"a", ~"b", false).to_str(), ~"(a, b, false)");
        assert_eq!(((), ((), 100)).to_str(), ~"((), ((), 100))");
    }

    #[test]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert_eq!(x.to_str(), ~"[]");
        assert_eq!((~[1]).to_str(), ~"[1]");
        assert_eq!((~[1, 2, 3]).to_str(), ~"[1, 2, 3]");
        assert!((~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"[[], [1], [1, 1]]");
    }

    #[test]
    fn test_hashmap() {
        let mut table: HashMap<int, int> = HashMap::new();
        let empty: HashMap<int, int> = HashMap::new();

        table.insert(3, 4);
        table.insert(1, 2);

        let table_str = table.to_str();

        assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}");
        assert_eq!(empty.to_str(), ~"{}");
    }

    #[test]
    fn test_hashset() {
        let mut set: HashSet<int> = HashSet::new();
        let empty_set: HashSet<int> = HashSet::new();

        set.insert(1);
        set.insert(2);

        let set_str = set.to_str();

        assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}");
        assert_eq!(empty_set.to_str(), ~"{}");
    }
}
<|endoftext|>


<commit_before>use chrono::{DateTime, FixedOffset};
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::deserialize_sync_user;
use model::*;

#[cfg(feature = "model")]
use std::borrow::Cow;
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(all(feature = "cache", feature = "model"))]
use internal::prelude::*;
#[cfg(all(feature = "cache", feature = "model"))]
use http;
#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
use builder::EditMember;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use utils::Colour;

pub trait BanOptions {
    fn dmd(&self) -> u8 { 0 }
    fn reason(&self) -> &str { "" }
}

impl BanOptions for u8 {
    fn dmd(&self) -> u8 { *self }
}

impl BanOptions for str {
    fn reason(&self) -> &str { self }
}

impl BanOptions for String {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for (u8, &'a str) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { self.1 }
}

impl BanOptions for (u8, String) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { &self.1 }
}

/// Information about a member of a guild.
#[derive(Clone, Debug, Deserialize)]
pub struct Member {
    /// Indicator of whether the member can hear in voice channels.
    pub deaf: bool,
    /// The unique Id of the guild that the member is a part of.
    pub guild_id: GuildId,
    /// Timestamp representing the date when the member joined.
    pub joined_at: Option<DateTime<FixedOffset>>,
    /// Indicator of whether the member can speak in voice channels.
    pub mute: bool,
    /// The member's nickname, if present.
    ///
    /// Can't be longer than 32 characters.
    pub nick: Option<String>,
    /// Vector of Ids of [`Role`]s given to the member.
    pub roles: Vec<RoleId>,
    /// Attached User struct.
    #[serde(deserialize_with = "deserialize_sync_user")]
    pub user: Arc<RwLock<User>>,
}

#[cfg(feature = "model")]
impl Member {
    /// Adds a [`Role`] to the member, editing its roles in-place if the request
    /// was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::add_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.push(role_id);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Adds one or multiple [`Role`]s to the member, editing
    /// its roles in-place if the request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.extend_from_slice(role_ids);

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.retain(|r| !role_ids.contains(r));

                Err(why)
            },
        }
    }

    /// Ban the member from its guild, deleting the last X number of
    /// days' worth of messages.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    ///
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn ban<BO: BanOptions>(&self, ban_options: BO) -> Result<()> {
        let dmd = ban_options.dmd();
        if dmd > 7 {
            return Err(Error::Model(ModelError::DeleteMessageDaysAmount(dmd)));
        }

        let reason = ban_options.reason();

        if reason.len() > 512 {
            return Err(Error::ExceededLimit(reason.to_string(), 512));
        }

        http::ban_user(
            self.guild_id.0,
            self.user.read().unwrap().id.0,
            dmd,
            &*reason,
        )
    }

    /// Determines the member's colour.
    #[cfg(all(feature = "cache", feature = "utils"))]
    pub fn colour(&self) -> Option<Colour> {
        let cache = CACHE.read().unwrap();
        let guild = match cache.guilds.get(&self.guild_id) {
            Some(guild) => guild.read().unwrap(),
            None => return None,
        };

        let mut roles = self.roles
            .iter()
            .filter_map(|role_id| guild.roles.get(role_id))
            .collect::<Vec<&Role>>();
        roles.sort_by(|a, b| b.cmp(a));

        let default = Colour::default();

        roles
            .iter()
            .find(|r| r.colour.0 != default.0)
            .map(|r| r.colour)
    }

    /// Calculates the member's display name.
    ///
    /// The nickname takes priority over the member's username if it exists.
    #[inline]
    pub fn display_name(&self) -> Cow<String> {
        self.nick
            .as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(self.user.read().unwrap().name.clone()))
    }

    /// Returns the DiscordTag of a Member, taking possible nickname into account.
    #[inline]
    pub fn distinct(&self) -> String {
        format!(
            "{}#{}",
            self.display_name(),
            self.user.read().unwrap().discriminator
        )
    }

    /// Edits the member with the given data. See [`Guild::edit_member`] for
    /// more information.
    ///
    /// See [`EditMember`] for the permission(s) required for separate builder
    /// methods, as well as usage of this.
    ///
    /// [`Guild::edit_member`]: ../model/struct.Guild.html#method.edit_member
    /// [`EditMember`]: ../builder/struct.EditMember.html
    #[cfg(feature = "cache")]
    pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
        let map = f(EditMember::default()).0;

        http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map)
    }

    /// Kick the member from the guild.
    ///
    /// **Note**: Requires the [Kick Members] permission.
    ///
    /// # Examples
    ///
    /// Kick a member from its guild:
    ///
    /// ```rust,ignore
    /// // assuming a `member` has already been bound
    /// match member.kick() {
    ///     Ok(()) => println!("Successfully kicked member"),
    ///     Err(Error::Model(ModelError::GuildNotFound)) => {
    ///         println!("Couldn't determine guild of member");
    ///     },
    ///     Err(Error::Model(ModelError::InvalidPermissions(missing_perms))) => {
    ///         println!("Didn't have permissions; missing: {:?}", missing_perms);
    ///     },
    ///     _ => {},
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the Id of the member's guild
    /// could not be determined.
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform the kick.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
    pub fn kick(&self) -> Result<()> {
        #[cfg(feature = "cache")]
        {
            let req = Permissions::KICK_MEMBERS;

            let has_perms = CACHE
                .read()
                .unwrap()
                .guilds
                .get(&self.guild_id)
                .map(|guild| guild.read().unwrap().has_perms(req));

            if let Some(Ok(false)) = has_perms {
                return Err(Error::Model(ModelError::InvalidPermissions(req)));
            }
        }

        self.guild_id.kick(self.user.read().unwrap().id)
    }

    /// Returns the permissions for the member.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assuming there's a `member` variable gotten from anything.
    /// println!("The permission bits for the member are: {}",
    /// member.permissions().expect("permissions").bits);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild the member's in could not be
    /// found in the cache.
    ///
    /// And/or returns [`ModelError::ItemMissing`] if the "default channel" of the guild is not
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::ItemMissing`]: enum.ModelError.html#variant.ItemMissing
    #[cfg(feature = "cache")]
    pub fn permissions(&self) -> Result<Permissions> {
        let guild = match self.guild_id.find() {
            Some(guild) => guild,
            None => return Err(From::from(ModelError::GuildNotFound)),
        };

        let guild = guild.read().unwrap();

        let default_channel = match guild.default_channel() {
            Some(dc) => dc,
            None => return Err(From::from(ModelError::ItemMissing)),
        };

        Ok(
            guild
                .permissions_for(default_channel.id, self.user.read().unwrap().id),
        )
    }

    /// Removes a [`Role`] from the member, editing its roles in-place if the
    /// request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if !self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::remove_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.retain(|r| r.0 != role_id.0);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Removes one or multiple [`Role`]s from the member.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.retain(|r| !role_ids.contains(r));

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.extend_from_slice(role_ids);

                Err(why)
            },
        }
    }

    /// Retrieves the full role data for the user's roles.
    ///
    /// This is shorthand for manually searching through the CACHE.
    ///
    /// If role data can not be found for the member, then `None` is returned.
    #[cfg(feature = "cache")]
    pub fn roles(&self) -> Option<Vec<Role>> {
        CACHE
            .read()
            .unwrap()
            .guilds
            .values()
            .find(|guild| {
                guild.read().unwrap().members.values().any(|m| {
                    m.user.read().unwrap().id == self.user.read().unwrap().id &&
                    m.joined_at == self.joined_at
                })
            })
            .map(|guild| {
                guild
                    .read()
                    .unwrap()
                    .roles
                    .values()
                    .filter(|role| self.roles.contains(&role.id))
                    .cloned()
                    .collect()
            })
    }

    /// Unbans the [`User`] from the guild.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform bans.
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`User`]: struct.User.html
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn unban(&self) -> Result<()> {
        http::remove_ban(self.guild_id.0, self.user.read().unwrap().id.0)
    }
}

impl Display for Member {
    /// Mentions the user so that they receive a notification.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assumes a `member` has already been bound
    /// println!("{} is a member!", member);
    /// ```
    ///
    // This is in the format of `<@USER_ID>`.
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        Display::fmt(&self.user.read().unwrap().mention(), f)
    }
}
<commit_msg>Add an impl for `&str`<commit_after>use chrono::{DateTime, FixedOffset};
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::deserialize_sync_user;
use model::*;

#[cfg(feature = "model")]
use std::borrow::Cow;
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(all(feature = "cache", feature = "model"))]
use internal::prelude::*;
#[cfg(all(feature = "cache", feature = "model"))]
use http;
#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
use builder::EditMember;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use utils::Colour;

pub trait BanOptions {
    fn dmd(&self) -> u8 { 0 }
    fn reason(&self) -> &str { "" }
}

impl BanOptions for u8 {
    fn dmd(&self) -> u8 { *self }
}

impl BanOptions for str {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for &'a str {
    fn reason(&self) -> &str { self }
}

impl BanOptions for String {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for (u8, &'a str) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { self.1 }
}

impl BanOptions for (u8, String) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { &self.1 }
}

/// Information about a member of a guild.
#[derive(Clone, Debug, Deserialize)]
pub struct Member {
    /// Indicator of whether the member can hear in voice channels.
    pub deaf: bool,
    /// The unique Id of the guild that the member is a part of.
    pub guild_id: GuildId,
    /// Timestamp representing the date when the member joined.
    pub joined_at: Option<DateTime<FixedOffset>>,
    /// Indicator of whether the member can speak in voice channels.
    pub mute: bool,
    /// The member's nickname, if present.
    ///
    /// Can't be longer than 32 characters.
    pub nick: Option<String>,
    /// Vector of Ids of [`Role`]s given to the member.
    pub roles: Vec<RoleId>,
    /// Attached User struct.
    #[serde(deserialize_with = "deserialize_sync_user")]
    pub user: Arc<RwLock<User>>,
}

#[cfg(feature = "model")]
impl Member {
    /// Adds a [`Role`] to the member, editing its roles in-place if the request
    /// was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::add_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.push(role_id);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Adds one or multiple [`Role`]s to the member, editing
    /// its roles in-place if the request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.extend_from_slice(role_ids);

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.retain(|r| !role_ids.contains(r));

                Err(why)
            },
        }
    }

    /// Ban the member from its guild, deleting the last X number of
    /// days' worth of messages.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    ///
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn ban<BO: BanOptions>(&self, ban_options: BO) -> Result<()> {
        let dmd = ban_options.dmd();
        if dmd > 7 {
            return Err(Error::Model(ModelError::DeleteMessageDaysAmount(dmd)));
        }

        let reason = ban_options.reason();

        if reason.len() > 512 {
            return Err(Error::ExceededLimit(reason.to_string(), 512));
        }

        http::ban_user(
            self.guild_id.0,
            self.user.read().unwrap().id.0,
            dmd,
            &*reason,
        )
    }

    /// Determines the member's colour.
    #[cfg(all(feature = "cache", feature = "utils"))]
    pub fn colour(&self) -> Option<Colour> {
        let cache = CACHE.read().unwrap();
        let guild = match cache.guilds.get(&self.guild_id) {
            Some(guild) => guild.read().unwrap(),
            None => return None,
        };

        let mut roles = self.roles
            .iter()
            .filter_map(|role_id| guild.roles.get(role_id))
            .collect::<Vec<&Role>>();
        roles.sort_by(|a, b| b.cmp(a));

        let default = Colour::default();

        roles
            .iter()
            .find(|r| r.colour.0 != default.0)
            .map(|r| r.colour)
    }

    /// Calculates the member's display name.
    ///
    /// The nickname takes priority over the member's username if it exists.
    #[inline]
    pub fn display_name(&self) -> Cow<String> {
        self.nick
            .as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(self.user.read().unwrap().name.clone()))
    }

    /// Returns the DiscordTag of a Member, taking possible nickname into account.
    #[inline]
    pub fn distinct(&self) -> String {
        format!(
            "{}#{}",
            self.display_name(),
            self.user.read().unwrap().discriminator
        )
    }

    /// Edits the member with the given data. See [`Guild::edit_member`] for
    /// more information.
    ///
    /// See [`EditMember`] for the permission(s) required for separate builder
    /// methods, as well as usage of this.
    ///
    /// [`Guild::edit_member`]: ../model/struct.Guild.html#method.edit_member
    /// [`EditMember`]: ../builder/struct.EditMember.html
    #[cfg(feature = "cache")]
    pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
        let map = f(EditMember::default()).0;

        http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map)
    }

    /// Kick the member from the guild.
    ///
    /// **Note**: Requires the [Kick Members] permission.
    ///
    /// # Examples
    ///
    /// Kick a member from its guild:
    ///
    /// ```rust,ignore
    /// // assuming a `member` has already been bound
    /// match member.kick() {
    ///     Ok(()) => println!("Successfully kicked member"),
    ///     Err(Error::Model(ModelError::GuildNotFound)) => {
    ///         println!("Couldn't determine guild of member");
    ///     },
    ///     Err(Error::Model(ModelError::InvalidPermissions(missing_perms))) => {
    ///         println!("Didn't have permissions; missing: {:?}", missing_perms);
    ///     },
    ///     _ => {},
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the Id of the member's guild
    /// could not be determined.
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform the kick.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
    pub fn kick(&self) -> Result<()> {
        #[cfg(feature = "cache")]
        {
            let req = Permissions::KICK_MEMBERS;

            let has_perms = CACHE
                .read()
                .unwrap()
                .guilds
                .get(&self.guild_id)
                .map(|guild| guild.read().unwrap().has_perms(req));

            if let Some(Ok(false)) = has_perms {
                return Err(Error::Model(ModelError::InvalidPermissions(req)));
            }
        }

        self.guild_id.kick(self.user.read().unwrap().id)
    }

    /// Returns the permissions for the member.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assuming there's a `member` variable gotten from anything.
    /// println!("The permission bits for the member are: {}",
    /// member.permissions().expect("permissions").bits);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild the member's in could not be
    /// found in the cache.
    ///
    /// And/or returns [`ModelError::ItemMissing`] if the "default channel" of the guild is not
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::ItemMissing`]: enum.ModelError.html#variant.ItemMissing
    #[cfg(feature = "cache")]
    pub fn permissions(&self) -> Result<Permissions> {
        let guild = match self.guild_id.find() {
            Some(guild) => guild,
            None => return Err(From::from(ModelError::GuildNotFound)),
        };

        let guild = guild.read().unwrap();

        let default_channel = match guild.default_channel() {
            Some(dc) => dc,
            None => return Err(From::from(ModelError::ItemMissing)),
        };

        Ok(
            guild
                .permissions_for(default_channel.id, self.user.read().unwrap().id),
        )
    }

    /// Removes a [`Role`] from the member, editing its roles in-place if the
    /// request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if !self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::remove_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.retain(|r| r.0 != role_id.0);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Removes one or multiple [`Role`]s from the member.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.retain(|r| !role_ids.contains(r));

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.extend_from_slice(role_ids);

                Err(why)
            },
        }
    }

    /// Retrieves the full role data for the user's roles.
    ///
    /// This is shorthand for manually searching through the CACHE.
    ///
    /// If role data can not be found for the member, then `None` is returned.
    #[cfg(feature = "cache")]
    pub fn roles(&self) -> Option<Vec<Role>> {
        CACHE
            .read()
            .unwrap()
            .guilds
            .values()
            .find(|guild| {
                guild.read().unwrap().members.values().any(|m| {
                    m.user.read().unwrap().id == self.user.read().unwrap().id &&
                    m.joined_at == self.joined_at
                })
            })
            .map(|guild| {
                guild
                    .read()
                    .unwrap()
                    .roles
                    .values()
                    .filter(|role| self.roles.contains(&role.id))
                    .cloned()
                    .collect()
            })
    }

    /// Unbans the [`User`] from the guild.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform bans.
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`User`]: struct.User.html
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn unban(&self) -> Result<()> {
        http::remove_ban(self.guild_id.0, self.user.read().unwrap().id.0)
    }
}

impl Display for Member {
    /// Mentions the user so that they receive a notification.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assumes a `member` has already been bound
    /// println!("{} is a member!", member);
    /// ```
    ///
    // This is in the format of `<@USER_ID>`.
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        Display::fmt(&self.user.read().unwrap().mention(), f)
    }
}
<|endoftext|>


<commit_before>use std::ops::ControlFlow::{self, Break, Continue};

use chalk_ir::{
    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
    DebruijnIndex,
};
use hir_def::{
    adt::VariantData, attr::Attrs, type_ref::ConstScalar, visibility::Visibility, AdtId,
    EnumVariantId, HasModule, Lookup, ModuleId, VariantId,
};

use crate::{
    db::HirDatabase, Binders, ConcreteConst, Const, ConstValue, Interner, Substitution, Ty, TyKind,
};

pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool {
    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
    let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
    inhabitedness == BREAK_VISIBLY_UNINHABITED
}

pub(crate) fn is_enum_variant_uninhabited_from(
    variant: EnumVariantId,
    subst: &Substitution,
    target_mod: ModuleId,
    db: &dyn HirDatabase,
) -> bool {
    let enum_data = db.enum_data(variant.parent);
    let vars_attrs = db.variants_attrs(variant.parent);
    let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate();

    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
    let inhabitedness = uninhabited_from.visit_variant(
        variant.into(),
        &enum_data.variants[variant.local_id].variant_data,
        subst,
        &vars_attrs[variant.local_id],
        is_local,
    );
    inhabitedness == BREAK_VISIBLY_UNINHABITED
}

struct UninhabitedFrom<'a> {
    target_mod: ModuleId,
    db: &'a dyn HirDatabase,
}

const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
const BREAK_VISIBLY_UNINHABITED: ControlFlow<VisiblyUninhabited> = Break(VisiblyUninhabited);
#[derive(PartialEq, Eq)]
struct VisiblyUninhabited;

impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
    type BreakTy = VisiblyUninhabited;

    fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = VisiblyUninhabited> {
        self
    }

    fn visit_ty(
        &mut self,
        ty: &Ty,
        outer_binder: DebruijnIndex,
    ) -> ControlFlow<VisiblyUninhabited> {
        match ty.kind(Interner) {
            TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst),
            TyKind::Never => BREAK_VISIBLY_UNINHABITED,
            TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder),
            TyKind::Array(item_ty, len) => match try_usize_const(len) {
                Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
                Some(1..) => item_ty.super_visit_with(self, outer_binder),
            },

            TyKind::Ref(..) | _ => CONTINUE_OPAQUELY_INHABITED,
        }
    }

    fn interner(&self) -> Interner {
        Interner
    }
}

impl UninhabitedFrom<'_> {
    fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
        let attrs = self.db.attrs(adt.into());
        let adt_non_exhaustive = attrs.by_key("non_exhaustive").exists();
        let is_local = adt.module(self.db.upcast()).krate() == self.target_mod.krate();
        if adt_non_exhaustive && !is_local {
            return CONTINUE_OPAQUELY_INHABITED;
        }

        // An ADT is uninhabited iff all its variants uninhabited.
        match adt {
            // rustc: For now, `union`s are never considered uninhabited.
            AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
            AdtId::StructId(s) => {
                let struct_data = self.db.struct_data(s);
                self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local)
            }
            AdtId::EnumId(e) => {
                let vars_attrs = self.db.variants_attrs(e);
                let enum_data = self.db.enum_data(e);

                for (local_id, enum_var) in enum_data.variants.iter() {
                    let variant_inhabitedness = self.visit_variant(
                        EnumVariantId { parent: e, local_id }.into(),
                        &enum_var.variant_data,
                        subst,
                        &vars_attrs[local_id],
                        is_local,
                    );
                    match variant_inhabitedness {
                        Break(VisiblyUninhabited) => continue,
                        Continue(()) => return CONTINUE_OPAQUELY_INHABITED,
                    }
                }
                BREAK_VISIBLY_UNINHABITED
            }
        }
    }

    fn visit_variant(
        &mut self,
        variant: VariantId,
        variant_data: &VariantData,
        subst: &Substitution,
        attrs: &Attrs,
        is_local: bool,
    ) -> ControlFlow<VisiblyUninhabited> {
        let non_exhaustive_field_list = attrs.by_key("non_exhaustive").exists();
        if non_exhaustive_field_list && !is_local {
            return CONTINUE_OPAQUELY_INHABITED;
        }

        let is_enum = matches!(variant, VariantId::EnumVariantId(..));
        let field_tys = self.db.field_types(variant);
        let field_vis = self.db.field_visibilities(variant);

        for (fid, _) in variant_data.fields().iter() {
            self.visit_field(field_vis[fid], &field_tys[fid], subst, is_enum)?;
        }
        CONTINUE_OPAQUELY_INHABITED
    }

    fn visit_field(
        &mut self,
        vis: Visibility,
        ty: &Binders<Ty>,
        subst: &Substitution,
        is_enum: bool,
    ) -> ControlFlow<VisiblyUninhabited> {
        let target_mod = self.target_mod;
        let mut data_uninhabitedness =
            || ty.clone().substitute(Interner, subst).visit_with(self, DebruijnIndex::INNERMOST);
        if is_enum {
            data_uninhabitedness()
        } else {
            match vis {
                Visibility::Module(mod_id) if mod_id == target_mod => data_uninhabitedness(),
                Visibility::Module(_) => CONTINUE_OPAQUELY_INHABITED,
                Visibility::Public => data_uninhabitedness(),
            }
        }
    }
}

fn try_usize_const(c: &Const) -> Option<u128> {
    let data = &c.data(Interner);
    if data.ty.kind(Interner) != &TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)) {
        return None;
    }
    match data.value {
        ConstValue::Concrete(ConcreteConst { interned: ConstScalar::UInt(value) }) => Some(value),
        _ => None,
    }
}
<commit_msg>Correct visibility check<commit_after>use std::ops::ControlFlow::{self, Break, Continue};

use chalk_ir::{
    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
    DebruijnIndex,
};
use hir_def::{
    adt::VariantData, attr::Attrs, type_ref::ConstScalar, visibility::Visibility, AdtId,
    EnumVariantId, HasModule, Lookup, ModuleId, VariantId,
};

use crate::{
    db::HirDatabase, Binders, ConcreteConst, Const, ConstValue, Interner, Substitution, Ty, TyKind,
};

pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool {
    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
    let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
    inhabitedness == BREAK_VISIBLY_UNINHABITED
}

pub(crate) fn is_enum_variant_uninhabited_from(
    variant: EnumVariantId,
    subst: &Substitution,
    target_mod: ModuleId,
    db: &dyn HirDatabase,
) -> bool {
    let enum_data = db.enum_data(variant.parent);
    let vars_attrs = db.variants_attrs(variant.parent);
    let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate();

    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
    let inhabitedness = uninhabited_from.visit_variant(
        variant.into(),
        &enum_data.variants[variant.local_id].variant_data,
        subst,
        &vars_attrs[variant.local_id],
        is_local,
    );
    inhabitedness == BREAK_VISIBLY_UNINHABITED
}

struct UninhabitedFrom<'a> {
    target_mod: ModuleId,
    db: &'a dyn HirDatabase,
}

const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
const BREAK_VISIBLY_UNINHABITED: ControlFlow<VisiblyUninhabited> = Break(VisiblyUninhabited);
#[derive(PartialEq, Eq)]
struct VisiblyUninhabited;

impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
    type BreakTy = VisiblyUninhabited;

    fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = VisiblyUninhabited> {
        self
    }

    fn visit_ty(
        &mut self,
        ty: &Ty,
        outer_binder: DebruijnIndex,
    ) -> ControlFlow<VisiblyUninhabited> {
        match ty.kind(Interner) {
            TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst),
            TyKind::Never => BREAK_VISIBLY_UNINHABITED,
            TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder),
            TyKind::Array(item_ty, len) => match try_usize_const(len) {
                Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
                Some(1..) => item_ty.super_visit_with(self, outer_binder),
            },

            TyKind::Ref(..) | _ => CONTINUE_OPAQUELY_INHABITED,
        }
    }

    fn interner(&self) -> Interner {
        Interner
    }
}

impl UninhabitedFrom<'_> {
    fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
        let attrs = self.db.attrs(adt.into());
        let adt_non_exhaustive = attrs.by_key("non_exhaustive").exists();
        let is_local = adt.module(self.db.upcast()).krate() == self.target_mod.krate();
        if adt_non_exhaustive && !is_local {
            return CONTINUE_OPAQUELY_INHABITED;
        }

        // An ADT is uninhabited iff all its variants uninhabited.
        match adt {
            // rustc: For now, `union`s are never considered uninhabited.
            AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
            AdtId::StructId(s) => {
                let struct_data = self.db.struct_data(s);
                self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local)
            }
            AdtId::EnumId(e) => {
                let vars_attrs = self.db.variants_attrs(e);
                let enum_data = self.db.enum_data(e);

                for (local_id, enum_var) in enum_data.variants.iter() {
                    let variant_inhabitedness = self.visit_variant(
                        EnumVariantId { parent: e, local_id }.into(),
                        &enum_var.variant_data,
                        subst,
                        &vars_attrs[local_id],
                        is_local,
                    );
                    match variant_inhabitedness {
                        Break(VisiblyUninhabited) => continue,
                        Continue(()) => return CONTINUE_OPAQUELY_INHABITED,
                    }
                }
                BREAK_VISIBLY_UNINHABITED
            }
        }
    }

    fn visit_variant(
        &mut self,
        variant: VariantId,
        variant_data: &VariantData,
        subst: &Substitution,
        attrs: &Attrs,
        is_local: bool,
    ) -> ControlFlow<VisiblyUninhabited> {
        let non_exhaustive_field_list = attrs.by_key("non_exhaustive").exists();
        if non_exhaustive_field_list && !is_local {
            return CONTINUE_OPAQUELY_INHABITED;
        }

        let is_enum = matches!(variant, VariantId::EnumVariantId(..));
        let field_tys = self.db.field_types(variant);
        let field_vis = self.db.field_visibilities(variant);

        for (fid, _) in variant_data.fields().iter() {
            self.visit_field(field_vis[fid], &field_tys[fid], subst, is_enum)?;
        }
        CONTINUE_OPAQUELY_INHABITED
    }

    fn visit_field(
        &mut self,
        vis: Visibility,
        ty: &Binders<Ty>,
        subst: &Substitution,
        is_enum: bool,
    ) -> ControlFlow<VisiblyUninhabited> {
        if is_enum || vis.is_visible_from(self.db.upcast(), self.target_mod) {
            let ty = ty.clone().substitute(Interner, subst);
            ty.visit_with(self, DebruijnIndex::INNERMOST)
        } else {
            CONTINUE_OPAQUELY_INHABITED
        }
    }
}

fn try_usize_const(c: &Const) -> Option<u128> {
    let data = &c.data(Interner);
    if data.ty.kind(Interner) != &TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)) {
        return None;
    }
    match data.value {
        ConstValue::Concrete(ConcreteConst { interned: ConstScalar::UInt(value) }) => Some(value),
        _ => None,
    }
}
<|endoftext|>


<commit_before>// 1-indexed. [0] is unused.
type BIT = Vec<i64>;

pub fn bit_new(len: usize) -> BIT {
    vec![0; len + 1]
}

pub fn bit_len(bit: &BIT) -> usize {
    bit.len() - 1
}

/// Increments an element.
pub fn bit_add(bit: &mut BIT, index: usize, value: i64) {
    let mut j = index + 1;
    while j < bit_len(bit) {
        bit[j] += value;
        j += rightmost_bit(j);
    }
}

/// Gets sum of items in range 0..right.
pub fn bit_acc(bit: &BIT, right: usize) -> i64 {
    let mut acc = 0;
    let mut j = right;
    while 0 < j && j < bit_len(bit) {
        acc += bit[j];
        j -= rightmost_bit(j);
    }
    acc
}

/// Gets sum of items in range left..right.
pub fn bit_sum(bit: &BIT, left: usize, right: usize) -> i64 {
    let mut acc = bit_acc(bit, right);
    acc -= bit_acc(bit, left);
    acc
}

fn rightmost_bit(n: usize) -> usize {
    let s = n as isize;
    (s & -s) as usize
}

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

    #[test]
    fn test() {
        let mut bit = bit_new(6);
        for (i, &x) in [3, 1, 4, 1, 5, 9].into_iter().enumerate() {
            bit_add(&mut bit, i, x);
        }

        assert_eq!(1 + 4 + 1, bit_sum(&bit, 1, 4));
    }
}
<commit_msg>Add BIT notes<commit_after>// Binary Indexed Tree (BIT) is an array structure
// implemented as a tree that looks like:
//
//      [                       8                     ] _ ..
//      [          4          ] _______________________ [ ..
//      [    2    ] ___________ [    6    ] ___________ [ ..
//      [ 1 ] _____ [ 3 ] _____ [ 5 ] _____ [ 7 ] _____ [ ..
//                                                        ..
//      < 0 > < 1 > < 2 > < 3 > < 4 > < 5 > < 6 > < 7 > < ..
//
// where each ``[ i ]`` is i-th node
// and each ``< i >`` is i-th element of the structure.

// Invariant: each node holds the sum of values of elements that covers. e.g.
//      [1] = <0>,
//      [6] = <4> + <5>,
//      [2^N] = <0> + .. + <2^N - 1>.

// Technique: for i (> 1), node [i]'s parent is [i + (i & -i)].

// 1-indexed. [0] is unused.
type BIT = Vec<i64>;

pub fn bit_new(len: usize) -> BIT {
    vec![0; len + 1]
}

pub fn bit_len(bit: &BIT) -> usize {
    bit.len() - 1
}

/// Increments an element.
pub fn bit_add(bit: &mut BIT, index: usize, value: i64) {
    let mut j = index + 1;
    while j < bit_len(bit) {
        bit[j] += value;
        j += rightmost_bit(j);
    }
}

/// Gets sum of items in range 0..right.
pub fn bit_acc(bit: &BIT, right: usize) -> i64 {
    let mut acc = 0;
    let mut j = right;
    while 0 < j && j < bit_len(bit) {
        acc += bit[j];
        j -= rightmost_bit(j);
    }
    acc
}

/// Gets sum of items in range left..right.
pub fn bit_sum(bit: &BIT, left: usize, right: usize) -> i64 {
    let mut acc = bit_acc(bit, right);
    acc -= bit_acc(bit, left);
    acc
}

fn rightmost_bit(n: usize) -> usize {
    let s = n as isize;
    (s & -s) as usize
}

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

    #[test]
    fn test() {
        let mut bit = bit_new(6);
        for (i, &x) in [3, 1, 4, 1, 5, 9].into_iter().enumerate() {
            bit_add(&mut bit, i, x);
        }

        assert_eq!(1 + 4 + 1, bit_sum(&bit, 1, 4));
    }
}
<|endoftext|>