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

use font::{Font, FontDescriptor, FontGroup, FontHandleMethods, FontStyle,
           SelectorPlatformIdentifier};
use font::{SpecifiedFontStyle, UsedFontStyle};
use font_list::FontList;
use servo_util::cache::{Cache, LRUCache};
use servo_util::time::ProfilerChan;

use platform::font::FontHandle;
use platform::font_context::FontContextHandle;
use style::computed_values::font_weight;

use azure::azure_hl::BackendType;
use std::hashmap::HashMap;

use std::rc::RcMut;

// TODO(Rust #3934): creating lots of new dummy styles is a workaround
// for not being able to store symbolic enums in top-level constants.
pub fn dummy_style() -> FontStyle {
    return FontStyle {
        pt_size: 20f64,
        weight: font_weight::Weight300,
        italic: false,
        oblique: false,
        families: ~"serif, sans-serif",
    }
}

pub trait FontContextHandleMethods {
    fn create_font_from_identifier(&self, ~str, UsedFontStyle) -> Result<FontHandle, ()>;
}

pub struct FontContext {
    instance_cache: LRUCache<FontDescriptor, RcMut<Font>>,
    font_list: Option<FontList>, // only needed by layout
    group_cache: LRUCache<SpecifiedFontStyle, RcMut<FontGroup>>,
    handle: FontContextHandle,
    backend: BackendType,
    generic_fonts: HashMap<~str,~str>,
    profiler_chan: ProfilerChan,
}

impl<'self> FontContext {
    pub fn new(backend: BackendType,
           needs_font_list: bool,
           profiler_chan: ProfilerChan)
           -> FontContext {
        let handle = FontContextHandle::new();
        let font_list = if needs_font_list {
                            Some(FontList::new(&handle, profiler_chan.clone())) }
                        else { None };

        // TODO: Allow users to specify these.
        let mut generic_fonts = HashMap::with_capacity(5);
        generic_fonts.insert(~"serif", ~"Times New Roman");
        generic_fonts.insert(~"sans-serif", ~"Arial");
        generic_fonts.insert(~"cursive", ~"Apple Chancery");
        generic_fonts.insert(~"fantasy", ~"Papyrus");
        generic_fonts.insert(~"monospace", ~"Menlo");

        FontContext {
            instance_cache: LRUCache::new(10),
            font_list: font_list,
            group_cache: LRUCache::new(10),
            handle: handle,
            backend: backend,
            generic_fonts: generic_fonts,
            profiler_chan: profiler_chan,
        }
    }

    fn get_font_list(&'self self) -> &'self FontList {
        self.font_list.get_ref()
    }

    pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
        match self.group_cache.find(style) {
            Some(fg) => {
                debug!("font group cache hit");
                fg
            },
            None => {
                debug!("font group cache miss");
                let fg = self.create_font_group(style);
                self.group_cache.insert(style.clone(), fg.clone());
                fg
            }
        }
    }

    pub fn get_font_by_descriptor(&mut self, desc: &FontDescriptor) -> Result<RcMut<Font>, ()> {
        match self.instance_cache.find(desc) {
            Some(f) => {
                debug!("font cache hit");
                Ok(f)
            },
            None => {
                debug!("font cache miss");
                let result = self.create_font_instance(desc);
                match result.clone() {
                    Ok(ref font) => {
                        self.instance_cache.insert(desc.clone(), font.clone());
                    }, _ => {}
                };
                result
            }
        }
    }

    fn transform_family(&self, family: &str) -> ~str {
        // FIXME: Need a find_like() in HashMap.
        let family = family.to_str();
        debug!("(transform family) searching for `{:s}`", family);
        match self.generic_fonts.find(&family) {
            None => family,
            Some(mapped_family) => (*mapped_family).clone()
        }
    }

    fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
        let mut fonts = ~[];

        debug!("(create font group) --- starting ---");

        // TODO(Issue #193): make iteration over 'font-family' more robust.
        for family in style.families.split_iter(',') {
            let family_name = family.trim();
            let transformed_family_name = self.transform_family(family_name);
            debug!("(create font group) transformed family is `{:s}`", transformed_family_name);
            let mut found = false;

            let result = match self.font_list {
                Some(ref mut fl) => {
                    let font_in_family = fl.find_font_in_family(&transformed_family_name, style);
                    match font_in_family {
                        Some(font_entry) => {
                            let font_id =
                                SelectorPlatformIdentifier(font_entry.handle.face_identifier());
                            let font_desc = FontDescriptor::new((*style).clone(), font_id);
                            Some(font_desc)
                        },
                        None => {
                            None
                        }
                    }
                }
                None => None,
            };

            match result {
                Some(ref result) => {
                    found = true;
                    let instance = self.get_font_by_descriptor(result);

                    for font in instance.iter() { fonts.push(font.clone()); }
                },
                _ => {}
            }

            if !found {
                debug!("(create font group) didn't find `{:s}`", transformed_family_name);
            }
        }

        if fonts.len() == 0 {
            let last_resort = FontList::get_last_resort_font_families();
            for family in last_resort.iter() {
                let font_desc = match self.font_list {
                    Some(ref mut font_list) => {
                        let font_desc = {
                            let font_entry = font_list.find_font_in_family(family, style);
                            match font_entry {
                                Some(v) => {
                                    let font_id =
                                        SelectorPlatformIdentifier(v.handle.face_identifier());
                                    Some(FontDescriptor::new((*style).clone(), font_id))
                                },
                                None => {
                                    None
                                }
                            }
                        };
                        font_desc
                    },
                    None => {
                        None
                    }
                };

                match font_desc {
                    Some(ref fd) => {
                        let instance = self.get_font_by_descriptor(fd);

                        for font in instance.iter() {
                            fonts.push(font.clone());
                        }
                    },
                    None => { }
                };
            }
        }
        assert!(fonts.len() > 0);
        // TODO(Issue #179): Split FontStyle into specified and used styles
        let used_style = (*style).clone();

        debug!("(create font group) --- finished ---");

        unsafe { RcMut::new_unchecked(FontGroup::new(style.families.to_owned(), &used_style, fonts)) }
    }

    fn create_font_instance(&self, desc: &FontDescriptor) -> Result<RcMut<Font>, ()> {
        return match &desc.selector {
            // TODO(Issue #174): implement by-platform-name font selectors.
            &SelectorPlatformIdentifier(ref identifier) => {
                let result_handle = self.handle.create_font_from_identifier((*identifier).clone(),
                                                                            desc.style.clone());
                do result_handle.and_then |handle| {
                    Ok(RcMut::new(Font::new_from_adopted_handle(self,
                                                     handle,
                                                     &desc.style,
                                                     self.backend,
                                                     self.profiler_chan.clone())))
                }
            }
        };
    }
}
<commit_msg>auto merge of #1453 : SimonSapin/servo/dead-code, r=larsbergstrom<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use font::{Font, FontDescriptor, FontGroup, FontHandleMethods,
           SelectorPlatformIdentifier};
use font::{SpecifiedFontStyle, UsedFontStyle};
use font_list::FontList;
use servo_util::cache::{Cache, LRUCache};
use servo_util::time::ProfilerChan;

use platform::font::FontHandle;
use platform::font_context::FontContextHandle;

use azure::azure_hl::BackendType;
use std::hashmap::HashMap;

use std::rc::RcMut;

pub trait FontContextHandleMethods {
    fn create_font_from_identifier(&self, ~str, UsedFontStyle) -> Result<FontHandle, ()>;
}

pub struct FontContext {
    instance_cache: LRUCache<FontDescriptor, RcMut<Font>>,
    font_list: Option<FontList>, // only needed by layout
    group_cache: LRUCache<SpecifiedFontStyle, RcMut<FontGroup>>,
    handle: FontContextHandle,
    backend: BackendType,
    generic_fonts: HashMap<~str,~str>,
    profiler_chan: ProfilerChan,
}

impl<'self> FontContext {
    pub fn new(backend: BackendType,
           needs_font_list: bool,
           profiler_chan: ProfilerChan)
           -> FontContext {
        let handle = FontContextHandle::new();
        let font_list = if needs_font_list {
                            Some(FontList::new(&handle, profiler_chan.clone())) }
                        else { None };

        // TODO: Allow users to specify these.
        let mut generic_fonts = HashMap::with_capacity(5);
        generic_fonts.insert(~"serif", ~"Times New Roman");
        generic_fonts.insert(~"sans-serif", ~"Arial");
        generic_fonts.insert(~"cursive", ~"Apple Chancery");
        generic_fonts.insert(~"fantasy", ~"Papyrus");
        generic_fonts.insert(~"monospace", ~"Menlo");

        FontContext {
            instance_cache: LRUCache::new(10),
            font_list: font_list,
            group_cache: LRUCache::new(10),
            handle: handle,
            backend: backend,
            generic_fonts: generic_fonts,
            profiler_chan: profiler_chan,
        }
    }

    fn get_font_list(&'self self) -> &'self FontList {
        self.font_list.get_ref()
    }

    pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
        match self.group_cache.find(style) {
            Some(fg) => {
                debug!("font group cache hit");
                fg
            },
            None => {
                debug!("font group cache miss");
                let fg = self.create_font_group(style);
                self.group_cache.insert(style.clone(), fg.clone());
                fg
            }
        }
    }

    pub fn get_font_by_descriptor(&mut self, desc: &FontDescriptor) -> Result<RcMut<Font>, ()> {
        match self.instance_cache.find(desc) {
            Some(f) => {
                debug!("font cache hit");
                Ok(f)
            },
            None => {
                debug!("font cache miss");
                let result = self.create_font_instance(desc);
                match result.clone() {
                    Ok(ref font) => {
                        self.instance_cache.insert(desc.clone(), font.clone());
                    }, _ => {}
                };
                result
            }
        }
    }

    fn transform_family(&self, family: &str) -> ~str {
        // FIXME: Need a find_like() in HashMap.
        let family = family.to_str();
        debug!("(transform family) searching for `{:s}`", family);
        match self.generic_fonts.find(&family) {
            None => family,
            Some(mapped_family) => (*mapped_family).clone()
        }
    }

    fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
        let mut fonts = ~[];

        debug!("(create font group) --- starting ---");

        // TODO(Issue #193): make iteration over 'font-family' more robust.
        for family in style.families.split_iter(',') {
            let family_name = family.trim();
            let transformed_family_name = self.transform_family(family_name);
            debug!("(create font group) transformed family is `{:s}`", transformed_family_name);
            let mut found = false;

            let result = match self.font_list {
                Some(ref mut fl) => {
                    let font_in_family = fl.find_font_in_family(&transformed_family_name, style);
                    match font_in_family {
                        Some(font_entry) => {
                            let font_id =
                                SelectorPlatformIdentifier(font_entry.handle.face_identifier());
                            let font_desc = FontDescriptor::new((*style).clone(), font_id);
                            Some(font_desc)
                        },
                        None => {
                            None
                        }
                    }
                }
                None => None,
            };

            match result {
                Some(ref result) => {
                    found = true;
                    let instance = self.get_font_by_descriptor(result);

                    for font in instance.iter() { fonts.push(font.clone()); }
                },
                _ => {}
            }

            if !found {
                debug!("(create font group) didn't find `{:s}`", transformed_family_name);
            }
        }

        if fonts.len() == 0 {
            let last_resort = FontList::get_last_resort_font_families();
            for family in last_resort.iter() {
                let font_desc = match self.font_list {
                    Some(ref mut font_list) => {
                        let font_desc = {
                            let font_entry = font_list.find_font_in_family(family, style);
                            match font_entry {
                                Some(v) => {
                                    let font_id =
                                        SelectorPlatformIdentifier(v.handle.face_identifier());
                                    Some(FontDescriptor::new((*style).clone(), font_id))
                                },
                                None => {
                                    None
                                }
                            }
                        };
                        font_desc
                    },
                    None => {
                        None
                    }
                };

                match font_desc {
                    Some(ref fd) => {
                        let instance = self.get_font_by_descriptor(fd);

                        for font in instance.iter() {
                            fonts.push(font.clone());
                        }
                    },
                    None => { }
                };
            }
        }
        assert!(fonts.len() > 0);
        // TODO(Issue #179): Split FontStyle into specified and used styles
        let used_style = (*style).clone();

        debug!("(create font group) --- finished ---");

        unsafe { RcMut::new_unchecked(FontGroup::new(style.families.to_owned(), &used_style, fonts)) }
    }

    fn create_font_instance(&self, desc: &FontDescriptor) -> Result<RcMut<Font>, ()> {
        return match &desc.selector {
            // TODO(Issue #174): implement by-platform-name font selectors.
            &SelectorPlatformIdentifier(ref identifier) => {
                let result_handle = self.handle.create_font_from_identifier((*identifier).clone(),
                                                                            desc.style.clone());
                do result_handle.and_then |handle| {
                    Ok(RcMut::new(Font::new_from_adopted_handle(self,
                                                     handle,
                                                     &desc.style,
                                                     self.backend,
                                                     self.profiler_chan.clone())))
                }
            }
        };
    }
}
<|endoftext|>


<commit_before>//! Create cycles in a timely dataflow graph.

use Data;

use progress::{Timestamp, PathSummary};
use progress::frontier::Antichain;
use order::Product;

use dataflow::channels::pushers::Tee;
use dataflow::channels::pact::Pipeline;
use dataflow::{Stream, Scope};
use dataflow::scopes::child::Iterative;
use dataflow::operators::generic::builder_rc::OperatorBuilder;
use dataflow::operators::generic::OutputWrapper;

/// Creates a `Stream` and a `Handle` to later bind the source of that `Stream`.
pub trait Feedback<G: Scope> {
    /// Creates a `Stream` and a `Handle` to later bind the source of that `Stream`.
    ///
    /// The resulting `Stream` will have its data defined by a future call to `connect_loop` with
    /// its `Handle` passed as an argument. Data passed through the stream will have their
    /// timestamps advanced by `summary`, and will be dropped if the result exceeds `limit`.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{Feedback, ConnectLoop, ToStream, Concat, Inspect, BranchWhen};
    ///
    /// timely::example(|scope| {
    ///     // circulate 0..10 for 100 iterations.
    ///     let (handle, cycle) = scope.feedback(1);
    ///     (0..10).to_stream(scope)
    ///            .concat(&cycle)
    ///            .inspect(|x| println!("seen: {:?}", x))
    ///            .branch_when(|t| t < &100).1
    ///            .connect_loop(handle);
    /// });
    /// ```
    fn feedback<D: Data>(&mut self, summary: <G::Timestamp as Timestamp>::Summary) -> (Handle<G, D>, Stream<G, D>);
}

/// Creates a `Stream` and a `Handle` to later bind the source of that `Stream`.
pub trait LoopVariable<'a, G: Scope, T: Timestamp> {
    /// Creates a `Stream` and a `Handle` to later bind the source of that `Stream`.
    ///
    /// The resulting `Stream` will have its data defined by a future call to `connect_loop` with
    /// its `Handle` passed as an argument. Data passed through the stream will have their
    /// timestamps advanced by `summary`, and will be dropped if the result exceeds `limit`.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{LoopVariable, ConnectLoop, ToStream, Concat, Inspect, BranchWhen};
    ///
    /// timely::example(|scope| {
    ///     // circulate 0..10 for 100 iterations.
    ///     scope.iterative::<usize,_,_>(|inner| {
    ///         let (handle, cycle) = inner.loop_variable(1);
    ///         (0..10).to_stream(inner)
    ///                .concat(&cycle)
    ///                .inspect(|x| println!("seen: {:?}", x))
    ///                .branch_when(|t| t.inner < 100).1
    ///                .connect_loop(handle);
    ///     });
    /// });
    /// ```
    fn loop_variable<D: Data>(&mut self, summary: T::Summary) -> (Handle<Iterative<'a, G, T>, D>, Stream<Iterative<'a, G, T>, D>);
}

impl<G: Scope> Feedback<G> for G {
    fn feedback<D: Data>(&mut self, summary: <G::Timestamp as Timestamp>::Summary) -> (Handle<G, D>, Stream<G, D>) {

        if summary == Default::default() {
            panic!("Cannot use default summary for a loop variable");
        }

        let mut builder = OperatorBuilder::new("Feedback".to_owned(), self.clone());
        let (output, stream) = builder.new_output();

        (Handle { builder, summary, output }, stream)
    }
}

impl<'a, G: Scope, T: Timestamp> LoopVariable<'a, G, T> for Iterative<'a, G, T> {
    fn loop_variable<D: Data>(&mut self, summary: T::Summary) -> (Handle<Iterative<'a, G, T>, D>, Stream<Iterative<'a, G, T>, D>) {
        self.feedback(Product::new(Default::default(), summary))
    }
}

/// Connect a `Stream` to the input of a loop variable.
pub trait ConnectLoop<G: Scope, D: Data> {
    /// Connect a `Stream` to be the input of a loop variable.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{Feedback, ConnectLoop, ToStream, Concat, Inspect, BranchWhen};
    ///
    /// timely::example(|scope| {
    ///     // circulate 0..10 for 100 iterations.
    ///     let (handle, cycle) = scope.feedback(1);
    ///     (0..10).to_stream(scope)
    ///            .concat(&cycle)
    ///            .inspect(|x| println!("seen: {:?}", x))
    ///            .branch_when(|t| t < &100).1
    ///            .connect_loop(handle);
    /// });
    /// ```
    fn connect_loop(&self, Handle<G, D>);
}

impl<G: Scope, D: Data> ConnectLoop<G, D> for Stream<G, D> {
    fn connect_loop(&self, helper: Handle<G, D>) {

        let mut builder = helper.builder;
        let summary = helper.summary;
        let mut output = helper.output;

        let mut input = builder.new_input_connection(self, Pipeline, vec![Antichain::from_elem(summary.clone())]);

        let mut vector = Vec::new();
        builder.build(move |_capability| move |_frontier| {
            let mut output = output.activate();
            input.for_each(|cap, data| {
                data.swap(&mut vector);
                if let Some(new_time) = summary.results_in(cap.time()) {
                    let new_cap = cap.delayed(&new_time);
                    output
                        .session(&new_cap)
                        .give_vec(&mut vector);
                }
            });
        });
    }
}

/// A handle used to bind the source of a loop variable.
pub struct Handle<G: Scope, D: Data> {
    builder: OperatorBuilder<G>,
    summary: <G::Timestamp as Timestamp>::Summary,
    output: OutputWrapper<G::Timestamp, D, Tee<G::Timestamp, D>>,
}
<commit_msg>relax feedback requirement<commit_after>//! Create cycles in a timely dataflow graph.

use Data;

use progress::{Timestamp, PathSummary};
use progress::frontier::Antichain;
use order::Product;

use dataflow::channels::pushers::Tee;
use dataflow::channels::pact::Pipeline;
use dataflow::{Stream, Scope};
use dataflow::scopes::child::Iterative;
use dataflow::operators::generic::builder_rc::OperatorBuilder;
use dataflow::operators::generic::OutputWrapper;

/// Creates a `Stream` and a `Handle` to later bind the source of that `Stream`.
pub trait Feedback<G: Scope> {
    /// Creates a `Stream` and a `Handle` to later bind the source of that `Stream`.
    ///
    /// The resulting `Stream` will have its data defined by a future call to `connect_loop` with
    /// its `Handle` passed as an argument. Data passed through the stream will have their
    /// timestamps advanced by `summary`, and will be dropped if the result exceeds `limit`.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{Feedback, ConnectLoop, ToStream, Concat, Inspect, BranchWhen};
    ///
    /// timely::example(|scope| {
    ///     // circulate 0..10 for 100 iterations.
    ///     let (handle, cycle) = scope.feedback(1);
    ///     (0..10).to_stream(scope)
    ///            .concat(&cycle)
    ///            .inspect(|x| println!("seen: {:?}", x))
    ///            .branch_when(|t| t < &100).1
    ///            .connect_loop(handle);
    /// });
    /// ```
    fn feedback<D: Data>(&mut self, summary: <G::Timestamp as Timestamp>::Summary) -> (Handle<G, D>, Stream<G, D>);
}

/// Creates a `Stream` and a `Handle` to later bind the source of that `Stream`.
pub trait LoopVariable<'a, G: Scope, T: Timestamp> {
    /// Creates a `Stream` and a `Handle` to later bind the source of that `Stream`.
    ///
    /// The resulting `Stream` will have its data defined by a future call to `connect_loop` with
    /// its `Handle` passed as an argument. Data passed through the stream will have their
    /// timestamps advanced by `summary`, and will be dropped if the result exceeds `limit`.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{LoopVariable, ConnectLoop, ToStream, Concat, Inspect, BranchWhen};
    ///
    /// timely::example(|scope| {
    ///     // circulate 0..10 for 100 iterations.
    ///     scope.iterative::<usize,_,_>(|inner| {
    ///         let (handle, cycle) = inner.loop_variable(1);
    ///         (0..10).to_stream(inner)
    ///                .concat(&cycle)
    ///                .inspect(|x| println!("seen: {:?}", x))
    ///                .branch_when(|t| t.inner < 100).1
    ///                .connect_loop(handle);
    ///     });
    /// });
    /// ```
    fn loop_variable<D: Data>(&mut self, summary: T::Summary) -> (Handle<Iterative<'a, G, T>, D>, Stream<Iterative<'a, G, T>, D>);
}

impl<G: Scope> Feedback<G> for G {
    fn feedback<D: Data>(&mut self, summary: <G::Timestamp as Timestamp>::Summary) -> (Handle<G, D>, Stream<G, D>) {

        let mut builder = OperatorBuilder::new("Feedback".to_owned(), self.clone());
        let (output, stream) = builder.new_output();

        (Handle { builder, summary, output }, stream)
    }
}

impl<'a, G: Scope, T: Timestamp> LoopVariable<'a, G, T> for Iterative<'a, G, T> {
    fn loop_variable<D: Data>(&mut self, summary: T::Summary) -> (Handle<Iterative<'a, G, T>, D>, Stream<Iterative<'a, G, T>, D>) {
        self.feedback(Product::new(Default::default(), summary))
    }
}

/// Connect a `Stream` to the input of a loop variable.
pub trait ConnectLoop<G: Scope, D: Data> {
    /// Connect a `Stream` to be the input of a loop variable.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{Feedback, ConnectLoop, ToStream, Concat, Inspect, BranchWhen};
    ///
    /// timely::example(|scope| {
    ///     // circulate 0..10 for 100 iterations.
    ///     let (handle, cycle) = scope.feedback(1);
    ///     (0..10).to_stream(scope)
    ///            .concat(&cycle)
    ///            .inspect(|x| println!("seen: {:?}", x))
    ///            .branch_when(|t| t < &100).1
    ///            .connect_loop(handle);
    /// });
    /// ```
    fn connect_loop(&self, Handle<G, D>);
}

impl<G: Scope, D: Data> ConnectLoop<G, D> for Stream<G, D> {
    fn connect_loop(&self, helper: Handle<G, D>) {

        let mut builder = helper.builder;
        let summary = helper.summary;
        let mut output = helper.output;

        let mut input = builder.new_input_connection(self, Pipeline, vec![Antichain::from_elem(summary.clone())]);

        let mut vector = Vec::new();
        builder.build(move |_capability| move |_frontier| {
            let mut output = output.activate();
            input.for_each(|cap, data| {
                data.swap(&mut vector);
                if let Some(new_time) = summary.results_in(cap.time()) {
                    let new_cap = cap.delayed(&new_time);
                    output
                        .session(&new_cap)
                        .give_vec(&mut vector);
                }
            });
        });
    }
}

/// A handle used to bind the source of a loop variable.
pub struct Handle<G: Scope, D: Data> {
    builder: OperatorBuilder<G>,
    summary: <G::Timestamp as Timestamp>::Summary,
    output: OutputWrapper<G::Timestamp, D, Tee<G::Timestamp, D>>,
}
<|endoftext|>


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

// Code to handle cleanup after a failed operation.

use super::super::engine::HasUuid;
use super::super::errors::{EngineResult, EngineError, ErrorEnum};

use super::blockdev::BlockDev;
use super::pool::StratPool;

/// Wipe a Vec of blockdevs of their identifying headers.
/// Return an error if any of the blockdevs could not be wiped.
/// If an error occurs while wiping a blockdev, attempt to wipe all remaining.
pub fn wipe_blockdevs(mut blockdevs: Vec<BlockDev>) -> EngineResult<()> {
    let mut unerased_devnodes = Vec::new();

    for bd in blockdevs.drain(..) {
        let bd_devnode = bd.devnode.clone();
        bd.wipe_metadata()
            .unwrap_or_else(|_| unerased_devnodes.push(bd_devnode));
    }

    if unerased_devnodes.is_empty() {
        Ok(())
    } else {
        let err_msg = format!("Failed to wipe already initialized devnodes: {:?}",
                              unerased_devnodes);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}

/// Teardown pools.
pub fn teardown_pools(mut pools: Vec<StratPool>) -> EngineResult<()> {
    let mut untorndown_pools = Vec::new();
    for pool in pools.drain(..) {
        let pool_uuid = *pool.uuid();
        pool.teardown()
            .unwrap_or_else(|_| untorndown_pools.push(pool_uuid));
    }
    if untorndown_pools.is_empty() {
        Ok(())
    } else {
        let err_msg = format!("Failed to teardown already set up pools: {:?}",
                              untorndown_pools);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}
<commit_msg>Don't drain Vecs<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle cleanup after a failed operation.

use super::super::engine::HasUuid;
use super::super::errors::{EngineResult, EngineError, ErrorEnum};

use super::blockdev::BlockDev;
use super::pool::StratPool;

/// Wipe a Vec of blockdevs of their identifying headers.
/// Return an error if any of the blockdevs could not be wiped.
/// If an error occurs while wiping a blockdev, attempt to wipe all remaining.
pub fn wipe_blockdevs(blockdevs: Vec<BlockDev>) -> EngineResult<()> {
    let mut unerased_devnodes = Vec::new();

    for bd in blockdevs {
        let bd_devnode = bd.devnode.clone();
        bd.wipe_metadata()
            .unwrap_or_else(|_| unerased_devnodes.push(bd_devnode));
    }

    if unerased_devnodes.is_empty() {
        Ok(())
    } else {
        let err_msg = format!("Failed to wipe already initialized devnodes: {:?}",
                              unerased_devnodes);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}

/// Teardown pools.
pub fn teardown_pools(pools: Vec<StratPool>) -> EngineResult<()> {
    let mut untorndown_pools = Vec::new();
    for pool in pools {
        let pool_uuid = *pool.uuid();
        pool.teardown()
            .unwrap_or_else(|_| untorndown_pools.push(pool_uuid));
    }
    if untorndown_pools.is_empty() {
        Ok(())
    } else {
        let err_msg = format!("Failed to teardown already set up pools: {:?}",
                              untorndown_pools);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}
<|endoftext|>


<commit_before>use std::io;

#[deriving(Eq)]
enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

fn read_nows(input: &str, start: uint) -> Option<char> {
	input.iter().skip(start).skip_while(|&c| c == ' ' || c == '\t').next()
}

fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| c == ' ' || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if read_nows(input, i) == Some(')') => return Some((~List(list), i)),
			None => return None
		}
	}
}

fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| c != ' ' && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len() || input.is_whitespace() || input.slice(start, input.len()).is_whitespace()) {
		return None
	}

	match input[start] as char {
		' ' => read_value(input, start+1),
		'(' => read_list(input, start+1),
		')' => None,
		c if c.is_digit() || c == '.' => read_number(input, start),
		c => read_atom(input, start)
	}
}

fn parse(input: &str) -> Option<Value> {
	/*do io::with_str_reader(input) |r| {
		//let c =
		println("blah: " + input + " -> " + read_token(r));
		List(~[])
	}*/
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

#[test]
fn test_sexp() {
	assert_eq!(parse(""), None);
	assert_eq!(parse("123"), Some(Num(123.0)));
	assert_eq!(parse("()"), Some(List(~[])));
	assert_eq!(parse("3.14159265358"), Some(Num(3.14159265358)));
	assert_eq!(parse("(hi)"), Some(List(~[Atom(~"hi")])));
	assert_eq!(parse("(1)"), Some(List(~[Num(1.0)])));
	assert_eq!(parse("  (  1  )  "), Some(List(~[Num(1.0)])));
	assert_eq!(parse("(hi there)"), Some(List(~[Atom(~"hi"), Atom(~"there")])));
	assert_eq!(parse("(hi (there))"), Some(List(~[Atom(~"hi"), List(~[Atom(~"there")])])));
	assert_eq!(parse("(hi 123456)"), Some(List(~[Atom(~"hi"), Num(123456.0)])));
	assert_eq!(parse("(())"), Some(List(~[List(~[])])));
	assert_eq!(parse("  (  (  )  )  )"), Some(List(~[List(~[])])));
	assert_eq!(parse("(hi (there (fellow (human-bot!))))"), Some(
		List(~[Atom(~"hi"),
			List(~[Atom(~"there"),
				List(~[Atom(~"fellow"),
					List(~[Atom(~"human-bot!")])])])])
	));
}<commit_msg>remove whitespace tests in read_value<commit_after>use std::io;

#[deriving(Eq)]
enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

fn read_nows(input: &str, start: uint) -> Option<char> {
	input.iter().skip(start).skip_while(|&c| c == ' ' || c == '\t').next()
}

fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| c == ' ' || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if read_nows(input, i) == Some(')') => return Some((~List(list), i)),
			None => return None
		}
	}
}

fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| c != ' ' && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len()) {
		return None
	}

	match input[start] as char {
		' ' => read_value(input, start+1),
		'(' => read_list(input, start+1),
		')' => None,
		c if c.is_digit() || c == '.' => read_number(input, start),
		c => read_atom(input, start)
	}
}

fn parse(input: &str) -> Option<Value> {
	/*do io::with_str_reader(input) |r| {
		//let c =
		println("blah: " + input + " -> " + read_token(r));
		List(~[])
	}*/
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

#[test]
fn test_sexp() {
	assert_eq!(parse(""), None);
	assert_eq!(parse("123"), Some(Num(123.0)));
	assert_eq!(parse("()"), Some(List(~[])));
	assert_eq!(parse("3.14159265358"), Some(Num(3.14159265358)));
	assert_eq!(parse("(hi)"), Some(List(~[Atom(~"hi")])));
	assert_eq!(parse("(1)"), Some(List(~[Num(1.0)])));
	assert_eq!(parse("  (  1  )  "), Some(List(~[Num(1.0)])));
	assert_eq!(parse("(hi there)"), Some(List(~[Atom(~"hi"), Atom(~"there")])));
	assert_eq!(parse("(hi (there))"), Some(List(~[Atom(~"hi"), List(~[Atom(~"there")])])));
	assert_eq!(parse("(hi 123456)"), Some(List(~[Atom(~"hi"), Num(123456.0)])));
	assert_eq!(parse("(())"), Some(List(~[List(~[])])));
	assert_eq!(parse("  (  (  )  )  )"), Some(List(~[List(~[])])));
	assert_eq!(parse("(hi (there (fellow (human-bot!))))"), Some(
		List(~[Atom(~"hi"),
			List(~[Atom(~"there"),
				List(~[Atom(~"fellow"),
					List(~[Atom(~"human-bot!")])])])])
	));
}<|endoftext|>


<commit_before>#![recursion_limit = "128"]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;
extern crate syn;

mod getable;
mod pushable;
mod shared;
mod userdata;
mod vm_type;

#[proc_macro_derive(Getable)]
pub fn getable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    getable::derive(input.into()).into()
}

#[proc_macro_derive(Pushable)]
pub fn pushable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    pushable::derive(input.into()).into()
}

#[proc_macro_derive(Userdata)]
pub fn userdata(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    userdata::derive(input.into()).into()
}

#[proc_macro_derive(VmType, attributes(gluon))]
pub fn vm_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    vm_type::derive(input.into()).into()
}
<commit_msg>Add crate documentation<commit_after>//! Various macros for integrating with the `gluon` vm.
//!
//! ## Derive Macros
//!
//! Custom derives for the following `gluon`-Traits are available:
//!
//! ### Getable
//!
//! Derives `Getable` for any enum or struct as long as all fields also implement
//! `Getable` (generic type parameters included). If the type is generic over a
//! lifetime, the lifetime will be constrained to that of the `'vm` lifetime in the
//! trait definition.
//!
//! #### Examples
//!
//! Marhalling this gluon type:
//!
//! ```gluon
//! type Comment =
//!     | Normal String
//!     | Multiline String
//!     | Doc String
//! ```
//!
//! To this rust enum:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! enum Comment {
//!     Normal(String),
//!     Multiline(String),
//!     Doc(String),
//! }
//! # fn main() {}
//! ```
//!
//! ### Pushable
//!
//! Derives `Pushable` for any enum or struct as long as all fields also implement
//! `Pushable` (generic type parameters included).
//!
//! #### Examples
//!
//! Allowing the `User` struct to be marshalled to gluon code:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! #[derive(Pushable)]
//! struct User {
//!     name: String,
//!     age: u32,
//! }
//! # fn main() {}
//! ```
//!
//! As this compatible Record:
//!
//! ```gluon
//! type User = { name: String, age: Int }
//! ```
//!
//! ### VmType
//!
//! Derives `VmType` for a rust type, mapping it to a gluon type. You must specify
//! the corresponding gluon type with the `#[gluon(vm_type = "<gluon_type>")]` attribute,
//! where the gluon type is the fully qualified type name. The gluon type must be
//! registered before a binding using the mapped rust type is first loaded.
//!
//! If the rust type has type parameters, they have to implement `VmType` as well.
//! All lifetimes have to be `'static`.
//!
//! #### Examples
//!
//! Assuming the following gluon type in the module `types`:
//!
//! ```gluon
//! type Either l r = | Left l | Right r
//! ```
//!
//! This will map the correct rust type to it:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! #[derive(VmType)]
//! #[gluon(vm_type = "types.Either")]
//! enum Either<L, R> {
//!     Left(L),
//!     Right(R),
//! }
//! # fn main() {}
//! ```
//!
//! ### Userdata
//!
//! Derives `Userdata` and the required `Traverseable` and `VmType` for a rust type.
//! Note that you will still have to use `Thread::register_type` to register the
//! rust type with the vm before it is used.
//!
//! #### Examples
//!
//! Deriving `Userdata` for a type that will be opaque for the gluon code:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! use std::sync::Arc;
//!
//! // Userdata requires Debug + Send + Sync
//! #[derive(Userdata, Debug)]
//! struct Ident {
//!     group: Arc<str>,
//!     name: Arc<str>,
//! }
//! # fn main() {}
//! ```
//!

#![recursion_limit = "128"]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;
extern crate syn;

mod getable;
mod pushable;
mod shared;
mod userdata;
mod vm_type;

#[proc_macro_derive(Getable)]
pub fn getable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    getable::derive(input.into()).into()
}

#[proc_macro_derive(Pushable)]
pub fn pushable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    pushable::derive(input.into()).into()
}

#[proc_macro_derive(Userdata)]
pub fn userdata(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    userdata::derive(input.into()).into()
}

#[proc_macro_derive(VmType, attributes(gluon))]
pub fn vm_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    vm_type::derive(input.into()).into()
}
<|endoftext|>


<commit_before>//! Various macros for integrating with the `gluon` vm.
//!
//! ## Derive Macros
//!
//! Custom derives for the following `gluon`-Traits are available:
//!
//! ### Getable
//!
//! Derives `Getable` for any enum or struct as long as all fields also implement
//! `Getable` (generic type parameters included). If the type is generic over a
//! lifetime, the lifetime will be constrained to that of the `'vm` lifetime in the
//! trait definition.
//!
//! #### Examples
//!
//! Marhalling this gluon type:
//!
//! ```gluon
//! type Comment =
//!     | Normal String
//!     | Multiline String
//!     | Doc String
//! ```
//!
//! To this rust enum:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! enum Comment {
//!     Normal(String),
//!     Multiline(String),
//!     Doc(String),
//! }
//! # fn main() {}
//! ```
//!
//! ### Pushable
//!
//! Derives `Pushable` for any enum or struct as long as all fields also implement
//! `Pushable` (generic type parameters included).
//!
//! #### Examples
//!
//! Allowing the `User` struct to be marshalled to gluon code:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! #[derive(Pushable)]
//! struct User {
//!     name: String,
//!     age: u32,
//! }
//! # fn main() {}
//! ```
//!
//! As this compatible Record:
//!
//! ```gluon
//! type User = { name: String, age: Int }
//! ```
//!
//! ### VmType
//!
//! Derives `VmType` for a rust type, mapping it to a gluon type. You must specify
//! the corresponding gluon type with the `#[gluon(vm_type = "<gluon_type>")]` attribute,
//! where the gluon type is the fully qualified type name. The gluon type must be
//! registered before a binding using the mapped rust type is first loaded.
//!
//! If the rust type has type parameters, they have to implement `VmType` as well.
//! All lifetimes have to be `'static`.
//!
//! #### Examples
//!
//! Assuming the following gluon type in the module `types`:
//!
//! ```gluon
//! type Either l r = | Left l | Right r
//! ```
//!
//! This will map the correct rust type to it:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! #[derive(VmType)]
//! #[gluon(vm_type = "types.Either")]
//! enum Either<L, R> {
//!     Left(L),
//!     Right(R),
//! }
//! # fn main() {}
//! ```
//!
//! ### Userdata
//!
//! Derives `Userdata` and the required `Traverseable` and `VmType` for a rust type.
//! Note that you will still have to use `Thread::register_type` to register the
//! rust type with the vm before it is used.
//!
//! #### Examples
//!
//! Deriving `Userdata` for a type that will be opaque for the gluon code:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! use std::sync::Arc;
//!
//! // Userdata requires Debug + Send + Sync
//! #[derive(Userdata, Debug)]
//! struct Ident {
//!     group: Arc<str>,
//!     name: Arc<str>,
//! }
//! # fn main() {}
//! ```
//!

#![recursion_limit = "128"]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;
extern crate syn;

mod getable;
mod pushable;
mod shared;
mod userdata;
mod vm_type;

#[proc_macro_derive(Getable)]
pub fn getable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    getable::derive(input.into()).into()
}

#[proc_macro_derive(Pushable)]
pub fn pushable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    pushable::derive(input.into()).into()
}

#[proc_macro_derive(Userdata)]
pub fn userdata(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    userdata::derive(input.into()).into()
}

#[proc_macro_derive(VmType, attributes(gluon))]
pub fn vm_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    vm_type::derive(input.into()).into()
}
<commit_msg>Hide derive functions from docs<commit_after>//! Various macros for integrating with the `gluon` vm.
//!
//! ## Derive Macros
//!
//! Custom derives for the following `gluon`-Traits are available:
//!
//! ### Getable
//!
//! Derives `Getable` for any enum or struct as long as all fields also implement
//! `Getable` (generic type parameters included). If the type is generic over a
//! lifetime, the lifetime will be constrained to that of the `'vm` lifetime in the
//! trait definition.
//!
//! #### Examples
//!
//! Marhalling this gluon type:
//!
//! ```gluon
//! type Comment =
//!     | Normal String
//!     | Multiline String
//!     | Doc String
//! ```
//!
//! To this rust enum:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! enum Comment {
//!     Normal(String),
//!     Multiline(String),
//!     Doc(String),
//! }
//! # fn main() {}
//! ```
//!
//! ### Pushable
//!
//! Derives `Pushable` for any enum or struct as long as all fields also implement
//! `Pushable` (generic type parameters included).
//!
//! #### Examples
//!
//! Allowing the `User` struct to be marshalled to gluon code:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! #[derive(Pushable)]
//! struct User {
//!     name: String,
//!     age: u32,
//! }
//! # fn main() {}
//! ```
//!
//! As this compatible Record:
//!
//! ```gluon
//! type User = { name: String, age: Int }
//! ```
//!
//! ### VmType
//!
//! Derives `VmType` for a rust type, mapping it to a gluon type. You must specify
//! the corresponding gluon type with the `#[gluon(vm_type = "<gluon_type>")]` attribute,
//! where the gluon type is the fully qualified type name. The gluon type must be
//! registered before a binding using the mapped rust type is first loaded.
//!
//! If the rust type has type parameters, they have to implement `VmType` as well.
//! All lifetimes have to be `'static`.
//!
//! #### Examples
//!
//! Assuming the following gluon type in the module `types`:
//!
//! ```gluon
//! type Either l r = | Left l | Right r
//! ```
//!
//! This will map the correct rust type to it:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! #[derive(VmType)]
//! #[gluon(vm_type = "types.Either")]
//! enum Either<L, R> {
//!     Left(L),
//!     Right(R),
//! }
//! # fn main() {}
//! ```
//!
//! ### Userdata
//!
//! Derives `Userdata` and the required `Traverseable` and `VmType` for a rust type.
//! Note that you will still have to use `Thread::register_type` to register the
//! rust type with the vm before it is used.
//!
//! #### Examples
//!
//! Deriving `Userdata` for a type that will be opaque for the gluon code:
//!
//! ```rust
//! #[macro_use]
//! extern crate gluon_codegen;
//! extern crate gluon;
//!
//! use std::sync::Arc;
//!
//! // Userdata requires Debug + Send + Sync
//! #[derive(Userdata, Debug)]
//! struct Ident {
//!     group: Arc<str>,
//!     name: Arc<str>,
//! }
//! # fn main() {}
//! ```
//!

#![recursion_limit = "128"]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;
extern crate syn;

mod getable;
mod pushable;
mod shared;
mod userdata;
mod vm_type;

#[doc(hidden)]
#[proc_macro_derive(Getable)]
pub fn getable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    getable::derive(input.into()).into()
}

#[doc(hidden)]
#[proc_macro_derive(Pushable)]
pub fn pushable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    pushable::derive(input.into()).into()
}

#[doc(hidden)]
#[proc_macro_derive(Userdata)]
pub fn userdata(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    userdata::derive(input.into()).into()
}

#[doc(hidden)]
#[proc_macro_derive(VmType, attributes(gluon))]
pub fn vm_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    vm_type::derive(input.into()).into()
}
<|endoftext|>


<commit_before>// Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
  clippy::all,
  clippy::default_trait_access,
  clippy::expl_impl_clone_on_copy,
  clippy::if_not_else,
  clippy::needless_continue,
  clippy::unseparated_literal_suffix,
  // TODO: Falsely triggers for async/await:
  //   see https://github.com/rust-lang/rust-clippy/issues/5360
  // clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
  clippy::len_without_is_empty,
  clippy::redundant_field_names,
  clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]

use std::convert::AsRef;
use std::env;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::SystemTime;

use log::debug;
use strum::VariantNames;
use strum_macros::{AsRefStr, EnumString, EnumVariantNames};

use client::option_id;
use client::options::OptionParser;
use client::pantsd;
use client::render_choice;

// TODO(John Sirois): Maybe consolidate with PythonLogLevel in src/rust/engine/logging/src/lib.rs.
#[derive(AsRefStr, EnumString, EnumVariantNames)]
#[strum(serialize_all = "snake_case")]
enum PythonLogLevel {
  Trace,
  Debug,
  Info,
  Warn,
  Error,
}

async fn execute(start: SystemTime) -> Result<i32, String> {
  let options_parser = OptionParser::new()?;

  let use_pantsd = options_parser.parse_bool(&option_id!("pantsd"), true)?;
  if !use_pantsd.value {
    return Err(format!(
      "Pantsd has been turned off via {option_source:?}.",
      option_source = use_pantsd.source
    ));
  }

  let level_option = option_id!(-'l', "level");
  let log_level_option_value =
    options_parser.parse_string(&level_option, PythonLogLevel::Info.as_ref())?;
  let level = PythonLogLevel::from_str(&log_level_option_value.value).map_err(|_| {
    format!(
      "Not a valid log level {level} from {option_source:?}. Should be one of {levels}.",
      level = log_level_option_value.value,
      option_source = log_level_option_value.source,
      levels = render_choice(PythonLogLevel::VARIANTS)
        .expect("We know there is at least one PythonLogLevel enum variant."),
    )
  })?;
  env_logger::init_from_env(env_logger::Env::new().filter_or("__PANTS_LEVEL__", level.as_ref()));

  let working_dir = env::current_dir()
    .map_err(|e| format!("Could not detect current working directory: {err}", err = e))?;
  let pantsd_settings = find_pantsd(&working_dir, &options_parser)?;
  let env = env::vars().collect::<Vec<(_, _)>>();
  let argv = env::args().collect::<Vec<_>>();
  client::execute_command(start, pantsd_settings, env, argv).await
}

fn find_pantsd(
  working_dir: &Path,
  options_parser: &OptionParser,
) -> Result<client::ConnectionSettings, String> {
  let pants_subprocessdir = option_id!("pants", "subprocessdir");
  let option_value = options_parser.parse_string(&pants_subprocessdir, ".pids")?;
  let metadata_dir = {
    let path = PathBuf::from(&option_value.value);
    if path.is_absolute() {
      path
    } else {
      match working_dir.join(&path) {
        p if p.is_absolute() => p,
        p => p.canonicalize().map_err(|e| {
          format!(
            "Failed to resolve relative pants subprocessdir specified via {:?} as {}: {}",
            option_value,
            path.display(),
            e
          )
        })?,
      }
    }
  };
  debug!(
    "\
    Looking for pantsd metadata in {metadata_dir} as specified by {option} = {value} via \
    {source:?}.\
    ",
    metadata_dir = metadata_dir.display(),
    option = pants_subprocessdir,
    value = option_value.value,
    source = option_value.source
  );
  let port = pantsd::probe(&working_dir, &metadata_dir)?;
  let mut pantsd_settings = client::ConnectionSettings::new(port);
  pantsd_settings.timeout_limit = options_parser
    .parse_float(
      &option_id!("pantsd", "timeout", "when", "multiple", "invocations"),
      pantsd_settings.timeout_limit,
    )?
    .value;
  pantsd_settings.dynamic_ui = options_parser
    .parse_bool(&option_id!("dynamic", "ui"), pantsd_settings.dynamic_ui)?
    .value;
  Ok(pantsd_settings)
}

// The value is taken from this C precedent:
// ```
// $ grep 75 /usr/include/sysexits.h
// #define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
// ```
const EX_TEMPFAIL: i32 = 75;

#[tokio::main]
async fn main() {
  let start = SystemTime::now();
  match execute(start).await {
    Err(err) => {
      eprintln!("{}", err);
      // We use this exit code to indicate an error running pants via the nailgun protocol to
      // differentiate from a successful nailgun protocol session.
      std::process::exit(EX_TEMPFAIL);
    }
    Ok(exit_code) => std::process::exit(exit_code),
  }
}
<commit_msg>Native client respects `--concurrent`. (#12324)<commit_after>// Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
  clippy::all,
  clippy::default_trait_access,
  clippy::expl_impl_clone_on_copy,
  clippy::if_not_else,
  clippy::needless_continue,
  clippy::unseparated_literal_suffix,
  // TODO: Falsely triggers for async/await:
  //   see https://github.com/rust-lang/rust-clippy/issues/5360
  // clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
  clippy::len_without_is_empty,
  clippy::redundant_field_names,
  clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]

use std::convert::AsRef;
use std::env;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::SystemTime;

use log::debug;
use strum::VariantNames;
use strum_macros::{AsRefStr, EnumString, EnumVariantNames};

use client::option_id;
use client::options::OptionParser;
use client::pantsd;
use client::render_choice;

// TODO(John Sirois): Maybe consolidate with PythonLogLevel in src/rust/engine/logging/src/lib.rs.
#[derive(AsRefStr, EnumString, EnumVariantNames)]
#[strum(serialize_all = "snake_case")]
enum PythonLogLevel {
  Trace,
  Debug,
  Info,
  Warn,
  Error,
}

async fn execute(start: SystemTime) -> Result<i32, String> {
  let options_parser = OptionParser::new()?;

  let use_pantsd = options_parser.parse_bool(&option_id!("pantsd"), true)?;
  if !use_pantsd.value {
    return Err(format!(
      "Pantsd has been turned off via {option_source:?}.",
      option_source = use_pantsd.source
    ));
  }

  let concurrent = options_parser.parse_bool(&option_id!("concurrent"), false)?;
  if concurrent.value {
    return Err("Pantsd is being turned off since --concurrent is true.".to_owned());
  }

  let level_option = option_id!(-'l', "level");
  let log_level_option_value =
    options_parser.parse_string(&level_option, PythonLogLevel::Info.as_ref())?;
  let level = PythonLogLevel::from_str(&log_level_option_value.value).map_err(|_| {
    format!(
      "Not a valid log level {level} from {option_source:?}. Should be one of {levels}.",
      level = log_level_option_value.value,
      option_source = log_level_option_value.source,
      levels = render_choice(PythonLogLevel::VARIANTS)
        .expect("We know there is at least one PythonLogLevel enum variant."),
    )
  })?;
  env_logger::init_from_env(env_logger::Env::new().filter_or("__PANTS_LEVEL__", level.as_ref()));

  let working_dir = env::current_dir()
    .map_err(|e| format!("Could not detect current working directory: {err}", err = e))?;
  let pantsd_settings = find_pantsd(&working_dir, &options_parser)?;
  let env = env::vars().collect::<Vec<(_, _)>>();
  let argv = env::args().collect::<Vec<_>>();
  client::execute_command(start, pantsd_settings, env, argv).await
}

fn find_pantsd(
  working_dir: &Path,
  options_parser: &OptionParser,
) -> Result<client::ConnectionSettings, String> {
  let pants_subprocessdir = option_id!("pants", "subprocessdir");
  let option_value = options_parser.parse_string(&pants_subprocessdir, ".pids")?;
  let metadata_dir = {
    let path = PathBuf::from(&option_value.value);
    if path.is_absolute() {
      path
    } else {
      match working_dir.join(&path) {
        p if p.is_absolute() => p,
        p => p.canonicalize().map_err(|e| {
          format!(
            "Failed to resolve relative pants subprocessdir specified via {:?} as {}: {}",
            option_value,
            path.display(),
            e
          )
        })?,
      }
    }
  };
  debug!(
    "\
    Looking for pantsd metadata in {metadata_dir} as specified by {option} = {value} via \
    {source:?}.\
    ",
    metadata_dir = metadata_dir.display(),
    option = pants_subprocessdir,
    value = option_value.value,
    source = option_value.source
  );
  let port = pantsd::probe(&working_dir, &metadata_dir)?;
  let mut pantsd_settings = client::ConnectionSettings::new(port);
  pantsd_settings.timeout_limit = options_parser
    .parse_float(
      &option_id!("pantsd", "timeout", "when", "multiple", "invocations"),
      pantsd_settings.timeout_limit,
    )?
    .value;
  pantsd_settings.dynamic_ui = options_parser
    .parse_bool(&option_id!("dynamic", "ui"), pantsd_settings.dynamic_ui)?
    .value;
  Ok(pantsd_settings)
}

// The value is taken from this C precedent:
// ```
// $ grep 75 /usr/include/sysexits.h
// #define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
// ```
const EX_TEMPFAIL: i32 = 75;

#[tokio::main]
async fn main() {
  let start = SystemTime::now();
  match execute(start).await {
    Err(err) => {
      eprintln!("{}", err);
      // We use this exit code to indicate an error running pants via the nailgun protocol to
      // differentiate from a successful nailgun protocol session.
      std::process::exit(EX_TEMPFAIL);
    }
    Ok(exit_code) => std::process::exit(exit_code),
  }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "filelocal", feature(proc_macro_span))]
//! The dynasm crate contains the procedural macros that power the magic of dynasm-rs. It seamlessly integrates
//! a full dynamic assembler for several assembly dialects with rust code.
//!
//! As this is a proc-macro crate, it only exports the `dynasm!` and `dynasm_backwards!` macros.
//! Any directives used in these macro invocations are normally local to the invocation itself, unless
//! the `filelocal` crate feature is used. This feature requires a nightly compiler.
//!
//! Additionally, the `dynasm_opmap` and `dynasm_extract` development features can be used to export two additional macros
//! with matching names. These macros expand into instruction listing overviews and are normally only used for documentation purposes.

extern crate proc_macro;

use syn::parse;
use syn::{Token, parse_macro_input};
use proc_macro2::{TokenTree, TokenStream};
use quote::quote;
use proc_macro_error::proc_macro_error;

use std::collections::HashMap;

#[cfg(feature = "filelocal")]
use std::sync::{MutexGuard, Mutex};
#[cfg(feature = "filelocal")]
use std::path::PathBuf;
#[cfg(any(feature = "filelocal", feature = "dynasm_opmap", feature = "dynasm_extract"))]
use proc_macro2::Span;

/// Module with common infrastructure across assemblers
mod common;
/// Module with architecture-specific assembler implementations
mod arch;
/// Module contaning the implementation of directives
mod directive;
/// Module containing utility functions for creating TokenTrees from assembler / directive output
mod serialize;
/// Module containing utility functions for parsing
mod parse_helpers;

/// The whole point. This macro compiles given assembly/rust templates down to `DynasmApi` and `DynasmLabelApi`
/// compliant calls to an assembler.
#[proc_macro]
#[proc_macro_error]
pub fn dynasm(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
    // try parsing the tokenstream into a dynasm struct containing
    // an abstract representation of the statements to create
    let dynasm = parse_macro_input!(tokens as Dynasm);

    // serialize the resulting output into tokens
    serialize::serialize(&dynasm.target, dynasm.stmts).into()
}

/// Similar to `dynasm!`, but the calls to the assembler are executed in piecewise reversed order.
/// This is to allow the system to be used with assemblers that assemble backwards.
/// Currently this is not supported by the `dynasmrt` crate, but this allows experimentation with it
/// out of tree.
#[proc_macro]
#[proc_macro_error]
pub fn dynasm_backwards(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
    // try parsing the tokenstream into a dynasm struct containing
    // an abstract representation of the statements to create
    let dynasm = parse_macro_input!(tokens as Dynasm);

    // reverse the statement stream
    let stmts = serialize::invert(dynasm.stmts);

    // serialize the resulting output into tokens
    serialize::serialize(&dynasm.target, stmts).into()
}

/// output from parsing a full dynasm invocation. target represents the first dynasm argument, being the assembler
/// variable being used. stmts contains an abstract representation of the statements to be generated from this dynasm
/// invocation.
struct Dynasm {
    target: TokenTree,
    stmts: Vec<common::Stmt>
}

/// top-level parsing. Handles common prefix symbols and diverts to the selected architecture
/// when an assembly instruction is encountered. When parsing fails an Err() is returned, when
/// non-parsing errors happen err() will be called, but this function returns Ok().
impl parse::Parse for Dynasm {
    fn parse(input: parse::ParseStream) -> parse::Result<Self> {

        // parse the assembler target declaration
        let target: syn::Expr = input.parse()?;
        // and just convert it back to a tokentree since that's how we'll always be using it.
        let target = common::delimited(target);

        // get file-local data (alias definitions, current architecture)
        let mut provider = ContextProvider::new();
        let invocation_context = provider.get_context_mut();

        // prepare the statement buffer
        let mut stmts = Vec::new();

        // if we're not at the end of the macro, we should be expecting a semicolon and a new directive/statement/label/op
        while !input.is_empty() {
            let _: Token![;] = input.parse()?;

            // ;; stmt
            if input.peek(Token![;]) {
                let _: Token![;] = input.parse()?;

                // collect all tokentrees till the next ;
                let mut buffer = TokenStream::new();
                while !(input.is_empty() || input.peek(Token![;])) {
                    buffer.extend(std::iter::once(input.parse::<TokenTree>()?));
                }
                // glue an extra ; on there
                buffer.extend(quote! { ; } );

                if !buffer.is_empty() {
                    // ensure that the statement is actually a proper statement and then emit it for serialization
                    let stmt: syn::Stmt = syn::parse2(buffer)?;
                    stmts.push(common::Stmt::Stmt(common::delimited(stmt)));
                }
                continue;
            }

            // ; -> label :
            if input.peek(Token![->]) {
                let _: Token![->] = input.parse()?;

                let name: syn::Ident = input.parse()?;
                let _: Token![:] = input.parse()?;

                stmts.push(common::Stmt::GlobalLabel(name));
                continue;
            }

            // ; => expr
            if input.peek(Token![=>]) {
                let _: Token![=>] = input.parse()?;

                let expr: syn::Expr = input.parse()?;

                stmts.push(common::Stmt::DynamicLabel(common::delimited(expr)));
                continue;
            }

            // ; label :
            if input.peek(syn::Ident) && input.peek2(Token![:]) {

                let name: syn::Ident = input.parse()?;
                let _: Token![:] = input.parse()?;

                stmts.push(common::Stmt::LocalLabel(name));
                continue;
            }

            // ; . directive
            if input.peek(Token![.]) {
                let _: Token![.] = input.parse()?;

                directive::evaluate_directive(invocation_context, &mut stmts, input)?;
            } else {
                // anything else is an assembly instruction which should be in current_arch

                let mut state = State {
                    stmts: &mut stmts,
                    target: &target,
                    invocation_context: &*invocation_context,
                };
                invocation_context.current_arch.compile_instruction(&mut state, input)?;
            }

        }

        Ok(Dynasm {
            target,
            stmts
        })
    }
}

/// This is only compiled when the dynasm_opmap feature is used. It exports the internal assembly listings
/// into a string that can then be included into the documentation for dynasm.
#[cfg(feature = "dynasm_opmap")]
#[proc_macro]
pub fn dynasm_opmap(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {

    // parse to ensure that no macro arguments were provided
    let opmap = parse_macro_input!(tokens as DynasmOpmap);

    let mut s = String::new();
    s.push_str("% Instruction Reference\n\n");

    s.push_str(&match opmap.arch.as_str() {
        "x64" | "x86" => arch::x64::create_opmap(),
        "aarch64" => arch::aarch64::create_opmap(),
        x => panic!("Unknown architecture {}", x)
    });

    let token = quote::quote_spanned! { Span::mixed_site()=>
        #s
    };
    token.into()
}

/// This is only compiled when the dynasm_extract feature is used. It exports the internal assembly listings
/// into a string that can then be included into the documentation for dynasm.
#[cfg(feature = "dynasm_extract")]
#[proc_macro]
pub fn dynasm_extract(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {

    // parse to ensure that no macro arguments were provided
    let opmap = parse_macro_input!(tokens as DynasmOpmap);

    let s = match opmap.arch.as_str() {
        "x64" | "x86" => "UNIMPLEMENTED".into(),
        "aarch64" => arch::aarch64::extract_opmap(),
        x => panic!("Unknown architecture {}", x)
    };

    let token = quote::quote_spanned! { Span::mixed_site()=>
        #s
    };
    token.into()
}

/// As dynasm_opmap takes no args it doesn't parse to anything
struct DynasmOpmap {
    pub arch: String
}

/// As dynasm_opmap takes no args it doesn't parse to anything.
/// This just exists so syn will give an error when no args are present.
impl parse::Parse for DynasmOpmap {
    fn parse(input: parse::ParseStream) -> parse::Result<Self> {
        let arch: syn::Ident = input.parse()?;

        Ok(DynasmOpmap {
            arch: arch.to_string()
        })
    }
}

/// This struct contains all non-parsing state that dynasm! requires while parsing and compiling
struct State<'a> {
    pub stmts: &'a mut Vec<common::Stmt>,
    pub target: &'a TokenTree,
    pub invocation_context: &'a DynasmContext,
}

// File local data implementation.

// context inside of a dynasm invocation, manipulated by directives and such
struct DynasmContext {
    pub current_arch: Box<dyn arch::Arch>,
    pub aliases: HashMap<String, String>,
}

impl DynasmContext {
    fn new() -> DynasmContext {
        DynasmContext {
            current_arch: arch::from_str(arch::CURRENT_ARCH).expect("Invalid default architecture"),
            aliases: HashMap::new()
        }
    }
}

// Oneshot context provider
#[cfg(not(feature = "filelocal"))]
struct ContextProvider {
    context: DynasmContext
}

#[cfg(not(feature = "filelocal"))]
impl ContextProvider {
    pub fn new() -> ContextProvider {
        ContextProvider {
            context: DynasmContext::new()
        }
    }

    pub fn get_context_mut(&mut self) -> &mut DynasmContext {
        &mut self.context
    }
}

/// Filelocal context provider
#[cfg(feature = "filelocal")]
struct ContextProvider {
    guard: MutexGuard<'static, HashMap<PathBuf, DynasmContext>>
}

#[cfg(feature = "filelocal")]
impl ContextProvider {
    pub fn new() -> ContextProvider {
        ContextProvider {
            guard: CONTEXT_STORAGE.lock().unwrap()
        }
    }

    pub fn get_context_mut(&mut self) -> &mut DynasmContext {
        // get the file that generated this macro expansion
        let span = Span::call_site().unstable();

        // and use the file that that was at as scope for resolving dynasm data
        let id = span.source_file().path();

        self.guard.entry(id).or_insert_with(DynasmContext::new)
    }
}

#[cfg(feature = "filelocal")]
lazy_static::lazy_static! {
    static ref CONTEXT_STORAGE: Mutex<HashMap<PathBuf, DynasmContext>> = Mutex::new(HashMap::new());
}

// type DynasmStorage = HashMap<PathBuf, Mutex<DynasmData>>;

// struct DynasmData {
//     pub current_arch: Box<dyn arch::Arch>,
//     pub aliases: HashMap<String, String>,
// }

// impl DynasmData {
//     fn new() -> DynasmData {
//         DynasmData {
//             current_arch:
//                 arch::from_str(arch::CURRENT_ARCH).expect("Default architecture is invalid"),
//             aliases: HashMap::new(),
//         }
//     }
// }

// type FileLocalData = OwningRef<RwLockReadGuard<'static, DynasmStorage>, Mutex<DynasmData>>;

// fn file_local_data() -> FileLocalData {
//     // get the file that generated this macro expansion
//     let span = Span::call_site().unstable();

//     // and use the file that that was at as scope for resolving dynasm data
//     let id = span.source_file().path();

//     {
//         let data = RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap());

//         if data.get(&id).is_some() {
//             return data.map(|x| x.get(&id).unwrap());
//         }
//     }

//     {
//         let mut lock = DYNASM_STORAGE.write().unwrap();
//         lock.insert(id.clone(), Mutex::new(DynasmData::new()));
//     }
//     RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap()).map(|x| x.get(&id).unwrap())
// }

// // this is where the actual storage resides.
// lazy_static! {
//     static ref DYNASM_STORAGE: RwLock<DynasmStorage> = RwLock::new(HashMap::new());
// }
<commit_msg>Remove use of mixed_site in dynasm_opmap and dynasm_extract as it's not necessary and blocking documentation right now<commit_after>#![cfg_attr(feature = "filelocal", feature(proc_macro_span))]
//! The dynasm crate contains the procedural macros that power the magic of dynasm-rs. It seamlessly integrates
//! a full dynamic assembler for several assembly dialects with rust code.
//!
//! As this is a proc-macro crate, it only exports the `dynasm!` and `dynasm_backwards!` macros.
//! Any directives used in these macro invocations are normally local to the invocation itself, unless
//! the `filelocal` crate feature is used. This feature requires a nightly compiler.
//!
//! Additionally, the `dynasm_opmap` and `dynasm_extract` development features can be used to export two additional macros
//! with matching names. These macros expand into instruction listing overviews and are normally only used for documentation purposes.

extern crate proc_macro;

use syn::parse;
use syn::{Token, parse_macro_input};
use proc_macro2::{TokenTree, TokenStream};
use quote::quote;
use proc_macro_error::proc_macro_error;

use std::collections::HashMap;

#[cfg(feature = "filelocal")]
use std::sync::{MutexGuard, Mutex};
#[cfg(feature = "filelocal")]
use std::path::PathBuf;
#[cfg(any(feature = "filelocal", feature = "dynasm_opmap", feature = "dynasm_extract"))]
use proc_macro2::Span;

/// Module with common infrastructure across assemblers
mod common;
/// Module with architecture-specific assembler implementations
mod arch;
/// Module contaning the implementation of directives
mod directive;
/// Module containing utility functions for creating TokenTrees from assembler / directive output
mod serialize;
/// Module containing utility functions for parsing
mod parse_helpers;

/// The whole point. This macro compiles given assembly/rust templates down to `DynasmApi` and `DynasmLabelApi`
/// compliant calls to an assembler.
#[proc_macro]
#[proc_macro_error]
pub fn dynasm(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
    // try parsing the tokenstream into a dynasm struct containing
    // an abstract representation of the statements to create
    let dynasm = parse_macro_input!(tokens as Dynasm);

    // serialize the resulting output into tokens
    serialize::serialize(&dynasm.target, dynasm.stmts).into()
}

/// Similar to `dynasm!`, but the calls to the assembler are executed in piecewise reversed order.
/// This is to allow the system to be used with assemblers that assemble backwards.
/// Currently this is not supported by the `dynasmrt` crate, but this allows experimentation with it
/// out of tree.
#[proc_macro]
#[proc_macro_error]
pub fn dynasm_backwards(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
    // try parsing the tokenstream into a dynasm struct containing
    // an abstract representation of the statements to create
    let dynasm = parse_macro_input!(tokens as Dynasm);

    // reverse the statement stream
    let stmts = serialize::invert(dynasm.stmts);

    // serialize the resulting output into tokens
    serialize::serialize(&dynasm.target, stmts).into()
}

/// output from parsing a full dynasm invocation. target represents the first dynasm argument, being the assembler
/// variable being used. stmts contains an abstract representation of the statements to be generated from this dynasm
/// invocation.
struct Dynasm {
    target: TokenTree,
    stmts: Vec<common::Stmt>
}

/// top-level parsing. Handles common prefix symbols and diverts to the selected architecture
/// when an assembly instruction is encountered. When parsing fails an Err() is returned, when
/// non-parsing errors happen err() will be called, but this function returns Ok().
impl parse::Parse for Dynasm {
    fn parse(input: parse::ParseStream) -> parse::Result<Self> {

        // parse the assembler target declaration
        let target: syn::Expr = input.parse()?;
        // and just convert it back to a tokentree since that's how we'll always be using it.
        let target = common::delimited(target);

        // get file-local data (alias definitions, current architecture)
        let mut provider = ContextProvider::new();
        let invocation_context = provider.get_context_mut();

        // prepare the statement buffer
        let mut stmts = Vec::new();

        // if we're not at the end of the macro, we should be expecting a semicolon and a new directive/statement/label/op
        while !input.is_empty() {
            let _: Token![;] = input.parse()?;

            // ;; stmt
            if input.peek(Token![;]) {
                let _: Token![;] = input.parse()?;

                // collect all tokentrees till the next ;
                let mut buffer = TokenStream::new();
                while !(input.is_empty() || input.peek(Token![;])) {
                    buffer.extend(std::iter::once(input.parse::<TokenTree>()?));
                }
                // glue an extra ; on there
                buffer.extend(quote! { ; } );

                if !buffer.is_empty() {
                    // ensure that the statement is actually a proper statement and then emit it for serialization
                    let stmt: syn::Stmt = syn::parse2(buffer)?;
                    stmts.push(common::Stmt::Stmt(common::delimited(stmt)));
                }
                continue;
            }

            // ; -> label :
            if input.peek(Token![->]) {
                let _: Token![->] = input.parse()?;

                let name: syn::Ident = input.parse()?;
                let _: Token![:] = input.parse()?;

                stmts.push(common::Stmt::GlobalLabel(name));
                continue;
            }

            // ; => expr
            if input.peek(Token![=>]) {
                let _: Token![=>] = input.parse()?;

                let expr: syn::Expr = input.parse()?;

                stmts.push(common::Stmt::DynamicLabel(common::delimited(expr)));
                continue;
            }

            // ; label :
            if input.peek(syn::Ident) && input.peek2(Token![:]) {

                let name: syn::Ident = input.parse()?;
                let _: Token![:] = input.parse()?;

                stmts.push(common::Stmt::LocalLabel(name));
                continue;
            }

            // ; . directive
            if input.peek(Token![.]) {
                let _: Token![.] = input.parse()?;

                directive::evaluate_directive(invocation_context, &mut stmts, input)?;
            } else {
                // anything else is an assembly instruction which should be in current_arch

                let mut state = State {
                    stmts: &mut stmts,
                    target: &target,
                    invocation_context: &*invocation_context,
                };
                invocation_context.current_arch.compile_instruction(&mut state, input)?;
            }

        }

        Ok(Dynasm {
            target,
            stmts
        })
    }
}

/// This is only compiled when the dynasm_opmap feature is used. It exports the internal assembly listings
/// into a string that can then be included into the documentation for dynasm.
#[cfg(feature = "dynasm_opmap")]
#[proc_macro]
pub fn dynasm_opmap(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {

    // parse to ensure that no macro arguments were provided
    let opmap = parse_macro_input!(tokens as DynasmOpmap);

    let mut s = String::new();
    s.push_str("% Instruction Reference\n\n");

    s.push_str(&match opmap.arch.as_str() {
        "x64" | "x86" => arch::x64::create_opmap(),
        "aarch64" => arch::aarch64::create_opmap(),
        x => panic!("Unknown architecture {}", x)
    });

    let token = quote::quote_spanned! { Span::call_site()=>
        #s
    };
    token.into()
}

/// This is only compiled when the dynasm_extract feature is used. It exports the internal assembly listings
/// into a string that can then be included into the documentation for dynasm.
#[cfg(feature = "dynasm_extract")]
#[proc_macro]
pub fn dynasm_extract(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {

    // parse to ensure that no macro arguments were provided
    let opmap = parse_macro_input!(tokens as DynasmOpmap);

    let s = match opmap.arch.as_str() {
        "x64" | "x86" => "UNIMPLEMENTED".into(),
        "aarch64" => arch::aarch64::extract_opmap(),
        x => panic!("Unknown architecture {}", x)
    };

    let token = quote::quote_spanned! { Span::call_site()=>
        #s
    };
    token.into()
}

/// As dynasm_opmap takes no args it doesn't parse to anything
struct DynasmOpmap {
    pub arch: String
}

/// As dynasm_opmap takes no args it doesn't parse to anything.
/// This just exists so syn will give an error when no args are present.
impl parse::Parse for DynasmOpmap {
    fn parse(input: parse::ParseStream) -> parse::Result<Self> {
        let arch: syn::Ident = input.parse()?;

        Ok(DynasmOpmap {
            arch: arch.to_string()
        })
    }
}

/// This struct contains all non-parsing state that dynasm! requires while parsing and compiling
struct State<'a> {
    pub stmts: &'a mut Vec<common::Stmt>,
    pub target: &'a TokenTree,
    pub invocation_context: &'a DynasmContext,
}

// File local data implementation.

// context inside of a dynasm invocation, manipulated by directives and such
struct DynasmContext {
    pub current_arch: Box<dyn arch::Arch>,
    pub aliases: HashMap<String, String>,
}

impl DynasmContext {
    fn new() -> DynasmContext {
        DynasmContext {
            current_arch: arch::from_str(arch::CURRENT_ARCH).expect("Invalid default architecture"),
            aliases: HashMap::new()
        }
    }
}

// Oneshot context provider
#[cfg(not(feature = "filelocal"))]
struct ContextProvider {
    context: DynasmContext
}

#[cfg(not(feature = "filelocal"))]
impl ContextProvider {
    pub fn new() -> ContextProvider {
        ContextProvider {
            context: DynasmContext::new()
        }
    }

    pub fn get_context_mut(&mut self) -> &mut DynasmContext {
        &mut self.context
    }
}

/// Filelocal context provider
#[cfg(feature = "filelocal")]
struct ContextProvider {
    guard: MutexGuard<'static, HashMap<PathBuf, DynasmContext>>
}

#[cfg(feature = "filelocal")]
impl ContextProvider {
    pub fn new() -> ContextProvider {
        ContextProvider {
            guard: CONTEXT_STORAGE.lock().unwrap()
        }
    }

    pub fn get_context_mut(&mut self) -> &mut DynasmContext {
        // get the file that generated this macro expansion
        let span = Span::call_site().unstable();

        // and use the file that that was at as scope for resolving dynasm data
        let id = span.source_file().path();

        self.guard.entry(id).or_insert_with(DynasmContext::new)
    }
}

#[cfg(feature = "filelocal")]
lazy_static::lazy_static! {
    static ref CONTEXT_STORAGE: Mutex<HashMap<PathBuf, DynasmContext>> = Mutex::new(HashMap::new());
}

// type DynasmStorage = HashMap<PathBuf, Mutex<DynasmData>>;

// struct DynasmData {
//     pub current_arch: Box<dyn arch::Arch>,
//     pub aliases: HashMap<String, String>,
// }

// impl DynasmData {
//     fn new() -> DynasmData {
//         DynasmData {
//             current_arch:
//                 arch::from_str(arch::CURRENT_ARCH).expect("Default architecture is invalid"),
//             aliases: HashMap::new(),
//         }
//     }
// }

// type FileLocalData = OwningRef<RwLockReadGuard<'static, DynasmStorage>, Mutex<DynasmData>>;

// fn file_local_data() -> FileLocalData {
//     // get the file that generated this macro expansion
//     let span = Span::call_site().unstable();

//     // and use the file that that was at as scope for resolving dynasm data
//     let id = span.source_file().path();

//     {
//         let data = RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap());

//         if data.get(&id).is_some() {
//             return data.map(|x| x.get(&id).unwrap());
//         }
//     }

//     {
//         let mut lock = DYNASM_STORAGE.write().unwrap();
//         lock.insert(id.clone(), Mutex::new(DynasmData::new()));
//     }
//     RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap()).map(|x| x.get(&id).unwrap())
// }

// // this is where the actual storage resides.
// lazy_static! {
//     static ref DYNASM_STORAGE: RwLock<DynasmStorage> = RwLock::new(HashMap::new());
// }
<|endoftext|>


<commit_before>use std::{convert::TryFrom, env, process::exit};

use http::Uri;
use ruma::{
    api::client::r0::{alias::get_alias, membership::join_room_by_id, message::send_message_event},
    events::{
        room::message::{MessageEventContent, TextMessageEventContent},
        EventType,
    },
    RoomAliasId,
};
use ruma_client::{self, Client};
use serde_json::value::to_raw_value as to_raw_json_value;

async fn hello_world(homeserver_url: Uri, room_alias: &RoomAliasId) -> anyhow::Result<()> {
    let client = Client::new(homeserver_url, None);

    client.register_guest().await?;
    let response = client.request(get_alias::Request { room_alias }).await?;

    let room_id = response.room_id;

    client.request(join_room_by_id::Request::new(&room_id)).await?;

    client
        .request(send_message_event::Request {
            room_id: &room_id,
            event_type: EventType::RoomMessage,
            txn_id: "1",
            data: to_raw_json_value(&MessageEventContent::Text(TextMessageEventContent {
                body: "Hello World!".to_owned(),
                formatted: None,
                relates_to: None,
            }))?,
        })
        .await?;

    Ok(())
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let (homeserver_url, room) = match (env::args().nth(1), env::args().nth(2)) {
        (Some(a), Some(b)) => (a, b),
        _ => {
            eprintln!("Usage: {} <homeserver_url> <room>", env::args().next().unwrap());
            exit(1)
        }
    };

    hello_world(homeserver_url.parse()?, &RoomAliasId::try_from(room.as_str())?).await
}
<commit_msg>fixup! Make some request and response types non-exhaustive<commit_after>use std::{convert::TryFrom, env, process::exit};

use http::Uri;
use ruma::{
    api::client::r0::{alias::get_alias, membership::join_room_by_id, message::send_message_event},
    events::{
        room::message::{MessageEventContent, TextMessageEventContent},
        EventType,
    },
    RoomAliasId,
};
use ruma_client::{self, Client};
use serde_json::value::to_raw_value as to_raw_json_value;

async fn hello_world(homeserver_url: Uri, room_alias: &RoomAliasId) -> anyhow::Result<()> {
    let client = Client::new(homeserver_url, None);

    client.register_guest().await?;
    let response = client.request(get_alias::Request::new(room_alias)).await?;

    let room_id = response.room_id;

    client.request(join_room_by_id::Request::new(&room_id)).await?;

    client
        .request(send_message_event::Request {
            room_id: &room_id,
            event_type: EventType::RoomMessage,
            txn_id: "1",
            data: to_raw_json_value(&MessageEventContent::Text(TextMessageEventContent {
                body: "Hello World!".to_owned(),
                formatted: None,
                relates_to: None,
            }))?,
        })
        .await?;

    Ok(())
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let (homeserver_url, room) = match (env::args().nth(1), env::args().nth(2)) {
        (Some(a), Some(b)) => (a, b),
        _ => {
            eprintln!("Usage: {} <homeserver_url> <room>", env::args().next().unwrap());
            exit(1)
        }
    };

    hello_world(homeserver_url.parse()?, &RoomAliasId::try_from(room.as_str())?).await
}
<|endoftext|>


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

// xfail-test

tag a_tag {
    a_tag(u64);
}

type t_rec = {
    c8: u8,
    t: a_tag
};

fn mk_rec() -> t_rec {
    return { c8:0u8, t:a_tag(0u64) };
}

fn is_8_byte_aligned(&&u: a_tag) -> bool {
    let p = ptr::to_unsafe_ptr(u) as u64;
    return (p & 7u64) == 0u64;
}

pub fn main() {
    let x = mk_rec();
    assert!(is_8_byte_aligned(x.t));
}
<commit_msg>fixed this test case too<commit_after>// Copyright 2012 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.

enum a_tag {
    a_tag(u64)
}

struct t_rec {
    c8: u8,
    t: a_tag
}

fn mk_rec() -> t_rec {
    return t_rec { c8:0u8, t:a_tag(0u64) };
}

fn is_8_byte_aligned(u: &a_tag) -> bool {
    let p = ptr::to_unsafe_ptr(u) as u64;
    return (p & 7u64) == 0u64;
}

pub fn main() {
    let x = mk_rec();
    assert!(is_8_byte_aligned(&x.t));
}
<|endoftext|>


<commit_before>//! # Documentation for Additional Attributes
//!
//! Strum supports several custom attributes to modify the generated code. At the enum level, the
//! `#[strum(serialize_all = "snake_case")]` attribute can be used to change the case used when
//! serializing to and deserializing from strings:
//!
//! ```rust
//! use std::string::ToString;
//! use strum;
//! use strum_macros;
//!
//! #[derive(Debug, Eq, PartialEq, strum_macros::Display)]
//! #[strum(serialize_all = "snake_case")]
//! enum Brightness {
//!     DarkBlack,
//!     Dim {
//!         glow: usize,
//!     },
//!     #[strum(serialize = "bright")]
//!     BrightWhite,
//! }
//!
//! assert_eq!(
//!     String::from("dark_black"),
//!     Brightness::DarkBlack.to_string().as_ref()
//! );
//! assert_eq!(
//!     String::from("dim"),
//!     Brightness::Dim { glow: 0 }.to_string().as_ref()
//! );
//! assert_eq!(
//!     String::from("bright"),
//!     Brightness::BrightWhite.to_string().as_ref()
//! );
//! ```
//!
//! You can also apply the `#[strum(ascii_case_insensitive)]` attribute to the enum,
//! and this has the same effect of applying it to every variant.
//!
//! Custom attributes are applied to a variant by adding `#[strum(parameter="value")]` to the variant.
//!
//! - `serialize="..."`: Changes the text that `FromStr()` looks for when parsing a string. This attribute can
//!    be applied multiple times to an element and the enum variant will be parsed if any of them match.
//!
//! - `to_string="..."`: Similar to `serialize`. This value will be included when using `FromStr()`. More importantly,
//!    this specifies what text to use when calling `variant.to_string()` with the `Display` derivation, or when calling `variant.as_ref()` with `AsRefStr`.
//!
//! - `default`: Applied to a single variant of an enum. The variant must be a Tuple-like
//!    variant with a single piece of data that can be create from a `&str` i.e. `T: From<&str>`.
//!    The generated code will now return the variant with the input string captured as shown below
//!    instead of failing.
//!
//!     ```rust,ignore
//!     // Replaces this:
//!     _ => Err(strum::ParseError::VariantNotFound)
//!     // With this in generated code:
//!     default => Ok(Variant(default.into()))
//!     ```
//!     The plugin will fail if the data doesn't implement From<&str>. You can only have one `default`
//!     on your enum.
//!
//! - `disabled`: removes variant from generated code.
//!
//! - `ascii_case_insensitive`: makes the comparison to this variant case insensitive (ASCII only).
//!   If the whole enum is marked `ascii_case_insensitive`, you can specify `ascii_case_insensitive = false`
//!   to disable case insensitivity on this v ariant.
//!
//! - `message=".."`: Adds a message to enum variant. This is used in conjunction with the `EnumMessage`
//!    trait to associate a message with a variant. If `detailed_message` is not provided,
//!    then `message` will also be returned when get_detailed_message() is called.
//!
//! - `detailed_message=".."`: Adds a more detailed message to a variant. If this value is omitted, then
//!    `message` will be used in it's place.
//!
//! - `props(key="value")`: Enables associating additional information with a given variant.
<commit_msg>Update documentation to include listing all the supported case styles. (#182)<commit_after>//! # Documentation for Additional Attributes
//!
//! ## Attributes on Enums
//!
//! Strum supports several custom attributes to modify the generated code. At the enum level, the following attributes are supported:
//!
//! - `#[strum(serialize_all = "case_style")]` attribute can be used to change the case used when serializing to and deserializing
//!   from strings. This feature is enabled by [withoutboats/heck](https://github.com/withoutboats/heck) and supported case styles are:
//!
//!   - `camelCase`
//!   - `PascalCase`
//!   - `kebab-case`
//!   - `snake_case`
//!   - `SCREAMING_SNAKE_CASE`
//!   - `SCREAMING-KEBAB-CASE`
//!   - `lowercase`
//!   - `UPPERCASE`
//!   - `title_case`
//!   - `mixed_case`
//!
//!   ```rust
//!   use std::string::ToString;
//!   use strum;
//!   use strum_macros;
//!
//!   #[derive(Debug, Eq, PartialEq, strum_macros::ToString)]
//!   #[strum(serialize_all = "snake_case")]
//!   enum Brightness {
//!       DarkBlack,
//!       Dim {
//!           glow: usize,
//!       },
//!       #[strum(serialize = "bright")]
//!       BrightWhite,
//!   }
//!
//!   assert_eq!(
//!       String::from("dark_black"),
//!       Brightness::DarkBlack.to_string().as_ref()
//!   );
//!   assert_eq!(
//!       String::from("dim"),
//!       Brightness::Dim { glow: 0 }.to_string().as_ref()
//!   );
//!   assert_eq!(
//!       String::from("bright"),
//!       Brightness::BrightWhite.to_string().as_ref()
//!   );
//!   ```
//!
//! - You can also apply the `#[strum(ascii_case_insensitive)]` attribute to the enum,
//!   and this has the same effect of applying it to every variant.
//!
//! ## Attributes on Variants
//!
//! Custom attributes are applied to a variant by adding `#[strum(parameter="value")]` to the variant.
//!
//! - `serialize="..."`: Changes the text that `FromStr()` looks for when parsing a string. This attribute can
//!    be applied multiple times to an element and the enum variant will be parsed if any of them match.
//!
//! - `to_string="..."`: Similar to `serialize`. This value will be included when using `FromStr()`. More importantly,
//!    this specifies what text to use when calling `variant.to_string()` with the `Display` derivation, or when calling `variant.as_ref()` with `AsRefStr`.
//!
//! - `default`: Applied to a single variant of an enum. The variant must be a Tuple-like
//!    variant with a single piece of data that can be create from a `&str` i.e. `T: From<&str>`.
//!    The generated code will now return the variant with the input string captured as shown below
//!    instead of failing.
//!
//!     ```rust,ignore
//!     // Replaces this:
//!     _ => Err(strum::ParseError::VariantNotFound)
//!     // With this in generated code:
//!     default => Ok(Variant(default.into()))
//!     ```
//!     The plugin will fail if the data doesn't implement From<&str>. You can only have one `default`
//!     on your enum.
//!
//! - `disabled`: removes variant from generated code.
//!
//! - `ascii_case_insensitive`: makes the comparison to this variant case insensitive (ASCII only).
//!   If the whole enum is marked `ascii_case_insensitive`, you can specify `ascii_case_insensitive = false`
//!   to disable case insensitivity on this v ariant.
//!
//! - `message=".."`: Adds a message to enum variant. This is used in conjunction with the `EnumMessage`
//!    trait to associate a message with a variant. If `detailed_message` is not provided,
//!    then `message` will also be returned when get_detailed_message() is called.
//!
//! - `detailed_message=".."`: Adds a more detailed message to a variant. If this value is omitted, then
//!    `message` will be used in it's place.
//!
//! - `props(key="value")`: Enables associating additional information with a given variant.
<|endoftext|>


<commit_before>//! Telegram bot types.

pub mod requests;
pub use requests::*;

pub use telegram_bot_raw::{Integer, Float, Request, DetachedRequest};
pub use telegram_bot_raw::{ResponseType, JsonResponse, JsonIdResponse, JsonTrueToUnitResponse};
pub use telegram_bot_raw::{Update, UpdateKind};
pub use telegram_bot_raw::{User, Group, Supergroup, Channel, Chat};
pub use telegram_bot_raw::{UserId, GroupId, SupergroupId, ChannelId, ChatId, ChatRef};
pub use telegram_bot_raw::{CallbackQuery, CallbackQueryId};
pub use telegram_bot_raw::{Message, MessageId, MessageKind, Forward, ForwardFrom};
pub use telegram_bot_raw::{MessageEntity, MessageEntityKind};
pub use telegram_bot_raw::{Audio, Document, PhotoSize, Sticker, Video, Voice};
pub use telegram_bot_raw::{Contact, Location, Venue, File, FileRef};
pub use telegram_bot_raw::{ToChatRef, ToUserId, ToMessageId, ToSourceChat, ToFileRef, ToCallbackQueryId};

pub use telegram_bot_raw::{ParseMode};
pub use telegram_bot_raw::{ReplyMarkup, ReplyKeyboardMarkup, KeyboardButton};
pub use telegram_bot_raw::{InlineKeyboardMarkup, InlineKeyboardButton};
pub use telegram_bot_raw::{ReplyKeyboardRemove, ForceReply};
pub use telegram_bot_raw::{ChatAction};
<commit_msg>refactor: re-export some new types from -raw<commit_after>//! Telegram bot types.

pub mod requests;
pub use requests::*;

pub use telegram_bot_raw::{Integer, Float, Request, DetachedRequest};
pub use telegram_bot_raw::{ResponseType, JsonResponse, JsonIdResponse, JsonTrueToUnitResponse};
pub use telegram_bot_raw::{Update, UpdateKind};
pub use telegram_bot_raw::{User, Group, Supergroup, Channel, Chat, MessageChat};
pub use telegram_bot_raw::{UserId, GroupId, SupergroupId, ChannelId, ChatId, ChatRef};
pub use telegram_bot_raw::{CallbackQuery, CallbackQueryId};
pub use telegram_bot_raw::{MessageId, MessageKind, Forward, ForwardFrom};
pub use telegram_bot_raw::{MessageOrChannelPost, Message, ChannelPost};
pub use telegram_bot_raw::{MessageEntity, MessageEntityKind};
pub use telegram_bot_raw::{Audio, Document, PhotoSize, Sticker, Video, Voice};
pub use telegram_bot_raw::{Contact, Location, Venue, File, FileRef};
pub use telegram_bot_raw::{ToChatRef, ToUserId, ToMessageId, ToSourceChat, ToFileRef, ToCallbackQueryId};

pub use telegram_bot_raw::{ParseMode};
pub use telegram_bot_raw::{ReplyMarkup, ReplyKeyboardMarkup, KeyboardButton};
pub use telegram_bot_raw::{InlineKeyboardMarkup, InlineKeyboardButton};
pub use telegram_bot_raw::{ReplyKeyboardRemove, ForceReply};
pub use telegram_bot_raw::{ChatAction};
<|endoftext|>