<commit_before>//! Messages from Streaming API.

mod event;
mod warning;

pub use self::event::{Event, EventKind};
pub use self::warning::{Warning, WarningCode};

use {DirectMessage};
use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Unexpected, Visitor};
use serde::de::impls::IgnoredAny;
use std::fmt;
use tweet::{StatusId, Tweet};
use types::{JsonMap, JsonValue};
use user::UserId;

/// Represents a message from Twitter Streaming API.
///
/// # Reference
///
/// 1. [Streaming message types — Twitter Developers](https://dev.twitter.com/streaming/overview/messages-types)
#[derive(Clone, Debug, PartialEq)]
pub enum StreamMessage {
    /// Tweet
    Tweet(Box<Tweet>),

    /// Notifications about non-Tweet events.
    Event(Box<Event>),

    /// Indicate that a given Tweet has been deleted.
    Delete(Delete),

    /// Indicate that geolocated data must be stripped from a range of Tweets.
    ScrubGeo(ScrubGeo),

    /// Indicate that a filtered stream has matched more Tweets than its current rate limit allows to be delivered,
    /// noticing a total count of the number of undelivered Tweets since the connection was opened.
    Limit(Limit),

    /// Indicate that a given tweet has had its content withheld.
    StatusWithheld(StatusWithheld),

    /// Indicate that a user has had their content withheld.
    UserWithheld(UserWithheld),

    /// This message is sent when a stream is disconnected, indicating why the stream was closed.
    Disconnect(Disconnect),

    /// Variout warning message
    Warning(Warning),

    /// List of the user's friends. Only be sent upon establishing a User Stream connection.
    Friends(Friends),

    // FriendsStr(Vec<String>), // TODO: deserialize `friends_str` into `Friends`

    /// Direct message
    DirectMessage(Box<DirectMessage>),

    /// A [control URI][1] for Site Streams.
    /// [1]: https://dev.twitter.com/streaming/sitestreams/controlstreams
    Control(Control),

    /// An [envelope][1] for Site Stream.
    /// [1]: https://dev.twitter.com/streaming/overview/messages-types#envelopes_for_user
    ForUser(UserId, Box<StreamMessage>),

    // ForUserStr(String, Box<StreamMessage>),

    /// A message not known to this library.
    Custom(JsonMap<String, JsonValue>),
}

/// Represents a deleted Tweet.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Delete {
    pub id: StatusId,
    pub user_id: UserId,
}

/// Represents a range of Tweets whose geolocated data must be stripped.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct ScrubGeo {
    pub user_id: UserId,
    pub up_to_status_id: StatusId,
}

#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct Limit {
    pub track: u64,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct StatusWithheld {
    pub id: StatusId,
    pub user_id: UserId,
    pub withheld_in_countries: Vec<String>,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct UserWithheld {
    pub id: UserId,
    pub withheld_in_countries: Vec<String>,
}

/// Indicates why a stream was closed.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct Disconnect {
    pub code: DisconnectCode,
    pub stream_name: String,
    pub reason: String,
}

macro_rules! number_enum {
    (
        $(#[$attr:meta])*
        pub enum $E:ident {
            $(
                $(#[$v_attr:meta])*
                :$V:ident = $n:expr,
            )*
        }
    ) => {
        $(#[$attr])*
        pub enum $E {
            $(
                $(#[$v_attr])*
                $V = $n,
            )*
        }

        impl Deserialize for $E {
            fn deserialize<D: Deserializer>(d: D) -> Result<Self, D::Error> {
                struct NEVisitor;

                impl Visitor for NEVisitor {
                    type Value = $E;

                    fn visit_u64<E: Error>(self, v: u64) -> Result<$E, E> {
                        match v {
                            $($n => Ok($E::$V),)*
                            _ => Err(E::invalid_value(Unexpected::Unsigned(v), &self)),
                        }
                    }

                    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                        write!(f, concat!("one of the following integers: ", $($n, ','),*))
                    }
                }

                d.deserialize_u64(NEVisitor)
            }
        }

        impl AsRef<str> for $E {
            fn as_ref(&self) -> &str {
                match *self {
                    $($E::$V => stringify!($V),)*
                }
            }
        }
    };
}

number_enum! {
    /// Status code for a `Disconnect` message.
    #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
    pub enum DisconnectCode {
        /// The feed was shutdown (possibly a machine restart).
        :Shutdown = 1,
        /// The same endpoint was connected too many times.
        :DuplicateStream = 2,
        /// Control streams was used to close a stream (applies to sitestreams).
        :ControlRequest = 3,
        /// The client was reading too slowly and was disconnected by the server.
        :Stall = 4,
        /// The client appeared to have initiated a disconnect.
        :Normal = 5,
        /// An oauth token was revoked for a user (applies to site and userstreams).
        :TokenRevoked = 6,
        /// The same credentials were used to connect a new stream and the oldest was disconnected.
        :AdminLogout = 7,
        // Reserved for internal use. Will not be delivered to external clients.
        // _ = 8,
        /// The stream connected with a negative count parameter and was disconnected after all backfill was delivered.
        :MaxMessageLimit = 9,
        /// An internal issue disconnected the stream.
        :StreamException = 10,
        /// An internal issue disconnected the stream.
        :BrokerStall = 11,
        /// The host the stream was connected to became overloaded and streams were disconnected to balance load.
        /// Reconnect as usual.
        :ShedLoad = 12,
    }
}

/// Represents a control message.
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Hash)]
pub struct Control {
    control_uri: String,
}

pub type Friends = Vec<UserId>;

impl Deserialize for StreamMessage {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer {
        struct SMVisitor;

        impl Visitor for SMVisitor {
            type Value = StreamMessage;

            fn visit_map<V>(self, mut v: V) -> Result<StreamMessage, V::Error> where V: MapVisitor {
                let key = match v.visit_key::<String>()? {
                    Some(k) => k,
                    None => return Ok(StreamMessage::Custom(JsonMap::new())),
                };

                let ret = match key.as_str() {
                    "delete"          => Some(v.visit_value().map(StreamMessage::Delete)),
                    "scrub_geo"       => Some(v.visit_value().map(StreamMessage::ScrubGeo)),
                    "limit"           => Some(v.visit_value().map(StreamMessage::Limit)),
                    "status_withheld" => Some(v.visit_value().map(StreamMessage::StatusWithheld)),
                    "user_withheld"   => Some(v.visit_value().map(StreamMessage::UserWithheld)),
                    "disconnect"      => Some(v.visit_value().map(StreamMessage::Disconnect)),
                    "warning"         => Some(v.visit_value().map(StreamMessage::Warning)),
                    "friends"         => Some(v.visit_value().map(StreamMessage::Friends)),
                    // "friends_str"     => Some(v.visit_value().map(StreamMessage::Friends)),
                    "direct_message"  => Some(v.visit_value().map(StreamMessage::DirectMessage)),
                    "control"         => Some(v.visit_value().map(StreamMessage::Control)),
                    _ => None,
                };

                if let Some(ret) = ret {
                    if ret.is_ok() {
                        while v.visit::<IgnoredAny,IgnoredAny>()?.is_some() {}
                    }
                    return ret;
                }

                // Tweet, Event or for_user envelope:

                let mut map = JsonMap::new();
                map.insert(key, v.visit_value()?);
                while let Some((k, v)) = v.visit()? {
                    map.insert(k, v);
                }

                if map.contains_key("id") {
                    Tweet::deserialize(JsonValue::Object(map))
                        .map(Box::new)
                        .map(StreamMessage::Tweet)
                        .map_err(|e| V::Error::custom(e.to_string()))
                } else if map.contains_key("event") {
                    Event::deserialize(JsonValue::Object(map))
                        .map(Box::new)
                        .map(StreamMessage::Event)
                        .map_err(|e| V::Error::custom(e.to_string()))
                } else if let Some(id) = map.remove("for_user") {
                    if let JsonValue::Number(id) = id {
                        if let Some(id) = id.as_u64() {
                            if let Some(msg) = map.remove("message") {
                                StreamMessage::deserialize(msg)
                                    .map(|m| StreamMessage::ForUser(id, Box::new(m)))
                                    .map_err(|e| V::Error::custom(e.to_string()))
                            } else {
                                Err(V::Error::missing_field("message"))
                            }
                        } else {
                            Err(V::Error::custom("expected u64"))
                        }
                    } else {
                        Err(V::Error::custom("expected u64"))
                    }
                } else {
                    Ok(StreamMessage::Custom(map))
                }
            }

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "map")
            }
        }

        deserializer.deserialize_map(SMVisitor)
    }
}

impl Deserialize for Delete {
    fn deserialize<D: Deserializer>(d: D) -> Result<Self, D::Error> {
        struct DeleteVisitor;

        impl Visitor for DeleteVisitor {
            type Value = Delete;

            fn visit_map<V: MapVisitor>(self, mut v: V) -> Result<Delete, V::Error> {
                use std::mem;

                #[allow(dead_code)]
                #[derive(Deserialize)]
                struct Status { id: StatusId, user_id: UserId };

                while let Some(k) = v.visit_key::<String>()? {
                    if "status" == k.as_str() {
                        let ret = v.visit_value::<Status>()?;
                        while v.visit::<IgnoredAny,IgnoredAny>()?.is_some() {}
                        unsafe {
                            return Ok(mem::transmute(ret));
                        }
                    } else {
                        v.visit_value::<IgnoredAny>()?;
                    }
                }

                Err(V::Error::missing_field("status"))
            }

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "a map with a field `status` which contains field `id` and `user_id` of integer type`")
            }
        }

        d.deserialize_map(DeleteVisitor)
    }
}

impl fmt::Display for Disconnect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: {} {}: {}", self.stream_name, self.code as u32, self.code.as_ref(), self.reason)
    }
}

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

    #[test]
    fn warning() {
        assert_eq!(
            StreamMessage::Warning(Warning {
                message: "Your connection is falling behind and messages are being queued for delivery to you. \
                    Your queue is now over 60% full. You will be disconnected when the queue is full.".to_owned(),
                code: WarningCode::FallingBehind(60),
            }),
            json::from_str(
                "{\"warning\":{\"code\":\"FALLING_BEHIND\",\"message\":\"Your connection is falling \
                    behind and messages are being queued for delivery to you. Your queue is now over 60% full. \
                    You will be disconnected when the queue is full.\",\"percent_full\": 60}}"
            ).unwrap()
        )
    }
}
<commit_msg>Minor cleanup<commit_after>//! Messages from Streaming API.

mod event;
mod warning;

pub use self::event::{Event, EventKind};
pub use self::warning::{Warning, WarningCode};

use {DirectMessage};
use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Unexpected, Visitor};
use serde::de::impls::IgnoredAny;
use std::fmt;
use tweet::{StatusId, Tweet};
use types::{JsonMap, JsonValue};
use user::UserId;

/// Represents a message from Twitter Streaming API.
///
/// # Reference
///
/// 1. [Streaming message types — Twitter Developers](https://dev.twitter.com/streaming/overview/messages-types)
#[derive(Clone, Debug, PartialEq)]
pub enum StreamMessage {
    /// Tweet
    Tweet(Box<Tweet>),

    /// Notifications about non-Tweet events.
    Event(Box<Event>),

    /// Indicate that a given Tweet has been deleted.
    Delete(Delete),

    /// Indicate that geolocated data must be stripped from a range of Tweets.
    ScrubGeo(ScrubGeo),

    /// Indicate that a filtered stream has matched more Tweets than its current rate limit allows to be delivered,
    /// noticing a total count of the number of undelivered Tweets since the connection was opened.
    Limit(Limit),

    /// Indicate that a given tweet has had its content withheld.
    StatusWithheld(StatusWithheld),

    /// Indicate that a user has had their content withheld.
    UserWithheld(UserWithheld),

    /// This message is sent when a stream is disconnected, indicating why the stream was closed.
    Disconnect(Disconnect),

    /// Variout warning message
    Warning(Warning),

    /// List of the user's friends. Only be sent upon establishing a User Stream connection.
    Friends(Friends),

    // FriendsStr(Vec<String>), // TODO: deserialize `friends_str` into `Friends`

    /// Direct message
    DirectMessage(Box<DirectMessage>),

    /// A [control URI][1] for Site Streams.
    /// [1]: https://dev.twitter.com/streaming/sitestreams/controlstreams
    Control(Control),

    /// An [envelope][1] for Site Stream.
    /// [1]: https://dev.twitter.com/streaming/overview/messages-types#envelopes_for_user
    ForUser(UserId, Box<StreamMessage>),

    // ForUserStr(String, Box<StreamMessage>),

    /// A message not known to this library.
    Custom(JsonMap<String, JsonValue>),
}

/// Represents a deleted Tweet.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Delete {
    pub id: StatusId,
    pub user_id: UserId,
}

/// Represents a range of Tweets whose geolocated data must be stripped.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct ScrubGeo {
    pub user_id: UserId,
    pub up_to_status_id: StatusId,
}

#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct Limit {
    pub track: u64,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct StatusWithheld {
    pub id: StatusId,
    pub user_id: UserId,
    pub withheld_in_countries: Vec<String>,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct UserWithheld {
    pub id: UserId,
    pub withheld_in_countries: Vec<String>,
}

/// Indicates why a stream was closed.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash)]
pub struct Disconnect {
    pub code: DisconnectCode,
    pub stream_name: String,
    pub reason: String,
}

macro_rules! number_enum {
    (
        $(#[$attr:meta])*
        pub enum $E:ident {
            $(
                $(#[$v_attr:meta])*
                :$V:ident = $n:expr,
            )*
        }
    ) => {
        $(#[$attr])*
        pub enum $E {
            $(
                $(#[$v_attr])*
                $V = $n,
            )*
        }

        impl Deserialize for $E {
            fn deserialize<D: Deserializer>(d: D) -> Result<Self, D::Error> {
                struct NEVisitor;

                impl Visitor for NEVisitor {
                    type Value = $E;

                    fn visit_u64<E: Error>(self, v: u64) -> Result<$E, E> {
                        match v {
                            $($n => Ok($E::$V),)*
                            _ => Err(E::invalid_value(Unexpected::Unsigned(v), &self)),
                        }
                    }

                    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                        write!(f, concat!("one of the following integers: ", $($n, ','),*))
                    }
                }

                d.deserialize_u64(NEVisitor)
            }
        }

        impl AsRef<str> for $E {
            fn as_ref(&self) -> &str {
                match *self {
                    $($E::$V => stringify!($V),)*
                }
            }
        }
    };
}

number_enum! {
    /// Status code for a `Disconnect` message.
    #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
    pub enum DisconnectCode {
        /// The feed was shutdown (possibly a machine restart).
        :Shutdown = 1,
        /// The same endpoint was connected too many times.
        :DuplicateStream = 2,
        /// Control streams was used to close a stream (applies to sitestreams).
        :ControlRequest = 3,
        /// The client was reading too slowly and was disconnected by the server.
        :Stall = 4,
        /// The client appeared to have initiated a disconnect.
        :Normal = 5,
        /// An oauth token was revoked for a user (applies to site and userstreams).
        :TokenRevoked = 6,
        /// The same credentials were used to connect a new stream and the oldest was disconnected.
        :AdminLogout = 7,
        // Reserved for internal use. Will not be delivered to external clients.
        // _ = 8,
        /// The stream connected with a negative count parameter and was disconnected after all backfill was delivered.
        :MaxMessageLimit = 9,
        /// An internal issue disconnected the stream.
        :StreamException = 10,
        /// An internal issue disconnected the stream.
        :BrokerStall = 11,
        /// The host the stream was connected to became overloaded and streams were disconnected to balance load.
        /// Reconnect as usual.
        :ShedLoad = 12,
    }
}

/// Represents a control message.
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Hash)]
pub struct Control {
    control_uri: String,
}

pub type Friends = Vec<UserId>;

impl Deserialize for StreamMessage {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer {
        struct SMVisitor;

        impl Visitor for SMVisitor {
            type Value = StreamMessage;

            fn visit_map<V>(self, mut v: V) -> Result<StreamMessage, V::Error> where V: MapVisitor {
                let key = match v.visit_key::<String>()? {
                    Some(k) => k,
                    None => return Ok(StreamMessage::Custom(JsonMap::new())),
                };

                let ret = match key.as_str() {
                    "delete"          => Some(v.visit_value().map(StreamMessage::Delete)),
                    "scrub_geo"       => Some(v.visit_value().map(StreamMessage::ScrubGeo)),
                    "limit"           => Some(v.visit_value().map(StreamMessage::Limit)),
                    "status_withheld" => Some(v.visit_value().map(StreamMessage::StatusWithheld)),
                    "user_withheld"   => Some(v.visit_value().map(StreamMessage::UserWithheld)),
                    "disconnect"      => Some(v.visit_value().map(StreamMessage::Disconnect)),
                    "warning"         => Some(v.visit_value().map(StreamMessage::Warning)),
                    "friends"         => Some(v.visit_value().map(StreamMessage::Friends)),
                    // "friends_str"     => Some(v.visit_value().map(StreamMessage::Friends)),
                    "direct_message"  => Some(v.visit_value().map(StreamMessage::DirectMessage)),
                    "control"         => Some(v.visit_value().map(StreamMessage::Control)),
                    _ => None,
                };

                if let Some(ret) = ret {
                    if ret.is_ok() {
                        while v.visit::<IgnoredAny,IgnoredAny>()?.is_some() {}
                    }
                    return ret;
                }

                // Tweet, Event or for_user envelope:

                let mut map = JsonMap::new();
                map.insert(key, v.visit_value()?);
                while let Some((k, v)) = v.visit()? {
                    map.insert(k, v);
                }

                if map.contains_key("id") {
                    Tweet::deserialize(JsonValue::Object(map))
                        .map(Box::new)
                        .map(StreamMessage::Tweet)
                        .map_err(|e| V::Error::custom(e.to_string()))
                } else if map.contains_key("event") {
                    Event::deserialize(JsonValue::Object(map))
                        .map(Box::new)
                        .map(StreamMessage::Event)
                        .map_err(|e| V::Error::custom(e.to_string()))
                } else if let Some(id) = map.remove("for_user") {
                    if let Some(id) = id.as_u64() {
                        if let Some(msg) = map.remove("message") {
                            StreamMessage::deserialize(msg)
                                .map(|m| StreamMessage::ForUser(id, Box::new(m)))
                                .map_err(|e| V::Error::custom(e.to_string()))
                        } else {
                            Err(V::Error::missing_field("message"))
                        }
                    } else {
                        Err(V::Error::custom("expected u64"))
                    }
                } else {
                    Ok(StreamMessage::Custom(map))
                }
            }

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "map")
            }
        }

        deserializer.deserialize_map(SMVisitor)
    }
}

impl Deserialize for Delete {
    fn deserialize<D: Deserializer>(d: D) -> Result<Self, D::Error> {
        struct DeleteVisitor;

        impl Visitor for DeleteVisitor {
            type Value = Delete;

            fn visit_map<V: MapVisitor>(self, mut v: V) -> Result<Delete, V::Error> {
                use std::mem;

                #[allow(dead_code)]
                #[derive(Deserialize)]
                struct Status { id: StatusId, user_id: UserId };

                while let Some(k) = v.visit_key::<String>()? {
                    if "status" == k.as_str() {
                        let ret = v.visit_value::<Status>()?;
                        while v.visit::<IgnoredAny,IgnoredAny>()?.is_some() {}
                        unsafe {
                            return Ok(mem::transmute(ret));
                        }
                    } else {
                        v.visit_value::<IgnoredAny>()?;
                    }
                }

                Err(V::Error::missing_field("status"))
            }

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "a map with a field `status` which contains field `id` and `user_id` of integer type`")
            }
        }

        d.deserialize_map(DeleteVisitor)
    }
}

impl fmt::Display for Disconnect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: {} {}: {}", self.stream_name, self.code as u32, self.code.as_ref(), self.reason)
    }
}

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

    #[test]
    fn warning() {
        assert_eq!(
            StreamMessage::Warning(Warning {
                message: "Your connection is falling behind and messages are being queued for delivery to you. \
                    Your queue is now over 60% full. You will be disconnected when the queue is full.".to_owned(),
                code: WarningCode::FallingBehind(60),
            }),
            json::from_str(
                "{\"warning\":{\"code\":\"FALLING_BEHIND\",\"message\":\"Your connection is falling \
                    behind and messages are being queued for delivery to you. Your queue is now over 60% full. \
                    You will be disconnected when the queue is full.\",\"percent_full\": 60}}"
            ).unwrap()
        )
    }
}
<|endoftext|>


<commit_before>use rustc_serialize;
use std::mem;

use super::{Decoder, DecodeError};
use super::DecodeErrorKind::*;
use Value;

impl rustc_serialize::Decoder for Decoder {
    type Error = DecodeError;
    fn read_nil(&mut self) -> Result<(), DecodeError> {
        match self.toml {
            Some(Value::String(ref s)) if s.len() == 0 => {}
            Some(Value::String(..)) => return Err(self.err(NilTooLong)),
            ref found => return Err(self.mismatch("string", found)),
        }
        self.toml.take();
        Ok(())
    }
    fn read_usize(&mut self) -> Result<usize, DecodeError> {
        self.read_i64().map(|i| i as usize)
    }
    fn read_u64(&mut self) -> Result<u64, DecodeError> {
        self.read_i64().map(|i| i as u64)
    }
    fn read_u32(&mut self) -> Result<u32, DecodeError> {
        self.read_i64().map(|i| i as u32)
    }
    fn read_u16(&mut self) -> Result<u16, DecodeError> {
        self.read_i64().map(|i| i as u16)
    }
    fn read_u8(&mut self) -> Result<u8, DecodeError> {
        self.read_i64().map(|i| i as u8)
    }
    fn read_isize(&mut self) -> Result<isize, DecodeError> {
        self.read_i64().map(|i| i as isize)
    }
    fn read_i64(&mut self) -> Result<i64, DecodeError> {
        match self.toml {
            Some(Value::Integer(i)) => { self.toml.take(); Ok(i) }
            ref found => Err(self.mismatch("integer", found)),
        }
    }
    fn read_i32(&mut self) -> Result<i32, DecodeError> {
        self.read_i64().map(|i| i as i32)
    }
    fn read_i16(&mut self) -> Result<i16, DecodeError> {
        self.read_i64().map(|i| i as i16)
    }
    fn read_i8(&mut self) -> Result<i8, DecodeError> {
        self.read_i64().map(|i| i as i8)
    }
    fn read_bool(&mut self) -> Result<bool, DecodeError> {
        match self.toml {
            Some(Value::Boolean(b)) => { self.toml.take(); Ok(b) }
            ref found => Err(self.mismatch("bool", found)),
        }
    }
    fn read_f64(&mut self) -> Result<f64, DecodeError> {
        match self.toml {
            Some(Value::Float(f)) => Ok(f),
            ref found => Err(self.mismatch("float", found)),
        }
    }
    fn read_f32(&mut self) -> Result<f32, DecodeError> {
        self.read_f64().map(|f| f as f32)
    }
    fn read_char(&mut self) -> Result<char, DecodeError> {
        let ch = match self.toml {
            Some(Value::String(ref s)) if s.chars().count() == 1 =>
                s.chars().next().unwrap(),
            ref found => return Err(self.mismatch("string", found)),
        };
        self.toml.take();
        Ok(ch)
    }
    fn read_str(&mut self) -> Result<String, DecodeError> {
        match self.toml.take() {
            Some(Value::String(s)) => Ok(s),
            found => {
                let err = Err(self.mismatch("string", &found));
                self.toml = found;
                err
            }
        }
    }

    // Compound types:
    fn read_enum<T, F>(&mut self, _name: &str, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        f(self)
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F)
        -> Result<T, DecodeError>
        where F: FnMut(&mut Decoder, usize) -> Result<T, DecodeError>
    {
        // When decoding enums, this crate takes the strategy of trying to
        // decode the current TOML as all of the possible variants, returning
        // success on the first one that succeeds.
        //
        // Note that fidelity of the errors returned here is a little nebulous,
        // but we try to return the error that had the relevant field as the
        // longest field. This way we hopefully match an error against what was
        // most likely being written down without losing too much info.
        let mut first_error = None::<DecodeError>;
        for i in 0..names.len() {
            let mut d = self.sub_decoder(self.toml.clone(), "");
            match f(&mut d, i) {
                Ok(t) => {
                    self.toml = d.toml;
                    return Ok(t)
                }
                Err(e) => {
                    if let Some(ref first) = first_error {
                        let my_len = e.field.as_ref().map(|s| s.len());
                        let first_len = first.field.as_ref().map(|s| s.len());
                        if my_len <= first_len {
                            continue
                        }
                    }
                    first_error = Some(e);
                }
            }
        }
        Err(first_error.unwrap_or_else(|| self.err(NoEnumVariants)))
    }
    fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        f(self)
    }

    fn read_enum_struct_variant<T, F>(&mut self, _names: &[&str], _f: F)
        -> Result<T, DecodeError>
        where F: FnMut(&mut Decoder, usize) -> Result<T, DecodeError>
    {
        panic!()
    }
    fn read_enum_struct_variant_field<T, F>(&mut self,
                                            _f_name: &str,
                                            _f_idx: usize,
                                            _f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        panic!()
    }

    fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        match self.toml {
            Some(Value::Table(..)) => {
                let ret = try!(f(self));
                match self.toml {
                    Some(Value::Table(ref t)) if t.len() == 0 => {}
                    _ => return Ok(ret)
                }
                self.toml.take();
                Ok(ret)
            }
            ref found => Err(self.mismatch("table", found)),
        }
    }
    fn read_struct_field<T, F>(&mut self, f_name: &str, _f_idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        let field = format!("{}", f_name);
        let toml = match self.toml {
            Some(Value::Table(ref mut table)) => {
                table.remove(&field)
                     .or_else(|| table.remove(&f_name.replace("_", "-")))
            },
            ref found => return Err(self.mismatch("table", found)),
        };
        let mut d = self.sub_decoder(toml, f_name);
        let ret = try!(f(&mut d));
        if let Some(value) = d.toml {
            if let Some(Value::Table(ref mut table)) = self.toml {
                table.insert(field, value);
            }
        }
        Ok(ret)
    }

    fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        self.read_seq(move |d, len| {
            assert!(len == tuple_len,
                    "expected tuple of length `{}`, found tuple \
                         of length `{}`", tuple_len, len);
            f(d)
        })
    }
    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        self.read_seq_elt(a_idx, f)
    }

    fn read_tuple_struct<T, F>(&mut self, _s_name: &str, _len: usize, _f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        panic!()
    }
    fn read_tuple_struct_arg<T, F>(&mut self, _a_idx: usize, _f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        panic!()
    }

    // Specialized types:
    fn read_option<T, F>(&mut self, mut f: F)
        -> Result<T, DecodeError>
        where F: FnMut(&mut Decoder, bool) -> Result<T, DecodeError>
    {
        match self.toml {
            Some(..) => f(self, true),
            None => f(self, false),
        }
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError>
    {
        let len = match self.toml {
            Some(Value::Array(ref arr)) => arr.len(),
            None => 0,
            ref found => return Err(self.mismatch("array", found)),
        };
        let ret = try!(f(self, len));
        match self.toml {
            Some(Value::Array(ref mut arr)) => {
                arr.retain(|slot| slot.as_integer() != Some(0));
                if arr.len() != 0 { return Ok(ret) }
            }
            _ => return Ok(ret)
        }
        self.toml.take();
        Ok(ret)
    }
    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        let toml = match self.toml {
            Some(Value::Array(ref mut arr)) => {
                mem::replace(&mut arr[idx], Value::Integer(0))
            }
            ref found => return Err(self.mismatch("array", found)),
        };
        let mut d = self.sub_decoder(Some(toml), "");
        let ret = try!(f(&mut d));
        match d.toml {
            Some(toml) => match self.toml {
                Some(Value::Array(ref mut arr)) => arr[idx] = toml,
                _ => {}
            },
            _ => {}
        }
        Ok(ret)
    }

    fn read_map<T, F>(&mut self, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError>
    {
        let len = match self.toml {
            Some(Value::Table(ref table)) => table.len(),
            ref found => return Err(self.mismatch("table", found)),
        };
        let ret = try!(f(self, len));
        self.toml.take();
        Ok(ret)
    }
    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        match self.toml {
            Some(Value::Table(ref table)) => {
                match table.iter().skip(idx).next() {
                    Some((key, _)) => {
                        let val = Value::String(key.to_string());
                        f(&mut self.sub_decoder(Some(val), key))
                    }
                    None => Err(self.err(ExpectedMapKey(idx))),
                }
            }
            ref found => Err(self.mismatch("table", found)),
        }
    }
    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        match self.toml {
            Some(Value::Table(ref table)) => {
                match table.iter().skip(idx).next() {
                    Some((key, value)) => {
                        // XXX: this shouldn't clone
                        f(&mut self.sub_decoder(Some(value.clone()), key))
                    }
                    None => Err(self.err(ExpectedMapElement(idx))),
                }
            }
            ref found => Err(self.mismatch("table", found)),
        }
    }

    fn error(&mut self, err: &str) -> DecodeError {
        DecodeError {
            field: self.cur_field.clone(),
            kind: ApplicationError(format!("{}", err))
        }
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::Decodable;
    use std::collections::HashMap;

    use {Parser, Decoder, Value};

    #[test]
    fn bad_enum_chooses_longest_error() {
        #[derive(RustcDecodable)]
        #[allow(dead_code)]
        struct Foo {
            wut: HashMap<String, Bar>,
        }

        #[derive(RustcDecodable)]
        enum Bar {
            Simple(String),
            Detailed(Baz),
        }

        #[derive(RustcDecodable, Debug)]
        struct Baz {
            features: Vec<String>,
        }

        let s = r#"
            [wut]
            a = { features = "" }
        "#;
        let v = Parser::new(s).parse().unwrap();
        let mut d = Decoder::new(Value::Table(v));
        let err = match Foo::decode(&mut d) {
            Ok(_) => panic!("expected error"),
            Err(e) => e,
        };
        assert_eq!(err.field.as_ref().unwrap(), "wut.a.features");

    }
}
<commit_msg>Fixed bug: floats always end up in Decoder.toml, even when they have been successfully decoded.<commit_after>use rustc_serialize;
use std::mem;

use super::{Decoder, DecodeError};
use super::DecodeErrorKind::*;
use Value;

impl rustc_serialize::Decoder for Decoder {
    type Error = DecodeError;
    fn read_nil(&mut self) -> Result<(), DecodeError> {
        match self.toml {
            Some(Value::String(ref s)) if s.len() == 0 => {}
            Some(Value::String(..)) => return Err(self.err(NilTooLong)),
            ref found => return Err(self.mismatch("string", found)),
        }
        self.toml.take();
        Ok(())
    }
    fn read_usize(&mut self) -> Result<usize, DecodeError> {
        self.read_i64().map(|i| i as usize)
    }
    fn read_u64(&mut self) -> Result<u64, DecodeError> {
        self.read_i64().map(|i| i as u64)
    }
    fn read_u32(&mut self) -> Result<u32, DecodeError> {
        self.read_i64().map(|i| i as u32)
    }
    fn read_u16(&mut self) -> Result<u16, DecodeError> {
        self.read_i64().map(|i| i as u16)
    }
    fn read_u8(&mut self) -> Result<u8, DecodeError> {
        self.read_i64().map(|i| i as u8)
    }
    fn read_isize(&mut self) -> Result<isize, DecodeError> {
        self.read_i64().map(|i| i as isize)
    }
    fn read_i64(&mut self) -> Result<i64, DecodeError> {
        match self.toml {
            Some(Value::Integer(i)) => { self.toml.take(); Ok(i) }
            ref found => Err(self.mismatch("integer", found)),
        }
    }
    fn read_i32(&mut self) -> Result<i32, DecodeError> {
        self.read_i64().map(|i| i as i32)
    }
    fn read_i16(&mut self) -> Result<i16, DecodeError> {
        self.read_i64().map(|i| i as i16)
    }
    fn read_i8(&mut self) -> Result<i8, DecodeError> {
        self.read_i64().map(|i| i as i8)
    }
    fn read_bool(&mut self) -> Result<bool, DecodeError> {
        match self.toml {
            Some(Value::Boolean(b)) => { self.toml.take(); Ok(b) }
            ref found => Err(self.mismatch("bool", found)),
        }
    }
    fn read_f64(&mut self) -> Result<f64, DecodeError> {
        match self.toml {
            Some(Value::Float(f)) => { self.toml.take(); Ok(f) },
            ref found => Err(self.mismatch("float", found)),
        }
    }
    fn read_f32(&mut self) -> Result<f32, DecodeError> {
        self.read_f64().map(|f| f as f32)
    }
    fn read_char(&mut self) -> Result<char, DecodeError> {
        let ch = match self.toml {
            Some(Value::String(ref s)) if s.chars().count() == 1 =>
                s.chars().next().unwrap(),
            ref found => return Err(self.mismatch("string", found)),
        };
        self.toml.take();
        Ok(ch)
    }
    fn read_str(&mut self) -> Result<String, DecodeError> {
        match self.toml.take() {
            Some(Value::String(s)) => Ok(s),
            found => {
                let err = Err(self.mismatch("string", &found));
                self.toml = found;
                err
            }
        }
    }

    // Compound types:
    fn read_enum<T, F>(&mut self, _name: &str, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        f(self)
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F)
        -> Result<T, DecodeError>
        where F: FnMut(&mut Decoder, usize) -> Result<T, DecodeError>
    {
        // When decoding enums, this crate takes the strategy of trying to
        // decode the current TOML as all of the possible variants, returning
        // success on the first one that succeeds.
        //
        // Note that fidelity of the errors returned here is a little nebulous,
        // but we try to return the error that had the relevant field as the
        // longest field. This way we hopefully match an error against what was
        // most likely being written down without losing too much info.
        let mut first_error = None::<DecodeError>;
        for i in 0..names.len() {
            let mut d = self.sub_decoder(self.toml.clone(), "");
            match f(&mut d, i) {
                Ok(t) => {
                    self.toml = d.toml;
                    return Ok(t)
                }
                Err(e) => {
                    if let Some(ref first) = first_error {
                        let my_len = e.field.as_ref().map(|s| s.len());
                        let first_len = first.field.as_ref().map(|s| s.len());
                        if my_len <= first_len {
                            continue
                        }
                    }
                    first_error = Some(e);
                }
            }
        }
        Err(first_error.unwrap_or_else(|| self.err(NoEnumVariants)))
    }
    fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        f(self)
    }

    fn read_enum_struct_variant<T, F>(&mut self, _names: &[&str], _f: F)
        -> Result<T, DecodeError>
        where F: FnMut(&mut Decoder, usize) -> Result<T, DecodeError>
    {
        panic!()
    }
    fn read_enum_struct_variant_field<T, F>(&mut self,
                                            _f_name: &str,
                                            _f_idx: usize,
                                            _f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        panic!()
    }

    fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        match self.toml {
            Some(Value::Table(..)) => {
                let ret = try!(f(self));
                match self.toml {
                    Some(Value::Table(ref t)) if t.len() == 0 => {}
                    _ => return Ok(ret)
                }
                self.toml.take();
                Ok(ret)
            }
            ref found => Err(self.mismatch("table", found)),
        }
    }
    fn read_struct_field<T, F>(&mut self, f_name: &str, _f_idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        let field = format!("{}", f_name);
        let toml = match self.toml {
            Some(Value::Table(ref mut table)) => {
                table.remove(&field)
                     .or_else(|| table.remove(&f_name.replace("_", "-")))
            },
            ref found => return Err(self.mismatch("table", found)),
        };
        let mut d = self.sub_decoder(toml, f_name);
        let ret = try!(f(&mut d));
        if let Some(value) = d.toml {
            if let Some(Value::Table(ref mut table)) = self.toml {
                table.insert(field, value);
            }
        }
        Ok(ret)
    }

    fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        self.read_seq(move |d, len| {
            assert!(len == tuple_len,
                    "expected tuple of length `{}`, found tuple \
                         of length `{}`", tuple_len, len);
            f(d)
        })
    }
    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        self.read_seq_elt(a_idx, f)
    }

    fn read_tuple_struct<T, F>(&mut self, _s_name: &str, _len: usize, _f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        panic!()
    }
    fn read_tuple_struct_arg<T, F>(&mut self, _a_idx: usize, _f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        panic!()
    }

    // Specialized types:
    fn read_option<T, F>(&mut self, mut f: F)
        -> Result<T, DecodeError>
        where F: FnMut(&mut Decoder, bool) -> Result<T, DecodeError>
    {
        match self.toml {
            Some(..) => f(self, true),
            None => f(self, false),
        }
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError>
    {
        let len = match self.toml {
            Some(Value::Array(ref arr)) => arr.len(),
            None => 0,
            ref found => return Err(self.mismatch("array", found)),
        };
        let ret = try!(f(self, len));
        match self.toml {
            Some(Value::Array(ref mut arr)) => {
                arr.retain(|slot| slot.as_integer() != Some(0));
                if arr.len() != 0 { return Ok(ret) }
            }
            _ => return Ok(ret)
        }
        self.toml.take();
        Ok(ret)
    }
    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        let toml = match self.toml {
            Some(Value::Array(ref mut arr)) => {
                mem::replace(&mut arr[idx], Value::Integer(0))
            }
            ref found => return Err(self.mismatch("array", found)),
        };
        let mut d = self.sub_decoder(Some(toml), "");
        let ret = try!(f(&mut d));
        match d.toml {
            Some(toml) => match self.toml {
                Some(Value::Array(ref mut arr)) => arr[idx] = toml,
                _ => {}
            },
            _ => {}
        }
        Ok(ret)
    }

    fn read_map<T, F>(&mut self, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError>
    {
        let len = match self.toml {
            Some(Value::Table(ref table)) => table.len(),
            ref found => return Err(self.mismatch("table", found)),
        };
        let ret = try!(f(self, len));
        self.toml.take();
        Ok(ret)
    }
    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        match self.toml {
            Some(Value::Table(ref table)) => {
                match table.iter().skip(idx).next() {
                    Some((key, _)) => {
                        let val = Value::String(key.to_string());
                        f(&mut self.sub_decoder(Some(val), key))
                    }
                    None => Err(self.err(ExpectedMapKey(idx))),
                }
            }
            ref found => Err(self.mismatch("table", found)),
        }
    }
    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        match self.toml {
            Some(Value::Table(ref table)) => {
                match table.iter().skip(idx).next() {
                    Some((key, value)) => {
                        // XXX: this shouldn't clone
                        f(&mut self.sub_decoder(Some(value.clone()), key))
                    }
                    None => Err(self.err(ExpectedMapElement(idx))),
                }
            }
            ref found => Err(self.mismatch("table", found)),
        }
    }

    fn error(&mut self, err: &str) -> DecodeError {
        DecodeError {
            field: self.cur_field.clone(),
            kind: ApplicationError(format!("{}", err))
        }
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::Decodable;
    use std::collections::HashMap;

    use {Parser, Decoder, Value};

    #[test]
    fn bad_enum_chooses_longest_error() {
        #[derive(RustcDecodable)]
        #[allow(dead_code)]
        struct Foo {
            wut: HashMap<String, Bar>,
        }

        #[derive(RustcDecodable)]
        enum Bar {
            Simple(String),
            Detailed(Baz),
        }

        #[derive(RustcDecodable, Debug)]
        struct Baz {
            features: Vec<String>,
        }

        let s = r#"
            [wut]
            a = { features = "" }
        "#;
        let v = Parser::new(s).parse().unwrap();
        let mut d = Decoder::new(Value::Table(v));
        let err = match Foo::decode(&mut d) {
            Ok(_) => panic!("expected error"),
            Err(e) => e,
        };
        assert_eq!(err.field.as_ref().unwrap(), "wut.a.features");

    }
}
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;$cpu_state.S = $val >= 0x80 );
}

macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 | $cpu_state.sp,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=1;
            $mem.read8(0x0100 | $cpu_state.sp;)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BCS => {
                if cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1; }
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc-1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.decode_register.value_final.unwrap()));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<commit_msg>implemented BCC opcode<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;$cpu_state.S = $val >= 0x80 );
}

macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 | $cpu_state.sp,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=1;
            $mem.read8(0x0100 | $cpu_state.sp;)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BCC => {
                if !cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1; }
    		},
    		OpcodeClass::BCS => {
                if cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1; }
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc-1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.decode_register.value_final.unwrap()));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<|endoftext|>


<commit_before>//! Timestamp formatting.

use std::time::Duration;

use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece};
use datetime::fmt::DateFormat;
use locale;
use std::cmp;

/// Every timestamp in exa needs to be rendered by a **time format**.
/// Formatting times is tricky, because how a timestamp is rendered can
/// depend on one or more of the following:
///
/// - The user’s locale, for printing the month name as “Feb”, or as “fév”,
///   or as “2月”;
/// - The current year, because certain formats will be less precise when
///   dealing with dates far in the past;
/// - The formatting style that the user asked for on the command-line.
///
/// Because not all formatting styles need the same data, they all have their
/// own enum variants. It’s not worth looking the locale up if the formatter
/// prints month names as numbers.
///
/// Currently exa does not support *custom* styles, where the user enters a
/// format string in an environment variable or something. Just these four.
#[derive(Debug)]
pub enum TimeFormat {

    /// The **default format** uses the user’s locale to print month names,
    /// and specifies the timestamp down to the minute for recent times, and
    /// day for older times.
    DefaultFormat(DefaultFormat),

    /// Use the **ISO format**, which specifies the timestamp down to the
    /// minute for recent times, and day for older times. It uses a number
    /// for the month so it doesn’t need a locale.
    ISOFormat(ISOFormat),

    /// Use the **long ISO format**, which specifies the timestamp down to the
    /// minute using only numbers, without needing the locale or year.
    LongISO,

    /// Use the **full ISO format**, which specifies the timestamp down to the
    /// millisecond and includes its offset down to the minute. This too uses
    /// only numbers so doesn’t require any special consideration.
    FullISO,
}

// There are two different formatting functions because local and zoned
// timestamps are separate types.

impl TimeFormat {
    pub fn format_local(&self, time: Duration) -> String {
        match *self {
            TimeFormat::DefaultFormat(ref fmt) => fmt.format_local(time),
            TimeFormat::ISOFormat(ref iso)     => iso.format_local(time),
            TimeFormat::LongISO                => long_local(time),
            TimeFormat::FullISO                => full_local(time),
        }
    }

    pub fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
        match *self {
            TimeFormat::DefaultFormat(ref fmt) => fmt.format_zoned(time, zone),
            TimeFormat::ISOFormat(ref iso)     => iso.format_zoned(time, zone),
            TimeFormat::LongISO                => long_zoned(time, zone),
            TimeFormat::FullISO                => full_zoned(time, zone),
        }
    }
}

#[derive(Debug, Clone)]
pub struct DefaultFormat {

    /// The year of the current time. This gets used to determine which date
    /// format to use.
    pub current_year: i64,

    /// Localisation rules for formatting timestamps.
    pub locale: locale::Time,

    /// Date format for printing out timestamps that are in the current year.
    pub date_and_time: DateFormat<'static>,

    /// Date format for printing out timestamps that *aren’t*.
    pub date_and_year: DateFormat<'static>,
}

impl DefaultFormat {
    pub fn load() -> DefaultFormat {
        use unicode_width::UnicodeWidthStr;

        let locale = locale::Time::load_user_locale()
                       .unwrap_or_else(|_| locale::Time::english());

        let current_year = LocalDateTime::now().year();

        // Some locales use a three-character wide month name (Jan to Dec);
        // others vary between three to four (1月 to 12月, juil.). We check each month width
        // to detect the longest and set the output format accordingly.
        let mut maximum_month_width = 0;
        for i in 0..11 {
            let current_month_width = UnicodeWidthStr::width(&*locale.short_month_name(i));
            maximum_month_width = cmp::max(maximum_month_width, current_month_width);
        }

        let date_and_time = match maximum_month_width {
            4  => DateFormat::parse("{2>:D} {4<:M} {2>:h}:{02>:m}").unwrap(),
            5  => DateFormat::parse("{2>:D} {5<:M} {2>:h}:{02>:m}").unwrap(),
            _  => DateFormat::parse("{2>:D} {:M} {2>:h}:{02>:m}").unwrap(),
        };

        let date_and_year = match maximum_month_width {
            4 => DateFormat::parse("{2>:D} {4<:M} {5>:Y}").unwrap(),
            5 => DateFormat::parse("{2>:D} {5<:M} {5>:Y}").unwrap(),
            _ => DateFormat::parse("{2>:D} {:M} {5>:Y}").unwrap()
        };

        DefaultFormat { current_year, locale, date_and_time, date_and_year }
    }
}

impl DefaultFormat {
    fn is_recent(&self, date: LocalDateTime) -> bool {
        date.year() == self.current_year
    }

    fn month_to_abbrev(month: datetime::Month) -> &'static str {
        match month {
            datetime::Month::January => "Jan",
            datetime::Month::February => "Feb",
            datetime::Month::March => "Mar",
            datetime::Month::April => "Apr",
            datetime::Month::May => "May",
            datetime::Month::June => "Jun",
            datetime::Month::July => "Jul",
            datetime::Month::August => "August",
            datetime::Month::September => "Sep",
            datetime::Month::October => "Oct",
            datetime::Month::November => "Nov",
            datetime::Month::December => "Dec",
        }
    }

    #[allow(trivial_numeric_casts)]
    fn format_local(&self, time: Duration) -> String {
        if time.as_nanos() == 0 {
            return "-".to_string();
        }
        let date = LocalDateTime::at(time.as_secs() as i64);

        if self.is_recent(date) {
            format!("{:2} {} {:02}:{:02}",
            date.day(), DefaultFormat::month_to_abbrev(date.month()),
            date.hour(), date.minute())
        }
        else {
            self.date_and_year.format(&date, &self.locale)
        }
    }

    #[allow(trivial_numeric_casts)]
    fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
        if time.as_nanos() == 0 {
            return "-".to_string();
        }

        let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));

        if self.is_recent(date) {
            format!("{:2} {} {:02}:{:02}",
            date.day(), DefaultFormat::month_to_abbrev(date.month()),
            date.hour(), date.minute())
        }
        else {
            self.date_and_year.format(&date, &self.locale)
        }
    }
}

#[allow(trivial_numeric_casts)]
fn long_local(time: Duration) -> String {
    let date = LocalDateTime::at(time.as_secs() as i64);
    format!("{:04}-{:02}-{:02} {:02}:{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute())
}

#[allow(trivial_numeric_casts)]
fn long_zoned(time: Duration, zone: &TimeZone) -> String {
    let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));
    format!("{:04}-{:02}-{:02} {:02}:{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute())
}

#[allow(trivial_numeric_casts)]
fn full_local(time: Duration) -> String {
    let date = LocalDateTime::at(time.as_secs() as i64);
    format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute(), date.second(), time.subsec_nanos())
}

#[allow(trivial_numeric_casts)]
fn full_zoned(time: Duration, zone: &TimeZone) -> String {
    use datetime::Offset;

    let local = LocalDateTime::at(time.as_secs() as i64);
    let date = zone.to_zoned(local);
    let offset = Offset::of_seconds(zone.offset(local) as i32).expect("Offset out of range");
    format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09} {:+03}{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute(), date.second(), time.subsec_nanos(),
            offset.hours(), offset.minutes().abs())
}

#[derive(Debug, Clone)]
pub struct ISOFormat {

    /// The year of the current time. This gets used to determine which date
    /// format to use.
    pub current_year: i64,
}

impl ISOFormat {
    pub fn load() -> ISOFormat {
        let current_year = LocalDateTime::now().year();
        ISOFormat { current_year }
    }
}

impl ISOFormat {
    fn is_recent(&self, date: LocalDateTime) -> bool {
        date.year() == self.current_year
    }

    #[allow(trivial_numeric_casts)]
    fn format_local(&self, time: Duration) -> String {
        let date = LocalDateTime::at(time.as_secs() as i64);

        if self.is_recent(date) {
            format!("{:02}-{:02} {:02}:{:02}",
                    date.month() as usize, date.day(),
                    date.hour(), date.minute())
        }
        else {
            format!("{:04}-{:02}-{:02}",
                    date.year(), date.month() as usize, date.day())
        }
    }

    #[allow(trivial_numeric_casts)]
    fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
        let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));

        if self.is_recent(date) {
            format!("{:02}-{:02} {:02}:{:02}",
                    date.month() as usize, date.day(),
                    date.hour(), date.minute())
        }
        else {
            format!("{:04}-{:02}-{:02}",
                    date.year(), date.month() as usize, date.day())
        }
    }
}
<commit_msg>Change August to Aug. Fix issue #719.<commit_after>//! Timestamp formatting.

use std::time::Duration;

use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece};
use datetime::fmt::DateFormat;
use locale;
use std::cmp;

/// Every timestamp in exa needs to be rendered by a **time format**.
/// Formatting times is tricky, because how a timestamp is rendered can
/// depend on one or more of the following:
///
/// - The user’s locale, for printing the month name as “Feb”, or as “fév”,
///   or as “2月”;
/// - The current year, because certain formats will be less precise when
///   dealing with dates far in the past;
/// - The formatting style that the user asked for on the command-line.
///
/// Because not all formatting styles need the same data, they all have their
/// own enum variants. It’s not worth looking the locale up if the formatter
/// prints month names as numbers.
///
/// Currently exa does not support *custom* styles, where the user enters a
/// format string in an environment variable or something. Just these four.
#[derive(Debug)]
pub enum TimeFormat {

    /// The **default format** uses the user’s locale to print month names,
    /// and specifies the timestamp down to the minute for recent times, and
    /// day for older times.
    DefaultFormat(DefaultFormat),

    /// Use the **ISO format**, which specifies the timestamp down to the
    /// minute for recent times, and day for older times. It uses a number
    /// for the month so it doesn’t need a locale.
    ISOFormat(ISOFormat),

    /// Use the **long ISO format**, which specifies the timestamp down to the
    /// minute using only numbers, without needing the locale or year.
    LongISO,

    /// Use the **full ISO format**, which specifies the timestamp down to the
    /// millisecond and includes its offset down to the minute. This too uses
    /// only numbers so doesn’t require any special consideration.
    FullISO,
}

// There are two different formatting functions because local and zoned
// timestamps are separate types.

impl TimeFormat {
    pub fn format_local(&self, time: Duration) -> String {
        match *self {
            TimeFormat::DefaultFormat(ref fmt) => fmt.format_local(time),
            TimeFormat::ISOFormat(ref iso)     => iso.format_local(time),
            TimeFormat::LongISO                => long_local(time),
            TimeFormat::FullISO                => full_local(time),
        }
    }

    pub fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
        match *self {
            TimeFormat::DefaultFormat(ref fmt) => fmt.format_zoned(time, zone),
            TimeFormat::ISOFormat(ref iso)     => iso.format_zoned(time, zone),
            TimeFormat::LongISO                => long_zoned(time, zone),
            TimeFormat::FullISO                => full_zoned(time, zone),
        }
    }
}

#[derive(Debug, Clone)]
pub struct DefaultFormat {

    /// The year of the current time. This gets used to determine which date
    /// format to use.
    pub current_year: i64,

    /// Localisation rules for formatting timestamps.
    pub locale: locale::Time,

    /// Date format for printing out timestamps that are in the current year.
    pub date_and_time: DateFormat<'static>,

    /// Date format for printing out timestamps that *aren’t*.
    pub date_and_year: DateFormat<'static>,
}

impl DefaultFormat {
    pub fn load() -> DefaultFormat {
        use unicode_width::UnicodeWidthStr;

        let locale = locale::Time::load_user_locale()
                       .unwrap_or_else(|_| locale::Time::english());

        let current_year = LocalDateTime::now().year();

        // Some locales use a three-character wide month name (Jan to Dec);
        // others vary between three to four (1月 to 12月, juil.). We check each month width
        // to detect the longest and set the output format accordingly.
        let mut maximum_month_width = 0;
        for i in 0..11 {
            let current_month_width = UnicodeWidthStr::width(&*locale.short_month_name(i));
            maximum_month_width = cmp::max(maximum_month_width, current_month_width);
        }

        let date_and_time = match maximum_month_width {
            4  => DateFormat::parse("{2>:D} {4<:M} {2>:h}:{02>:m}").unwrap(),
            5  => DateFormat::parse("{2>:D} {5<:M} {2>:h}:{02>:m}").unwrap(),
            _  => DateFormat::parse("{2>:D} {:M} {2>:h}:{02>:m}").unwrap(),
        };

        let date_and_year = match maximum_month_width {
            4 => DateFormat::parse("{2>:D} {4<:M} {5>:Y}").unwrap(),
            5 => DateFormat::parse("{2>:D} {5<:M} {5>:Y}").unwrap(),
            _ => DateFormat::parse("{2>:D} {:M} {5>:Y}").unwrap()
        };

        DefaultFormat { current_year, locale, date_and_time, date_and_year }
    }
}

impl DefaultFormat {
    fn is_recent(&self, date: LocalDateTime) -> bool {
        date.year() == self.current_year
    }

    fn month_to_abbrev(month: datetime::Month) -> &'static str {
        match month {
            datetime::Month::January => "Jan",
            datetime::Month::February => "Feb",
            datetime::Month::March => "Mar",
            datetime::Month::April => "Apr",
            datetime::Month::May => "May",
            datetime::Month::June => "Jun",
            datetime::Month::July => "Jul",
            datetime::Month::August => "Aug",
            datetime::Month::September => "Sep",
            datetime::Month::October => "Oct",
            datetime::Month::November => "Nov",
            datetime::Month::December => "Dec",
        }
    }

    #[allow(trivial_numeric_casts)]
    fn format_local(&self, time: Duration) -> String {
        if time.as_nanos() == 0 {
            return "-".to_string();
        }
        let date = LocalDateTime::at(time.as_secs() as i64);

        if self.is_recent(date) {
            format!("{:2} {} {:02}:{:02}",
            date.day(), DefaultFormat::month_to_abbrev(date.month()),
            date.hour(), date.minute())
        }
        else {
            self.date_and_year.format(&date, &self.locale)
        }
    }

    #[allow(trivial_numeric_casts)]
    fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
        if time.as_nanos() == 0 {
            return "-".to_string();
        }

        let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));

        if self.is_recent(date) {
            format!("{:2} {} {:02}:{:02}",
            date.day(), DefaultFormat::month_to_abbrev(date.month()),
            date.hour(), date.minute())
        }
        else {
            self.date_and_year.format(&date, &self.locale)
        }
    }
}

#[allow(trivial_numeric_casts)]
fn long_local(time: Duration) -> String {
    let date = LocalDateTime::at(time.as_secs() as i64);
    format!("{:04}-{:02}-{:02} {:02}:{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute())
}

#[allow(trivial_numeric_casts)]
fn long_zoned(time: Duration, zone: &TimeZone) -> String {
    let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));
    format!("{:04}-{:02}-{:02} {:02}:{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute())
}

#[allow(trivial_numeric_casts)]
fn full_local(time: Duration) -> String {
    let date = LocalDateTime::at(time.as_secs() as i64);
    format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute(), date.second(), time.subsec_nanos())
}

#[allow(trivial_numeric_casts)]
fn full_zoned(time: Duration, zone: &TimeZone) -> String {
    use datetime::Offset;

    let local = LocalDateTime::at(time.as_secs() as i64);
    let date = zone.to_zoned(local);
    let offset = Offset::of_seconds(zone.offset(local) as i32).expect("Offset out of range");
    format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09} {:+03}{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute(), date.second(), time.subsec_nanos(),
            offset.hours(), offset.minutes().abs())
}

#[derive(Debug, Clone)]
pub struct ISOFormat {

    /// The year of the current time. This gets used to determine which date
    /// format to use.
    pub current_year: i64,
}

impl ISOFormat {
    pub fn load() -> ISOFormat {
        let current_year = LocalDateTime::now().year();
        ISOFormat { current_year }
    }
}

impl ISOFormat {
    fn is_recent(&self, date: LocalDateTime) -> bool {
        date.year() == self.current_year
    }

    #[allow(trivial_numeric_casts)]
    fn format_local(&self, time: Duration) -> String {
        let date = LocalDateTime::at(time.as_secs() as i64);

        if self.is_recent(date) {
            format!("{:02}-{:02} {:02}:{:02}",
                    date.month() as usize, date.day(),
                    date.hour(), date.minute())
        }
        else {
            format!("{:04}-{:02}-{:02}",
                    date.year(), date.month() as usize, date.day())
        }
    }

    #[allow(trivial_numeric_casts)]
    fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
        let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));

        if self.is_recent(date) {
            format!("{:02}-{:02} {:02}:{:02}",
                    date.month() as usize, date.day(),
                    date.hour(), date.minute())
        }
        else {
            format!("{:04}-{:02}-{:02}",
                    date.year(), date.month() as usize, date.day())
        }
    }
}
<|endoftext|>


<commit_before>//! Enabling and disabling interrupts

/// Returns whether interrupts are enabled.
#[inline]
pub fn are_enabled() -> bool {
    use crate::registers::rflags::{self, RFlags};

    rflags::read().contains(RFlags::INTERRUPT_FLAG)
}

/// Enable interrupts.
///
/// This is a wrapper around the `sti` instruction.
#[inline]
pub fn enable() {
    #[cfg(feature = "inline_asm")]
    unsafe {
        asm!("sti", options(nomem, nostack));
    }
    #[cfg(not(feature = "inline_asm"))]
    unsafe {
        crate::asm::x86_64_asm_interrupt_enable();
    }
}

/// Disable interrupts.
///
/// This is a wrapper around the `cli` instruction.
#[inline]
pub fn disable() {
    #[cfg(feature = "inline_asm")]
    unsafe {
        asm!("cli", options(nomem, nostack));
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe {
        crate::asm::x86_64_asm_interrupt_disable();
    }
}

/// Run a closure with disabled interrupts.
///
/// Run the given closure, disabling interrupts before running it (if they aren't already disabled).
/// Afterwards, interrupts are enabling again if they were enabled before.
///
/// If you have other `enable` and `disable` calls _within_ the closure, things may not work as expected.
///
/// # Examples
///
/// ```ignore
/// // interrupts are enabled
/// without_interrupts(|| {
///     // interrupts are disabled
///     without_interrupts(|| {
///         // interrupts are disabled
///     });
///     // interrupts are still disabled
/// });
/// // interrupts are enabled again
/// ```
#[inline]
pub fn without_interrupts<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    // true if the interrupt flag is set (i.e. interrupts are enabled)
    let saved_intpt_flag = are_enabled();

    // if interrupts are enabled, disable them for now
    if saved_intpt_flag {
        disable();
    }

    // do `f` while interrupts are disabled
    let ret = f();

    // re-enable interrupts if they were previously enabled
    if saved_intpt_flag {
        enable();
    }

    // return the result of `f` to the caller
    ret
}

/// Atomically enable interrupts and put the CPU to sleep
///
/// Executes the `sti; hlt` instruction sequence. Since the `sti` instruction
/// keeps interrupts disabled until after the immediately following
/// instruction (called "interrupt shadow"), no interrupt can occur between the
/// two instructions. (One exception to this are non-maskable interrupts; this
/// is explained below.)
///
/// This function is useful to put the CPU to sleep without missing interrupts
/// that occur immediately before the `hlt` instruction:
///
/// ```ignore
/// // there is a race between the check and the `hlt` instruction here:
///
/// if nothing_to_do() {
///     // <- race when the interrupt occurs here
///     x86_64::instructions::hlt(); // wait for the next interrupt
/// }
///
/// // avoid this race by using `enable_interrupts_and_hlt`:
///
/// x86_64::instructions::interrupts::disable();
/// if nothing_to_do() {
///     // <- no interrupts can occur here (interrupts are disabled)
///     x86_64::instructions::interrupts::enable_interrupts_and_hlt();
/// }
///
/// ```
///
/// ## Non-maskable Interrupts
///
/// On some processors, the interrupt shadow of `sti` does not apply to
/// non-maskable interrupts (NMIs). This means that an NMI can occur between
/// the `sti` and `hlt` instruction, with the result that the CPU is put to
/// sleep even though a new interrupt occured.
///
/// To work around this, it is recommended to check in the NMI handler if
/// the interrupt occured between `sti` and `hlt` instructions. If this is the
/// case, the handler should increase the instruction pointer stored in the
/// interrupt stack frame so that the `hlt` instruction is skipped.
///
/// See <http://lkml.iu.edu/hypermail/linux/kernel/1009.2/01406.html> for more
/// information.
#[inline]
pub fn enable_interrupts_and_hlt() {
    #[cfg(feature = "inline_asm")]
    unsafe {
        asm!("sti; hlt", options(nomem, nostack));
    }
    #[cfg(not(feature = "inline_asm"))]
    unsafe {
        crate::asm::x86_64_asm_interrupt_enable_and_hlt();
    }
}

/// Cause a breakpoint exception by invoking the `int3` instruction.
#[inline]
pub fn int3() {
    #[cfg(feature = "inline_asm")]
    unsafe {
        asm!("int3", options(nomem, nostack));
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe {
        crate::asm::x86_64_asm_int3();
    }
}

/// Generate a software interrupt by invoking the `int` instruction.
///
/// This currently needs to be a macro because the `int` argument needs to be an
/// immediate. This macro will be replaced by a generic function when support for
/// const generics is implemented in Rust.
#[cfg(feature = "inline_asm")]
#[macro_export]
macro_rules! software_interrupt {
    ($x:expr) => {{
        asm!("int {id}", id = const $x, options(nomem, nostack));
    }};
}

/// Not implemented
#[cfg(not(feature = "inline_asm"))]
#[macro_export]
macro_rules! software_interrupt {
    ($x:expr) => {{
        compile_error!("software_interrupt not implemented for non-nightly");
    }};
}
<commit_msg>Rename `enable_interrupts_and_hlt` to `enable_and_hlt`<commit_after>//! Enabling and disabling interrupts

/// Returns whether interrupts are enabled.
#[inline]
pub fn are_enabled() -> bool {
    use crate::registers::rflags::{self, RFlags};

    rflags::read().contains(RFlags::INTERRUPT_FLAG)
}

/// Enable interrupts.
///
/// This is a wrapper around the `sti` instruction.
#[inline]
pub fn enable() {
    #[cfg(feature = "inline_asm")]
    unsafe {
        asm!("sti", options(nomem, nostack));
    }
    #[cfg(not(feature = "inline_asm"))]
    unsafe {
        crate::asm::x86_64_asm_interrupt_enable();
    }
}

/// Disable interrupts.
///
/// This is a wrapper around the `cli` instruction.
#[inline]
pub fn disable() {
    #[cfg(feature = "inline_asm")]
    unsafe {
        asm!("cli", options(nomem, nostack));
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe {
        crate::asm::x86_64_asm_interrupt_disable();
    }
}

/// Run a closure with disabled interrupts.
///
/// Run the given closure, disabling interrupts before running it (if they aren't already disabled).
/// Afterwards, interrupts are enabling again if they were enabled before.
///
/// If you have other `enable` and `disable` calls _within_ the closure, things may not work as expected.
///
/// # Examples
///
/// ```ignore
/// // interrupts are enabled
/// without_interrupts(|| {
///     // interrupts are disabled
///     without_interrupts(|| {
///         // interrupts are disabled
///     });
///     // interrupts are still disabled
/// });
/// // interrupts are enabled again
/// ```
#[inline]
pub fn without_interrupts<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    // true if the interrupt flag is set (i.e. interrupts are enabled)
    let saved_intpt_flag = are_enabled();

    // if interrupts are enabled, disable them for now
    if saved_intpt_flag {
        disable();
    }

    // do `f` while interrupts are disabled
    let ret = f();

    // re-enable interrupts if they were previously enabled
    if saved_intpt_flag {
        enable();
    }

    // return the result of `f` to the caller
    ret
}

/// Atomically enable interrupts and put the CPU to sleep
///
/// Executes the `sti; hlt` instruction sequence. Since the `sti` instruction
/// keeps interrupts disabled until after the immediately following
/// instruction (called "interrupt shadow"), no interrupt can occur between the
/// two instructions. (One exception to this are non-maskable interrupts; this
/// is explained below.)
///
/// This function is useful to put the CPU to sleep without missing interrupts
/// that occur immediately before the `hlt` instruction:
///
/// ```ignore
/// // there is a race between the check and the `hlt` instruction here:
///
/// if nothing_to_do() {
///     // <- race when the interrupt occurs here
///     x86_64::instructions::hlt(); // wait for the next interrupt
/// }
///
/// // avoid this race by using `enable_and_hlt`:
///
/// x86_64::instructions::interrupts::disable();
/// if nothing_to_do() {
///     // <- no interrupts can occur here (interrupts are disabled)
///     x86_64::instructions::interrupts::enable_and_hlt();
/// }
///
/// ```
///
/// ## Non-maskable Interrupts
///
/// On some processors, the interrupt shadow of `sti` does not apply to
/// non-maskable interrupts (NMIs). This means that an NMI can occur between
/// the `sti` and `hlt` instruction, with the result that the CPU is put to
/// sleep even though a new interrupt occured.
///
/// To work around this, it is recommended to check in the NMI handler if
/// the interrupt occured between `sti` and `hlt` instructions. If this is the
/// case, the handler should increase the instruction pointer stored in the
/// interrupt stack frame so that the `hlt` instruction is skipped.
///
/// See <http://lkml.iu.edu/hypermail/linux/kernel/1009.2/01406.html> for more
/// information.
#[inline]
pub fn enable_and_hlt() {
    #[cfg(feature = "inline_asm")]
    unsafe {
        asm!("sti; hlt", options(nomem, nostack));
    }
    #[cfg(not(feature = "inline_asm"))]
    unsafe {
        crate::asm::x86_64_asm_interrupt_enable_and_hlt();
    }
}

/// Alias for [`enable_and_hlt`][enable_and_hlt] for backwards compatibility.
#[inline]
#[deprecated(note = "Use enable_and_hlt instead")]
pub fn enable_interrupts_and_hlt() {
    enable_and_hlt();
}

/// Cause a breakpoint exception by invoking the `int3` instruction.
#[inline]
pub fn int3() {
    #[cfg(feature = "inline_asm")]
    unsafe {
        asm!("int3", options(nomem, nostack));
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe {
        crate::asm::x86_64_asm_int3();
    }
}

/// Generate a software interrupt by invoking the `int` instruction.
///
/// This currently needs to be a macro because the `int` argument needs to be an
/// immediate. This macro will be replaced by a generic function when support for
/// const generics is implemented in Rust.
#[cfg(feature = "inline_asm")]
#[macro_export]
macro_rules! software_interrupt {
    ($x:expr) => {{
        asm!("int {id}", id = const $x, options(nomem, nostack));
    }};
}

/// Not implemented
#[cfg(not(feature = "inline_asm"))]
#[macro_export]
macro_rules! software_interrupt {
    ($x:expr) => {{
        compile_error!("software_interrupt not implemented for non-nightly");
    }};
}
<|endoftext|>