<commit_before>pub mod listeners;
mod parse;

extern crate csv;
extern crate hyper;

use std::io::Read;
use config::Config;
use self::hyper::client::Client;

error_chain! {
    links {
        Parse(parse::Error, parse::ErrorKind);
    }
}

enum FeedSource {
    Top,
    State(u32),
}

#[derive(Debug)]
pub struct Feed {
    pub id:        u32,
    pub state_id:  u32,
    pub county:    String,
    pub name:      String,
    pub listeners: u32,
    pub alert:     Option<String>,
}

impl PartialEq for Feed {
    fn eq(&self, other: &Feed) -> bool {
        self.id == other.id
    }
}

impl Feed {
    // TODO: Parse states from website (?)
    pub fn get_state_abbrev(&self) -> Option<&str> {
        macro_rules! create_matches {
            ($($id:expr => $abbrev:expr,)+) => {
                match self.state_id {
                    $($id => Some($abbrev),)+
                    _ => None,
                }
            };
        }

        create_matches!(
            1   => "AL", // Alabama
            2   => "AK", // Alaska
            4   => "AZ", // Arizona
            5   => "AR", // Arkansas
            6   => "CA", // California
            8   => "CO", // Colorado
            9   => "CT", // Connecticut
            10  => "DE", // Delaware
            11  => "DC", // District of Columbia
            12  => "FL", // Florida
            13  => "GA", // Georgia
            183 => "GU", // Guam
            15  => "HI", // Hawaii
            16  => "ID", // Idaho
            17  => "IL", // Illinois
            18  => "IN", // Indiana
            19  => "IA", // Iowa
            20  => "KS", // Kansas
            21  => "KY", // Kentucky
            22  => "LA", // Louisiana
            23  => "ME", // Maine
            24  => "MD", // Maryland
            25  => "MA", // Massachusetts
            26  => "MI", // Michigan
            27  => "MN", // Minnesota
            28  => "MS", // Mississippi
            29  => "MO", // Missouri
            30  => "MT", // Montana
            31  => "NE", // Nebraska
            32  => "NV", // Nevada
            33  => "NH", // New Hampshire
            34  => "NJ", // New Jersey
            35  => "NM", // New Mexico
            36  => "NY", // New York
            37  => "NC", // North Carolina
            38  => "ND", // North Dakota
            39  => "OH", // Ohio
            40  => "OK", // Oklahoma
            41  => "OR", // Oregon
            42  => "PA", // Pennsylvania
            57  => "PR", // Puerto Rico
            44  => "RI", // Rhode Island
            45  => "SC", // South Carolina
            46  => "SD", // South Dakota
            47  => "TN", // Tennessee
            48  => "TX", // Texas
            49  => "UT", // Utah
            50  => "VT", // Vermont
            181 => "VI", // Virgin Islands
            51  => "VA", // Virginia
            53  => "WA", // Washington
            54  => "WV", // West Virginia
            55  => "WI", // Wisconsin
            56  => "WY", // Wyoming
        )
    }
}

pub fn get_latest(config: &Config) -> Result<Vec<Feed>> {
    use self::FeedSource::*;

    let client = Client::new();
    let mut feeds = parse::top_feeds(&download_feed_data(&config, &client, Top)?)?;

    if let Some(id) = config.misc.state_feeds_id {
        feeds.extend(parse::state_feeds(
            &download_feed_data(&config, &client, State(id))?,
            id)?
        );

        // Remove any state feeds that show up in the top 50 list
        feeds.sort_by_key(|f| f.id);
        feeds.dedup();
    }

    filter(&config, &mut feeds);
    Ok(feeds)
}

fn download_feed_data(config: &Config, client: &Client, source: FeedSource) -> Result<String> {
    let url = match source {
        FeedSource::Top       => config.links.top_feeds.clone(),
        FeedSource::State(id) => format!("{}{}", &config.links.state_feeds, id),
    };

    let mut resp = client.get(&url).send()
        .chain_err(|| format!("failed to download feed data from {}", url))?;

    let mut body = String::new();

    resp.read_to_string(&mut body)
        .chain_err(|| format!("failed to read feed data into string from {}", url))?;

    Ok(body)
}

fn filter(config: &Config, feeds: &mut Vec<Feed>) {
    if config.whitelist.len() > 0 {
        feeds.retain(|ref feed| {
            config.whitelist
                .iter()
                .any(|entry| entry.matches_feed(&feed))
        });
    }

    if config.blacklist.len() > 0 {
        feeds.retain(|ref feed| {
            config.blacklist
                .iter()
                .any(|entry| !entry.matches_feed(&feed))
        });
    }
}<commit_msg>Return error if no feeds were parsed<commit_after>pub mod listeners;
mod parse;

extern crate csv;
extern crate hyper;

use std::io::Read;
use config::Config;
use self::hyper::client::Client;

error_chain! {
    links {
        Parse(parse::Error, parse::ErrorKind);
    }

    errors {
        NoFeeds {
            description("no feeds parsed")
            display("no feeds were parsed")
        }
    }
}

enum FeedSource {
    Top,
    State(u32),
}

#[derive(Debug)]
pub struct Feed {
    pub id:        u32,
    pub state_id:  u32,
    pub county:    String,
    pub name:      String,
    pub listeners: u32,
    pub alert:     Option<String>,
}

impl PartialEq for Feed {
    fn eq(&self, other: &Feed) -> bool {
        self.id == other.id
    }
}

impl Feed {
    // TODO: Parse states from website (?)
    pub fn get_state_abbrev(&self) -> Option<&str> {
        macro_rules! create_matches {
            ($($id:expr => $abbrev:expr,)+) => {
                match self.state_id {
                    $($id => Some($abbrev),)+
                    _ => None,
                }
            };
        }

        create_matches!(
            1   => "AL", // Alabama
            2   => "AK", // Alaska
            4   => "AZ", // Arizona
            5   => "AR", // Arkansas
            6   => "CA", // California
            8   => "CO", // Colorado
            9   => "CT", // Connecticut
            10  => "DE", // Delaware
            11  => "DC", // District of Columbia
            12  => "FL", // Florida
            13  => "GA", // Georgia
            183 => "GU", // Guam
            15  => "HI", // Hawaii
            16  => "ID", // Idaho
            17  => "IL", // Illinois
            18  => "IN", // Indiana
            19  => "IA", // Iowa
            20  => "KS", // Kansas
            21  => "KY", // Kentucky
            22  => "LA", // Louisiana
            23  => "ME", // Maine
            24  => "MD", // Maryland
            25  => "MA", // Massachusetts
            26  => "MI", // Michigan
            27  => "MN", // Minnesota
            28  => "MS", // Mississippi
            29  => "MO", // Missouri
            30  => "MT", // Montana
            31  => "NE", // Nebraska
            32  => "NV", // Nevada
            33  => "NH", // New Hampshire
            34  => "NJ", // New Jersey
            35  => "NM", // New Mexico
            36  => "NY", // New York
            37  => "NC", // North Carolina
            38  => "ND", // North Dakota
            39  => "OH", // Ohio
            40  => "OK", // Oklahoma
            41  => "OR", // Oregon
            42  => "PA", // Pennsylvania
            57  => "PR", // Puerto Rico
            44  => "RI", // Rhode Island
            45  => "SC", // South Carolina
            46  => "SD", // South Dakota
            47  => "TN", // Tennessee
            48  => "TX", // Texas
            49  => "UT", // Utah
            50  => "VT", // Vermont
            181 => "VI", // Virgin Islands
            51  => "VA", // Virginia
            53  => "WA", // Washington
            54  => "WV", // West Virginia
            55  => "WI", // Wisconsin
            56  => "WY", // Wyoming
        )
    }
}

pub fn get_latest(config: &Config) -> Result<Vec<Feed>> {
    use self::FeedSource::*;

    let client = Client::new();
    let mut feeds = parse::top_feeds(&download_feed_data(&config, &client, Top)?)?;

    if let Some(id) = config.misc.state_feeds_id {
        feeds.extend(parse::state_feeds(
            &download_feed_data(&config, &client, State(id))?,
            id)?
        );

        // Remove any state feeds that show up in the top 50 list
        feeds.sort_by_key(|f| f.id);
        feeds.dedup();
    }

    if feeds.len() > 0 {
        filter(&config, &mut feeds);
        Ok(feeds)
    } else {
        bail!(ErrorKind::NoFeeds)
    }
}

fn download_feed_data(config: &Config, client: &Client, source: FeedSource) -> Result<String> {
    let url = match source {
        FeedSource::Top       => config.links.top_feeds.clone(),
        FeedSource::State(id) => format!("{}{}", &config.links.state_feeds, id),
    };

    let mut resp = client.get(&url).send()
        .chain_err(|| format!("failed to download feed data from {}", url))?;

    let mut body = String::new();

    resp.read_to_string(&mut body)
        .chain_err(|| format!("failed to read feed data into string from {}", url))?;

    Ok(body)
}

fn filter(config: &Config, feeds: &mut Vec<Feed>) {
    if config.whitelist.len() > 0 {
        feeds.retain(|ref feed| {
            config.whitelist
                .iter()
                .any(|entry| entry.matches_feed(&feed))
        });
    }

    if config.blacklist.len() > 0 {
        feeds.retain(|ref feed| {
            config.blacklist
                .iter()
                .any(|entry| !entry.matches_feed(&feed))
        });
    }
}<|endoftext|>


<commit_before>//! # generator
//!
//! Rust generator implementation
//!

use std::any::Any;
use std::fmt;
use std::marker::PhantomData;
use std::panic;
use std::thread;

use crate::reg_context::RegContext;
use crate::rt::{Context, ContextStack, Error};
use crate::scope::Scope;
use crate::yield_::yield_now;

// default stack size, in usize
// windows has a minimal size as 0x4a8!!!!
pub const DEFAULT_STACK_SIZE: usize = 0x1000;

/// Generator helper
pub struct Gn<A = ()> {
    dummy: PhantomData<A>,
}

/// the generator type
pub type Generator<'a, A, T> = Box<GeneratorImpl<'a, A, T>>;
unsafe impl<A, T> Send for GeneratorImpl<'static, A, T> {}

impl<A> Gn<A> {
    /// create a scoped generator with default stack size
    pub fn new_scoped<'a, T, F>(f: F) -> Generator<'a, A, T>
    where
        F: FnOnce(Scope<A, T>) -> T + 'a,
        T: 'a,
        A: 'a,
    {
        Self::new_scoped_opt(DEFAULT_STACK_SIZE, f)
    }

    /// create a scoped generator with specified stack size
    pub fn new_scoped_opt<'a, T, F>(size: usize, f: F) -> Generator<'a, A, T>
    where
        F: FnOnce(Scope<A, T>) -> T + 'a,
        T: 'a,
        A: 'a,
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        g.scoped_init(f);
        g
    }
}

impl<A: Any> Gn<A> {
    /// create a new generator with default stack size
    #[cfg_attr(feature = "cargo-clippy", allow(clippy::new_ret_no_self))]
    #[deprecated(since = "0.6.18", note = "please use `scope` version instead")]
    pub fn new<'a, T: Any, F>(f: F) -> Generator<'a, A, T>
    where
        F: FnOnce() -> T + 'a,
    {
        Self::new_opt(DEFAULT_STACK_SIZE, f)
    }

    /// create a new generator with specified stack size
    // the `may` library use this API so we can't deprecated it yet.
    pub fn new_opt<'a, T: Any, F>(size: usize, f: F) -> Generator<'a, A, T>
    where
        F: FnOnce() -> T + 'a,
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        g.init_context();
        g.init(f);
        g
    }
}

/// `GeneratorImpl`
pub struct GeneratorImpl<'a, A, T> {
    // run time context
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<Box<dyn FnOnce() + 'a>>,
}

impl<'a, A: Any, T: Any> GeneratorImpl<'a, A, T> {
    /// create a new generator with default stack size
    pub fn init_context(&mut self) {
        unsafe {
            *self.context.para.as_mut_ptr() = &mut self.para as &mut dyn Any;
            *self.context.ret.as_mut_ptr() = &mut self.ret as &mut dyn Any;
        }
    }
}

impl<'a, A, T> GeneratorImpl<'a, A, T> {
    /// create a new generator with specified stack size
    pub fn new(size: usize) -> Box<Self> {
        Box::new(GeneratorImpl {
            para: None,
            ret: None,
            f: None,
            context: Context::new(size),
        })
    }

    /// prefetch the generator into cache
    #[inline]
    pub fn prefetch(&self) {
        self.context.regs.prefetch();
    }

    /// init a heap based generator with scoped closure
    pub fn scoped_init<F: FnOnce(Scope<'a, A, T>) -> T + 'a>(&mut self, f: F)
    where
        T: 'a,
        A: 'a,
    {
        use std::mem::transmute;
        let scope = unsafe { transmute(Scope::new(&mut self.para, &mut self.ret)) };
        self.init(move || f(scope));
    }

    /// init a heap based generator
    // it's can be used to re-init a 'done' generator before it's get dropped
    pub fn init<F: FnOnce() -> T + 'a>(&mut self, f: F)
    where
        T: 'a,
    {
        // make sure the last one is finished
        if self.f.is_none() && self.context._ref == 0 {
            unsafe {
                self.cancel();
            }
        }

        // init ctx parent to itself, this would be the new top
        self.context.parent = &mut self.context;

        // init the ref to 0 means that it's ready to start
        self.context._ref = 0;
        let ret = &mut self.ret as *mut _;
        let context = &mut self.context as *mut Context;
        // windows box::new is quite slow than unix
        self.f = Some(Box::new(move || {
            let r = f();
            let ret = unsafe { &mut *ret };
            let _ref = unsafe { (*context)._ref };
            if _ref == 0xf {
                ::std::mem::forget(r);
                *ret = None; // this is a done return
            } else {
                *ret = Some(r); // normal return
            }
        }));

        let stk = &self.context.stack;
        self.context
            .regs
            .init_with(gen_init, 0, &mut self.f as *mut _ as *mut usize, stk);
    }

    /// resume the generator
    #[inline]
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        // get the current regs
        let cur = &mut env.top().regs;

        // switch to new context, always use the top context's reg
        // for normal generator self.context.parent == self.context
        // for coroutine self.context.parent == top generator context
        debug_assert!(!self.context.parent.is_null());
        let top = unsafe { &mut *self.context.parent };

        // save current generator context on stack
        env.push_context(&mut self.context);

        // swap to the generator
        RegContext::swap(cur, &top.regs);

        // comes back, check the panic status
        // this would propagate the panic until root context
        // if it's a coroutine just stop propagate
        if !self.context.local_data.is_null() {
            return;
        }

        if let Some(err) = self.context.err.take() {
            // pass the error to the parent until root
            #[cold]
            panic::resume_unwind(err);
        }
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }

    /// prepare the para that passed into generator before send
    #[inline]
    pub fn set_para(&mut self, para: A) {
        self.para = Some(para);
    }

    /// set the generator local data
    #[inline]
    pub fn set_local_data(&mut self, data: *mut u8) {
        self.context.local_data = data;
    }

    /// get the generator local data
    #[inline]
    pub fn get_local_data(&self) -> *mut u8 {
        self.context.local_data
    }

    /// get the generator panic data
    #[inline]
    pub fn get_panic_data(&mut self) -> Option<Box<dyn Any + Send>> {
        self.context.err.take()
    }

    /// resume the generator without touch the para
    /// you should call `set_para` before this method
    #[inline]
    pub fn resume(&mut self) -> Option<T> {
        if self.is_done() {
            #[cold]
            return None;
        }

        // every time we call the function, increase the ref count
        // yield will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// `raw_send`
    #[inline]
    pub fn raw_send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_done() {
            #[cold]
            return None;
        }

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        self.para = para;

        // every time we call the function, increase the ref count
        // yield will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// send interface
    pub fn send(&mut self, para: A) -> T {
        let ret = self.raw_send(Some(para));
        ret.expect("send got None return")
    }

    /// cancel the generator without any check
    #[inline]
    unsafe fn raw_cancel(&mut self) {
        // tell the func to panic
        // so that we can stop the inner func
        self.context._ref = 2;
        // save the old panic hook, we don't want to print anything for the Cancel
        let old = ::std::panic::take_hook();
        ::std::panic::set_hook(Box::new(|_| {}));
        self.resume_gen();
        ::std::panic::set_hook(old);
    }

    /// cancel the generator
    /// this will trigger a Cancel panic, it's unsafe in that you must care about the resource
    pub unsafe fn cancel(&mut self) {
        if self.is_done() {
            return;
        }

        // consume the fun if it's not started
        if !self.is_started() {
            self.f.take();
            self.context._ref = 1;
        } else {
            self.raw_cancel();
        }
    }

    /// is finished
    #[inline]
    pub fn is_done(&self) -> bool {
        self.is_started() && (self.context._ref & 0x3) != 0
    }

    /// get stack total size and used size in word
    pub fn stack_usage(&self) -> (usize, usize) {
        (
            self.context.stack.size(),
            self.context.stack.get_used_size(),
        )
    }
}

impl<'a, A, T> Drop for GeneratorImpl<'a, A, T> {
    fn drop(&mut self) {
        // when the thread is already panic, do nothing
        if thread::panicking() {
            return;
        }

        if !self.is_started() {
            // not started yet, just drop the gen
            return;
        }

        if !self.is_done() {
            warn!("generator is not done while drop");
            unsafe { self.raw_cancel() }
        }

        assert!(self.is_done());

        let (total_stack, used_stack) = self.stack_usage();
        if used_stack < total_stack {
            // here we should record the stack in the class
            // next time will just use
            // set_stack_size::<F>(used_stack);
        } else {
            error!("stack overflow detected!");
            panic!(Error::StackErr);
        }
    }
}

impl<'a, T> Iterator for GeneratorImpl<'a, (), T> {
    type Item = T;
    // The 'Iterator' trait only requires the 'next' method to be defined. The
    // return type is 'Option<T>', 'None' is returned when the 'Iterator' is
    // over, otherwise the next value is returned wrapped in 'Some'
    fn next(&mut self) -> Option<T> {
        self.resume()
    }
}

impl<'a, A, T> fmt::Debug for GeneratorImpl<'a, A, T> {
    #[cfg(nightly)]
    #[allow(unused_unsafe)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::intrinsics::type_name;
        write!(
            f,
            "Generator<{}, Output={}> {{ ... }}",
            unsafe { type_name::<A>() },
            unsafe { type_name::<T>() }
        )
    }

    #[cfg(not(nightly))]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Generator {{ ... }}")
    }
}

/// the init function passed to reg_context
fn gen_init(_: usize, f: *mut usize) -> ! {
    let clo = move || {
        // consume self.f
        let f: &mut Option<Box<dyn FnOnce()>> = unsafe { &mut *(f as *mut _) };
        let func = f.take().unwrap();
        func();
    };

    fn check_err(cause: Box<dyn Any + Send + 'static>) {
        if let Some(&Error::Cancel) = cause.downcast_ref::<Error>() {
            // this is not an error at all, ignore it
            return;
        }
        error!("set panicked inside generator");
        ContextStack::current().top().err = Some(cause);
    }

    // we can't panic inside the generator context
    // need to propagate the panic to the main thread
    if let Err(cause) = panic::catch_unwind(clo) {
        check_err(cause);
    }

    yield_now();

    unreachable!("Should never comeback");
}
<commit_msg>:bug: remove UB<commit_after>//! # generator
//!
//! Rust generator implementation
//!

use std::any::Any;
use std::fmt;
use std::marker::PhantomData;
use std::panic;
use std::thread;

use crate::reg_context::RegContext;
use crate::rt::{Context, ContextStack, Error};
use crate::scope::Scope;
use crate::yield_::yield_now;

// default stack size, in usize
// windows has a minimal size as 0x4a8!!!!
pub const DEFAULT_STACK_SIZE: usize = 0x1000;

/// Generator helper
pub struct Gn<A = ()> {
    dummy: PhantomData<A>,
}

/// the generator type
pub type Generator<'a, A, T> = Box<GeneratorImpl<'a, A, T>>;
unsafe impl<A, T> Send for GeneratorImpl<'static, A, T> {}

impl<A> Gn<A> {
    /// create a scoped generator with default stack size
    pub fn new_scoped<'a, T, F>(f: F) -> Generator<'a, A, T>
    where
        F: FnOnce(Scope<A, T>) -> T + 'a,
        T: 'a,
        A: 'a,
    {
        Self::new_scoped_opt(DEFAULT_STACK_SIZE, f)
    }

    /// create a scoped generator with specified stack size
    pub fn new_scoped_opt<'a, T, F>(size: usize, f: F) -> Generator<'a, A, T>
    where
        F: FnOnce(Scope<A, T>) -> T + 'a,
        T: 'a,
        A: 'a,
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        g.scoped_init(f);
        g
    }
}

impl<A: Any> Gn<A> {
    /// create a new generator with default stack size
    #[cfg_attr(feature = "cargo-clippy", allow(clippy::new_ret_no_self))]
    #[deprecated(since = "0.6.18", note = "please use `scope` version instead")]
    pub fn new<'a, T: Any, F>(f: F) -> Generator<'a, A, T>
    where
        F: FnOnce() -> T + 'a,
    {
        Self::new_opt(DEFAULT_STACK_SIZE, f)
    }

    /// create a new generator with specified stack size
    // the `may` library use this API so we can't deprecated it yet.
    pub fn new_opt<'a, T: Any, F>(size: usize, f: F) -> Generator<'a, A, T>
    where
        F: FnOnce() -> T + 'a,
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        g.init_context();
        g.init(f);
        g
    }
}

/// `GeneratorImpl`
pub struct GeneratorImpl<'a, A, T> {
    // run time context
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<Box<dyn FnOnce() + 'a>>,
}

impl<'a, A: Any, T: Any> GeneratorImpl<'a, A, T> {
    /// create a new generator with default stack size
    pub fn init_context(&mut self) {
        unsafe {
            std::ptr::write(self.context.para.as_mut_ptr(), &mut self.para as &mut dyn Any);
            std::ptr::write(self.context.ret.as_mut_ptr(), &mut self.ret as &mut dyn Any);
        }
    }
}

impl<'a, A, T> GeneratorImpl<'a, A, T> {
    /// create a new generator with specified stack size
    pub fn new(size: usize) -> Box<Self> {
        Box::new(GeneratorImpl {
            para: None,
            ret: None,
            f: None,
            context: Context::new(size),
        })
    }

    /// prefetch the generator into cache
    #[inline]
    pub fn prefetch(&self) {
        self.context.regs.prefetch();
    }

    /// init a heap based generator with scoped closure
    pub fn scoped_init<F: FnOnce(Scope<'a, A, T>) -> T + 'a>(&mut self, f: F)
    where
        T: 'a,
        A: 'a,
    {
        use std::mem::transmute;
        let scope = unsafe { transmute(Scope::new(&mut self.para, &mut self.ret)) };
        self.init(move || f(scope));
    }

    /// init a heap based generator
    // it's can be used to re-init a 'done' generator before it's get dropped
    pub fn init<F: FnOnce() -> T + 'a>(&mut self, f: F)
    where
        T: 'a,
    {
        // make sure the last one is finished
        if self.f.is_none() && self.context._ref == 0 {
            unsafe {
                self.cancel();
            }
        }

        // init ctx parent to itself, this would be the new top
        self.context.parent = &mut self.context;

        // init the ref to 0 means that it's ready to start
        self.context._ref = 0;
        let ret = &mut self.ret as *mut _;
        let context = &mut self.context as *mut Context;
        // windows box::new is quite slow than unix
        self.f = Some(Box::new(move || {
            let r = f();
            let ret = unsafe { &mut *ret };
            let _ref = unsafe { (*context)._ref };
            if _ref == 0xf {
                ::std::mem::forget(r);
                *ret = None; // this is a done return
            } else {
                *ret = Some(r); // normal return
            }
        }));

        let stk = &self.context.stack;
        self.context
            .regs
            .init_with(gen_init, 0, &mut self.f as *mut _ as *mut usize, stk);
    }

    /// resume the generator
    #[inline]
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        // get the current regs
        let cur = &mut env.top().regs;

        // switch to new context, always use the top context's reg
        // for normal generator self.context.parent == self.context
        // for coroutine self.context.parent == top generator context
        debug_assert!(!self.context.parent.is_null());
        let top = unsafe { &mut *self.context.parent };

        // save current generator context on stack
        env.push_context(&mut self.context);

        // swap to the generator
        RegContext::swap(cur, &top.regs);

        // comes back, check the panic status
        // this would propagate the panic until root context
        // if it's a coroutine just stop propagate
        if !self.context.local_data.is_null() {
            return;
        }

        if let Some(err) = self.context.err.take() {
            // pass the error to the parent until root
            #[cold]
            panic::resume_unwind(err);
        }
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }

    /// prepare the para that passed into generator before send
    #[inline]
    pub fn set_para(&mut self, para: A) {
        self.para = Some(para);
    }

    /// set the generator local data
    #[inline]
    pub fn set_local_data(&mut self, data: *mut u8) {
        self.context.local_data = data;
    }

    /// get the generator local data
    #[inline]
    pub fn get_local_data(&self) -> *mut u8 {
        self.context.local_data
    }

    /// get the generator panic data
    #[inline]
    pub fn get_panic_data(&mut self) -> Option<Box<dyn Any + Send>> {
        self.context.err.take()
    }

    /// resume the generator without touch the para
    /// you should call `set_para` before this method
    #[inline]
    pub fn resume(&mut self) -> Option<T> {
        if self.is_done() {
            #[cold]
            return None;
        }

        // every time we call the function, increase the ref count
        // yield will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// `raw_send`
    #[inline]
    pub fn raw_send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_done() {
            #[cold]
            return None;
        }

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        self.para = para;

        // every time we call the function, increase the ref count
        // yield will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// send interface
    pub fn send(&mut self, para: A) -> T {
        let ret = self.raw_send(Some(para));
        ret.expect("send got None return")
    }

    /// cancel the generator without any check
    #[inline]
    unsafe fn raw_cancel(&mut self) {
        // tell the func to panic
        // so that we can stop the inner func
        self.context._ref = 2;
        // save the old panic hook, we don't want to print anything for the Cancel
        let old = ::std::panic::take_hook();
        ::std::panic::set_hook(Box::new(|_| {}));
        self.resume_gen();
        ::std::panic::set_hook(old);
    }

    /// cancel the generator
    /// this will trigger a Cancel panic, it's unsafe in that you must care about the resource
    pub unsafe fn cancel(&mut self) {
        if self.is_done() {
            return;
        }

        // consume the fun if it's not started
        if !self.is_started() {
            self.f.take();
            self.context._ref = 1;
        } else {
            self.raw_cancel();
        }
    }

    /// is finished
    #[inline]
    pub fn is_done(&self) -> bool {
        self.is_started() && (self.context._ref & 0x3) != 0
    }

    /// get stack total size and used size in word
    pub fn stack_usage(&self) -> (usize, usize) {
        (
            self.context.stack.size(),
            self.context.stack.get_used_size(),
        )
    }
}

impl<'a, A, T> Drop for GeneratorImpl<'a, A, T> {
    fn drop(&mut self) {
        // when the thread is already panic, do nothing
        if thread::panicking() {
            return;
        }

        if !self.is_started() {
            // not started yet, just drop the gen
            return;
        }

        if !self.is_done() {
            warn!("generator is not done while drop");
            unsafe { self.raw_cancel() }
        }

        assert!(self.is_done());

        let (total_stack, used_stack) = self.stack_usage();
        if used_stack < total_stack {
            // here we should record the stack in the class
            // next time will just use
            // set_stack_size::<F>(used_stack);
        } else {
            error!("stack overflow detected!");
            panic!(Error::StackErr);
        }
    }
}

impl<'a, T> Iterator for GeneratorImpl<'a, (), T> {
    type Item = T;
    // The 'Iterator' trait only requires the 'next' method to be defined. The
    // return type is 'Option<T>', 'None' is returned when the 'Iterator' is
    // over, otherwise the next value is returned wrapped in 'Some'
    fn next(&mut self) -> Option<T> {
        self.resume()
    }
}

impl<'a, A, T> fmt::Debug for GeneratorImpl<'a, A, T> {
    #[cfg(nightly)]
    #[allow(unused_unsafe)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::intrinsics::type_name;
        write!(
            f,
            "Generator<{}, Output={}> {{ ... }}",
            unsafe { type_name::<A>() },
            unsafe { type_name::<T>() }
        )
    }

    #[cfg(not(nightly))]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Generator {{ ... }}")
    }
}

/// the init function passed to reg_context
fn gen_init(_: usize, f: *mut usize) -> ! {
    let clo = move || {
        // consume self.f
        let f: &mut Option<Box<dyn FnOnce()>> = unsafe { &mut *(f as *mut _) };
        let func = f.take().unwrap();
        func();
    };

    fn check_err(cause: Box<dyn Any + Send + 'static>) {
        if let Some(&Error::Cancel) = cause.downcast_ref::<Error>() {
            // this is not an error at all, ignore it
            return;
        }
        error!("set panicked inside generator");
        ContextStack::current().top().err = Some(cause);
    }

    // we can't panic inside the generator context
    // need to propagate the panic to the main thread
    if let Err(cause) = panic::catch_unwind(clo) {
        check_err(cause);
    }

    yield_now();

    unreachable!("Should never comeback");
}
<|endoftext|>


<commit_before>// Copyright 2013 The rust-glib authors.
//
// 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.

#[link(name = "glib", vers = "0.1")];
#[crate_type = "lib"];

use std::libc;

pub use types::*;

mod detail;
pub mod error;
pub mod quark;
pub mod strfuncs;
pub mod string;
pub mod types;

pub type gint8 = i8;
pub type guint8 = u8;
pub type gint16 = i16;
pub type guint16 = u16;
pub type gint32 = i32;
pub type guint32 = u32;
pub type gint64 = i64;
pub type guint64 = u64;

pub type gssize = libc::ssize_t;
pub type gsize = libc::size_t;

pub type gintptr = libc::intptr_t;
pub type guintptr = libc::uintptr_t;
<commit_msg>Make glib::detail public<commit_after>// Copyright 2013 The rust-glib authors.
//
// 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.

#[link(name = "glib", vers = "0.1")];
#[crate_type = "lib"];

use std::libc;

pub use types::*;

pub mod detail;
pub mod error;
pub mod quark;
pub mod strfuncs;
pub mod string;
pub mod types;

pub type gint8 = i8;
pub type guint8 = u8;
pub type gint16 = i16;
pub type guint16 = u16;
pub type gint32 = i32;
pub type guint32 = u32;
pub type gint64 = i64;
pub type guint64 = u64;

pub type gssize = libc::ssize_t;
pub type gsize = libc::size_t;

pub type gintptr = libc::intptr_t;
pub type guintptr = libc::uintptr_t;
<|endoftext|>


<commit_before>extern crate sfunc;

use std::rand::Rng;
use std::rand::distributions::{Gamma, IndependentSample};

use super::Distribution;

/// A beta distribution.
pub struct Beta {
    /// The first shape parameter.
    pub alpha: f64,
    /// The second shape parameter.
    pub beta: f64,
    /// The left endpoint of the support.
    pub a: f64,
    /// The right endpoint of the support.
    pub b: f64,

    ln_beta: f64,
    gamma_alpha: Gamma,
    gamma_beta: Gamma,
}

impl Beta {
    /// Creates a beta distribution with the shape parameters `alpha` and
    /// `beta` on the interval `[a, b]`.
    #[inline]
    pub fn new(alpha: f64, beta: f64, a: f64, b: f64) -> Beta {
        Beta {
            alpha: alpha,
            beta: beta,
            a: a,
            b: b,
            ln_beta: sfunc::ln_beta(alpha, beta),
            gamma_alpha: Gamma::new(alpha, 1.0),
            gamma_beta: Gamma::new(beta, 1.0),
        }
    }
}

impl Distribution<f64> for Beta {
    #[inline]
    fn cdf(&self, x: f64) -> f64 {
        use self::sfunc::inc_beta;
        inc_beta((x - self.a) / (self.b - self.a), self.alpha, self.beta, self.ln_beta)
    }

    #[inline]
    fn inv_cdf(&self, p: f64) -> f64 {
        use self::sfunc::inv_inc_beta;
        self.a + (self.b - self.a) * inv_inc_beta(p, self.alpha, self.beta, self.ln_beta)
    }

    #[inline]
    fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let x = self.gamma_alpha.ind_sample(rng);
        let y = self.gamma_beta.ind_sample(rng);
        self.a + (self.b - self.a) * x / (x + y)
    }
}

#[cfg(test)]
mod test {
    use super::super::{Distribution, Sampler};
    use super::Beta;

    macro_rules! assert_almost_eq(
        ($x:expr, $y:expr) => ({
            let e: f64 = ::std::f64::EPSILON.sqrt();
            let x: Vec<f64> = $x;
            let y: Vec<f64> = $y;
            for i in range(0u, x.len()) {
                assert!(::std::num::abs(x[i] - y[i]) < e,
                        "expected {:e} ~ {:e}", x[i], y[i]);
            }
        });
    )

    #[test]
    fn cdf() {
        let dist = Beta::new(2.0, 3.0, -1.0, 2.0);

        let x = vec![-1.00, -0.85, -0.70, -0.55, -0.40, -0.25, -0.10, 0.05,
                     0.20, 0.35, 0.50, 0.65, 0.80, 0.95, 1.10, 1.25, 1.40,
                     1.55, 1.70, 1.85, 2.00];
        let p = vec![0.000000000000000e+00, 1.401875000000000e-02,
                     5.230000000000002e-02, 1.095187500000000e-01,
                     1.807999999999999e-01, 2.617187500000001e-01,
                     3.483000000000000e-01, 4.370187500000001e-01,
                     5.248000000000003e-01, 6.090187500000001e-01,
                     6.875000000000000e-01, 7.585187500000001e-01,
                     8.208000000000000e-01, 8.735187499999999e-01,
                     9.163000000000000e-01, 9.492187500000000e-01,
                     9.728000000000000e-01, 9.880187500000001e-01,
                     9.963000000000000e-01, 9.995187500000000e-01,
                     1.000000000000000e+00];

        assert_almost_eq!(x.iter().map(|&x| dist.cdf(x)).collect(), p);
    }

    #[test]
    fn inv_cdf() {
        let dist = Beta::new(1.0, 2.0, 3.0, 4.0);

        let p = vec![0.00, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40,
                     0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85,
                     0.90, 0.95, 1.00];
        let x = vec![3.000000000000000e+00, 3.025320565519104e+00,
                     3.051316701949486e+00, 3.078045554270711e+00,
                     3.105572809000084e+00, 3.133974596215561e+00,
                     3.163339973465924e+00, 3.193774225170145e+00,
                     3.225403330758517e+00, 3.258380151290432e+00,
                     3.292893218813452e+00, 3.329179606750063e+00,
                     3.367544467966324e+00, 3.408392021690038e+00,
                     3.452277442494834e+00, 3.500000000000000e+00,
                     3.552786404500042e+00, 3.612701665379257e+00,
                     3.683772233983162e+00, 3.776393202250021e+00,
                     4.000000000000000e+00];

        assert_almost_eq!(p.iter().map(|&p| dist.inv_cdf(p)).collect(), x);
    }

    #[test]
    fn sample() {
        let mut rng = ::std::rand::task_rng();
        for x in Sampler(&Beta::new(1.0, 2.0, 7.0, 42.0), &mut rng).take(100) {
            assert!(7.0 <= x && x <= 42.0);
        }
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use std::rand::random;

    use super::super::Distribution;
    use super::Beta;

    #[bench]
    fn cdf(bench: &mut test::Bencher) {
        let dist = Beta::new(0.5, 1.5, 0.0, 1.0);
        let x = range(0u, 1000).map(|_| random()).collect::<Vec<_>>();

        bench.iter(|| {
            for &x in x.iter() {
                test::black_box(dist.cdf(x));
            }
        });
    }

    #[bench]
    fn inv_cdf(bench: &mut test::Bencher) {
        let dist = Beta::new(0.5, 1.5, 0.0, 1.0);
        let p = range(0u, 1000).map(|_| random()).collect::<Vec<_>>();

        bench.iter(|| {
            for &p in p.iter() {
                test::black_box(dist.inv_cdf(p));
            }
        });
    }
}
<commit_msg>Changed the benchmarks of Beta<commit_after>extern crate sfunc;

use std::rand::Rng;
use std::rand::distributions::{Gamma, IndependentSample};

use super::Distribution;

/// A beta distribution.
pub struct Beta {
    /// The first shape parameter.
    pub alpha: f64,
    /// The second shape parameter.
    pub beta: f64,
    /// The left endpoint of the support.
    pub a: f64,
    /// The right endpoint of the support.
    pub b: f64,

    ln_beta: f64,
    gamma_alpha: Gamma,
    gamma_beta: Gamma,
}

impl Beta {
    /// Creates a beta distribution with the shape parameters `alpha` and
    /// `beta` on the interval `[a, b]`.
    #[inline]
    pub fn new(alpha: f64, beta: f64, a: f64, b: f64) -> Beta {
        Beta {
            alpha: alpha,
            beta: beta,
            a: a,
            b: b,
            ln_beta: sfunc::ln_beta(alpha, beta),
            gamma_alpha: Gamma::new(alpha, 1.0),
            gamma_beta: Gamma::new(beta, 1.0),
        }
    }
}

impl Distribution<f64> for Beta {
    #[inline]
    fn cdf(&self, x: f64) -> f64 {
        use self::sfunc::inc_beta;
        inc_beta((x - self.a) / (self.b - self.a), self.alpha, self.beta, self.ln_beta)
    }

    #[inline]
    fn inv_cdf(&self, p: f64) -> f64 {
        use self::sfunc::inv_inc_beta;
        self.a + (self.b - self.a) * inv_inc_beta(p, self.alpha, self.beta, self.ln_beta)
    }

    #[inline]
    fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let x = self.gamma_alpha.ind_sample(rng);
        let y = self.gamma_beta.ind_sample(rng);
        self.a + (self.b - self.a) * x / (x + y)
    }
}

#[cfg(test)]
mod test {
    use super::super::{Distribution, Sampler};
    use super::Beta;

    macro_rules! assert_almost_eq(
        ($x:expr, $y:expr) => ({
            let e: f64 = ::std::f64::EPSILON.sqrt();
            let x: Vec<f64> = $x;
            let y: Vec<f64> = $y;
            for i in range(0u, x.len()) {
                assert!(::std::num::abs(x[i] - y[i]) < e,
                        "expected {:e} ~ {:e}", x[i], y[i]);
            }
        });
    )

    #[test]
    fn cdf() {
        let dist = Beta::new(2.0, 3.0, -1.0, 2.0);

        let x = vec![-1.00, -0.85, -0.70, -0.55, -0.40, -0.25, -0.10, 0.05,
                     0.20, 0.35, 0.50, 0.65, 0.80, 0.95, 1.10, 1.25, 1.40,
                     1.55, 1.70, 1.85, 2.00];
        let p = vec![0.000000000000000e+00, 1.401875000000000e-02,
                     5.230000000000002e-02, 1.095187500000000e-01,
                     1.807999999999999e-01, 2.617187500000001e-01,
                     3.483000000000000e-01, 4.370187500000001e-01,
                     5.248000000000003e-01, 6.090187500000001e-01,
                     6.875000000000000e-01, 7.585187500000001e-01,
                     8.208000000000000e-01, 8.735187499999999e-01,
                     9.163000000000000e-01, 9.492187500000000e-01,
                     9.728000000000000e-01, 9.880187500000001e-01,
                     9.963000000000000e-01, 9.995187500000000e-01,
                     1.000000000000000e+00];

        assert_almost_eq!(x.iter().map(|&x| dist.cdf(x)).collect(), p);
    }

    #[test]
    fn inv_cdf() {
        let dist = Beta::new(1.0, 2.0, 3.0, 4.0);

        let p = vec![0.00, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40,
                     0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85,
                     0.90, 0.95, 1.00];
        let x = vec![3.000000000000000e+00, 3.025320565519104e+00,
                     3.051316701949486e+00, 3.078045554270711e+00,
                     3.105572809000084e+00, 3.133974596215561e+00,
                     3.163339973465924e+00, 3.193774225170145e+00,
                     3.225403330758517e+00, 3.258380151290432e+00,
                     3.292893218813452e+00, 3.329179606750063e+00,
                     3.367544467966324e+00, 3.408392021690038e+00,
                     3.452277442494834e+00, 3.500000000000000e+00,
                     3.552786404500042e+00, 3.612701665379257e+00,
                     3.683772233983162e+00, 3.776393202250021e+00,
                     4.000000000000000e+00];

        assert_almost_eq!(p.iter().map(|&p| dist.inv_cdf(p)).collect(), x);
    }

    #[test]
    fn sample() {
        let mut rng = ::std::rand::task_rng();
        for x in Sampler(&Beta::new(1.0, 2.0, 7.0, 42.0), &mut rng).take(100) {
            assert!(7.0 <= x && x <= 42.0);
        }
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use super::super::{Distribution, Sampler, Uniform};
    use super::Beta;

    #[bench]
    fn cdf(bench: &mut test::Bencher) {
        let mut rng = ::std::rand::task_rng();
        let dist = Beta::new(0.5, 1.5, 0.0, 1.0);
        let x = Sampler(&dist, &mut rng).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(x.iter().map(|&x| dist.cdf(x)).collect::<Vec<_>>())
        });
    }

    #[bench]
    fn inv_cdf(bench: &mut test::Bencher) {
        let mut rng = ::std::rand::task_rng();
        let dist = Beta::new(0.5, 1.5, 0.0, 1.0);
        let p = Sampler(&Uniform::new(0.0, 1.0), &mut rng).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(p.iter().map(|&p| dist.inv_cdf(p)).collect::<Vec<_>>())
        });
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;

fn main() {
    let mut args = env::args_os().skip(1).collect::<Vec<_>>();

    let rustc = env::var_os("RUSTC_REAL").unwrap();
    let mut cmd = Command::new(&rustc);

    // easiest way to differentiate last pass
    let time_passes = args.iter().position(|arg| arg == "-Ztime-passes");
    if let Some(pos) = time_passes {
        args.remove(pos);
    }

    if env::var_os("USE_PERF").is_some() && time_passes.is_some() {
        cmd = Command::new("perf");
        cmd.arg("stat")
            .arg("-x;")
            .arg("-e")
            .arg("instructions:u,cycles:u,task-clock,cpu-clock,faults")
            .arg("--log-fd")
            .arg("1")
            .arg(&rustc);
    }
    cmd.args(&args);

    if time_passes.is_some() {
        raise_priority();
        assert!(cmd.status().expect("failed to spawn").success());
        print_memory();
    } else {
        exec(&mut cmd);
    }
}

#[cfg(unix)]
fn exec(cmd: &mut Command) -> ! {
    use std::os::unix::prelude::*;
    panic!("failed to spawn: {}", cmd.exec());
}

#[cfg(unix)]
fn raise_priority() {
    extern crate libc;

    unsafe {
        // Try to reduce jitter in wall time by increasing our priority to the
        // maximum
        for i in (1..21).rev() {
            let r = libc::setpriority(libc::PRIO_PROCESS as _, libc::getpid() as libc::id_t, -i);
            if r == 0 {
                break;
            }
        }
    }
}

#[cfg(unix)]
fn print_memory() {
    extern crate libc;

    use std::mem;

    unsafe {
        let mut usage = mem::zeroed();
        let r = libc::getrusage(libc::RUSAGE_CHILDREN, &mut usage);
        if r == 0 {
            println!("{};;max-rss;3;100.00", usage.ru_maxrss);
        }
    }
}

#[cfg(windows)]
fn raise_priority() {}

#[cfg(windows)]
fn print_memory() {}
<commit_msg>Collect wall-time statistics<commit_after>use std::env;
use std::process::Command;
use std::time::{Instant, Duration};

fn main() {
    let mut args = env::args_os().skip(1).collect::<Vec<_>>();

    let rustc = env::var_os("RUSTC_REAL").unwrap();
    let mut cmd = Command::new(&rustc);

    // easiest way to differentiate last pass
    let time_passes = args.iter().position(|arg| arg == "-Ztime-passes");
    if let Some(pos) = time_passes {
        args.remove(pos);
    }

    if env::var_os("USE_PERF").is_some() && time_passes.is_some() {
        cmd = Command::new("perf");
        cmd.arg("stat")
            .arg("-x;")
            .arg("-e")
            .arg("instructions:u,cycles:u,task-clock,cpu-clock,faults")
            .arg("--log-fd")
            .arg("1")
            .arg(&rustc);
    }
    cmd.args(&args);

    if time_passes.is_some() {
        raise_priority();
        let start = Instant::now();
        assert!(cmd.status().expect("failed to spawn").success());
        let dur = start.elapsed();
        print_memory();
        print_time(dur);
    } else {
        exec(&mut cmd);
    }
}

#[cfg(unix)]
fn exec(cmd: &mut Command) -> ! {
    use std::os::unix::prelude::*;
    panic!("failed to spawn: {}", cmd.exec());
}

#[cfg(unix)]
fn raise_priority() {
    extern crate libc;

    unsafe {
        // Try to reduce jitter in wall time by increasing our priority to the
        // maximum
        for i in (1..21).rev() {
            let r = libc::setpriority(libc::PRIO_PROCESS as _, libc::getpid() as libc::id_t, -i);
            if r == 0 {
                break;
            }
        }
    }
}

#[cfg(unix)]
fn print_memory() {
    extern crate libc;

    use std::mem;

    unsafe {
        let mut usage = mem::zeroed();
        let r = libc::getrusage(libc::RUSAGE_CHILDREN, &mut usage);
        if r == 0 {
            // for explanation of all the semicolons, see `print_time` below
            println!("{};;max-rss;3;100.00", usage.ru_maxrss);
        }
    }
}

fn print_time(dur: Duration) {
    // Format output the same as `perf stat` in CSV mode, explained at
    // http://man7.org/linux/man-pages/man1/perf-stat.1.html#CSV_FORMAT
    //
    // tl;dr; it's:
    //
    //      $value ; $unit ; $name ; $runtime ; $pct
    println!("{}.{:09};;wall-time;4;100.00", dur.as_secs(), dur.subsec_nanos());
}

#[cfg(windows)]
fn raise_priority() {}

#[cfg(windows)]
fn print_memory() {}
<|endoftext|>


<commit_before>//! Defines `Body`: a lowered representation of bodies of functions, statics and
//! consts.
mod lower;
pub mod scope;

use std::{mem, ops::Index, sync::Arc};

use arena::{map::ArenaMap, Arena};
use base_db::CrateId;
use cfg::CfgOptions;
use drop_bomb::DropBomb;
use either::Either;
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId};
use rustc_hash::FxHashMap;
use syntax::{ast, AstNode, AstPtr};
use test_utils::mark;

pub(crate) use lower::LowerCtx;

use crate::{
    attr::Attrs,
    db::DefDatabase,
    expr::{Expr, ExprId, Pat, PatId},
    item_scope::BuiltinShadowMode,
    item_scope::ItemScope,
    nameres::CrateDefMap,
    path::{ModPath, Path},
    src::HasSource,
    AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId,
};

/// A subset of Expander that only deals with cfg attributes. We only need it to
/// avoid cyclic queries in crate def map during enum processing.
pub(crate) struct CfgExpander {
    cfg_options: CfgOptions,
    hygiene: Hygiene,
}

pub(crate) struct Expander {
    cfg_expander: CfgExpander,
    crate_def_map: Arc<CrateDefMap>,
    current_file_id: HirFileId,
    ast_id_map: Arc<AstIdMap>,
    module: ModuleId,
    recursion_limit: usize,
}

#[cfg(test)]
const EXPANSION_RECURSION_LIMIT: usize = 32;

#[cfg(not(test))]
const EXPANSION_RECURSION_LIMIT: usize = 128;

impl CfgExpander {
    pub(crate) fn new(
        db: &dyn DefDatabase,
        current_file_id: HirFileId,
        krate: CrateId,
    ) -> CfgExpander {
        let hygiene = Hygiene::new(db.upcast(), current_file_id);
        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
        CfgExpander { cfg_options, hygiene }
    }

    pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
        Attrs::new(owner, &self.hygiene)
    }

    pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
        let attrs = self.parse_attrs(owner);
        attrs.is_cfg_enabled(&self.cfg_options)
    }
}

impl Expander {
    pub(crate) fn new(
        db: &dyn DefDatabase,
        current_file_id: HirFileId,
        module: ModuleId,
    ) -> Expander {
        let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
        let crate_def_map = db.crate_def_map(module.krate);
        let ast_id_map = db.ast_id_map(current_file_id);
        Expander {
            cfg_expander,
            crate_def_map,
            current_file_id,
            ast_id_map,
            module,
            recursion_limit: 0,
        }
    }

    pub(crate) fn enter_expand<T: ast::AstNode>(
        &mut self,
        db: &dyn DefDatabase,
        local_scope: Option<&ItemScope>,
        macro_call: ast::MacroCall,
    ) -> Option<(Mark, T)> {
        self.recursion_limit += 1;
        if self.recursion_limit > EXPANSION_RECURSION_LIMIT {
            mark::hit!(your_stack_belongs_to_me);
            return None;
        }

        let macro_call = InFile::new(self.current_file_id, &macro_call);

        if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| {
            if let Some(local_scope) = local_scope {
                if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) {
                    return Some(def);
                }
            }
            self.resolve_path_as_macro(db, &path)
        }) {
            let file_id = call_id.as_file();
            if let Some(node) = db.parse_or_expand(file_id) {
                if let Some(expr) = T::cast(node) {
                    log::debug!("macro expansion {:#?}", expr.syntax());

                    let mark = Mark {
                        file_id: self.current_file_id,
                        ast_id_map: mem::take(&mut self.ast_id_map),
                        bomb: DropBomb::new("expansion mark dropped"),
                    };
                    self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
                    self.current_file_id = file_id;
                    self.ast_id_map = db.ast_id_map(file_id);
                    return Some((mark, expr));
                }
            }
        }

        // FIXME: Instead of just dropping the error from expansion
        // report it
        None
    }

    pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
        self.current_file_id = mark.file_id;
        self.ast_id_map = mem::take(&mut mark.ast_id_map);
        self.recursion_limit -= 1;
        mark.bomb.defuse();
    }

    pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
        InFile { file_id: self.current_file_id, value }
    }

    pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
        self.cfg_expander.is_cfg_enabled(owner)
    }

    fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
        Path::from_src(path, &self.cfg_expander.hygiene)
    }

    fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
        self.crate_def_map
            .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
            .0
            .take_macros()
    }

    fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> {
        let file_local_id = self.ast_id_map.ast_id(item);
        AstId::new(self.current_file_id, file_local_id)
    }
}

pub(crate) struct Mark {
    file_id: HirFileId,
    ast_id_map: Arc<AstIdMap>,
    bomb: DropBomb,
}

/// The body of an item (function, const etc.).
#[derive(Debug, Eq, PartialEq)]
pub struct Body {
    pub exprs: Arena<Expr>,
    pub pats: Arena<Pat>,
    /// The patterns for the function's parameters. While the parameter types are
    /// part of the function signature, the patterns are not (they don't change
    /// the external type of the function).
    ///
    /// If this `Body` is for the body of a constant, this will just be
    /// empty.
    pub params: Vec<PatId>,
    /// The `ExprId` of the actual body expression.
    pub body_expr: ExprId,
    pub item_scope: ItemScope,
}

pub type ExprPtr = AstPtr<ast::Expr>;
pub type ExprSource = InFile<ExprPtr>;

pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
pub type PatSource = InFile<PatPtr>;

/// An item body together with the mapping from syntax nodes to HIR expression
/// IDs. This is needed to go from e.g. a position in a file to the HIR
/// expression containing it; but for type inference etc., we want to operate on
/// a structure that is agnostic to the actual positions of expressions in the
/// file, so that we don't recompute types whenever some whitespace is typed.
///
/// One complication here is that, due to macro expansion, a single `Body` might
/// be spread across several files. So, for each ExprId and PatId, we record
/// both the HirFileId and the position inside the file. However, we only store
/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
/// this properly for macros.
#[derive(Default, Debug, Eq, PartialEq)]
pub struct BodySourceMap {
    expr_map: FxHashMap<ExprSource, ExprId>,
    expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
    pat_map: FxHashMap<PatSource, PatId>,
    pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
    field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>,
    expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
}

#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
pub struct SyntheticSyntax;

impl Body {
    pub(crate) fn body_with_source_map_query(
        db: &dyn DefDatabase,
        def: DefWithBodyId,
    ) -> (Arc<Body>, Arc<BodySourceMap>) {
        let _p = profile::span("body_with_source_map_query");
        let mut params = None;

        let (file_id, module, body) = match def {
            DefWithBodyId::FunctionId(f) => {
                let f = f.lookup(db);
                let src = f.source(db);
                params = src.value.param_list();
                (src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
            }
            DefWithBodyId::ConstId(c) => {
                let c = c.lookup(db);
                let src = c.source(db);
                (src.file_id, c.module(db), src.value.body())
            }
            DefWithBodyId::StaticId(s) => {
                let s = s.lookup(db);
                let src = s.source(db);
                (src.file_id, s.module(db), src.value.body())
            }
        };
        let expander = Expander::new(db, file_id, module);
        let (body, source_map) = Body::new(db, def, expander, params, body);
        (Arc::new(body), Arc::new(source_map))
    }

    pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> {
        db.body_with_source_map(def).0
    }

    fn new(
        db: &dyn DefDatabase,
        def: DefWithBodyId,
        expander: Expander,
        params: Option<ast::ParamList>,
        body: Option<ast::Expr>,
    ) -> (Body, BodySourceMap) {
        lower::lower(db, def, expander, params, body)
    }
}

impl Index<ExprId> for Body {
    type Output = Expr;

    fn index(&self, expr: ExprId) -> &Expr {
        &self.exprs[expr]
    }
}

impl Index<PatId> for Body {
    type Output = Pat;

    fn index(&self, pat: PatId) -> &Pat {
        &self.pats[pat]
    }
}

impl BodySourceMap {
    pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
        self.expr_map_back[expr].clone()
    }

    pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
        let src = node.map(|it| AstPtr::new(it));
        self.expr_map.get(&src).cloned()
    }

    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> {
        let src = node.map(|it| AstPtr::new(it));
        self.expansions.get(&src).cloned()
    }

    pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
        self.pat_map_back[pat].clone()
    }

    pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
        let src = node.map(|it| Either::Left(AstPtr::new(it)));
        self.pat_map.get(&src).cloned()
    }

    pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> {
        let src = node.map(|it| Either::Right(AstPtr::new(it)));
        self.pat_map.get(&src).cloned()
    }

    pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> {
        self.field_map[&(expr, field)].clone()
    }
}

#[cfg(test)]
mod tests {
    use base_db::{fixture::WithFixture, SourceDatabase};
    use test_utils::mark;

    use crate::ModuleDefId;

    use super::*;

    fn lower(ra_fixture: &str) -> Arc<Body> {
        let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture);

        let krate = db.crate_graph().iter().next().unwrap();
        let def_map = db.crate_def_map(krate);
        let module = def_map.modules_for_file(file_id).next().unwrap();
        let module = &def_map[module];
        let fn_def = match module.scope.declarations().next().unwrap() {
            ModuleDefId::FunctionId(it) => it,
            _ => panic!(),
        };

        db.body(fn_def.into())
    }

    #[test]
    fn your_stack_belongs_to_me() {
        mark::check!(your_stack_belongs_to_me);
        lower(
            "
macro_rules! n_nuple {
    ($e:tt) => ();
    ($($rest:tt)*) => {{
        (n_nuple!($($rest)*)None,)
    }};
}
fn main() { n_nuple!(1,2,3); }
",
        );
    }
}
<commit_msg>Improve readability<commit_after>//! Defines `Body`: a lowered representation of bodies of functions, statics and
//! consts.
mod lower;
pub mod scope;

use std::{mem, ops::Index, sync::Arc};

use arena::{map::ArenaMap, Arena};
use base_db::CrateId;
use cfg::CfgOptions;
use drop_bomb::DropBomb;
use either::Either;
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId};
use rustc_hash::FxHashMap;
use syntax::{ast, AstNode, AstPtr};
use test_utils::mark;

pub(crate) use lower::LowerCtx;

use crate::{
    attr::Attrs,
    db::DefDatabase,
    expr::{Expr, ExprId, Pat, PatId},
    item_scope::BuiltinShadowMode,
    item_scope::ItemScope,
    nameres::CrateDefMap,
    path::{ModPath, Path},
    src::HasSource,
    AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId,
};

/// A subset of Expander that only deals with cfg attributes. We only need it to
/// avoid cyclic queries in crate def map during enum processing.
pub(crate) struct CfgExpander {
    cfg_options: CfgOptions,
    hygiene: Hygiene,
}

pub(crate) struct Expander {
    cfg_expander: CfgExpander,
    crate_def_map: Arc<CrateDefMap>,
    current_file_id: HirFileId,
    ast_id_map: Arc<AstIdMap>,
    module: ModuleId,
    recursion_limit: usize,
}

#[cfg(test)]
const EXPANSION_RECURSION_LIMIT: usize = 32;

#[cfg(not(test))]
const EXPANSION_RECURSION_LIMIT: usize = 128;

impl CfgExpander {
    pub(crate) fn new(
        db: &dyn DefDatabase,
        current_file_id: HirFileId,
        krate: CrateId,
    ) -> CfgExpander {
        let hygiene = Hygiene::new(db.upcast(), current_file_id);
        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
        CfgExpander { cfg_options, hygiene }
    }

    pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
        Attrs::new(owner, &self.hygiene)
    }

    pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
        let attrs = self.parse_attrs(owner);
        attrs.is_cfg_enabled(&self.cfg_options)
    }
}

impl Expander {
    pub(crate) fn new(
        db: &dyn DefDatabase,
        current_file_id: HirFileId,
        module: ModuleId,
    ) -> Expander {
        let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
        let crate_def_map = db.crate_def_map(module.krate);
        let ast_id_map = db.ast_id_map(current_file_id);
        Expander {
            cfg_expander,
            crate_def_map,
            current_file_id,
            ast_id_map,
            module,
            recursion_limit: 0,
        }
    }

    pub(crate) fn enter_expand<T: ast::AstNode>(
        &mut self,
        db: &dyn DefDatabase,
        local_scope: Option<&ItemScope>,
        macro_call: ast::MacroCall,
    ) -> Option<(Mark, T)> {
        self.recursion_limit += 1;
        if self.recursion_limit > EXPANSION_RECURSION_LIMIT {
            mark::hit!(your_stack_belongs_to_me);
            return None;
        }

        let macro_call = InFile::new(self.current_file_id, &macro_call);

        let resolver = |path: ModPath| -> Option<MacroDefId> {
            if let Some(local_scope) = local_scope {
                if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) {
                    return Some(def);
                }
            }
            self.resolve_path_as_macro(db, &path)
        };

        if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, resolver) {
            let file_id = call_id.as_file();
            if let Some(node) = db.parse_or_expand(file_id) {
                if let Some(expr) = T::cast(node) {
                    log::debug!("macro expansion {:#?}", expr.syntax());

                    let mark = Mark {
                        file_id: self.current_file_id,
                        ast_id_map: mem::take(&mut self.ast_id_map),
                        bomb: DropBomb::new("expansion mark dropped"),
                    };
                    self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
                    self.current_file_id = file_id;
                    self.ast_id_map = db.ast_id_map(file_id);
                    return Some((mark, expr));
                }
            }
        }

        // FIXME: Instead of just dropping the error from expansion
        // report it
        None
    }

    pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
        self.current_file_id = mark.file_id;
        self.ast_id_map = mem::take(&mut mark.ast_id_map);
        self.recursion_limit -= 1;
        mark.bomb.defuse();
    }

    pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
        InFile { file_id: self.current_file_id, value }
    }

    pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
        self.cfg_expander.is_cfg_enabled(owner)
    }

    fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
        Path::from_src(path, &self.cfg_expander.hygiene)
    }

    fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
        self.crate_def_map
            .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
            .0
            .take_macros()
    }

    fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> {
        let file_local_id = self.ast_id_map.ast_id(item);
        AstId::new(self.current_file_id, file_local_id)
    }
}

pub(crate) struct Mark {
    file_id: HirFileId,
    ast_id_map: Arc<AstIdMap>,
    bomb: DropBomb,
}

/// The body of an item (function, const etc.).
#[derive(Debug, Eq, PartialEq)]
pub struct Body {
    pub exprs: Arena<Expr>,
    pub pats: Arena<Pat>,
    /// The patterns for the function's parameters. While the parameter types are
    /// part of the function signature, the patterns are not (they don't change
    /// the external type of the function).
    ///
    /// If this `Body` is for the body of a constant, this will just be
    /// empty.
    pub params: Vec<PatId>,
    /// The `ExprId` of the actual body expression.
    pub body_expr: ExprId,
    pub item_scope: ItemScope,
}

pub type ExprPtr = AstPtr<ast::Expr>;
pub type ExprSource = InFile<ExprPtr>;

pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
pub type PatSource = InFile<PatPtr>;

/// An item body together with the mapping from syntax nodes to HIR expression
/// IDs. This is needed to go from e.g. a position in a file to the HIR
/// expression containing it; but for type inference etc., we want to operate on
/// a structure that is agnostic to the actual positions of expressions in the
/// file, so that we don't recompute types whenever some whitespace is typed.
///
/// One complication here is that, due to macro expansion, a single `Body` might
/// be spread across several files. So, for each ExprId and PatId, we record
/// both the HirFileId and the position inside the file. However, we only store
/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
/// this properly for macros.
#[derive(Default, Debug, Eq, PartialEq)]
pub struct BodySourceMap {
    expr_map: FxHashMap<ExprSource, ExprId>,
    expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
    pat_map: FxHashMap<PatSource, PatId>,
    pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
    field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>,
    expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
}

#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
pub struct SyntheticSyntax;

impl Body {
    pub(crate) fn body_with_source_map_query(
        db: &dyn DefDatabase,
        def: DefWithBodyId,
    ) -> (Arc<Body>, Arc<BodySourceMap>) {
        let _p = profile::span("body_with_source_map_query");
        let mut params = None;

        let (file_id, module, body) = match def {
            DefWithBodyId::FunctionId(f) => {
                let f = f.lookup(db);
                let src = f.source(db);
                params = src.value.param_list();
                (src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
            }
            DefWithBodyId::ConstId(c) => {
                let c = c.lookup(db);
                let src = c.source(db);
                (src.file_id, c.module(db), src.value.body())
            }
            DefWithBodyId::StaticId(s) => {
                let s = s.lookup(db);
                let src = s.source(db);
                (src.file_id, s.module(db), src.value.body())
            }
        };
        let expander = Expander::new(db, file_id, module);
        let (body, source_map) = Body::new(db, def, expander, params, body);
        (Arc::new(body), Arc::new(source_map))
    }

    pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> {
        db.body_with_source_map(def).0
    }

    fn new(
        db: &dyn DefDatabase,
        def: DefWithBodyId,
        expander: Expander,
        params: Option<ast::ParamList>,
        body: Option<ast::Expr>,
    ) -> (Body, BodySourceMap) {
        lower::lower(db, def, expander, params, body)
    }
}

impl Index<ExprId> for Body {
    type Output = Expr;

    fn index(&self, expr: ExprId) -> &Expr {
        &self.exprs[expr]
    }
}

impl Index<PatId> for Body {
    type Output = Pat;

    fn index(&self, pat: PatId) -> &Pat {
        &self.pats[pat]
    }
}

impl BodySourceMap {
    pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
        self.expr_map_back[expr].clone()
    }

    pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
        let src = node.map(|it| AstPtr::new(it));
        self.expr_map.get(&src).cloned()
    }

    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> {
        let src = node.map(|it| AstPtr::new(it));
        self.expansions.get(&src).cloned()
    }

    pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
        self.pat_map_back[pat].clone()
    }

    pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
        let src = node.map(|it| Either::Left(AstPtr::new(it)));
        self.pat_map.get(&src).cloned()
    }

    pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> {
        let src = node.map(|it| Either::Right(AstPtr::new(it)));
        self.pat_map.get(&src).cloned()
    }

    pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> {
        self.field_map[&(expr, field)].clone()
    }
}

#[cfg(test)]
mod tests {
    use base_db::{fixture::WithFixture, SourceDatabase};
    use test_utils::mark;

    use crate::ModuleDefId;

    use super::*;

    fn lower(ra_fixture: &str) -> Arc<Body> {
        let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture);

        let krate = db.crate_graph().iter().next().unwrap();
        let def_map = db.crate_def_map(krate);
        let module = def_map.modules_for_file(file_id).next().unwrap();
        let module = &def_map[module];
        let fn_def = match module.scope.declarations().next().unwrap() {
            ModuleDefId::FunctionId(it) => it,
            _ => panic!(),
        };

        db.body(fn_def.into())
    }

    #[test]
    fn your_stack_belongs_to_me() {
        mark::check!(your_stack_belongs_to_me);
        lower(
            "
macro_rules! n_nuple {
    ($e:tt) => ();
    ($($rest:tt)*) => {{
        (n_nuple!($($rest)*)None,)
    }};
}
fn main() { n_nuple!(1,2,3); }
",
        );
    }
}
<|endoftext|>


<commit_before>use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData};
use rustc_span::def_id::{DefPathHash, StableCrateId};

#[test]
fn def_path_hash_depends_on_crate_id() {
    // This test makes sure that *both* halves of a DefPathHash depend on
    // the crate-id of the defining crate. This is a desirable property
    // because the crate-id can be more easily changed than the DefPath
    // of an item, so, in the case of a crate-local DefPathHash collision,
    // the user can simply "role the dice again" for all DefPathHashes in
    // the crate by changing the crate disambiguator (e.g. via bumping the
    // crate's version number).

    let id0 = StableCrateId::new("foo", false, vec!["1".to_string()]);
    let id1 = StableCrateId::new("foo", false, vec!["2".to_string()]);

    let h0 = mk_test_hash(id0);
    let h1 = mk_test_hash(id1);

    assert_ne!(h0.stable_crate_id(), h1.stable_crate_id());
    assert_ne!(h0.local_hash(), h1.local_hash());

    fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash {
        let parent_hash = DefPathHash::new(stable_crate_id, 0);

        let key = DefKey {
            parent: None,
            disambiguated_data: DisambiguatedDefPathData {
                data: DefPathData::CrateRoot,
                disambiguator: 0,
            },
        };

        key.compute_stable_hash(parent_hash)
    }
}
<commit_msg>Revert "Fix test"<commit_after>use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_span::crate_disambiguator::CrateDisambiguator;
use rustc_span::def_id::{DefPathHash, StableCrateId};

#[test]
fn def_path_hash_depends_on_crate_id() {
    // This test makes sure that *both* halves of a DefPathHash depend on
    // the crate-id of the defining crate. This is a desirable property
    // because the crate-id can be more easily changed than the DefPath
    // of an item, so, in the case of a crate-local DefPathHash collision,
    // the user can simply "role the dice again" for all DefPathHashes in
    // the crate by changing the crate disambiguator (e.g. via bumping the
    // crate's version number).

    let d0 = CrateDisambiguator::from(Fingerprint::new(12, 34));
    let d1 = CrateDisambiguator::from(Fingerprint::new(56, 78));

    let h0 = mk_test_hash("foo", d0);
    let h1 = mk_test_hash("foo", d1);

    assert_ne!(h0.stable_crate_id(), h1.stable_crate_id());
    assert_ne!(h0.local_hash(), h1.local_hash());

    fn mk_test_hash(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> DefPathHash {
        let stable_crate_id = StableCrateId::new(crate_name, crate_disambiguator);
        let parent_hash = DefPathHash::new(stable_crate_id, 0);

        let key = DefKey {
            parent: None,
            disambiguated_data: DisambiguatedDefPathData {
                data: DefPathData::CrateRoot,
                disambiguator: 0,
            },
        };

        key.compute_stable_hash(parent_hash)
    }
}
<|endoftext|>


<commit_before>#![feature(allow_internal_unstable)]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(extend_one)]
#![feature(unboxed_closures)]
#![feature(test)]
#![feature(fn_traits)]

pub mod bit_set;
pub mod vec;
<commit_msg>Apply workaround from #72003 for #56935<commit_after>#![feature(allow_internal_unstable)]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(extend_one)]
#![feature(unboxed_closures)]
#![feature(test)]
#![feature(fn_traits)]

pub mod bit_set;
pub mod vec;

// FIXME(#56935): Work around ICEs during cross-compilation.
#[allow(unused)]
extern crate rustc_macros;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(plugin)]
#![plugin(plugins)]

extern crate content_blocker;
extern crate cookie as cookie_rs;
extern crate devtools_traits;
extern crate flate2;
extern crate hyper;
extern crate hyper_serde;
extern crate ipc_channel;
extern crate msg;
extern crate net;
extern crate net_traits;
extern crate profile_traits;
extern crate time;
extern crate unicase;
extern crate url;
extern crate util;

#[cfg(test)] mod chrome_loader;
#[cfg(test)] mod cookie;
#[cfg(test)] mod cookie_http_state;
#[cfg(test)] mod data_loader;
#[cfg(test)] mod file_loader;
#[cfg(test)] mod fetch;
#[cfg(test)] mod mime_classifier;
#[cfg(test)] mod resource_thread;
#[cfg(test)] mod hsts;
#[cfg(test)] mod http_loader;
#[cfg(test)] mod filemanager_thread;

use devtools_traits::DevtoolsControlMsg;
use filemanager_thread::{TestProvider, TEST_PROVIDER};
use hyper::server::{Handler, Listening, Server};
use net::fetch::methods::{FetchContext, fetch};
use net::filemanager_thread::FileManager;
use net::test::HttpState;
use net_traits::FetchTaskTarget;
use net_traits::request::Request;
use net_traits::response::Response;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use std::thread;
use url::Url;

const DEFAULT_USER_AGENT: &'static str = "Such Browser. Very Layout. Wow.";

struct FetchResponseCollector {
    sender: Sender<Response>,
}

fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext<TestProvider> {
    FetchContext {
        state: HttpState::new(),
        user_agent: DEFAULT_USER_AGENT.into(),
        devtools_chan: dc,
        filemanager: FileManager::new(TEST_PROVIDER),
    }
}
impl FetchTaskTarget for FetchResponseCollector {
    fn process_request_body(&mut self, _: &Request) {}
    fn process_request_eof(&mut self, _: &Request) {}
    fn process_response(&mut self, _: &Response) {}
    fn process_response_chunk(&mut self, _: Vec<u8>) {}
    /// Fired when the response is fully fetched
    fn process_response_eof(&mut self, response: &Response) {
        let _ = self.sender.send(response.clone());
    }
}

fn fetch_async(request: Request, target: Box<FetchTaskTarget + Send>, dc: Option<Sender<DevtoolsControlMsg>>) {
    thread::spawn(move || {
        fetch(Rc::new(request), &mut Some(target), new_fetch_context(dc));
    });
}

fn fetch_sync(request: Request, dc: Option<Sender<DevtoolsControlMsg>>) -> Response {
    fetch(Rc::new(request), &mut None, new_fetch_context(dc))
}

fn make_server<H: Handler + 'static>(handler: H) -> (Listening, Url) {
    // this is a Listening server because of handle_threads()
    let server = Server::http("0.0.0.0:0").unwrap().handle_threads(handler, 1).unwrap();
    let port = server.socket.port().to_string();
    let mut url_string = "http://localhost:".to_owned();
    url_string.push_str(&port);
    let url = Url::parse(&url_string).unwrap();
    (server, url)
}
<commit_msg>Simplify string handling in make_server.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(plugin)]
#![plugin(plugins)]

extern crate content_blocker;
extern crate cookie as cookie_rs;
extern crate devtools_traits;
extern crate flate2;
extern crate hyper;
extern crate hyper_serde;
extern crate ipc_channel;
extern crate msg;
extern crate net;
extern crate net_traits;
extern crate profile_traits;
extern crate time;
extern crate unicase;
extern crate url;
extern crate util;

#[cfg(test)] mod chrome_loader;
#[cfg(test)] mod cookie;
#[cfg(test)] mod cookie_http_state;
#[cfg(test)] mod data_loader;
#[cfg(test)] mod file_loader;
#[cfg(test)] mod fetch;
#[cfg(test)] mod mime_classifier;
#[cfg(test)] mod resource_thread;
#[cfg(test)] mod hsts;
#[cfg(test)] mod http_loader;
#[cfg(test)] mod filemanager_thread;

use devtools_traits::DevtoolsControlMsg;
use filemanager_thread::{TestProvider, TEST_PROVIDER};
use hyper::server::{Handler, Listening, Server};
use net::fetch::methods::{FetchContext, fetch};
use net::filemanager_thread::FileManager;
use net::test::HttpState;
use net_traits::FetchTaskTarget;
use net_traits::request::Request;
use net_traits::response::Response;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use std::thread;
use url::Url;

const DEFAULT_USER_AGENT: &'static str = "Such Browser. Very Layout. Wow.";

struct FetchResponseCollector {
    sender: Sender<Response>,
}

fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext<TestProvider> {
    FetchContext {
        state: HttpState::new(),
        user_agent: DEFAULT_USER_AGENT.into(),
        devtools_chan: dc,
        filemanager: FileManager::new(TEST_PROVIDER),
    }
}
impl FetchTaskTarget for FetchResponseCollector {
    fn process_request_body(&mut self, _: &Request) {}
    fn process_request_eof(&mut self, _: &Request) {}
    fn process_response(&mut self, _: &Response) {}
    fn process_response_chunk(&mut self, _: Vec<u8>) {}
    /// Fired when the response is fully fetched
    fn process_response_eof(&mut self, response: &Response) {
        let _ = self.sender.send(response.clone());
    }
}

fn fetch_async(request: Request, target: Box<FetchTaskTarget + Send>, dc: Option<Sender<DevtoolsControlMsg>>) {
    thread::spawn(move || {
        fetch(Rc::new(request), &mut Some(target), new_fetch_context(dc));
    });
}

fn fetch_sync(request: Request, dc: Option<Sender<DevtoolsControlMsg>>) -> Response {
    fetch(Rc::new(request), &mut None, new_fetch_context(dc))
}

fn make_server<H: Handler + 'static>(handler: H) -> (Listening, Url) {
    // this is a Listening server because of handle_threads()
    let server = Server::http("0.0.0.0:0").unwrap().handle_threads(handler, 1).unwrap();
    let url_string = format!("http://localhost:{}", server.socket.port());
    let url = Url::parse(&url_string).unwrap();
    (server, url)
}
<|endoftext|>


<commit_before>use sass::value_part::ValuePart;
use sass::op::Op;
use value_tokenizer::ValueTokenizer;

use std::borrow::Cow::Borrowed;
use std::collections::HashMap;

#[derive(Debug)]
pub struct Evaluator<'a> {
    original: &'a str,
    variables: &'a HashMap<String, String>,
    value_stack: Vec<ValuePart<'a>>,
    op_stack: Vec<Op>,
}

impl<'a> Evaluator<'a> {
    pub fn new(original: &'a str, variables: &'a HashMap<String, String>) -> Evaluator<'a> {
        Evaluator {
            original: &original,
            variables: &variables,
            value_stack: Vec::new(),
            op_stack: Vec::new(),
        }
    }

    pub fn evaluate(&mut self) -> ValuePart<'a> {
        let mut vt = ValueTokenizer::new(self.original);
        let mut last_was_an_operator = true;

        while let Some(part) = vt.next() {
            match part {
                ValuePart::Variable(name) => {
                    match (*self.variables).get(&(*name).to_string()) {
                        Some(ref v) => self.value_stack.push(ValuePart::String(Borrowed(v))),
                        None => self.value_stack.push(ValuePart::String(name)),
                    };
                    last_was_an_operator = false;
                },
                s @ ValuePart::String(..) => {
                    self.value_stack.push(s);
                    last_was_an_operator = false;
                },
                n @ ValuePart::Number(..) | n @ ValuePart::NumberUnits(..) => {
                    if last_was_an_operator {
                        self.value_stack.push(n);
                    } else {
                        while !self.op_stack.is_empty() && self.op_stack.last() != Some(&Op::LeftParen) {
                            self.math_machine();
                        }
                        let list_starter = self.value_stack.pop().expect("No expected list starter on the value stack!");
                        let list_parts = match list_starter {
                            ValuePart::List(mut v) => {
                                v.push(n);
                                v
                            },
                            other => vec![other, n],
                        };
                        self.value_stack.push(ValuePart::List(list_parts));
                    }
                    last_was_an_operator = false;
                },
                ValuePart::Operator(ref o) => {
                    if *o == Op::RightParen {
                        let mut last_operator = self.op_stack.last().unwrap_or(&Op::LeftParen).clone();
                        while last_operator != Op::LeftParen {
                            self.math_machine();
                            last_operator = self.op_stack.last().unwrap_or(&Op::LeftParen).clone();
                        }
                        self.op_stack.pop();
                        last_was_an_operator = false;
                    } else if *o == Op::LeftParen {
                        self.op_stack.push(*o);
                        last_was_an_operator = true;
                    } else {
                        if let Some(&last_operator) = self.op_stack.last() {
                            if last_operator.same_or_greater_precedence(*o) {
                                self.math_machine();
                            }
                        }
                        self.op_stack.push(*o);
                        last_was_an_operator = true;
                    }
                },
                _ => unreachable!(),
            }
        }

        while !self.op_stack.is_empty() {
            self.math_machine();
        }

        if self.value_stack.len() > 1 {
            // TODO: figure out how to make borrowck like not cloning this, it's cool i swear
            ValuePart::List(self.value_stack.clone())
        } else {
            self.value_stack.pop().unwrap_or(ValuePart::Number(0.0))
        }
    }

    fn math_machine(&mut self) {
        let op = self.op_stack.pop().unwrap_or(Op::Plus);
        let second = self.value_stack.pop().unwrap_or(ValuePart::Number(0.0));
        let first  = self.value_stack.pop().unwrap_or(ValuePart::Number(0.0));
        self.value_stack.push(op.apply(first, second));
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::value_part::ValuePart;
    use std::collections::HashMap;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_subtitutes_variable_values() {
        let mut vars = HashMap::new();
        vars.insert("$bar".to_string(), "4".to_string());
        vars.insert("$quux".to_string(), "3px 10px".to_string());

        let answer = Evaluator::new("foo $bar 199.82 baz $quux", &vars).evaluate();

        assert_eq!(
            ValuePart::List(vec![
                ValuePart::String(Borrowed("foo")),
                ValuePart::List(vec![
                    ValuePart::String(Borrowed("4")),
                    ValuePart::Number(199.82)
                ]),
                ValuePart::String(Borrowed("baz")),
                ValuePart::String(Borrowed("3px 10px"))
            ]),
            answer
        );
    }

    #[test]
    fn it_handles_units() {
        let vars = HashMap::new();
        let answer = Evaluator::new("0px", &vars).evaluate();
        assert_eq!(ValuePart::NumberUnits(0.0, Borrowed("px")), answer);
    }

    #[test]
    fn it_adds() {
        let vars = HashMap::new();
        let answer = Evaluator::new("1 + 2", &vars).evaluate();
        assert_eq!(ValuePart::Number(3.0), answer);
    }

    #[test]
    fn it_doesnt_need_space_around_operators() {
        let vars = HashMap::new();
        let answer = Evaluator::new("12*4", &vars).evaluate();
        assert_eq!(ValuePart::Number(48.0), answer);
    }

    #[test]
    fn it_divides_and_adds_with_the_right_precedence() {
        let vars = HashMap::new();
        let answer = Evaluator::new("3 + 3/4", &vars).evaluate();
        assert_eq!(ValuePart::Number(3.75), answer);
    }

    #[test]
    fn it_gets_the_right_precedence_with_parens() {
        let vars = HashMap::new();
        let answer = Evaluator::new("(3 + 3)/4", &vars).evaluate();
        assert_eq!(ValuePart::Number(1.5), answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list() {
        let vars = HashMap::new();
        let answer = Evaluator::new("2+(3 4)", &vars).evaluate();
        assert_eq!(ValuePart::List(vec![ValuePart::String(Borrowed("23")), ValuePart::Number(4.0)]), answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list_in_a_list() {
        let vars = HashMap::new();
        let answer = Evaluator::new("(2+(3 4) 5)", &vars).evaluate();
        assert_eq!(ValuePart::List(vec![ValuePart::String(Borrowed("23")), ValuePart::Number(4.0), ValuePart::Number(5.0)]), answer);
    }

    #[test]
    fn it_divides_because_parens_and_string_concats_because_list() {
        let vars = HashMap::new();
        let answer = Evaluator::new("1 + (5/10 2 3)", &vars).evaluate();
        assert_eq!(ValuePart::List(vec![ValuePart::String(Borrowed("10.5")), ValuePart::Number(2.0), ValuePart::Number(3.0)]), answer);
    }
}<commit_msg>Make Evaluator generically have an iterator instead of string<commit_after>use sass::value_part::ValuePart;
use sass::op::Op;
use value_tokenizer::ValueTokenizer;

use std::borrow::Cow::Borrowed;
use std::collections::HashMap;

#[derive(Debug)]
pub struct Evaluator<'a, T> {
    value_tokens: T,
    variables: &'a HashMap<String, String>,
    value_stack: Vec<ValuePart<'a>>,
    op_stack: Vec<Op>,
}

impl<'a> Evaluator<'a, ValueTokenizer<'a>> {
    pub fn new(original: &'a str, variables: &'a HashMap<String, String>) -> Evaluator<'a, ValueTokenizer<'a>>
    {
        Evaluator {
            value_tokens: ValueTokenizer::new(&original),
            variables: &variables,
            value_stack: Vec::new(),
            op_stack: Vec::new(),
        }
    }
}

impl<'a, T> Evaluator<'a, T>
where T: Iterator<Item = ValuePart<'a>>
{
    pub fn evaluate(&mut self) -> ValuePart<'a> {
        let mut last_was_an_operator = true;

        while let Some(part) = self.value_tokens.next() {
            match part {
                ValuePart::Variable(name) => {
                    match (*self.variables).get(&(*name).to_string()) {
                        Some(ref v) => self.value_stack.push(ValuePart::String(Borrowed(v))),
                        None => self.value_stack.push(ValuePart::String(name)),
                    };
                    last_was_an_operator = false;
                },
                s @ ValuePart::String(..) => {
                    self.value_stack.push(s);
                    last_was_an_operator = false;
                },
                n @ ValuePart::Number(..) | n @ ValuePart::NumberUnits(..) => {
                    if last_was_an_operator {
                        self.value_stack.push(n);
                    } else {
                        while !self.op_stack.is_empty() && self.op_stack.last() != Some(&Op::LeftParen) {
                            self.math_machine();
                        }
                        let list_starter = self.value_stack.pop().expect("No expected list starter on the value stack!");
                        let list_parts = match list_starter {
                            ValuePart::List(mut v) => {
                                v.push(n);
                                v
                            },
                            other => vec![other, n],
                        };
                        self.value_stack.push(ValuePart::List(list_parts));
                    }
                    last_was_an_operator = false;
                },
                ValuePart::Operator(ref o) => {
                    if *o == Op::RightParen {
                        let mut last_operator = self.op_stack.last().unwrap_or(&Op::LeftParen).clone();
                        while last_operator != Op::LeftParen {
                            self.math_machine();
                            last_operator = self.op_stack.last().unwrap_or(&Op::LeftParen).clone();
                        }
                        self.op_stack.pop();
                        last_was_an_operator = false;
                    } else if *o == Op::LeftParen {
                        self.op_stack.push(*o);
                        last_was_an_operator = true;
                    } else {
                        if let Some(&last_operator) = self.op_stack.last() {
                            if last_operator.same_or_greater_precedence(*o) {
                                self.math_machine();
                            }
                        }
                        self.op_stack.push(*o);
                        last_was_an_operator = true;
                    }
                },
                _ => unreachable!(),
            }
        }

        while !self.op_stack.is_empty() {
            self.math_machine();
        }

        if self.value_stack.len() > 1 {
            // TODO: figure out how to make borrowck like not cloning this, it's cool i swear
            ValuePart::List(self.value_stack.clone())
        } else {
            self.value_stack.pop().unwrap_or(ValuePart::Number(0.0))
        }
    }

    fn math_machine(&mut self) {
        let op = self.op_stack.pop().unwrap_or(Op::Plus);
        let second = self.value_stack.pop().unwrap_or(ValuePart::Number(0.0));
        let first  = self.value_stack.pop().unwrap_or(ValuePart::Number(0.0));
        self.value_stack.push(op.apply(first, second));
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::value_part::ValuePart;
    use std::collections::HashMap;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_subtitutes_variable_values() {
        let mut vars = HashMap::new();
        vars.insert("$bar".to_string(), "4".to_string());
        vars.insert("$quux".to_string(), "3px 10px".to_string());

        let answer = Evaluator::new("foo $bar 199.82 baz $quux", &vars).evaluate();

        assert_eq!(
            ValuePart::List(vec![
                ValuePart::String(Borrowed("foo")),
                ValuePart::List(vec![
                    ValuePart::String(Borrowed("4")),
                    ValuePart::Number(199.82)
                ]),
                ValuePart::String(Borrowed("baz")),
                ValuePart::String(Borrowed("3px 10px"))
            ]),
            answer
        );
    }

    #[test]
    fn it_handles_units() {
        let vars = HashMap::new();
        let answer = Evaluator::new("0px", &vars).evaluate();
        assert_eq!(ValuePart::NumberUnits(0.0, Borrowed("px")), answer);
    }

    #[test]
    fn it_adds() {
        let vars = HashMap::new();
        let answer = Evaluator::new("1 + 2", &vars).evaluate();
        assert_eq!(ValuePart::Number(3.0), answer);
    }

    #[test]
    fn it_doesnt_need_space_around_operators() {
        let vars = HashMap::new();
        let answer = Evaluator::new("12*4", &vars).evaluate();
        assert_eq!(ValuePart::Number(48.0), answer);
    }

    #[test]
    fn it_divides_and_adds_with_the_right_precedence() {
        let vars = HashMap::new();
        let answer = Evaluator::new("3 + 3/4", &vars).evaluate();
        assert_eq!(ValuePart::Number(3.75), answer);
    }

    #[test]
    fn it_gets_the_right_precedence_with_parens() {
        let vars = HashMap::new();
        let answer = Evaluator::new("(3 + 3)/4", &vars).evaluate();
        assert_eq!(ValuePart::Number(1.5), answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list() {
        let vars = HashMap::new();
        let answer = Evaluator::new("2+(3 4)", &vars).evaluate();
        assert_eq!(ValuePart::List(vec![ValuePart::String(Borrowed("23")), ValuePart::Number(4.0)]), answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list_in_a_list() {
        let vars = HashMap::new();
        let answer = Evaluator::new("(2+(3 4) 5)", &vars).evaluate();
        assert_eq!(ValuePart::List(vec![ValuePart::String(Borrowed("23")), ValuePart::Number(4.0), ValuePart::Number(5.0)]), answer);
    }

    #[test]
    fn it_divides_because_parens_and_string_concats_because_list() {
        let vars = HashMap::new();
        let answer = Evaluator::new("1 + (5/10 2 3)", &vars).evaluate();
        assert_eq!(ValuePart::List(vec![ValuePart::String(Borrowed("10.5")), ValuePart::Number(2.0), ValuePart::Number(3.0)]), answer);
    }
}<|endoftext|>