<commit_before>use crate::loom::sync::atomic::AtomicUsize;

use std::fmt;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
use std::usize;

pub(super) struct State {
    val: AtomicUsize,
}

/// Current state value
#[derive(Copy, Clone)]
pub(super) struct Snapshot(usize);

/// The task is currently being run.
const RUNNING: usize = 0b00_0001;

/// The task has been notified by a waker.
const NOTIFIED: usize = 0b00_0010;

/// The task is complete.
///
/// Once this bit is set, it is never unset
const COMPLETE: usize = 0b00_0100;

/// The primary task handle has been dropped.
const RELEASED: usize = 0b00_1000;

/// The join handle is still around
const JOIN_INTEREST: usize = 0b01_0000;

/// A join handle waker has been set
const JOIN_WAKER: usize = 0b10_0000;

/// The task has been forcibly canceled.
const CANCELLED: usize = 0b100_0000;

/// All bits
const LIFECYCLE_MASK: usize =
    RUNNING | NOTIFIED | COMPLETE | RELEASED | JOIN_INTEREST | JOIN_WAKER | CANCELLED;

/// Bits used by the waker ref count portion of the state.
///
/// Ref counts only cover **wakers**. Other handles are tracked with other state
/// bits.
const WAKER_COUNT_MASK: usize = usize::MAX - LIFECYCLE_MASK;

/// Number of positions to shift the ref count
const WAKER_COUNT_SHIFT: usize = WAKER_COUNT_MASK.count_zeros() as usize;

/// One ref count
const WAKER_ONE: usize = 1 << WAKER_COUNT_SHIFT;

/// Initial state
const INITIAL_STATE: usize = NOTIFIED;

/// All transitions are performed via RMW operations. This establishes an
/// unambiguous modification order.
impl State {
    /// Starts with a ref count of 2
    pub(super) fn new_joinable() -> State {
        State {
            val: AtomicUsize::new(INITIAL_STATE | JOIN_INTEREST),
        }
    }

    /// Loads the current state, establishes `Acquire` ordering.
    pub(super) fn load(&self) -> Snapshot {
        Snapshot(self.val.load(Acquire))
    }

    /// Transitions a task to the `Running` state.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn transition_to_running(&self) -> Snapshot {
        const DELTA: usize = RUNNING | NOTIFIED;

        let prev = Snapshot(self.val.fetch_xor(DELTA, Acquire));
        debug_assert!(prev.is_notified());

        if prev.is_running() {
            // We were signalled to cancel
            //
            // Apply the state
            let prev = self.val.fetch_or(CANCELLED, AcqRel);
            return Snapshot(prev | CANCELLED);
        }

        debug_assert!(!prev.is_running());

        let next = Snapshot(prev.0 ^ DELTA);

        debug_assert!(next.is_running());
        debug_assert!(!next.is_notified());

        next
    }

    /// Transitions the task from `Running` -> `Idle`.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn transition_to_idle(&self) -> Snapshot {
        const DELTA: usize = RUNNING;

        let prev = Snapshot(self.val.fetch_xor(DELTA, AcqRel));

        if !prev.is_running() {
            // We were signaled to cancel.
            //
            // Apply the state
            let prev = self.val.fetch_or(CANCELLED, AcqRel);
            return Snapshot(prev | CANCELLED);
        }

        let next = Snapshot(prev.0 ^ DELTA);

        debug_assert!(!next.is_running());

        next
    }

    /// Transitions the task from `Running` -> `Complete`.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn transition_to_complete(&self) -> Snapshot {
        const DELTA: usize = RUNNING | COMPLETE;

        let prev = Snapshot(self.val.fetch_xor(DELTA, AcqRel));

        debug_assert!(!prev.is_complete());

        let next = Snapshot(prev.0 ^ DELTA);

        debug_assert!(next.is_complete());

        next
    }

    /// Transitions the task from `Running` -> `Released`.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn transition_to_released(&self) -> Snapshot {
        const DELTA: usize = RUNNING | COMPLETE | RELEASED;

        let prev = Snapshot(self.val.fetch_xor(DELTA, AcqRel));

        debug_assert!(prev.is_running());
        debug_assert!(!prev.is_complete());
        debug_assert!(!prev.is_released());

        let next = Snapshot(prev.0 ^ DELTA);

        debug_assert!(!next.is_running());
        debug_assert!(next.is_complete());
        debug_assert!(next.is_released());

        next
    }

    /// Transitions the task to the canceled state.
    ///
    /// Returns the snapshot of the state **after** the transition **if** the
    /// transition was made successfully
    ///
    /// # States
    ///
    /// - Notifed: task may be in a queue, caller must not release.
    /// - Running: cannot drop. The poll handle will handle releasing.
    /// - Other prior states do not require cancellation.
    ///
    /// If the task has been notified, then it may still be in a queue. The
    /// caller must not release the task.
    pub(super) fn transition_to_canceled_from_queue(&self) -> Snapshot {
        let prev = Snapshot(self.val.fetch_or(CANCELLED, AcqRel));

        debug_assert!(!prev.is_complete());
        debug_assert!(!prev.is_running() || prev.is_notified());

        Snapshot(prev.0 | CANCELLED)
    }

    pub(super) fn transition_to_canceled_from_list(&self) -> Option<Snapshot> {
        let mut prev = self.load();

        loop {
            if !prev.is_active() {
                return None;
            }

            let mut next = prev;

            // Use the running flag to signal cancellation
            if prev.is_running() {
                next.0 -= RUNNING;
                next.0 |= NOTIFIED;
            } else if prev.is_notified() {
                next.0 += RUNNING;
                next.0 |= NOTIFIED;
            } else {
                next.0 |= CANCELLED;
            }

            let res = self.val.compare_exchange(prev.0, next.0, AcqRel, Acquire);

            match res {
                Ok(_) if next.is_canceled() => return Some(next),
                Ok(_) => return None,
                Err(actual) => {
                    prev = Snapshot(actual);
                }
            }
        }
    }

    /// Transitions to `Released`. Called when primary task handle is
    /// dropped. This is roughly a "ref decrement" operation.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn release_task(&self) -> Snapshot {
        use crate::loom::sync::atomic;

        const DELTA: usize = RELEASED;

        let prev = Snapshot(self.val.fetch_or(DELTA, Release));

        debug_assert!(!prev.is_released());
        debug_assert!(prev.is_terminal(), "state = {:?}", prev);

        let next = Snapshot(prev.0 | DELTA);

        debug_assert!(next.is_released());

        if next.is_final_ref() || (next.has_join_waker() && !next.is_join_interested()) {
            // The final reference to the task was dropped, the caller must free the
            // memory. Establish an acquire ordering.
            atomic::fence(Acquire);
        }

        next
    }

    /// Transitions the state to `Scheduled`.
    ///
    /// Returns `true` if the task needs to be submitted to the pool for
    /// execution
    pub(super) fn transition_to_notified(&self) -> bool {
        const MASK: usize = RUNNING | NOTIFIED | COMPLETE | CANCELLED;

        let prev = self.val.fetch_or(NOTIFIED, Release);
        prev & MASK == 0
    }

    /// Optimistically tries to swap the state assuming the join handle is
    /// __immediately__ dropped on spawn
    pub(super) fn drop_join_handle_fast(&self) -> bool {
        use std::sync::atomic::Ordering::Relaxed;

        // Relaxed is acceptable as if this function is called and succeeds,
        // then nothing has been done w/ the join handle.
        //
        // The moment the join handle is used (polled), the `JOIN_WAKER` flag is
        // set, at which point the CAS will fail.
        //
        // Given this, there is no risk if this operation is reordered.
        self.val
            .compare_exchange_weak(
                INITIAL_STATE | JOIN_INTEREST,
                INITIAL_STATE,
                Release,
                Relaxed,
            )
            .is_ok()
    }

    /// The join handle has completed by reading the output.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn complete_join_handle(&self) -> Snapshot {
        use crate::loom::sync::atomic;

        const DELTA: usize = JOIN_INTEREST;

        let prev = Snapshot(self.val.fetch_sub(DELTA, Release));

        debug_assert!(prev.is_join_interested());

        let next = Snapshot(prev.0 - DELTA);

        if !next.is_final_ref() {
            return next;
        }

        atomic::fence(Acquire);

        next
    }

    /// The join handle is being dropped, this fails if the task has been
    /// completed and the output must be dropped first then
    /// `complete_join_handle` should be called.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn drop_join_handle_slow(&self) -> Result<Snapshot, Snapshot> {
        const MASK: usize = COMPLETE | CANCELLED;

        let mut prev = self.val.load(Acquire);

        loop {
            // Once the complete bit is set, it is never unset.
            if prev & MASK != 0 {
                return Err(Snapshot(prev));
            }

            debug_assert!(prev & JOIN_INTEREST == JOIN_INTEREST);

            let next = (prev - JOIN_INTEREST) & !JOIN_WAKER;

            let res = self.val.compare_exchange(prev, next, AcqRel, Acquire);

            match res {
                Ok(_) => {
                    return Ok(Snapshot(next));
                }
                Err(actual) => {
                    prev = actual;
                }
            }
        }
    }

    /// Stores the join waker.
    pub(super) fn store_join_waker(&self) -> Snapshot {
        use crate::loom::sync::atomic;

        const DELTA: usize = JOIN_WAKER;

        let prev = Snapshot(self.val.fetch_xor(DELTA, Release));

        debug_assert!(!prev.has_join_waker());

        let next = Snapshot(prev.0 ^ DELTA);

        debug_assert!(next.has_join_waker());

        if next.is_complete() {
            atomic::fence(Acquire);
        }

        next
    }

    pub(super) fn unset_waker(&self) -> Snapshot {
        const MASK: usize = COMPLETE | CANCELLED;

        let mut prev = self.val.load(Acquire);

        loop {
            // Once the `COMPLETE` bit is set, it is never unset
            if prev & MASK != 0 {
                return Snapshot(prev);
            }

            debug_assert!(Snapshot(prev).has_join_waker());

            let next = prev - JOIN_WAKER;

            let res = self.val.compare_exchange(prev, next, AcqRel, Acquire);

            match res {
                Ok(_) => return Snapshot(next),
                Err(actual) => {
                    prev = actual;
                }
            }
        }
    }

    pub(super) fn ref_inc(&self) {
        use std::process;
        use std::sync::atomic::Ordering::Relaxed;

        // Using a relaxed ordering is alright here, as knowledge of the
        // original reference prevents other threads from erroneously deleting
        // the object.
        //
        // As explained in the [Boost documentation][1], Increasing the
        // reference counter can always be done with memory_order_relaxed: New
        // references to an object can only be formed from an existing
        // reference, and passing an existing reference from one thread to
        // another must already provide any required synchronization.
        //
        // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
        let prev = self.val.fetch_add(WAKER_ONE, Relaxed);

        // If the reference count overflowed, abort.
        if prev > isize::max_value() as usize {
            process::abort();
        }
    }

    /// Returns `true` if the task should be released.
    pub(super) fn ref_dec(&self) -> bool {
        use crate::loom::sync::atomic;

        let prev = self.val.fetch_sub(WAKER_ONE, Release);
        let next = Snapshot(prev - WAKER_ONE);

        if next.is_final_ref() {
            atomic::fence(Acquire);
        }

        next.is_final_ref()
    }
}

impl Snapshot {
    pub(super) fn is_running(self) -> bool {
        self.0 & RUNNING == RUNNING
    }

    pub(super) fn is_notified(self) -> bool {
        self.0 & NOTIFIED == NOTIFIED
    }

    pub(super) fn is_released(self) -> bool {
        self.0 & RELEASED == RELEASED
    }

    pub(super) fn is_complete(self) -> bool {
        self.0 & COMPLETE == COMPLETE
    }

    pub(super) fn is_canceled(self) -> bool {
        self.0 & CANCELLED == CANCELLED
    }

    /// Used during normal runtime.
    pub(super) fn is_active(self) -> bool {
        self.0 & (COMPLETE | CANCELLED) == 0
    }

    /// Used before dropping the task
    pub(super) fn is_terminal(self) -> bool {
        // When both the notified & running flags are set, the task was canceled
        // after being notified, before it was run.
        //
        // There is a race where:
        // - The task state transitions to notified
        // - The global queue is shutdown
        // - The waker attempts to push into the global queue and fails.
        // - The waker holds the last reference to the task, thus drops it.
        //
        // In this scenario, the cancelled bit will never get set.
        !self.is_active() || (self.is_notified() && self.is_running())
    }

    pub(super) fn is_join_interested(self) -> bool {
        self.0 & JOIN_INTEREST == JOIN_INTEREST
    }

    pub(super) fn has_join_waker(self) -> bool {
        self.0 & JOIN_WAKER == JOIN_WAKER
    }

    pub(super) fn is_final_ref(self) -> bool {
        const MASK: usize = WAKER_COUNT_MASK | RELEASED | JOIN_INTEREST;

        (self.0 & MASK) == RELEASED
    }
}

impl fmt::Debug for State {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        use std::sync::atomic::Ordering::SeqCst;

        let snapshot = Snapshot(self.val.load(SeqCst));

        fmt.debug_struct("State")
            .field("snapshot", &snapshot)
            .finish()
    }
}

impl fmt::Debug for Snapshot {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.debug_struct("Snapshot")
            .field("is_running", &self.is_running())
            .field("is_notified", &self.is_notified())
            .field("is_released", &self.is_released())
            .field("is_complete", &self.is_complete())
            .field("is_canceled", &self.is_canceled())
            .field("is_join_interested", &self.is_join_interested())
            .field("has_join_waker", &self.has_join_waker())
            .field("is_final_ref", &self.is_final_ref())
            .finish()
    }
}
<commit_msg>rt: enable task state assertions under loom (#2192)<commit_after>use crate::loom::sync::atomic::AtomicUsize;

use std::fmt;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
use std::usize;

pub(super) struct State {
    val: AtomicUsize,
}

/// Current state value
#[derive(Copy, Clone)]
pub(super) struct Snapshot(usize);

/// The task is currently being run.
const RUNNING: usize = 0b00_0001;

/// The task has been notified by a waker.
const NOTIFIED: usize = 0b00_0010;

/// The task is complete.
///
/// Once this bit is set, it is never unset
const COMPLETE: usize = 0b00_0100;

/// The primary task handle has been dropped.
const RELEASED: usize = 0b00_1000;

/// The join handle is still around
const JOIN_INTEREST: usize = 0b01_0000;

/// A join handle waker has been set
const JOIN_WAKER: usize = 0b10_0000;

/// The task has been forcibly canceled.
const CANCELLED: usize = 0b100_0000;

/// All bits
const LIFECYCLE_MASK: usize =
    RUNNING | NOTIFIED | COMPLETE | RELEASED | JOIN_INTEREST | JOIN_WAKER | CANCELLED;

/// Bits used by the waker ref count portion of the state.
///
/// Ref counts only cover **wakers**. Other handles are tracked with other state
/// bits.
const WAKER_COUNT_MASK: usize = usize::MAX - LIFECYCLE_MASK;

/// Number of positions to shift the ref count
const WAKER_COUNT_SHIFT: usize = WAKER_COUNT_MASK.count_zeros() as usize;

/// One ref count
const WAKER_ONE: usize = 1 << WAKER_COUNT_SHIFT;

/// Initial state
const INITIAL_STATE: usize = NOTIFIED;

/// All transitions are performed via RMW operations. This establishes an
/// unambiguous modification order.
impl State {
    /// Starts with a ref count of 2
    pub(super) fn new_joinable() -> State {
        State {
            val: AtomicUsize::new(INITIAL_STATE | JOIN_INTEREST),
        }
    }

    /// Loads the current state, establishes `Acquire` ordering.
    pub(super) fn load(&self) -> Snapshot {
        Snapshot(self.val.load(Acquire))
    }

    /// Transitions a task to the `Running` state.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn transition_to_running(&self) -> Snapshot {
        const DELTA: usize = RUNNING | NOTIFIED;

        let prev = Snapshot(self.val.fetch_xor(DELTA, Acquire));
        assert!(prev.is_notified());

        if prev.is_running() {
            // We were signalled to cancel
            //
            // Apply the state
            let prev = self.val.fetch_or(CANCELLED, AcqRel);
            return Snapshot(prev | CANCELLED);
        }

        assert!(!prev.is_running());

        let next = Snapshot(prev.0 ^ DELTA);

        assert!(next.is_running());
        assert!(!next.is_notified());

        next
    }

    /// Transitions the task from `Running` -> `Idle`.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn transition_to_idle(&self) -> Snapshot {
        const DELTA: usize = RUNNING;

        let prev = Snapshot(self.val.fetch_xor(DELTA, AcqRel));

        if !prev.is_running() {
            // We were signaled to cancel.
            //
            // Apply the state
            let prev = self.val.fetch_or(CANCELLED, AcqRel);
            return Snapshot(prev | CANCELLED);
        }

        let next = Snapshot(prev.0 ^ DELTA);

        assert!(!next.is_running());

        next
    }

    /// Transitions the task from `Running` -> `Complete`.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn transition_to_complete(&self) -> Snapshot {
        const DELTA: usize = RUNNING | COMPLETE;

        let prev = Snapshot(self.val.fetch_xor(DELTA, AcqRel));

        assert!(!prev.is_complete());

        let next = Snapshot(prev.0 ^ DELTA);

        assert!(next.is_complete());

        next
    }

    /// Transitions the task from `Running` -> `Released`.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn transition_to_released(&self) -> Snapshot {
        const DELTA: usize = RUNNING | COMPLETE | RELEASED;

        let prev = Snapshot(self.val.fetch_xor(DELTA, AcqRel));

        assert!(prev.is_running());
        assert!(!prev.is_complete());
        assert!(!prev.is_released());

        let next = Snapshot(prev.0 ^ DELTA);

        assert!(!next.is_running());
        assert!(next.is_complete());
        assert!(next.is_released());

        next
    }

    /// Transitions the task to the canceled state.
    ///
    /// Returns the snapshot of the state **after** the transition **if** the
    /// transition was made successfully
    ///
    /// # States
    ///
    /// - Notifed: task may be in a queue, caller must not release.
    /// - Running: cannot drop. The poll handle will handle releasing.
    /// - Other prior states do not require cancellation.
    ///
    /// If the task has been notified, then it may still be in a queue. The
    /// caller must not release the task.
    pub(super) fn transition_to_canceled_from_queue(&self) -> Snapshot {
        let prev = Snapshot(self.val.fetch_or(CANCELLED, AcqRel));

        assert!(!prev.is_complete());
        assert!(!prev.is_running() || prev.is_notified());

        Snapshot(prev.0 | CANCELLED)
    }

    pub(super) fn transition_to_canceled_from_list(&self) -> Option<Snapshot> {
        let mut prev = self.load();

        loop {
            if !prev.is_active() {
                return None;
            }

            let mut next = prev;

            // Use the running flag to signal cancellation
            if prev.is_running() {
                next.0 -= RUNNING;
                next.0 |= NOTIFIED;
            } else if prev.is_notified() {
                next.0 += RUNNING;
                next.0 |= NOTIFIED;
            } else {
                next.0 |= CANCELLED;
            }

            let res = self.val.compare_exchange(prev.0, next.0, AcqRel, Acquire);

            match res {
                Ok(_) if next.is_canceled() => return Some(next),
                Ok(_) => return None,
                Err(actual) => {
                    prev = Snapshot(actual);
                }
            }
        }
    }

    /// Transitions to `Released`. Called when primary task handle is
    /// dropped. This is roughly a "ref decrement" operation.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn release_task(&self) -> Snapshot {
        use crate::loom::sync::atomic;

        const DELTA: usize = RELEASED;

        let prev = Snapshot(self.val.fetch_or(DELTA, Release));

        assert!(!prev.is_released());
        assert!(prev.is_terminal(), "state = {:?}", prev);

        let next = Snapshot(prev.0 | DELTA);

        assert!(next.is_released());

        if next.is_final_ref() || (next.has_join_waker() && !next.is_join_interested()) {
            // The final reference to the task was dropped, the caller must free the
            // memory. Establish an acquire ordering.
            atomic::fence(Acquire);
        }

        next
    }

    /// Transitions the state to `Scheduled`.
    ///
    /// Returns `true` if the task needs to be submitted to the pool for
    /// execution
    pub(super) fn transition_to_notified(&self) -> bool {
        const MASK: usize = RUNNING | NOTIFIED | COMPLETE | CANCELLED;

        let prev = self.val.fetch_or(NOTIFIED, Release);
        prev & MASK == 0
    }

    /// Optimistically tries to swap the state assuming the join handle is
    /// __immediately__ dropped on spawn
    pub(super) fn drop_join_handle_fast(&self) -> bool {
        use std::sync::atomic::Ordering::Relaxed;

        // Relaxed is acceptable as if this function is called and succeeds,
        // then nothing has been done w/ the join handle.
        //
        // The moment the join handle is used (polled), the `JOIN_WAKER` flag is
        // set, at which point the CAS will fail.
        //
        // Given this, there is no risk if this operation is reordered.
        self.val
            .compare_exchange_weak(
                INITIAL_STATE | JOIN_INTEREST,
                INITIAL_STATE,
                Release,
                Relaxed,
            )
            .is_ok()
    }

    /// The join handle has completed by reading the output.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn complete_join_handle(&self) -> Snapshot {
        use crate::loom::sync::atomic;

        const DELTA: usize = JOIN_INTEREST;

        let prev = Snapshot(self.val.fetch_sub(DELTA, Release));

        assert!(prev.is_join_interested());

        let next = Snapshot(prev.0 - DELTA);

        if !next.is_final_ref() {
            return next;
        }

        atomic::fence(Acquire);

        next
    }

    /// The join handle is being dropped, this fails if the task has been
    /// completed and the output must be dropped first then
    /// `complete_join_handle` should be called.
    ///
    /// Returns a snapshot of the state **after** the transition.
    pub(super) fn drop_join_handle_slow(&self) -> Result<Snapshot, Snapshot> {
        const MASK: usize = COMPLETE | CANCELLED;

        let mut prev = self.val.load(Acquire);

        loop {
            // Once the complete bit is set, it is never unset.
            if prev & MASK != 0 {
                return Err(Snapshot(prev));
            }

            assert!(prev & JOIN_INTEREST == JOIN_INTEREST);

            let next = (prev - JOIN_INTEREST) & !JOIN_WAKER;

            let res = self.val.compare_exchange(prev, next, AcqRel, Acquire);

            match res {
                Ok(_) => {
                    return Ok(Snapshot(next));
                }
                Err(actual) => {
                    prev = actual;
                }
            }
        }
    }

    /// Stores the join waker.
    pub(super) fn store_join_waker(&self) -> Snapshot {
        use crate::loom::sync::atomic;

        const DELTA: usize = JOIN_WAKER;

        let prev = Snapshot(self.val.fetch_xor(DELTA, Release));

        assert!(!prev.has_join_waker());

        let next = Snapshot(prev.0 ^ DELTA);

        assert!(next.has_join_waker());

        if next.is_complete() {
            atomic::fence(Acquire);
        }

        next
    }

    pub(super) fn unset_waker(&self) -> Snapshot {
        const MASK: usize = COMPLETE | CANCELLED;

        let mut prev = self.val.load(Acquire);

        loop {
            // Once the `COMPLETE` bit is set, it is never unset
            if prev & MASK != 0 {
                return Snapshot(prev);
            }

            assert!(Snapshot(prev).has_join_waker());

            let next = prev - JOIN_WAKER;

            let res = self.val.compare_exchange(prev, next, AcqRel, Acquire);

            match res {
                Ok(_) => return Snapshot(next),
                Err(actual) => {
                    prev = actual;
                }
            }
        }
    }

    pub(super) fn ref_inc(&self) {
        use std::process;
        use std::sync::atomic::Ordering::Relaxed;

        // Using a relaxed ordering is alright here, as knowledge of the
        // original reference prevents other threads from erroneously deleting
        // the object.
        //
        // As explained in the [Boost documentation][1], Increasing the
        // reference counter can always be done with memory_order_relaxed: New
        // references to an object can only be formed from an existing
        // reference, and passing an existing reference from one thread to
        // another must already provide any required synchronization.
        //
        // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
        let prev = self.val.fetch_add(WAKER_ONE, Relaxed);

        // If the reference count overflowed, abort.
        if prev > isize::max_value() as usize {
            process::abort();
        }
    }

    /// Returns `true` if the task should be released.
    pub(super) fn ref_dec(&self) -> bool {
        use crate::loom::sync::atomic;

        let prev = self.val.fetch_sub(WAKER_ONE, Release);
        let next = Snapshot(prev - WAKER_ONE);

        if next.is_final_ref() {
            atomic::fence(Acquire);
        }

        next.is_final_ref()
    }
}

impl Snapshot {
    pub(super) fn is_running(self) -> bool {
        self.0 & RUNNING == RUNNING
    }

    pub(super) fn is_notified(self) -> bool {
        self.0 & NOTIFIED == NOTIFIED
    }

    pub(super) fn is_released(self) -> bool {
        self.0 & RELEASED == RELEASED
    }

    pub(super) fn is_complete(self) -> bool {
        self.0 & COMPLETE == COMPLETE
    }

    pub(super) fn is_canceled(self) -> bool {
        self.0 & CANCELLED == CANCELLED
    }

    /// Used during normal runtime.
    pub(super) fn is_active(self) -> bool {
        self.0 & (COMPLETE | CANCELLED) == 0
    }

    /// Used before dropping the task
    pub(super) fn is_terminal(self) -> bool {
        // When both the notified & running flags are set, the task was canceled
        // after being notified, before it was run.
        //
        // There is a race where:
        // - The task state transitions to notified
        // - The global queue is shutdown
        // - The waker attempts to push into the global queue and fails.
        // - The waker holds the last reference to the task, thus drops it.
        //
        // In this scenario, the cancelled bit will never get set.
        !self.is_active() || (self.is_notified() && self.is_running())
    }

    pub(super) fn is_join_interested(self) -> bool {
        self.0 & JOIN_INTEREST == JOIN_INTEREST
    }

    pub(super) fn has_join_waker(self) -> bool {
        self.0 & JOIN_WAKER == JOIN_WAKER
    }

    pub(super) fn is_final_ref(self) -> bool {
        const MASK: usize = WAKER_COUNT_MASK | RELEASED | JOIN_INTEREST;

        (self.0 & MASK) == RELEASED
    }
}

impl fmt::Debug for State {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        use std::sync::atomic::Ordering::SeqCst;

        let snapshot = Snapshot(self.val.load(SeqCst));

        fmt.debug_struct("State")
            .field("snapshot", &snapshot)
            .finish()
    }
}

impl fmt::Debug for Snapshot {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.debug_struct("Snapshot")
            .field("is_running", &self.is_running())
            .field("is_notified", &self.is_notified())
            .field("is_released", &self.is_released())
            .field("is_complete", &self.is_complete())
            .field("is_canceled", &self.is_canceled())
            .field("is_join_interested", &self.is_join_interested())
            .field("has_join_waker", &self.has_join_waker())
            .field("is_final_ref", &self.is_final_ref())
            .finish()
    }
}
<|endoftext|>


<commit_before>use std::path::Path;

use regex::Regex;

use crate::rustc_stderr::Level;

use color_eyre::eyre::{bail, ensure, eyre, Result};

#[cfg(test)]
mod tests;

/// This crate supports various magic comments that get parsed as file-specific
/// configuration values. This struct parses them all in one go and then they
/// get processed by their respective use sites.
#[derive(Default, Debug)]
pub(crate) struct Comments {
    /// List of revision names to execute. Can only be speicified once
    pub revisions: Option<Vec<String>>,
    /// Don't run this test if any of these filters apply
    pub ignore: Vec<Condition>,
    /// Only run this test if all of these filters apply
    pub only: Vec<Condition>,
    /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar
    pub stderr_per_bitwidth: bool,
    /// Additional flags to pass to the executable
    pub compile_flags: Vec<String>,
    /// Additional env vars to set for the executable
    pub env_vars: Vec<(String, String)>,
    /// Normalizations to apply to the stderr output before emitting it to disk
    pub normalize_stderr: Vec<(Regex, String)>,
    /// An arbitrary pattern to look for in the stderr.
    pub error_pattern: Option<(String, usize)>,
    pub error_matches: Vec<ErrorMatch>,
}

/// The conditions used for "ignore" and "only" filters.
#[derive(Debug)]
pub(crate) enum Condition {
    /// The given string must appear in the target.
    Target(String),
    /// Tests that the bitwidth is the given one.
    Bitwidth(u8),
}

#[derive(Debug)]
pub(crate) struct ErrorMatch {
    pub matched: String,
    pub revision: Option<String>,
    pub level: Option<Level>,
    /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found).
    pub definition_line: usize,
    /// The line this pattern is expecting to find a message in.
    pub line: usize,
}

impl Condition {
    fn parse(c: &str) -> Self {
        if let Some(bits) = c.strip_suffix("bit") {
            let bits: u8 = bits.parse().expect(
                "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N",
            );
            Condition::Bitwidth(bits)
        } else {
            Condition::Target(c.to_owned())
        }
    }
}

impl Comments {
    pub(crate) fn parse_file(path: &Path) -> Result<Self> {
        let content = std::fs::read_to_string(path)?;
        Self::parse(path, &content)
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    ///
    /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant)
    /// and ignore all others
    fn parse_checked(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::default();

        let mut fallthrough_to = None; // The line that a `|` will refer to.
        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| {
                err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display()))
            })?;
        }
        Ok(this)
    }

    fn parse_checked_line(
        &mut self,
        l: usize,
        fallthrough_to: &mut Option<usize>,
        line: &str,
    ) -> Result<()> {
        if let Some((_, command)) = line.split_once("//@") {
            self.parse_command(command.trim(), l)
        } else if let Some((_, pattern)) = line.split_once("//~") {
            self.parse_pattern(pattern, fallthrough_to, l)
        } else if let Some((_, pattern)) = line.split_once("//[") {
            self.parse_revisioned_pattern(pattern, fallthrough_to, l)
        } else {
            *fallthrough_to = None;
            Ok(())
        }
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    pub(crate) fn parse(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::parse_checked(path, content)?;
        if content.contains("//@") {
            // Migration mode: if new syntax is used, ignore all old syntax
            return Ok(this);
        }

        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            if let Some(revisions) = line.strip_prefix("// revisions:") {
                assert_eq!(
                    this.revisions,
                    None,
                    "{}:{l}, cannot specifiy revisions twice",
                    path.display()
                );
                this.revisions =
                    Some(revisions.split_whitespace().map(|s| s.to_string()).collect());
            }
            if let Some(s) = line.strip_prefix("// ignore-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.ignore.push(Condition::parse(s));
            }
            if let Some(s) = line.strip_prefix("// only-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.only.push(Condition::parse(s));
            }
            if line.starts_with("// stderr-per-bitwidth") {
                assert!(
                    !this.stderr_per_bitwidth,
                    "{}:{l}, cannot specifiy stderr-per-bitwidth twice",
                    path.display()
                );
                this.stderr_per_bitwidth = true;
            }
            if let Some(s) = line.strip_prefix("// compile-flags:") {
                this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string()));
            }
            if let Some(s) = line.strip_prefix("// rustc-env:") {
                for env in s.split_whitespace() {
                    if let Some((k, v)) = env.split_once('=') {
                        this.env_vars.push((k.to_string(), v.to_string()));
                    }
                }
            }
            if let Some(s) = line.strip_prefix("// normalize-stderr-test:") {
                let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`");
                let from = from.trim().trim_matches('"');
                let to = to.trim().trim_matches('"');
                let from = Regex::new(from).unwrap();
                this.normalize_stderr.push((from, to.to_string()));
            }
            if let Some(s) = line.strip_prefix("// error-pattern:") {
                assert_eq!(
                    this.error_pattern,
                    None,
                    "{}:{l}, cannot specifiy error_pattern twice",
                    path.display()
                );
                this.error_pattern = Some((s.trim().to_string(), l));
            }
        }
        Ok(this)
    }

    fn parse_command(&mut self, command: &str, l: usize) -> Result<()> {
        // Commands are letters or dashes, grab everything until the first character that is neither of those.
        let (command, args) =
            match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') {
                None => (command, ""),
                Some(i) => {
                    let (command, args) = command.split_at(i);
                    let mut args = args.chars();
                    // Commands are separated from their arguments by ':' or ' '
                    let next = args
                        .next()
                        .expect("the `position` above guarantees that there is at least one char");
                    let args = match next {
                        ':' | ' ' => args.as_str(),
                        _ => bail!("expected space or `:`, got `{next}`"),
                    };
                    (command, args.trim())
                }
            };

        match command {
            "revisions" => {
                ensure!(self.revisions.is_none(), "cannot specifiy revisions twice");
                self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect());
            }
            "compile-flags" => {
                self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string()));
            }
            "rustc-env" =>
                for env in args.split_whitespace() {
                    let (k, v) = env.split_once('=').ok_or_else(|| {
                        eyre!("environment variables must be key/value pairs separated by a `=`")
                    })?;
                    self.env_vars.push((k.to_string(), v.to_string()));
                },
            "normalize-stderr-test" => {
                fn parse_str(s: &str) -> Result<(&str, &str)> {
                    let mut chars = s.char_indices();
                    match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 {
                        '"' => {
                            let s = chars.as_str();
                            let mut escaped = false;
                            for (i, c) in chars {
                                if escaped {
                                    escaped = false;
                                } else if c == '"' {
                                    return Ok((&s[..(i - 1)], s[i..].trim_start()));
                                } else {
                                    escaped = c == '\\';
                                }
                            }
                            bail!("no closing quotes found for {s}")
                        }
                        c => bail!("expected '\"', got {c}"),
                    }
                }

                let (from, rest) = parse_str(args)?;

                let to = rest.strip_prefix("->").ok_or_else(|| {
                    eyre!("normalize-stderr-test needs a pattern and replacement separated by `->`")
                })?.trim_start();
                let (to, rest) = parse_str(to)?;

                ensure!(rest.is_empty(), "trailing text after pattern replacement: {rest}");

                let from = Regex::new(from)?;
                self.normalize_stderr.push((from, to.to_string()));
            }
            "error-pattern" => {
                ensure!(
                    self.error_pattern.is_none(),
                    "cannot specifiy error_pattern twice, previous: {:?}",
                    self.error_pattern
                );
                self.error_pattern = Some((args.trim().to_string(), l));
            }
            "stderr-per-bitwidth" => {
                ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice");
                self.stderr_per_bitwidth = true;
            }
            command => {
                if let Some(s) = command.strip_prefix("ignore-") {
                    self.ignore.push(Condition::parse(s));
                    return Ok(());
                }

                if let Some(s) = command.strip_prefix("only-") {
                    self.only.push(Condition::parse(s));
                    return Ok(());
                }
                bail!("unknown command {command}");
            }
        }

        Ok(())
    }

    fn parse_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        self.parse_pattern_inner(pattern, fallthrough_to, None, l)
    }

    fn parse_revisioned_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        let (revision, pattern) =
            pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?;
        if let Some(pattern) = pattern.strip_prefix('~') {
            self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l)
        } else {
            bail!("revisioned pattern must have `~` following the `]`");
        }
    }

    // parse something like (?P<offset>\||[\^]+)? *(?P<level>ERROR|HELP|WARN|NOTE)?:?(?P<text>.*)
    fn parse_pattern_inner(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        revision: Option<String>,
        l: usize,
    ) -> Result<()> {
        let (match_line, pattern) =
            match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? {
                '|' =>
                    (
                        *fallthrough_to
                            .as_mut()
                            .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?,
                        &pattern[1..],
                    ),
                '^' => {
                    let offset = pattern.chars().take_while(|&c| c == '^').count();
                    (l - offset, &pattern[offset..])
                }
                _ => (l, pattern),
            };

        let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) {
            None => (None, pattern),
            Some((level, pattern_without_level)) =>
                match level.parse().ok() {
                    Some(level) => (Some(level), pattern_without_level),
                    None => (None, pattern),
                },
        };

        let matched = pattern.trim().to_string();

        ensure!(!matched.is_empty(), "no pattern specified");

        *fallthrough_to = Some(match_line);

        self.error_matches.push(ErrorMatch {
            matched,
            revision,
            level,
            definition_line: l,
            line: match_line,
        });

        Ok(())
    }
}
<commit_msg>Add FIXME<commit_after>use std::path::Path;

use regex::Regex;

use crate::rustc_stderr::Level;

use color_eyre::eyre::{bail, ensure, eyre, Result};

#[cfg(test)]
mod tests;

/// This crate supports various magic comments that get parsed as file-specific
/// configuration values. This struct parses them all in one go and then they
/// get processed by their respective use sites.
#[derive(Default, Debug)]
pub(crate) struct Comments {
    /// List of revision names to execute. Can only be speicified once
    pub revisions: Option<Vec<String>>,
    /// Don't run this test if any of these filters apply
    pub ignore: Vec<Condition>,
    /// Only run this test if all of these filters apply
    pub only: Vec<Condition>,
    /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar
    pub stderr_per_bitwidth: bool,
    /// Additional flags to pass to the executable
    pub compile_flags: Vec<String>,
    /// Additional env vars to set for the executable
    pub env_vars: Vec<(String, String)>,
    /// Normalizations to apply to the stderr output before emitting it to disk
    pub normalize_stderr: Vec<(Regex, String)>,
    /// An arbitrary pattern to look for in the stderr.
    pub error_pattern: Option<(String, usize)>,
    pub error_matches: Vec<ErrorMatch>,
}

/// The conditions used for "ignore" and "only" filters.
#[derive(Debug)]
pub(crate) enum Condition {
    /// The given string must appear in the target.
    Target(String),
    /// Tests that the bitwidth is the given one.
    Bitwidth(u8),
}

#[derive(Debug)]
pub(crate) struct ErrorMatch {
    pub matched: String,
    pub revision: Option<String>,
    pub level: Option<Level>,
    /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found).
    pub definition_line: usize,
    /// The line this pattern is expecting to find a message in.
    pub line: usize,
}

impl Condition {
    fn parse(c: &str) -> Self {
        if let Some(bits) = c.strip_suffix("bit") {
            let bits: u8 = bits.parse().expect(
                "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N",
            );
            Condition::Bitwidth(bits)
        } else {
            Condition::Target(c.to_owned())
        }
    }
}

impl Comments {
    pub(crate) fn parse_file(path: &Path) -> Result<Self> {
        let content = std::fs::read_to_string(path)?;
        Self::parse(path, &content)
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    ///
    /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant)
    /// and ignore all others
    fn parse_checked(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::default();

        let mut fallthrough_to = None; // The line that a `|` will refer to.
        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| {
                err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display()))
            })?;
        }
        Ok(this)
    }

    fn parse_checked_line(
        &mut self,
        l: usize,
        fallthrough_to: &mut Option<usize>,
        line: &str,
    ) -> Result<()> {
        if let Some((_, command)) = line.split_once("//@") {
            self.parse_command(command.trim(), l)
        } else if let Some((_, pattern)) = line.split_once("//~") {
            self.parse_pattern(pattern, fallthrough_to, l)
        } else if let Some((_, pattern)) = line.split_once("//[") {
            self.parse_revisioned_pattern(pattern, fallthrough_to, l)
        } else {
            *fallthrough_to = None;
            Ok(())
        }
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    pub(crate) fn parse(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::parse_checked(path, content)?;
        if content.contains("//@") {
            // Migration mode: if new syntax is used, ignore all old syntax
            return Ok(this);
        }

        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            if let Some(revisions) = line.strip_prefix("// revisions:") {
                assert_eq!(
                    this.revisions,
                    None,
                    "{}:{l}, cannot specifiy revisions twice",
                    path.display()
                );
                this.revisions =
                    Some(revisions.split_whitespace().map(|s| s.to_string()).collect());
            }
            if let Some(s) = line.strip_prefix("// ignore-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.ignore.push(Condition::parse(s));
            }
            if let Some(s) = line.strip_prefix("// only-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.only.push(Condition::parse(s));
            }
            if line.starts_with("// stderr-per-bitwidth") {
                assert!(
                    !this.stderr_per_bitwidth,
                    "{}:{l}, cannot specifiy stderr-per-bitwidth twice",
                    path.display()
                );
                this.stderr_per_bitwidth = true;
            }
            if let Some(s) = line.strip_prefix("// compile-flags:") {
                this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string()));
            }
            if let Some(s) = line.strip_prefix("// rustc-env:") {
                for env in s.split_whitespace() {
                    if let Some((k, v)) = env.split_once('=') {
                        this.env_vars.push((k.to_string(), v.to_string()));
                    }
                }
            }
            if let Some(s) = line.strip_prefix("// normalize-stderr-test:") {
                let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`");
                let from = from.trim().trim_matches('"');
                let to = to.trim().trim_matches('"');
                let from = Regex::new(from).unwrap();
                this.normalize_stderr.push((from, to.to_string()));
            }
            if let Some(s) = line.strip_prefix("// error-pattern:") {
                assert_eq!(
                    this.error_pattern,
                    None,
                    "{}:{l}, cannot specifiy error_pattern twice",
                    path.display()
                );
                this.error_pattern = Some((s.trim().to_string(), l));
            }
        }
        Ok(this)
    }

    fn parse_command(&mut self, command: &str, l: usize) -> Result<()> {
        // Commands are letters or dashes, grab everything until the first character that is neither of those.
        let (command, args) =
            match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') {
                None => (command, ""),
                Some(i) => {
                    let (command, args) = command.split_at(i);
                    let mut args = args.chars();
                    // Commands are separated from their arguments by ':' or ' '
                    let next = args
                        .next()
                        .expect("the `position` above guarantees that there is at least one char");
                    // FIXME: this replicates the existing flexibility in our syntax. Consider requiring the colon.
                    let args = match next {
                        ':' | ' ' => args.as_str(),
                        _ => bail!("expected space or `:`, got `{next}`"),
                    };
                    (command, args.trim())
                }
            };

        match command {
            "revisions" => {
                ensure!(self.revisions.is_none(), "cannot specifiy revisions twice");
                self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect());
            }
            "compile-flags" => {
                self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string()));
            }
            "rustc-env" =>
                for env in args.split_whitespace() {
                    let (k, v) = env.split_once('=').ok_or_else(|| {
                        eyre!("environment variables must be key/value pairs separated by a `=`")
                    })?;
                    self.env_vars.push((k.to_string(), v.to_string()));
                },
            "normalize-stderr-test" => {
                fn parse_str(s: &str) -> Result<(&str, &str)> {
                    let mut chars = s.char_indices();
                    match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 {
                        '"' => {
                            let s = chars.as_str();
                            let mut escaped = false;
                            for (i, c) in chars {
                                if escaped {
                                    escaped = false;
                                } else if c == '"' {
                                    return Ok((&s[..(i - 1)], s[i..].trim_start()));
                                } else {
                                    escaped = c == '\\';
                                }
                            }
                            bail!("no closing quotes found for {s}")
                        }
                        c => bail!("expected '\"', got {c}"),
                    }
                }

                let (from, rest) = parse_str(args)?;

                let to = rest.strip_prefix("->").ok_or_else(|| {
                    eyre!("normalize-stderr-test needs a pattern and replacement separated by `->`")
                })?.trim_start();
                let (to, rest) = parse_str(to)?;

                ensure!(rest.is_empty(), "trailing text after pattern replacement: {rest}");

                let from = Regex::new(from)?;
                self.normalize_stderr.push((from, to.to_string()));
            }
            "error-pattern" => {
                ensure!(
                    self.error_pattern.is_none(),
                    "cannot specifiy error_pattern twice, previous: {:?}",
                    self.error_pattern
                );
                self.error_pattern = Some((args.trim().to_string(), l));
            }
            "stderr-per-bitwidth" => {
                ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice");
                self.stderr_per_bitwidth = true;
            }
            command => {
                if let Some(s) = command.strip_prefix("ignore-") {
                    self.ignore.push(Condition::parse(s));
                    return Ok(());
                }

                if let Some(s) = command.strip_prefix("only-") {
                    self.only.push(Condition::parse(s));
                    return Ok(());
                }
                bail!("unknown command {command}");
            }
        }

        Ok(())
    }

    fn parse_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        self.parse_pattern_inner(pattern, fallthrough_to, None, l)
    }

    fn parse_revisioned_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        let (revision, pattern) =
            pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?;
        if let Some(pattern) = pattern.strip_prefix('~') {
            self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l)
        } else {
            bail!("revisioned pattern must have `~` following the `]`");
        }
    }

    // parse something like (?P<offset>\||[\^]+)? *(?P<level>ERROR|HELP|WARN|NOTE)?:?(?P<text>.*)
    fn parse_pattern_inner(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        revision: Option<String>,
        l: usize,
    ) -> Result<()> {
        let (match_line, pattern) =
            match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? {
                '|' =>
                    (
                        *fallthrough_to
                            .as_mut()
                            .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?,
                        &pattern[1..],
                    ),
                '^' => {
                    let offset = pattern.chars().take_while(|&c| c == '^').count();
                    (l - offset, &pattern[offset..])
                }
                _ => (l, pattern),
            };

        let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) {
            None => (None, pattern),
            Some((level, pattern_without_level)) =>
                match level.parse().ok() {
                    Some(level) => (Some(level), pattern_without_level),
                    None => (None, pattern),
                },
        };

        let matched = pattern.trim().to_string();

        ensure!(!matched.is_empty(), "no pattern specified");

        *fallthrough_to = Some(match_line);

        self.error_matches.push(ErrorMatch {
            matched,
            revision,
            level,
            definition_line: l,
            line: match_line,
        });

        Ok(())
    }
}
<|endoftext|>


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

use abi::{FnType, ArgType, LayoutExt, Reg, Uniform};
use context::CrateContext;

fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
    if !ret.layout.is_aggregate() {
        ret.extend_integer_width_to(32);
        return;
    }
    let size = ret.layout.size(ccx);
    let bits = size.bits();
    if bits <= 32 {
        let unit = if bits <= 8 {
            Reg::i8()
        } else if bits <= 16 {
            Reg::i16()
        } else {
            Reg::i32()
        };
        ret.cast_to(ccx, Uniform {
            unit,
            total: size
        });
        return;
    }
    ret.make_indirect(ccx);
}

fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
    if !arg.layout.is_aggregate() {
        arg.extend_integer_width_to(32);
        return;
    }
    let align = arg.layout.align(ccx).abi();
    let total = arg.layout.size(ccx);
    arg.cast_to(ccx, Uniform {
        unit: if align <= 4 { Reg::i32() } else { Reg::i64() },
        total
    });
}

pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
    if !fty.ret.is_ignore() {
        classify_ret_ty(ccx, &mut fty.ret);
    }

    for arg in &mut fty.args {
        if arg.is_ignore() { continue; }
        classify_arg_ty(ccx, arg);
    }
}
<commit_msg>Support homogeneous aggregates for hard-float ARM<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
use context::CrateContext;
use llvm::CallConv;

fn is_homogeneous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
                                     -> Option<Uniform> {
    arg.layout.homogeneous_aggregate(ccx).and_then(|unit| {
        let size = arg.layout.size(ccx);

        // Ensure we have at most four uniquely addressable members.
        if size > unit.size.checked_mul(4, ccx).unwrap() {
            return None;
        }

        let valid_unit = match unit.kind {
            RegKind::Integer => false,
            RegKind::Float => true,
            RegKind::Vector => size.bits() == 64 || size.bits() == 128
        };

        if valid_unit {
            Some(Uniform {
                unit,
                total: size
            })
        } else {
            None
        }
    })
}

fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>, vfp: bool) {
    if !ret.layout.is_aggregate() {
        ret.extend_integer_width_to(32);
        return;
    }

    if vfp {
        if let Some(uniform) = is_homogeneous_aggregate(ccx, ret) {
            ret.cast_to(ccx, uniform);
            return;
        }
    }

    let size = ret.layout.size(ccx);
    let bits = size.bits();
    if bits <= 32 {
        let unit = if bits <= 8 {
            Reg::i8()
        } else if bits <= 16 {
            Reg::i16()
        } else {
            Reg::i32()
        };
        ret.cast_to(ccx, Uniform {
            unit,
            total: size
        });
        return;
    }
    ret.make_indirect(ccx);
}

fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>, vfp: bool) {
    if !arg.layout.is_aggregate() {
        arg.extend_integer_width_to(32);
        return;
    }

    if vfp {
        if let Some(uniform) = is_homogeneous_aggregate(ccx, arg) {
            arg.cast_to(ccx, uniform);
            return;
        }
    }

    let align = arg.layout.align(ccx).abi();
    let total = arg.layout.size(ccx);
    arg.cast_to(ccx, Uniform {
        unit: if align <= 4 { Reg::i32() } else { Reg::i64() },
        total
    });
}

pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
    // If this is a target with a hard-float ABI, and the function is not explicitly
    // `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates.
    let vfp = ccx.sess().target.target.llvm_target.ends_with("hf")
        && fty.cconv != CallConv::ArmAapcsCallConv
        && !fty.variadic;

    if !fty.ret.is_ignore() {
        classify_ret_ty(ccx, &mut fty.ret, vfp);
    }

    for arg in &mut fty.args {
        if arg.is_ignore() { continue; }
        classify_arg_ty(ccx, arg, vfp);
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use serde::{Serialize, Deserialize};

use de::Deserializer;
use ser::Serializer;
use token::Token;

use std::fmt::Debug;

/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
    T: Serialize + Deserialize<'de> + PartialEq + Debug,
{
    assert_ser_tokens(value, tokens);
    assert_de_tokens(value, tokens);
}

/// Asserts that `value` serializes to the given `tokens`.
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
where
    T: Serialize,
{
    let mut ser = Serializer::new(tokens);
    match value.serialize(&mut ser) {
        Ok(_) => {}
        Err(err) => panic!("value failed to serialize: {}", err),
    }

    if ser.remaining() > 0 {
        panic!("{} remaining tokens", ser.remaining());
    }
}

/// Asserts that `value` serializes to the given `tokens`, and then yields `error`.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_derive;
/// #
/// # extern crate serde_test;
/// #
/// # fn main() {
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// use serde_test::{assert_ser_tokens_error, Token};
///
/// #[derive(Serialize)]
/// struct Example {
///     lock: Arc<Mutex<u32>>,
/// }
///
/// let example = Example { lock: Arc::new(Mutex::new(0)) };
/// let lock = example.lock.clone();
///
/// let _ = thread::spawn(move || {
///     // This thread will acquire the mutex first, unwrapping the result
///     // of `lock` because the lock has not been poisoned.
///     let _guard = lock.lock().unwrap();
///
///     // This panic while holding the lock (`_guard` is in scope) will
///     // poison the mutex.
///     panic!()
/// }).join();
///
/// let expected = &[
///     Token::Struct { name: "Example", len: 1 },
///     Token::Str("lock"),
/// ];
/// let error = "lock poison error while serializing";
/// assert_ser_tokens_error(&example, expected, error);
/// # }
/// ```
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: &str)
where
    T: Serialize,
{
    let mut ser = Serializer::new(tokens);
    match value.serialize(&mut ser) {
        Ok(_) => panic!("value serialized successfully"),
        Err(e) => assert_eq!(e, *error),
    }

    if ser.remaining() > 0 {
        panic!("{} remaining tokens", ser.remaining());
    }
}

/// Asserts that the given `tokens` deserialize into `value`.
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
    T: Deserialize<'de> + PartialEq + Debug,
{
    let mut de = Deserializer::new(tokens);
    match T::deserialize(&mut de) {
        Ok(v) => assert_eq!(v, *value),
        Err(e) => panic!("tokens failed to deserialize: {}", e),
    }

    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }
}

/// Asserts that the given `tokens` yield `error` when deserializing.
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
where
    T: Deserialize<'de>,
{
    let mut de = Deserializer::new(tokens);
    match T::deserialize(&mut de) {
        Ok(_) => panic!("tokens deserialized successfully"),
        Err(e) => assert_eq!(e, *error),
    }

    // There may be one token left if a peek caused the error
    de.next_token_opt();

    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }
}
<commit_msg>Examples for serde_test methods<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use serde::{Serialize, Deserialize};

use de::Deserializer;
use ser::Serializer;
use token::Token;

use std::fmt::Debug;

/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_derive;
/// #
/// # extern crate serde;
/// # extern crate serde_test;
/// #
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_tokens(&s, &[
///     Token::Struct { name: "S", len: 2 },
///     Token::Str("a"),
///     Token::U8(0),
///     Token::Str("b"),
///     Token::U8(0),
///     Token::StructEnd,
/// ]);
/// # }
/// ```
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
    T: Serialize + Deserialize<'de> + PartialEq + Debug,
{
    assert_ser_tokens(value, tokens);
    assert_de_tokens(value, tokens);
}

/// Asserts that `value` serializes to the given `tokens`.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_derive;
/// #
/// # extern crate serde;
/// # extern crate serde_test;
/// #
/// # use serde_test::{assert_ser_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_ser_tokens(&s, &[
///     Token::Struct { name: "S", len: 2 },
///     Token::Str("a"),
///     Token::U8(0),
///     Token::Str("b"),
///     Token::U8(0),
///     Token::StructEnd,
/// ]);
/// # }
/// ```
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
where
    T: Serialize,
{
    let mut ser = Serializer::new(tokens);
    match value.serialize(&mut ser) {
        Ok(_) => {}
        Err(err) => panic!("value failed to serialize: {}", err),
    }

    if ser.remaining() > 0 {
        panic!("{} remaining tokens", ser.remaining());
    }
}

/// Asserts that `value` serializes to the given `tokens`, and then yields `error`.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_derive;
/// #
/// # extern crate serde_test;
/// #
/// # fn main() {
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// use serde_test::{assert_ser_tokens_error, Token};
///
/// #[derive(Serialize)]
/// struct Example {
///     lock: Arc<Mutex<u32>>,
/// }
///
/// let example = Example { lock: Arc::new(Mutex::new(0)) };
/// let lock = example.lock.clone();
///
/// let _ = thread::spawn(move || {
///     // This thread will acquire the mutex first, unwrapping the result
///     // of `lock` because the lock has not been poisoned.
///     let _guard = lock.lock().unwrap();
///
///     // This panic while holding the lock (`_guard` is in scope) will
///     // poison the mutex.
///     panic!()
/// }).join();
///
/// let expected = &[
///     Token::Struct { name: "Example", len: 1 },
///     Token::Str("lock"),
/// ];
/// let error = "lock poison error while serializing";
/// assert_ser_tokens_error(&example, expected, error);
/// # }
/// ```
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: &str)
where
    T: Serialize,
{
    let mut ser = Serializer::new(tokens);
    match value.serialize(&mut ser) {
        Ok(_) => panic!("value serialized successfully"),
        Err(e) => assert_eq!(e, *error),
    }

    if ser.remaining() > 0 {
        panic!("{} remaining tokens", ser.remaining());
    }
}

/// Asserts that the given `tokens` deserialize into `value`.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_derive;
/// #
/// # extern crate serde;
/// # extern crate serde_test;
/// #
/// # use serde_test::{assert_de_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_de_tokens(&s, &[
///     Token::Struct { name: "S", len: 2 },
///     Token::Str("a"),
///     Token::U8(0),
///     Token::Str("b"),
///     Token::U8(0),
///     Token::StructEnd,
/// ]);
/// # }
/// ```
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
    T: Deserialize<'de> + PartialEq + Debug,
{
    let mut de = Deserializer::new(tokens);
    match T::deserialize(&mut de) {
        Ok(v) => assert_eq!(v, *value),
        Err(e) => panic!("tokens failed to deserialize: {}", e),
    }

    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }
}

/// Asserts that the given `tokens` yield `error` when deserializing.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_derive;
/// #
/// # extern crate serde;
/// # extern crate serde_test;
/// #
/// # use serde_test::{assert_de_tokens_error, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// #[serde(deny_unknown_fields)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// assert_de_tokens_error::<S>(
///     &[
///         Token::Struct { name: "S", len: 1 },
///         Token::Str("x"),
///     ],
///     "unknown field `x`, expected `a` or `b`",
/// );
/// # }
/// ```
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
where
    T: Deserialize<'de>,
{
    let mut de = Deserializer::new(tokens);
    match T::deserialize(&mut de) {
        Ok(_) => panic!("tokens deserialized successfully"),
        Err(e) => assert_eq!(e, *error),
    }

    // There may be one token left if a peek caused the error
    de.next_token_opt();

    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }
}
<|endoftext|>


<commit_before>//! Matrix math is used to render things on a computer screen. This is common
//! throughout computer graphics, for examples and primers on using matrix
//! math to render things to screens please read an OpengGL tutorial.
//!
//! In wlroots we primarily use a 3x3 matrix of 32 bit floating point values to
//! represent a 2D screen. We also provide basic helper functions to assist in
//! transforming the matrices.

use Area;
use wlroots_sys::{wl_output_transform, wlr_matrix_multiply,
                  wlr_matrix_project_box, wlr_matrix_projection, wlr_matrix_rotate,
                  wlr_matrix_scale, wlr_matrix_transform, wlr_matrix_translate,
                  wlr_matrix_transpose};

pub const IDENTITY: [f32; 9] =[
    1.0, 0.0, 0.0,
    0.0, 1.0, 0.0,
    0.0, 0.0, 1.0
];

/// Translate the matrix in x, and y.
pub fn matrix_translate(x: f32, y: f32) -> [f32; 9] {
    let mut output = [0.0; 9];
    unsafe {
        wlr_matrix_translate(output.as_mut_ptr(), x, y);
    }
    output
}

/// Scale the output in the x, and y.
pub fn matrix_scale(x: f32, y: f32) -> [f32; 9] {
    let mut output = [0.0; 9];
    unsafe {
        wlr_matrix_scale(output.as_mut_ptr(), x, y);
    }
    output
}

/// Rotate the matrix by some amount of radians.
pub fn matrix_rotate(mut matrix: [f32; 9], radians: f32) -> [f32; 9] {
    unsafe {
        wlr_matrix_rotate(matrix.as_mut_ptr(), radians);
    }
    matrix
}

/// Multiply two matrices together.
pub fn matrix_multiply(x: [f32; 9], y: [f32; 9]) -> [f32; 9] {
    let mut output = [0.0; 9];
    unsafe {
        wlr_matrix_multiply(output.as_mut_ptr(), x.as_ptr(), y.as_ptr());
    }
    output
}

/// Transform the matrix based on the given Wayland output transform mode.
pub fn matrix_transform(mut matrix: [f32; 9], transform: wl_output_transform) -> [f32; 9] {
    unsafe {
        wlr_matrix_transform(matrix.as_mut_ptr(), transform);
    }
    matrix
}

/// Transform the matrix based on the given Wayland output transform mode and
/// the width and height of a texture.
pub fn matrix_projection(mut matrix: [f32; 9],
                         width: i32,
                         height: i32,
                         transform: wl_output_transform)
                         -> [f32; 9] {
    unsafe {
        wlr_matrix_projection(matrix.as_mut_ptr(), width, height, transform);
    }
    matrix
}

pub fn matrix_transpose(matrix: [f32; 9]) -> [f32; 9] {
    let mut result = [0.0; 9];
    unsafe {
        wlr_matrix_transpose(result.as_mut_ptr(), matrix.as_ptr());
    }
    result
}

pub fn project_box(area: Area,
                   transform: wl_output_transform,
                   rotation: f32,
                   projection: [f32; 9])
                   -> [f32; 9] {
    unsafe {
        let mut output = [0.0; 9];
        wlr_matrix_project_box(output.as_mut_ptr(),
                               &area.into(),
                               transform,
                               rotation,
                               projection.as_ptr());
        output
    }
}
<commit_msg>Remove matrix name, move project_box to top<commit_after>//! Matrix math is used to render things on a computer screen. This is common
//! throughout computer graphics, for examples and primers on using matrix
//! math to render things to screens please read an OpengGL tutorial.
//!
//! In wlroots we primarily use a 3x3 matrix of 32 bit floating point values to
//! represent a 2D screen. We also provide basic helper functions to assist in
//! transforming the matrices.

use Area;
use wlroots_sys::{wl_output_transform, wlr_matrix_multiply,
                  wlr_matrix_project_box, wlr_matrix_projection, wlr_matrix_rotate,
                  wlr_matrix_scale, wlr_matrix_transform, wlr_matrix_translate,
                  wlr_matrix_transpose};

pub const IDENTITY: [f32; 9] =[
    1.0, 0.0, 0.0,
    0.0, 1.0, 0.0,
    0.0, 0.0, 1.0
];

/// Shortcut for the various matrix operations involved in projecting the
/// specified wlr_box onto a given orthographic projection with a given
/// rotation. The result can be applied to each coordinate of the box to
/// get a new coordinate from [-1,1].
pub fn project_box(area: Area,
                   transform: wl_output_transform,
                   rotation: f32,
                   projection: [f32; 9])
                   -> [f32; 9] {
    unsafe {
        let mut output = [0.0; 9];
        wlr_matrix_project_box(output.as_mut_ptr(),
                               &area.into(),
                               transform,
                               rotation,
                               projection.as_ptr());
        output
    }
}

/// Translate the 2D matrix to a magnitude of (x, y).
pub fn translate(x: f32, y: f32) -> [f32; 9] {
    let mut output = [0.0; 9];
    unsafe {
        wlr_matrix_translate(output.as_mut_ptr(), x, y);
    }
    output
}

/// Scales the 2D matrix to a magnitude of (x, y).
pub fn scale(x: f32, y: f32) -> [f32; 9] {
    let mut output = [0.0; 9];
    unsafe {
        wlr_matrix_scale(output.as_mut_ptr(), x, y);
    }
    output
}

/// Rotate the matrix by some amount of radians.
pub fn rotate(mut matrix: [f32; 9], radians: f32) -> [f32; 9] {
    unsafe {
        wlr_matrix_rotate(matrix.as_mut_ptr(), radians);
    }
    matrix
}

/// Multiply two matrices together.
pub fn multiply(x: [f32; 9], y: [f32; 9]) -> [f32; 9] {
    let mut output = [0.0; 9];
    unsafe {
        wlr_matrix_multiply(output.as_mut_ptr(), x.as_ptr(), y.as_ptr());
    }
    output
}

/// Transform the matrix based on the given Wayland output transform mode.
pub fn transform(mut matrix: [f32; 9], transform: wl_output_transform) -> [f32; 9] {
    unsafe {
        wlr_matrix_transform(matrix.as_mut_ptr(), transform);
    }
    matrix
}

/// Create a 2D orthographic projection matrix of (width, height) with a
/// specified `wl_output_transform`
pub fn projection(mut matrix: [f32; 9],
                         width: i32,
                         height: i32,
                         transform: wl_output_transform)
                         -> [f32; 9] {
    unsafe {
        wlr_matrix_projection(matrix.as_mut_ptr(), width, height, transform);
    }
    matrix
}

/// Flip the values over the diagonal of a matrix
pub fn transpose(matrix: [f32; 9]) -> [f32; 9] {
    let mut result = [0.0; 9];
    unsafe {
        wlr_matrix_transpose(result.as_mut_ptr(), matrix.as_ptr());
    }
    result
}
<|endoftext|>


<commit_before>use std::{ptr, mem};
use winapi::*;
use math::*;
use brush::{self, Brush};
use geometry::{Geometry};
use error::D2D1Error;
use stroke_style::StrokeStyle;
use factory::Factory;
use comptr::ComPtr;
use helpers::{GetRaw, FromRaw, ToWide};
use directwrite::{TextFormat, TextLayout};

/// This trait is intended to be implemented by external APIs who would
/// like to allow a Direct2D interface for drawing onto them. Since the
/// Direct2D creation APIs require more information, this will likely be
/// implemented on Builder objects which contain enough context about
/// the actual backing structure and what needs to be done to set it up.
pub unsafe trait RenderTargetBacking {
    /// The ID2D1RenderTarget's ownership is passed out of the function and as such
    /// the caller is now responsible for ensuring the pointer will receive its
    /// Release() call.
    fn create_target(self, factory: &mut ID2D1Factory) -> Result<*mut ID2D1RenderTarget, HRESULT>;
}

#[derive(Clone, Debug)]
pub struct RenderTarget {
    ptr: ComPtr<ID2D1RenderTarget>,
}

#[derive(Copy, Clone, Debug)]
pub struct RenderTag {
    pub file_line: &'static str,
}

struct RenderTagRaw(usize, usize);

#[macro_export]
macro_rules! make_render_tag {
    () => {
        RenderTag {
            file: concat!(file!(), ':', line!())
        }
    }
}

#[macro_export]
macro_rules! set_render_tag {
    ($rt:ident) => {
        $rt.set_tag(make_render_tag!());
    }
}

impl RenderTarget {
    unsafe fn rt<'a>(&self) -> &'a mut ID2D1RenderTarget {
        &mut *self.ptr.raw_value()
    }

    pub unsafe fn hwnd_rt(&self) -> Option<ComPtr<ID2D1HwndRenderTarget>> {
        self.ptr.query_interface().ok()
    }

    unsafe fn make_tag(tag1: D2D1_TAG, tag2: D2D1_TAG) -> Option<RenderTag> {
        if tag1 == 0 {
            None
        } else {
            let raw = RenderTagRaw(tag1 as usize, tag2 as usize);
            let tag = mem::transmute(raw);
            Some(tag)
        }
    }

    pub fn get_factory(&mut self) -> Factory {
        unsafe {
            let mut factory = ComPtr::<ID2D1Factory>::new();
            self.rt().GetFactory(factory.raw_addr());

            Factory::from_ptr(factory)
        }
    }

    pub fn get_size(&self) -> SizeF {
        unsafe {
            let mut size = mem::uninitialized();
            self.rt().GetSize(&mut size);
            SizeF(size)
        }
    }

    pub fn create_solid_color_brush<C: Into<ColorF>>(
        &self, color: C, props: &BrushProperties
    ) -> Result<brush::SolidColor, D2D1Error> {
        unsafe {
            let mut ptr = ComPtr::<ID2D1SolidColorBrush>::new();
            let result = self.rt().CreateSolidColorBrush(&color.into().0, &props.0, ptr.raw_addr());

            if SUCCEEDED(result) {
                Ok(FromRaw::from_raw(ptr.raw_value()))
            } else {
                Err(From::from(result))
            }
        }
    }

    pub fn begin_draw(&mut self) {
        unsafe {
            self.rt().BeginDraw();
        }
    }

    pub fn end_draw(&mut self) -> Result<(), (D2D1Error, Option<RenderTag>)> {
        let mut tag1 = 0;
        let mut tag2 = 0;
        unsafe {
            let result = self.rt().EndDraw(&mut tag1, &mut tag2);

            if SUCCEEDED(result) {
                Ok(())
            } else {
                let tag = RenderTarget::make_tag(tag1, tag2);
                Err((From::from(result), tag))
            }
        }
    }

    pub fn set_tag(&mut self, tag: RenderTag) {
        unsafe {
            let RenderTagRaw(tag1, tag2) = mem::transmute(tag);
            self.rt().SetTags(tag1 as u64, tag2 as u64)
        };
    }

    pub fn get_tag(&mut self) -> Option<RenderTag> {
        let mut tag1 = 0;
        let mut tag2 = 0;
        unsafe {
            self.rt().GetTags(&mut tag1, &mut tag2);
            RenderTarget::make_tag(tag1, tag2)
        }
    }

    pub fn flush(&mut self) -> Result<(), (D2D1Error, Option<RenderTag>)> {
        let mut tag1 = 0;
        let mut tag2 = 0;
        unsafe {
            let result = self.rt().Flush(&mut tag1, &mut tag2);

            if SUCCEEDED(result) {
                Ok(())
            } else {
                let tag = RenderTarget::make_tag(tag1, tag2);
                Err((From::from(result), tag))
            }
        }
    }

    pub fn clear(&mut self, color: &ColorF) {
        unsafe {
            self.rt().Clear(&color.0);
        }
    }

    pub fn draw_line<B: Brush>(
        &mut self, p0: &Point2F, p1: &Point2F, brush: &B, stroke_width: f32,
        stroke_style: Option<&StrokeStyle>
    ) {
        unsafe {
            let stroke_style = match stroke_style {
                Some(s) => s.get_ptr(),
                None => ptr::null_mut(),
            };

            self.rt().DrawLine(
                p0.0,
                p1.0,
                brush.get_ptr(),
                stroke_width,
                stroke_style,
            )
        }
    }

    pub fn draw_rectangle<B: Brush>(
        &mut self, rect: &RectF, brush: &B, stroke_width: f32, stroke_style: Option<&StrokeStyle>
    ) {
        unsafe {
            let stroke_style = match stroke_style {
                Some(s) => s.get_ptr(),
                None => ptr::null_mut(),
            };

            self.rt().DrawRectangle(
                &rect.0,
                brush.get_ptr(),
                stroke_width,
                stroke_style,
            );
        }
    }

    pub fn fill_rectangle<B: Brush>(&mut self, rect: &RectF, brush: &B) {
        unsafe {
            self.rt().FillRectangle(
                &rect.0,
                brush.get_ptr(),
            );
        }
    }

    pub fn draw_rounded_rectangle<B: Brush>(
        &mut self, rect: &RoundedRect, brush: &B, stroke_width: f32, stroke_style: Option<&StrokeStyle>
    ) {
        unsafe {
            let stroke_style = match stroke_style {
                Some(s) => s.get_ptr(),
                None => ptr::null_mut(),
            };

            self.rt().DrawRoundedRectangle(
                &rect.0,
                brush.get_ptr(),
                stroke_width,
                stroke_style,
            );
        }
    }

    pub fn fill_rounded_rectangle<B: Brush>(&mut self, rect: &RoundedRect, brush: &B) {
        unsafe {
            self.rt().FillRoundedRectangle(
                &rect.0,
                brush.get_ptr(),
            );
        }
    }

    pub fn draw_ellipse<B: Brush>(
        &mut self, ellipse: &Ellipse, brush: &B, stroke_width: f32, stroke_style: Option<&StrokeStyle>
    ) {
        unsafe {
            let stroke_style = match stroke_style {
                Some(s) => s.get_ptr(),
                None => ptr::null_mut(),
            };

            self.rt().DrawEllipse(
                &ellipse.0,
                brush.get_ptr(),
                stroke_width,
                stroke_style,
            );
        }
    }

    pub fn fill_ellipse<B: Brush>(&mut self, ellipse: &Ellipse, brush: &B) {
        unsafe {
            self.rt().FillEllipse(
                &ellipse.0,
                brush.get_ptr(),
            );
        }
    }

    pub fn fill_geometry<G: Geometry, B: Brush>(&mut self, geometry: &G, brush: &B) {
        unsafe {
            self.rt().FillGeometry(
                geometry.get_ptr(),
                brush.get_ptr(),
                ptr::null_mut(),
            );
        }
    }

    pub fn fill_geometry_with_opacity<G: Geometry, B: Brush, OB: Brush>(
        &mut self, geometry: &G, brush: &B, opacity_brush: &OB
    ) {
        unsafe {
            self.rt().FillGeometry(
                geometry.get_ptr(),
                brush.get_ptr(),
                opacity_brush.get_ptr(),
            );
        }
    }

    pub fn draw_text<B: Brush>(
        &mut self, text: &str, format: &TextFormat, layout_rect: &RectF, foreground_brush: &B,
        options: &[DrawTextOption],
    ) {
        let text = text.to_wide_null();
        let mut draw_options = D2D1_DRAW_TEXT_OPTIONS_NONE.0;
        for &option in options {
            draw_options |= option as u32;
        }

        unsafe {
            let format = format.get_raw();
            self.rt().DrawText(
                text.as_ptr(),
                text.len() as u32,
                format,
                &layout_rect.0,
                foreground_brush.get_ptr(),
                D2D1_DRAW_TEXT_OPTIONS(draw_options),
                DWRITE_MEASURING_MODE_NATURAL,
            );
        }
    }

    pub fn draw_text_layout<B: Brush>(
        &mut self, origin: &Point2F, layout: &TextLayout, brush: &B, options: &[DrawTextOption],
    ) {
        let mut draw_options = D2D1_DRAW_TEXT_OPTIONS_NONE.0;
        for &option in options {
            draw_options |= option as u32;
        }

        unsafe {
            let layout = layout.get_raw();
            self.rt().DrawTextLayout(
                origin.0,
                layout,
                brush.get_ptr(),
                D2D1_DRAW_TEXT_OPTIONS(draw_options),
            );
        }
    }
}

impl GetRaw for RenderTarget {
    type Raw = ID2D1RenderTarget;
    unsafe fn get_raw(&self) -> *mut ID2D1RenderTarget {
        self.ptr.raw_value()
    }
}

impl FromRaw for RenderTarget {
    type Raw = ID2D1RenderTarget;
    unsafe fn from_raw(raw: *mut ID2D1RenderTarget) -> Self {
        RenderTarget {
            ptr: ComPtr::attach(raw)
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum DrawTextOption {
    NoSnap = 1,
    Clip = 2,
    EnableColorFont = 4,
}
<commit_msg>draw_geometry<commit_after>use std::{ptr, mem};
use winapi::*;
use math::*;
use brush::{self, Brush};
use geometry::{Geometry};
use error::D2D1Error;
use stroke_style::StrokeStyle;
use factory::Factory;
use comptr::ComPtr;
use helpers::{GetRaw, FromRaw, ToWide};
use directwrite::{TextFormat, TextLayout};

/// This trait is intended to be implemented by external APIs who would
/// like to allow a Direct2D interface for drawing onto them. Since the
/// Direct2D creation APIs require more information, this will likely be
/// implemented on Builder objects which contain enough context about
/// the actual backing structure and what needs to be done to set it up.
pub unsafe trait RenderTargetBacking {
    /// The ID2D1RenderTarget's ownership is passed out of the function and as such
    /// the caller is now responsible for ensuring the pointer will receive its
    /// Release() call.
    fn create_target(self, factory: &mut ID2D1Factory) -> Result<*mut ID2D1RenderTarget, HRESULT>;
}

#[derive(Clone, Debug)]
pub struct RenderTarget {
    ptr: ComPtr<ID2D1RenderTarget>,
}

#[derive(Copy, Clone, Debug)]
pub struct RenderTag {
    pub file_line: &'static str,
}

struct RenderTagRaw(usize, usize);

#[macro_export]
macro_rules! make_render_tag {
    () => {
        RenderTag {
            file: concat!(file!(), ':', line!())
        }
    }
}

#[macro_export]
macro_rules! set_render_tag {
    ($rt:ident) => {
        $rt.set_tag(make_render_tag!());
    }
}

impl RenderTarget {
    unsafe fn rt<'a>(&self) -> &'a mut ID2D1RenderTarget {
        &mut *self.ptr.raw_value()
    }

    pub unsafe fn hwnd_rt(&self) -> Option<ComPtr<ID2D1HwndRenderTarget>> {
        self.ptr.query_interface().ok()
    }

    unsafe fn make_tag(tag1: D2D1_TAG, tag2: D2D1_TAG) -> Option<RenderTag> {
        if tag1 == 0 {
            None
        } else {
            let raw = RenderTagRaw(tag1 as usize, tag2 as usize);
            let tag = mem::transmute(raw);
            Some(tag)
        }
    }

    pub fn get_factory(&mut self) -> Factory {
        unsafe {
            let mut factory = ComPtr::<ID2D1Factory>::new();
            self.rt().GetFactory(factory.raw_addr());

            Factory::from_ptr(factory)
        }
    }

    pub fn get_size(&self) -> SizeF {
        unsafe {
            let mut size = mem::uninitialized();
            self.rt().GetSize(&mut size);
            SizeF(size)
        }
    }

    pub fn create_solid_color_brush<C: Into<ColorF>>(
        &self, color: C, props: &BrushProperties
    ) -> Result<brush::SolidColor, D2D1Error> {
        unsafe {
            let mut ptr = ComPtr::<ID2D1SolidColorBrush>::new();
            let result = self.rt().CreateSolidColorBrush(&color.into().0, &props.0, ptr.raw_addr());

            if SUCCEEDED(result) {
                Ok(FromRaw::from_raw(ptr.raw_value()))
            } else {
                Err(From::from(result))
            }
        }
    }

    pub fn begin_draw(&mut self) {
        unsafe {
            self.rt().BeginDraw();
        }
    }

    pub fn end_draw(&mut self) -> Result<(), (D2D1Error, Option<RenderTag>)> {
        let mut tag1 = 0;
        let mut tag2 = 0;
        unsafe {
            let result = self.rt().EndDraw(&mut tag1, &mut tag2);

            if SUCCEEDED(result) {
                Ok(())
            } else {
                let tag = RenderTarget::make_tag(tag1, tag2);
                Err((From::from(result), tag))
            }
        }
    }

    pub fn set_tag(&mut self, tag: RenderTag) {
        unsafe {
            let RenderTagRaw(tag1, tag2) = mem::transmute(tag);
            self.rt().SetTags(tag1 as u64, tag2 as u64)
        };
    }

    pub fn get_tag(&mut self) -> Option<RenderTag> {
        let mut tag1 = 0;
        let mut tag2 = 0;
        unsafe {
            self.rt().GetTags(&mut tag1, &mut tag2);
            RenderTarget::make_tag(tag1, tag2)
        }
    }

    pub fn flush(&mut self) -> Result<(), (D2D1Error, Option<RenderTag>)> {
        let mut tag1 = 0;
        let mut tag2 = 0;
        unsafe {
            let result = self.rt().Flush(&mut tag1, &mut tag2);

            if SUCCEEDED(result) {
                Ok(())
            } else {
                let tag = RenderTarget::make_tag(tag1, tag2);
                Err((From::from(result), tag))
            }
        }
    }

    pub fn clear(&mut self, color: &ColorF) {
        unsafe {
            self.rt().Clear(&color.0);
        }
    }

    pub fn draw_line<B: Brush>(
        &mut self, p0: &Point2F, p1: &Point2F, brush: &B, stroke_width: f32,
        stroke_style: Option<&StrokeStyle>
    ) {
        unsafe {
            let stroke_style = match stroke_style {
                Some(s) => s.get_ptr(),
                None => ptr::null_mut(),
            };

            self.rt().DrawLine(
                p0.0,
                p1.0,
                brush.get_ptr(),
                stroke_width,
                stroke_style,
            )
        }
    }

    pub fn draw_rectangle<B: Brush>(
        &mut self, rect: &RectF, brush: &B, stroke_width: f32, stroke_style: Option<&StrokeStyle>
    ) {
        unsafe {
            let stroke_style = match stroke_style {
                Some(s) => s.get_ptr(),
                None => ptr::null_mut(),
            };

            self.rt().DrawRectangle(
                &rect.0,
                brush.get_ptr(),
                stroke_width,
                stroke_style,
            );
        }
    }

    pub fn fill_rectangle<B: Brush>(&mut self, rect: &RectF, brush: &B) {
        unsafe {
            self.rt().FillRectangle(
                &rect.0,
                brush.get_ptr(),
            );
        }
    }

    pub fn draw_rounded_rectangle<B: Brush>(
        &mut self, rect: &RoundedRect, brush: &B, stroke_width: f32, stroke_style: Option<&StrokeStyle>
    ) {
        unsafe {
            let stroke_style = match stroke_style {
                Some(s) => s.get_ptr(),
                None => ptr::null_mut(),
            };

            self.rt().DrawRoundedRectangle(
                &rect.0,
                brush.get_ptr(),
                stroke_width,
                stroke_style,
            );
        }
    }

    pub fn fill_rounded_rectangle<B: Brush>(&mut self, rect: &RoundedRect, brush: &B) {
        unsafe {
            self.rt().FillRoundedRectangle(
                &rect.0,
                brush.get_ptr(),
            );
        }
    }

    pub fn draw_ellipse<B: Brush>(
        &mut self, ellipse: &Ellipse, brush: &B, stroke_width: f32, stroke_style: Option<&StrokeStyle>
    ) {
        unsafe {
            let stroke_style = match stroke_style {
                Some(s) => s.get_ptr(),
                None => ptr::null_mut(),
            };

            self.rt().DrawEllipse(
                &ellipse.0,
                brush.get_ptr(),
                stroke_width,
                stroke_style,
            );
        }
    }

    pub fn fill_ellipse<B: Brush>(&mut self, ellipse: &Ellipse, brush: &B) {
        unsafe {
            self.rt().FillEllipse(
                &ellipse.0,
                brush.get_ptr(),
            );
        }
    }

    pub fn draw_geometry<G: Geometry, B: Brush>(
        &mut self, geometry: &G, brush: &B, stroke_width: f32, stroke_style: Option<&StrokeStyle>
    ) {
        unsafe {
            let stroke_style = match stroke_style {
                Some(s) => s.get_ptr(),
                None => ptr::null_mut(),
            };

            self.rt().DrawGeometry(
                geometry.get_ptr(),
                brush.get_ptr(),
                stroke_width,
                stroke_style,
            );
        }
    }

    pub fn fill_geometry<G: Geometry, B: Brush>(&mut self, geometry: &G, brush: &B) {
        unsafe {
            self.rt().FillGeometry(
                geometry.get_ptr(),
                brush.get_ptr(),
                ptr::null_mut(),
            );
        }
    }

    pub fn fill_geometry_with_opacity<G: Geometry, B: Brush, OB: Brush>(
        &mut self, geometry: &G, brush: &B, opacity_brush: &OB
    ) {
        unsafe {
            self.rt().FillGeometry(
                geometry.get_ptr(),
                brush.get_ptr(),
                opacity_brush.get_ptr(),
            );
        }
    }

    pub fn draw_text<B: Brush>(
        &mut self, text: &str, format: &TextFormat, layout_rect: &RectF, foreground_brush: &B,
        options: &[DrawTextOption],
    ) {
        let text = text.to_wide_null();
        let mut draw_options = D2D1_DRAW_TEXT_OPTIONS_NONE.0;
        for &option in options {
            draw_options |= option as u32;
        }

        unsafe {
            let format = format.get_raw();
            self.rt().DrawText(
                text.as_ptr(),
                text.len() as u32,
                format,
                &layout_rect.0,
                foreground_brush.get_ptr(),
                D2D1_DRAW_TEXT_OPTIONS(draw_options),
                DWRITE_MEASURING_MODE_NATURAL,
            );
        }
    }

    pub fn draw_text_layout<B: Brush>(
        &mut self, origin: &Point2F, layout: &TextLayout, brush: &B, options: &[DrawTextOption],
    ) {
        let mut draw_options = D2D1_DRAW_TEXT_OPTIONS_NONE.0;
        for &option in options {
            draw_options |= option as u32;
        }

        unsafe {
            let layout = layout.get_raw();
            self.rt().DrawTextLayout(
                origin.0,
                layout,
                brush.get_ptr(),
                D2D1_DRAW_TEXT_OPTIONS(draw_options),
            );
        }
    }
}

impl GetRaw for RenderTarget {
    type Raw = ID2D1RenderTarget;
    unsafe fn get_raw(&self) -> *mut ID2D1RenderTarget {
        self.ptr.raw_value()
    }
}

impl FromRaw for RenderTarget {
    type Raw = ID2D1RenderTarget;
    unsafe fn from_raw(raw: *mut ID2D1RenderTarget) -> Self {
        RenderTarget {
            ptr: ComPtr::attach(raw)
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum DrawTextOption {
    NoSnap = 1,
    Clip = 2,
    EnableColorFont = 4,
}
<|endoftext|>