<commit_before>use crate::errors::{AttributeError, NetworkError};
use crate::hashes::ATTRIBUTES;
use crate::network::attributes::{AttributeDecoder, ProductValueDecoder};
use crate::network::models::{
    ActorId, Frame, NewActor, ObjectId, SpawnTrajectory, StreamId, Trajectory, UpdatedAttribute,
};
use crate::network::{CacheInfo, ObjectAttribute, VersionTriplet};
use crate::parser::ReplayBody;
use bitter::BitGet;
use failure::Error;
use fnv::FnvHashMap;
use std::collections::HashMap;
use std::ops::Deref;

pub(crate) struct FrameDecoder<'a, 'b: 'a> {
    pub frames_len: usize,
    pub product_decoder: ProductValueDecoder,
    pub channel_bits: i32,
    pub body: &'a ReplayBody<'b>,
    pub spawns: &'a Vec<SpawnTrajectory>,
    pub object_ind_attributes: FnvHashMap<ObjectId, CacheInfo>,
    pub object_ind_attrs: HashMap<ObjectId, HashMap<StreamId, ObjectAttribute>>,
    pub version: VersionTriplet,
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct ContextObjectAttribute {
    obj_id: ObjectId,
    obj_name: String,
    prop_id: ObjectId,
    prop_name: String,
}

impl<'a, 'b> FrameDecoder<'a, 'b> {
    fn object_ind_to_string(&self, object_id: ObjectId) -> String {
        String::from(
            self.body
                .objects
                .get(usize::from(object_id))
                .map(Deref::deref)
                .unwrap_or("Out of bounds"),
        )
    }

    fn missing_attribute(
        &self,
        cache_info: &CacheInfo,
        actor_id: ActorId,
        object_id: ObjectId,
        stream_id: StreamId,
    ) -> NetworkError {
        NetworkError::MissingAttribute(
            actor_id,
            object_id,
            self.object_ind_to_string(object_id),
            stream_id,
            cache_info
                .attributes
                .keys()
                .map(ToString::to_string)
                .collect::<Vec<_>>()
                .join(","),
        )
    }

    fn properties_with_stream_id(&self, stream_id: StreamId) -> Vec<ContextObjectAttribute> {
        self.body
            .net_cache
            .iter()
            .map(|x| {
                x.properties
                    .iter()
                    .map(|prop| (x.object_ind, prop.object_ind, prop.stream_id))
                    .collect::<Vec<(i32, i32, i32)>>()
            })
            .flat_map(|x| x)
            .filter(|&(_obj_id, _prop_id, prop_stream_id)| StreamId(prop_stream_id) == stream_id)
            .map(|(obj_id, prop_id, _prop_stream_id)| {
                let obj_id = ObjectId(obj_id);
                let prop_id = ObjectId(prop_id);
                ContextObjectAttribute {
                    obj_id,
                    prop_id,
                    obj_name: self.object_ind_to_string(obj_id),
                    prop_name: self.object_ind_to_string(prop_id),
                }
            })
            .filter(|x| !ATTRIBUTES.contains_key(x.prop_name.as_str()))
            .collect()
    }

    fn unimplemented_attribute(
        &self,
        actor_id: ActorId,
        object_id: ObjectId,
        stream_id: StreamId,
    ) -> NetworkError {
        let fm = self
            .properties_with_stream_id(stream_id)
            .into_iter()
            .map(|x| {
                format!(
                    "\tobject {} ({}) has property {} ({})",
                    x.obj_id, x.obj_name, x.prop_id, x.prop_name
                )
            })
            .collect::<Vec<String>>()
            .join("\n");

        NetworkError::UnimplementedAttribute(
            actor_id,
            object_id,
            self.object_ind_to_string(object_id),
            stream_id,
            self.object_ind_attrs
                .get(&object_id)
                .and_then(|x| x.get(&stream_id))
                .map(|x| self.object_ind_to_string(x.object_id))
                .unwrap_or_else(|| "type id not recognized".to_string()),
            fm,
        )
    }

    fn parse_new_actor(
        &self,
        mut bits: &mut BitGet<'_>,
        actor_id: ActorId,
    ) -> Result<NewActor, NetworkError> {
        if_chain! {
            if let Some(name_id) =
                if self.version >= VersionTriplet(868, 14, 0) {
                    bits.read_i32().map(Some)
                } else {
                    Some(None)
                };

            if let Some(_) = bits.read_bit();
            if let Some(object_id) = bits.read_i32().map(ObjectId);
            let spawn = self.spawns.get(usize::from(object_id))
                .ok_or_else(|| NetworkError::ObjectIdOutOfRange(object_id))?;

            if let Some(traj) = Trajectory::from_spawn(&mut bits, *spawn, self.version.net_version());
            then {
                Ok(NewActor {
                    actor_id,
                    name_id,
                    object_id,
                    initial_trajectory: traj
                })
            } else {
                Err(NetworkError::NotEnoughDataFor("New Actor"))
            }
        }
    }

    fn decode_frame(
        &self,
        attr_decoder: &AttributeDecoder,
        mut bits: &mut BitGet<'_>,
        actors: &mut FnvHashMap<ActorId, ObjectId>,
        time: f32,
        delta: f32,
    ) -> Result<Frame, NetworkError> {
        let mut new_actors = Vec::new();
        let mut updated_actors = Vec::new();
        let mut deleted_actors = Vec::new();

        while bits
            .read_bit()
            .ok_or_else(|| NetworkError::NotEnoughDataFor("Actor data"))?
        {
            let actor_id = bits
                .read_i32_bits(self.channel_bits)
                .map(ActorId)
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Actor Id"))?;

            // alive
            if bits
                .read_bit()
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Is actor alive"))?
            {
                // new
                if bits
                    .read_bit()
                    .ok_or_else(|| NetworkError::NotEnoughDataFor("Is new actor"))?
                {
                    let actor = self.parse_new_actor(&mut bits, actor_id)?;

                    // Insert the new actor so we can keep track of it for attribute
                    // updates. It's common for an actor id to already exist, so we
                    // overwrite it.
                    actors.insert(actor.actor_id, actor.object_id);
                    new_actors.push(actor);
                } else {
                    // We'll be updating an existing actor with some attributes so we need
                    // to track down what the actor's type is
                    let object_id = actors
                        .get(&actor_id)
                        .ok_or_else(|| NetworkError::MissingActor(actor_id))?;

                    // Once we have the type we need to look up what attributes are
                    // available for said type
                    let cache_info =
                        self.object_ind_attributes.get(object_id).ok_or_else(|| {
                            NetworkError::MissingCache(
                                actor_id,
                                *object_id,
                                self.object_ind_to_string(*object_id),
                            )
                        })?;

                    // While there are more attributes to update for our actor:
                    while bits
                        .read_bit()
                        .ok_or_else(|| NetworkError::NotEnoughDataFor("Is prop present"))?
                    {
                        // We've previously calculated the max the stream id can be for a
                        // given type and how many bits that it encompasses so use those
                        // values now
                        let stream_id = bits
                            .read_bits_max(cache_info.prop_id_bits, cache_info.max_prop_id)
                            .map(|x| StreamId(x as i32))
                            .ok_or_else(|| NetworkError::NotEnoughDataFor("Prop id"))?;

                        // Look the stream id up and find the corresponding attribute
                        // decoding function. Experience has told me replays that fail to
                        // parse, fail to do so here, so a large chunk is dedicated to
                        // generating an error message with context
                        let attr = cache_info.attributes.get(&stream_id).ok_or_else(|| {
                            self.missing_attribute(cache_info, actor_id, *object_id, stream_id)
                        })?;

                        let attribute =
                            attr_decoder.decode(*attr, &mut bits).map_err(|e| match e {
                                AttributeError::Unimplemented => {
                                    self.unimplemented_attribute(actor_id, *object_id, stream_id)
                                }
                                _ => NetworkError::AttributeError(e),
                            })?;

                        updated_actors.push(UpdatedAttribute {
                            actor_id,
                            stream_id,
                            attribute,
                        });
                    }
                }
            } else {
                deleted_actors.push(actor_id);
                actors.remove(&actor_id);
            }
        }

        Ok(Frame {
            time,
            delta,
            new_actors,
            deleted_actors,
            updated_actors,
        })
    }

    pub fn decode_frames(&self) -> Result<Vec<Frame>, Error> {
        let attr_decoder = AttributeDecoder::new(self.version, self.product_decoder);
        let mut frames: Vec<Frame> = Vec::with_capacity(self.frames_len);
        let mut actors = FnvHashMap::default();
        let mut bits = BitGet::new(self.body.network_data);
        while !bits.is_empty() && frames.len() < self.frames_len {
            let time = bits
                .read_f32()
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Time"))?;

            if time < 0.0 || (time > 0.0 && time < 1e-10) {
                let mut frame_index = frames.len() - 1;
                while let Some(frame) = frames.get(frame_index) {
                    if let Some(last_update) = frame.updated_actors.last() {
                        return Err(NetworkError::TimeOutOfRangeUpdate(
                            frames.len(),
                            frame_index,
                            last_update.actor_id,
                            last_update.stream_id,
                            last_update.attribute.clone(),
                        ))?;
                    }
                    frame_index -= 1;
                }

                return Err(NetworkError::TimeOutOfRange(time))?;
            }

            let delta = bits
                .read_f32()
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Delta"))?;

            if delta < 0.0 || (delta > 0.0 && delta < 1e-10) {
                return Err(NetworkError::DeltaOutOfRange(delta))?;
            }

            if time == 0.0 && delta == 0.0 {
                break;
            }

            let frame = self.decode_frame(&attr_decoder, &mut bits, &mut actors, time, delta)?;
            frames.push(frame);
        }

        if self.version >= VersionTriplet(868, 24, 10) {
            bits.read_u32()
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Trailer"))?;
        }

        Ok(frames)
    }
}
<commit_msg>Fix overflow panic for out of bound time messages<commit_after>use crate::errors::{AttributeError, NetworkError};
use crate::hashes::ATTRIBUTES;
use crate::network::attributes::{AttributeDecoder, ProductValueDecoder};
use crate::network::models::{
    ActorId, Frame, NewActor, ObjectId, SpawnTrajectory, StreamId, Trajectory, UpdatedAttribute,
};
use crate::network::{CacheInfo, ObjectAttribute, VersionTriplet};
use crate::parser::ReplayBody;
use bitter::BitGet;
use failure::Error;
use fnv::FnvHashMap;
use std::collections::HashMap;
use std::ops::Deref;

pub(crate) struct FrameDecoder<'a, 'b: 'a> {
    pub frames_len: usize,
    pub product_decoder: ProductValueDecoder,
    pub channel_bits: i32,
    pub body: &'a ReplayBody<'b>,
    pub spawns: &'a Vec<SpawnTrajectory>,
    pub object_ind_attributes: FnvHashMap<ObjectId, CacheInfo>,
    pub object_ind_attrs: HashMap<ObjectId, HashMap<StreamId, ObjectAttribute>>,
    pub version: VersionTriplet,
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct ContextObjectAttribute {
    obj_id: ObjectId,
    obj_name: String,
    prop_id: ObjectId,
    prop_name: String,
}

impl<'a, 'b> FrameDecoder<'a, 'b> {
    fn object_ind_to_string(&self, object_id: ObjectId) -> String {
        String::from(
            self.body
                .objects
                .get(usize::from(object_id))
                .map(Deref::deref)
                .unwrap_or("Out of bounds"),
        )
    }

    fn missing_attribute(
        &self,
        cache_info: &CacheInfo,
        actor_id: ActorId,
        object_id: ObjectId,
        stream_id: StreamId,
    ) -> NetworkError {
        NetworkError::MissingAttribute(
            actor_id,
            object_id,
            self.object_ind_to_string(object_id),
            stream_id,
            cache_info
                .attributes
                .keys()
                .map(ToString::to_string)
                .collect::<Vec<_>>()
                .join(","),
        )
    }

    fn properties_with_stream_id(&self, stream_id: StreamId) -> Vec<ContextObjectAttribute> {
        self.body
            .net_cache
            .iter()
            .map(|x| {
                x.properties
                    .iter()
                    .map(|prop| (x.object_ind, prop.object_ind, prop.stream_id))
                    .collect::<Vec<(i32, i32, i32)>>()
            })
            .flat_map(|x| x)
            .filter(|&(_obj_id, _prop_id, prop_stream_id)| StreamId(prop_stream_id) == stream_id)
            .map(|(obj_id, prop_id, _prop_stream_id)| {
                let obj_id = ObjectId(obj_id);
                let prop_id = ObjectId(prop_id);
                ContextObjectAttribute {
                    obj_id,
                    prop_id,
                    obj_name: self.object_ind_to_string(obj_id),
                    prop_name: self.object_ind_to_string(prop_id),
                }
            })
            .filter(|x| !ATTRIBUTES.contains_key(x.prop_name.as_str()))
            .collect()
    }

    fn unimplemented_attribute(
        &self,
        actor_id: ActorId,
        object_id: ObjectId,
        stream_id: StreamId,
    ) -> NetworkError {
        let fm = self
            .properties_with_stream_id(stream_id)
            .into_iter()
            .map(|x| {
                format!(
                    "\tobject {} ({}) has property {} ({})",
                    x.obj_id, x.obj_name, x.prop_id, x.prop_name
                )
            })
            .collect::<Vec<String>>()
            .join("\n");

        NetworkError::UnimplementedAttribute(
            actor_id,
            object_id,
            self.object_ind_to_string(object_id),
            stream_id,
            self.object_ind_attrs
                .get(&object_id)
                .and_then(|x| x.get(&stream_id))
                .map(|x| self.object_ind_to_string(x.object_id))
                .unwrap_or_else(|| "type id not recognized".to_string()),
            fm,
        )
    }

    fn parse_new_actor(
        &self,
        mut bits: &mut BitGet<'_>,
        actor_id: ActorId,
    ) -> Result<NewActor, NetworkError> {
        if_chain! {
            if let Some(name_id) =
                if self.version >= VersionTriplet(868, 14, 0) {
                    bits.read_i32().map(Some)
                } else {
                    Some(None)
                };

            if let Some(_) = bits.read_bit();
            if let Some(object_id) = bits.read_i32().map(ObjectId);
            let spawn = self.spawns.get(usize::from(object_id))
                .ok_or_else(|| NetworkError::ObjectIdOutOfRange(object_id))?;

            if let Some(traj) = Trajectory::from_spawn(&mut bits, *spawn, self.version.net_version());
            then {
                Ok(NewActor {
                    actor_id,
                    name_id,
                    object_id,
                    initial_trajectory: traj
                })
            } else {
                Err(NetworkError::NotEnoughDataFor("New Actor"))
            }
        }
    }

    fn decode_frame(
        &self,
        attr_decoder: &AttributeDecoder,
        mut bits: &mut BitGet<'_>,
        actors: &mut FnvHashMap<ActorId, ObjectId>,
        time: f32,
        delta: f32,
    ) -> Result<Frame, NetworkError> {
        let mut new_actors = Vec::new();
        let mut updated_actors = Vec::new();
        let mut deleted_actors = Vec::new();

        while bits
            .read_bit()
            .ok_or_else(|| NetworkError::NotEnoughDataFor("Actor data"))?
        {
            let actor_id = bits
                .read_i32_bits(self.channel_bits)
                .map(ActorId)
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Actor Id"))?;

            // alive
            if bits
                .read_bit()
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Is actor alive"))?
            {
                // new
                if bits
                    .read_bit()
                    .ok_or_else(|| NetworkError::NotEnoughDataFor("Is new actor"))?
                {
                    let actor = self.parse_new_actor(&mut bits, actor_id)?;

                    // Insert the new actor so we can keep track of it for attribute
                    // updates. It's common for an actor id to already exist, so we
                    // overwrite it.
                    actors.insert(actor.actor_id, actor.object_id);
                    new_actors.push(actor);
                } else {
                    // We'll be updating an existing actor with some attributes so we need
                    // to track down what the actor's type is
                    let object_id = actors
                        .get(&actor_id)
                        .ok_or_else(|| NetworkError::MissingActor(actor_id))?;

                    // Once we have the type we need to look up what attributes are
                    // available for said type
                    let cache_info =
                        self.object_ind_attributes.get(object_id).ok_or_else(|| {
                            NetworkError::MissingCache(
                                actor_id,
                                *object_id,
                                self.object_ind_to_string(*object_id),
                            )
                        })?;

                    // While there are more attributes to update for our actor:
                    while bits
                        .read_bit()
                        .ok_or_else(|| NetworkError::NotEnoughDataFor("Is prop present"))?
                    {
                        // We've previously calculated the max the stream id can be for a
                        // given type and how many bits that it encompasses so use those
                        // values now
                        let stream_id = bits
                            .read_bits_max(cache_info.prop_id_bits, cache_info.max_prop_id)
                            .map(|x| StreamId(x as i32))
                            .ok_or_else(|| NetworkError::NotEnoughDataFor("Prop id"))?;

                        // Look the stream id up and find the corresponding attribute
                        // decoding function. Experience has told me replays that fail to
                        // parse, fail to do so here, so a large chunk is dedicated to
                        // generating an error message with context
                        let attr = cache_info.attributes.get(&stream_id).ok_or_else(|| {
                            self.missing_attribute(cache_info, actor_id, *object_id, stream_id)
                        })?;

                        let attribute =
                            attr_decoder.decode(*attr, &mut bits).map_err(|e| match e {
                                AttributeError::Unimplemented => {
                                    self.unimplemented_attribute(actor_id, *object_id, stream_id)
                                }
                                _ => NetworkError::AttributeError(e),
                            })?;

                        updated_actors.push(UpdatedAttribute {
                            actor_id,
                            stream_id,
                            attribute,
                        });
                    }
                }
            } else {
                deleted_actors.push(actor_id);
                actors.remove(&actor_id);
            }
        }

        Ok(Frame {
            time,
            delta,
            new_actors,
            deleted_actors,
            updated_actors,
        })
    }

    pub fn decode_frames(&self) -> Result<Vec<Frame>, Error> {
        let attr_decoder = AttributeDecoder::new(self.version, self.product_decoder);
        let mut frames: Vec<Frame> = Vec::with_capacity(self.frames_len);
        let mut actors = FnvHashMap::default();
        let mut bits = BitGet::new(self.body.network_data);
        while !bits.is_empty() && frames.len() < self.frames_len {
            let time = bits
                .read_f32()
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Time"))?;

            if time < 0.0 || (time > 0.0 && time < 1e-10) {
                for (i, frame) in frames.iter().enumerate().rev() {
                    if let Some(last_update) = frame.updated_actors.last() {
                        return Err(NetworkError::TimeOutOfRangeUpdate(
                            frames.len(),
                            i,
                            last_update.actor_id,
                            last_update.stream_id,
                            last_update.attribute.clone(),
                        ))?;
                    }
                }

                return Err(NetworkError::TimeOutOfRange(time))?;
            }

            let delta = bits
                .read_f32()
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Delta"))?;

            if delta < 0.0 || (delta > 0.0 && delta < 1e-10) {
                return Err(NetworkError::DeltaOutOfRange(delta))?;
            }

            if time == 0.0 && delta == 0.0 {
                break;
            }

            let frame = self.decode_frame(&attr_decoder, &mut bits, &mut actors, time, delta)?;
            frames.push(frame);
        }

        if self.version >= VersionTriplet(868, 24, 10) {
            bits.read_u32()
                .ok_or_else(|| NetworkError::NotEnoughDataFor("Trailer"))?;
        }

        Ok(frames)
    }
}
<|endoftext|>


<commit_before>use hir::def_id::DefId;
use infer::error_reporting::nice_region_error::NiceRegionError;
use infer::lexical_region_resolve::RegionResolutionError;
use infer::ValuePairs;
use infer::{SubregionOrigin, TypeTrace};
use traits::{ObligationCause, ObligationCauseCode};
use ty;
use ty::error::ExpectedFound;
use ty::subst::Substs;
use util::common::ErrorReported;
use util::ppaux::RegionHighlightMode;

impl NiceRegionError<'me, 'gcx, 'tcx> {
    /// When given a `ConcreteFailure` for a function with arguments containing a named region and
    /// an anonymous region, emit an descriptive diagnostic error.
    pub(super) fn try_report_placeholder_conflict(&self) -> Option<ErrorReported> {
        match &self.error {
            ///////////////////////////////////////////////////////////////////////////
            // NB. The ordering of cases in this match is very
            // sensitive, because we are often matching against
            // specific cases and then using an `_` to match all
            // others.

            ///////////////////////////////////////////////////////////////////////////
            // Check for errors from comparing trait failures -- first
            // with two placeholders, then with one.
            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_placeholder @ ty::RePlaceholder(_),
                _,
                sup_placeholder @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(self.tcx().mk_region(ty::ReVar(*vid))),
                    cause,
                    Some(sub_placeholder),
                    Some(sup_placeholder),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_placeholder @ ty::RePlaceholder(_),
                _,
                _,
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(self.tcx().mk_region(ty::ReVar(*vid))),
                    cause,
                    Some(sub_placeholder),
                    None,
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                _,
                _,
                sup_placeholder @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(self.tcx().mk_region(ty::ReVar(*vid))),
                    cause,
                    None,
                    Some(*sup_placeholder),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                _,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sup_placeholder @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(self.tcx().mk_region(ty::ReVar(*vid))),
                    cause,
                    None,
                    Some(*sup_placeholder),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region @ ty::RePlaceholder(_),
                sup_region @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    None,
                    cause,
                    Some(*sub_region),
                    Some(*sup_region),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region @ ty::RePlaceholder(_),
                sup_region,
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(sup_region),
                    cause,
                    Some(*sub_region),
                    None,
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region,
                sup_region @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(sub_region),
                    cause,
                    None,
                    Some(*sup_region),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            _ => None,
        }
    }

    // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
    //   --> /home/nmatsakis/tmp/foo.rs:12:5
    //    |
    // 12 |     all::<&'static u32>();
    //    |     ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    //    |
    //    = note: Due to a where-clause on the function `all`,
    //    = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
    //    = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
    fn try_report_placeholders_trait(
        &self,
        vid: Option<ty::Region<'tcx>>,
        cause: &ObligationCause<'tcx>,
        sub_placeholder: Option<ty::Region<'tcx>>,
        sup_placeholder: Option<ty::Region<'tcx>>,
        trait_def_id: DefId,
        expected_substs: &'tcx Substs<'tcx>,
        actual_substs: &'tcx Substs<'tcx>,
    ) -> ErrorReported {
        let mut err = self.tcx().sess.struct_span_err(
            cause.span(&self.tcx()),
            &format!(
                "implementation of `{}` is not general enough",
                self.tcx().item_path_str(trait_def_id),
            ),
        );

        match cause.code {
            ObligationCauseCode::ItemObligation(def_id) => {
                err.note(&format!(
                    "Due to a where-clause on `{}`,",
                    self.tcx().item_path_str(def_id),
                ));
            }
            _ => (),
        }

        let expected_trait_ref = self.infcx.resolve_type_vars_if_possible(
            &ty::TraitRef {
                def_id: trait_def_id,
                substs: expected_substs,
            }
        );
        let actual_trait_ref = self.infcx.resolve_type_vars_if_possible(
            &ty::TraitRef {
                def_id: trait_def_id,
                substs: actual_substs,
            }
        );

        // Search the expected and actual trait references to see (a)
        // whether the sub/sup placeholders appear in them (sometimes
        // you have a trait ref like `T: Foo<fn(&u8)>`, where the
        // placeholder was created as part of an inner type) and (b)
        // whether the inference variable appears. In each case,
        // assign a counter value in each case if so.
        let mut counter = 0;
        let mut has_sub = None;
        let mut has_sup = None;
        let mut has_vid = None;

        self.tcx().for_each_free_region(&expected_trait_ref, |r| {
            if Some(r) == sub_placeholder && has_sub.is_none() {
                has_sub = Some(counter);
                counter += 1;
            } else if Some(r) == sup_placeholder && has_sup.is_none() {
                has_sup = Some(counter);
                counter += 1;
            }
        });

        self.tcx().for_each_free_region(&actual_trait_ref, |r| {
            if Some(r) == vid && has_vid.is_none() {
                has_vid = Some(counter);
                counter += 1;
            }
        });

        let self_ty_has_vid = self
            .tcx()
            .any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);

        RegionHighlightMode::maybe_highlighting_region(sub_placeholder, has_sub, || {
            RegionHighlightMode::maybe_highlighting_region(sup_placeholder, has_sup, || {
                match (has_sub, has_sup) {
                    (Some(n1), Some(n2)) => {
                        err.note(&format!(
                            "`{}` must implement `{}` \
                             for any two lifetimes `'{}` and `'{}`",
                            expected_trait_ref.self_ty(),
                            expected_trait_ref,
                            std::cmp::min(n1, n2),
                            std::cmp::max(n1, n2),
                        ));
                    }
                    (Some(n), _) | (_, Some(n)) => {
                        err.note(&format!(
                            "`{}` must implement `{}` \
                             for any lifetime `'{}`",
                            expected_trait_ref.self_ty(),
                            expected_trait_ref,
                            n,
                        ));
                    }
                    (None, None) => {
                        err.note(&format!(
                            "`{}` must implement `{}`",
                            expected_trait_ref.self_ty(),
                            expected_trait_ref,
                        ));
                    }
                }
            })
        });

        RegionHighlightMode::maybe_highlighting_region(vid, has_vid, || match has_vid {
            Some(n) => {
                if self_ty_has_vid {
                    err.note(&format!(
                        "but `{}` only implements `{}` for the lifetime `'{}`",
                        actual_trait_ref.self_ty(),
                        actual_trait_ref,
                        n
                    ));
                } else {
                    err.note(&format!(
                        "but `{}` only implements `{}` for some lifetime `'{}`",
                        actual_trait_ref.self_ty(),
                        actual_trait_ref,
                        n
                    ));
                }
            }
            None => {
                err.note(&format!(
                    "but `{}` only implements `{}`",
                    actual_trait_ref.self_ty(),
                    actual_trait_ref,
                ));
            }
        });

        err.emit();
        ErrorReported
    }
}
<commit_msg>Try to reword placeholder error messages to make them clearer<commit_after>use hir::def_id::DefId;
use infer::error_reporting::nice_region_error::NiceRegionError;
use infer::lexical_region_resolve::RegionResolutionError;
use infer::ValuePairs;
use infer::{SubregionOrigin, TypeTrace};
use traits::{ObligationCause, ObligationCauseCode};
use ty;
use ty::error::ExpectedFound;
use ty::subst::Substs;
use util::common::ErrorReported;
use util::ppaux::RegionHighlightMode;

impl NiceRegionError<'me, 'gcx, 'tcx> {
    /// When given a `ConcreteFailure` for a function with arguments containing a named region and
    /// an anonymous region, emit an descriptive diagnostic error.
    pub(super) fn try_report_placeholder_conflict(&self) -> Option<ErrorReported> {
        match &self.error {
            ///////////////////////////////////////////////////////////////////////////
            // NB. The ordering of cases in this match is very
            // sensitive, because we are often matching against
            // specific cases and then using an `_` to match all
            // others.

            ///////////////////////////////////////////////////////////////////////////
            // Check for errors from comparing trait failures -- first
            // with two placeholders, then with one.
            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_placeholder @ ty::RePlaceholder(_),
                _,
                sup_placeholder @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(self.tcx().mk_region(ty::ReVar(*vid))),
                    cause,
                    Some(sub_placeholder),
                    Some(sup_placeholder),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_placeholder @ ty::RePlaceholder(_),
                _,
                _,
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(self.tcx().mk_region(ty::ReVar(*vid))),
                    cause,
                    Some(sub_placeholder),
                    None,
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                _,
                _,
                sup_placeholder @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(self.tcx().mk_region(ty::ReVar(*vid))),
                    cause,
                    None,
                    Some(*sup_placeholder),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                _,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sup_placeholder @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(self.tcx().mk_region(ty::ReVar(*vid))),
                    cause,
                    None,
                    Some(*sup_placeholder),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region @ ty::RePlaceholder(_),
                sup_region @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    None,
                    cause,
                    Some(*sub_region),
                    Some(*sup_region),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region @ ty::RePlaceholder(_),
                sup_region,
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(sup_region),
                    cause,
                    Some(*sub_region),
                    None,
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region,
                sup_region @ ty::RePlaceholder(_),
            ))
                if expected.def_id == found.def_id =>
            {
                Some(self.try_report_placeholders_trait(
                    Some(sub_region),
                    cause,
                    None,
                    Some(*sup_region),
                    expected.def_id,
                    expected.substs,
                    found.substs,
                ))
            }

            _ => None,
        }
    }

    // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
    //   --> /home/nmatsakis/tmp/foo.rs:12:5
    //    |
    // 12 |     all::<&'static u32>();
    //    |     ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    //    |
    //    = note: Due to a where-clause on the function `all`,
    //    = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
    //    = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
    fn try_report_placeholders_trait(
        &self,
        vid: Option<ty::Region<'tcx>>,
        cause: &ObligationCause<'tcx>,
        sub_placeholder: Option<ty::Region<'tcx>>,
        sup_placeholder: Option<ty::Region<'tcx>>,
        trait_def_id: DefId,
        expected_substs: &'tcx Substs<'tcx>,
        actual_substs: &'tcx Substs<'tcx>,
    ) -> ErrorReported {
        let mut err = self.tcx().sess.struct_span_err(
            cause.span(&self.tcx()),
            &format!(
                "implementation of `{}` is not general enough",
                self.tcx().item_path_str(trait_def_id),
            ),
        );

        match cause.code {
            ObligationCauseCode::ItemObligation(def_id) => {
                err.note(&format!(
                    "Due to a where-clause on `{}`,",
                    self.tcx().item_path_str(def_id),
                ));
            }
            _ => (),
        }

        let expected_trait_ref = self.infcx.resolve_type_vars_if_possible(
            &ty::TraitRef {
                def_id: trait_def_id,
                substs: expected_substs,
            }
        );
        let actual_trait_ref = self.infcx.resolve_type_vars_if_possible(
            &ty::TraitRef {
                def_id: trait_def_id,
                substs: actual_substs,
            }
        );

        // Search the expected and actual trait references to see (a)
        // whether the sub/sup placeholders appear in them (sometimes
        // you have a trait ref like `T: Foo<fn(&u8)>`, where the
        // placeholder was created as part of an inner type) and (b)
        // whether the inference variable appears. In each case,
        // assign a counter value in each case if so.
        let mut counter = 0;
        let mut has_sub = None;
        let mut has_sup = None;

        let mut actual_has_vid = None;
        let mut expected_has_vid = None;

        self.tcx().for_each_free_region(&expected_trait_ref, |r| {
            if Some(r) == sub_placeholder && has_sub.is_none() {
                has_sub = Some(counter);
                counter += 1;
            } else if Some(r) == sup_placeholder && has_sup.is_none() {
                has_sup = Some(counter);
                counter += 1;
            }

            if Some(r) == vid && expected_has_vid.is_none() {
                expected_has_vid = Some(counter);
                counter += 1;
            }
        });

        self.tcx().for_each_free_region(&actual_trait_ref, |r| {
            if Some(r) == vid && actual_has_vid.is_none() {
                actual_has_vid = Some(counter);
                counter += 1;
            }
        });

        let self_ty_has_vid = self
            .tcx()
            .any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);

        RegionHighlightMode::maybe_highlighting_region(sub_placeholder, has_sub, || {
            RegionHighlightMode::maybe_highlighting_region(sup_placeholder, has_sup, || {
                match (has_sub, has_sup) {
                    (Some(n1), Some(n2)) => {
                        err.note(&format!(
                            "`{}` would have to be implemented for the type `{}`, \
                            for any two lifetimes `'{}` and `'{}`",
                            expected_trait_ref,
                            expected_trait_ref.self_ty(),
                            std::cmp::min(n1, n2),
                            std::cmp::max(n1, n2),
                        ));
                    }
                    (Some(n), _) | (_, Some(n)) => {
                        err.note(&format!(
                            "`{}` would have to be implemented for the type `{}`, \
                            for any lifetime `'{}`",
                            expected_trait_ref,
                            expected_trait_ref.self_ty(),
                            n,
                        ));
                    }
                    (None, None) => {
                        err.note(&format!(
                            "`{}` would have to be implemented for the type `{}`",
                            expected_trait_ref,
                            expected_trait_ref.self_ty(),
                        ));
                    }
                }
            })
        });

        RegionHighlightMode::maybe_highlighting_region(
            vid,
            actual_has_vid.or(expected_has_vid),
            || match actual_has_vid {
                Some(n) => {
                    if self_ty_has_vid {
                        err.note(&format!(
                            "but `{}` is actually implemented for the type `{}`, \
                            for the specific lifetime `'{}`",
                            actual_trait_ref,
                            actual_trait_ref.self_ty(),
                            n
                        ));
                    } else {
                        err.note(&format!(
                            "but `{}` is actually implemented for the type `{}`, \
                            for some lifetime `'{}`",
                            actual_trait_ref,
                            actual_trait_ref.self_ty(),
                            n
                        ));
                    }
                }

                _ => {
                    err.note(&format!(
                        "but `{}` is actually implemented for the type `{}`",
                        actual_trait_ref,
                        actual_trait_ref.self_ty(),
                    ));
                }
            }
        );

        err.emit();
        ErrorReported
    }
}
<|endoftext|>


<commit_before>use command_prelude::*;

use cargo::print_json;

pub fn cli() -> App {
    subcommand("locate-project")
        .about("Checkout a copy of a Git repository")
        .arg_manifest_path()
}

#[derive(Serialize)]
pub struct ProjectLocation {
    root: String,
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let root = args.root_manifest(config)?;

    let root = root.to_str()
        .ok_or_else(|| {
            format_err!(
                "your project path contains characters \
                 not representable in Unicode"
            )
        })
        .map_err(|e| CliError::new(e, 1))?
        .to_string();

    let location = ProjectLocation { root };

    print_json(&location);
    Ok(())
}
<commit_msg>locate-project: Fix help description.<commit_after>use command_prelude::*;

use cargo::print_json;

pub fn cli() -> App {
    subcommand("locate-project")
        .about("Print a JSON representation of a Cargo.toml file's location")
        .arg_manifest_path()
}

#[derive(Serialize)]
pub struct ProjectLocation {
    root: String,
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let root = args.root_manifest(config)?;

    let root = root.to_str()
        .ok_or_else(|| {
            format_err!(
                "your project path contains characters \
                 not representable in Unicode"
            )
        })
        .map_err(|e| CliError::new(e, 1))?
        .to_string();

    let location = ProjectLocation { root };

    print_json(&location);
    Ok(())
}
<|endoftext|>


<commit_before>use proc_macro::{LineColumn, Punct};

pub fn test() {
    test_line_column_ord();
    test_punct_eq();
}

fn test_line_column_ord() {
    let line0_column0 = LineColumn { line: 0, column: 0 };
    let line0_column1 = LineColumn { line: 0, column: 1 };
    let line1_column0 = LineColumn { line: 1, column: 0 };
    assert!(line0_column0 < line0_column1);
    assert!(line0_column1 < line1_column0);
}

fn test_punct_eq() {
    // Good enough if it typechecks, since proc_macro::Punct can't exist in a test.
    fn _check(punct: Punct) {
        let _ = punct == ':';
    }
}
<commit_msg>Make a more meaningful test for Punct eq<commit_after>use proc_macro::{LineColumn, Punct, Spacing};

pub fn test() {
    test_line_column_ord();
    test_punct_eq();
}

fn test_line_column_ord() {
    let line0_column0 = LineColumn { line: 0, column: 0 };
    let line0_column1 = LineColumn { line: 0, column: 1 };
    let line1_column0 = LineColumn { line: 1, column: 0 };
    assert!(line0_column0 < line0_column1);
    assert!(line0_column1 < line1_column0);
}

fn test_punct_eq() {
    let colon_alone = Punct::new(':', Spacing::Alone);
    assert_eq!(colon_alone, ':');
    let colon_joint = Punct::new(':', Spacing::Joint);
    assert_eq!(colon_joint, ':');
}
<|endoftext|>


<commit_before><commit_msg>mach: Fix MultiArch Debug impl panic (#251)<commit_after><|endoftext|>


<commit_before>use std::time::{Instant, Duration};
use std::future::Future;
use std::sync::Arc;

use glutin::{
    GlProfile,
    GlRequest,
    ContextBuilder,
    WindowedContext,
    PossiblyCurrent,
    dpi::{LogicalSize, PhysicalPosition},
    window::{WindowBuilder, Fullscreen},
    event::{
        Event as GlutinEvent,
        StartCause,
        WindowEvent,
        KeyboardInput,
        VirtualKeyCode,
        ElementState,
    },
    event_loop::{ControlFlow, EventLoop},
    platform::desktop::EventLoopExtDesktop,
};
use tokio::{
    sync::{mpsc, Mutex},
    runtime::Handle,
};

use crate::Event;
use crate::ipc_protocol::{ServerSender, ServerReceiver, ConnectionError};

use super::{
    app::App,
    coords::ScreenPoint,
    renderer::{
        Renderer,
        display_list::DisplayList,
    },
    event_loop_notifier::{EventLoopNotifier, MainThreadAction},
};

/// The maximum rendering FPS allowed
///
/// Rendering is intentionally throttled to avoid too much contention over the display list. If
/// multiple turtles are used or if many lines are drawn quickly, we may get >= 1 redraw request
/// per *millisecond* this is far too many redraws. Limiting to this rate helps avoid that.
const MAX_RENDERING_FPS: u64 = 60;

// 1,000,000 us in 1 s
const MICROS_PER_SEC: u64 = 1_000_000;

fn new_event_loop<T>() -> EventLoop<T> {
    cfg_if::cfg_if! {
        if #[cfg(target_os = "macos")] {
            EventLoop::with_user_event()

        } else if #[cfg(target_os = "windows")] {
            use glutin::platform::windows::EventLoopExtWindows;
            EventLoop::new_any_thread()

        } else {
            use glutin::platform::unix::EventLoopExtUnix;
            EventLoop::new_any_thread()
        }
    }
}

/// Run the window event loop in the current thread/task
///
/// When the window is opened, this will spawn a task that establishes the server connection using
/// the given future and begin to serve client requests.
///
/// On some platforms this function may only run on the main thread
pub fn run_main(
    // A handle used to block on asynchronous code and spawn new tasks
    //
    // Necessary because this function is not run on a runtime thread in all backends
    handle: Handle,

    // Polled to establish the server connection
    establish_connection: impl Future<Output=Result<(ServerSender, ServerReceiver), ConnectionError>> + Send + 'static,
) {
    // The state of the drawing and the state/drawings associated with each turtle
    let app = Arc::new(App::default());
    // All of the drawing primitives in the order in which they wil be drawn
    //
    // This is managed separately from the rest of the app state because the display list is shared
    // by pretty much everything. Trying to control it via `AccessControl` would remove all
    // opportunities for parallelism and essentially make all turtle programs sequential.
    //
    // Critical sections containing the display list should be as short as possible.
    let display_list = Arc::new(Mutex::new(DisplayList::default()));

    let mut event_loop = new_event_loop();
    // Create the proxy that will be given to the thread managing IPC
    let event_loop_notifier = EventLoopNotifier::new(event_loop.create_proxy());

    // A channel for transferring events
    let (events_sender, events_receiver) = mpsc::unbounded_channel();
    // Put these variables in an Option so we can call `take()` in the event loop. Required
    // because borrow checker cannot verify which events only fire once.
    let mut events_receiver = Some(events_receiver);
    let mut establish_connection = Some(establish_connection);
    let (mut server_shutdown, server_shutdown_receiver) = mpsc::channel(1);
    let mut server_shutdown_receiver = Some(server_shutdown_receiver);

    let window_builder = {
        let drawing = handle.block_on(app.drawing_mut());
        WindowBuilder::new()
            .with_title(&drawing.title)
            .with_inner_size(LogicalSize {width: drawing.width, height: drawing.height})
    };

    // Create an OpenGL 3.x context for Pathfinder to use
    let gl_context = ContextBuilder::new()
        .with_gl(GlRequest::Latest)
        .with_gl_profile(GlProfile::Core)
        .with_vsync(true)
        .with_double_buffer(Some(true))
        .build_windowed(window_builder, &event_loop)
        .expect("either could not create window or could not build OpenGL context");

    // Load OpenGL, and make the context current
    let gl_context = unsafe { gl_context.make_current().unwrap() };
    gl::load_with(|name| gl_context.get_proc_address(name) as *const _);

    // Need to draw using the physical size in pixels, not the logical size
    let draw_size = gl_context.window().inner_size();
    let mut renderer = Renderer::new(draw_size, gl_context.window().scale_factor());

    // For rate limiting rendering
    let min_render_delay = Duration::from_micros(MICROS_PER_SEC / MAX_RENDERING_FPS);
    // Subtracting the delay so we do an initial render right away
    let mut last_render = Instant::now() - min_render_delay;
    // Very important to use `run_return` here instead of `run` because `run` calls process::exit()
    // and that is not appropriate for the multithreaded backend as that would cause the entire
    // process to end when the window is closed.
    event_loop.run_return(move |event, _, control_flow| match event {
        GlutinEvent::NewEvents(StartCause::Init) => {
            // Spawn the actual server thread(s) that will handle incoming IPC messages and
            // asynchronous update the shared state
            //
            // Note that putting this code here instead of before the event loop causes the
            // `Turtle::new()`, etc. methods not to return before the window opens. Those methods
            // can't return because the connection handshake cannot complete before the thread used
            // for IPC is spawned.
            spawn_async_server(
                &handle,
                app.clone(),
                display_list.clone(),
                event_loop_notifier.clone(),
                events_receiver.take().expect("bug: init event should only occur once"),
                establish_connection.take().expect("bug: init event should only occur once"),
                server_shutdown_receiver.take().expect("bug: init event should only occur once"),
            );
        },

        GlutinEvent::NewEvents(StartCause::ResumeTimeReached {..}) => {
            // A render was delayed in the `RedrawRequested` so let's try to do it again now that
            // we have resumed
            gl_context.window().request_redraw();
        },

        // Quit if the window is closed or if Esc is pressed and then released
        GlutinEvent::WindowEvent {
            event: WindowEvent::CloseRequested,
            ..
        } | GlutinEvent::WindowEvent {
            event: WindowEvent::Destroyed,
            ..
        } | GlutinEvent::WindowEvent {
            event: WindowEvent::KeyboardInput {
                input: KeyboardInput {
                    state: ElementState::Released,
                    virtual_keycode: Some(VirtualKeyCode::Escape),
                    ..
                },
                ..
            },
            ..
        } => {
            *control_flow = ControlFlow::Exit;
        },

        GlutinEvent::WindowEvent {
            event: WindowEvent::ScaleFactorChanged {scale_factor, ..},
            ..
        } => {
            renderer.set_scale_factor(scale_factor);
        },

        GlutinEvent::WindowEvent {event, ..} => {
            let scale_factor = renderer.scale_factor();
            match event {
                WindowEvent::Resized(size) => {
                    let size = size.to_logical(scale_factor);
                    let mut drawing = handle.block_on(app.drawing_mut());
                    drawing.width = size.width;
                    drawing.height = size.height;
                },

                //TODO: There are currently no events for updating is_maximized, so that property
                // should not be relied on. https://github.com/rust-windowing/glutin/issues/1298

                _ => {},
            }

            // Converts to logical coordinates, only locking the drawing if this is actually called
            let to_logical = |pos: PhysicalPosition<f64>| {
                let drawing = handle.block_on(app.drawing_mut());
                let center = drawing.center;
                let draw_size = gl_context.window().inner_size();
                let fb_center = ScreenPoint {
                    x: draw_size.width as f64 / 2.0,
                    y: draw_size.height as f64 / 2.0,
                };

                let pos: ScreenPoint = pos.into();
                pos.to_logical(scale_factor, center, fb_center)
            };

            //TODO: There is no guarantee that sending this event here will actually allow a client
            // to receive it. After all, if the window closes and this process exits, there will be
            // no way to handle subsequent `NextEvent` requests.
            if let Some(event) = Event::from_window_event(event, scale_factor, to_logical) {
                // Sending may fail if the IPC thread has ended due to a disconnection when the
                // main process ends. This is not a fatal error though so we just ignore it.
                events_sender.send(event).unwrap_or(());
            }
        },

        // Window events are currently sufficient for the turtle event API
        GlutinEvent::DeviceEvent {..} => {},

        GlutinEvent::UserEvent(MainThreadAction::Redraw) => {
            gl_context.window().request_redraw();
        },

        GlutinEvent::UserEvent(MainThreadAction::SetTitle(title)) => {
            gl_context.window().set_title(&title);
        },

        GlutinEvent::UserEvent(MainThreadAction::SetSize(size)) => {
            gl_context.window().set_inner_size(size);
        },

        GlutinEvent::UserEvent(MainThreadAction::SetIsMaximized(is_maximized)) => {
            gl_context.window().set_maximized(is_maximized);
        },

        GlutinEvent::UserEvent(MainThreadAction::SetIsFullscreen(is_fullscreen)) => {
            gl_context.window().set_fullscreen(if is_fullscreen {
                Some(Fullscreen::Borderless(gl_context.window().current_monitor()))
            } else { None });
        },

        GlutinEvent::RedrawRequested(_) => {
            // Check if we just rendered
            let last_render_delay = last_render.elapsed();
            if last_render_delay < min_render_delay {
                let remaining = min_render_delay - last_render_delay;
                *control_flow = ControlFlow::WaitUntil(Instant::now() + remaining);
                return;
            }

            handle.block_on(redraw(&app, &display_list, &gl_context, &mut renderer));
            *control_flow = ControlFlow::Wait;
            last_render = Instant::now();
        },

        GlutinEvent::LoopDestroyed => {
            // Notify the server that it should shutdown, ignoring the error if the channel has
            // been dropped since that just means that the server task has ended already
            handle.block_on(server_shutdown.send(())).unwrap_or(());
        },

        _ => {},
    });
}

async fn redraw(
    app: &App,
    display_list: &Mutex<DisplayList>,
    gl_context: &WindowedContext<PossiblyCurrent>,
    renderer: &mut Renderer,
) {
    let drawing = {
        // Hold the drawing lock for as little time as possible
        let drawing = app.drawing_mut().await;
        drawing.clone()
    };

    // Locking the turtles before the display list to be consistent with all of the request
    // handlers. Inconsistent lock ordering can cause deadlock.
    let mut turtles = Vec::new();
    for id in app.turtle_ids().await {
        turtles.push(app.turtle(id).await);
    }
    // Very important to have all the data locked before rendering. Do not want renderer to have
    // to figure out how to lock.
    let mut locked_turtles = Vec::with_capacity(turtles.len());
    for turtle in &turtles {
        locked_turtles.push(turtle.lock().await);
    }
    // Renderer only needs (read-only) access to TurtleState
    // Doing this also decouples renderer code from runtime by not having to
    // know about the `MutexGuard` type in tokio
    let turtle_states = locked_turtles.iter().map(|t| &t.state);

    let display_list = display_list.lock().await;

    let draw_size = gl_context.window().inner_size();
    renderer.render(draw_size, &display_list, &drawing, turtle_states);
    gl_context.swap_buffers().expect("unable to swap the buffer (for double buffering)");
}

fn spawn_async_server(
    handle: &Handle,
    app: Arc<App>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: EventLoopNotifier,
    events_receiver: mpsc::UnboundedReceiver<Event>,
    establish_connection: impl Future<Output=Result<(ServerSender, ServerReceiver), ConnectionError>> + Send + 'static,
    server_shutdown_receiver: mpsc::Receiver<()>,
) {
    // Spawn root task
    handle.spawn(async {
        let (conn_sender, conn_receiver) = establish_connection.await
            .expect("unable to establish turtle server connection");

        super::serve(
            conn_sender,
            conn_receiver,
            app,
            display_list,
            event_loop,
            events_receiver,
            server_shutdown_receiver,
        ).await;
    });
}
<commit_msg>Tweaking comments in main.rs<commit_after>use std::time::{Instant, Duration};
use std::future::Future;
use std::sync::Arc;

use glutin::{
    GlProfile,
    GlRequest,
    ContextBuilder,
    WindowedContext,
    PossiblyCurrent,
    dpi::{LogicalSize, PhysicalPosition},
    window::{WindowBuilder, Fullscreen},
    event::{
        Event as GlutinEvent,
        StartCause,
        WindowEvent,
        KeyboardInput,
        VirtualKeyCode,
        ElementState,
    },
    event_loop::{ControlFlow, EventLoop},
    platform::desktop::EventLoopExtDesktop,
};
use tokio::{
    sync::{mpsc, Mutex},
    runtime::Handle,
};

use crate::Event;
use crate::ipc_protocol::{ServerSender, ServerReceiver, ConnectionError};

use super::{
    app::App,
    coords::ScreenPoint,
    renderer::{
        Renderer,
        display_list::DisplayList,
    },
    event_loop_notifier::{EventLoopNotifier, MainThreadAction},
};

/// The maximum rendering FPS allowed
///
/// Rendering is intentionally throttled to avoid too much contention over the display list. If
/// multiple turtles are used or if many lines are drawn quickly, we may get >= 1 redraw request
/// per *millisecond* this is far too many redraws. Limiting to this rate helps avoid that.
const MAX_RENDERING_FPS: u64 = 60;

// 1,000,000 us in 1 s
const MICROS_PER_SEC: u64 = 1_000_000;

fn new_event_loop<T>() -> EventLoop<T> {
    cfg_if::cfg_if! {
        if #[cfg(target_os = "macos")] {
            EventLoop::with_user_event()

        } else if #[cfg(target_os = "windows")] {
            use glutin::platform::windows::EventLoopExtWindows;
            EventLoop::new_any_thread()

        } else {
            use glutin::platform::unix::EventLoopExtUnix;
            EventLoop::new_any_thread()
        }
    }
}

/// Run the window event loop in the current thread/task
///
/// When the window is opened, this will spawn a task that establishes the server connection using
/// the given future and begin to serve client requests.
///
/// On some platforms this function may only run on the main thread
pub fn run_main(
    // A handle used to block on asynchronous code and spawn new tasks
    //
    // Necessary because this function is not run on a runtime thread in all backends
    handle: Handle,

    // Polled to establish the server connection
    establish_connection: impl Future<Output=Result<(ServerSender, ServerReceiver), ConnectionError>> + Send + 'static,
) {
    // The state of the drawing and the state/drawings associated with each turtle
    let app = Arc::new(App::default());
    // All of the drawing primitives in the order in which they wil be drawn
    //
    // This is managed separately from the rest of the app state because the display list is shared
    // by pretty much everything. Trying to control it via `AccessControl` would remove all
    // opportunities for parallelism and essentially make all turtle programs sequential.
    //
    // Critical sections containing the display list should be as short as possible.
    let display_list = Arc::new(Mutex::new(DisplayList::default()));

    let mut event_loop = new_event_loop();
    // Create the proxy that will be given to the thread managing IPC
    let event_loop_notifier = EventLoopNotifier::new(event_loop.create_proxy());

    // A channel for transferring events
    let (events_sender, events_receiver) = mpsc::unbounded_channel();
    // Put these variables in an Option so we can call `take()` in the event loop. Required
    // because borrow checker cannot verify which events only fire once.
    let mut events_receiver = Some(events_receiver);
    let mut establish_connection = Some(establish_connection);
    let (mut server_shutdown, server_shutdown_receiver) = mpsc::channel(1);
    let mut server_shutdown_receiver = Some(server_shutdown_receiver);

    let window_builder = {
        let drawing = handle.block_on(app.drawing_mut());
        WindowBuilder::new()
            .with_title(&drawing.title)
            .with_inner_size(LogicalSize {width: drawing.width, height: drawing.height})
    };

    // Create an OpenGL 3.x context for Pathfinder to use
    let gl_context = ContextBuilder::new()
        .with_gl(GlRequest::Latest)
        .with_gl_profile(GlProfile::Core)
        .with_vsync(true)
        .with_double_buffer(Some(true))
        .build_windowed(window_builder, &event_loop)
        .expect("either could not create window or could not build OpenGL context");

    // Load OpenGL, and make the context current
    let gl_context = unsafe { gl_context.make_current().unwrap() };
    gl::load_with(|name| gl_context.get_proc_address(name) as *const _);

    // Need to draw using the physical size in pixels, not the logical size
    let draw_size = gl_context.window().inner_size();
    let mut renderer = Renderer::new(draw_size, gl_context.window().scale_factor());

    // For rate limiting rendering
    let min_render_delay = Duration::from_micros(MICROS_PER_SEC / MAX_RENDERING_FPS);
    // Subtracting the delay so we do an initial render right away
    let mut last_render = Instant::now() - min_render_delay;
    // Very important to use `run_return` here instead of `run` because `run` calls process::exit()
    // and that is not appropriate for the multithreaded backend as that would cause the entire
    // process to end when the window is closed.
    event_loop.run_return(move |event, _, control_flow| match event {
        GlutinEvent::NewEvents(StartCause::Init) => {
            // Spawn the actual server thread(s) that will handle incoming IPC messages and
            // asynchronous update the shared state
            //
            // Note that putting this code here instead of before the event loop causes the
            // `Turtle::new()`, etc. methods not to return before the window opens. Those methods
            // can't return because the connection handshake cannot complete before the thread used
            // for IPC is spawned.
            spawn_async_server(
                &handle,
                app.clone(),
                display_list.clone(),
                event_loop_notifier.clone(),
                events_receiver.take().expect("bug: init event should only occur once"),
                establish_connection.take().expect("bug: init event should only occur once"),
                server_shutdown_receiver.take().expect("bug: init event should only occur once"),
            );
        },

        GlutinEvent::NewEvents(StartCause::ResumeTimeReached {..}) => {
            // A render was delayed in the `RedrawRequested` so let's try to do it again now that
            // we have resumed
            gl_context.window().request_redraw();
        },

        // Quit if the window is closed or if Esc is pressed and then released
        GlutinEvent::WindowEvent {
            event: WindowEvent::CloseRequested,
            ..
        } | GlutinEvent::WindowEvent {
            event: WindowEvent::Destroyed,
            ..
        } | GlutinEvent::WindowEvent {
            event: WindowEvent::KeyboardInput {
                input: KeyboardInput {
                    state: ElementState::Released,
                    virtual_keycode: Some(VirtualKeyCode::Escape),
                    ..
                },
                ..
            },
            ..
        } => {
            *control_flow = ControlFlow::Exit;
        },

        GlutinEvent::WindowEvent {
            event: WindowEvent::ScaleFactorChanged {scale_factor, ..},
            ..
        } => {
            renderer.set_scale_factor(scale_factor);
        },

        GlutinEvent::WindowEvent {event, ..} => {
            let scale_factor = renderer.scale_factor();
            match event {
                WindowEvent::Resized(size) => {
                    let size = size.to_logical(scale_factor);
                    let mut drawing = handle.block_on(app.drawing_mut());
                    drawing.width = size.width;
                    drawing.height = size.height;
                },

                //TODO: There are currently no events for updating is_maximized, so that property
                // should not be relied on. https://github.com/rust-windowing/glutin/issues/1298

                _ => {},
            }

            // Converts to logical coordinates, only locking the drawing if this is actually called
            let to_logical = |pos: PhysicalPosition<f64>| {
                let drawing = handle.block_on(app.drawing_mut());
                let center = drawing.center;
                let draw_size = gl_context.window().inner_size();
                let fb_center = ScreenPoint {
                    x: draw_size.width as f64 / 2.0,
                    y: draw_size.height as f64 / 2.0,
                };

                let pos: ScreenPoint = pos.into();
                pos.to_logical(scale_factor, center, fb_center)
            };

            //TODO: There is no guarantee that sending this event here will actually allow a client
            // to receive it. After all, if the window closes and this process exits, there will be
            // no way to handle subsequent `NextEvent` requests.
            if let Some(event) = Event::from_window_event(event, scale_factor, to_logical) {
                // Sending may fail if the IPC thread has ended due to a disconnection when the
                // main process ends. This is not a fatal error though so we just ignore it.
                events_sender.send(event).unwrap_or(());
            }
        },

        // Window events are currently sufficient for the turtle event API
        GlutinEvent::DeviceEvent {..} => {},

        GlutinEvent::UserEvent(MainThreadAction::Redraw) => {
            gl_context.window().request_redraw();
        },

        GlutinEvent::UserEvent(MainThreadAction::SetTitle(title)) => {
            gl_context.window().set_title(&title);
        },

        GlutinEvent::UserEvent(MainThreadAction::SetSize(size)) => {
            gl_context.window().set_inner_size(size);
        },

        GlutinEvent::UserEvent(MainThreadAction::SetIsMaximized(is_maximized)) => {
            gl_context.window().set_maximized(is_maximized);
        },

        GlutinEvent::UserEvent(MainThreadAction::SetIsFullscreen(is_fullscreen)) => {
            gl_context.window().set_fullscreen(if is_fullscreen {
                Some(Fullscreen::Borderless(gl_context.window().current_monitor()))
            } else { None });
        },

        GlutinEvent::RedrawRequested(_) => {
            // Check if we just rendered
            let last_render_delay = last_render.elapsed();
            if last_render_delay < min_render_delay {
                let remaining = min_render_delay - last_render_delay;
                *control_flow = ControlFlow::WaitUntil(Instant::now() + remaining);
                return;
            }

            handle.block_on(redraw(&app, &display_list, &gl_context, &mut renderer));
            last_render = Instant::now();

            // Do not re-render unless there is a reason to
            //
            // This is why the window has 0 CPU usage when nothing is happening
            *control_flow = ControlFlow::Wait;
        },

        GlutinEvent::LoopDestroyed => {
            // Notify the server that it should shutdown, ignoring the error if the channel has
            // been dropped since that just means that the server task has ended already
            handle.block_on(server_shutdown.send(())).unwrap_or(());
        },

        _ => {},
    });
}

async fn redraw(
    app: &App,
    display_list: &Mutex<DisplayList>,
    gl_context: &WindowedContext<PossiblyCurrent>,
    renderer: &mut Renderer,
) {
    let drawing = {
        // Hold the drawing lock for as little time as possible
        let drawing = app.drawing_mut().await;
        drawing.clone()
    };

    // Locking the turtles before the display list to be consistent with all of the request
    // handlers. Inconsistent lock ordering can cause deadlock.
    let mut turtles = Vec::new();
    for id in app.turtle_ids().await {
        turtles.push(app.turtle(id).await);
    }
    // Very important to have all the data locked before rendering. Do not want renderer to have
    // to figure out how to lock.
    let mut locked_turtles = Vec::with_capacity(turtles.len());
    for turtle in &turtles {
        locked_turtles.push(turtle.lock().await);
    }
    // Renderer only needs (read-only) access to TurtleState
    // Doing this also decouples renderer code from runtime by not having to
    // know about the `MutexGuard` type in tokio
    let turtle_states = locked_turtles.iter().map(|t| &t.state);

    let display_list = display_list.lock().await;

    let draw_size = gl_context.window().inner_size();
    renderer.render(draw_size, &display_list, &drawing, turtle_states);
    gl_context.swap_buffers().expect("unable to swap the buffer (for double buffering)");
}

fn spawn_async_server(
    handle: &Handle,
    app: Arc<App>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: EventLoopNotifier,
    events_receiver: mpsc::UnboundedReceiver<Event>,
    establish_connection: impl Future<Output=Result<(ServerSender, ServerReceiver), ConnectionError>> + Send + 'static,
    server_shutdown_receiver: mpsc::Receiver<()>,
) {
    handle.spawn(async {
        let (conn_sender, conn_receiver) = establish_connection.await
            .expect("unable to establish turtle server connection");

        super::serve(
            conn_sender,
            conn_receiver,
            app,
            display_list,
            event_loop,
            events_receiver,
            server_shutdown_receiver,
        ).await;
    });
}
<|endoftext|>


<commit_before>extern crate find_folder;

use std::path::PathBuf;
use graphics::Texture;
use piston_window::{PistonWindow, Flip, TextureSettings};

pub enum Textures {
    EmptyTile,
}

pub struct Manager {
    assets_path: PathBuf,
}

impl Manager {
    pub fn new() -> Self {
        Manager { assets_path: find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap() }
    }

    pub fn get_asset(&self, name: &str) -> PathBuf {
        self.assets_path.join(name)
    }

    pub fn get_font(&self) -> PathBuf {
        self.get_asset("NotoSans-Regular.ttf")
    }

    pub fn load_texture(&self, window: &PistonWindow, texture: Textures) -> Texture {
        Texture::from_path(&mut *window.factory.borrow_mut(),
                           self.get_asset(texture_to_str(texture)),
                           Flip::None,
                           &TextureSettings::new())
            .unwrap()
    }
}

fn texture_to_str(texture: Textures) -> &'static str {
    match texture {
        Textures::EmptyTile => "skeleton.png",
    }
}

#[test]
fn new() {
    let manager = Manager::new();
    assert!(!manager.assets_path.to_string_lossy().is_empty());
    assert!(manager.assets_path.is_absolute());
    assert!(manager.assets_path.exists());
    assert!(manager.assets_path.is_dir());
}

#[test]
fn get_asset() {
    let manager = Manager::new();
    let asset_path = manager.get_asset("test");
    assert!(asset_path.to_string_lossy().len() > manager.assets_path.to_string_lossy().len());
}

#[test]
fn get_font() {
    let manager = Manager::new();
    let font_path = manager.get_font();
    assert!(font_path.is_absolute());
    assert!(font_path.is_file());
    assert_eq!("ttf", font_path.extension().unwrap());
}
<commit_msg>Empty tile - different texture<commit_after>extern crate find_folder;

use std::path::PathBuf;
use graphics::Texture;
use piston_window::{PistonWindow, Flip, TextureSettings};

pub enum Textures {
    EmptyTile,
}

pub struct Manager {
    assets_path: PathBuf,
}

impl Manager {
    pub fn new() -> Self {
        Manager { assets_path: find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap() }
    }

    pub fn get_asset(&self, name: &str) -> PathBuf {
        self.assets_path.join(name)
    }

    pub fn get_font(&self) -> PathBuf {
        self.get_asset("NotoSans-Regular.ttf")
    }

    pub fn load_texture(&self, window: &PistonWindow, texture: Textures) -> Texture {
        Texture::from_path(&mut *window.factory.borrow_mut(),
                           self.get_asset(texture_to_str(texture)),
                           Flip::None,
                           &TextureSettings::new())
            .unwrap()
    }
}

fn texture_to_str(texture: Textures) -> &'static str {
    match texture {
        Textures::EmptyTile => "empty_tile.png",
    }
}

#[test]
fn new() {
    let manager = Manager::new();
    assert!(!manager.assets_path.to_string_lossy().is_empty());
    assert!(manager.assets_path.is_absolute());
    assert!(manager.assets_path.exists());
    assert!(manager.assets_path.is_dir());
}

#[test]
fn get_asset() {
    let manager = Manager::new();
    let asset_path = manager.get_asset("test");
    assert!(asset_path.to_string_lossy().len() > manager.assets_path.to_string_lossy().len());
}

#[test]
fn get_font() {
    let manager = Manager::new();
    let font_path = manager.get_font();
    assert!(font_path.is_absolute());
    assert!(font_path.is_file());
    assert_eq!("ttf", font_path.extension().unwrap());
}
<|endoftext|>


<commit_before>// Binop corner cases

fn test_nil() {
    assert (() == ());
    assert (!(() != ()));
    assert (!(() < ()));
    assert (() <= ());
    assert (!(() > ()));
    assert (() >= ());
}

fn test_bool() {
    assert (!(true < false));
    assert (!(true <= false));
    assert (true > false);
    assert (true >= false);

    assert (false < true);
    assert (false <= true);
    assert (!(false > true));
    assert (!(false >= true));

    // Bools support bitwise binops
    assert (false & false == false);
    assert (true & false == false);
    assert (true & true == true);
    assert (false | false == false);
    assert (true | false == true);
    assert (true | true == true);
    assert (false ^ false == false);
    assert (true ^ false == true);
    assert (true ^ true == false);
}

fn test_char() {
    let ch10 = 10 as char;
    let ch4 = 4 as char;
    let ch2 = 2 as char;
    assert (ch10 + ch4 == 14 as char);
    assert (ch10 - ch4 == 6 as char);
    assert (ch10 * ch4 == 40 as char);
    assert (ch10 / ch4 == ch2);
    assert (ch10 % ch4 == ch2);
    assert (ch10 >> ch2 == ch2);
    assert (ch10 >>> ch2 == ch2);
    assert (ch10 << ch4 == 160 as char);
    assert (ch10 | ch4 == 14 as char);
    assert (ch10 & ch2 == ch2);
    assert (ch10 ^ ch2 == 8 as char);
}

fn test_box() {
    assert (@10 == 10);
    assert (0xFF & @0xF0 == 0xF0);
    assert ({a: 1, b: 3} < @{a: 1, b: 4});
    assert (@{a: 'x'} != @{a: 'y'});
}

fn test_port() {
    let p1: port[int] = port();
    let p2: port[int] = port();

    // FIXME (#577) comparison of ports
    // assert (p1 != p2);
    // assert !(p1 < p2);
    // etc
}

fn test_chan() {
    let p: port[int] = port();
    let ch1 = chan(p);
    let ch2 = chan(p);

    // FIXME (#577) comparison of channels
    // assert (ch1 != ch2);
    // etc
}

fn test_ptr() {
    // FIXME: Don't know what binops apply to pointers. Don't know how
    // to make or use pointers
}

fn test_task() {
    fn f() { }
    let t1 = spawn f();
    let t2 = spawn f();
    // FIXME (#577) comparison of tasks
    //assert t1 != t2;
}

fn test_fn() {
    fn f() { }
    fn g() { }
    fn h(i: int) { }
    let f1 = f;
    let f2 = f;
    let g1 = g;
    let h1 = h;
    let h2 = h;
    assert (f1 == f2);
    assert (f1 == f);

    assert (f1 != g1);
    assert (h1 == h2);
    assert (!(f1 != f2));
    assert (!(h1 < h2));
    assert (h1 <= h2);
    assert (!(h1 > h2));
    assert (h1 >= h2);
}

native "rust" mod native_mod = "" {
    fn str_byte_len(s: str) -> vec[u8];
    fn str_alloc(n_bytes: uint) -> str;
}

// FIXME: comparison of native fns
fn test_native_fn() {
    /*assert (native_mod::str_byte_len == native_mod::str_byte_len);
      assert (native_mod::str_byte_len != native_mod::str_alloc);*/
}

fn test_obj() {
    let o1 = obj () {  };
    let o2 = obj () {  };

    assert (o1 != o2);
    assert (!(o1 == o2));

    obj constr1(i: int) { }
    obj constr2(i: int) { }

    let o5 = constr1(10);
    let o6 = constr1(10);
    let o7 = constr1(11);
    let o8 = constr2(11);

    assert (o5 != o6);
    assert (o6 != o7);
    assert (o7 != o8);
}

fn main() {
    test_nil();
    test_bool();
    test_char();
    test_box();
    test_port();
    test_chan();
    test_ptr();
    test_task();
    test_fn();
    test_native_fn();
    test_obj();
}
<commit_msg>test: XFAIL binops.rs for now due to mysterious tinderbox failure on Linux<commit_after>// xfail-stage0
// xfail-stage1
// xfail-stage2
// xfail-stage3

// Binop corner cases

fn test_nil() {
    assert (() == ());
    assert (!(() != ()));
    assert (!(() < ()));
    assert (() <= ());
    assert (!(() > ()));
    assert (() >= ());
}

fn test_bool() {
    assert (!(true < false));
    assert (!(true <= false));
    assert (true > false);
    assert (true >= false);

    assert (false < true);
    assert (false <= true);
    assert (!(false > true));
    assert (!(false >= true));

    // Bools support bitwise binops
    assert (false & false == false);
    assert (true & false == false);
    assert (true & true == true);
    assert (false | false == false);
    assert (true | false == true);
    assert (true | true == true);
    assert (false ^ false == false);
    assert (true ^ false == true);
    assert (true ^ true == false);
}

fn test_char() {
    let ch10 = 10 as char;
    let ch4 = 4 as char;
    let ch2 = 2 as char;
    assert (ch10 + ch4 == 14 as char);
    assert (ch10 - ch4 == 6 as char);
    assert (ch10 * ch4 == 40 as char);
    assert (ch10 / ch4 == ch2);
    assert (ch10 % ch4 == ch2);
    assert (ch10 >> ch2 == ch2);
    assert (ch10 >>> ch2 == ch2);
    assert (ch10 << ch4 == 160 as char);
    assert (ch10 | ch4 == 14 as char);
    assert (ch10 & ch2 == ch2);
    assert (ch10 ^ ch2 == 8 as char);
}

fn test_box() {
    assert (@10 == 10);
    assert (0xFF & @0xF0 == 0xF0);
    assert ({a: 1, b: 3} < @{a: 1, b: 4});
    assert (@{a: 'x'} != @{a: 'y'});
}

fn test_port() {
    let p1: port[int] = port();
    let p2: port[int] = port();

    // FIXME (#577) comparison of ports
    // assert (p1 != p2);
    // assert !(p1 < p2);
    // etc
}

fn test_chan() {
    let p: port[int] = port();
    let ch1 = chan(p);
    let ch2 = chan(p);

    // FIXME (#577) comparison of channels
    // assert (ch1 != ch2);
    // etc
}

fn test_ptr() {
    // FIXME: Don't know what binops apply to pointers. Don't know how
    // to make or use pointers
}

fn test_task() {
    fn f() { }
    let t1 = spawn f();
    let t2 = spawn f();
    // FIXME (#577) comparison of tasks
    //assert t1 != t2;
}

fn test_fn() {
    fn f() { }
    fn g() { }
    fn h(i: int) { }
    let f1 = f;
    let f2 = f;
    let g1 = g;
    let h1 = h;
    let h2 = h;
    assert (f1 == f2);
    assert (f1 == f);

    assert (f1 != g1);
    assert (h1 == h2);
    assert (!(f1 != f2));
    assert (!(h1 < h2));
    assert (h1 <= h2);
    assert (!(h1 > h2));
    assert (h1 >= h2);
}

native "rust" mod native_mod = "" {
    fn str_byte_len(s: str) -> vec[u8];
    fn str_alloc(n_bytes: uint) -> str;
}

// FIXME: comparison of native fns
fn test_native_fn() {
    /*assert (native_mod::str_byte_len == native_mod::str_byte_len);
      assert (native_mod::str_byte_len != native_mod::str_alloc);*/
}

fn test_obj() {
    let o1 = obj () {  };
    let o2 = obj () {  };

    assert (o1 != o2);
    assert (!(o1 == o2));

    obj constr1(i: int) { }
    obj constr2(i: int) { }

    let o5 = constr1(10);
    let o6 = constr1(10);
    let o7 = constr1(11);
    let o8 = constr2(11);

    assert (o5 != o6);
    assert (o6 != o7);
    assert (o7 != o8);
}

fn main() {
    test_nil();
    test_bool();
    test_char();
    test_box();
    test_port();
    test_chan();
    test_ptr();
    test_task();
    test_fn();
    test_native_fn();
    test_obj();
}
<|endoftext|>