<commit_before>//! The implementation for Version 1 UUIDs.
//!
//! Note that you need feature `v1` in order to use these features.

use crate::{Uuid, Version};

use atomic::Atomic;

/// The number of 100 ns ticks between the UUID epoch
/// `1582-10-15 00:00:00` and the Unix epoch `1970-01-01 00:00:00`.
const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;

/// A thread-safe, stateful context for the v1 generator to help ensure
/// process-wide uniqueness.
#[derive(Debug)]
pub struct Context {
    count: Atomic<usize>,
}

/// Stores the number of nanoseconds from an epoch and a counter for ensuring
/// V1 ids generated on the same host are unique.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Timestamp {
    ticks: u64,
    counter: u16,
}

impl Timestamp {
    /// Construct a `Timestamp` from its raw component values: an RFC4122
    /// timestamp and counter.
    ///
    /// RFC4122, which defines the V1 UUID, specifies a 60-byte timestamp format
    /// as the number of 100-nanosecond intervals elapsed since 00:00:00.00,
    /// 15 Oct 1582, "the date of the Gregorian reform of the Christian
    /// calendar."
    ///
    /// The counter value is used to differentiate between ids generated by
    /// the same host computer in rapid succession (i.e. with the same observed
    /// time). See the [`ClockSequence`] trait for a generic interface to any
    /// counter generators that might be used.
    ///
    /// Internally, the timestamp is stored as a `u64`. For this reason, dates
    /// prior to October 1582 are not supported.
    ///
    /// [`ClockSequence`]: trait.ClockSequence.html
    pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
        Timestamp { ticks, counter }
    }

    /// Construct a `Timestamp` from a unix timestamp and sequence-generating
    /// `context`.
    ///
    /// A unix timestamp represents the elapsed time since Jan 1 1970. Libc's
    /// `clock_gettime` and other popular implementations traditionally
    /// represent this duration as a `timespec`: a struct with `u64` and
    /// `u32` fields representing the seconds, and "subsecond" or fractional
    /// nanoseconds elapsed since the timestamp's second began,
    /// respectively.
    ///
    /// This constructs a `Timestamp` from the seconds and fractional
    /// nanoseconds of a unix timestamp, converting the duration since 1970
    /// into the number of 100-nanosecond intervals since 00:00:00.00, 15
    /// Oct 1582 specified by RFC4122 and used internally by `Timestamp`.
    ///
    /// The function is not guaranteed to produce monotonically increasing
    /// values however. There is a slight possibility that two successive
    /// equal time values could be supplied and the sequence counter wraps back
    /// over to 0.
    ///
    /// If uniqueness and monotonicity is required, the user is responsible for
    /// ensuring that the time value always increases between calls (including
    /// between restarts of the process and device).
    pub fn from_unix(
        context: impl ClockSequence,
        seconds: u64,
        subsec_nanos: u32,
    ) -> Self {
        let counter = context.generate_sequence(seconds, subsec_nanos);
        let ticks = UUID_TICKS_BETWEEN_EPOCHS
            + seconds * 10_000_000
            + u64::from(subsec_nanos) / 100;

        Timestamp { ticks, counter }
    }

    /// Returns the raw RFC4122 timestamp and counter values stored by the
    /// `Timestamp`.
    ///
    /// The timestamp (the first, `u64` element in the tuple) represents the
    /// number of 100-nanosecond intervals since 00:00:00.00, 15 Oct 1582.
    /// The counter is used to differentiate between ids generated on the
    /// same host computer with the same observed time.
    pub const fn to_rfc4122(&self) -> (u64, u16) {
        (self.ticks, self.counter)
    }

    /// Returns the timestamp converted to the seconds and fractional
    /// nanoseconds since Jan 1 1970.
    ///
    /// Internally, the time is stored in 100-nanosecond intervals,
    /// thus the maximum precision represented by the fractional nanoseconds
    /// value is less than its unit size (100 ns vs. 1 ns).
    pub const fn to_unix(&self) -> (u64, u32) {
        (
            (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000,
            ((self.ticks - UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32
                * 100,
        )
    }

    /// Returns the timestamp converted into nanoseconds elapsed since Jan 1
    /// 1970. Internally, the time is stored in 100-nanosecond intervals,
    /// thus the maximum precision represented is less than the units it is
    /// measured in (100 ns vs. 1 ns). The value returned represents the
    /// same duration as [`Timestamp::to_unix`]; this provides it in nanosecond
    /// units for convenience.
    pub const fn to_unix_nanos(&self) -> u64 {
        (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) * 100
    }
}

/// A trait that abstracts over generation of UUID v1 "Clock Sequence" values.
pub trait ClockSequence {
    /// Return a 16-bit number that will be used as the "clock sequence" in
    /// the UUID. The number must be different if the time has changed since
    /// the last time a clock sequence was requested.
    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16;
}

impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T {
    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16 {
        (**self).generate_sequence(seconds, subsec_nanos)
    }
}

impl Uuid {
    /// Create a new UUID (version 1) using a time value + sequence +
    /// *NodeId*.
    ///
    /// When generating [`Timestamp`]s using a [`ClockSequence`], this function
    /// is only guaranteed to produce unique values if the following conditions
    /// hold:
    ///
    /// 1. The *NodeId* is unique for this process,
    /// 2. The *Context* is shared across all threads which are generating v1
    ///    UUIDs,
    /// 3. The [`ClockSequence`] implementation reliably returns unique
    ///    clock sequences (this crate provides [`Context`] for this
    ///    purpose. However you can create your own [`ClockSequence`]
    ///    implementation, if [`Context`] does not meet your needs).
    ///
    /// The NodeID must be exactly 6 bytes long.
    ///
    /// Note that usage of this method requires the `v1` feature of this crate
    /// to be enabled.
    ///
    /// # Examples
    ///
    /// A UUID can be created from a unix [`Timestamp`] with a
    /// [`ClockSequence`]:
    ///
    /// ```rust
    /// use uuid::v1::{Timestamp, Context};
    /// use uuid::Uuid;
    ///
    /// let context = Context::new(42);
    /// let ts = Timestamp::from_unix(&context, 1497624119, 1234);
    /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]);
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "f3b4958c-52a1-11e7-802a-010203040506"
    /// );
    /// ```
    ///
    /// The timestamp can also be created manually as per RFC4122:
    ///
    /// ```
    /// use uuid::v1::{Timestamp, Context};
    /// use uuid::Uuid;
    ///
    /// let context = Context::new(42);
    /// let ts = Timestamp::from_rfc4122(1497624119, 0);
    /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]);
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "5943ee37-0000-1000-8000-010203040506"
    /// );
    /// ```
    ///
    /// [`Timestamp`]: v1/struct.Timestamp.html
    /// [`ClockSequence`]: v1/struct.ClockSequence.html
    /// [`Context`]: v1/struct.Context.html
    pub const fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self {
        let time_low = (ts.ticks & 0xFFFF_FFFF) as u32;
        let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16;
        let time_high_and_version =
            (((ts.ticks >> 48) & 0x0FFF) as u16) | (1 << 12);

        let mut d4 = [0; 8];

        d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80;
        d4[1] = (ts.counter & 0xFF) as u8;
        d4[2] = node_id[0];
        d4[3] = node_id[1];
        d4[4] = node_id[2];
        d4[5] = node_id[3];
        d4[6] = node_id[4];
        d4[7] = node_id[5];

        Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
    }

    /// Returns an optional [`Timestamp`] storing the timestamp and
    /// counter portion parsed from a V1 UUID.
    ///
    /// Returns `None` if the supplied UUID is not V1.
    ///
    /// The V1 timestamp format defined in RFC4122 specifies a 60-bit
    /// integer representing the number of 100-nanosecond intervals
    /// since 00:00:00.00, 15 Oct 1582.
    ///
    /// [`Timestamp`] offers several options for converting the raw RFC4122
    /// value into more commonly-used formats, such as a unix timestamp.
    ///
    /// [`Timestamp`]: v1/struct.Timestamp.html
    pub const fn get_timestamp(&self) -> Option<Timestamp> {
        match self.get_version() {
            Some(Version::Mac) => {
                let ticks: u64 = ((self.as_bytes()[6] & 0x0F) as u64) << 56
                    | ((self.as_bytes()[7]) as u64) << 48
                    | ((self.as_bytes()[4]) as u64) << 40
                    | ((self.as_bytes()[5]) as u64) << 32
                    | ((self.as_bytes()[0]) as u64) << 24
                    | ((self.as_bytes()[1]) as u64) << 16
                    | ((self.as_bytes()[2]) as u64) << 8
                    | (self.as_bytes()[3] as u64);

                let counter: u16 = ((self.as_bytes()[8] & 0x3F) as u16) << 8
                    | (self.as_bytes()[9] as u16);

                Some(Timestamp::from_rfc4122(ticks, counter))
            }
            _ => None,
        }
    }
}

impl Context {
    /// Creates a thread-safe, internally mutable context to help ensure
    /// uniqueness.
    ///
    /// This is a context which can be shared across threads. It maintains an
    /// internal counter that is incremented at every request, the value ends
    /// up in the clock_seq portion of the UUID (the fourth group). This
    /// will improve the probability that the UUID is unique across the
    /// process.
    pub const fn new(count: u16) -> Self {
        Self {
            count: Atomic::new(count as usize),
        }
    }
}

impl ClockSequence for Context {
    fn generate_sequence(&self, _: u64, _: u32) -> u16 {
        (self.count.fetch_add(1, atomic::Ordering::SeqCst) & 0xffff) as u16
    }
}

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

    #[cfg(target_arch = "wasm32")]
    use wasm_bindgen_test::*;

    use crate::{std::string::ToString, Variant};

    #[test]
    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
    fn test_new_v1() {
        let time: u64 = 1_496_854_535;
        let time_fraction: u32 = 812_946_000;
        let node = [1, 2, 3, 4, 5, 6];
        let context = Context::new(0);

        {
            let uuid = Uuid::new_v1(
                Timestamp::from_unix(&context, time, time_fraction),
                &node,
            );

            assert_eq!(uuid.get_version(), Some(Version::Mac));
            assert_eq!(uuid.get_variant(), Variant::RFC4122);
            assert_eq!(
                uuid.to_hyphenated().to_string(),
                "20616934-4ba2-11e7-8000-010203040506"
            );

            let ts = uuid.get_timestamp().unwrap().to_rfc4122();

            assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
            assert_eq!(ts.1, 0);
        };

        {
            let uuid2 = Uuid::new_v1(
                Timestamp::from_unix(&context, time, time_fraction),
                &node,
            );

            assert_eq!(
                uuid2.to_hyphenated().to_string(),
                "20616934-4ba2-11e7-8001-010203040506"
            );
            assert_eq!(uuid2.get_timestamp().unwrap().to_rfc4122().1, 1)
        };
    }
}
<commit_msg>split up v1 tests<commit_after>//! The implementation for Version 1 UUIDs.
//!
//! Note that you need feature `v1` in order to use these features.

use crate::{Uuid, Version};

use atomic::Atomic;

/// The number of 100 ns ticks between the UUID epoch
/// `1582-10-15 00:00:00` and the Unix epoch `1970-01-01 00:00:00`.
const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;

/// A thread-safe, stateful context for the v1 generator to help ensure
/// process-wide uniqueness.
#[derive(Debug)]
pub struct Context {
    count: Atomic<usize>,
}

/// Stores the number of nanoseconds from an epoch and a counter for ensuring
/// V1 ids generated on the same host are unique.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Timestamp {
    ticks: u64,
    counter: u16,
}

impl Timestamp {
    /// Construct a `Timestamp` from its raw component values: an RFC4122
    /// timestamp and counter.
    ///
    /// RFC4122, which defines the V1 UUID, specifies a 60-byte timestamp format
    /// as the number of 100-nanosecond intervals elapsed since 00:00:00.00,
    /// 15 Oct 1582, "the date of the Gregorian reform of the Christian
    /// calendar."
    ///
    /// The counter value is used to differentiate between ids generated by
    /// the same host computer in rapid succession (i.e. with the same observed
    /// time). See the [`ClockSequence`] trait for a generic interface to any
    /// counter generators that might be used.
    ///
    /// Internally, the timestamp is stored as a `u64`. For this reason, dates
    /// prior to October 1582 are not supported.
    ///
    /// [`ClockSequence`]: trait.ClockSequence.html
    pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
        Timestamp { ticks, counter }
    }

    /// Construct a `Timestamp` from a unix timestamp and sequence-generating
    /// `context`.
    ///
    /// A unix timestamp represents the elapsed time since Jan 1 1970. Libc's
    /// `clock_gettime` and other popular implementations traditionally
    /// represent this duration as a `timespec`: a struct with `u64` and
    /// `u32` fields representing the seconds, and "subsecond" or fractional
    /// nanoseconds elapsed since the timestamp's second began,
    /// respectively.
    ///
    /// This constructs a `Timestamp` from the seconds and fractional
    /// nanoseconds of a unix timestamp, converting the duration since 1970
    /// into the number of 100-nanosecond intervals since 00:00:00.00, 15
    /// Oct 1582 specified by RFC4122 and used internally by `Timestamp`.
    ///
    /// The function is not guaranteed to produce monotonically increasing
    /// values however. There is a slight possibility that two successive
    /// equal time values could be supplied and the sequence counter wraps back
    /// over to 0.
    ///
    /// If uniqueness and monotonicity is required, the user is responsible for
    /// ensuring that the time value always increases between calls (including
    /// between restarts of the process and device).
    pub fn from_unix(
        context: impl ClockSequence,
        seconds: u64,
        subsec_nanos: u32,
    ) -> Self {
        let counter = context.generate_sequence(seconds, subsec_nanos);
        let ticks = UUID_TICKS_BETWEEN_EPOCHS
            + seconds * 10_000_000
            + u64::from(subsec_nanos) / 100;

        Timestamp { ticks, counter }
    }

    /// Returns the raw RFC4122 timestamp and counter values stored by the
    /// `Timestamp`.
    ///
    /// The timestamp (the first, `u64` element in the tuple) represents the
    /// number of 100-nanosecond intervals since 00:00:00.00, 15 Oct 1582.
    /// The counter is used to differentiate between ids generated on the
    /// same host computer with the same observed time.
    pub const fn to_rfc4122(&self) -> (u64, u16) {
        (self.ticks, self.counter)
    }

    /// Returns the timestamp converted to the seconds and fractional
    /// nanoseconds since Jan 1 1970.
    ///
    /// Internally, the time is stored in 100-nanosecond intervals,
    /// thus the maximum precision represented by the fractional nanoseconds
    /// value is less than its unit size (100 ns vs. 1 ns).
    pub const fn to_unix(&self) -> (u64, u32) {
        (
            (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000,
            ((self.ticks - UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32
                * 100,
        )
    }

    /// Returns the timestamp converted into nanoseconds elapsed since Jan 1
    /// 1970. Internally, the time is stored in 100-nanosecond intervals,
    /// thus the maximum precision represented is less than the units it is
    /// measured in (100 ns vs. 1 ns). The value returned represents the
    /// same duration as [`Timestamp::to_unix`]; this provides it in nanosecond
    /// units for convenience.
    pub const fn to_unix_nanos(&self) -> u64 {
        (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) * 100
    }
}

/// A trait that abstracts over generation of UUID v1 "Clock Sequence" values.
pub trait ClockSequence {
    /// Return a 16-bit number that will be used as the "clock sequence" in
    /// the UUID. The number must be different if the time has changed since
    /// the last time a clock sequence was requested.
    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16;
}

impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T {
    fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16 {
        (**self).generate_sequence(seconds, subsec_nanos)
    }
}

impl Uuid {
    /// Create a new UUID (version 1) using a time value + sequence +
    /// *NodeId*.
    ///
    /// When generating [`Timestamp`]s using a [`ClockSequence`], this function
    /// is only guaranteed to produce unique values if the following conditions
    /// hold:
    ///
    /// 1. The *NodeId* is unique for this process,
    /// 2. The *Context* is shared across all threads which are generating v1
    ///    UUIDs,
    /// 3. The [`ClockSequence`] implementation reliably returns unique
    ///    clock sequences (this crate provides [`Context`] for this
    ///    purpose. However you can create your own [`ClockSequence`]
    ///    implementation, if [`Context`] does not meet your needs).
    ///
    /// The NodeID must be exactly 6 bytes long.
    ///
    /// Note that usage of this method requires the `v1` feature of this crate
    /// to be enabled.
    ///
    /// # Examples
    ///
    /// A UUID can be created from a unix [`Timestamp`] with a
    /// [`ClockSequence`]:
    ///
    /// ```rust
    /// use uuid::v1::{Timestamp, Context};
    /// use uuid::Uuid;
    ///
    /// let context = Context::new(42);
    /// let ts = Timestamp::from_unix(&context, 1497624119, 1234);
    /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]);
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "f3b4958c-52a1-11e7-802a-010203040506"
    /// );
    /// ```
    ///
    /// The timestamp can also be created manually as per RFC4122:
    ///
    /// ```
    /// use uuid::v1::{Timestamp, Context};
    /// use uuid::Uuid;
    ///
    /// let context = Context::new(42);
    /// let ts = Timestamp::from_rfc4122(1497624119, 0);
    /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]);
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "5943ee37-0000-1000-8000-010203040506"
    /// );
    /// ```
    ///
    /// [`Timestamp`]: v1/struct.Timestamp.html
    /// [`ClockSequence`]: v1/struct.ClockSequence.html
    /// [`Context`]: v1/struct.Context.html
    pub const fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self {
        let time_low = (ts.ticks & 0xFFFF_FFFF) as u32;
        let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16;
        let time_high_and_version =
            (((ts.ticks >> 48) & 0x0FFF) as u16) | (1 << 12);

        let mut d4 = [0; 8];

        d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80;
        d4[1] = (ts.counter & 0xFF) as u8;
        d4[2] = node_id[0];
        d4[3] = node_id[1];
        d4[4] = node_id[2];
        d4[5] = node_id[3];
        d4[6] = node_id[4];
        d4[7] = node_id[5];

        Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
    }

    /// Returns an optional [`Timestamp`] storing the timestamp and
    /// counter portion parsed from a V1 UUID.
    ///
    /// Returns `None` if the supplied UUID is not V1.
    ///
    /// The V1 timestamp format defined in RFC4122 specifies a 60-bit
    /// integer representing the number of 100-nanosecond intervals
    /// since 00:00:00.00, 15 Oct 1582.
    ///
    /// [`Timestamp`] offers several options for converting the raw RFC4122
    /// value into more commonly-used formats, such as a unix timestamp.
    ///
    /// [`Timestamp`]: v1/struct.Timestamp.html
    pub const fn get_timestamp(&self) -> Option<Timestamp> {
        match self.get_version() {
            Some(Version::Mac) => {
                let ticks: u64 = ((self.as_bytes()[6] & 0x0F) as u64) << 56
                    | ((self.as_bytes()[7]) as u64) << 48
                    | ((self.as_bytes()[4]) as u64) << 40
                    | ((self.as_bytes()[5]) as u64) << 32
                    | ((self.as_bytes()[0]) as u64) << 24
                    | ((self.as_bytes()[1]) as u64) << 16
                    | ((self.as_bytes()[2]) as u64) << 8
                    | (self.as_bytes()[3] as u64);

                let counter: u16 = ((self.as_bytes()[8] & 0x3F) as u16) << 8
                    | (self.as_bytes()[9] as u16);

                Some(Timestamp::from_rfc4122(ticks, counter))
            }
            _ => None,
        }
    }
}

impl Context {
    /// Creates a thread-safe, internally mutable context to help ensure
    /// uniqueness.
    ///
    /// This is a context which can be shared across threads. It maintains an
    /// internal counter that is incremented at every request, the value ends
    /// up in the clock_seq portion of the UUID (the fourth group). This
    /// will improve the probability that the UUID is unique across the
    /// process.
    pub const fn new(count: u16) -> Self {
        Self {
            count: Atomic::new(count as usize),
        }
    }
}

impl ClockSequence for Context {
    fn generate_sequence(&self, _: u64, _: u32) -> u16 {
        (self.count.fetch_add(1, atomic::Ordering::SeqCst) & 0xffff) as u16
    }
}

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

    #[cfg(target_arch = "wasm32")]
    use wasm_bindgen_test::*;

    use crate::{std::string::ToString, Variant};

    #[test]
    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
    fn test_new_v1() {
        let time: u64 = 1_496_854_535;
        let time_fraction: u32 = 812_946_000;
        let node = [1, 2, 3, 4, 5, 6];
        let context = Context::new(0);

        let uuid = Uuid::new_v1(
            Timestamp::from_unix(&context, time, time_fraction),
            &node,
        );

        assert_eq!(uuid.get_version(), Some(Version::Mac));
        assert_eq!(uuid.get_variant(), Variant::RFC4122);
        assert_eq!(
            uuid.to_hyphenated().to_string(),
            "20616934-4ba2-11e7-8000-010203040506"
        );

        let ts = uuid.get_timestamp().unwrap().to_rfc4122();

        assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);

        // Ensure parsing the same UUID produces the same timestamp
        let parsed = Uuid::parse_str("20616934-4ba2-11e7-8000-010203040506").unwrap();

        assert_eq!(uuid.get_timestamp().unwrap(), parsed.get_timestamp().unwrap());
    }

    #[test]
    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
    fn test_new_v1_context() {
        let time: u64 = 1_496_854_535;
        let time_fraction: u32 = 812_946_000;
        let node = [1, 2, 3, 4, 5, 6];
        let context = Context::new(0);

        let uuid1 = Uuid::new_v1(
            Timestamp::from_unix(&context, time, time_fraction),
            &node,
        );

        let uuid2 = Uuid::new_v1(
            Timestamp::from_unix(&context, time, time_fraction),
            &node,
        );

        assert_eq!(uuid1.get_timestamp().unwrap().to_rfc4122().1, 0);
        assert_eq!(uuid2.get_timestamp().unwrap().to_rfc4122().1, 1);
    }
}
<|endoftext|>


<commit_before>use values::*;
use color::{Color, rgba};
use units::{Length, Px, Em, Pt};
use netsurfcss::util::css_fixed_to_float;
use either::{Either, Left, Right};

pub struct ComputedStyle {
    inner: n::c::CssComputedStyle
}

impl ComputedStyle {

    // CSS 2.1, Section 8 - Box model

    pub fn margin_top() -> CSSValue<CSSMargin> {
        convert_net_margin(self.inner.margin_top())
    }

    pub fn margin_right() -> CSSValue<CSSMargin> {
        convert_net_margin(self.inner.margin_right())
    }

    pub fn margin_bottom() -> CSSValue<CSSMargin> {
        convert_net_margin(self.inner.margin_bottom())
    }

    pub fn margin_left() -> CSSValue<CSSMargin> {
        convert_net_margin(self.inner.margin_left())
    }

    pub fn border_top_width() -> CSSValue<CSSBorderWidth> {
        convert_net_border_width(self.inner.border_top_width())
    }

    pub fn border_right_width() -> CSSValue<CSSBorderWidth> {
        convert_net_border_width(self.inner.border_right_width())
    }

    pub fn border_bottom_width() -> CSSValue<CSSBorderWidth> {
        convert_net_border_width(self.inner.border_bottom_width())
    }

    pub fn border_left_width() -> CSSValue<CSSBorderWidth> {
        convert_net_border_width(self.inner.border_left_width())
    }

    pub fn border_top_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_top_color())
    }

    pub fn border_top_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_top_color())
    }

    pub fn border_right_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_right_color())
    }

    pub fn border_bottom_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_bottom_color())
    }

    pub fn border_left_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_left_color())
    }

    // CSS 2.1, Section 9 - Visual formatting model

    pub fn display(root: bool) -> CSSValue<CSSDisplay> {
        convert_net_display_value(self.inner.display(root))
    }

    pub fn position() -> CSSValue<CSSPosition> {
        convert_net_position_value(self.inner.position())
    }

    pub fn float() -> CSSValue<CSSFloat> {
        convert_net_float_value(self.inner.float())
    }

    // CSS 2.1, Section 10 - Visual formatting model details

    pub fn width() -> CSSValue<CSSWidth> {
        convert_net_width_value(self.inner.width())
    }

    pub fn height() -> CSSValue<CSSHeight> {
        convert_net_height_value(self.inner.height())
    }

    // CSS 2.1, Section 11 - Visual effects

    // CSS 2.1, Section 12 - Generated content, automatic numbering, and lists

    // CSS 2.1, Section 13 - Paged media

    // CSS 2.1, Section 14 - Colors and Backgrounds

    pub fn background_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.background_color())
    }

    pub fn color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.color())
    }

    // CSS 2.1, Section 15 - Fonts

    pub fn font_family() -> CSSValue<~[CSSFontFamily]> {
        convert_net_font_family_value(self.inner.font_family())
    }

    pub fn font_style() -> CSSValue<CSSFontStyle> {
        convert_net_font_style_value(self.inner.font_style())
    }

    pub fn font_weight() -> CSSValue<CSSFontWeight> {
        convert_net_font_weight_value(self.inner.font_weight())
    }

    pub fn font_size() -> CSSValue<CSSFontSize> {
        convert_net_font_size_value(self.inner.font_size())
    }

    // CSS 2.1, Section 16 - Text

    pub fn text_align() -> CSSValue<CSSTextAlign> {
        convert_net_text_align_value(self.inner.text_align())
    }

    // CSS 2.1, Section 17 - Tables

    // CSS 2.1, Section 18 - User interface

}

fn convert_net_color(color: n::t::CssColor) -> Color {
    rgba(color.r, color.g, color.b, (color.a as float) / 255.0)
}

fn convert_net_color_value(color: n::v::CssColorValue) -> CSSValue<Color> {
    match color {
        n::v::CssColorInherit => Inherit,
        n::v::CssColorColor(v) => Specified(convert_net_color(v))
    }
}

fn convert_net_border_width(width: n::v::CssBorderWidthValue) -> CSSValue<CSSBorderWidth> {
    match width {
        n::v::CssBorderWidthInherit => Inherit,
        n::v::CssBorderWidthThin => Specified(CSSBorderWidthThin),
        n::v::CssBorderWidthMedium => Specified(CSSBorderWidthMedium),
        n::v::CssBorderWidthThick => Specified(CSSBorderWidthThick),
        n::v::CssBorderWidthWidth(width) => Specified(CSSBorderWidthLength(convert_net_unit_to_length(width))),
    }
}

fn convert_net_margin(margin: n::v::CssMarginValue) -> CSSValue<CSSMargin> {
    match margin {
        n::v::CssMarginInherit => Inherit,
        n::v::CssMarginSet(length) => Specified(CSSMarginLength(convert_net_unit_to_length(length))),
        n::v::CssMarginAuto => Specified(CSSMarginAuto)
    }
}

fn convert_net_width_value(value: n::v::CssWidthValue) -> CSSValue<CSSWidth> {
    match value {
        n::v::CssWidthInherit => Inherit,
        n::v::CssWidthSet(length) => Specified(CSSWidthLength(convert_net_unit_to_length(length))),
        n::v::CssWidthAuto => Specified(CSSWidthAuto)
    }
}

fn convert_net_height_value(value: n::v::CssHeightValue) -> CSSValue<CSSHeight> {
    match value {
        n::v::CssHeightInherit => Inherit,
        n::v::CssHeightSet(length) => Specified(CSSHeightLength(convert_net_unit_to_length(length))),
        n::v::CssHeightAuto => Specified(CSSHeightAuto)
    }
}

fn convert_net_display_value(value: n::v::CssDisplayValue) -> CSSValue<CSSDisplay> {
    match value {
        n::v::CssDisplayInherit => Inherit,
        n::v::CssDisplayInline => Specified(CSSDisplayInline),
        n::v::CssDisplayBlock => Specified(CSSDisplayBlock),
        n::v::CssDisplayListItem => Specified(CSSDisplayListItem),
        n::v::CssDisplayRunIn => fail unimpl("display: run-in"), // FIXME: Not in CSS 2.1
        n::v::CssDisplayInlineBlock => Specified(CSSDisplayInlineBlock),
        n::v::CssDisplayTable => Specified(CSSDisplayTable),
        n::v::CssDisplayInlineTable => Specified(CSSDisplayInlineTable),
        n::v::CssDisplayTableRowGroup => Specified(CSSDisplayTableRowGroup),
        n::v::CssDisplayTableHeaderGroup => Specified(CSSDisplayTableHeaderGroup),
        n::v::CssDisplayTableFooterGroup => Specified(CSSDisplayTableFooterGroup),
        n::v::CssDisplayTableRow => Specified(CSSDisplayTableRow),
        n::v::CssDisplayTableColumnGroup => Specified(CSSDisplayTableColumnGroup),
        n::v::CssDisplayTableColumn => Specified(CSSDisplayTableColumn),
        n::v::CssDisplayTableCell => Specified(CSSDisplayTableCell),
        n::v::CssDisplayTableCaption => Specified(CSSDisplayTableCaption),
        n::v::CssDisplayNone => Specified(CSSDisplayNone)
    }
}

fn convert_net_float_value(value: n::v::CssFloatValue) -> CSSValue<CSSFloat> {
    match value {
        n::v::CssFloatInherit => Inherit,
        n::v::CssFloatLeft => Specified(CSSFloatLeft),
        n::v::CssFloatRight => Specified(CSSFloatRight),
        n::v::CssFloatNone => Specified(CSSFloatNone)
    }
}

fn convert_net_position_value(value: n::v::CssPositionValue) -> CSSValue<CSSPosition> {
    match value {
        n::v::CssPositionInherit => Inherit,
        n::v::CssPositionStatic => Specified(CSSPositionStatic),
        n::v::CssPositionRelative => Specified(CSSPositionRelative),
        n::v::CssPositionAbsolute => Specified(CSSPositionAbsolute),
        n::v::CssPositionFixed => Specified(CSSPositionFixed)
    }
}

fn convert_net_font_family_value(value: n::v::CssFontFamilyValue) -> CSSValue<~[CSSFontFamily]> {
    use units::{Serif, SansSerif, Cursive, Fantasy, Monospace};

    match value {
        n::v::CssFontFamilyInherit => Inherit,
        n::v::CssFontFamilySerif => Specified(~[CSSFontFamilyGenericFamily(Serif)]),
        n::v::CssFontFamilySansSerif => Specified(~[CSSFontFamilyGenericFamily(SansSerif)]),
        n::v::CssFontFamilyCursive => Specified(~[CSSFontFamilyGenericFamily(Cursive)]),
        n::v::CssFontFamilyFantasy => Specified(~[CSSFontFamilyGenericFamily(Fantasy)]),
        n::v::CssFontFamilyMonospace => Specified(~[CSSFontFamilyGenericFamily(Monospace)]),
        n::v::CssFontFamilyValue(names) => Specified(names.map(|n| CSSFontFamilyFamilyName(n.to_str()) ))
    }
}

fn convert_net_font_size_value(value: n::v::CssFontSizeValue) -> CSSValue<CSSFontSize> {
    use units::*;

    match value {
        n::v::CssFontSizeInherit => Inherit,
        n::v::CssFontSizeXXSmall => Specified(CSSFontSizeAbsoluteSize(XXSmall)),
        n::v::CssFontSizeXSmall => Specified(CSSFontSizeAbsoluteSize(XSmall)),
        n::v::CssFontSizeSmall => Specified(CSSFontSizeAbsoluteSize(Small)),
        n::v::CssFontSizeMedium => Specified(CSSFontSizeAbsoluteSize(Medium)),
        n::v::CssFontSizeLarge => Specified(CSSFontSizeAbsoluteSize(Large)),
        n::v::CssFontSizeXLarge => Specified(CSSFontSizeAbsoluteSize(XLarge)),
        n::v::CssFontSizeXXLarge => Specified(CSSFontSizeAbsoluteSize(XXLarge)),
        n::v::CssFontSizeLarger => Specified(CSSFontSizeRelativeSize(Larger)),
        n::v::CssFontSizeSmaller => Specified(CSSFontSizeRelativeSize(Smaller)),
        n::v::CssFontSizeDimension(size) => {
            match convert_net_unit_to_length_or_percent(size) {
                Left(move val) => Specified(CSSFontSizeLength(move val)),
                Right(move val) => Specified(CSSFontSizePercentage(move val))
            }
        }
    }
}

fn convert_net_font_style_value(value: n::v::CssFontStyleValue) -> CSSValue<CSSFontStyle> {
    match value {
        n::v::CssFontStyleInherit => Inherit,
        n::v::CssFontStyleNormal => Specified(CSSFontStyleNormal),
        n::v::CssFontStyleItalic => Specified(CSSFontStyleItalic),
        n::v::CssFontStyleOblique => Specified(CSSFontStyleOblique)
    }
}

fn convert_net_font_weight_value(value: n::v::CssFontWeightValue) -> CSSValue<CSSFontWeight> {
    match value {
        n::v::CssFontWeightInherit => Inherit,
        n::v::CssFontWeightNormal => Specified(CSSFontWeightNormal),
        n::v::CssFontWeightBold => Specified(CSSFontWeightBold),
        n::v::CssFontWeightBolder => Specified(CSSFontWeightBolder),
        n::v::CssFontWeightLighter => Specified(CSSFontWeightLighter),
        n::v::CssFontWeight100 => Specified(CSSFontWeight100),
        n::v::CssFontWeight200 => Specified(CSSFontWeight200),
        n::v::CssFontWeight300 => Specified(CSSFontWeight300),
        n::v::CssFontWeight400 => Specified(CSSFontWeight400),
        n::v::CssFontWeight500 => Specified(CSSFontWeight500),
        n::v::CssFontWeight600 => Specified(CSSFontWeight600),
        n::v::CssFontWeight700 => Specified(CSSFontWeight700),
        n::v::CssFontWeight800 => Specified(CSSFontWeight800),
        n::v::CssFontWeight900 => Specified(CSSFontWeight900),
    }
}

fn convert_net_text_align_value(value: n::v::CssTextAlignValue) -> CSSValue<CSSTextAlign> {
    match value {
        n::v::CssTextAlignInherit => Inherit,
        n::v::CssTextAlignInheritIfNonMagic => unimpl("inherit if non-magic? wtf?"),
        n::v::CssTextAlignLeft => Specified(CSSTextAlignLeft),
        n::v::CssTextAlignRight => Specified(CSSTextAlignRight),
        n::v::CssTextAlignCenter => Specified(CSSTextAlignCenter),
        n::v::CssTextAlignJustify => Specified(CSSTextAlignJustify),
        n::v::CssTextAlignDefault => unimpl("text-align default"), // What is this? not in spec
        n::v::CssTextAlignLibcssLeft => unimpl("text-align libcss left"),
        n::v::CssTextAlignLibcssCenter => unimpl("text-align libcss center"),
        n::v::CssTextAlignLibcssRight => unimpl("text-align libcss right"),
    }
}

fn convert_net_unit_to_length(unit: n::t::CssUnit) -> Length {
    match convert_net_unit_to_length_or_percent(unit) {
        Left(move v) => v,
        Right(*) => fail ~"unexpected percentage unit"
    }
}

fn convert_net_unit_to_length_or_percent(unit: n::t::CssUnit) -> Either<Length, float> {
    match unit {
        n::t::CssUnitPx(l) => Left(Px(css_fixed_to_float(l))),
        n::t::CssUnitEm(l) => Left(Em(css_fixed_to_float(l))),
        n::t::CssUnitPt(l) => Left(Pt(css_fixed_to_float(l))),
        n::t::CssUnitPct(p) => Right(css_fixed_to_float(p)),
        _ => unimpl("unit")
    }
}

fn unimpl(what: &str) -> ! {
    fail fmt!("css unimplemented %?", what)
}
<commit_msg>Default -> Left<commit_after>use values::*;
use color::{Color, rgba};
use units::{Length, Px, Em, Pt};
use netsurfcss::util::css_fixed_to_float;
use either::{Either, Left, Right};

pub struct ComputedStyle {
    inner: n::c::CssComputedStyle
}

impl ComputedStyle {

    // CSS 2.1, Section 8 - Box model

    pub fn margin_top() -> CSSValue<CSSMargin> {
        convert_net_margin(self.inner.margin_top())
    }

    pub fn margin_right() -> CSSValue<CSSMargin> {
        convert_net_margin(self.inner.margin_right())
    }

    pub fn margin_bottom() -> CSSValue<CSSMargin> {
        convert_net_margin(self.inner.margin_bottom())
    }

    pub fn margin_left() -> CSSValue<CSSMargin> {
        convert_net_margin(self.inner.margin_left())
    }

    pub fn border_top_width() -> CSSValue<CSSBorderWidth> {
        convert_net_border_width(self.inner.border_top_width())
    }

    pub fn border_right_width() -> CSSValue<CSSBorderWidth> {
        convert_net_border_width(self.inner.border_right_width())
    }

    pub fn border_bottom_width() -> CSSValue<CSSBorderWidth> {
        convert_net_border_width(self.inner.border_bottom_width())
    }

    pub fn border_left_width() -> CSSValue<CSSBorderWidth> {
        convert_net_border_width(self.inner.border_left_width())
    }

    pub fn border_top_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_top_color())
    }

    pub fn border_top_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_top_color())
    }

    pub fn border_right_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_right_color())
    }

    pub fn border_bottom_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_bottom_color())
    }

    pub fn border_left_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.border_left_color())
    }

    // CSS 2.1, Section 9 - Visual formatting model

    pub fn display(root: bool) -> CSSValue<CSSDisplay> {
        convert_net_display_value(self.inner.display(root))
    }

    pub fn position() -> CSSValue<CSSPosition> {
        convert_net_position_value(self.inner.position())
    }

    pub fn float() -> CSSValue<CSSFloat> {
        convert_net_float_value(self.inner.float())
    }

    // CSS 2.1, Section 10 - Visual formatting model details

    pub fn width() -> CSSValue<CSSWidth> {
        convert_net_width_value(self.inner.width())
    }

    pub fn height() -> CSSValue<CSSHeight> {
        convert_net_height_value(self.inner.height())
    }

    // CSS 2.1, Section 11 - Visual effects

    // CSS 2.1, Section 12 - Generated content, automatic numbering, and lists

    // CSS 2.1, Section 13 - Paged media

    // CSS 2.1, Section 14 - Colors and Backgrounds

    pub fn background_color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.background_color())
    }

    pub fn color() -> CSSValue<Color> {
        convert_net_color_value(self.inner.color())
    }

    // CSS 2.1, Section 15 - Fonts

    pub fn font_family() -> CSSValue<~[CSSFontFamily]> {
        convert_net_font_family_value(self.inner.font_family())
    }

    pub fn font_style() -> CSSValue<CSSFontStyle> {
        convert_net_font_style_value(self.inner.font_style())
    }

    pub fn font_weight() -> CSSValue<CSSFontWeight> {
        convert_net_font_weight_value(self.inner.font_weight())
    }

    pub fn font_size() -> CSSValue<CSSFontSize> {
        convert_net_font_size_value(self.inner.font_size())
    }

    // CSS 2.1, Section 16 - Text

    pub fn text_align() -> CSSValue<CSSTextAlign> {
        convert_net_text_align_value(self.inner.text_align())
    }

    // CSS 2.1, Section 17 - Tables

    // CSS 2.1, Section 18 - User interface

}

fn convert_net_color(color: n::t::CssColor) -> Color {
    rgba(color.r, color.g, color.b, (color.a as float) / 255.0)
}

fn convert_net_color_value(color: n::v::CssColorValue) -> CSSValue<Color> {
    match color {
        n::v::CssColorInherit => Inherit,
        n::v::CssColorColor(v) => Specified(convert_net_color(v))
    }
}

fn convert_net_border_width(width: n::v::CssBorderWidthValue) -> CSSValue<CSSBorderWidth> {
    match width {
        n::v::CssBorderWidthInherit => Inherit,
        n::v::CssBorderWidthThin => Specified(CSSBorderWidthThin),
        n::v::CssBorderWidthMedium => Specified(CSSBorderWidthMedium),
        n::v::CssBorderWidthThick => Specified(CSSBorderWidthThick),
        n::v::CssBorderWidthWidth(width) => Specified(CSSBorderWidthLength(convert_net_unit_to_length(width))),
    }
}

fn convert_net_margin(margin: n::v::CssMarginValue) -> CSSValue<CSSMargin> {
    match margin {
        n::v::CssMarginInherit => Inherit,
        n::v::CssMarginSet(length) => Specified(CSSMarginLength(convert_net_unit_to_length(length))),
        n::v::CssMarginAuto => Specified(CSSMarginAuto)
    }
}

fn convert_net_width_value(value: n::v::CssWidthValue) -> CSSValue<CSSWidth> {
    match value {
        n::v::CssWidthInherit => Inherit,
        n::v::CssWidthSet(length) => Specified(CSSWidthLength(convert_net_unit_to_length(length))),
        n::v::CssWidthAuto => Specified(CSSWidthAuto)
    }
}

fn convert_net_height_value(value: n::v::CssHeightValue) -> CSSValue<CSSHeight> {
    match value {
        n::v::CssHeightInherit => Inherit,
        n::v::CssHeightSet(length) => Specified(CSSHeightLength(convert_net_unit_to_length(length))),
        n::v::CssHeightAuto => Specified(CSSHeightAuto)
    }
}

fn convert_net_display_value(value: n::v::CssDisplayValue) -> CSSValue<CSSDisplay> {
    match value {
        n::v::CssDisplayInherit => Inherit,
        n::v::CssDisplayInline => Specified(CSSDisplayInline),
        n::v::CssDisplayBlock => Specified(CSSDisplayBlock),
        n::v::CssDisplayListItem => Specified(CSSDisplayListItem),
        n::v::CssDisplayRunIn => fail unimpl("display: run-in"), // FIXME: Not in CSS 2.1
        n::v::CssDisplayInlineBlock => Specified(CSSDisplayInlineBlock),
        n::v::CssDisplayTable => Specified(CSSDisplayTable),
        n::v::CssDisplayInlineTable => Specified(CSSDisplayInlineTable),
        n::v::CssDisplayTableRowGroup => Specified(CSSDisplayTableRowGroup),
        n::v::CssDisplayTableHeaderGroup => Specified(CSSDisplayTableHeaderGroup),
        n::v::CssDisplayTableFooterGroup => Specified(CSSDisplayTableFooterGroup),
        n::v::CssDisplayTableRow => Specified(CSSDisplayTableRow),
        n::v::CssDisplayTableColumnGroup => Specified(CSSDisplayTableColumnGroup),
        n::v::CssDisplayTableColumn => Specified(CSSDisplayTableColumn),
        n::v::CssDisplayTableCell => Specified(CSSDisplayTableCell),
        n::v::CssDisplayTableCaption => Specified(CSSDisplayTableCaption),
        n::v::CssDisplayNone => Specified(CSSDisplayNone)
    }
}

fn convert_net_float_value(value: n::v::CssFloatValue) -> CSSValue<CSSFloat> {
    match value {
        n::v::CssFloatInherit => Inherit,
        n::v::CssFloatLeft => Specified(CSSFloatLeft),
        n::v::CssFloatRight => Specified(CSSFloatRight),
        n::v::CssFloatNone => Specified(CSSFloatNone)
    }
}

fn convert_net_position_value(value: n::v::CssPositionValue) -> CSSValue<CSSPosition> {
    match value {
        n::v::CssPositionInherit => Inherit,
        n::v::CssPositionStatic => Specified(CSSPositionStatic),
        n::v::CssPositionRelative => Specified(CSSPositionRelative),
        n::v::CssPositionAbsolute => Specified(CSSPositionAbsolute),
        n::v::CssPositionFixed => Specified(CSSPositionFixed)
    }
}

fn convert_net_font_family_value(value: n::v::CssFontFamilyValue) -> CSSValue<~[CSSFontFamily]> {
    use units::{Serif, SansSerif, Cursive, Fantasy, Monospace};

    match value {
        n::v::CssFontFamilyInherit => Inherit,
        n::v::CssFontFamilySerif => Specified(~[CSSFontFamilyGenericFamily(Serif)]),
        n::v::CssFontFamilySansSerif => Specified(~[CSSFontFamilyGenericFamily(SansSerif)]),
        n::v::CssFontFamilyCursive => Specified(~[CSSFontFamilyGenericFamily(Cursive)]),
        n::v::CssFontFamilyFantasy => Specified(~[CSSFontFamilyGenericFamily(Fantasy)]),
        n::v::CssFontFamilyMonospace => Specified(~[CSSFontFamilyGenericFamily(Monospace)]),
        n::v::CssFontFamilyValue(names) => Specified(names.map(|n| CSSFontFamilyFamilyName(n.to_str()) ))
    }
}

fn convert_net_font_size_value(value: n::v::CssFontSizeValue) -> CSSValue<CSSFontSize> {
    use units::*;

    match value {
        n::v::CssFontSizeInherit => Inherit,
        n::v::CssFontSizeXXSmall => Specified(CSSFontSizeAbsoluteSize(XXSmall)),
        n::v::CssFontSizeXSmall => Specified(CSSFontSizeAbsoluteSize(XSmall)),
        n::v::CssFontSizeSmall => Specified(CSSFontSizeAbsoluteSize(Small)),
        n::v::CssFontSizeMedium => Specified(CSSFontSizeAbsoluteSize(Medium)),
        n::v::CssFontSizeLarge => Specified(CSSFontSizeAbsoluteSize(Large)),
        n::v::CssFontSizeXLarge => Specified(CSSFontSizeAbsoluteSize(XLarge)),
        n::v::CssFontSizeXXLarge => Specified(CSSFontSizeAbsoluteSize(XXLarge)),
        n::v::CssFontSizeLarger => Specified(CSSFontSizeRelativeSize(Larger)),
        n::v::CssFontSizeSmaller => Specified(CSSFontSizeRelativeSize(Smaller)),
        n::v::CssFontSizeDimension(size) => {
            match convert_net_unit_to_length_or_percent(size) {
                Left(move val) => Specified(CSSFontSizeLength(move val)),
                Right(move val) => Specified(CSSFontSizePercentage(move val))
            }
        }
    }
}

fn convert_net_font_style_value(value: n::v::CssFontStyleValue) -> CSSValue<CSSFontStyle> {
    match value {
        n::v::CssFontStyleInherit => Inherit,
        n::v::CssFontStyleNormal => Specified(CSSFontStyleNormal),
        n::v::CssFontStyleItalic => Specified(CSSFontStyleItalic),
        n::v::CssFontStyleOblique => Specified(CSSFontStyleOblique)
    }
}

fn convert_net_font_weight_value(value: n::v::CssFontWeightValue) -> CSSValue<CSSFontWeight> {
    match value {
        n::v::CssFontWeightInherit => Inherit,
        n::v::CssFontWeightNormal => Specified(CSSFontWeightNormal),
        n::v::CssFontWeightBold => Specified(CSSFontWeightBold),
        n::v::CssFontWeightBolder => Specified(CSSFontWeightBolder),
        n::v::CssFontWeightLighter => Specified(CSSFontWeightLighter),
        n::v::CssFontWeight100 => Specified(CSSFontWeight100),
        n::v::CssFontWeight200 => Specified(CSSFontWeight200),
        n::v::CssFontWeight300 => Specified(CSSFontWeight300),
        n::v::CssFontWeight400 => Specified(CSSFontWeight400),
        n::v::CssFontWeight500 => Specified(CSSFontWeight500),
        n::v::CssFontWeight600 => Specified(CSSFontWeight600),
        n::v::CssFontWeight700 => Specified(CSSFontWeight700),
        n::v::CssFontWeight800 => Specified(CSSFontWeight800),
        n::v::CssFontWeight900 => Specified(CSSFontWeight900),
    }
}

fn convert_net_text_align_value(value: n::v::CssTextAlignValue) -> CSSValue<CSSTextAlign> {
    match value {
        n::v::CssTextAlignInherit => Inherit,
        n::v::CssTextAlignInheritIfNonMagic => unimpl("inherit if non-magic? wtf?"),
        n::v::CssTextAlignLeft => Specified(CSSTextAlignLeft),
        n::v::CssTextAlignRight => Specified(CSSTextAlignRight),
        n::v::CssTextAlignCenter => Specified(CSSTextAlignCenter),
        n::v::CssTextAlignJustify => Specified(CSSTextAlignJustify),
        n::v::CssTextAlignDefault => Specified(CSSTextAlignLeft),
        n::v::CssTextAlignLibcssLeft => unimpl("text-align libcss left"),
        n::v::CssTextAlignLibcssCenter => unimpl("text-align libcss center"),
        n::v::CssTextAlignLibcssRight => unimpl("text-align libcss right"),
    }
}

fn convert_net_unit_to_length(unit: n::t::CssUnit) -> Length {
    match convert_net_unit_to_length_or_percent(unit) {
        Left(move v) => v,
        Right(*) => fail ~"unexpected percentage unit"
    }
}

fn convert_net_unit_to_length_or_percent(unit: n::t::CssUnit) -> Either<Length, float> {
    match unit {
        n::t::CssUnitPx(l) => Left(Px(css_fixed_to_float(l))),
        n::t::CssUnitEm(l) => Left(Em(css_fixed_to_float(l))),
        n::t::CssUnitPt(l) => Left(Pt(css_fixed_to_float(l))),
        n::t::CssUnitPct(p) => Right(css_fixed_to_float(p)),
        _ => unimpl("unit")
    }
}

fn unimpl(what: &str) -> ! {
    fail fmt!("css unimplemented %?", what)
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use futures::{Future, Poll};

use ::client::ClientHandle;
use ::error::*;
use ::op::Message;

#[derive(Clone)]
pub struct RetryClientHandle<H: ClientHandle> {
  client: H,
  attempts: usize,
}

impl<H> RetryClientHandle<H> where H: ClientHandle {
  pub fn new(client: H, attempts: usize) -> RetryClientHandle<H> {
    RetryClientHandle { client: client, attempts: attempts }
  }
}

impl<H> ClientHandle for RetryClientHandle<H> where H: ClientHandle + 'static {
  fn send(&self, message: Message) -> Box<Future<Item=Message, Error=ClientError>> {
    // need to clone here so that the retry can resend if necessary...
    //  obviously it would be nice to be lazy about this...
    let future = self.client.send(message.clone());

    return Box::new(RetrySendFuture{
      message: message,
      client: self.client.clone(),
      future: future,
      remaining_attempts: self.attempts
    });
  }
}

/// A future for retrying (on failure, for the remaining number of times specified)
struct RetrySendFuture<H: ClientHandle> {
  message: Message,
  client: H,
  future: Box<Future<Item=Message, Error=ClientError>>,
  remaining_attempts: usize,
}

impl<H> Future for RetrySendFuture<H> where H: ClientHandle {
  type Item = Message;
  type Error = ClientError;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    // loop over the future, on errors, spawn a new future
    //  on ready and not ready return.
    loop {
      match self.future.poll() {
        r @ Ok(_) => return r,
        Err(e) => {
          if self.remaining_attempts == 0 {
            return Err(e);
          }

          self.remaining_attempts = self.remaining_attempts - 1;
          // TODO: if the "sent" Message is part of the error result,
          //  then we can just reuse it... and no clone necessary
          self.future = self.client.send(self.message.clone());
        }
      }
    }
  }
}

#[cfg(test)]
mod test {
  use std::cell::Cell;
  use ::client::*;
  use ::error::*;
  use ::op::*;
  use futures::*;

  #[derive(Clone)]
  struct TestClient { last_succeed: bool, retries: u16, attempts: Cell<u16> }

  impl ClientHandle for TestClient {
    fn send(&self, _: Message) -> Box<Future<Item=Message, Error=ClientError>> {
      let i = self.attempts.get();
      self.attempts.set(i + 1);

      if self.retries - i == 0 && self.last_succeed {
        let mut message = Message::new();
        message.id(i);
        return Box::new(finished(message))
      }

      return Box::new(failed(ClientErrorKind::Message("last retry set to fail").into()))
    }
  }

  #[test]
  fn test_retry() {
    let client = RetryClientHandle::new(TestClient{last_succeed: true, retries: 1, attempts: Cell::new(0)}, 2);
    let test1 = Message::new();
    let result = client.send(test1).wait().ok().expect("should have succeeded");
    assert_eq!(result.get_id(), 1); // this is checking the number of iterations the TestCient ran
  }

  #[test]
  fn test_error() {
    let client = RetryClientHandle::new(TestClient{last_succeed: false, retries: 1, attempts: Cell::new(0)}, 2);
    let test1 = Message::new();
    assert!(client.send(test1).wait().is_err());

  }
}
<commit_msg>fix retry handle test overflow<commit_after>// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use futures::{Future, Poll};

use ::client::ClientHandle;
use ::error::*;
use ::op::Message;

#[derive(Clone)]
pub struct RetryClientHandle<H: ClientHandle> {
  client: H,
  attempts: usize,
}

impl<H> RetryClientHandle<H> where H: ClientHandle {
  pub fn new(client: H, attempts: usize) -> RetryClientHandle<H> {
    RetryClientHandle { client: client, attempts: attempts }
  }
}

impl<H> ClientHandle for RetryClientHandle<H> where H: ClientHandle + 'static {
  fn send(&self, message: Message) -> Box<Future<Item=Message, Error=ClientError>> {
    // need to clone here so that the retry can resend if necessary...
    //  obviously it would be nice to be lazy about this...
    let future = self.client.send(message.clone());

    return Box::new(RetrySendFuture{
      message: message,
      client: self.client.clone(),
      future: future,
      remaining_attempts: self.attempts
    });
  }
}

/// A future for retrying (on failure, for the remaining number of times specified)
struct RetrySendFuture<H: ClientHandle> {
  message: Message,
  client: H,
  future: Box<Future<Item=Message, Error=ClientError>>,
  remaining_attempts: usize,
}

impl<H> Future for RetrySendFuture<H> where H: ClientHandle {
  type Item = Message;
  type Error = ClientError;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    // loop over the future, on errors, spawn a new future
    //  on ready and not ready return.
    loop {
      match self.future.poll() {
        r @ Ok(_) => return r,
        Err(e) => {
          if self.remaining_attempts == 0 {
            return Err(e);
          }

          self.remaining_attempts = self.remaining_attempts - 1;
          // TODO: if the "sent" Message is part of the error result,
          //  then we can just reuse it... and no clone necessary
          self.future = self.client.send(self.message.clone());
        }
      }
    }
  }
}

#[cfg(test)]
mod test {
  use std::cell::Cell;
  use ::client::*;
  use ::error::*;
  use ::op::*;
  use futures::*;

  #[derive(Clone)]
  struct TestClient { last_succeed: bool, retries: u16, attempts: Cell<u16> }

  impl ClientHandle for TestClient {
    fn send(&self, _: Message) -> Box<Future<Item=Message, Error=ClientError>> {
      let i = self.attempts.get();

      if i > self.retries || self.retries - i == 0 {
        if self.last_succeed {
          let mut message = Message::new();
          message.id(i);
          return Box::new(finished(message))
        }
      }

      self.attempts.set(i + 1);
      return Box::new(failed(ClientErrorKind::Message("last retry set to fail").into()))
    }
  }

  #[test]
  fn test_retry() {
    let client = RetryClientHandle::new(TestClient{last_succeed: true, retries: 1, attempts: Cell::new(0)}, 2);
    let test1 = Message::new();
    let result = client.send(test1).wait().ok().expect("should have succeeded");
    assert_eq!(result.get_id(), 1); // this is checking the number of iterations the TestCient ran
  }

  #[test]
  fn test_error() {
    let client = RetryClientHandle::new(TestClient{last_succeed: false, retries: 1, attempts: Cell::new(0)}, 2);
    let test1 = Message::new();
    assert!(client.send(test1).wait().is_err());

  }
}
<|endoftext|>


<commit_before>#[phase(plugin)]
extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};

pub struct PropertyValue {
    params: String,
    value: String,
}

impl PropertyValue {
    pub fn get_raw_value(&self) -> &String { &self.value }
    pub fn get_raw_params(&self) -> &String { &self.params }
}

pub struct Item {
    pub props: HashMap<String, Vec<PropertyValue>>,
    empty_prop_vector: Vec<PropertyValue>
}

impl Item {
    fn new() -> Item {
        Item {
            props: HashMap::new(),
            empty_prop_vector: vec![]
        }
    }

    pub fn single_value(&self, key: &String) -> Option<&String> {
        match self.props.find(key) {
            Some(x) => { if x.len() > 0 { Some(x[0].get_raw_value()) } else { None } },
            None => { None }
        }
    }

    pub fn all_values_mut(&mut self, key: String) -> &mut Vec<PropertyValue> {
        match self.props.entry(key) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.set(vec![])
        }
    }

    pub fn all_values(&self, key: &String) -> &Vec<PropertyValue> {
        match self.props.find(key) {
            Some(values) => values,
            None => &self.empty_prop_vector
        }
    }
}

peg! parser(r#"
use super::{Item,PropertyValue};

#[pub]

item -> Item
    = p:prop ++ eol {
        let mut rv = Item::new();

        for (k, v) in p.into_iter() {
            rv.all_values_mut(k).push(v);
        };
        rv
    }

prop -> (String, PropertyValue)
    = k:prop_name p:(";" p:prop_params {p})? ":" v:prop_value {
        (k, PropertyValue {
            value: v,
            params: match p { Some(x) => x, None => "".to_string() }
        })
    }

prop_name -> String
    = name_char+ { match_str.into_string() }

prop_params -> String
    = prop_char+ { match_str.into_string() }

prop_value -> String
    = value_char+ { match_str.into_string() }

// Characters
name_char = ([a-zA-Z] / "-")
prop_char = name_char / [=;]
value_char = !eol .
eol = "\n" / "\r\n" / "\r" / "\u2028" / "\u2029"

"#)

pub fn parse_item(s: &String) -> Result<Item, String> {
    parser::item(s.as_slice())
}
<commit_msg>Remove stupid default value field<commit_after>#[phase(plugin)]
extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};

pub struct PropertyValue {
    params: String,
    value: String,
}

impl PropertyValue {
    pub fn get_raw_value(&self) -> &String { &self.value }
    pub fn get_raw_params(&self) -> &String { &self.params }
}

pub struct Item {
    pub props: HashMap<String, Vec<PropertyValue>>
}

impl Item {
    fn new() -> Item {
        Item {
            props: HashMap::new()
        }
    }

    pub fn single_value(&self, key: &String) -> Option<&String> {
        match self.props.find(key) {
            Some(x) => { if x.len() > 0 { Some(x[0].get_raw_value()) } else { None } },
            None => { None }
        }
    }

    pub fn all_values_mut(&mut self, key: String) -> &mut Vec<PropertyValue> {
        match self.props.entry(key) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.set(vec![])
        }
    }

    pub fn all_values(&self, key: &String) -> &[PropertyValue] {
        static EMPTY: &'static [PropertyValue] = [];
        match self.props.find(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

peg! parser(r#"
use super::{Item,PropertyValue};

#[pub]

item -> Item
    = p:prop ++ eol {
        let mut rv = Item::new();

        for (k, v) in p.into_iter() {
            rv.all_values_mut(k).push(v);
        };
        rv
    }

prop -> (String, PropertyValue)
    = k:prop_name p:(";" p:prop_params {p})? ":" v:prop_value {
        (k, PropertyValue {
            value: v,
            params: match p { Some(x) => x, None => "".to_string() }
        })
    }

prop_name -> String
    = name_char+ { match_str.into_string() }

prop_params -> String
    = prop_char+ { match_str.into_string() }

prop_value -> String
    = value_char+ { match_str.into_string() }

// Characters
name_char = ([a-zA-Z] / "-")
prop_char = name_char / [=;]
value_char = !eol .
eol = "\n" / "\r\n" / "\r" / "\u2028" / "\u2029"

"#)

pub fn parse_item(s: &String) -> Result<Item, String> {
    parser::item(s.as_slice())
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::rc::Weak;

use cell::Cell;
use globals;

struct EnvironmentImpl {
    table:     HashMap<String, Cell>,
    enclosing: Option<Weak<RefCell<EnvironmentImpl>>>,
}

#[derive(Clone)]
pub struct Environment(Rc<RefCell<EnvironmentImpl>>);

impl Environment {
    pub fn new() -> Environment {
        Environment(Rc::new(RefCell::new(EnvironmentImpl {
            table:     HashMap::new(),
            enclosing: None,
        })))
    }

    pub fn make_sub_environment(&self) -> Environment {
        let &Environment(ref env) = self;
        Environment(Rc::new(RefCell::new(EnvironmentImpl {
            table:     HashMap::new(),
            enclosing: Some(env.downgrade()),
        })))
    }

    pub fn lookup(&self, key: &str) -> Cell {
        let &Environment(ref env) = self;
        match (env.borrow().table.get(key), &env.borrow().enclosing) {
            (Some(c), _)         => c.clone(),
            (None, &Some(ref e)) => Environment(e.upgrade().expect("Internal error")).lookup(key),
            (None, &None)        => {
                match globals::GLOBAL_ENVIROMENT.get(key) {
                    Some(bfs) => Cell::Builtin(bfs),
                    None      => Cell::Error(format!("Undefined symbol: {}", key))
                }
            }
        }
    }

    pub fn insert(&self, key: &str, c: &Cell) {
        let &Environment(ref env) = self;
        env.borrow_mut().table.insert(key.to_string(), c.clone());
    }

    pub fn insert_top(&self, key: &str, c: &Cell) {
        let &Environment(ref env) = self;
        let enclosing = env.borrow().enclosing.clone();
        match enclosing {
            Some(ref e) => Environment(e.upgrade().expect("Internal error")).insert_top(key, c),
            None        => { env.borrow_mut().table.insert(key.to_string(), c.clone()); },
        };
    }
}<commit_msg>Use new form of rc downgrade<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::rc::Weak;

use cell::Cell;
use globals;

struct EnvironmentImpl {
    table:     HashMap<String, Cell>,
    enclosing: Option<Weak<RefCell<EnvironmentImpl>>>,
}

#[derive(Clone)]
pub struct Environment(Rc<RefCell<EnvironmentImpl>>);

impl Environment {
    pub fn new() -> Environment {
        Environment(Rc::new(RefCell::new(EnvironmentImpl {
            table:     HashMap::new(),
            enclosing: None,
        })))
    }

    pub fn make_sub_environment(&self) -> Environment {
        let &Environment(ref env) = self;
        Environment(Rc::new(RefCell::new(EnvironmentImpl {
            table:     HashMap::new(),
            enclosing: Some(Rc::downgrade(&env)),
        })))
    }

    pub fn lookup(&self, key: &str) -> Cell {
        let &Environment(ref env) = self;
        match (env.borrow().table.get(key), &env.borrow().enclosing) {
            (Some(c), _)         => c.clone(),
            (None, &Some(ref e)) => Environment(e.upgrade().expect("Internal error")).lookup(key),
            (None, &None)        => {
                match globals::GLOBAL_ENVIROMENT.get(key) {
                    Some(bfs) => Cell::Builtin(bfs),
                    None      => Cell::Error(format!("Undefined symbol: {}", key))
                }
            }
        }
    }

    pub fn insert(&self, key: &str, c: &Cell) {
        let &Environment(ref env) = self;
        env.borrow_mut().table.insert(key.to_string(), c.clone());
    }

    pub fn insert_top(&self, key: &str, c: &Cell) {
        let &Environment(ref env) = self;
        let enclosing = env.borrow().enclosing.clone();
        match enclosing {
            Some(ref e) => Environment(e.upgrade().expect("Internal error")).insert_top(key, c),
            None        => { env.borrow_mut().table.insert(key.to_string(), c.clone()); },
        };
    }
}<|endoftext|>


<commit_before>//! This module implements the in-memory database
//!
//! A support folder with SDK debug symbols can be processed into a
//! in-memory database format which is a flat file on the file system
//! that gets mmaped into the process.
use std::str::from_utf8;
use std::mem;
use std::slice;
use std::path::Path;
use std::borrow::Cow;
use std::ffi::CStr;
use std::os::raw::c_char;

use std::fmt;
use uuid::Uuid;
use memmap::{Mmap, Protection};

use super::types::{IndexItem, StoredSlice, MemDbHeader, IndexedUuid};
use super::super::{Result, ErrorKind};
use super::super::sdk::SdkInfo;
use super::super::utils::binsearch_by_key;

enum Backing<'a> {
    Buf(Cow<'a, [u8]>),
    Mmap(Mmap),
}

/// Provides access to a memdb file
pub struct MemDb<'a> {
    info: SdkInfo,
    backing: Backing<'a>
}

/// Represents a symbol from a memdb file.
#[derive(Debug)]
pub struct Symbol<'a> {
    object_uuid: Uuid,
    object_name: Cow<'a, str>,
    symbol: Cow<'a, str>,
    addr: u64,
}

/// Represents a symbol iterator
pub struct SymbolIter<'a> {
    memdb: &'a MemDb<'a>,
    uuid: &'a Uuid,
    index: &'a [IndexItem],
    pos: usize,
}

impl<'a> Iterator for SymbolIter<'a> {
    type Item = Result<Symbol<'a>>;

    fn next(&mut self) -> Option<Result<Symbol<'a>>> {
        if self.pos < self.index.len() {
            let ii = &self.index[self.pos];
            self.pos += 1;
            Some(self.memdb.index_item_to_symbol(ii, self.uuid))
        } else {
            None
        }
    }
}

impl<'a> fmt::Display for Symbol<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:016x} {} ({})", self.addr(), self.symbol(), self.object_name())
    }
}

impl<'a> Backing<'a> {

    fn get_data(&self, start: usize, len: usize) -> Result<&[u8]> {
        let buffer = self.buffer();
        let end = start.wrapping_add(len);
        if end < start || end > buffer.len() {
            Err(ErrorKind::BadMemDb.into())
        } else {
            Ok(&buffer[start..end])
        }
    }

    fn get_slice<T>(&self, offset: usize, count: usize) -> Result<&[T]> {
        let size = mem::size_of::<T>();
        Ok(unsafe {
            slice::from_raw_parts(
                mem::transmute(self.get_data(offset, count * size)?.as_ptr()),
                count
            )
        })
    }

    #[inline(always)]
    fn header(&self) -> Result<&MemDbHeader> {
        unsafe {
            Ok(mem::transmute(self.get_data(0, mem::size_of::<MemDbHeader>())?.as_ptr()))
        }
    }

    #[inline(always)]
    fn buffer(&self) -> &[u8] {
        match *self {
            Backing::Buf(ref buf) => buf,
            Backing::Mmap(ref mmap) => unsafe { mmap.as_slice() }
        }
    }
}

impl<'a> Symbol<'a> {

    /// The uuid of the image
    pub fn object_uuid(&self) -> Uuid {
        self.object_uuid.clone()
    }

    /// The object name a string
    pub fn object_name(&self) -> &str {
        return &self.object_name
    }

    /// The symbol as string
    pub fn symbol(&self) -> &str {
        return &self.symbol
    }

    /// The symbol address as u64
    pub fn addr(&self) -> u64 {
        self.addr
    }
}

fn load_memdb<'a>(backing: Backing<'a>) -> Result<MemDb<'a>> {
    let info = {
        let header = backing.header()?;
        if header.version != 1 {
            return Err(ErrorKind::UnsupportedMemDbVersion.into());
        }
        header.sdk_info.to_sdk_info()
    };
    Ok(MemDb {
        backing: backing,
        info: info,
    })
}

impl<'a> MemDb<'a> {

    /// Constructs a memdb object from a byte slice cow.
    pub fn from_cow(cow: Cow<'a, [u8]>) -> Result<MemDb<'a>> {
        load_memdb(Backing::Buf(cow))
    }

    /// Constructs a memdb object from a byte slice.
    pub fn from_slice(buffer: &'a [u8]) -> Result<MemDb<'a>> {
        MemDb::from_cow(Cow::Borrowed(buffer))
    }

    /// Constructs a memdb object from a byte vector.
    pub fn from_vec(buffer: Vec<u8>) -> Result<MemDb<'a>> {
        MemDb::from_cow(Cow::Owned(buffer))
    }

    /// Constructs a memdb object by mmapping a file from the filesystem in.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<MemDb<'a>> {
        let mmap = Mmap::open_path(path, Protection::Read)?;
        load_memdb(Backing::Mmap(mmap))
    }

    /// Return the SDK info.
    pub fn info(&self) -> &SdkInfo {
        &self.info
    }

    /// Finds a symbol by UUID and address.
    pub fn lookup_by_uuid(&'a self, uuid: &Uuid, addr: u64) -> Option<Symbol<'a>> {
        self.lookup_impl(uuid, addr).ok().and_then(|x| x)
    }

    /// Finds a symbol by object name and architecture
    pub fn lookup_by_object_name(&'a self, object_name: &str, arch: &str, addr: u64)
        -> Option<Symbol<'a>>
    {
        if let Ok(Some(uuid)) = self.find_uuid(object_name, arch) {
            self.lookup_impl(uuid, addr).ok().and_then(|x| x)
        } else {
            None
        }
    }

    /// Given an object namd and architecture this finds the image UUID in the file.
    pub fn find_uuid(&self, object_name: &str, arch: &str) -> Result<Option<&Uuid>> {
        let header = self.backing.header()?;
        let mut offset = header.tagged_object_names_start as usize;
        let refstr = format!("{}:{}", object_name, arch);
        let mut uuid_idx = 0;
        while offset < header.tagged_object_names_end as usize {
            let s = self.get_cstr(offset)?;
            if s == &refstr {
                return Ok(Some(&self.uuids()?[uuid_idx].uuid));
            }
            offset += s.len() + 1;
            uuid_idx += 1;
        }
        Ok(None)
    }

    /// Given object name and architecture or UUID as string, this finds the
    /// UUID in the file.
    pub fn find_uuid_fuzzy(&self, name_or_uuid: &str) -> Result<Option<&Uuid>> {
        if let Ok(parsed_uuid) = name_or_uuid.parse::<Uuid>() {
            let uuids = self.uuids()?;
            if let Some(item) = binsearch_by_key(uuids, parsed_uuid, |item| *item.uuid()) {
                return Ok(Some(item.uuid()));
            }
            return Ok(None)
        }
        let mut parts = name_or_uuid.rsplitn(2, ':');
        if_chain! {
            if let Some(arch) = parts.next();
            if let Some(name) = parts.next();
            if let Some(uuid) = self.find_uuid(name, arch)?;
            then {
                Ok(Some(uuid))
            } else {
                Ok(None)
            }
        }
    }

    /// Returns the symbols for an Uuid
    pub fn iter_symbols(&'a self, uuid: &'a Uuid) -> Result<SymbolIter<'a>> {
        let index = self.get_index(uuid)?.unwrap_or(&[][..]);
        Ok(SymbolIter {
            memdb: self,
            uuid: uuid,
            index: index,
            pos: 0,
        })
    }

    fn get_cstr(&self, offset: usize) -> Result<&str> {
        unsafe {
            Ok(from_utf8(CStr::from_ptr(self.backing.buffer().as_ptr().offset(
                offset as isize) as *const c_char).to_bytes())?)
        }
    }

    fn lookup_impl(&'a self, uuid: &Uuid, addr: u64) -> Result<Option<Symbol<'a>>>
    {
        if let Some(index) = self.get_index(uuid)? {
            if let Some(item) = binsearch_by_key(index, addr, |item| item.addr()) {
                return Ok(Some(self.index_item_to_symbol(item, uuid)?));
            }
        }
        Ok(None)
    }

    #[inline(always)]
    fn uuids(&self) -> Result<&[IndexedUuid]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.uuids_start as usize, head.uuids_count as usize)
    }

    #[inline(always)]
    fn variants(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.variants_start as usize, head.variants_count as usize)
    }

    #[inline(always)]
    fn get_index(&self, uuid: &Uuid) -> Result<Option<&[IndexItem]>> {
        let uuids = self.uuids()?;
        if let Some(iuuid) = binsearch_by_key(uuids, *uuid, |item| *item.uuid()) {
            let variant_slice = &self.variants()?[iuuid.idx()];
            unsafe {
                let data = self.backing.get_data(variant_slice.offset(),
                                                 variant_slice.len())?;
                let count = variant_slice.len() / mem::size_of::<IndexItem>();
                return Ok(Some(slice::from_raw_parts(
                    mem::transmute(data.as_ptr()),
                    count
                )));
            }
        }
        Ok(None)
    }

    #[inline(always)]
    fn symbols(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.symbols_start as usize, head.symbols_count as usize)
    }

    #[inline(always)]
    fn object_names(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.object_names_start as usize,
                               head.object_names_count as usize)
    }

    #[inline(always)]
    fn get_string(&'a self, slice: &StoredSlice) -> Result<Cow<'a, str>> {
        let bytes = self.backing.get_data(slice.offset(), slice.len())?;
        if slice.is_compressed() {
            panic!("We do not support compression");
        } else {
            Ok(Cow::Borrowed(from_utf8(bytes)?))
        }
    }

    fn get_object_name(&'a self, src_id: usize) -> Result<Cow<'a, str>> {
        self.get_string(&self.object_names()?[src_id])
    }

    fn get_symbol(&'a self, sym_id: usize) -> Result<Cow<'a, str>> {
        self.get_string(&self.symbols()?[sym_id])
    }

    fn index_item_to_symbol(&'a self, ii: &IndexItem, uuid: &Uuid) -> Result<Symbol<'a>> {
        Ok(Symbol {
            object_uuid: uuid.clone(),
            object_name: self.get_object_name(ii.src_id())?,
            symbol: self.get_symbol(ii.sym_id())?,
            addr: ii.addr(),
        })
    }
}
<commit_msg>Require exact uuid matches<commit_after>//! This module implements the in-memory database
//!
//! A support folder with SDK debug symbols can be processed into a
//! in-memory database format which is a flat file on the file system
//! that gets mmaped into the process.
use std::str::from_utf8;
use std::mem;
use std::slice;
use std::path::Path;
use std::borrow::Cow;
use std::ffi::CStr;
use std::os::raw::c_char;

use std::fmt;
use uuid::Uuid;
use memmap::{Mmap, Protection};

use super::types::{IndexItem, StoredSlice, MemDbHeader, IndexedUuid};
use super::super::{Result, ErrorKind};
use super::super::sdk::SdkInfo;
use super::super::utils::binsearch_by_key;

enum Backing<'a> {
    Buf(Cow<'a, [u8]>),
    Mmap(Mmap),
}

/// Provides access to a memdb file
pub struct MemDb<'a> {
    info: SdkInfo,
    backing: Backing<'a>
}

/// Represents a symbol from a memdb file.
#[derive(Debug)]
pub struct Symbol<'a> {
    object_uuid: Uuid,
    object_name: Cow<'a, str>,
    symbol: Cow<'a, str>,
    addr: u64,
}

/// Represents a symbol iterator
pub struct SymbolIter<'a> {
    memdb: &'a MemDb<'a>,
    uuid: &'a Uuid,
    index: &'a [IndexItem],
    pos: usize,
}

impl<'a> Iterator for SymbolIter<'a> {
    type Item = Result<Symbol<'a>>;

    fn next(&mut self) -> Option<Result<Symbol<'a>>> {
        if self.pos < self.index.len() {
            let ii = &self.index[self.pos];
            self.pos += 1;
            Some(self.memdb.index_item_to_symbol(ii, self.uuid))
        } else {
            None
        }
    }
}

impl<'a> fmt::Display for Symbol<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:016x} {} ({})", self.addr(), self.symbol(), self.object_name())
    }
}

impl<'a> Backing<'a> {

    fn get_data(&self, start: usize, len: usize) -> Result<&[u8]> {
        let buffer = self.buffer();
        let end = start.wrapping_add(len);
        if end < start || end > buffer.len() {
            Err(ErrorKind::BadMemDb.into())
        } else {
            Ok(&buffer[start..end])
        }
    }

    fn get_slice<T>(&self, offset: usize, count: usize) -> Result<&[T]> {
        let size = mem::size_of::<T>();
        Ok(unsafe {
            slice::from_raw_parts(
                mem::transmute(self.get_data(offset, count * size)?.as_ptr()),
                count
            )
        })
    }

    #[inline(always)]
    fn header(&self) -> Result<&MemDbHeader> {
        unsafe {
            Ok(mem::transmute(self.get_data(0, mem::size_of::<MemDbHeader>())?.as_ptr()))
        }
    }

    #[inline(always)]
    fn buffer(&self) -> &[u8] {
        match *self {
            Backing::Buf(ref buf) => buf,
            Backing::Mmap(ref mmap) => unsafe { mmap.as_slice() }
        }
    }
}

impl<'a> Symbol<'a> {

    /// The uuid of the image
    pub fn object_uuid(&self) -> Uuid {
        self.object_uuid.clone()
    }

    /// The object name a string
    pub fn object_name(&self) -> &str {
        return &self.object_name
    }

    /// The symbol as string
    pub fn symbol(&self) -> &str {
        return &self.symbol
    }

    /// The symbol address as u64
    pub fn addr(&self) -> u64 {
        self.addr
    }
}

fn load_memdb<'a>(backing: Backing<'a>) -> Result<MemDb<'a>> {
    let info = {
        let header = backing.header()?;
        if header.version != 1 {
            return Err(ErrorKind::UnsupportedMemDbVersion.into());
        }
        header.sdk_info.to_sdk_info()
    };
    Ok(MemDb {
        backing: backing,
        info: info,
    })
}

impl<'a> MemDb<'a> {

    /// Constructs a memdb object from a byte slice cow.
    pub fn from_cow(cow: Cow<'a, [u8]>) -> Result<MemDb<'a>> {
        load_memdb(Backing::Buf(cow))
    }

    /// Constructs a memdb object from a byte slice.
    pub fn from_slice(buffer: &'a [u8]) -> Result<MemDb<'a>> {
        MemDb::from_cow(Cow::Borrowed(buffer))
    }

    /// Constructs a memdb object from a byte vector.
    pub fn from_vec(buffer: Vec<u8>) -> Result<MemDb<'a>> {
        MemDb::from_cow(Cow::Owned(buffer))
    }

    /// Constructs a memdb object by mmapping a file from the filesystem in.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<MemDb<'a>> {
        let mmap = Mmap::open_path(path, Protection::Read)?;
        load_memdb(Backing::Mmap(mmap))
    }

    /// Return the SDK info.
    pub fn info(&self) -> &SdkInfo {
        &self.info
    }

    /// Finds a symbol by UUID and address.
    pub fn lookup_by_uuid(&'a self, uuid: &Uuid, addr: u64) -> Option<Symbol<'a>> {
        self.lookup_impl(uuid, addr).ok().and_then(|x| x)
    }

    /// Finds a symbol by object name and architecture
    pub fn lookup_by_object_name(&'a self, object_name: &str, arch: &str, addr: u64)
        -> Option<Symbol<'a>>
    {
        if let Ok(Some(uuid)) = self.find_uuid(object_name, arch) {
            self.lookup_impl(uuid, addr).ok().and_then(|x| x)
        } else {
            None
        }
    }

    /// Given an object namd and architecture this finds the image UUID in the file.
    pub fn find_uuid(&self, object_name: &str, arch: &str) -> Result<Option<&Uuid>> {
        let header = self.backing.header()?;
        let mut offset = header.tagged_object_names_start as usize;
        let refstr = format!("{}:{}", object_name, arch);
        let mut uuid_idx = 0;
        while offset < header.tagged_object_names_end as usize {
            let s = self.get_cstr(offset)?;
            if s == &refstr {
                return Ok(Some(&self.uuids()?[uuid_idx].uuid));
            }
            offset += s.len() + 1;
            uuid_idx += 1;
        }
        Ok(None)
    }

    /// Given object name and architecture or UUID as string, this finds the
    /// UUID in the file.
    pub fn find_uuid_fuzzy(&self, name_or_uuid: &str) -> Result<Option<&Uuid>> {
        if let Ok(parsed_uuid) = name_or_uuid.parse::<Uuid>() {
            let uuids = self.uuids()?;
            if let Some(item) = binsearch_by_key(uuids, parsed_uuid, |item| *item.uuid()) {
                return Ok(Some(item.uuid()));
            }
            return Ok(None)
        }
        let mut parts = name_or_uuid.rsplitn(2, ':');
        if_chain! {
            if let Some(arch) = parts.next();
            if let Some(name) = parts.next();
            if let Some(uuid) = self.find_uuid(name, arch)?;
            then {
                Ok(Some(uuid))
            } else {
                Ok(None)
            }
        }
    }

    /// Returns the symbols for an Uuid
    pub fn iter_symbols(&'a self, uuid: &'a Uuid) -> Result<SymbolIter<'a>> {
        let index = self.get_index(uuid)?.unwrap_or(&[][..]);
        Ok(SymbolIter {
            memdb: self,
            uuid: uuid,
            index: index,
            pos: 0,
        })
    }

    fn get_cstr(&self, offset: usize) -> Result<&str> {
        unsafe {
            Ok(from_utf8(CStr::from_ptr(self.backing.buffer().as_ptr().offset(
                offset as isize) as *const c_char).to_bytes())?)
        }
    }

    fn lookup_impl(&'a self, uuid: &Uuid, addr: u64) -> Result<Option<Symbol<'a>>>
    {
        if let Some(index) = self.get_index(uuid)? {
            if let Some(item) = binsearch_by_key(index, addr, |item| item.addr()) {
                return Ok(Some(self.index_item_to_symbol(item, uuid)?));
            }
        }
        Ok(None)
    }

    #[inline(always)]
    fn uuids(&self) -> Result<&[IndexedUuid]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.uuids_start as usize, head.uuids_count as usize)
    }

    #[inline(always)]
    fn variants(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.variants_start as usize, head.variants_count as usize)
    }

    #[inline(always)]
    fn get_index(&self, uuid: &Uuid) -> Result<Option<&[IndexItem]>> {
        let uuids = self.uuids()?;
        if let Some(iuuid) = binsearch_by_key(uuids, *uuid, |item| *item.uuid()) {
            // only consider exact matches
            if iuuid.uuid() != uuid {
                return Ok(None);
            }
            let variant_slice = &self.variants()?[iuuid.idx()];
            unsafe {
                let data = self.backing.get_data(variant_slice.offset(),
                                                 variant_slice.len())?;
                let count = variant_slice.len() / mem::size_of::<IndexItem>();
                return Ok(Some(slice::from_raw_parts(
                    mem::transmute(data.as_ptr()),
                    count
                )));
            }
        }
        Ok(None)
    }

    #[inline(always)]
    fn symbols(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.symbols_start as usize, head.symbols_count as usize)
    }

    #[inline(always)]
    fn object_names(&self) -> Result<&[StoredSlice]> {
        let head = self.backing.header()?;
        self.backing.get_slice(head.object_names_start as usize,
                               head.object_names_count as usize)
    }

    #[inline(always)]
    fn get_string(&'a self, slice: &StoredSlice) -> Result<Cow<'a, str>> {
        let bytes = self.backing.get_data(slice.offset(), slice.len())?;
        if slice.is_compressed() {
            panic!("We do not support compression");
        } else {
            Ok(Cow::Borrowed(from_utf8(bytes)?))
        }
    }

    fn get_object_name(&'a self, src_id: usize) -> Result<Cow<'a, str>> {
        self.get_string(&self.object_names()?[src_id])
    }

    fn get_symbol(&'a self, sym_id: usize) -> Result<Cow<'a, str>> {
        self.get_string(&self.symbols()?[sym_id])
    }

    fn index_item_to_symbol(&'a self, ii: &IndexItem, uuid: &Uuid) -> Result<Symbol<'a>> {
        Ok(Symbol {
            object_uuid: uuid.clone(),
            object_name: self.get_object_name(ii.src_id())?,
            symbol: self.get_symbol(ii.sym_id())?,
            addr: ii.addr(),
        })
    }
}
<|endoftext|>


<commit_before>/**
 * 4.2 Pattern matching
 * http://static.rust-lang.org/doc/master/tutorial.html#pattern-matching
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */
extern crate rand;
use rand::{task_rng, Rng};
use std::f64;
use std::num::atan;

struct Point { x: f64, y: f64 }

fn angle(vector: (f64, f64)) -> f64 {
	let pi = f64::consts::PI;
	/*
	 * A powerful application of pattern matching is destructuring:
	 * matching in order to bind names to the contents of data types.
	 */
	match vector {
		(0.0, y) if y < 0.0 => 1.5 * pi,
		(0.0, _) => 0.5 * pi,
		(x, y) => (y / x).atan()
	}
}
fn main() {
	let mut rng = task_rng();
	let my_number: uint = rng.gen_range(0u, 10);
	println!("my_number = {}", my_number);

	/*
	 * Rust's match construct is a generalized, cleaned-up version of C's
	 * switch construct. You provide it with a value and a number of arms,
	 * each labelled with a pattern, and the code compares the value
	 * against each pattern in order until one matches. The matching
	 * pattern executes its corresponding arm.
	 */
	match my_number {
		0     => println!("zero"),
		1 | 2 => println!("one or two"),
		3..10 => println!("three to ten"),
		_     => println!("something else")
	}
	/*
	 * match constructs must be exhaustive: they must have an arm covering
	 * every possible case. For example, the typechecker would reject the
	 * previous example if the arm with the wildcard pattern was omitted.
	 */
	match my_number {
		0 => { println!("zero") }
		_ => { println!("something else") }
	}

	let age: uint = rng.gen_range(0u, 100);
	println!("age = {}", age);
	match age {
		a @ 0..20 => println!("{} years old", a),
		_ => println!("older than 21")
	}

	let vector = (1f64,1f64);
	println!("angle({:?}) == {:?}", vector, angle(vector));

	/*
	 * To destructure a struct, use `..`.
	 * http://static.rust-lang.org/doc/master/tutorial.html#structs
	 */
	let mypoint = Point { x: 0.0, y: 0.0 };
	match mypoint {
		Point { x, .. } => println!("{}", x),
	}
}
<commit_msg>tutorial-04_2-pattern-matching.rs : remove 'warning: unused import'<commit_after>/**
 * 4.2 Pattern matching
 * http://static.rust-lang.org/doc/master/tutorial.html#pattern-matching
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */
extern crate rand;
use rand::{task_rng, Rng};
use std::f64;

struct Point { x: f64, y: f64 }

fn angle(vector: (f64, f64)) -> f64 {
	let pi = f64::consts::PI;
	/*
	 * A powerful application of pattern matching is destructuring:
	 * matching in order to bind names to the contents of data types.
	 */
	match vector {
		(0.0, y) if y < 0.0 => 1.5 * pi,
		(0.0, _) => 0.5 * pi,
		(x, y) => (y / x).atan()
	}
}
fn main() {
	let mut rng = task_rng();
	let my_number: uint = rng.gen_range(0u, 10);
	println!("my_number = {}", my_number);

	/*
	 * Rust's match construct is a generalized, cleaned-up version of C's
	 * switch construct. You provide it with a value and a number of arms,
	 * each labelled with a pattern, and the code compares the value
	 * against each pattern in order until one matches. The matching
	 * pattern executes its corresponding arm.
	 */
	match my_number {
		0     => println!("zero"),
		1 | 2 => println!("one or two"),
		3..10 => println!("three to ten"),
		_     => println!("something else")
	}
	/*
	 * match constructs must be exhaustive: they must have an arm covering
	 * every possible case. For example, the typechecker would reject the
	 * previous example if the arm with the wildcard pattern was omitted.
	 */
	match my_number {
		0 => { println!("zero") }
		_ => { println!("something else") }
	}

	let age: uint = rng.gen_range(0u, 100);
	println!("age = {}", age);
	match age {
		a @ 0..20 => println!("{} years old", a),
		_ => println!("older than 21")
	}

	let vector = (1f64,1f64);
	println!("angle({:?}) == {:?}", vector, angle(vector));

	/*
	 * To destructure a struct, use `..`.
	 * http://static.rust-lang.org/doc/master/tutorial.html#structs
	 */
	let mypoint = Point { x: 0.0, y: 0.0 };
	match mypoint {
		Point { x, .. } => println!("{}", x),
	}
}
<|endoftext|>