<commit_before>use std::{
    collections::HashMap,
    future::Future,
    pin::Pin,
    sync::{
        atomic::{AtomicBool, Ordering::Relaxed},
        mpsc::{sync_channel, Receiver, SyncSender, TryRecvError},
    },
    task::{Context, Poll, Waker},
};

use crate::*;

static ID_GEN: AtomicUsize = AtomicUsize::new(0);

/// An event that happened to a key that a subscriber is interested in.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Event {
    /// A new complete (key, value) pair
    Insert {
        /// The key that has been set
        key: IVec,
        /// The value that has been set
        value: IVec,
    },
    /// A deleted key
    Remove {
        /// The key that has been removed
        key: IVec,
    },
}

impl Event {
    /// Return the key associated with the `Event`
    pub fn key(&self) -> &IVec {
        match self {
            Event::Insert { key, .. } | Event::Remove { key } => key,
        }
    }
}

type Senders =
    HashMap<usize, (Option<Waker>, SyncSender<OneShot<Option<Event>>>)>;

/// A subscriber listening on a specified prefix
pub struct Subscriber {
    id: usize,
    rx: Receiver<OneShot<Option<Event>>>,
    home: Arc<RwLock<Senders>>,
}

impl Drop for Subscriber {
    fn drop(&mut self) {
        let mut w_senders = self.home.write();
        w_senders.remove(&self.id);
    }
}

impl Future for Subscriber {
    type Output = Option<Event>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match self.rx.try_recv() {
                Ok(mut future_rx) => {
                    #[allow(unsafe_code)]
                    let future_rx =
                        unsafe { std::pin::Pin::new_unchecked(&mut future_rx) };

                    match Future::poll(future_rx, cx) {
                        Poll::Ready(Some(event)) => {
                            return Poll::Ready(Some(event));
                        }
                        Poll::Ready(None) => {
                            continue;
                        }
                        Poll::Pending => {
                            return Poll::Pending;
                        }
                    }
                }
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => return Poll::Ready(None),
            }
        }
        let mut home = self.home.write();
        let entry = home.get_mut(&self.id).unwrap();
        entry.0 = Some(cx.waker().clone());
        Poll::Pending
    }
}

impl Iterator for Subscriber {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        loop {
            let future_rx = self.rx.recv().ok()?;
            match future_rx.wait() {
                Some(Some(event)) => return Some(event),
                Some(None) => return None,
                None => continue,
            }
        }
    }
}

#[derive(Debug, Default)]
pub(crate) struct Subscriptions {
    watched: RwLock<BTreeMap<Vec<u8>, Arc<RwLock<Senders>>>>,
    ever_used: AtomicBool,
}

impl Drop for Subscriptions {
    fn drop(&mut self) {
        let watched = self.watched.read();

        for (_, senders) in &*watched {
            let mut senders = senders.write();
            for (_, (waker, sender)) in senders.drain() {
                drop(sender);
                if let Some(waker) = waker {
                    waker.wake();
                }
            }
        }
    }
}

impl Subscriptions {
    pub(crate) fn register(&self, prefix: &[u8]) -> Subscriber {
        self.ever_used.store(true, Relaxed);
        let r_mu = {
            let r_mu = self.watched.read();
            if r_mu.contains_key(prefix) {
                r_mu
            } else {
                drop(r_mu);
                let mut w_mu = self.watched.write();
                if !w_mu.contains_key(prefix) {
                    let old = w_mu.insert(
                        prefix.to_vec(),
                        Arc::new(RwLock::new(HashMap::default())),
                    );
                    assert!(old.is_none());
                }
                drop(w_mu);
                self.watched.read()
            }
        };

        let (tx, rx) = sync_channel(1024);

        let arc_senders = &r_mu[prefix];
        let mut w_senders = arc_senders.write();

        let id = ID_GEN.fetch_add(1, Relaxed);

        w_senders.insert(id, (None, tx));

        Subscriber { id, rx, home: arc_senders.clone() }
    }

    pub(crate) fn reserve<R: AsRef<[u8]>>(
        &self,
        key: R,
    ) -> Option<ReservedBroadcast> {
        if !self.ever_used.load(Relaxed) {
            return None;
        }

        let r_mu = self.watched.read();
        let prefixes = r_mu.iter().filter(|(k, _)| key.as_ref().starts_with(k));

        let mut subscribers = vec![];

        for (_, subs_rwl) in prefixes {
            let subs = subs_rwl.read();

            for (_id, (waker, sender)) in subs.iter() {
                let (tx, rx) = OneShot::pair();
                if sender.send(rx).is_err() {
                    continue;
                }
                subscribers.push((waker.clone(), tx));
            }
        }

        if subscribers.is_empty() {
            None
        } else {
            Some(ReservedBroadcast { subscribers })
        }
    }
}

pub(crate) struct ReservedBroadcast {
    subscribers: Vec<(Option<Waker>, OneShotFiller<Option<Event>>)>,
}

impl ReservedBroadcast {
    pub fn complete(self, event: &Event) {
        let iter = self.subscribers.into_iter();

        for (waker, tx) in iter {
            tx.fill(Some(event.clone()));
            if let Some(waker) = waker {
                waker.wake();
            }
        }
    }
}

#[test]
fn basic_subscription() {
    let subs = Subscriptions::default();

    let mut s2 = subs.register(&[0]);
    let mut s3 = subs.register(&[0, 1]);
    let mut s4 = subs.register(&[1, 2]);

    let r1 = subs.reserve(b"awft");
    assert!(r1.is_none());

    let mut s1 = subs.register(&[]);

    let k2: IVec = vec![].into();
    let r2 = subs.reserve(&k2).unwrap();
    r2.complete(&Event::Insert {
        key: k2.clone(),
        value: IVec::from(k2.clone()),
    });

    let k3: IVec = vec![0].into();
    let r3 = subs.reserve(&k3).unwrap();
    r3.complete(&Event::Insert {
        key: k3.clone(),
        value: IVec::from(k3.clone()),
    });

    let k4: IVec = vec![0, 1].into();
    let r4 = subs.reserve(&k4).unwrap();
    r4.complete(&Event::Remove { key: k4.clone() });

    let k5: IVec = vec![0, 1, 2].into();
    let r5 = subs.reserve(&k5).unwrap();
    r5.complete(&Event::Insert {
        key: k5.clone(),
        value: IVec::from(k5.clone()),
    });

    let k6: IVec = vec![1, 1, 2].into();
    let r6 = subs.reserve(&k6).unwrap();
    r6.complete(&Event::Remove { key: k6.clone() });

    let k7: IVec = vec![1, 1, 2].into();
    let r7 = subs.reserve(&k7).unwrap();
    drop(r7);

    let k8: IVec = vec![1, 2, 2].into();
    let r8 = subs.reserve(&k8).unwrap();
    r8.complete(&Event::Insert {
        key: k8.clone(),
        value: IVec::from(k8.clone()),
    });

    assert_eq!(s1.next().unwrap().key(), &*k2);
    assert_eq!(s1.next().unwrap().key(), &*k3);
    assert_eq!(s1.next().unwrap().key(), &*k4);
    assert_eq!(s1.next().unwrap().key(), &*k5);
    assert_eq!(s1.next().unwrap().key(), &*k6);
    assert_eq!(s1.next().unwrap().key(), &*k8);

    assert_eq!(s2.next().unwrap().key(), &*k3);
    assert_eq!(s2.next().unwrap().key(), &*k4);
    assert_eq!(s2.next().unwrap().key(), &*k5);

    assert_eq!(s3.next().unwrap().key(), &*k4);
    assert_eq!(s3.next().unwrap().key(), &*k5);

    assert_eq!(s4.next().unwrap().key(), &*k8);
}
<commit_msg>Update docs for the Subscriber struct<commit_after>use std::{
    collections::HashMap,
    future::Future,
    pin::Pin,
    sync::{
        atomic::{AtomicBool, Ordering::Relaxed},
        mpsc::{sync_channel, Receiver, SyncSender, TryRecvError},
    },
    task::{Context, Poll, Waker},
};

use crate::*;

static ID_GEN: AtomicUsize = AtomicUsize::new(0);

/// An event that happened to a key that a subscriber is interested in.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Event {
    /// A new complete (key, value) pair
    Insert {
        /// The key that has been set
        key: IVec,
        /// The value that has been set
        value: IVec,
    },
    /// A deleted key
    Remove {
        /// The key that has been removed
        key: IVec,
    },
}

impl Event {
    /// Return the key associated with the `Event`
    pub fn key(&self) -> &IVec {
        match self {
            Event::Insert { key, .. } | Event::Remove { key } => key,
        }
    }
}

type Senders =
    HashMap<usize, (Option<Waker>, SyncSender<OneShot<Option<Event>>>)>;

/// A subscriber listening on a specified prefix
///
/// `Subscriber` implements both `Iterator<Item = Event>`
/// and `Future<Output=Option<Event>>`
///
/// # Examples
///
/// Synchronous, blocking subscription:
/// ```
/// use sled::{Config, Event};
/// let config = Config::new().temporary(true);
///
/// let tree = config.open().unwrap();
///
/// // watch all events by subscribing to the empty prefix
/// let mut subscription = tree.watch_prefix(vec![]);
///
/// let tree_2 = tree.clone();
/// let thread = std::thread::spawn(move || {
///     tree.insert(vec![0], vec![1]).unwrap();
/// });
///
/// // `Subscription` implements `Iterator<Item=Event>`
/// for event in subscription.take(1) {
///     match event {
///         Event::Insert{ key, value } => assert_eq!(key.as_ref(), &[0]),
///         Event::Remove {key } => {}
///     }
/// }
///
/// thread.join().unwrap();
/// ```
/// Aynchronous, non-blocking subscription:
///
/// `Subscription` implements `Future<Output=Option<Event>>`.
///
/// `while let Some(event) = subscription.await { /* use it */ }`
pub struct Subscriber {
    id: usize,
    rx: Receiver<OneShot<Option<Event>>>,
    home: Arc<RwLock<Senders>>,
}

impl Drop for Subscriber {
    fn drop(&mut self) {
        let mut w_senders = self.home.write();
        w_senders.remove(&self.id);
    }
}

impl Future for Subscriber {
    type Output = Option<Event>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match self.rx.try_recv() {
                Ok(mut future_rx) => {
                    #[allow(unsafe_code)]
                    let future_rx =
                        unsafe { std::pin::Pin::new_unchecked(&mut future_rx) };

                    match Future::poll(future_rx, cx) {
                        Poll::Ready(Some(event)) => {
                            return Poll::Ready(Some(event));
                        }
                        Poll::Ready(None) => {
                            continue;
                        }
                        Poll::Pending => {
                            return Poll::Pending;
                        }
                    }
                }
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => return Poll::Ready(None),
            }
        }
        let mut home = self.home.write();
        let entry = home.get_mut(&self.id).unwrap();
        entry.0 = Some(cx.waker().clone());
        Poll::Pending
    }
}

impl Iterator for Subscriber {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        loop {
            let future_rx = self.rx.recv().ok()?;
            match future_rx.wait() {
                Some(Some(event)) => return Some(event),
                Some(None) => return None,
                None => continue,
            }
        }
    }
}

#[derive(Debug, Default)]
pub(crate) struct Subscriptions {
    watched: RwLock<BTreeMap<Vec<u8>, Arc<RwLock<Senders>>>>,
    ever_used: AtomicBool,
}

impl Drop for Subscriptions {
    fn drop(&mut self) {
        let watched = self.watched.read();

        for (_, senders) in &*watched {
            let mut senders = senders.write();
            for (_, (waker, sender)) in senders.drain() {
                drop(sender);
                if let Some(waker) = waker {
                    waker.wake();
                }
            }
        }
    }
}

impl Subscriptions {
    pub(crate) fn register(&self, prefix: &[u8]) -> Subscriber {
        self.ever_used.store(true, Relaxed);
        let r_mu = {
            let r_mu = self.watched.read();
            if r_mu.contains_key(prefix) {
                r_mu
            } else {
                drop(r_mu);
                let mut w_mu = self.watched.write();
                if !w_mu.contains_key(prefix) {
                    let old = w_mu.insert(
                        prefix.to_vec(),
                        Arc::new(RwLock::new(HashMap::default())),
                    );
                    assert!(old.is_none());
                }
                drop(w_mu);
                self.watched.read()
            }
        };

        let (tx, rx) = sync_channel(1024);

        let arc_senders = &r_mu[prefix];
        let mut w_senders = arc_senders.write();

        let id = ID_GEN.fetch_add(1, Relaxed);

        w_senders.insert(id, (None, tx));

        Subscriber { id, rx, home: arc_senders.clone() }
    }

    pub(crate) fn reserve<R: AsRef<[u8]>>(
        &self,
        key: R,
    ) -> Option<ReservedBroadcast> {
        if !self.ever_used.load(Relaxed) {
            return None;
        }

        let r_mu = self.watched.read();
        let prefixes = r_mu.iter().filter(|(k, _)| key.as_ref().starts_with(k));

        let mut subscribers = vec![];

        for (_, subs_rwl) in prefixes {
            let subs = subs_rwl.read();

            for (_id, (waker, sender)) in subs.iter() {
                let (tx, rx) = OneShot::pair();
                if sender.send(rx).is_err() {
                    continue;
                }
                subscribers.push((waker.clone(), tx));
            }
        }

        if subscribers.is_empty() {
            None
        } else {
            Some(ReservedBroadcast { subscribers })
        }
    }
}

pub(crate) struct ReservedBroadcast {
    subscribers: Vec<(Option<Waker>, OneShotFiller<Option<Event>>)>,
}

impl ReservedBroadcast {
    pub fn complete(self, event: &Event) {
        let iter = self.subscribers.into_iter();

        for (waker, tx) in iter {
            tx.fill(Some(event.clone()));
            if let Some(waker) = waker {
                waker.wake();
            }
        }
    }
}

#[test]
fn basic_subscription() {
    let subs = Subscriptions::default();

    let mut s2 = subs.register(&[0]);
    let mut s3 = subs.register(&[0, 1]);
    let mut s4 = subs.register(&[1, 2]);

    let r1 = subs.reserve(b"awft");
    assert!(r1.is_none());

    let mut s1 = subs.register(&[]);

    let k2: IVec = vec![].into();
    let r2 = subs.reserve(&k2).unwrap();
    r2.complete(&Event::Insert {
        key: k2.clone(),
        value: IVec::from(k2.clone()),
    });

    let k3: IVec = vec![0].into();
    let r3 = subs.reserve(&k3).unwrap();
    r3.complete(&Event::Insert {
        key: k3.clone(),
        value: IVec::from(k3.clone()),
    });

    let k4: IVec = vec![0, 1].into();
    let r4 = subs.reserve(&k4).unwrap();
    r4.complete(&Event::Remove { key: k4.clone() });

    let k5: IVec = vec![0, 1, 2].into();
    let r5 = subs.reserve(&k5).unwrap();
    r5.complete(&Event::Insert {
        key: k5.clone(),
        value: IVec::from(k5.clone()),
    });

    let k6: IVec = vec![1, 1, 2].into();
    let r6 = subs.reserve(&k6).unwrap();
    r6.complete(&Event::Remove { key: k6.clone() });

    let k7: IVec = vec![1, 1, 2].into();
    let r7 = subs.reserve(&k7).unwrap();
    drop(r7);

    let k8: IVec = vec![1, 2, 2].into();
    let r8 = subs.reserve(&k8).unwrap();
    r8.complete(&Event::Insert {
        key: k8.clone(),
        value: IVec::from(k8.clone()),
    });

    assert_eq!(s1.next().unwrap().key(), &*k2);
    assert_eq!(s1.next().unwrap().key(), &*k3);
    assert_eq!(s1.next().unwrap().key(), &*k4);
    assert_eq!(s1.next().unwrap().key(), &*k5);
    assert_eq!(s1.next().unwrap().key(), &*k6);
    assert_eq!(s1.next().unwrap().key(), &*k8);

    assert_eq!(s2.next().unwrap().key(), &*k3);
    assert_eq!(s2.next().unwrap().key(), &*k4);
    assert_eq!(s2.next().unwrap().key(), &*k5);

    assert_eq!(s3.next().unwrap().key(), &*k4);
    assert_eq!(s3.next().unwrap().key(), &*k5);

    assert_eq!(s4.next().unwrap().key(), &*k8);
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]
use std::str::FromStr;

use hyper::{self, Uri};

use serde::{Serialize, Deserialize};
use serde_json;

use client::{self, ApiClient};
use svc::common;

static BIGQUERY_ROOT: &str = "https://www.googleapis.com/bigquery/v2/projects";

pub struct BigQueryService {}
pub type Hub<'a> = client::Hub<'a, BigQueryService>;

#[derive(Default, Debug)]
pub struct ListDatasetsRequest {
    pub all: bool,
    pub filter: Option<String>,
    pub max_results: Option<usize>,
    pub page_token: Option<String>,
}

impl ListDatasetsRequest {
    fn to_query(&self) -> String {
        let mut params = vec![("all", self.all.to_string())];
        if let Some(ref filter) = self.filter {
            params.push(("filter", filter.clone()));
        }
        if let Some(ref max_results) = self.max_results {
            params.push(("maxResults", max_results.to_string()));
        }
        if let Some(ref page_token) = self.page_token {
            params.push(("pageToken", page_token.clone()));
        }
        client::encode_query_params(params)
    }
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ListDatasetsResponse {
    pub next_page_token: Option<String>,

    pub datasets: Vec<DatasetMeta>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DatasetMeta {
    pub id: String,
    pub dataset_reference: DatasetReference,
    pub friendly_name: Option<String>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DatasetReference {
    pub project_id: String,
    pub dataset_id: String,
}

#[derive(Default, Debug)]
pub struct ListTablesRequest {
    pub max_results: Option<usize>,
    pub page_token: Option<String>,
}

impl ListTablesRequest {
    fn to_query(&self) -> String {
        let mut params = vec![];
        if let Some(ref max_results) = self.max_results {
            params.push(("maxResults", max_results.to_string()));
        }
        if let Some(ref page_token) = self.page_token {
            params.push(("pageToken", page_token.clone()));
        }
        client::encode_query_params(params)
    }
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ListTablesResponse {
    pub next_page_token: Option<String>,
    pub tables: Vec<TableMeta>,
    pub total_items: usize,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TableMeta {
    pub id: String,
    pub table_reference: TableReference,
    pub friendly_name: Option<String>,
    pub view: Option<ViewMeta>,

    #[serde(rename = "type")]
    pub type0: String,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ViewMeta {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub query: Option<String>,

    #[serde(default = "default_view_use_legacy_sql")]
    pub use_legacy_sql: bool,
}

fn default_view_use_legacy_sql() -> bool {
    true
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TableReference {
    pub project_id: String,
    pub dataset_id: String,
    pub table_id: String,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DescribeTableResponse {
    pub id: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub schema: Option<TableFieldSchema>,

    #[serde(rename = "type")]
    pub type0: String,

    pub table_reference: TableReference,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub friendly_name: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub external_data_configuration: Option<ExtDataConfig>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub view: Option<ViewMeta>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ExtDataConfig {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schema: Option<TableFieldSchema>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TableFieldSchema {
    pub fields: Vec<TableField>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TableField {
    pub name: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default = "default_table_field_mode")]
    pub mode: String,

    #[serde(rename = "type")]
    pub type0: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub fields: Option<Vec<TableField>>,
}

fn default_table_field_mode() -> String {
    "NULLABLE".into()
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JobResource {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub kind: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub dry_run: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub job_reference: Option<JobReference>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option<JobStatus>,

    pub configuration: JobConfiguration,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JobConfiguration {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub query: Option<QueryResource>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct QueryResource {
    pub query: String,
    pub use_legacy_sql: bool,
    pub use_query_cache: bool,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub destination_table: Option<TableReference>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JobStatus {
    pub state: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub error_result: Option<QueryError>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub errors: Option<Vec<QueryError>>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JobReference {
    pub project_id: String,

    pub job_id: String,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct QueryError {
    pub reason: Option<String>,
    pub location: Option<String>,
    pub message: Option<String>,
    pub debug_info: Option<String>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GetQueryResultsRequest {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timeout_ms: Option<usize>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_results: Option<usize>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub start_index: Option<usize>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page_token: Option<String>,
}

impl GetQueryResultsRequest {
    fn to_query(&self) -> String {
        let mut params = Vec::new();
        if let Some(ref timeout_ms) = self.timeout_ms {
            params.push(("timeoutMs", timeout_ms.to_string()));
        }
        if let Some(ref max_results) = self.max_results {
            params.push(("maxResults", max_results.to_string()));
        }
        if let Some(ref page_token) = self.page_token {
            params.push(("pageToken", page_token.clone()));
        }
        if let Some(ref start_index) = self.start_index {
            params.push(("startIndex", start_index.to_string()));
        }
        client::encode_query_params(params)
    }
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GetQueryResultsResponse {
    pub schema: Option<TableFieldSchema>,
    pub job_reference: Option<JobReference>,
    pub total_rows: Option<String>,
    pub rows: Option<Vec<TableRow>>,
    pub job_complete: bool,
    pub page_token: Option<String>,
    pub errors: Option<Vec<QueryError>>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct TableRow {
    pub f: Vec<TableCell>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct TableCell {
    pub v: Cell,
}

#[serde(untagged)]
#[derive(Serialize, Deserialize, Debug)]
pub enum Cell {
    Value(Option<String>),
    Repeat(Vec<TableCell>),
    Row(TableRow),
}

impl Default for Cell {
    fn default() -> Self {
        Cell::Value(None)
    }
}

impl<'a> Hub<'a> {
    pub fn list_datasets(
        &self,
        token: &str,
        project_id: &str,
        req: &ListDatasetsRequest,
    ) -> client::Result<ListDatasetsResponse> {
        let path = format!(
            "{}/{}/datasets?{}",
            BIGQUERY_ROOT,
            project_id,
            req.to_query()
        );

        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<ListDatasetsResponse>(&uri, token.to_string())
    }

    pub fn list_tables(
        &self,
        token: &str,
        project_id: &str,
        dataset_id: &str,
        req: &ListTablesRequest,
    ) -> client::Result<ListTablesResponse> {
        let path = format!(
            "{}/{}/datasets/{}/tables?{}",
            BIGQUERY_ROOT,
            project_id,
            dataset_id,
            req.to_query()
        );
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<ListTablesResponse>(&uri, token.to_string())
    }

    pub fn describe_table(
        &self,
        token: &str,
        project_id: &str,
        dataset_id: &str,
        table_id: &str,
    ) -> client::Result<DescribeTableResponse> {
        let path = format!(
            "{}/{}/datasets/{}/tables/{}",
            BIGQUERY_ROOT,
            project_id,
            dataset_id,
            table_id
        );
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<DescribeTableResponse>(&uri, token.to_string())
    }

    pub fn create_job(
        &self,
        token: &str,
        project_id: &str,
        req: &JobResource,
    ) -> client::Result<JobResource> {
        let path = format!("{}/{}/jobs", BIGQUERY_ROOT, project_id);
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.post_bq::<_, _>(&uri, req, token.to_string())
    }

    pub fn cancel_job(
        &self,
        token: &str,
        project_id: &str,
        job_id: &str,
    ) -> client::Result<JobResource> {
        let path = format!("{}/{}/jobs/{}/cancel", BIGQUERY_ROOT, project_id, job_id);
        let uri = Uri::from_str(&path).expect("uri to be valid");

        #[derive(Deserialize, Debug)]
        #[serde(rename_all = "camelCase")]
        struct Response {
            pub job: JobResource,
        }

        self.post_bq::<_, Response>(&uri, common::Empty {}, token.to_string())
            .map(|r| r.job)
    }

    pub fn get_job(
        &self,
        token: &str,
        project_id: &str,
        job_id: &str,
    ) -> client::Result<JobResource> {
        let path = format!("{}/{}/jobs/{}", BIGQUERY_ROOT, project_id, job_id);
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<_>(&uri, token.to_string())
    }

    pub fn get_query_results(
        &self,
        token: &str,
        project_id: &str,
        job_id: &str,
        req: &GetQueryResultsRequest,
    ) -> client::Result<GetQueryResultsResponse> {
        let path = format!(
            "{}/{}/queries/{}?{}",
            BIGQUERY_ROOT,
            project_id,
            job_id,
            req.to_query()
        );
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<_>(&uri, token.to_string())
    }

    // helper method for making a GET request
    fn get_bq<D>(&self, uri: &hyper::Uri, token: String) -> client::Result<D>
    where
        for<'de> D: 'static + Send + Deserialize<'de>,
    {
        let mut req = hyper::Request::new(hyper::Method::Get, uri.clone());
        let auth = hyper::header::Authorization(hyper::header::Bearer { token });
        req.headers_mut().set(auth);

        self.request(req).map(|(_, res)| res)
    }

    // helper method for making a POST request with a JSON body
    fn post_bq<B: Serialize, D>(
        &self,
        uri: &hyper::Uri,
        body: B,
        token: String,
    ) -> client::Result<D>
    where
        for<'de> D: 'static + Send + Deserialize<'de>,
    {
        let mut req = hyper::Request::new(hyper::Method::Post, uri.clone());
        req.headers_mut().set(hyper::header::ContentType::json());

        let auth = hyper::header::Authorization(hyper::header::Bearer { token });
        req.headers_mut().set(auth);

        let body = serde_json::to_string(&body).unwrap();
        req.set_body(body);

        self.request(req).map(|(_, res)| res)
    }
}
<commit_msg>make 'tables' an Option<commit_after>#![allow(unused_variables)]
use std::str::FromStr;

use hyper::{self, Uri};

use serde::{Serialize, Deserialize};
use serde_json;

use client::{self, ApiClient};
use svc::common;

static BIGQUERY_ROOT: &str = "https://www.googleapis.com/bigquery/v2/projects";

pub struct BigQueryService {}
pub type Hub<'a> = client::Hub<'a, BigQueryService>;

#[derive(Default, Debug)]
pub struct ListDatasetsRequest {
    pub all: bool,
    pub filter: Option<String>,
    pub max_results: Option<usize>,
    pub page_token: Option<String>,
}

impl ListDatasetsRequest {
    fn to_query(&self) -> String {
        let mut params = vec![("all", self.all.to_string())];
        if let Some(ref filter) = self.filter {
            params.push(("filter", filter.clone()));
        }
        if let Some(ref max_results) = self.max_results {
            params.push(("maxResults", max_results.to_string()));
        }
        if let Some(ref page_token) = self.page_token {
            params.push(("pageToken", page_token.clone()));
        }
        client::encode_query_params(params)
    }
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ListDatasetsResponse {
    pub next_page_token: Option<String>,

    pub datasets: Vec<DatasetMeta>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DatasetMeta {
    pub id: String,
    pub dataset_reference: DatasetReference,
    pub friendly_name: Option<String>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DatasetReference {
    pub project_id: String,
    pub dataset_id: String,
}

#[derive(Default, Debug)]
pub struct ListTablesRequest {
    pub max_results: Option<usize>,
    pub page_token: Option<String>,
}

impl ListTablesRequest {
    fn to_query(&self) -> String {
        let mut params = vec![];
        if let Some(ref max_results) = self.max_results {
            params.push(("maxResults", max_results.to_string()));
        }
        if let Some(ref page_token) = self.page_token {
            params.push(("pageToken", page_token.clone()));
        }
        client::encode_query_params(params)
    }
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ListTablesResponse {
    pub next_page_token: Option<String>,
    pub tables: Option<Vec<TableMeta>>,
    pub total_items: usize,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TableMeta {
    pub id: String,
    pub table_reference: TableReference,
    pub friendly_name: Option<String>,
    pub view: Option<ViewMeta>,

    #[serde(rename = "type")]
    pub type0: String,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ViewMeta {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub query: Option<String>,

    #[serde(default = "default_view_use_legacy_sql")]
    pub use_legacy_sql: bool,
}

fn default_view_use_legacy_sql() -> bool {
    true
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TableReference {
    pub project_id: String,
    pub dataset_id: String,
    pub table_id: String,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DescribeTableResponse {
    pub id: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub schema: Option<TableFieldSchema>,

    #[serde(rename = "type")]
    pub type0: String,

    pub table_reference: TableReference,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub friendly_name: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub external_data_configuration: Option<ExtDataConfig>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub view: Option<ViewMeta>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ExtDataConfig {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schema: Option<TableFieldSchema>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TableFieldSchema {
    pub fields: Vec<TableField>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TableField {
    pub name: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default = "default_table_field_mode")]
    pub mode: String,

    #[serde(rename = "type")]
    pub type0: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub fields: Option<Vec<TableField>>,
}

fn default_table_field_mode() -> String {
    "NULLABLE".into()
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JobResource {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub kind: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub dry_run: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub job_reference: Option<JobReference>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option<JobStatus>,

    pub configuration: JobConfiguration,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JobConfiguration {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub query: Option<QueryResource>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct QueryResource {
    pub query: String,
    pub use_legacy_sql: bool,
    pub use_query_cache: bool,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub destination_table: Option<TableReference>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JobStatus {
    pub state: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub error_result: Option<QueryError>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub errors: Option<Vec<QueryError>>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JobReference {
    pub project_id: String,

    pub job_id: String,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct QueryError {
    pub reason: Option<String>,
    pub location: Option<String>,
    pub message: Option<String>,
    pub debug_info: Option<String>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GetQueryResultsRequest {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timeout_ms: Option<usize>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_results: Option<usize>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub start_index: Option<usize>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub page_token: Option<String>,
}

impl GetQueryResultsRequest {
    fn to_query(&self) -> String {
        let mut params = Vec::new();
        if let Some(ref timeout_ms) = self.timeout_ms {
            params.push(("timeoutMs", timeout_ms.to_string()));
        }
        if let Some(ref max_results) = self.max_results {
            params.push(("maxResults", max_results.to_string()));
        }
        if let Some(ref page_token) = self.page_token {
            params.push(("pageToken", page_token.clone()));
        }
        if let Some(ref start_index) = self.start_index {
            params.push(("startIndex", start_index.to_string()));
        }
        client::encode_query_params(params)
    }
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GetQueryResultsResponse {
    pub schema: Option<TableFieldSchema>,
    pub job_reference: Option<JobReference>,
    pub total_rows: Option<String>,
    pub rows: Option<Vec<TableRow>>,
    pub job_complete: bool,
    pub page_token: Option<String>,
    pub errors: Option<Vec<QueryError>>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct TableRow {
    pub f: Vec<TableCell>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct TableCell {
    pub v: Cell,
}

#[serde(untagged)]
#[derive(Serialize, Deserialize, Debug)]
pub enum Cell {
    Value(Option<String>),
    Repeat(Vec<TableCell>),
    Row(TableRow),
}

impl Default for Cell {
    fn default() -> Self {
        Cell::Value(None)
    }
}

impl<'a> Hub<'a> {
    pub fn list_datasets(
        &self,
        token: &str,
        project_id: &str,
        req: &ListDatasetsRequest,
    ) -> client::Result<ListDatasetsResponse> {
        let path = format!(
            "{}/{}/datasets?{}",
            BIGQUERY_ROOT,
            project_id,
            req.to_query()
        );

        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<ListDatasetsResponse>(&uri, token.to_string())
    }

    pub fn list_tables(
        &self,
        token: &str,
        project_id: &str,
        dataset_id: &str,
        req: &ListTablesRequest,
    ) -> client::Result<ListTablesResponse> {
        let path = format!(
            "{}/{}/datasets/{}/tables?{}",
            BIGQUERY_ROOT,
            project_id,
            dataset_id,
            req.to_query()
        );
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<ListTablesResponse>(&uri, token.to_string())
    }

    pub fn describe_table(
        &self,
        token: &str,
        project_id: &str,
        dataset_id: &str,
        table_id: &str,
    ) -> client::Result<DescribeTableResponse> {
        let path = format!(
            "{}/{}/datasets/{}/tables/{}",
            BIGQUERY_ROOT,
            project_id,
            dataset_id,
            table_id
        );
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<DescribeTableResponse>(&uri, token.to_string())
    }

    pub fn create_job(
        &self,
        token: &str,
        project_id: &str,
        req: &JobResource,
    ) -> client::Result<JobResource> {
        let path = format!("{}/{}/jobs", BIGQUERY_ROOT, project_id);
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.post_bq::<_, _>(&uri, req, token.to_string())
    }

    pub fn cancel_job(
        &self,
        token: &str,
        project_id: &str,
        job_id: &str,
    ) -> client::Result<JobResource> {
        let path = format!("{}/{}/jobs/{}/cancel", BIGQUERY_ROOT, project_id, job_id);
        let uri = Uri::from_str(&path).expect("uri to be valid");

        #[derive(Deserialize, Debug)]
        #[serde(rename_all = "camelCase")]
        struct Response {
            pub job: JobResource,
        }

        self.post_bq::<_, Response>(&uri, common::Empty {}, token.to_string())
            .map(|r| r.job)
    }

    pub fn get_job(
        &self,
        token: &str,
        project_id: &str,
        job_id: &str,
    ) -> client::Result<JobResource> {
        let path = format!("{}/{}/jobs/{}", BIGQUERY_ROOT, project_id, job_id);
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<_>(&uri, token.to_string())
    }

    pub fn get_query_results(
        &self,
        token: &str,
        project_id: &str,
        job_id: &str,
        req: &GetQueryResultsRequest,
    ) -> client::Result<GetQueryResultsResponse> {
        let path = format!(
            "{}/{}/queries/{}?{}",
            BIGQUERY_ROOT,
            project_id,
            job_id,
            req.to_query()
        );
        let uri = Uri::from_str(&path).expect("uri to be valid");
        self.get_bq::<_>(&uri, token.to_string())
    }

    // helper method for making a GET request
    fn get_bq<D>(&self, uri: &hyper::Uri, token: String) -> client::Result<D>
    where
        for<'de> D: 'static + Send + Deserialize<'de>,
    {
        let mut req = hyper::Request::new(hyper::Method::Get, uri.clone());
        let auth = hyper::header::Authorization(hyper::header::Bearer { token });
        req.headers_mut().set(auth);

        self.request(req).map(|(_, res)| res)
    }

    // helper method for making a POST request with a JSON body
    fn post_bq<B: Serialize, D>(
        &self,
        uri: &hyper::Uri,
        body: B,
        token: String,
    ) -> client::Result<D>
    where
        for<'de> D: 'static + Send + Deserialize<'de>,
    {
        let mut req = hyper::Request::new(hyper::Method::Post, uri.clone());
        req.headers_mut().set(hyper::header::ContentType::json());

        let auth = hyper::header::Authorization(hyper::header::Bearer { token });
        req.headers_mut().set(auth);

        let body = serde_json::to_string(&body).unwrap();
        req.set_body(body);

        self.request(req).map(|(_, res)| res)
    }
}
<|endoftext|>


<commit_before>use fmt_macros::{Parser, Piece, Position};

use crate::hir::def_id::DefId;
use crate::ty::{self, TyCtxt, GenericParamDefKind};
use crate::util::common::ErrorReported;
use crate::util::nodemap::FxHashMap;

use syntax::ast::{MetaItem, NestedMetaItem};
use syntax::attr;
use syntax::symbol::sym;
use syntax_pos::Span;
use syntax_pos::symbol::LocalInternedString;

#[derive(Clone, Debug)]
pub struct OnUnimplementedFormatString(LocalInternedString);

#[derive(Debug)]
pub struct OnUnimplementedDirective {
    pub condition: Option<MetaItem>,
    pub subcommands: Vec<OnUnimplementedDirective>,
    pub message: Option<OnUnimplementedFormatString>,
    pub label: Option<OnUnimplementedFormatString>,
    pub note: Option<OnUnimplementedFormatString>,
}

pub struct OnUnimplementedNote {
    pub message: Option<String>,
    pub label: Option<String>,
    pub note: Option<String>,
}

impl OnUnimplementedNote {
    pub fn empty() -> Self {
        OnUnimplementedNote { message: None, label: None, note: None }
    }
}

fn parse_error(tcx: TyCtxt<'_, '_, '_>, span: Span,
               message: &str,
               label: &str,
               note: Option<&str>)
               -> ErrorReported
{
    let mut diag = struct_span_err!(
        tcx.sess, span, E0232, "{}", message);
    diag.span_label(span, label);
    if let Some(note) = note {
        diag.note(note);
    }
    diag.emit();
    ErrorReported
}

impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
    pub fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                 trait_def_id: DefId,
                 items: &[NestedMetaItem],
                 span: Span,
                 is_root: bool)
                 -> Result<Self, ErrorReported>
    {
        let mut errored = false;
        let mut item_iter = items.iter();

        let condition = if is_root {
            None
        } else {
            let cond = item_iter.next().ok_or_else(||
                parse_error(tcx, span,
                            "empty `on`-clause in `#[rustc_on_unimplemented]`",
                            "empty on-clause here",
                            None)
            )?.meta_item().ok_or_else(||
                parse_error(tcx, span,
                            "invalid `on`-clause in `#[rustc_on_unimplemented]`",
                            "invalid on-clause here",
                            None)
            )?;
            attr::eval_condition(cond, &tcx.sess.parse_sess, &mut |_| true);
            Some(cond.clone())
        };

        let mut message = None;
        let mut label = None;
        let mut note = None;
        let mut subcommands = vec![];
        for item in item_iter {
            if item.check_name(sym::message) && message.is_none() {
                if let Some(message_) = item.value_str() {
                    message = Some(OnUnimplementedFormatString::try_parse(
                        tcx, trait_def_id, message_.as_str(), span)?);
                    continue;
                }
            } else if item.check_name(sym::label) && label.is_none() {
                if let Some(label_) = item.value_str() {
                    label = Some(OnUnimplementedFormatString::try_parse(
                        tcx, trait_def_id, label_.as_str(), span)?);
                    continue;
                }
            } else if item.check_name(sym::note) && note.is_none() {
                if let Some(note_) = item.value_str() {
                    note = Some(OnUnimplementedFormatString::try_parse(
                        tcx, trait_def_id, note_.as_str(), span)?);
                    continue;
                }
            } else if item.check_name(sym::on) && is_root &&
                message.is_none() && label.is_none() && note.is_none()
            {
                if let Some(items) = item.meta_item_list() {
                    if let Ok(subcommand) =
                        Self::parse(tcx, trait_def_id, &items, item.span(), false)
                    {
                        subcommands.push(subcommand);
                    } else {
                        errored = true;
                    }
                    continue
                }
            }

            // nothing found
            parse_error(tcx, item.span(),
                        "this attribute must have a valid value",
                        "expected value here",
                        Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#));
        }

        if errored {
            Err(ErrorReported)
        } else {
            Ok(OnUnimplementedDirective { condition, message, label, subcommands, note })
        }
    }

    pub fn of_item(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                   trait_def_id: DefId,
                   impl_def_id: DefId)
                   -> Result<Option<Self>, ErrorReported>
    {
        let attrs = tcx.get_attrs(impl_def_id);

        let attr = if let Some(item) = attr::find_by_name(&attrs, sym::rustc_on_unimplemented) {
            item
        } else {
            return Ok(None);
        };

        let result = if let Some(items) = attr.meta_item_list() {
            Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some)
        } else if let Some(value) = attr.value_str() {
            Ok(Some(OnUnimplementedDirective {
                condition: None,
                message: None,
                subcommands: vec![],
                label: Some(OnUnimplementedFormatString::try_parse(
                    tcx, trait_def_id, value.as_str(), attr.span)?),
                note: None,
            }))
        } else {
            return Err(ErrorReported);
        };
        debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result);
        result
    }

    pub fn evaluate(&self,
                    tcx: TyCtxt<'a, 'gcx, 'tcx>,
                    trait_ref: ty::TraitRef<'tcx>,
                    options: &[(String, Option<String>)])
                    -> OnUnimplementedNote
    {
        let mut message = None;
        let mut label = None;
        let mut note = None;
        info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);

        for command in self.subcommands.iter().chain(Some(self)).rev() {
            if let Some(ref condition) = command.condition {
                if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
                    c.ident().map_or(false, |ident| {
                        options.contains(&(
                            ident.to_string(),
                            c.value_str().map(|s| s.as_str().to_string())
                        ))
                    })
                }) {
                    debug!("evaluate: skipping {:?} due to condition", command);
                    continue
                }
            }
            debug!("evaluate: {:?} succeeded", command);
            if let Some(ref message_) = command.message {
                message = Some(message_.clone());
            }

            if let Some(ref label_) = command.label {
                label = Some(label_.clone());
            }

            if let Some(ref note_) = command.note {
                note = Some(note_.clone());
            }
        }

        let options: FxHashMap<String, String> = options.into_iter()
            .filter_map(|(k, v)| v.as_ref().map(|v| (k.to_owned(), v.to_owned())))
            .collect();
        OnUnimplementedNote {
            label: label.map(|l| l.format(tcx, trait_ref, &options)),
            message: message.map(|m| m.format(tcx, trait_ref, &options)),
            note: note.map(|n| n.format(tcx, trait_ref, &options)),
        }
    }
}

impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
    pub fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                     trait_def_id: DefId,
                     from: LocalInternedString,
                     err_sp: Span)
                     -> Result<Self, ErrorReported>
    {
        let result = OnUnimplementedFormatString(from);
        result.verify(tcx, trait_def_id, err_sp)?;
        Ok(result)
    }

    fn verify(
        &self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        trait_def_id: DefId,
        span: Span,
    ) -> Result<(), ErrorReported> {
        let name = tcx.item_name(trait_def_id);
        let generics = tcx.generics_of(trait_def_id);
        let parser = Parser::new(&self.0, None, vec![], false);
        let mut result = Ok(());
        for token in parser {
            match token {
                Piece::String(_) => (), // Normal string, no need to check it
                Piece::NextArgument(a) => match a.position {
                    // `{Self}` is allowed
                    Position::ArgumentNamed(s) if s == "Self" => (),
                    // `{ThisTraitsName}` is allowed
                    Position::ArgumentNamed(s) if s == name.as_str() => (),
                    // `{from_method}` is allowed
                    Position::ArgumentNamed(s) if s == "from_method" => (),
                    // `{from_desugaring}` is allowed
                    Position::ArgumentNamed(s) if s == "from_desugaring" => (),
                    // So is `{A}` if A is a type parameter
                    Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
                        param.name.as_str() == s
                    }) {
                        Some(_) => (),
                        None => {
                            span_err!(tcx.sess, span, E0230,
                                      "there is no parameter `{}` on trait `{}`", s, name);
                            result = Err(ErrorReported);
                        }
                    },
                    // `{:1}` and `{}` are not to be used
                    Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => {
                        span_err!(tcx.sess, span, E0231,
                                  "only named substitution parameters are allowed");
                        result = Err(ErrorReported);
                    }
                }
            }
        }

        result
    }

    pub fn format(
        &self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        trait_ref: ty::TraitRef<'tcx>,
        options: &FxHashMap<String, String>,
    ) -> String {
        let name = tcx.item_name(trait_ref.def_id);
        let trait_str = tcx.def_path_str(trait_ref.def_id);
        let generics = tcx.generics_of(trait_ref.def_id);
        let generic_map = generics.params.iter().filter_map(|param| {
            let value = match param.kind {
                GenericParamDefKind::Type { .. } |
                GenericParamDefKind::Const => {
                    trait_ref.substs[param.index as usize].to_string()
                },
                GenericParamDefKind::Lifetime => return None
            };
            let name = param.name.to_string();
            Some((name, value))
        }).collect::<FxHashMap<String, String>>();
        let empty_string = String::new();

        let parser = Parser::new(&self.0, None, vec![], false);
        parser.map(|p|
            match p {
                Piece::String(s) => s,
                Piece::NextArgument(a) => match a.position {
                    Position::ArgumentNamed(s) => match generic_map.get(s) {
                        Some(val) => val,
                        None if s == name.as_str() => {
                            &trait_str
                        }
                        None => {
                            if let Some(val) = options.get(s) {
                                val
                            } else if s == "from_desugaring" || s == "from_method" {
                                // don't break messages using these two arguments incorrectly
                                &empty_string
                            } else {
                                bug!("broken on_unimplemented {:?} for {:?}: \
                                      no argument matching {:?}",
                                     self.0, trait_ref, s)
                            }
                        }
                    },
                    _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0)
                }
            }
        ).collect()
    }
}
<commit_msg>Make a few methods private<commit_after>use fmt_macros::{Parser, Piece, Position};

use crate::hir::def_id::DefId;
use crate::ty::{self, TyCtxt, GenericParamDefKind};
use crate::util::common::ErrorReported;
use crate::util::nodemap::FxHashMap;

use syntax::ast::{MetaItem, NestedMetaItem};
use syntax::attr;
use syntax::symbol::sym;
use syntax_pos::Span;
use syntax_pos::symbol::LocalInternedString;

#[derive(Clone, Debug)]
pub struct OnUnimplementedFormatString(LocalInternedString);

#[derive(Debug)]
pub struct OnUnimplementedDirective {
    pub condition: Option<MetaItem>,
    pub subcommands: Vec<OnUnimplementedDirective>,
    pub message: Option<OnUnimplementedFormatString>,
    pub label: Option<OnUnimplementedFormatString>,
    pub note: Option<OnUnimplementedFormatString>,
}

pub struct OnUnimplementedNote {
    pub message: Option<String>,
    pub label: Option<String>,
    pub note: Option<String>,
}

impl OnUnimplementedNote {
    pub fn empty() -> Self {
        OnUnimplementedNote { message: None, label: None, note: None }
    }
}

fn parse_error(tcx: TyCtxt<'_, '_, '_>, span: Span,
               message: &str,
               label: &str,
               note: Option<&str>)
               -> ErrorReported
{
    let mut diag = struct_span_err!(
        tcx.sess, span, E0232, "{}", message);
    diag.span_label(span, label);
    if let Some(note) = note {
        diag.note(note);
    }
    diag.emit();
    ErrorReported
}

impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
    fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                 trait_def_id: DefId,
                 items: &[NestedMetaItem],
                 span: Span,
                 is_root: bool)
                 -> Result<Self, ErrorReported>
    {
        let mut errored = false;
        let mut item_iter = items.iter();

        let condition = if is_root {
            None
        } else {
            let cond = item_iter.next().ok_or_else(||
                parse_error(tcx, span,
                            "empty `on`-clause in `#[rustc_on_unimplemented]`",
                            "empty on-clause here",
                            None)
            )?.meta_item().ok_or_else(||
                parse_error(tcx, span,
                            "invalid `on`-clause in `#[rustc_on_unimplemented]`",
                            "invalid on-clause here",
                            None)
            )?;
            attr::eval_condition(cond, &tcx.sess.parse_sess, &mut |_| true);
            Some(cond.clone())
        };

        let mut message = None;
        let mut label = None;
        let mut note = None;
        let mut subcommands = vec![];
        for item in item_iter {
            if item.check_name(sym::message) && message.is_none() {
                if let Some(message_) = item.value_str() {
                    message = Some(OnUnimplementedFormatString::try_parse(
                        tcx, trait_def_id, message_.as_str(), span)?);
                    continue;
                }
            } else if item.check_name(sym::label) && label.is_none() {
                if let Some(label_) = item.value_str() {
                    label = Some(OnUnimplementedFormatString::try_parse(
                        tcx, trait_def_id, label_.as_str(), span)?);
                    continue;
                }
            } else if item.check_name(sym::note) && note.is_none() {
                if let Some(note_) = item.value_str() {
                    note = Some(OnUnimplementedFormatString::try_parse(
                        tcx, trait_def_id, note_.as_str(), span)?);
                    continue;
                }
            } else if item.check_name(sym::on) && is_root &&
                message.is_none() && label.is_none() && note.is_none()
            {
                if let Some(items) = item.meta_item_list() {
                    if let Ok(subcommand) =
                        Self::parse(tcx, trait_def_id, &items, item.span(), false)
                    {
                        subcommands.push(subcommand);
                    } else {
                        errored = true;
                    }
                    continue
                }
            }

            // nothing found
            parse_error(tcx, item.span(),
                        "this attribute must have a valid value",
                        "expected value here",
                        Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#));
        }

        if errored {
            Err(ErrorReported)
        } else {
            Ok(OnUnimplementedDirective { condition, message, label, subcommands, note })
        }
    }

    pub fn of_item(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                   trait_def_id: DefId,
                   impl_def_id: DefId)
                   -> Result<Option<Self>, ErrorReported>
    {
        let attrs = tcx.get_attrs(impl_def_id);

        let attr = if let Some(item) = attr::find_by_name(&attrs, sym::rustc_on_unimplemented) {
            item
        } else {
            return Ok(None);
        };

        let result = if let Some(items) = attr.meta_item_list() {
            Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some)
        } else if let Some(value) = attr.value_str() {
            Ok(Some(OnUnimplementedDirective {
                condition: None,
                message: None,
                subcommands: vec![],
                label: Some(OnUnimplementedFormatString::try_parse(
                    tcx, trait_def_id, value.as_str(), attr.span)?),
                note: None,
            }))
        } else {
            return Err(ErrorReported);
        };
        debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result);
        result
    }

    pub fn evaluate(&self,
                    tcx: TyCtxt<'a, 'gcx, 'tcx>,
                    trait_ref: ty::TraitRef<'tcx>,
                    options: &[(String, Option<String>)])
                    -> OnUnimplementedNote
    {
        let mut message = None;
        let mut label = None;
        let mut note = None;
        info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);

        for command in self.subcommands.iter().chain(Some(self)).rev() {
            if let Some(ref condition) = command.condition {
                if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
                    c.ident().map_or(false, |ident| {
                        options.contains(&(
                            ident.to_string(),
                            c.value_str().map(|s| s.as_str().to_string())
                        ))
                    })
                }) {
                    debug!("evaluate: skipping {:?} due to condition", command);
                    continue
                }
            }
            debug!("evaluate: {:?} succeeded", command);
            if let Some(ref message_) = command.message {
                message = Some(message_.clone());
            }

            if let Some(ref label_) = command.label {
                label = Some(label_.clone());
            }

            if let Some(ref note_) = command.note {
                note = Some(note_.clone());
            }
        }

        let options: FxHashMap<String, String> = options.into_iter()
            .filter_map(|(k, v)| v.as_ref().map(|v| (k.to_owned(), v.to_owned())))
            .collect();
        OnUnimplementedNote {
            label: label.map(|l| l.format(tcx, trait_ref, &options)),
            message: message.map(|m| m.format(tcx, trait_ref, &options)),
            note: note.map(|n| n.format(tcx, trait_ref, &options)),
        }
    }
}

impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
    fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                     trait_def_id: DefId,
                     from: LocalInternedString,
                     err_sp: Span)
                     -> Result<Self, ErrorReported>
    {
        let result = OnUnimplementedFormatString(from);
        result.verify(tcx, trait_def_id, err_sp)?;
        Ok(result)
    }

    fn verify(
        &self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        trait_def_id: DefId,
        span: Span,
    ) -> Result<(), ErrorReported> {
        let name = tcx.item_name(trait_def_id);
        let generics = tcx.generics_of(trait_def_id);
        let parser = Parser::new(&self.0, None, vec![], false);
        let mut result = Ok(());
        for token in parser {
            match token {
                Piece::String(_) => (), // Normal string, no need to check it
                Piece::NextArgument(a) => match a.position {
                    // `{Self}` is allowed
                    Position::ArgumentNamed(s) if s == "Self" => (),
                    // `{ThisTraitsName}` is allowed
                    Position::ArgumentNamed(s) if s == name.as_str() => (),
                    // `{from_method}` is allowed
                    Position::ArgumentNamed(s) if s == "from_method" => (),
                    // `{from_desugaring}` is allowed
                    Position::ArgumentNamed(s) if s == "from_desugaring" => (),
                    // So is `{A}` if A is a type parameter
                    Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
                        param.name.as_str() == s
                    }) {
                        Some(_) => (),
                        None => {
                            span_err!(tcx.sess, span, E0230,
                                      "there is no parameter `{}` on trait `{}`", s, name);
                            result = Err(ErrorReported);
                        }
                    },
                    // `{:1}` and `{}` are not to be used
                    Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => {
                        span_err!(tcx.sess, span, E0231,
                                  "only named substitution parameters are allowed");
                        result = Err(ErrorReported);
                    }
                }
            }
        }

        result
    }

    pub fn format(
        &self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        trait_ref: ty::TraitRef<'tcx>,
        options: &FxHashMap<String, String>,
    ) -> String {
        let name = tcx.item_name(trait_ref.def_id);
        let trait_str = tcx.def_path_str(trait_ref.def_id);
        let generics = tcx.generics_of(trait_ref.def_id);
        let generic_map = generics.params.iter().filter_map(|param| {
            let value = match param.kind {
                GenericParamDefKind::Type { .. } |
                GenericParamDefKind::Const => {
                    trait_ref.substs[param.index as usize].to_string()
                },
                GenericParamDefKind::Lifetime => return None
            };
            let name = param.name.to_string();
            Some((name, value))
        }).collect::<FxHashMap<String, String>>();
        let empty_string = String::new();

        let parser = Parser::new(&self.0, None, vec![], false);
        parser.map(|p|
            match p {
                Piece::String(s) => s,
                Piece::NextArgument(a) => match a.position {
                    Position::ArgumentNamed(s) => match generic_map.get(s) {
                        Some(val) => val,
                        None if s == name.as_str() => {
                            &trait_str
                        }
                        None => {
                            if let Some(val) = options.get(s) {
                                val
                            } else if s == "from_desugaring" || s == "from_method" {
                                // don't break messages using these two arguments incorrectly
                                &empty_string
                            } else {
                                bug!("broken on_unimplemented {:?} for {:?}: \
                                      no argument matching {:?}",
                                     self.0, trait_ref, s)
                            }
                        }
                    },
                    _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0)
                }
            }
        ).collect()
    }
}
<|endoftext|>


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

//! As always, windows has something very different than unix, we mainly want
//! to avoid having to depend too much on libunwind for windows.
//!
//! If you google around, you'll find a fair bit of references to built-in
//! functions to get backtraces on windows. It turns out that most of these are
//! in an external library called dbghelp. I was unable to find this library
//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
//! of it.
//!
//! You'll also find that there's a function called CaptureStackBackTrace
//! mentioned frequently (which is also easy to use), but sadly I didn't have a
//! copy of that function in my mingw install (maybe it was broken?). Instead,
//! this takes the route of using StackWalk64 in order to walk the stack.

#![allow(deprecated)] // dynamic_lib

use io;
use libc::c_void;
use mem;
use ptr;
use sys::c;
use sys::dynamic_lib::DynamicLibrary;
use sys_common::backtrace::Frame;

macro_rules! sym {
    ($lib:expr, $e:expr, $t:ident) => (
        $lib.symbol($e).map(|f| unsafe {
            $crate::mem::transmute::<usize, $t>(f)
        })
    )
}

mod printing;

#[cfg(target_env = "gnu")]
#[path = "backtrace_gnu.rs"]
pub mod gnu;

pub use self::printing::{foreach_symbol_fileline, resolve_symname};
use self::printing::{load_printing_fns_ex, load_printing_fns_64};

pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
    let dbghelp = DynamicLibrary::open("dbghelp.dll")?;

    // Fetch the symbols necessary from dbghelp.dll
    let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
    let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;

    // StackWalkEx might not be present and we'll fall back to StackWalk64
    let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
         Ok(StackWalkEx) =>
            StackWalkVariant::StackWalkEx(
                StackWalkEx,
                load_printing_fns_ex(&dbghelp)?,
            ),
        Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) {
            Ok(StackWalk64) =>
                StackWalkVariant::StackWalk64(
                    StackWalk64,
                    load_printing_fns_64(&dbghelp)?,
                ),
            Err(..) => return Err(e),
        },
    };

    // Allocate necessary structures for doing the stack walk
    let process = unsafe { c::GetCurrentProcess() };

    let backtrace_context = BacktraceContext {
        handle: process,
        SymCleanup,
        StackWalkVariant: sw_var,
        dbghelp,
    };

    // Initialize this process's symbols
    let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
    if ret != c::TRUE {
        return Ok((0, backtrace_context));
    }

    // And now that we're done with all the setup, do the stack walking!
    match backtrace_context.StackWalkVariant {
        StackWalkVariant::StackWalkEx(f, _) => set_frames_ex(f, frames, backtrace_context, process),
        StackWalkVariant::StackWalk64(f, _) => set_frames_64(f, frames, backtrace_context, process),
    }
}

fn set_frames_ex(
    StackWalkEx: StackWalkExFn,
    frames: &mut [Frame],
    backtrace_context: BacktraceContext,
    process: c::HANDLE,
) -> io::Result<(usize, BacktraceContext)> {
    let thread = unsafe { c::GetCurrentProcess() };
    let mut context: c::CONTEXT = unsafe { mem::zeroed() };
    unsafe { c::RtlCaptureContext(&mut context) };

    let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() };
    frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD;
    let image = init_frame_ex(&mut frame, &context);

    let mut i = 0;
    unsafe {
        while i < frames.len()
            && StackWalkEx(
                image,
                process,
                thread,
                &mut frame,
                &mut context,
                ptr::null_mut(),
                ptr::null_mut(),
                ptr::null_mut(),
                ptr::null_mut(),
                0,
            ) == c::TRUE
        {
            let addr = (frame.AddrPC.Offset - 1) as *const u8;

            frames[i] = Frame {
                symbol_addr: addr,
                exact_position: addr,
                inline_context: frame.InlineFrameContext,
            };
            i += 1;
        }
    }

    Ok((i, backtrace_context))
}

fn set_frames_64(
    StackWalk64: StackWalk64Fn,
    frames: &mut [Frame],
    backtrace_context: BacktraceContext,
    process: c::HANDLE,
) -> io::Result<(usize, BacktraceContext)> {
    let thread = unsafe { c::GetCurrentProcess() };
    let mut context: c::CONTEXT = unsafe { mem::zeroed() };
    unsafe { c::RtlCaptureContext(&mut context) };

    let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() };
    let image = init_frame_64(&mut frame, &context);

    // Start from -1 to avoid printing this stack frame, which will
    // always be exactly the same.
    let mut i = 0;
    unsafe {
        while i < frames.len()
            && StackWalk64(
                image,
                process,
                thread,
                &mut frame,
                &mut context,
                ptr::null_mut(),
                ptr::null_mut(),
                ptr::null_mut(),
                ptr::null_mut(),
            ) == c::TRUE
        {
            let addr = frame.AddrPC.Offset;
            if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0
            {
                break;
            }

            frames[i] = Frame {
                symbol_addr: (addr - 1) as *const u8,
                exact_position: (addr - 1) as *const u8,
                inline_context: 0,
            };
            i += 1;
        }
    }

    Ok((i, backtrace_context))
}

type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL;
type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL;

type StackWalkExFn = unsafe extern "system" fn(
    c::DWORD,
    c::HANDLE,
    c::HANDLE,
    *mut c::STACKFRAME_EX,
    *mut c::CONTEXT,
    *mut c_void,
    *mut c_void,
    *mut c_void,
    *mut c_void,
    c::DWORD,
) -> c::BOOL;

type StackWalk64Fn = unsafe extern "system" fn(
    c::DWORD,
    c::HANDLE,
    c::HANDLE,
    *mut c::STACKFRAME64,
    *mut c::CONTEXT,
    *mut c_void,
    *mut c_void,
    *mut c_void,
    *mut c_void,
) -> c::BOOL;

#[cfg(target_arch = "x86")]
fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD {
    frame.AddrPC.Offset = ctx.Eip as u64;
    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
    frame.AddrStack.Offset = ctx.Esp as u64;
    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
    frame.AddrFrame.Offset = ctx.Ebp as u64;
    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
    c::IMAGE_FILE_MACHINE_I386
}

#[cfg(target_arch = "x86_64")]
fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD {
    frame.AddrPC.Offset = ctx.Rip as u64;
    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
    frame.AddrStack.Offset = ctx.Rsp as u64;
    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
    frame.AddrFrame.Offset = ctx.Rbp as u64;
    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
    c::IMAGE_FILE_MACHINE_AMD64
}

#[cfg(target_arch = "x86")]
fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD {
    frame.AddrPC.Offset = ctx.Eip as u64;
    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
    frame.AddrStack.Offset = ctx.Esp as u64;
    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
    frame.AddrFrame.Offset = ctx.Ebp as u64;
    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
    c::IMAGE_FILE_MACHINE_I386
}

#[cfg(target_arch = "x86_64")]
fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD {
    frame.AddrPC.Offset = ctx.Rip as u64;
    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
    frame.AddrStack.Offset = ctx.Rsp as u64;
    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
    frame.AddrFrame.Offset = ctx.Rbp as u64;
    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
    c::IMAGE_FILE_MACHINE_AMD64
}

enum StackWalkVariant {
    StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
    StackWalk64(StackWalk64Fn, printing::PrintingFns64),
}

pub struct BacktraceContext {
    handle: c::HANDLE,
    SymCleanup: SymCleanupFn,
    // Only used in printing for msvc and not gnu
    // The gnu version is effectively a ZST dummy.
    #[allow(dead_code)]
    StackWalkVariant: StackWalkVariant,
    // keeping DynamycLibrary loaded until its functions no longer needed
    #[allow(dead_code)]
    dbghelp: DynamicLibrary,
}

impl Drop for BacktraceContext {
    fn drop(&mut self) {
        unsafe {
            (self.SymCleanup)(self.handle);
        }
    }
}
<commit_msg>Make stackwalking generic instead of matching on enum variants.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! As always, windows has something very different than unix, we mainly want
//! to avoid having to depend too much on libunwind for windows.
//!
//! If you google around, you'll find a fair bit of references to built-in
//! functions to get backtraces on windows. It turns out that most of these are
//! in an external library called dbghelp. I was unable to find this library
//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
//! of it.
//!
//! You'll also find that there's a function called CaptureStackBackTrace
//! mentioned frequently (which is also easy to use), but sadly I didn't have a
//! copy of that function in my mingw install (maybe it was broken?). Instead,
//! this takes the route of using StackWalk64 in order to walk the stack.

#![allow(deprecated)] // dynamic_lib

use io;
use libc::c_void;
use mem;
use ptr;
use sys::c;
use sys::dynamic_lib::DynamicLibrary;
use sys_common::backtrace::Frame;

macro_rules! sym {
    ($lib:expr, $e:expr, $t:ident) => (
        $lib.symbol($e).map(|f| unsafe {
            $crate::mem::transmute::<usize, $t>(f)
        })
    )
}

mod printing;

#[cfg(target_env = "gnu")]
#[path = "backtrace_gnu.rs"]
pub mod gnu;

pub use self::printing::{foreach_symbol_fileline, resolve_symname};
use self::printing::{load_printing_fns_64, load_printing_fns_ex};

pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
    let dbghelp = DynamicLibrary::open("dbghelp.dll")?;

    // Fetch the symbols necessary from dbghelp.dll
    let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
    let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;

    // StackWalkEx might not be present and we'll fall back to StackWalk64
    let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
        Ok(StackWalkEx) => {
            StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?)
        }
        Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) {
            Ok(StackWalk64) => {
                StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?)
            }
            Err(..) => return Err(e),
        },
    };

    // Allocate necessary structures for doing the stack walk
    let process = unsafe { c::GetCurrentProcess() };

    let backtrace_context = BacktraceContext {
        handle: process,
        SymCleanup,
        StackWalkVariant: sw_var,
        dbghelp,
    };

    // Initialize this process's symbols
    let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
    if ret != c::TRUE {
        return Ok((0, backtrace_context));
    }

    // And now that we're done with all the setup, do the stack walking!
    match backtrace_context.StackWalkVariant {
        StackWalkVariant::StackWalkEx(StackWalkEx, _) => {
            set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context))
        }

        StackWalkVariant::StackWalk64(StackWalk64, _) => {
            set_frames(StackWalk64, frames).map(|i| (i, backtrace_context))
        }
    }
}

fn set_frames<W: StackWalker>(StackWalk: W, frames: &mut [Frame]) -> io::Result<usize> {
    let process = unsafe { c::GetCurrentProcess() };
    let thread = unsafe { c::GetCurrentProcess() };
    let mut context: c::CONTEXT = unsafe { mem::zeroed() };
    unsafe { c::RtlCaptureContext(&mut context) };
    let mut frame = W::Item::new();
    let image = frame.init(&context);

    let mut i = 0;
    while i < frames.len()
        && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE
    {
        let addr = frame.get_addr();
        frames[i] = Frame {
            symbol_addr: addr,
            exact_position: addr,
            inline_context: 0,
        };

        i += 1
    }
    Ok(i)
}

type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL;
type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL;

type StackWalkExFn = unsafe extern "system" fn(
    c::DWORD,
    c::HANDLE,
    c::HANDLE,
    *mut c::STACKFRAME_EX,
    *mut c::CONTEXT,
    *mut c_void,
    *mut c_void,
    *mut c_void,
    *mut c_void,
    c::DWORD,
) -> c::BOOL;

type StackWalk64Fn = unsafe extern "system" fn(
    c::DWORD,
    c::HANDLE,
    c::HANDLE,
    *mut c::STACKFRAME64,
    *mut c::CONTEXT,
    *mut c_void,
    *mut c_void,
    *mut c_void,
    *mut c_void,
) -> c::BOOL;

trait StackWalker {
    type Item: StackFrame;

    fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL;
}

impl StackWalker for StackWalkExFn {
    type Item = c::STACKFRAME_EX;
    fn walk(
        &self,
        image: c::DWORD,
        process: c::HANDLE,
        thread: c::HANDLE,
        frame: &mut Self::Item,
        context: &mut c::CONTEXT,
    ) -> c::BOOL {
        unsafe {
            self(
                image,
                process,
                thread,
                frame,
                context,
                ptr::null_mut(),
                ptr::null_mut(),
                ptr::null_mut(),
                ptr::null_mut(),
                0,
            )
        }
    }
}

impl StackWalker for StackWalk64Fn {
    type Item = c::STACKFRAME64;
    fn walk(
        &self,
        image: c::DWORD,
        process: c::HANDLE,
        thread: c::HANDLE,
        frame: &mut Self::Item,
        context: &mut c::CONTEXT,
    ) -> c::BOOL {
        unsafe {
            self(
                image,
                process,
                thread,
                frame,
                context,
                ptr::null_mut(),
                ptr::null_mut(),
                ptr::null_mut(),
                ptr::null_mut(),
            )
        }
    }
}

trait StackFrame {
    fn new() -> Self;
    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD;
    fn get_addr(&self) -> *const u8;
}

impl StackFrame for c::STACKFRAME_EX {
    fn new() -> c::STACKFRAME_EX {
        unsafe { mem::zeroed() }
    }

    #[cfg(target_arch = "x86")]
    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
        self.AddrPC.Offset = ctx.Eip as u64;
        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
        self.AddrStack.Offset = ctx.Esp as u64;
        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
        self.AddrFrame.Offset = ctx.Ebp as u64;
        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
        c::IMAGE_FILE_MACHINE_I386
    }
    #[cfg(target_arch = "x86_64")]
    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
        self.AddrPC.Offset = ctx.Rip as u64;
        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
        self.AddrStack.Offset = ctx.Rsp as u64;
        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
        self.AddrFrame.Offset = ctx.Rbp as u64;
        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
        c::IMAGE_FILE_MACHINE_AMD64
    }

    fn get_addr(&self) -> *const u8 {
        (self.AddrPC.Offset - 1) as *const u8
    }
}

impl StackFrame for c::STACKFRAME64 {
    fn new() -> c::STACKFRAME64 {
        unsafe { mem::zeroed() }
    }

    #[cfg(target_arch = "x86")]
    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
        self.AddrPC.Offset = ctx.Eip as u64;
        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
        self.AddrStack.Offset = ctx.Esp as u64;
        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
        self.AddrFrame.Offset = ctx.Ebp as u64;
        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
        c::IMAGE_FILE_MACHINE_I386
    }
    #[cfg(target_arch = "x86_64")]
    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
        self.AddrPC.Offset = ctx.Rip as u64;
        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
        self.AddrStack.Offset = ctx.Rsp as u64;
        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
        self.AddrFrame.Offset = ctx.Rbp as u64;
        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
        c::IMAGE_FILE_MACHINE_AMD64
    }

    fn get_addr(&self) -> *const u8 {
        (self.AddrPC.Offset - 1) as *const u8
    }
}

enum StackWalkVariant {
    StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
    StackWalk64(StackWalk64Fn, printing::PrintingFns64),
}

pub struct BacktraceContext {
    handle: c::HANDLE,
    SymCleanup: SymCleanupFn,
    // Only used in printing for msvc and not gnu
    // The gnu version is effectively a ZST dummy.
    #[allow(dead_code)]
    StackWalkVariant: StackWalkVariant,
    // keeping DynamycLibrary loaded until its functions no longer needed
    #[allow(dead_code)]
    dbghelp: DynamicLibrary,
}

impl Drop for BacktraceContext {
    fn drop(&mut self) {
        unsafe {
            (self.SymCleanup)(self.handle);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#![feature(inclusive_range_syntax, conservative_impl_trait, plugin)]
#![plugin(tarpc_plugins)]

extern crate chrono;
extern crate clap;
extern crate env_logger;
extern crate futures;
#[macro_use]
extern crate log;
#[macro_use]
extern crate tarpc;
extern crate tokio_core;
extern crate futures_cpupool;

use clap::{Arg, App};
use futures::Future;
use futures_cpupool::{CpuFuture, CpuPool};
use std::time::{Duration, Instant, SystemTime};
use tarpc::future::{Connect};
use tarpc::util::{FirstSocketAddr, Never, spawn_core};
use tokio_core::reactor;

service! {
    rpc read(size: u32) -> Vec<u8>;
}

#[derive(Clone)]
struct Server(CpuPool);

impl Server {
    fn new() -> Self {
        Server(CpuPool::new_num_cpus())
    }
}

impl FutureService for Server {
    type ReadFut = CpuFuture<Vec<u8>, Never>;

    fn read(&self, size: u32) -> Self::ReadFut {
        debug!("Server received read({})", size);
        self.0
            .spawn(futures::lazy(move || {
                let mut vec: Vec<u8> = Vec::with_capacity(size as usize);
                for i in 0..size {
                    vec.push((i % 1 << 8) as u8);
                }
                futures::finished(vec)
            }))
    }
}

const CHUNK_SIZE: u32 = 1 << 10;

trait Microseconds {
    fn microseconds(&self) -> i64;
}

impl Microseconds for Duration {
    fn microseconds(&self) -> i64 {
         chrono::Duration::from_std(*self)
             .unwrap()
             .num_microseconds()
             .unwrap()
    }
}

fn run_once(clients: Vec<FutureClient>, concurrency: u32) -> impl Future<Item=(), Error=()> {
    let start = Instant::now();
    let futs = clients.iter()
        .enumerate()
        .cycle()
        .enumerate()
        .take(concurrency as usize)
        .map(|(iteration, (client_id, client))| {
            let start = SystemTime::now();
            debug!("Client {} reading (iteration {})...", client_id, iteration + 1);
            let future = client.read(CHUNK_SIZE).map(move |_| start.elapsed().unwrap());
            future
        })
        // Need an intermediate collection to kick off each future,
        // because futures::collect will iterate sequentially.
        .collect::<Vec<_>>();
    let futs = futures::collect(futs);

    futs.map(move |latencies| {
        let total_time = start.elapsed();

        let sum_latencies = latencies.iter().fold(Duration::new(0, 0), |sum, &dur| sum + dur);
        let mean = sum_latencies / latencies.len() as u32;
        let min_latency = *latencies.iter().min().unwrap();
        let max_latency = *latencies.iter().max().unwrap();

        info!("{} requests => Mean={}µs, Min={}µs, Max={}µs, Total={}µs",
                 latencies.len(),
                 mean.microseconds(),
                 min_latency.microseconds(),
                 max_latency.microseconds(),
                 total_time.microseconds());
    }).map_err(|e| panic!(e))
}

fn main() {
    let _ = env_logger::init();
    let matches = App::new("Tarpc Concurrency")
                          .about("Demonstrates making concurrent requests to a tarpc service.")
                          .arg(Arg::with_name("concurrency")
                               .short("c")
                               .long("concurrency")
                               .value_name("LEVEL")
                               .help("Sets a custom concurrency level")
                               .takes_value(true))
                          .get_matches();
    let concurrency = matches.value_of("concurrency")
        .map(&str::parse)
        .map(Result::unwrap)
        .unwrap_or(10);
    let addr = Server::new().listen("localhost:0".first_socket_addr()).wait().unwrap();
    info!("Server listening on {}.", addr);

    let clients = (0..4)
        // Spin up a couple threads to drive the clients.
        .map(|i| (i, spawn_core()))
        .map(|(i, remote)| {
            info!("Client {} connecting...", i);
            FutureClient::connect_remotely(&addr, &remote)
                .map_err(|e| panic!(e))
        })
        // Need an intermediate collection to connect the clients in parallel,
        // because `futures::collect` iterates sequentially.
        .collect::<Vec<_>>();

    let run = futures::collect(clients).and_then(|clients| run_once(clients, concurrency));

    info!("Starting...");

    // The driver of the main future.
    let mut core = reactor::Core::new().unwrap();
    core.run(run).unwrap();
}
<commit_msg>Count requests in concurrency example<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#![feature(inclusive_range_syntax, conservative_impl_trait, plugin)]
#![plugin(tarpc_plugins)]

extern crate chrono;
extern crate clap;
extern crate env_logger;
extern crate futures;
#[macro_use]
extern crate log;
#[macro_use]
extern crate tarpc;
extern crate tokio_core;
extern crate futures_cpupool;

use clap::{Arg, App};
use futures::Future;
use futures_cpupool::{CpuFuture, CpuPool};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{Duration, Instant, SystemTime};
use tarpc::future::{Connect};
use tarpc::util::{FirstSocketAddr, Never, spawn_core};
use tokio_core::reactor;

service! {
    rpc read(size: u32) -> Vec<u8>;
}

#[derive(Clone)]
struct Server {
    pool: CpuPool,
    request_count: Arc<AtomicUsize>,
}

impl Server {
    fn new() -> Self {
        Server {
            pool: CpuPool::new_num_cpus(),
            request_count: Arc::new(AtomicUsize::new(1)),
        }
    }
}

impl FutureService for Server {
    type ReadFut = CpuFuture<Vec<u8>, Never>;

    fn read(&self, size: u32) -> Self::ReadFut {
        let request_number = self.request_count.fetch_add(1, Ordering::SeqCst);
        debug!("Server received read({}) no. {}", size, request_number);
        self.pool
            .spawn(futures::lazy(move || {
                let mut vec: Vec<u8> = Vec::with_capacity(size as usize);
                for i in 0..size {
                    vec.push((i % 1 << 8) as u8);
                }
                debug!("Server sending response no. {}", request_number);
                futures::finished(vec)
            }))
    }
}

const CHUNK_SIZE: u32 = 1 << 10;

trait Microseconds {
    fn microseconds(&self) -> i64;
}

impl Microseconds for Duration {
    fn microseconds(&self) -> i64 {
         chrono::Duration::from_std(*self)
             .unwrap()
             .num_microseconds()
             .unwrap()
    }
}

fn run_once(clients: Vec<FutureClient>, concurrency: u32) -> impl Future<Item=(), Error=()> {
    let start = Instant::now();
    let futs = clients.iter()
        .enumerate()
        .cycle()
        .enumerate()
        .take(concurrency as usize)
        .map(|(iteration, (client_id, client))| {
            let iteration = iteration + 1;
            let start = SystemTime::now();
            debug!("Client {} reading (iteration {})...", client_id, iteration);
            let future = client.read(CHUNK_SIZE).map(move |_| {
                let elapsed = start.elapsed().unwrap();
                debug!("Client {} received reply (iteration {}).", client_id, iteration);
                elapsed
            });
            future
        })
        // Need an intermediate collection to kick off each future,
        // because futures::collect will iterate sequentially.
        .collect::<Vec<_>>();
    let futs = futures::collect(futs);

    futs.map(move |latencies| {
        let total_time = start.elapsed();

        let sum_latencies = latencies.iter().fold(Duration::new(0, 0), |sum, &dur| sum + dur);
        let mean = sum_latencies / latencies.len() as u32;
        let min_latency = *latencies.iter().min().unwrap();
        let max_latency = *latencies.iter().max().unwrap();

        info!("{} requests => Mean={}µs, Min={}µs, Max={}µs, Total={}µs",
                 latencies.len(),
                 mean.microseconds(),
                 min_latency.microseconds(),
                 max_latency.microseconds(),
                 total_time.microseconds());
    }).map_err(|e| panic!(e))
}

fn main() {
    let _ = env_logger::init();
    let matches = App::new("Tarpc Concurrency")
                          .about("Demonstrates making concurrent requests to a tarpc service.")
                          .arg(Arg::with_name("concurrency")
                               .short("c")
                               .long("concurrency")
                               .value_name("LEVEL")
                               .help("Sets a custom concurrency level")
                               .takes_value(true))
                          .arg(Arg::with_name("clients")
                               .short("n")
                               .long("num_clients")
                               .value_name("AMOUNT")
                               .help("How many clients to distribute requests between")
                               .takes_value(true))
                          .get_matches();
    let concurrency = matches.value_of("concurrency")
        .map(&str::parse)
        .map(Result::unwrap)
        .unwrap_or(10);
    let num_clients = matches.value_of("clients")
        .map(&str::parse)
        .map(Result::unwrap)
        .unwrap_or(4);

    let addr = Server::new().listen("localhost:0".first_socket_addr()).wait().unwrap();
    info!("Server listening on {}.", addr);

    let clients = (0..num_clients)
        // Spin up a couple threads to drive the clients.
        .map(|i| (i, spawn_core()))
        .map(|(i, remote)| {
            info!("Client {} connecting...", i);
            FutureClient::connect_remotely(&addr, &remote)
                .map_err(|e| panic!(e))
        })
        // Need an intermediate collection to connect the clients in parallel,
        // because `futures::collect` iterates sequentially.
        .collect::<Vec<_>>();

    let run = futures::collect(clients).and_then(|clients| run_once(clients, concurrency));

    info!("Starting...");

    // The driver of the main future.
    let mut core = reactor::Core::new().unwrap();

    core.run(run).unwrap();
}
<|endoftext|>