<commit_before>// Copyright 2017 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.

#![allow(warnings)]

use std::mem;
use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak};
use rustc_data_structures::OnDrop;
use syntax_pos::Span;
use ty::tls;
use ty::maps::Query;
use ty::maps::plumbing::CycleError;
use ty::context::TyCtxt;
use errors::Diagnostic;
use std::process;
use std::fmt;
use std::collections::HashSet;
#[cfg(parallel_queries)]
use {
    rayon_core,
    parking_lot::{Mutex, Condvar},
    std::sync::atomic::Ordering,
    std::thread,
    std::iter,
    std::iter::FromIterator,
    syntax_pos::DUMMY_SP,
    rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable},
};

/// Indicates the state of a query for a given key in a query map
pub(super) enum QueryResult<'tcx> {
    /// An already executing query. The query job can be used to await for its completion
    Started(Lrc<QueryJob<'tcx>>),

    /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic
    Poisoned,
}

/// A span and a query key
#[derive(Clone, Debug)]
pub struct QueryInfo<'tcx> {
    /// The span for a reason this query was required
    pub span: Span,
    pub query: Query<'tcx>,
}

/// A object representing an active query job.
pub struct QueryJob<'tcx> {
    pub info: QueryInfo<'tcx>,

    /// The parent query job which created this job and is implicitly waiting on it.
    pub parent: Option<Lrc<QueryJob<'tcx>>>,

    /// Diagnostic messages which are emitted while the query executes
    pub diagnostics: Lock<Vec<Diagnostic>>,

    #[cfg(parallel_queries)]
    latch: QueryLatch,
}

impl<'tcx> QueryJob<'tcx> {
    /// Creates a new query job
    pub fn new(info: QueryInfo<'tcx>, parent: Option<Lrc<QueryJob<'tcx>>>) -> Self {
        QueryJob {
            diagnostics: Lock::new(Vec::new()),
            info,
            parent,
            #[cfg(parallel_queries)]
            latch: QueryLatch::new(),
        }
    }

    /// Awaits for the query job to complete.
    ///
    /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any
    /// query that means that there is a query cycle, thus this always running a cycle error.
    pub(super) fn await<'lcx>(
        &self,
        tcx: TyCtxt<'_, 'tcx, 'lcx>,
        span: Span,
    ) -> Result<(), CycleError<'tcx>> {
        #[cfg(not(parallel_queries))]
        {
            self.find_cycle_in_stack(tcx, span)
        }

        #[cfg(parallel_queries)]
        {
            tls::with_related_context(tcx, move |icx| {
                let mut waiter = QueryWaiter {
                    query: &icx.query,
                    span,
                    cycle: None,
                    condvar: Condvar::new(),
                };
                self.latch.await(&mut waiter);

                match waiter.cycle {
                    None => Ok(()),
                    Some(cycle) => Err(cycle)
                }
            })
        }
    }

    #[cfg(not(parallel_queries))]
    fn find_cycle_in_stack<'lcx>(
        &self,
        tcx: TyCtxt<'_, 'tcx, 'lcx>,
        span: Span,
    ) -> Result<(), CycleError<'tcx>> {
        // Get the current executing query (waiter) and find the waitee amongst its parents
        let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone());
        let mut cycle = Vec::new();

        while let Some(job) = current_job {
            cycle.insert(0, job.info.clone());

            if &*job as *const _ == self as *const _ {
                // This is the end of the cycle
                // The span entry we included was for the usage
                // of the cycle itself, and not part of the cycle
                // Replace it with the span which caused the cycle to form
                cycle[0].span = span;
                // Find out why the cycle itself was used
                let usage = job.parent.as_ref().map(|parent| {
                    (job.info.span, parent.info.query.clone())
                });
                return Err(CycleError { usage, cycle });
            }

            current_job = job.parent.clone();
        }

        panic!("did not find a cycle")
    }

    /// Signals to waiters that the query is complete.
    ///
    /// This does nothing for single threaded rustc,
    /// as there are no concurrent jobs which could be waiting on us
    pub fn signal_complete(&self, tcx: TyCtxt<'_, 'tcx, '_>) {
        #[cfg(parallel_queries)]
        self.latch.set(tcx);
    }
}

#[cfg(parallel_queries)]
struct QueryWaiter<'a, 'tcx: 'a> {
    query: &'a Option<Lrc<QueryJob<'tcx>>>,
    condvar: Condvar,
    span: Span,
    cycle: Option<CycleError<'tcx>>,
}

#[cfg(parallel_queries)]
impl<'a, 'tcx> QueryWaiter<'a, 'tcx> {
    fn notify(&self, tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) {
        rayon_core::mark_unblocked(registry);
        self.condvar.notify_one();
    }
}

#[cfg(parallel_queries)]
struct QueryLatchInfo {
    complete: bool,
    waiters: Vec<&'static mut QueryWaiter<'static, 'static>>,
}

#[cfg(parallel_queries)]
struct QueryLatch {
    info: Mutex<QueryLatchInfo>,
}

#[cfg(parallel_queries)]
impl QueryLatch {
    fn new() -> Self {
        QueryLatch {
            info: Mutex::new(QueryLatchInfo {
                complete: false,
                waiters: Vec::new(),
            }),
        }
    }

    fn await(&self, waiter: &mut QueryWaiter<'_, '_>) {
        let mut info = self.info.lock();
        if !info.complete {
            let waiter = &*waiter;
            unsafe {
                #[allow(mutable_transmutes)]
                info.waiters.push(mem::transmute(waiter));
            }
            // If this detects a deadlock and the deadlock handler want to resume this thread
            // we have to be in the `wait` call. This is ensured by the deadlock handler
            // getting the self.info lock.
            rayon_core::mark_blocked();
            waiter.condvar.wait(&mut info);
        }
    }

    fn set(&self, tcx: TyCtxt<'_, '_, '_>) {
        let mut info = self.info.lock();
        debug_assert!(!info.complete);
        info.complete = true;
        let registry = rayon_core::Registry::current();
        for waiter in info.waiters.drain(..) {
            waiter.notify(tcx, &registry);
        }
    }

    fn resume_waiter(
        &self,
        waiter: usize,
        error: CycleError
    ) -> &'static mut QueryWaiter<'static, 'static> {
        let mut info = self.info.lock();
        debug_assert!(!info.complete);
        // Remove the waiter from the list of waiters
        let waiter = info.waiters.remove(waiter);

        // Set the cycle error it will be picked it up when resumed
        waiter.cycle = unsafe { Some(mem::transmute(error)) };

        waiter
    }
}

#[cfg(parallel_queries)]
type Ref<'tcx> = *const QueryJob<'tcx>;

#[cfg(parallel_queries)]
type Waiter<'tcx> = (Ref<'tcx>, usize);

#[cfg(parallel_queries)]
fn visit_waiters<'tcx, F>(query_ref: Ref<'tcx>, mut visit: F) -> Option<Option<Waiter<'tcx>>>
where
    F: FnMut(Span, Ref<'tcx>) -> Option<Option<Waiter<'tcx>>>
{
    let query = unsafe { &*query_ref };
    if let Some(ref parent) = query.parent {
        if let Some(cycle) = visit(query.info.span, &**parent as Ref) {
            return Some(cycle);
        }
    }
    for (i, waiter) in query.latch.info.lock().waiters.iter().enumerate() {
        if let Some(ref waiter_query) = waiter.query {
            if visit(waiter.span, &**waiter_query as Ref).is_some() {
                return Some(Some((query_ref, i)));
            }
        }
    }
    None
}

#[cfg(parallel_queries)]
fn cycle_check<'tcx>(query: Ref<'tcx>,
                     span: Span,
                     stack: &mut Vec<(Span, Ref<'tcx>)>,
                     visited: &mut HashSet<Ref<'tcx>>) -> Option<Option<Waiter<'tcx>>> {
    if visited.contains(&query) {
        return if let Some(p) = stack.iter().position(|q| q.1 == query) {
            // Remove previous stack entries
            stack.splice(0..p, iter::empty());
            // Replace the span for the first query with the cycle cause
            stack[0].0 = span;
            Some(None)
        } else {
            None
        }
    }

    visited.insert(query);
    stack.push((span, query));

    let r = visit_waiters(query, |span, successor| {
        cycle_check(successor, span, stack, visited)
    });

    if r.is_none() {
        stack.pop();
    }

    r
}

#[cfg(parallel_queries)]
fn connected_to_root<'tcx>(query: Ref<'tcx>, visited: &mut HashSet<Ref<'tcx>>) -> bool {
    if visited.contains(&query) {
        return false;
    }

    if unsafe { (*query).parent.is_none() } {
        return true;
    }

    visited.insert(query);

    let mut connected = false;

    visit_waiters(query, |_, successor| {
        if connected_to_root(successor, visited) {
            Some(None)
        } else {
            None
        }
    }).is_some()
}

#[cfg(parallel_queries)]
fn query_entry<'tcx>(r: Ref<'tcx>) -> QueryInfo<'tcx> {
    unsafe { (*r).info.clone() }
}

#[cfg(parallel_queries)]
fn remove_cycle<'tcx>(
    jobs: &mut Vec<Ref<'tcx>>,
    wakelist: &mut Vec<&'static mut QueryWaiter<'static, 'static>>,
    tcx: TyCtxt<'_, 'tcx, '_>
) {
    let mut visited = HashSet::new();
    let mut stack = Vec::new();
    if let Some(waiter) = cycle_check(jobs.pop().unwrap(),
                                      DUMMY_SP,
                                      &mut stack,
                                      &mut visited) {
        // Reverse the stack so earlier entries require later entries
        stack.reverse();

        let mut spans: Vec<_> = stack.iter().map(|e| e.0).collect();
        let queries = stack.iter().map(|e| e.1);

        // Shift the spans so that a query is matched the span for its waitee
        let last = spans.pop().unwrap();
        spans.insert(0, last);

        let mut stack: Vec<_> = spans.into_iter().zip(queries).collect();

        // Remove the queries in our cycle from the list of jobs to look at
        for r in &stack {
            jobs.remove_item(&r.1);
        }

        let (waitee_query, waiter_idx) = waiter.unwrap();
        let waitee_query = unsafe { &*waitee_query };

        // Find the queries in the cycle which are
        // connected to queries outside the cycle
        let entry_points: Vec<Ref<'_>> = stack.iter().filter_map(|query| {
            // Mark all the other queries in the cycle as already visited
            let mut visited = HashSet::from_iter(stack.iter().filter_map(|q| {
                if q.1 != query.1 {
                    Some(q.1)
                } else {
                    None
                }
            }));

            if connected_to_root(query.1, &mut visited) {
                Some(query.1)
            } else {
                None
            }
        }).collect();

        // Deterministically pick an entry point
        // FIXME: Sort this instead
        let mut hcx = tcx.create_stable_hashing_context();
        let entry_point = *entry_points.iter().min_by_key(|&&q| {
            let mut stable_hasher = StableHasher::<u64>::new();
            unsafe { (*q).info.query.hash_stable(&mut hcx, &mut stable_hasher); }
            stable_hasher.finish()
        }).unwrap();

        // Shift the stack until our entry point is first
        while stack[0].1 != entry_point {
            let last = stack.pop().unwrap();
            stack.insert(0, last);
        }

        let mut error = CycleError {
            usage: None,
            cycle: stack.iter().map(|&(s, q)| QueryInfo {
                span: s,
                query: unsafe { (*q).info.query.clone() },
            } ).collect(),
        };

        wakelist.push(waitee_query.latch.resume_waiter(waiter_idx, error));
    }
}

#[cfg(parallel_queries)]
pub fn handle_deadlock() {
    use syntax;
    use syntax_pos;

    let registry = rayon_core::Registry::current();

    let gcx_ptr = tls::GCX_PTR.with(|gcx_ptr| {
        gcx_ptr as *const _
    });
    let gcx_ptr = unsafe { &*gcx_ptr };

    let syntax_globals = syntax::GLOBALS.with(|syntax_globals| {
        syntax_globals as *const _
    });
    let syntax_globals = unsafe { &*syntax_globals };

    let syntax_pos_globals = syntax_pos::GLOBALS.with(|syntax_pos_globals| {
        syntax_pos_globals as *const _
    });
    let syntax_pos_globals = unsafe { &*syntax_pos_globals };
    thread::spawn(move || {
        tls::GCX_PTR.set(gcx_ptr, || {
            syntax_pos::GLOBALS.set(syntax_pos_globals, || {
                syntax_pos::GLOBALS.set(syntax_pos_globals, || {
                    tls::with_thread_locals(|| {
                        unsafe {
                            tls::with_global(|tcx| deadlock(tcx, &registry))
                        }
                    })
                })
            })
        })
    });
}

#[cfg(parallel_queries)]
fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) {
    let on_panic = OnDrop(|| {
        eprintln!("deadlock handler panicked, aborting process");
        process::abort();
    });

    let mut wakelist = Vec::new();
    let mut jobs: Vec<_> = tcx.maps.collect_active_jobs().iter().map(|j| &**j as Ref).collect();

    while jobs.len() > 0 {
        remove_cycle(&mut jobs, &mut wakelist, tcx);
    }

    // FIXME: Panic if no cycle is detected

    // FIXME: Write down the conditions when a deadlock happens without a cycle

    // FIXME: Ensure this won't cause a deadlock before we return
    for waiter in wakelist.into_iter() {
        waiter.notify(tcx, registry);
    }

    on_panic.disable();
}
<commit_msg>Use raw pointers<commit_after>// Copyright 2017 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.

#![allow(warnings)]

use std::mem;
use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak};
use rustc_data_structures::OnDrop;
use syntax_pos::Span;
use ty::tls;
use ty::maps::Query;
use ty::maps::plumbing::CycleError;
use ty::context::TyCtxt;
use errors::Diagnostic;
use std::process;
use std::fmt;
use std::collections::HashSet;
#[cfg(parallel_queries)]
use {
    rayon_core,
    parking_lot::{Mutex, Condvar},
    std::sync::atomic::Ordering,
    std::thread,
    std::iter,
    std::iter::FromIterator,
    syntax_pos::DUMMY_SP,
    rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable},
};

/// Indicates the state of a query for a given key in a query map
pub(super) enum QueryResult<'tcx> {
    /// An already executing query. The query job can be used to await for its completion
    Started(Lrc<QueryJob<'tcx>>),

    /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic
    Poisoned,
}

/// A span and a query key
#[derive(Clone, Debug)]
pub struct QueryInfo<'tcx> {
    /// The span for a reason this query was required
    pub span: Span,
    pub query: Query<'tcx>,
}

/// A object representing an active query job.
pub struct QueryJob<'tcx> {
    pub info: QueryInfo<'tcx>,

    /// The parent query job which created this job and is implicitly waiting on it.
    pub parent: Option<Lrc<QueryJob<'tcx>>>,

    /// Diagnostic messages which are emitted while the query executes
    pub diagnostics: Lock<Vec<Diagnostic>>,

    #[cfg(parallel_queries)]
    latch: QueryLatch<'tcx>,
}

impl<'tcx> QueryJob<'tcx> {
    /// Creates a new query job
    pub fn new(info: QueryInfo<'tcx>, parent: Option<Lrc<QueryJob<'tcx>>>) -> Self {
        QueryJob {
            diagnostics: Lock::new(Vec::new()),
            info,
            parent,
            #[cfg(parallel_queries)]
            latch: QueryLatch::new(),
        }
    }

    /// Awaits for the query job to complete.
    ///
    /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any
    /// query that means that there is a query cycle, thus this always running a cycle error.
    pub(super) fn await<'lcx>(
        &self,
        tcx: TyCtxt<'_, 'tcx, 'lcx>,
        span: Span,
    ) -> Result<(), CycleError<'tcx>> {
        #[cfg(not(parallel_queries))]
        {
            self.find_cycle_in_stack(tcx, span)
        }

        #[cfg(parallel_queries)]
        {
            tls::with_related_context(tcx, move |icx| {
                let mut waiter = QueryWaiter {
                    query: &icx.query,
                    span,
                    cycle: None,
                    condvar: Condvar::new(),
                };
                self.latch.await(&mut waiter);

                match waiter.cycle {
                    None => Ok(()),
                    Some(cycle) => Err(cycle)
                }
            })
        }
    }

    #[cfg(not(parallel_queries))]
    fn find_cycle_in_stack<'lcx>(
        &self,
        tcx: TyCtxt<'_, 'tcx, 'lcx>,
        span: Span,
    ) -> Result<(), CycleError<'tcx>> {
        // Get the current executing query (waiter) and find the waitee amongst its parents
        let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone());
        let mut cycle = Vec::new();

        while let Some(job) = current_job {
            cycle.insert(0, job.info.clone());

            if &*job as *const _ == self as *const _ {
                // This is the end of the cycle
                // The span entry we included was for the usage
                // of the cycle itself, and not part of the cycle
                // Replace it with the span which caused the cycle to form
                cycle[0].span = span;
                // Find out why the cycle itself was used
                let usage = job.parent.as_ref().map(|parent| {
                    (job.info.span, parent.info.query.clone())
                });
                return Err(CycleError { usage, cycle });
            }

            current_job = job.parent.clone();
        }

        panic!("did not find a cycle")
    }

    /// Signals to waiters that the query is complete.
    ///
    /// This does nothing for single threaded rustc,
    /// as there are no concurrent jobs which could be waiting on us
    pub fn signal_complete(&self) {
        #[cfg(parallel_queries)]
        self.latch.set();
    }
}

#[cfg(parallel_queries)]
struct QueryWaiter<'tcx> {
    query: *const Option<Lrc<QueryJob<'tcx>>>,
    condvar: Condvar,
    span: Span,
    cycle: Option<CycleError<'tcx>>,
}

#[cfg(parallel_queries)]
impl<'tcx> QueryWaiter<'tcx> {
    fn notify(&self, registry: &rayon_core::Registry) {
        rayon_core::mark_unblocked(registry);
        self.condvar.notify_one();
    }
}

#[cfg(parallel_queries)]
struct QueryLatchInfo<'tcx> {
    complete: bool,
    waiters: Vec<*mut QueryWaiter<'tcx>>,
}

// Required because of raw pointers
#[cfg(parallel_queries)]
unsafe impl<'tcx> Send for QueryLatchInfo<'tcx> {}

#[cfg(parallel_queries)]
struct QueryLatch<'tcx> {
    info: Mutex<QueryLatchInfo<'tcx>>,
}

#[cfg(parallel_queries)]
impl<'tcx> QueryLatch<'tcx> {
    fn new() -> Self {
        QueryLatch {
            info: Mutex::new(QueryLatchInfo {
                complete: false,
                waiters: Vec::new(),
            }),
        }
    }

    fn await(&self, waiter: &mut QueryWaiter<'tcx>) {
        let mut info = self.info.lock();
        if !info.complete {
            info.waiters.push(waiter);
            let condvar = &waiter.condvar;
            // If this detects a deadlock and the deadlock handler want to resume this thread
            // we have to be in the `wait` call. This is ensured by the deadlock handler
            // getting the self.info lock.
            rayon_core::mark_blocked();
            condvar.wait(&mut info);
        }
    }

    fn set(&self) {
        let mut info = self.info.lock();
        debug_assert!(!info.complete);
        info.complete = true;
        let registry = rayon_core::Registry::current();
        for waiter in info.waiters.drain(..) {
            unsafe {
                (*waiter).notify(&registry);
            }
        }
    }

    fn resume_waiter(
        &self,
        waiter: usize,
        error: CycleError<'tcx>
    ) -> *mut QueryWaiter<'tcx> {
        let mut info = self.info.lock();
        debug_assert!(!info.complete);
        // Remove the waiter from the list of waiters
        let waiter = info.waiters.remove(waiter);

        // Set the cycle error it will be picked it up when resumed
        unsafe {
            (*waiter).cycle = Some(error);
        }

        waiter
    }
}

#[cfg(parallel_queries)]
type Ref<'tcx> = *const QueryJob<'tcx>;

#[cfg(parallel_queries)]
type Waiter<'tcx> = (Ref<'tcx>, usize);

#[cfg(parallel_queries)]
fn visit_waiters<'tcx, F>(query_ref: Ref<'tcx>, mut visit: F) -> Option<Option<Waiter<'tcx>>>
where
    F: FnMut(Span, Ref<'tcx>) -> Option<Option<Waiter<'tcx>>>
{
    let query = unsafe { &*query_ref };
    if let Some(ref parent) = query.parent {
        if let Some(cycle) = visit(query.info.span, &**parent as Ref) {
            return Some(cycle);
        }
    }
    for (i, &waiter) in query.latch.info.lock().waiters.iter().enumerate() {
        unsafe {
            if let Some(ref waiter_query) = *(*waiter).query {
                if visit((*waiter).span, &**waiter_query as Ref).is_some() {
                    return Some(Some((query_ref, i)));
                }
            }
        }
    }
    None
}

#[cfg(parallel_queries)]
fn cycle_check<'tcx>(query: Ref<'tcx>,
                     span: Span,
                     stack: &mut Vec<(Span, Ref<'tcx>)>,
                     visited: &mut HashSet<Ref<'tcx>>) -> Option<Option<Waiter<'tcx>>> {
    if visited.contains(&query) {
        return if let Some(p) = stack.iter().position(|q| q.1 == query) {
            // Remove previous stack entries
            stack.splice(0..p, iter::empty());
            // Replace the span for the first query with the cycle cause
            stack[0].0 = span;
            Some(None)
        } else {
            None
        }
    }

    visited.insert(query);
    stack.push((span, query));

    let r = visit_waiters(query, |span, successor| {
        cycle_check(successor, span, stack, visited)
    });

    if r.is_none() {
        stack.pop();
    }

    r
}

#[cfg(parallel_queries)]
fn connected_to_root<'tcx>(query: Ref<'tcx>, visited: &mut HashSet<Ref<'tcx>>) -> bool {
    if visited.contains(&query) {
        return false;
    }

    if unsafe { (*query).parent.is_none() } {
        return true;
    }

    visited.insert(query);

    let mut connected = false;

    visit_waiters(query, |_, successor| {
        if connected_to_root(successor, visited) {
            Some(None)
        } else {
            None
        }
    }).is_some()
}

#[cfg(parallel_queries)]
fn query_entry<'tcx>(r: Ref<'tcx>) -> QueryInfo<'tcx> {
    unsafe { (*r).info.clone() }
}

#[cfg(parallel_queries)]
fn remove_cycle<'tcx>(
    jobs: &mut Vec<Ref<'tcx>>,
    wakelist: &mut Vec<*mut QueryWaiter<'tcx>>,
    tcx: TyCtxt<'_, 'tcx, '_>
) {
    let mut visited = HashSet::new();
    let mut stack = Vec::new();
    if let Some(waiter) = cycle_check(jobs.pop().unwrap(),
                                      DUMMY_SP,
                                      &mut stack,
                                      &mut visited) {
        // Reverse the stack so earlier entries require later entries
        stack.reverse();

        let mut spans: Vec<_> = stack.iter().map(|e| e.0).collect();
        let queries = stack.iter().map(|e| e.1);

        // Shift the spans so that a query is matched the span for its waitee
        let last = spans.pop().unwrap();
        spans.insert(0, last);

        let mut stack: Vec<_> = spans.into_iter().zip(queries).collect();

        // Remove the queries in our cycle from the list of jobs to look at
        for r in &stack {
            jobs.remove_item(&r.1);
        }

        let (waitee_query, waiter_idx) = waiter.unwrap();
        let waitee_query = unsafe { &*waitee_query };

        // Find the queries in the cycle which are
        // connected to queries outside the cycle
        let entry_points: Vec<Ref<'_>> = stack.iter().filter_map(|query| {
            // Mark all the other queries in the cycle as already visited
            let mut visited = HashSet::from_iter(stack.iter().filter_map(|q| {
                if q.1 != query.1 {
                    Some(q.1)
                } else {
                    None
                }
            }));

            if connected_to_root(query.1, &mut visited) {
                Some(query.1)
            } else {
                None
            }
        }).collect();

        // Deterministically pick an entry point
        // FIXME: Sort this instead
        let mut hcx = tcx.create_stable_hashing_context();
        let entry_point = *entry_points.iter().min_by_key(|&&q| {
            let mut stable_hasher = StableHasher::<u64>::new();
            unsafe { (*q).info.query.hash_stable(&mut hcx, &mut stable_hasher); }
            stable_hasher.finish()
        }).unwrap();

        // Shift the stack until our entry point is first
        while stack[0].1 != entry_point {
            let last = stack.pop().unwrap();
            stack.insert(0, last);
        }

        let mut error = CycleError {
            usage: None,
            cycle: stack.iter().map(|&(s, q)| QueryInfo {
                span: s,
                query: unsafe { (*q).info.query.clone() },
            } ).collect(),
        };

        wakelist.push(waitee_query.latch.resume_waiter(waiter_idx, error));
    }
}

#[cfg(parallel_queries)]
pub fn handle_deadlock() {
    use syntax;
    use syntax_pos;

    let registry = rayon_core::Registry::current();

    let gcx_ptr = tls::GCX_PTR.with(|gcx_ptr| {
        gcx_ptr as *const _
    });
    let gcx_ptr = unsafe { &*gcx_ptr };

    let syntax_globals = syntax::GLOBALS.with(|syntax_globals| {
        syntax_globals as *const _
    });
    let syntax_globals = unsafe { &*syntax_globals };

    let syntax_pos_globals = syntax_pos::GLOBALS.with(|syntax_pos_globals| {
        syntax_pos_globals as *const _
    });
    let syntax_pos_globals = unsafe { &*syntax_pos_globals };
    thread::spawn(move || {
        tls::GCX_PTR.set(gcx_ptr, || {
            syntax_pos::GLOBALS.set(syntax_pos_globals, || {
                syntax_pos::GLOBALS.set(syntax_pos_globals, || {
                    tls::with_thread_locals(|| {
                        unsafe {
                            tls::with_global(|tcx| deadlock(tcx, &registry))
                        }
                    })
                })
            })
        })
    });
}

#[cfg(parallel_queries)]
fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) {
    let on_panic = OnDrop(|| {
        eprintln!("deadlock handler panicked, aborting process");
        process::abort();
    });

    let mut wakelist = Vec::new();
    let mut jobs: Vec<_> = tcx.maps.collect_active_jobs().iter().map(|j| &**j as Ref).collect();

    while jobs.len() > 0 {
        remove_cycle(&mut jobs, &mut wakelist, tcx);
    }

    // FIXME: Panic if no cycle is detected

    // FIXME: Write down the conditions when a deadlock happens without a cycle

    // FIXME: Ensure this won't cause a deadlock before we return
    for waiter in wakelist.into_iter() {
        unsafe {
            (*waiter).notify(registry);
        }
    }

    on_panic.disable();
}
<|endoftext|>


<commit_before>pub struct List<T> {
    head: Link<T>,
}

type Link<T> = Option<Box<Node<T>>>;

struct Node<T> {
    elem: T,
    next: Link<T>,
}

pub struct IntoIter<T>(List<T>);

pub struct Iter<'a, T:'a> {
    next: Option<&'a Node<T>>,
}

impl<T> List<T> {
    pub fn new() -> Self {
        List { head: None }
    }

    pub fn push(&mut self, elem: T) {
        let new_node = Box::new(Node {
            elem: elem,
            next: self.head.take(),
        });

        self.head = Some(new_node);
    }

    pub fn pop(&mut self) -> Option<T> {
        self.head.take().map(|node| {
            let node = *node;
            self.head = node.next;
            node.elem
        })
    }

    pub fn peek(&self) -> Option<&T> {
        self.head.as_ref().map(|node| {
            &node.elem
        })
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.head.as_mut().map(|node| {
            &mut node.elem
        })
    }

    pub fn into_iter(self) -> IntoIter<T> {
        IntoIter(self)
    }

    pub fn iter(&self) -> Iter<T> {
        Iter { next: self.head.as_ref().map(|node| &**node) }
    }

    pub fn iter_mut(&self) -> IterMut<T> {
        IterMut { next: self.head.as_mut().map(|node| &mut **node) }
    }
}

impl<T> Drop for List<T> {
    fn drop(&mut self) {
        let mut cur_link = self.head.take();
        while let Some(mut boxed_node) = cur_link {
            cur_link = boxed_node.next.take();
        }
    }
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.pop()
    }
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        self.next.map(|node| {
            self.next = node.next.as_ref().map(|node| &**node);
            &node.elem
        })
    }
}

pub struct IterMut<'a, T: 'a> {
    next: Option<&'a mut Node<T>>,
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        self.next.take().map(|node| {
            self.next = node.next.as_mut().map(|node| &mut **node);
            &mut node.elem
        })
    }
}

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

    #[test]
    fn basics() {
        let mut list = List::new();

        // Check empty list behaves right
        assert_eq!(list.pop(), None);

        // Populate list
        list.push(1);
        list.push(2);
        list.push(3);

        // Check normal removal
        assert_eq!(list.pop(), Some(3));
        assert_eq!(list.pop(), Some(2));

        // Push some more just to make sure nothing's corrupted
        list.push(4);
        list.push(5);

        // Check normal removal
        assert_eq!(list.pop(), Some(5));
        assert_eq!(list.pop(), Some(4));

        // Check exhaustion
        assert_eq!(list.pop(), Some(1));
        assert_eq!(list.pop(), None);
    }

    #[test]
    fn into_iter() {
        let mut list = List::new();
        list.push(1); list.push(2); list.push(3);

        let mut iter = list.into_iter();
        assert_eq!(iter.next(), Some(3));
        assert_eq!(iter.next(), Some(2));
        assert_eq!(iter.next(), Some(1));
    }

    #[test]
    fn iter() {
        let mut list = List::new();
        list.push(1); list.push(2); list.push(3);

        let mut iter = list.iter();
        assert_eq!(iter.next(), Some(&3));
        assert_eq!(iter.next(), Some(&2));
        assert_eq!(iter.next(), Some(&1));
    }

    #[test]
    fn iter_mut() {
        let mut list = List::new();
        list.push(1); list.push(2); list.push(3);

        let mut iter = list.iter_mut();
        assert_eq!(iter.next(), Some(&mut 3));
        assert_eq!(iter.next(), Some(&mut 2));
        assert_eq!(iter.next(), Some(&mut 1));
    }
}
<commit_msg>fix second typo<commit_after>pub struct List<T> {
    head: Link<T>,
}

type Link<T> = Option<Box<Node<T>>>;

struct Node<T> {
    elem: T,
    next: Link<T>,
}

pub struct IntoIter<T>(List<T>);

pub struct Iter<'a, T:'a> {
    next: Option<&'a Node<T>>,
}

impl<T> List<T> {
    pub fn new() -> Self {
        List { head: None }
    }

    pub fn push(&mut self, elem: T) {
        let new_node = Box::new(Node {
            elem: elem,
            next: self.head.take(),
        });

        self.head = Some(new_node);
    }

    pub fn pop(&mut self) -> Option<T> {
        self.head.take().map(|node| {
            let node = *node;
            self.head = node.next;
            node.elem
        })
    }

    pub fn peek(&self) -> Option<&T> {
        self.head.as_ref().map(|node| {
            &node.elem
        })
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.head.as_mut().map(|node| {
            &mut node.elem
        })
    }

    pub fn into_iter(self) -> IntoIter<T> {
        IntoIter(self)
    }

    pub fn iter(&self) -> Iter<T> {
        Iter { next: self.head.as_ref().map(|node| &**node) }
    }

    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut { next: self.head.as_mut().map(|node| &mut **node) }
    }
}

impl<T> Drop for List<T> {
    fn drop(&mut self) {
        let mut cur_link = self.head.take();
        while let Some(mut boxed_node) = cur_link {
            cur_link = boxed_node.next.take();
        }
    }
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.pop()
    }
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        self.next.map(|node| {
            self.next = node.next.as_ref().map(|node| &**node);
            &node.elem
        })
    }
}

pub struct IterMut<'a, T: 'a> {
    next: Option<&'a mut Node<T>>,
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        self.next.take().map(|node| {
            self.next = node.next.as_mut().map(|node| &mut **node);
            &mut node.elem
        })
    }
}

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

    #[test]
    fn basics() {
        let mut list = List::new();

        // Check empty list behaves right
        assert_eq!(list.pop(), None);

        // Populate list
        list.push(1);
        list.push(2);
        list.push(3);

        // Check normal removal
        assert_eq!(list.pop(), Some(3));
        assert_eq!(list.pop(), Some(2));

        // Push some more just to make sure nothing's corrupted
        list.push(4);
        list.push(5);

        // Check normal removal
        assert_eq!(list.pop(), Some(5));
        assert_eq!(list.pop(), Some(4));

        // Check exhaustion
        assert_eq!(list.pop(), Some(1));
        assert_eq!(list.pop(), None);
    }

    #[test]
    fn into_iter() {
        let mut list = List::new();
        list.push(1); list.push(2); list.push(3);

        let mut iter = list.into_iter();
        assert_eq!(iter.next(), Some(3));
        assert_eq!(iter.next(), Some(2));
        assert_eq!(iter.next(), Some(1));
    }

    #[test]
    fn iter() {
        let mut list = List::new();
        list.push(1); list.push(2); list.push(3);

        let mut iter = list.iter();
        assert_eq!(iter.next(), Some(&3));
        assert_eq!(iter.next(), Some(&2));
        assert_eq!(iter.next(), Some(&1));
    }

    #[test]
    fn iter_mut() {
        let mut list = List::new();
        list.push(1); list.push(2); list.push(3);

        let mut iter = list.iter_mut();
        assert_eq!(iter.next(), Some(&mut 3));
        assert_eq!(iter.next(), Some(&mut 2));
        assert_eq!(iter.next(), Some(&mut 1));
    }
}
<|endoftext|>


<commit_before>use server::transactions::TxnId;
use server::transactions::*;
use ram::cell::{Cell, ReadError, WriteError};
use ram::types::{Id};
use std::sync::Arc;
use std::io;

pub enum TxnError {
    CannotFindAServer,
    IoError(io::Error),
    CannotBegin,
    NotRealizable,
    TooManyRetry,
}

pub struct Transaction {
    pub tid: TxnId,
    pub client: Arc<manager::SyncServiceClient>
}

impl Transaction {

    pub fn read(id: &Id) -> Result<Option<Cell>, TxnError> {
        unimplemented!()
    }
    pub fn write(cell: &Cell) -> Result<(), TxnError> {
        unimplemented!()
    }
    pub fn update(cell: &Cell) -> Result<(), TxnError> {
        unimplemented!()
    }
    pub fn remove(id: &Id) -> Result<(), TxnError> {
        unimplemented!()
    }

    pub fn prepare() -> Result<(), TxnError> {
        unimplemented!()
    }
    pub fn commit() -> Result<(), TxnError> {
        unimplemented!()
    }
    pub fn abort() -> Result<(), TxnError> {
        unimplemented!()
    }
}<commit_msg>client transaction proxy<commit_after>use server::transactions::TxnId;
use server::transactions::*;
use ram::cell::{Cell, ReadError, WriteError};
use ram::types::{Id};
use std::sync::Arc;
use std::io;

use bifrost::rpc::RPCError;

pub enum TxnError {
    CannotFindAServer,
    IoError(io::Error),
    CannotBegin,
    NotRealizable,
    TooManyRetry,
    InternalError,
    RPCError(RPCError),
    ManagerError(TMError),
    ReadError(ReadError),
    WriteError(WriteError),
    PrepareError(TMPrepareResult),
    CommitError(EndResult),
    AbortError(AbortResult)
}

pub struct Transaction {
    pub tid: TxnId,
    pub client: Arc<manager::SyncServiceClient>
}

impl Transaction {

    pub fn read(&self, id: &Id) -> Result<Option<Cell>, TxnError> {
        match self.client.read(&self.tid, id) {
            Ok(Ok(TxnExecResult::Accepted(cell))) => Ok(Some(cell)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn write(&self, cell: &Cell) -> Result<(), TxnError> {
        match self.client.write(&self.tid, cell) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn update(&self, cell: &Cell) -> Result<(), TxnError> {
        match self.client.update(&self.tid, cell) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn remove(&self, id: &Id) -> Result<(), TxnError> {
        match self.client.remove(&self.tid, id) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }

    pub fn prepare(&self) -> Result<(), TxnError> {
        match self.client.prepare(&self.tid) {
            Ok(Ok(TMPrepareResult::Success)) => Ok(()),
            Ok(Ok(TMPrepareResult::DMPrepareError
                  (DMPrepareResult::NotRealizable))) =>
                Err(TxnError::NotRealizable),
            Ok(Ok(TMPrepareResult::DMCommitError(
                      DMCommitResult::CellChanged(_, _)))) =>
                Err(TxnError::NotRealizable),
            Ok(Ok(rpr)) => Err(TxnError::PrepareError(rpr)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn commit(&self) -> Result<(), TxnError> {
        match self.client.commit(&self.tid) {
            Ok(Ok(EndResult::Success)) => Ok(()),
            Ok(Ok(EndResult::SomeLocksNotReleased)) => Ok(()),
            Ok(Ok(er)) => Err(TxnError::CommitError(er)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn abort(&self) -> Result<(), TxnError> {
        match self.client.abort(&self.tid) {
            Ok(Ok(AbortResult::Success(_))) => Ok(()),
            Ok(Ok(ar)) => Err(TxnError::AbortError(ar)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
}<|endoftext|>


<commit_before>use cairo;
use cairo::MatrixTrait;

use aspect_ratio::AspectRatio;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
use util::*;
use viewbox::*;

pub fn draw_in_viewport<F>(vx: f64, vy: f64, vw: f64, vh: f64,
                           clip_before_layer_push: bool,
                           do_clip: bool,
                           vbox: Option<ViewBox>,
                           preserve_aspect_ratio: AspectRatio,
                           mut affine: cairo::Matrix,
                           draw_ctx: *const RsvgDrawingCtx,
                           draw_fn: F)
    where F: FnOnce()
{
    // width or height set to 0 disables rendering of the element
    // https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
    // https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute

    if double_equals(vw, 0.0) || double_equals(vh, 0.0) {
        return;
    }

    let vbox_size;

    if let Some(vbox) = vbox {
        // the preserveAspectRatio attribute is only used if viewBox is specified
        // https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

        let (x, y, w, h) = preserve_aspect_ratio.compute(vbox.0.width, vbox.0.height,
                                                         vx, vy, vw, vh);

        affine.translate(x, y);
        affine.scale(w / vbox.0.width, h / vbox.0.height);
        affine.translate(-vbox.0.x, -vbox.0.y);

        vbox_size = (vbox.0.width, vbox.0.height);

        if clip_before_layer_push && do_clip {
            drawing_ctx::add_clipping_rect(draw_ctx, vbox.0.x, vbox.0.y, vbox.0.width, vbox.0.height);
        }
    } else {
        affine.translate(vx, vy);
        vbox_size = (vw, vh);
    }

    drawing_ctx::push_view_box(draw_ctx, vbox_size.0, vbox_size.1);
    drawing_ctx::push_discrete_layer(draw_ctx);

    if !clip_before_layer_push && do_clip {
        drawing_ctx::add_clipping_rect(draw_ctx, vx, vy, vw, vh);
    }

    drawing_ctx::set_current_state_affine(draw_ctx, affine);

    draw_fn();

    drawing_ctx::pop_discrete_layer(draw_ctx);
    drawing_ctx::pop_view_box(draw_ctx);
}
<commit_msg>Implement draw_in_viewport() indirectly so we can have some tests<commit_after>use cairo;
use cairo::MatrixTrait;

use aspect_ratio::AspectRatio;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
use util::*;
use viewbox::*;

pub fn draw_in_viewport<F>(vx: f64, vy: f64, vw: f64, vh: f64,
                           clip_before_layer_push: bool,
                           do_clip: bool,
                           vbox: Option<ViewBox>,
                           preserve_aspect_ratio: AspectRatio,
                           affine: cairo::Matrix,
                           draw_ctx: *const RsvgDrawingCtx,
                           draw_fn: F)
    where F: FnOnce()
{
    let mut ctx = RsvgDrawingCtxWrapper(draw_ctx);

    in_viewport(&mut ctx,
                vx, vy, vw, vh,
                clip_before_layer_push,
                do_clip,
                vbox,
                preserve_aspect_ratio,
                affine,
                draw_fn);
}

trait ViewportCtx {
    fn push_view_box(&mut self, width: f64, height: f64);
    fn pop_view_box(&mut self, );
    fn push_discrete_layer(&mut self);
    fn pop_discrete_layer(&mut self);
    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64);
    fn set_affine(&mut self, affine: cairo::Matrix);
}

struct RsvgDrawingCtxWrapper(pub *const RsvgDrawingCtx);

impl ViewportCtx for RsvgDrawingCtxWrapper {
    fn push_view_box(&mut self, width: f64, height: f64) {
        drawing_ctx::push_view_box(self.0, width, height);
    }

    fn pop_view_box(&mut self) {
        drawing_ctx::pop_view_box(self.0);
    }

    fn push_discrete_layer(&mut self) {
        drawing_ctx::push_discrete_layer(self.0);
    }

    fn pop_discrete_layer(&mut self) {
        drawing_ctx::pop_discrete_layer(self.0);
    }

    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
        drawing_ctx::add_clipping_rect(self.0, x, y, w, h);
    }

    fn set_affine(&mut self, affine: cairo::Matrix) {
        drawing_ctx::set_current_state_affine(self.0, affine);
    }
}

fn in_viewport<F>(ctx: &mut ViewportCtx,
                  vx: f64, vy: f64, vw: f64, vh: f64,
                  clip_before_layer_push: bool,
                  do_clip: bool,
                  vbox: Option<ViewBox>,
                  preserve_aspect_ratio: AspectRatio,
                  mut affine: cairo::Matrix,
                  draw_fn: F)
    where F: FnOnce()
{
    // width or height set to 0 disables rendering of the element
    // https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
    // https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute

    if double_equals(vw, 0.0) || double_equals(vh, 0.0) {
        return;
    }

    let vbox_size;

    if let Some(vbox) = vbox {
        // the preserveAspectRatio attribute is only used if viewBox is specified
        // https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

        let (x, y, w, h) = preserve_aspect_ratio.compute(vbox.0.width, vbox.0.height,
                                                         vx, vy, vw, vh);

        affine.translate(x, y);
        affine.scale(w / vbox.0.width, h / vbox.0.height);
        affine.translate(-vbox.0.x, -vbox.0.y);

        vbox_size = (vbox.0.width, vbox.0.height);

        if clip_before_layer_push && do_clip {
            ctx.add_clipping_rect(vbox.0.x, vbox.0.y, vbox.0.width, vbox.0.height);
        }
    } else {
        affine.translate(vx, vy);
        vbox_size = (vw, vh);
    }

    ctx.push_view_box(vbox_size.0, vbox_size.1);
    ctx.push_discrete_layer();

    if !clip_before_layer_push && do_clip {
        ctx.add_clipping_rect(vx, vy, vw, vh);
    }

    ctx.set_affine(affine);

    draw_fn();

    ctx.pop_discrete_layer();
    ctx.pop_view_box();
}
<|endoftext|>


<commit_before>#[test]
fn client_fetches_accounts() {
    unimplemented!()
}

#[test]
fn client_gets_current_user() {
    unimplemented!()
}
<commit_msg>test skeletons for API Accounts Methods<commit_after>// API Methods: Accounts
#[test]
fn client_fetches_account() {
    unimplemented!()
}

#[test]
fn client_gets_current_user() {
    unimplemented!()
}

#[test]
fn client_update_current_user() {
    unimplemented!()
}

#[test]
fn client_get_account_followers() {
    unimplemented!()
}

#[test]
fn client_get_who_account_is_following() {
    unimplemented!()
}

#[test]
fn client_get_account_statuses() {
    unimplemented!()
}

#[test]
fn client_follow_account() {
    unimplemented!()
}

#[test]
fn client_unfullow_account() {
    unimplemented!()
}

#[test]
fn client_mute_account() {
    unimplemented!()
}

#[test]
fn client_unmute_account() {
    unimplemented!()
}

#[test]
fn client_get_account_relationships() {
    unimplemented!()
}

#[test]
fn client_search_accounts() {
    unimplemented!()
}

// API Methods: Accounts
// #[test]
// fn client_() {
//     unimplemented!()
// }
<|endoftext|>


<commit_before>use std::error::Error;
use std::io::Write;
use std::io::stderr;

use ansi_term::Colour::Red;

/// Print an Error type and its cause recursively
///
/// The error is printed with "Error NNNN :" as prefix, where "NNNN" is a number which increases
/// which each recursion into the errors cause. The error description is used to visualize what
/// failed and if there is a cause "-- caused by:" is appended, and the cause is printed on the next
/// line.
///
/// Example output:
///
/// ```ignore
/// Error    1 : Some error -- caused by:
/// Error    2 : Some other error -- caused by:
/// Error    3 : Yet another Error -- caused by:
/// ...
///
/// Error <NNNN> : <Error description>
/// ```
pub fn trace_error(e: &Error) {
    print_trace_maxdepth(count_error_causes(e), e, ::std::u64::MAX);
    write!(stderr(), "\n").ok();
}

/// Print an Error type and its cause recursively, but only `max` levels
///
/// Output is the same as for `trace_error()`, though there are only `max` levels printed.
pub fn trace_error_maxdepth(e: &Error, max: u64) {
    let n = count_error_causes(e);
    let msg = Red.blink().paint(format!("{}/{} Levels of errors will be printed\n",
                                        (if max > n { n } else { max }), n));
    write!(stderr(), "{}", msg).ok();
    print_trace_maxdepth(n, e, max);
    write!(stderr(), "").ok();
}

/// Print an Error type and its cause recursively with the debug!() macro
///
/// Output is the same as for `trace_error()`.
pub fn trace_error_dbg(e: &Error) {
    print_trace_dbg(0, e);
}

/// Helper function for `trace_error()` and `trace_error_maxdepth()`.
///
/// Returns the cause of the last processed error in the recursion, so `None` if all errors where
/// processed.
fn print_trace_maxdepth(idx: u64, e: &Error, max: u64) -> Option<&Error> {
    if e.cause().is_some() && idx > 0 {
        match print_trace_maxdepth(idx - 1, e.cause().unwrap(), max) {
            None    => write!(stderr(), "\n").ok(),
            Some(_) => write!(stderr(), " -- caused:\n").ok(),
        };
    } else {
        write!(stderr(), "\n").ok();
    }
    write!(stderr(), "{}: {}", Red.paint(format!("ERROR[{:>4}]", idx)), e.description()).ok();
    e.cause()
}

/// Count errors in `Error::cause()` recursively
fn count_error_causes(e: &Error) -> u64 {
    1 + if e.cause().is_some() { count_error_causes(e.cause().unwrap()) } else { 0 }
}

fn print_trace_dbg(idx: u64, e: &Error) {
    debug!("{}: {}", Red.blink().paint(format!("ERROR[{:>4}]", idx)), e.description());
    if e.cause().is_some() {
        print_trace_dbg(idx + 1, e.cause().unwrap());
    }
}

<commit_msg>Add utility for calling trace_error() and exit()<commit_after>use std::error::Error;
use std::io::Write;
use std::io::stderr;

use ansi_term::Colour::Red;

/// Print an Error type and its cause recursively
///
/// The error is printed with "Error NNNN :" as prefix, where "NNNN" is a number which increases
/// which each recursion into the errors cause. The error description is used to visualize what
/// failed and if there is a cause "-- caused by:" is appended, and the cause is printed on the next
/// line.
///
/// Example output:
///
/// ```ignore
/// Error    1 : Some error -- caused by:
/// Error    2 : Some other error -- caused by:
/// Error    3 : Yet another Error -- caused by:
/// ...
///
/// Error <NNNN> : <Error description>
/// ```
pub fn trace_error(e: &Error) {
    print_trace_maxdepth(count_error_causes(e), e, ::std::u64::MAX);
    write!(stderr(), "\n").ok();
}

/// Convenience function: calls `trace_error()` with `e` and afterwards `std::process::exit()`
/// with `code`
pub fn trace_error_exit(e: &Error, code: i32) {
    use std::process::exit;

    trace_error(e);
    exit(code);
}

/// Print an Error type and its cause recursively, but only `max` levels
///
/// Output is the same as for `trace_error()`, though there are only `max` levels printed.
pub fn trace_error_maxdepth(e: &Error, max: u64) {
    let n = count_error_causes(e);
    let msg = Red.blink().paint(format!("{}/{} Levels of errors will be printed\n",
                                        (if max > n { n } else { max }), n));
    write!(stderr(), "{}", msg).ok();
    print_trace_maxdepth(n, e, max);
    write!(stderr(), "").ok();
}

/// Print an Error type and its cause recursively with the debug!() macro
///
/// Output is the same as for `trace_error()`.
pub fn trace_error_dbg(e: &Error) {
    print_trace_dbg(0, e);
}

/// Helper function for `trace_error()` and `trace_error_maxdepth()`.
///
/// Returns the cause of the last processed error in the recursion, so `None` if all errors where
/// processed.
fn print_trace_maxdepth(idx: u64, e: &Error, max: u64) -> Option<&Error> {
    if e.cause().is_some() && idx > 0 {
        match print_trace_maxdepth(idx - 1, e.cause().unwrap(), max) {
            None    => write!(stderr(), "\n").ok(),
            Some(_) => write!(stderr(), " -- caused:\n").ok(),
        };
    } else {
        write!(stderr(), "\n").ok();
    }
    write!(stderr(), "{}: {}", Red.paint(format!("ERROR[{:>4}]", idx)), e.description()).ok();
    e.cause()
}

/// Count errors in `Error::cause()` recursively
fn count_error_causes(e: &Error) -> u64 {
    1 + if e.cause().is_some() { count_error_causes(e.cause().unwrap()) } else { 0 }
}

fn print_trace_dbg(idx: u64, e: &Error) {
    debug!("{}: {}", Red.blink().paint(format!("ERROR[{:>4}]", idx)), e.description());
    if e.cause().is_some() {
        print_trace_dbg(idx + 1, e.cause().unwrap());
    }
}

<|endoftext|>


<commit_before>use slack_hook::{Attachment, AttachmentBuilder, Field, PayloadBuilder, Slack, SlackText, SlackLink};
use slack_hook::SlackTextContent::{Text, Link};

use taste::{BenchmarkResult, TastingResult};

pub struct SlackNotifier {
    conn: Slack,
    channel: String,
    github_repo: String,
}

impl SlackNotifier {
    pub fn new(hook_url: &str, channel: &str, repo_url: &str) -> SlackNotifier {
        SlackNotifier {
            conn: Slack::new(hook_url).unwrap(),
            channel: String::from(channel),
            github_repo: String::from(repo_url),
        }
    }

    pub fn notify(&self, res: &TastingResult) -> Result<(), String> {
        let payload = PayloadBuilder::new()
            .text(vec![Text("I've tasted commit _".into()),
                       Text(format!("\"{}\"_ -- ", res.commit_msg.lines().next().unwrap())
                           .into()),
                       Link(SlackLink::new(&format!("{}/commit/{}",
                                                    self.github_repo,
                                                    res.commit_id),
                                           &res.commit_id[0..6]))]
                .as_slice())
            .attachments(result_to_attachments(&res))
            .channel(self.channel.clone())
            .username("taster")
            .icon_emoji(":tea:")
            .build()
            .unwrap();

        match self.conn.send(&payload) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}

fn result_to_attachments(res: &TastingResult) -> Vec<Attachment> {
    let color = if !res.build || !res.bench {
        "danger"
    } else {
        "good"
    };

    let title = if !res.build {
        "Build failure!"
    } else if !res.bench {
        "Benchmark failure!"
    } else {
        "Performance results:"
    };

    let taste = if !res.build || !res.bench {
        "was inedible"
    } else {
        "tasted nice"
    };

    let mut attachments = Vec::new();
    let build_att = AttachmentBuilder::new("")
        .title(format!("It {}.", taste))
        .fields(vec![Field {
                         title: "Build".into(),
                         value: SlackText::new(if res.build { "success" } else { "failed" }),
                         short: Some(true),
                     },
                     Field {
                         title: "Benchmark".into(),
                         value: SlackText::new(if res.build { "success" } else { "failed" }),
                         short: Some(true),
                     }])
        .color(color)
        .build()
        .unwrap();
    attachments.push(build_att);

    match res.results {
        None => (),
        Some(ref r) => {
            for res in r {
                let mut nv = res.iter()
                    .map(|(k, v)| {
                        let val = match v {
                            &BenchmarkResult::Neutral(ref s, _) => s,
                            _ => unimplemented!(),
                        };
                        Field {
                            title: k.clone(),
                            value: SlackText::new(val.clone()),
                            short: Some(true),
                        }
                    })
                    .collect::<Vec<_>>();
                nv.sort_by(|a, b| b.title.cmp(&a.title));
                let att = AttachmentBuilder::new(format!("It {}.", taste))
                    .color(color)
                    .title(title)
                    .fields(nv)
                    .build()
                    .unwrap();
                attachments.push(att);
            }
        }
    }
    attachments
}
<commit_msg>Use benchmark success value, not build success.<commit_after>use slack_hook::{Attachment, AttachmentBuilder, Field, PayloadBuilder, Slack, SlackText, SlackLink};
use slack_hook::SlackTextContent::{Text, Link};

use taste::{BenchmarkResult, TastingResult};

pub struct SlackNotifier {
    conn: Slack,
    channel: String,
    github_repo: String,
}

impl SlackNotifier {
    pub fn new(hook_url: &str, channel: &str, repo_url: &str) -> SlackNotifier {
        SlackNotifier {
            conn: Slack::new(hook_url).unwrap(),
            channel: String::from(channel),
            github_repo: String::from(repo_url),
        }
    }

    pub fn notify(&self, res: &TastingResult) -> Result<(), String> {
        println!("{:#?}", res);
        let payload = PayloadBuilder::new()
            .text(vec![Text("I've tasted commit _".into()),
                       Text(format!("\"{}\"_ -- ", res.commit_msg.lines().next().unwrap())
                           .into()),
                       Link(SlackLink::new(&format!("{}/commit/{}",
                                                    self.github_repo,
                                                    res.commit_id),
                                           &res.commit_id[0..6]))]
                .as_slice())
            .attachments(result_to_attachments(&res))
            .channel(self.channel.clone())
            .username("taster")
            .icon_emoji(":tea:")
            .build()
            .unwrap();

        match self.conn.send(&payload) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}

fn result_to_attachments(res: &TastingResult) -> Vec<Attachment> {
    let color = if !res.build || !res.bench {
        "danger"
    } else {
        "good"
    };

    let title = if !res.build {
        "Build failure!"
    } else if !res.bench {
        "Benchmark failure!"
    } else {
        "Performance results:"
    };

    let taste = if !res.build || !res.bench {
        "was inedible"
    } else {
        "tasted nice"
    };

    let mut attachments = Vec::new();
    let build_att = AttachmentBuilder::new("")
        .title(format!("It {}.", taste))
        .fields(vec![Field {
                         title: "Build".into(),
                         value: SlackText::new(if res.build { "success" } else { "failed" }),
                         short: Some(true),
                     },
                     Field {
                         title: "Benchmark".into(),
                         value: SlackText::new(if res.benchmark { "success" } else { "failed" }),
                         short: Some(true),
                     }])
        .color(color)
        .build()
        .unwrap();
    attachments.push(build_att);

    match res.results {
        None => (),
        Some(ref r) => {
            for res in r {
                let mut nv = res.iter()
                    .map(|(k, v)| {
                        let val = match v {
                            &BenchmarkResult::Neutral(ref s, _) => s,
                            _ => unimplemented!(),
                        };
                        Field {
                            title: k.clone(),
                            value: SlackText::new(val.clone()),
                            short: Some(true),
                        }
                    })
                    .collect::<Vec<_>>();
                nv.sort_by(|a, b| b.title.cmp(&a.title));
                let att = AttachmentBuilder::new(format!("It {}.", taste))
                    .color(color)
                    .title(title)
                    .fields(nv)
                    .build()
                    .unwrap();
                attachments.push(att);
            }
        }
    }
    attachments
}
<|endoftext|>


<commit_before>use UndoCmd;

/// `UndoStack` maintains a stack of `UndoCmd`s that can be undone and redone by using methods
/// on the `UndoStack`.
///
/// `UndoStack` will notice when it's state changes to either dirty or clean, and the user can
/// set methods that should be called for either state change. This is useful for example if
/// you want to automatically enable or disable undo or redo buttons based on there are any
/// more actions that can be undone or redone.
pub struct UndoStack<'a> {
    // All commands on the stack.
    stack: Vec<Box<UndoCmd + 'a>>,
    // Current position in the stack.
    len: usize,
    // Called when the state changes from dirty to clean.
    on_clean: Option<Box<FnMut() + 'a>>,
    // Called when the state changes from clean to dirty.
    on_dirty: Option<Box<FnMut() + 'a>>,
}

impl<'a> UndoStack<'a> {
    /// Creates a new `UndoStack`.
    #[inline]
    pub fn new() -> Self {
        UndoStack {
            stack: Vec::new(),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Creates a new `UndoStack` with the specified capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        UndoStack {
            stack: Vec::with_capacity(capacity),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Returns the capacity of the `UndoStack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.stack.capacity()
    }

    /// Reserves capacity for at least `additional` more commands to be inserted in the given stack.
    /// The stack may reserve more space to avoid frequent reallocations.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.stack.reserve(additional);
    }

    /// Shrinks the capacity of the `UndoStack` as much as possible.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.stack.shrink_to_fit();
    }

    /// Sets what should happen if the state changes from dirty to clean.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// Note: An empty stack is clean, so the first push will not trigger this method.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_clean(|| x += 1);
    /// ```
    #[inline]
    pub fn on_clean<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_clean = Some(Box::new(f));
        self
    }

    /// Sets what should happen if the state changes from clean to dirty.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_dirty(|| x += 1);
    /// ```
    #[inline]
    pub fn on_dirty<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_dirty = Some(Box::new(f));
        self
    }

    /// Returns `true` if the state of the stack is clean, `false` otherwise.
    #[inline]
    pub fn is_clean(&self) -> bool {
        self.len == self.stack.len()
    }

    /// Returns `true` if the state of the stack is dirty, `false` otherwise.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        !self.is_clean()
    }

    /// Pushes a `UndoCmd` to the top of the `UndoStack` and executes its [`redo`] method.
    /// This pops off all `UndoCmd`s that is above the active command from the `UndoStack`.
    ///
    /// If `cmd`s id is equal to the current top command, the two commands are merged.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn push<T>(&mut self, mut cmd: T)
        where T: UndoCmd + 'a,
    {
        let is_dirty = self.is_dirty();
        let len = self.len;
        // Pop off all elements after len from stack.
        self.stack.truncate(len);
        cmd.redo();

        // Check if we should merge cmd with the top command on stack.
        let id = cmd.id();
        if len > 0 && id.is_some() && id == unsafe { self.stack.get_unchecked(len - 1).id() } {

            // MergeCmd is the result of the merging.
            struct MergeCmd<'a> {
                cmd1: Box<UndoCmd + 'a>,
                cmd2: Box<UndoCmd + 'a>,
            }

            impl<'a> UndoCmd for MergeCmd<'a> {
                #[inline]
                fn redo(&mut self) {
                    self.cmd1.redo();
                    self.cmd2.redo();
                }

                #[inline]
                fn undo(&mut self) {
                    self.cmd2.undo();
                    self.cmd1.undo();
                }

                #[inline]
                fn id(&self) -> Option<u64> {
                    self.cmd1.id()
                }
            }

            // Merge the command with the one on the top of the stack.
            let cmd = MergeCmd {
                cmd1: unsafe {
                    // Unchecked pop.
                    self.stack.set_len(len - 1);
                    ::std::ptr::read(self.stack.get_unchecked(self.stack.len()))
                },
                cmd2: Box::new(cmd),
            };
            self.stack.push(Box::new(cmd));
        } else {
            self.stack.push(Box::new(cmd));
            self.len += 1;
        }

        // State is always clean after a push, check if it was dirty before.
        if is_dirty {
            if let Some(ref mut f) = self.on_clean {
                f();
            }
        }
    }

    /// Calls the [`redo`] method for the active `UndoCmd` and sets the next `UndoCmd` as the new
    /// active one.
    ///
    /// Calling this method when there are no more commands to redo does nothing.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn redo(&mut self) {
        if self.len < self.stack.len() {
            let is_dirty = self.is_dirty();
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.redo();
            }
            self.len += 1;
            // Check if stack went from dirty to clean.
            if is_dirty && self.is_clean() {
                if let Some(ref mut f) = self.on_clean {
                    f();
                }
            }
        }
    }

    /// Calls the [`undo`] method for the active `UndoCmd` and sets the previous `UndoCmd` as the
    /// new active one.
    ///
    /// Calling this method when there are no more commands to undo does nothing.
    ///
    /// [`undo`]: trait.UndoCmd.html#tymethod.undo
    pub fn undo(&mut self) {
        if self.len > 0 {
            let is_clean = self.is_clean();
            self.len -= 1;
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.undo();
            }
            // Check if stack went from clean to dirty.
            if is_clean && self.is_dirty() {
                if let Some(ref mut f) = self.on_dirty {
                    f();
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use {UndoStack, UndoCmd};

    #[test]
    fn pop() {
        use std::rc::Rc;
        use std::cell::{Cell, RefCell};

        /// Pops an element from a vector.
        #[derive(Clone)]
        struct PopCmd {
            vec: Rc<RefCell<Vec<i32>>>,
            e: Option<i32>,
        }

        impl UndoCmd for PopCmd {
            fn redo(&mut self) {
                self.e = self.vec.borrow_mut().pop();
            }

            fn undo(&mut self) {
                self.vec.borrow_mut().push(self.e.unwrap());
                self.e = None;
            }
        }

        let a = Cell::new(0);
        let b = Cell::new(0);
        // We need to use Rc<RefCell> since all commands are going to mutate the vec.
        let vec = Rc::new(RefCell::new(vec![1, 2, 3]));
        let mut undo_stack = UndoStack::with_capacity(3)
            .on_clean(|| a.set(1))
            .on_dirty(|| b.set(1));

        let cmd = PopCmd { vec: vec.clone(), e: None };
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());

        assert!(vec.borrow().is_empty());

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        undo_stack.undo();
        undo_stack.undo();

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.push(cmd.clone());
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.redo();
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));
    }
}
<commit_msg>Use no-op for on_clean and on_dirty by default<commit_after>use UndoCmd;

/// `UndoStack` maintains a stack of `UndoCmd`s that can be undone and redone by using methods
/// on the `UndoStack`.
///
/// `UndoStack` will notice when it's state changes to either dirty or clean, and the user can
/// set methods that should be called for either state change. This is useful for example if
/// you want to automatically enable or disable undo or redo buttons based on there are any
/// more actions that can be undone or redone.
pub struct UndoStack<'a> {
    // All commands on the stack.
    stack: Vec<Box<UndoCmd + 'a>>,
    // Current position in the stack.
    len: usize,
    // Called when the state changes from dirty to clean.
    on_clean: Box<FnMut() + 'a>,
    // Called when the state changes from clean to dirty.
    on_dirty: Box<FnMut() + 'a>,
}

impl<'a> UndoStack<'a> {
    /// Creates a new `UndoStack`.
    #[inline]
    pub fn new() -> Self {
        UndoStack {
            stack: Vec::new(),
            len: 0,
            on_clean: Box::new(|| {}),
            on_dirty: Box::new(|| {}),
        }
    }

    /// Creates a new `UndoStack` with the specified capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        UndoStack {
            stack: Vec::with_capacity(capacity),
            len: 0,
            on_clean: Box::new(|| {}),
            on_dirty: Box::new(|| {}),
        }
    }

    /// Returns the capacity of the `UndoStack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.stack.capacity()
    }

    /// Reserves capacity for at least `additional` more commands to be inserted in the given stack.
    /// The stack may reserve more space to avoid frequent reallocations.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.stack.reserve(additional);
    }

    /// Shrinks the capacity of the `UndoStack` as much as possible.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.stack.shrink_to_fit();
    }

    /// Sets what should happen if the state changes from dirty to clean.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// Note: An empty stack is clean, so the first push will not trigger this method.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_clean(|| x += 1);
    /// ```
    #[inline]
    pub fn on_clean<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_clean = Box::new(f);
        self
    }

    /// Sets what should happen if the state changes from clean to dirty.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_dirty(|| x += 1);
    /// ```
    #[inline]
    pub fn on_dirty<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_dirty = Box::new(f);
        self
    }

    /// Returns `true` if the state of the stack is clean, `false` otherwise.
    #[inline]
    pub fn is_clean(&self) -> bool {
        self.len == self.stack.len()
    }

    /// Returns `true` if the state of the stack is dirty, `false` otherwise.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        !self.is_clean()
    }

    /// Pushes a `UndoCmd` to the top of the `UndoStack` and executes its [`redo`] method.
    /// This pops off all `UndoCmd`s that is above the active command from the `UndoStack`.
    ///
    /// If `cmd`s id is equal to the current top command, the two commands are merged.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn push<T>(&mut self, mut cmd: T)
        where T: UndoCmd + 'a,
    {
        let is_dirty = self.is_dirty();
        let len = self.len;
        // Pop off all elements after len from stack.
        self.stack.truncate(len);
        cmd.redo();

        // Check if we should merge cmd with the top command on stack.
        let id = cmd.id();
        if len > 0 && id.is_some() && id == unsafe { self.stack.get_unchecked(len - 1).id() } {

            // MergeCmd is the result of the merging.
            struct MergeCmd<'a> {
                cmd1: Box<UndoCmd + 'a>,
                cmd2: Box<UndoCmd + 'a>,
            }

            impl<'a> UndoCmd for MergeCmd<'a> {
                #[inline]
                fn redo(&mut self) {
                    self.cmd1.redo();
                    self.cmd2.redo();
                }

                #[inline]
                fn undo(&mut self) {
                    self.cmd2.undo();
                    self.cmd1.undo();
                }

                #[inline]
                fn id(&self) -> Option<u64> {
                    self.cmd1.id()
                }
            }

            // Merge the command with the one on the top of the stack.
            let cmd = MergeCmd {
                cmd1: unsafe {
                    // Unchecked pop.
                    self.stack.set_len(len - 1);
                    ::std::ptr::read(self.stack.get_unchecked(self.stack.len()))
                },
                cmd2: Box::new(cmd),
            };
            self.stack.push(Box::new(cmd));
        } else {
            self.stack.push(Box::new(cmd));
            self.len += 1;
        }

        // State is always clean after a push, check if it was dirty before.
        if is_dirty {
            let ref mut f = self.on_clean;
            f();
        }
    }

    /// Calls the [`redo`] method for the active `UndoCmd` and sets the next `UndoCmd` as the new
    /// active one.
    ///
    /// Calling this method when there are no more commands to redo does nothing.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn redo(&mut self) {
        if self.len < self.stack.len() {
            let is_dirty = self.is_dirty();
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.redo();
            }
            self.len += 1;
            // Check if stack went from dirty to clean.
            if is_dirty && self.is_clean() {
                let ref mut f = self.on_clean;
                f();
            }
        }
    }

    /// Calls the [`undo`] method for the active `UndoCmd` and sets the previous `UndoCmd` as the
    /// new active one.
    ///
    /// Calling this method when there are no more commands to undo does nothing.
    ///
    /// [`undo`]: trait.UndoCmd.html#tymethod.undo
    pub fn undo(&mut self) {
        if self.len > 0 {
            let is_clean = self.is_clean();
            self.len -= 1;
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.undo();
            }
            // Check if stack went from clean to dirty.
            if is_clean && self.is_dirty() {
                let ref mut f = self.on_dirty;
                f();
            }
        }
    }
}

#[cfg(test)]
mod test {
    use {UndoStack, UndoCmd};

    #[test]
    fn pop() {
        use std::rc::Rc;
        use std::cell::{Cell, RefCell};

        /// Pops an element from a vector.
        #[derive(Clone)]
        struct PopCmd {
            vec: Rc<RefCell<Vec<i32>>>,
            e: Option<i32>,
        }

        impl UndoCmd for PopCmd {
            fn redo(&mut self) {
                self.e = self.vec.borrow_mut().pop();
            }

            fn undo(&mut self) {
                self.vec.borrow_mut().push(self.e.unwrap());
                self.e = None;
            }
        }

        let a = Cell::new(0);
        let b = Cell::new(0);
        // We need to use Rc<RefCell> since all commands are going to mutate the vec.
        let vec = Rc::new(RefCell::new(vec![1, 2, 3]));
        let mut undo_stack = UndoStack::with_capacity(3)
            .on_clean(|| a.set(1))
            .on_dirty(|| b.set(1));

        let cmd = PopCmd { vec: vec.clone(), e: None };
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());

        assert!(vec.borrow().is_empty());

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        undo_stack.undo();
        undo_stack.undo();

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.push(cmd.clone());
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.redo();
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));
    }
}
<|endoftext|>


<commit_before>/// The state of a single unit
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct Unit {
    pub position: [u64; 2],
    pub angle: u64,
    pub speed_vector: [u64; 2],
    pub health: u64,
}

/// A player has an ID and consists of 0..N `Unit`s
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct Player {
    pub id: u32,
    pub units: Vec<Unit>,
}

impl Player {
    pub fn new(id: u32) -> Player {
        Player{
            id: id,
            units: vec![],
        }
    }
}

/// The whole game consists of N players
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct Game {
    pub players: Vec<Player>,
}

/// The world consists of an x and y size
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct World {
    pub x: u64,
    pub y: u64,
    pub game: Game,
}

impl World {
    pub fn new(x: u64, y: u64) -> World {
        World {
            x: x,
            y: y,
            game: Game{
                players: vec![],
            }
        }
    }
}

<commit_msg>state: Add constructor and update method to Unit<commit_after>/// The state of a single unit
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct Unit {
    /// X/Y position in the world in mm
    pub position: [u64; 2],
    /// Angle of the unit in milli degrees
    pub angle: u32,
    /// Direction and speed of the movement. The angle of the movement may be different then the
    /// angle of the unit. The unit is mm per milli second.
    pub speed_vector: [u64; 2],
    /// Health of the unit
    pub health: u64,
}

impl Unit {
    pub fn new(position: [u64;2]) -> Unit {
        println!("Create unit at {:?}", position);
        Unit {
            position: position,
            angle: 0,
            speed_vector: [0,0],
            health: 100_0000,
        }
    }
    pub fn update(&mut self, dt_ms: u64) {
        self.position[0] += self.speed_vector[0]*dt_ms;
        self.position[1] += self.speed_vector[1]*dt_ms;
    }
}

/// A player has an ID and consists of 0..N `Unit`s
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct Player {
    pub id: u32,
    pub units: Vec<Unit>,
}

impl Player {
    pub fn new(id: u32) -> Player {
        Player{
            id: id,
            units: vec![],
        }
    }
}

/// The whole game consists of N players
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct Game {
    pub players: Vec<Player>,
}

/// The world consists of an x and y size
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct World {
    /// Width of the world in mm
    pub x: u64,
    /// Height of the world in mm
    pub y: u64,
    pub game: Game,
}

impl World {
    pub fn new(x: u64, y: u64) -> World {
        World {
            x: x,
            y: y,
            game: Game{
                players: vec![],
            }
        }
    }
}

<|endoftext|>


<commit_before>#![warn(clippy::copy_iterator)]

#[derive(Copy, Clone)]
struct Countdown(u8);

impl Iterator for Countdown {
    type Item = u8;

    fn next(&mut self) -> Option<u8> {
        self.0.checked_sub(1).map(|c| {
            self.0 = c;
            c
        })
    }
}

fn main() {
    let my_iterator = Countdown(5);
    let a: Vec<_> = my_iterator.take(1).collect();
    assert_eq!(a.len(), 1);
    let b: Vec<_> = my_iterator.collect();
    assert_eq!(b.len(), 5);
}
<commit_msg>Fix copy_iterator uitest<commit_after>#![warn(clippy::copy_iterator)]

#[derive(Copy, Clone)]
struct Countdown(u8);

impl Iterator for Countdown {
    type Item = u8;

    fn next(&mut self) -> Option<u8> {
        self.0.checked_sub(1).map(|c| {
            self.0 = c;
            c
        })
    }
}

fn main() {
    let my_iterator = Countdown(5);
    assert_eq!(my_iterator.take(1).count(), 1);
    assert_eq!(my_iterator.count(), 5);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::timer::{
    sleep,
    Timer,
};
use std::io::net::ip::SocketAddr;
use std::rand::{
    task_rng,
    Rng,
};
use std::sync::{
    Arc,
    RWLock,
    Mutex,
};
use std::time::Duration;

use member::{
    Member,
    MemberState,
};

use gossip;
use gossip::Gossip;

use message::Message;

use config::Config;

pub struct Membership {
    meta: Arc<MembershipMeta>,

    /// Local incarnation number
    inc: u32,
}

impl Membership {
    /// Create the network listeners
    pub fn bind(config: Config) -> Result<Membership, String> {
        let gossip = Gossip::new(config.bind_addr);
        if let Err(e) = gossip {
            return Err(e);
        }

        let members = Vec::new();

        Ok(Membership {
            meta: Arc::new(MembershipMeta {
                config: config,
                members: RWLock::new(members),
                gossip: Mutex::new(gossip.unwrap()),

                ack_senders: Arc::new(Mutex::new(HashMap::new())),

                seq: Mutex::new(0),
                probe_index: Mutex::new(0),
            }),

            inc: 0,
        })
    }

    pub fn start(&mut self) {
        self.start_gossip_listening();
        self.start_probing();
    }

    /// Join a existing cluster
    pub fn join(&mut self, name: String, addr: SocketAddr) {
        let member = Member {
            name: name,
            addr: addr,
            state: MemberState::Alive,
            inc: 0,
        };

        {
            let mut members = self.meta.members.write();
            members.push(member);
        }

        self.start();
    }

    fn start_probing(&mut self) {
        if self.meta.config.probe_interval.is_zero() {
            return;
        }

        let meta = self.meta.clone();
        let duration = self.meta.config.probe_interval;

        spawn(proc() {
            loop {
                sleep(duration);
                meta.probe();
            }
        });
    }

    fn start_gossip_listening(&mut self) {
        let meta = self.meta.clone();

        spawn(proc() {
            loop {
                if let Some((msg, from)) = meta.recv_msg() {
                    meta.handle_message(msg, from);
                }
            }
        })
    }
}

struct MembershipMeta {
    config: Config,

    members: RWLock<Vec<Member>>,

    gossip: Mutex<Gossip>,

    ack_senders: Arc<Mutex<HashMap<u32, Sender<()>>>>,

    /// local sequence number
    seq: Mutex<u32>,

    probe_index: Mutex<uint>,
}

impl MembershipMeta {
    fn recv_msg(&self) -> Option<(Message, SocketAddr)> {
        let mut gossip = self.gossip.lock();

        gossip.udp.set_read_timeout(Some(1));

        let mut buf = [0u8, ..gossip::UDP_MAX_SIZE];
        let result = gossip.udp.recv_from(&mut buf);
        if let Err(_) = result {
            return None;
        }

        let (count, from) = result.unwrap();
        let mut buf = buf[..count];
        match Message::read(&mut buf) {
            Ok(msg) => {
                println!("Received message from {} => {}", from, msg);
                Some((msg, from))
            },
            Err(e) => {
                println!("Failed to decode message from {} => {}", from, e);
                None
            },
        }
    }

    fn handle_message(&self, msg: Message, from: SocketAddr) {
        match msg {
            Message::Ping {
                seq,
                name,
            } => {
                if name != self.config.name {
                    println!("Got ping for unexpected member `{}`", name);
                    return;
                }
                self.gossip.lock().ack(seq, from);
            },

            Message::Ack {
                seq,
            } => {
                if let Some(sender) = self.ack_senders.lock().remove(&seq) {
                    sender.send(());
                }
            },

            _ => {},
        }
    }

    /// Used to perform a single round of failure detection and gossip
    fn probe(&self) {
        let probe_index = { *self.probe_index.lock() };
        let members_len = { self.members.read().len() };

        if probe_index >= members_len {
            self.reset_members();
            (*self.probe_index.lock()) = 0;
        }

        let mut member_to_be_probed = None;
        {
            let members = self.members.read();
            let mut probe_index = self.probe_index.lock();
            while *probe_index < members.len() {
                let member = &members[*probe_index];
                (*probe_index) += 1;
                if member.name == self.config.name
                   || member.state == MemberState::Dead {
                    continue;
                }
                member_to_be_probed = Some((*member).clone())
            }
        }

        if let Some(member) = member_to_be_probed {
            self.probe_member(member);
        }
    }

    fn probe_member(&self, member: Member) {
        println!("Start probing {}", member);
        let seq = self.next_seq();
        self.gossip.lock().ping(seq, member.name, member.addr);
        if let Some(_) = self.wait_ack(seq, self.config.probe_timeout) {
            println!("Ack {} confirmed.", seq);
            return;
        }

        println!("Ack {} timeout.", seq);
    }

    fn wait_ack(&self, seq: u32, duration: Duration) -> Option<()> {
        let (tx, rx) = channel();
        self.ack_senders.lock().insert(seq, tx);
        let mut timer = Timer::new().unwrap();
        let timeout = timer.oneshot(duration);

        select!(
            () = rx.recv() => Some(()),
            () = timeout.recv() => {
                self.ack_senders.lock().remove(&seq);
                None
            }
        )
    }

    /// Used when the `probe_index` wraps around. It will reap the dead members
    /// and shuffle the member list
    fn reset_members(&self) { // TODO
        let mut rng = task_rng();
        rng.shuffle(self.members.write().as_mut_slice());
    }

    fn next_seq(&self) -> u32 {
        let mut seq = self.seq.lock();
        (*seq) += 1;
        *seq
    }
}
<commit_msg>Handle message in another task<commit_after>use std::collections::HashMap;
use std::io::timer::Timer;
use std::io::net::ip::SocketAddr;
use std::rand::{
    task_rng,
    Rng,
};
use std::sync::{
    Arc,
    RWLock,
    Mutex,
};
use std::time::Duration;

use member::{
    Member,
    MemberState,
};

use gossip;
use gossip::Gossip;

use message::Message;

use config::Config;

pub struct Membership {
    meta: Arc<MembershipMeta>,

    message_sender: Arc<Mutex<Option<Sender<(Message, SocketAddr)>>>>,

    /// Local incarnation number
    inc: u32,
}

impl Membership {
    /// Create the network listeners
    pub fn bind(config: Config) -> Result<Membership, String> {
        let gossip = Gossip::new(config.bind_addr);
        if let Err(e) = gossip {
            return Err(e);
        }

        let members = Vec::new();

        Ok(Membership {
            meta: Arc::new(MembershipMeta {
                config: config,
                members: RWLock::new(members),
                gossip: Mutex::new(gossip.unwrap()),

                ack_senders: Mutex::new(HashMap::new()),

                seq: Mutex::new(0),
                probe_index: Mutex::new(0),
            }),

            message_sender: Arc::new(Mutex::new(None)),

            inc: 0,
        })
    }

    pub fn start(&mut self) {
        self.start_gossip_listening();
        self.start_probing();
    }

    /// Join a existing cluster
    pub fn join(&mut self, name: String, addr: SocketAddr) {
        let member = Member {
            name: name,
            addr: addr,
            state: MemberState::Alive,
            inc: 0,
        };

        {
            let mut members = self.meta.members.write();
            members.push(member);
        }

        self.start();
    }

    fn start_probing(&mut self) {
        if self.meta.config.probe_interval.is_zero() {
            return;
        }

        let meta = self.meta.clone();

        spawn(proc() {
            let mut timer = Timer::new().unwrap();
            let timeout = timer.periodic(meta.config.probe_interval);

            loop {
                meta.probe();

                timeout.recv();
            }
        });
    }

    fn start_gossip_listening(&mut self) {
        let meta = self.meta.clone();
        let tx = self.message_sender.clone();
        // Receiver message from network
        spawn(proc() {
            loop {
                if let Some((msg, from)) = meta.recv_msg() {
                    if let Some(ref tx) = *tx.lock() {
                        tx.send((msg, from));
                    }
                }
            }
        });

        let meta = self.meta.clone();
        let message_sender = self.message_sender.clone();
        // Handle messages
        spawn(proc() {
            let (tx, rx) = channel();
            *message_sender.lock() = Some(tx);
            loop {
                let (msg, from) = rx.recv();
                meta.handle_message(msg, from);
            }
        });
    }
}

struct MembershipMeta {
    config: Config,

    members: RWLock<Vec<Member>>,

    gossip: Mutex<Gossip>,

    ack_senders: Mutex<HashMap<u32, Sender<()>>>,

    /// local sequence number
    seq: Mutex<u32>,

    probe_index: Mutex<uint>,
}

impl MembershipMeta {
    fn recv_msg(&self) -> Option<(Message, SocketAddr)> {
        let mut gossip = self.gossip.lock();

        gossip.udp.set_read_timeout(Some(1));

        let mut buf = [0u8, ..gossip::UDP_MAX_SIZE];
        let result = gossip.udp.recv_from(&mut buf);
        if let Err(_) = result {
            return None;
        }

        let (count, from) = result.unwrap();
        let mut buf = buf[..count];
        match Message::read(&mut buf) {
            Ok(msg) => {
                println!("Received message from {} => {}", from, msg);
                Some((msg, from))
            },
            Err(e) => {
                println!("Failed to decode message from {} => {}", from, e);
                None
            },
        }
    }

    fn handle_message(&self, msg: Message, from: SocketAddr) {
        match msg {
            Message::Ping {
                seq,
                name,
            } => {
                if name != self.config.name {
                    println!("Got ping for unexpected member `{}`", name);
                    return;
                }
                self.gossip.lock().ack(seq, from);
            },

            Message::Ack {
                seq,
            } => {
                if let Some(sender) = self.ack_senders.lock().remove(&seq) {
                    sender.send(());
                }
            },

            _ => {},
        }
    }

    /// Used to perform a single round of failure detection and gossip
    fn probe(&self) {
        let probe_index = { *self.probe_index.lock() };
        let members_len = { self.members.read().len() };

        if probe_index >= members_len {
            self.reset_members();
            (*self.probe_index.lock()) = 0;
        }

        let mut member_to_be_probed = None;
        {
            let members = self.members.read();
            let mut probe_index = self.probe_index.lock();
            while *probe_index < members.len() {
                let member = &members[*probe_index];
                (*probe_index) += 1;
                if member.name == self.config.name
                   || member.state == MemberState::Dead {
                    continue;
                }
                member_to_be_probed = Some((*member).clone())
            }
        }

        if let Some(member) = member_to_be_probed {
            self.probe_member(member);
        }
    }

    fn probe_member(&self, member: Member) {
        println!("Start probing {}", member);
        let seq = self.next_seq();
        self.gossip.lock().ping(seq, member.name, member.addr);
        if let Some(_) = self.wait_ack(seq, self.config.probe_timeout) {
            println!("Ack {} confirmed.", seq);
            return;
        }

        println!("Ack {} timeout.", seq);
    }

    fn wait_ack(&self, seq: u32, duration: Duration) -> Option<()> {
        let (tx, rx) = channel();
        self.ack_senders.lock().insert(seq, tx);
        let mut timer = Timer::new().unwrap();
        let timeout = timer.oneshot(duration);

        select!(
            () = rx.recv() => Some(()),
            () = timeout.recv() => {
                self.ack_senders.lock().remove(&seq);
                None
            }
        )
    }

    /// Used when the `probe_index` wraps around. It will reap the dead members
    /// and shuffle the member list
    fn reset_members(&self) { // TODO
        let mut rng = task_rng();
        rng.shuffle(self.members.write().as_mut_slice());
    }

    fn next_seq(&self) -> u32 {
        let mut seq = self.seq.lock();
        (*seq) += 1;
        *seq
    }
}
<|endoftext|>


<commit_before>//! Interface with distributed storage - e.g. Ceph/RADOS and etcd.
//!
//! The `store` module has several key pieces of functionality:
//! - Sending/receiving marshaled chunks/encoded files/subtrees/commits to and from the store.
//! - Caching already sent/received blobs.
//! - Coordinating refs with the consensus.
//!
//! As marshaling coalesces into a usable module, it will become more obvious exactly what
//! functionality is required.
<commit_msg>Initial store structures<commit_after>//! Interface with distributed storage - e.g. Ceph/RADOS and etcd.
//!
//! The `store` module has several key pieces of functionality:
//! - Sending/receiving marshaled chunks/encoded files/subtrees/commits to and from the store.
//! - Caching already sent/received blobs.
//! - Coordinating refs with the consensus.
//!
//! As marshaling coalesces into a usable module, it will become more obvious exactly what
//! functionality is required.

use std::ffi::CString;

use rad::{RadosConnectionBuilder, RadosConnection, RadosContext};

use errors::Result;
use marshal::Chunk;
use repository::CephConfig;

pub struct ObjectStore {
    connection: RadosConnection,
}

impl ObjectStore {
    pub fn connect(conf: &CephConfig) -> Result<ObjectStore> {
        let mut ceph_conf = conf.conf_dir.clone();
        ceph_conf.push("ceph.conf");

        let mut ceph_keyring = conf.conf_dir.clone();
        ceph_keyring.push(format!("ceph.{}.keyring", conf.user.to_str().unwrap()));

        let connection = RadosConnectionBuilder::with_user(&*conf.user)?
            .read_conf_file(CString::new(ceph_conf.to_str().unwrap()).unwrap())?
            .conf_set(
                c!("keyring"),
                CString::new(ceph_keyring.to_str().unwrap()).unwrap(),
            )?
            .connect()?;

        Ok(ObjectStore { connection })
    }
}

pub struct ObjectStoreContext {
    context: RadosContext,
}
<|endoftext|>


<commit_before>mod types;
mod parser;

pub use self::types::{
  MAX_FIXED_ORDER,
  SubFrame,
  Data,
  Fixed,
  EntropyCodingMethod, CodingMethod, PartitionedRice, PartitionedRiceContents,
};

pub use self::parser::subframe_parser;
<commit_msg>Export the LPC types from the subframe module<commit_after>mod types;
mod parser;

pub use self::types::{
  MAX_FIXED_ORDER, MAX_LPC_ORDER,
  SubFrame,
  Data,
  Fixed, LPC,
  EntropyCodingMethod, CodingMethod, PartitionedRice, PartitionedRiceContents,
};

pub use self::parser::subframe_parser;
<|endoftext|>