<commit_before>#![feature(test)]
#![recursion_limit = "512"]

extern crate test;

use quote::quote;
use test::Bencher;

#[bench]
fn bench_impl(b: &mut Bencher) {
    b.iter(|| {
        quote! {
            impl<'de> _serde::Deserialize<'de> for Response {
                fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
                where
                    __D: _serde::Deserializer<'de>,
                {
                    #[allow(non_camel_case_types)]
                    enum __Field {
                        __field0,
                        __field1,
                        __ignore,
                    }
                    struct __FieldVisitor;
                    impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                        type Value = __Field;
                        fn expecting(
                            &self,
                            __formatter: &mut _serde::export::Formatter,
                        ) -> _serde::export::fmt::Result {
                            _serde::export::Formatter::write_str(__formatter, "field identifier")
                        }
                        fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
                        where
                            __E: _serde::de::Error,
                        {
                            match __value {
                                0u64 => _serde::export::Ok(__Field::__field0),
                                1u64 => _serde::export::Ok(__Field::__field1),
                                _ => _serde::export::Err(_serde::de::Error::invalid_value(
                                    _serde::de::Unexpected::Unsigned(__value),
                                    &"field index 0 <= i < 2",
                                )),
                            }
                        }
                        fn visit_str<__E>(self, __value: &str) -> _serde::export::Result<Self::Value, __E>
                        where
                            __E: _serde::de::Error,
                        {
                            match __value {
                                "id" => _serde::export::Ok(__Field::__field0),
                                "s" => _serde::export::Ok(__Field::__field1),
                                _ => _serde::export::Ok(__Field::__ignore),
                            }
                        }
                        fn visit_bytes<__E>(
                            self,
                            __value: &[u8],
                        ) -> _serde::export::Result<Self::Value, __E>
                        where
                            __E: _serde::de::Error,
                        {
                            match __value {
                                b"id" => _serde::export::Ok(__Field::__field0),
                                b"s" => _serde::export::Ok(__Field::__field1),
                                _ => _serde::export::Ok(__Field::__ignore),
                            }
                        }
                    }
                    impl<'de> _serde::Deserialize<'de> for __Field {
                        #[inline]
                        fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
                        where
                            __D: _serde::Deserializer<'de>,
                        {
                            _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor)
                        }
                    }
                    struct __Visitor<'de> {
                        marker: _serde::export::PhantomData<Response>,
                        lifetime: _serde::export::PhantomData<&'de ()>,
                    }
                    impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                        type Value = Response;
                        fn expecting(
                            &self,
                            __formatter: &mut _serde::export::Formatter,
                        ) -> _serde::export::fmt::Result {
                            _serde::export::Formatter::write_str(__formatter, "struct Response")
                        }
                        #[inline]
                        fn visit_seq<__A>(
                            self,
                            mut __seq: __A,
                        ) -> _serde::export::Result<Self::Value, __A::Error>
                        where
                            __A: _serde::de::SeqAccess<'de>,
                        {
                            let __field0 =
                                match try!(_serde::de::SeqAccess::next_element::<u64>(&mut __seq)) {
                                    _serde::export::Some(__value) => __value,
                                    _serde::export::None => {
                                        return _serde::export::Err(_serde::de::Error::invalid_length(
                                            0usize,
                                            &"struct Response with 2 elements",
                                        ));
                                    }
                                };
                            let __field1 =
                                match try!(_serde::de::SeqAccess::next_element::<String>(&mut __seq)) {
                                    _serde::export::Some(__value) => __value,
                                    _serde::export::None => {
                                        return _serde::export::Err(_serde::de::Error::invalid_length(
                                            1usize,
                                            &"struct Response with 2 elements",
                                        ));
                                    }
                                };
                            _serde::export::Ok(Response {
                                id: __field0,
                                s: __field1,
                            })
                        }
                        #[inline]
                        fn visit_map<__A>(
                            self,
                            mut __map: __A,
                        ) -> _serde::export::Result<Self::Value, __A::Error>
                        where
                            __A: _serde::de::MapAccess<'de>,
                        {
                            let mut __field0: _serde::export::Option<u64> = _serde::export::None;
                            let mut __field1: _serde::export::Option<String> = _serde::export::None;
                            while let _serde::export::Some(__key) =
                                try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map))
                            {
                                match __key {
                                    __Field::__field0 => {
                                        if _serde::export::Option::is_some(&__field0) {
                                            return _serde::export::Err(
                                                <__A::Error as _serde::de::Error>::duplicate_field("id"),
                                            );
                                        }
                                        __field0 = _serde::export::Some(
                                            try!(_serde::de::MapAccess::next_value::<u64>(&mut __map)),
                                        );
                                    }
                                    __Field::__field1 => {
                                        if _serde::export::Option::is_some(&__field1) {
                                            return _serde::export::Err(
                                                <__A::Error as _serde::de::Error>::duplicate_field("s"),
                                            );
                                        }
                                        __field1 = _serde::export::Some(
                                            try!(_serde::de::MapAccess::next_value::<String>(&mut __map)),
                                        );
                                    }
                                    _ => {
                                        let _ = try!(_serde::de::MapAccess::next_value::<
                                            _serde::de::IgnoredAny,
                                        >(&mut __map));
                                    }
                                }
                            }
                            let __field0 = match __field0 {
                                _serde::export::Some(__field0) => __field0,
                                _serde::export::None => try!(_serde::private::de::missing_field("id")),
                            };
                            let __field1 = match __field1 {
                                _serde::export::Some(__field1) => __field1,
                                _serde::export::None => try!(_serde::private::de::missing_field("s")),
                            };
                            _serde::export::Ok(Response {
                                id: __field0,
                                s: __field1,
                            })
                        }
                    }
                    const FIELDS: &'static [&'static str] = &["id", "s"];
                    _serde::Deserializer::deserialize_struct(
                        __deserializer,
                        "Response",
                        FIELDS,
                        __Visitor {
                            marker: _serde::export::PhantomData::<Response>,
                            lifetime: _serde::export::PhantomData,
                        },
                    )
                }
            }
        }
    });
}
<commit_msg>Quote in benchmark no longer requires high recursion<commit_after>#![feature(test)]

extern crate test;

use quote::quote;
use test::Bencher;

#[bench]
fn bench_impl(b: &mut Bencher) {
    b.iter(|| {
        quote! {
            impl<'de> _serde::Deserialize<'de> for Response {
                fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
                where
                    __D: _serde::Deserializer<'de>,
                {
                    #[allow(non_camel_case_types)]
                    enum __Field {
                        __field0,
                        __field1,
                        __ignore,
                    }
                    struct __FieldVisitor;
                    impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                        type Value = __Field;
                        fn expecting(
                            &self,
                            __formatter: &mut _serde::export::Formatter,
                        ) -> _serde::export::fmt::Result {
                            _serde::export::Formatter::write_str(__formatter, "field identifier")
                        }
                        fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
                        where
                            __E: _serde::de::Error,
                        {
                            match __value {
                                0u64 => _serde::export::Ok(__Field::__field0),
                                1u64 => _serde::export::Ok(__Field::__field1),
                                _ => _serde::export::Err(_serde::de::Error::invalid_value(
                                    _serde::de::Unexpected::Unsigned(__value),
                                    &"field index 0 <= i < 2",
                                )),
                            }
                        }
                        fn visit_str<__E>(self, __value: &str) -> _serde::export::Result<Self::Value, __E>
                        where
                            __E: _serde::de::Error,
                        {
                            match __value {
                                "id" => _serde::export::Ok(__Field::__field0),
                                "s" => _serde::export::Ok(__Field::__field1),
                                _ => _serde::export::Ok(__Field::__ignore),
                            }
                        }
                        fn visit_bytes<__E>(
                            self,
                            __value: &[u8],
                        ) -> _serde::export::Result<Self::Value, __E>
                        where
                            __E: _serde::de::Error,
                        {
                            match __value {
                                b"id" => _serde::export::Ok(__Field::__field0),
                                b"s" => _serde::export::Ok(__Field::__field1),
                                _ => _serde::export::Ok(__Field::__ignore),
                            }
                        }
                    }
                    impl<'de> _serde::Deserialize<'de> for __Field {
                        #[inline]
                        fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
                        where
                            __D: _serde::Deserializer<'de>,
                        {
                            _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor)
                        }
                    }
                    struct __Visitor<'de> {
                        marker: _serde::export::PhantomData<Response>,
                        lifetime: _serde::export::PhantomData<&'de ()>,
                    }
                    impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                        type Value = Response;
                        fn expecting(
                            &self,
                            __formatter: &mut _serde::export::Formatter,
                        ) -> _serde::export::fmt::Result {
                            _serde::export::Formatter::write_str(__formatter, "struct Response")
                        }
                        #[inline]
                        fn visit_seq<__A>(
                            self,
                            mut __seq: __A,
                        ) -> _serde::export::Result<Self::Value, __A::Error>
                        where
                            __A: _serde::de::SeqAccess<'de>,
                        {
                            let __field0 =
                                match try!(_serde::de::SeqAccess::next_element::<u64>(&mut __seq)) {
                                    _serde::export::Some(__value) => __value,
                                    _serde::export::None => {
                                        return _serde::export::Err(_serde::de::Error::invalid_length(
                                            0usize,
                                            &"struct Response with 2 elements",
                                        ));
                                    }
                                };
                            let __field1 =
                                match try!(_serde::de::SeqAccess::next_element::<String>(&mut __seq)) {
                                    _serde::export::Some(__value) => __value,
                                    _serde::export::None => {
                                        return _serde::export::Err(_serde::de::Error::invalid_length(
                                            1usize,
                                            &"struct Response with 2 elements",
                                        ));
                                    }
                                };
                            _serde::export::Ok(Response {
                                id: __field0,
                                s: __field1,
                            })
                        }
                        #[inline]
                        fn visit_map<__A>(
                            self,
                            mut __map: __A,
                        ) -> _serde::export::Result<Self::Value, __A::Error>
                        where
                            __A: _serde::de::MapAccess<'de>,
                        {
                            let mut __field0: _serde::export::Option<u64> = _serde::export::None;
                            let mut __field1: _serde::export::Option<String> = _serde::export::None;
                            while let _serde::export::Some(__key) =
                                try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map))
                            {
                                match __key {
                                    __Field::__field0 => {
                                        if _serde::export::Option::is_some(&__field0) {
                                            return _serde::export::Err(
                                                <__A::Error as _serde::de::Error>::duplicate_field("id"),
                                            );
                                        }
                                        __field0 = _serde::export::Some(
                                            try!(_serde::de::MapAccess::next_value::<u64>(&mut __map)),
                                        );
                                    }
                                    __Field::__field1 => {
                                        if _serde::export::Option::is_some(&__field1) {
                                            return _serde::export::Err(
                                                <__A::Error as _serde::de::Error>::duplicate_field("s"),
                                            );
                                        }
                                        __field1 = _serde::export::Some(
                                            try!(_serde::de::MapAccess::next_value::<String>(&mut __map)),
                                        );
                                    }
                                    _ => {
                                        let _ = try!(_serde::de::MapAccess::next_value::<
                                            _serde::de::IgnoredAny,
                                        >(&mut __map));
                                    }
                                }
                            }
                            let __field0 = match __field0 {
                                _serde::export::Some(__field0) => __field0,
                                _serde::export::None => try!(_serde::private::de::missing_field("id")),
                            };
                            let __field1 = match __field1 {
                                _serde::export::Some(__field1) => __field1,
                                _serde::export::None => try!(_serde::private::de::missing_field("s")),
                            };
                            _serde::export::Ok(Response {
                                id: __field0,
                                s: __field1,
                            })
                        }
                    }
                    const FIELDS: &'static [&'static str] = &["id", "s"];
                    _serde::Deserializer::deserialize_struct(
                        __deserializer,
                        "Response",
                        FIELDS,
                        __Visitor {
                            marker: _serde::export::PhantomData::<Response>,
                            lifetime: _serde::export::PhantomData,
                        },
                    )
                }
            }
        }
    });
}
<|endoftext|>


<commit_before>#[cfg(feature = "hyphenation")]
extern crate hyphenation;
extern crate textwrap;

#[cfg(feature = "hyphenation")]
use hyphenation::{Language, Load, Standard};
use textwrap::Wrapper;

#[cfg(not(feature = "term_size"))]
fn main() {
    println!("Please enable the term_size feature to run this example.");
}

#[cfg(feature = "term_size")]
fn main() {
    #[cfg(not(feature = "hyphenation"))]
    fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, textwrap::HyphenSplitter>) {
        ("without hyphenation", Wrapper::with_termwidth())
    }

    #[cfg(feature = "hyphenation")]
    fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, Standard>) {
        let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
        ("with hyphenation", Wrapper::with_splitter(textwrap::termwidth(), dictionary))
    }

    let example = "Memory safety without garbage collection. \
                   Concurrency without data races. \
                   Zero-cost abstractions.";
    // Create a new Wrapper -- automatically set the width to the
    // current terminal width.
    let (msg, wrapper) = new_wrapper();
    println!("Formatted {} in {} columns:", msg, wrapper.width);
    println!("----");
    println!("{}", wrapper.fill(example));
    println!("----");
}
<commit_msg>examples: fix warning about unused Wrapper<commit_after>#[cfg(feature = "hyphenation")]
extern crate hyphenation;
extern crate textwrap;

#[cfg(feature = "hyphenation")]
use hyphenation::{Language, Load, Standard};
#[cfg(feature = "term_size")]
use textwrap::Wrapper;

#[cfg(not(feature = "term_size"))]
fn main() {
    println!("Please enable the term_size feature to run this example.");
}

#[cfg(feature = "term_size")]
fn main() {
    #[cfg(not(feature = "hyphenation"))]
    fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, textwrap::HyphenSplitter>) {
        ("without hyphenation", Wrapper::with_termwidth())
    }

    #[cfg(feature = "hyphenation")]
    fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, Standard>) {
        let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
        (
            "with hyphenation",
            Wrapper::with_splitter(textwrap::termwidth(), dictionary),
        )
    }

    let example = "Memory safety without garbage collection. \
                   Concurrency without data races. \
                   Zero-cost abstractions.";
    // Create a new Wrapper -- automatically set the width to the
    // current terminal width.
    let (msg, wrapper) = new_wrapper();
    println!("Formatted {} in {} columns:", msg, wrapper.width);
    println!("----");
    println!("{}", wrapper.fill(example));
    println!("----");
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Core primitive types for relm.
//!
//! The primary type is `EventStream`.

#![warn(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
)]

extern crate glib;
extern crate glib_sys;
extern crate libc;

mod source;

use std::cell::RefCell;
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::mpsc::{self, Receiver, SendError};

use source::{SourceFuncs, new_source, source_get};

use glib::{MainContext, Source};

/// A lock is used to temporarily stop emitting messages.
#[must_use]
pub struct Lock<MSG> {
    stream: Rc<RefCell<_EventStream<MSG>>>,
}

impl<MSG> Drop for Lock<MSG> {
    fn drop(&mut self) {
        self.stream.borrow_mut().locked = false;
    }
}

struct ChannelData<MSG> {
    callback: Box<FnMut(MSG)>,
    peeked_value: Option<MSG>,
    receiver: Receiver<MSG>,
}

/// A wrapper over a `std::sync::mpsc::Sender` to wakeup the glib event loop when sending a
/// message.
#[derive(Clone)]
pub struct Sender<MSG> {
    sender: mpsc::Sender<MSG>,
}

impl<MSG> Sender<MSG> {
    /// Send a message and wakeup the event loop.
    pub fn send(&self, msg: MSG) -> Result<(), SendError<MSG>> {
        let result = self.sender.send(msg);
        let context = MainContext::default();
        context.wakeup();
        result
    }
}

/// A channel to send a message to a relm widget from another thread.
pub struct Channel<MSG> {
    _source: Source,
    _phantom: PhantomData<MSG>,
}

impl<MSG> Channel<MSG> {
    /// Create a new channel with a callback that will be called when a message is received.
    pub fn new<CALLBACK: FnMut(MSG) + 'static>(callback: CALLBACK) -> (Self, Sender<MSG>) {
        let (sender, receiver) = mpsc::channel();
        let source = new_source(RefCell::new(ChannelData {
            callback: Box::new(callback),
            peeked_value: None,
            receiver,
        }));
        let main_context = MainContext::default();
        source.attach(&main_context);
        (Self {
            _source: source,
            _phantom: PhantomData,
        }, Sender {
            sender,
        })
    }
}

impl<MSG> SourceFuncs for RefCell<ChannelData<MSG>> {
    fn dispatch(&self) -> bool {
        // TODO: show errors.
        let msg = self.borrow_mut().peeked_value.take().or_else(|| {
            self.borrow().receiver.try_recv().ok()
        });
        if let Some(msg) = msg {
            let callback = &mut self.borrow_mut().callback;
            callback(msg);
        }
        true
    }

    fn prepare(&self) -> (bool, Option<u32>) {
        if self.borrow().peeked_value.is_some() {
            return (true, None);
        }
        let peek_val = self.borrow().receiver.try_recv().ok();
        self.borrow_mut().peeked_value = peek_val;
        (self.borrow().peeked_value.is_some(), None)
    }

}

struct _EventStream<MSG> {
    events: VecDeque<MSG>,
    locked: bool,
    observers: Vec<Rc<Fn(&MSG)>>,
}

impl<MSG> SourceFuncs for SourceData<MSG> {
    fn dispatch(&self) -> bool {
        let event = self.stream.borrow_mut().events.pop_front();
        if let (Some(event), Some(callback)) = (event, self.callback.borrow_mut().as_mut()) {
            callback(event);
        }
        true
    }

    fn prepare(&self) -> (bool, Option<u32>) {
        (!self.stream.borrow().events.is_empty(), None)
    }

}

struct SourceData<MSG> {
    callback: Rc<RefCell<Option<Box<FnMut(MSG)>>>>,
    stream: Rc<RefCell<_EventStream<MSG>>>,
}

/// A stream of messages to be used for widget/signal communication and inter-widget communication.
pub struct EventStream<MSG> {
    source: Source,
    _phantom: PhantomData<MSG>,
}

impl<MSG> Clone for EventStream<MSG> {
    fn clone(&self) -> Self {
        EventStream {
            source: self.source.clone(),
            _phantom: PhantomData,
        }
    }
}

impl<MSG> EventStream<MSG> {
    fn get_callback(&self) -> Rc<RefCell<Option<Box<FnMut(MSG)>>>> {
        source_get::<SourceData<MSG>>(&self.source).callback.clone()
    }

    fn get_stream(&self) -> Rc<RefCell<_EventStream<MSG>>> {
        source_get::<SourceData<MSG>>(&self.source).stream.clone()
    }
}

impl<MSG> EventStream<MSG> {
    /// Create a new event stream.
    pub fn new() -> Self {
        let event_stream: _EventStream<MSG> = _EventStream {
            events: VecDeque::new(),
            locked: false,
            observers: vec![],
        };
        let source = new_source(SourceData {
            callback: Rc::new(RefCell::new(None)),
            stream: Rc::new(RefCell::new(event_stream)),
        });
        let main_context = MainContext::default();
        source.attach(&main_context);
        EventStream {
            source,
            _phantom: PhantomData,
        }
    }

    /// Close the event stream, i.e. stop processing messages.
    pub fn close(&self) {
        self.source.destroy();
    }

    /// Send the `event` message to the stream and the observers.
    pub fn emit(&self, event: MSG) {
        let stream = self.get_stream();
        if !stream.borrow().locked {
            let len = stream.borrow().observers.len();
            for i in 0..len {
                let observer = stream.borrow().observers[i].clone();
                observer(&event);
            }

            stream.borrow_mut().events.push_back(event);
        }
    }

    /// Lock the stream (don't emit message) until the `Lock` goes out of scope.
    pub fn lock(&self) -> Lock<MSG> {
        let stream = self.get_stream();
        stream.borrow_mut().locked = true;
        Lock {
            stream: self.get_stream().clone(),
        }
    }

    /// Add an observer to the event stream.
    /// This callback will be called every time a message is emmited.
    pub fn observe<CALLBACK: Fn(&MSG) + 'static>(&self, callback: CALLBACK) {
        let stream = self.get_stream();
        stream.borrow_mut().observers.push(Rc::new(callback));
    }

    /// Add a callback to the event stream.
    /// This is the main callback and received a owned version of the message, in contrast to
    /// observe().
    pub fn set_callback<CALLBACK: FnMut(MSG) + 'static>(&self, callback: CALLBACK) {
        let source_callback = self.get_callback();
        *source_callback.borrow_mut() = Some(Box::new(callback));
    }
}
<commit_msg>Blanket impl Clone for Sender<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Core primitive types for relm.
//!
//! The primary type is `EventStream`.

#![warn(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
)]

extern crate glib;
extern crate glib_sys;
extern crate libc;

mod source;

use std::cell::RefCell;
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::mpsc::{self, Receiver, SendError};

use source::{SourceFuncs, new_source, source_get};

use glib::{MainContext, Source};

/// A lock is used to temporarily stop emitting messages.
#[must_use]
pub struct Lock<MSG> {
    stream: Rc<RefCell<_EventStream<MSG>>>,
}

impl<MSG> Drop for Lock<MSG> {
    fn drop(&mut self) {
        self.stream.borrow_mut().locked = false;
    }
}

struct ChannelData<MSG> {
    callback: Box<FnMut(MSG)>,
    peeked_value: Option<MSG>,
    receiver: Receiver<MSG>,
}

/// A wrapper over a `std::sync::mpsc::Sender` to wakeup the glib event loop when sending a
/// message.
pub struct Sender<MSG> {
    sender: mpsc::Sender<MSG>,
}

impl<MSG> Clone for Sender<MSG> {
    fn clone(&self) -> Self {
        Self {
            sender: self.sender.clone(),
        }
    }
}

impl<MSG> Sender<MSG> {
    /// Send a message and wakeup the event loop.
    pub fn send(&self, msg: MSG) -> Result<(), SendError<MSG>> {
        let result = self.sender.send(msg);
        let context = MainContext::default();
        context.wakeup();
        result
    }
}

/// A channel to send a message to a relm widget from another thread.
pub struct Channel<MSG> {
    _source: Source,
    _phantom: PhantomData<MSG>,
}

impl<MSG> Channel<MSG> {
    /// Create a new channel with a callback that will be called when a message is received.
    pub fn new<CALLBACK: FnMut(MSG) + 'static>(callback: CALLBACK) -> (Self, Sender<MSG>) {
        let (sender, receiver) = mpsc::channel();
        let source = new_source(RefCell::new(ChannelData {
            callback: Box::new(callback),
            peeked_value: None,
            receiver,
        }));
        let main_context = MainContext::default();
        source.attach(&main_context);
        (Self {
            _source: source,
            _phantom: PhantomData,
        }, Sender {
            sender,
        })
    }
}

impl<MSG> SourceFuncs for RefCell<ChannelData<MSG>> {
    fn dispatch(&self) -> bool {
        // TODO: show errors.
        let msg = self.borrow_mut().peeked_value.take().or_else(|| {
            self.borrow().receiver.try_recv().ok()
        });
        if let Some(msg) = msg {
            let callback = &mut self.borrow_mut().callback;
            callback(msg);
        }
        true
    }

    fn prepare(&self) -> (bool, Option<u32>) {
        if self.borrow().peeked_value.is_some() {
            return (true, None);
        }
        let peek_val = self.borrow().receiver.try_recv().ok();
        self.borrow_mut().peeked_value = peek_val;
        (self.borrow().peeked_value.is_some(), None)
    }

}

struct _EventStream<MSG> {
    events: VecDeque<MSG>,
    locked: bool,
    observers: Vec<Rc<Fn(&MSG)>>,
}

impl<MSG> SourceFuncs for SourceData<MSG> {
    fn dispatch(&self) -> bool {
        let event = self.stream.borrow_mut().events.pop_front();
        if let (Some(event), Some(callback)) = (event, self.callback.borrow_mut().as_mut()) {
            callback(event);
        }
        true
    }

    fn prepare(&self) -> (bool, Option<u32>) {
        (!self.stream.borrow().events.is_empty(), None)
    }

}

struct SourceData<MSG> {
    callback: Rc<RefCell<Option<Box<FnMut(MSG)>>>>,
    stream: Rc<RefCell<_EventStream<MSG>>>,
}

/// A stream of messages to be used for widget/signal communication and inter-widget communication.
pub struct EventStream<MSG> {
    source: Source,
    _phantom: PhantomData<MSG>,
}

impl<MSG> Clone for EventStream<MSG> {
    fn clone(&self) -> Self {
        EventStream {
            source: self.source.clone(),
            _phantom: PhantomData,
        }
    }
}

impl<MSG> EventStream<MSG> {
    fn get_callback(&self) -> Rc<RefCell<Option<Box<FnMut(MSG)>>>> {
        source_get::<SourceData<MSG>>(&self.source).callback.clone()
    }

    fn get_stream(&self) -> Rc<RefCell<_EventStream<MSG>>> {
        source_get::<SourceData<MSG>>(&self.source).stream.clone()
    }
}

impl<MSG> EventStream<MSG> {
    /// Create a new event stream.
    pub fn new() -> Self {
        let event_stream: _EventStream<MSG> = _EventStream {
            events: VecDeque::new(),
            locked: false,
            observers: vec![],
        };
        let source = new_source(SourceData {
            callback: Rc::new(RefCell::new(None)),
            stream: Rc::new(RefCell::new(event_stream)),
        });
        let main_context = MainContext::default();
        source.attach(&main_context);
        EventStream {
            source,
            _phantom: PhantomData,
        }
    }

    /// Close the event stream, i.e. stop processing messages.
    pub fn close(&self) {
        self.source.destroy();
    }

    /// Send the `event` message to the stream and the observers.
    pub fn emit(&self, event: MSG) {
        let stream = self.get_stream();
        if !stream.borrow().locked {
            let len = stream.borrow().observers.len();
            for i in 0..len {
                let observer = stream.borrow().observers[i].clone();
                observer(&event);
            }

            stream.borrow_mut().events.push_back(event);
        }
    }

    /// Lock the stream (don't emit message) until the `Lock` goes out of scope.
    pub fn lock(&self) -> Lock<MSG> {
        let stream = self.get_stream();
        stream.borrow_mut().locked = true;
        Lock {
            stream: self.get_stream().clone(),
        }
    }

    /// Add an observer to the event stream.
    /// This callback will be called every time a message is emmited.
    pub fn observe<CALLBACK: Fn(&MSG) + 'static>(&self, callback: CALLBACK) {
        let stream = self.get_stream();
        stream.borrow_mut().observers.push(Rc::new(callback));
    }

    /// Add a callback to the event stream.
    /// This is the main callback and received a owned version of the message, in contrast to
    /// observe().
    pub fn set_callback<CALLBACK: FnMut(MSG) + 'static>(&self, callback: CALLBACK) {
        let source_callback = self.get_callback();
        *source_callback.borrow_mut() = Some(Box::new(callback));
    }
}
<|endoftext|>


<commit_before>pub use client::ErrorResponse as MwsErrorResponse;
use types::GenericXmlResponseParseError;

#[derive(Fail, Debug)]
pub enum MwsError {
  #[fail(display = "io error: {}", _0)]
  Io(#[cause] ::std::io::Error),
  #[fail(display = "http error: {}", _0)]
  Http(#[cause] ::reqwest::Error),
  #[fail(display = "xml reader error: {}", _0)]
  XmlReader(#[cause] ::xml::reader::Error),
  #[fail(display = "xml writer error: {}", _0)]
  XmlWriter(#[cause] ::xml::writer::Error),
  #[fail(display = "xml element parse error: {}", _0)]
  XmlElementParse(#[cause] ::xmltree::ParseError),
  #[fail(display = "generic xml response parse error: {}", _0)]
  GenericXmlResponseParse(#[cause] GenericXmlResponseParseError),
  #[fail(display = "csv error: {}", _0)]
  Csv(#[cause] ::csv::Error),
  #[fail(display = "utf8 error: {}", _0)]
  Utf8(#[cause] ::std::str::Utf8Error),
  #[fail(display = "MWS request is unsuccessful: {:?}", _0)]
  ErrorResponse(MwsErrorResponse),
  #[fail(display = "unexpected end of xml: {}", _0)]
  UnexpectedEndOfXml(String),
  #[fail(
    display = "unexpected xml event: expected '{}', found '{}'",
    expected, found
  )]
  UnexpectedXmlEvent { expected: String, found: String },
  #[fail(display = "parse string error: {} : {}", what, message)]
  ParseString { what: String, message: String },
  #[fail(display = "invalid path name: '{}'", _0)]
  InvalidPath(String),
  #[fail(display = "Content-MD5 header missing")]
  ContentMD5HeaderMissing,
  #[fail(display = "{}", _0)]
  Msg(String),
}

impl MwsError {
  /// The common response to a 500 or 503 service error is
  /// to try the request again. Such service errors are
  /// usually only temporary and will resolve themselves.
  pub fn should_try_again(&self) -> bool {
    match *self {
      MwsError::ErrorResponse(ref res) => {
        let code = res.status.as_u16();
        code >= 500 && code < 600
      }
      MwsError::Io(_) => true,
      MwsError::Http(err) => {
        if err.is_redirect() {
          return false
        }

        if let Some(status) = err.status() {
          if status.is_client_error() {
            return false
          }
        }

        return true
      }
      _ => false,
    }
  }
}

macro_rules! impl_from {
  ($v:ident($t:ty)) => {
    impl From<$t> for MwsError {
      fn from(e: $t) -> Self {
        MwsError::$v(e)
      }
    }
  };
}

impl_from!(Io(::std::io::Error));
impl_from!(Http(::reqwest::Error));
impl_from!(XmlReader(::xml::reader::Error));
impl_from!(XmlWriter(::xml::writer::Error));
impl_from!(Csv(::csv::Error));
impl_from!(Utf8(::std::str::Utf8Error));
impl_from!(Msg(String));
impl_from!(XmlElementParse(::xmltree::ParseError));
impl_from!(GenericXmlResponseParse(GenericXmlResponseParseError));

pub type MwsResult<T> = Result<T, MwsError>;
<commit_msg>fix compile<commit_after>pub use client::ErrorResponse as MwsErrorResponse;
use types::GenericXmlResponseParseError;

#[derive(Fail, Debug)]
pub enum MwsError {
  #[fail(display = "io error: {}", _0)]
  Io(#[cause] ::std::io::Error),
  #[fail(display = "http error: {}", _0)]
  Http(#[cause] ::reqwest::Error),
  #[fail(display = "xml reader error: {}", _0)]
  XmlReader(#[cause] ::xml::reader::Error),
  #[fail(display = "xml writer error: {}", _0)]
  XmlWriter(#[cause] ::xml::writer::Error),
  #[fail(display = "xml element parse error: {}", _0)]
  XmlElementParse(#[cause] ::xmltree::ParseError),
  #[fail(display = "generic xml response parse error: {}", _0)]
  GenericXmlResponseParse(#[cause] GenericXmlResponseParseError),
  #[fail(display = "csv error: {}", _0)]
  Csv(#[cause] ::csv::Error),
  #[fail(display = "utf8 error: {}", _0)]
  Utf8(#[cause] ::std::str::Utf8Error),
  #[fail(display = "MWS request is unsuccessful: {:?}", _0)]
  ErrorResponse(MwsErrorResponse),
  #[fail(display = "unexpected end of xml: {}", _0)]
  UnexpectedEndOfXml(String),
  #[fail(
    display = "unexpected xml event: expected '{}', found '{}'",
    expected, found
  )]
  UnexpectedXmlEvent { expected: String, found: String },
  #[fail(display = "parse string error: {} : {}", what, message)]
  ParseString { what: String, message: String },
  #[fail(display = "invalid path name: '{}'", _0)]
  InvalidPath(String),
  #[fail(display = "Content-MD5 header missing")]
  ContentMD5HeaderMissing,
  #[fail(display = "{}", _0)]
  Msg(String),
}

impl MwsError {
  /// The common response to a 500 or 503 service error is
  /// to try the request again. Such service errors are
  /// usually only temporary and will resolve themselves.
  pub fn should_try_again(&self) -> bool {
    match *self {
      MwsError::ErrorResponse(ref res) => {
        let code = res.status.as_u16();
        code >= 500 && code < 600
      }
      MwsError::Io(_) => true,
      MwsError::Http(ref err) => {
        if err.is_redirect() {
          return false
        }

        if let Some(status) = err.status() {
          if status.is_client_error() {
            return false
          }
        }

        return true
      }
      _ => false,
    }
  }
}

macro_rules! impl_from {
  ($v:ident($t:ty)) => {
    impl From<$t> for MwsError {
      fn from(e: $t) -> Self {
        MwsError::$v(e)
      }
    }
  };
}

impl_from!(Io(::std::io::Error));
impl_from!(Http(::reqwest::Error));
impl_from!(XmlReader(::xml::reader::Error));
impl_from!(XmlWriter(::xml::writer::Error));
impl_from!(Csv(::csv::Error));
impl_from!(Utf8(::std::str::Utf8Error));
impl_from!(Msg(String));
impl_from!(XmlElementParse(::xmltree::ParseError));
impl_from!(GenericXmlResponseParse(GenericXmlResponseParseError));

pub type MwsResult<T> = Result<T, MwsError>;
<|endoftext|>


<commit_before>use std::{
    collections::BTreeMap,
    env,
    io::Write as _,
    path::Path,
    time::{Instant, SystemTime, UNIX_EPOCH},
};

use anyhow::{bail, format_err, Result};
use xshell::{cmd, mkdir_p, pushd, pushenv, read_file, rm_rf};

type Unit = String;

pub struct MetricsCmd {
    pub dry_run: bool,
}

impl MetricsCmd {
    pub fn run(self) -> Result<()> {
        let mut metrics = Metrics::new()?;
        if !self.dry_run {
            rm_rf("./target/release")?;
        }
        if !Path::new("./target/rustc-perf").exists() {
            mkdir_p("./target/rustc-perf")?;
            cmd!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")
                .run()?;
        }
        {
            let _d = pushd("./target/rustc-perf")?;
            cmd!("git reset --hard 1d9288b0da7febf2599917da1b57dc241a1af033").run()?;
        }

        let _env = pushenv("RA_METRICS", "1");

        metrics.measure_build()?;
        metrics.measure_analysis_stats_self()?;
        metrics.measure_analysis_stats("ripgrep")?;
        metrics.measure_analysis_stats("webrender")?;

        if !self.dry_run {
            let _d = pushd("target")?;
            let metrics_token = env::var("METRICS_TOKEN").unwrap();
            cmd!(
                "git clone --depth 1 https://{metrics_token}@github.com/rust-analyzer/metrics.git"
            )
            .run()?;
            let _d = pushd("metrics")?;

            let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?;
            writeln!(file, "{}", metrics.json())?;
            cmd!("git add .").run()?;
            cmd!("git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈")
                .run()?;
            cmd!("git push origin master").run()?;
        }
        eprintln!("{:#?}", metrics);
        Ok(())
    }
}

impl Metrics {
    fn measure_build(&mut self) -> Result<()> {
        eprintln!("\nMeasuring build");
        cmd!("cargo fetch").run()?;

        let time = Instant::now();
        cmd!("cargo build --release --package rust-analyzer --bin rust-analyzer").run()?;
        let time = time.elapsed();
        self.report("build", time.as_millis() as u64, "ms".into());
        Ok(())
    }
    fn measure_analysis_stats_self(&mut self) -> Result<()> {
        self.measure_analysis_stats_path("self", &".")
    }
    fn measure_analysis_stats(&mut self, bench: &str) -> Result<()> {
        self.measure_analysis_stats_path(
            bench,
            &format!("./target/rustc-perf/collector/benchmarks/{}", bench),
        )
    }
    fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> {
        eprintln!("\nMeasuring analysis-stats/{}", name);
        let output = cmd!("./target/release/rust-analyzer analysis-stats --quiet {path}").read()?;
        for (metric, value, unit) in parse_metrics(&output) {
            self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into());
        }
        Ok(())
    }
}

fn parse_metrics(output: &str) -> Vec<(&str, u64, &str)> {
    output
        .lines()
        .filter_map(|it| {
            let entry = it.split(':').collect::<Vec<_>>();
            match entry.as_slice() {
                ["METRIC", name, value, unit] => Some((*name, value.parse().unwrap(), *unit)),
                _ => None,
            }
        })
        .collect()
}

#[derive(Debug)]
struct Metrics {
    host: Host,
    timestamp: SystemTime,
    revision: String,
    metrics: BTreeMap<String, (u64, Unit)>,
}

#[derive(Debug)]
struct Host {
    os: String,
    cpu: String,
    mem: String,
}

impl Metrics {
    fn new() -> Result<Metrics> {
        let host = Host::new()?;
        let timestamp = SystemTime::now();
        let revision = cmd!("git rev-parse HEAD").read()?;
        Ok(Metrics { host, timestamp, revision, metrics: BTreeMap::new() })
    }

    fn report(&mut self, name: &str, value: u64, unit: Unit) {
        self.metrics.insert(name.into(), (value, unit));
    }

    fn json(&self) -> String {
        let mut buf = String::new();
        self.to_json(write_json::object(&mut buf));
        buf
    }

    fn to_json(&self, mut obj: write_json::Object<'_>) {
        self.host.to_json(obj.object("host"));
        let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap();
        obj.number("timestamp", timestamp.as_secs() as f64);
        obj.string("revision", &self.revision);
        let mut metrics = obj.object("metrics");
        for (k, (value, unit)) in &self.metrics {
            metrics.array(k).number(*value as f64).string(unit);
        }
    }
}

impl Host {
    fn new() -> Result<Host> {
        if cfg!(not(target_os = "linux")) {
            bail!("can only collect metrics on Linux ");
        }

        let os = read_field("/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();

        let cpu =
            read_field("/proc/cpuinfo", "model name")?.trim_start_matches(':').trim().to_string();

        let mem = read_field("/proc/meminfo", "MemTotal:")?;

        return Ok(Host { os, cpu, mem });

        fn read_field<'a>(path: &str, field: &str) -> Result<String> {
            let text = read_file(path)?;

            let line = text
                .lines()
                .find(|it| it.starts_with(field))
                .ok_or_else(|| format_err!("can't parse {}", path))?;
            Ok(line[field.len()..].trim().to_string())
        }
    }
    fn to_json(&self, mut obj: write_json::Object<'_>) {
        obj.string("os", &self.os).string("cpu", &self.cpu).string("mem", &self.mem);
    }
}
<commit_msg>Capture memory usage metrics<commit_after>use std::{
    collections::BTreeMap,
    env,
    io::Write as _,
    path::Path,
    process::{Command, Stdio},
    time::{Instant, SystemTime, UNIX_EPOCH},
};

use anyhow::{bail, format_err, Result};
use xshell::{cmd, mkdir_p, pushd, pushenv, read_file, rm_rf};

type Unit = String;

pub struct MetricsCmd {
    pub dry_run: bool,
}

impl MetricsCmd {
    pub fn run(self) -> Result<()> {
        let mut metrics = Metrics::new()?;
        if !self.dry_run {
            rm_rf("./target/release")?;
        }
        if !Path::new("./target/rustc-perf").exists() {
            mkdir_p("./target/rustc-perf")?;
            cmd!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")
                .run()?;
        }
        {
            let _d = pushd("./target/rustc-perf")?;
            cmd!("git reset --hard 1d9288b0da7febf2599917da1b57dc241a1af033").run()?;
        }

        let _env = pushenv("RA_METRICS", "1");

        metrics.measure_build()?;
        metrics.measure_analysis_stats_self()?;
        metrics.measure_analysis_stats("ripgrep")?;
        metrics.measure_analysis_stats("webrender")?;

        if !self.dry_run {
            let _d = pushd("target")?;
            let metrics_token = env::var("METRICS_TOKEN").unwrap();
            cmd!(
                "git clone --depth 1 https://{metrics_token}@github.com/rust-analyzer/metrics.git"
            )
            .run()?;
            let _d = pushd("metrics")?;

            let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?;
            writeln!(file, "{}", metrics.json())?;
            cmd!("git add .").run()?;
            cmd!("git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈")
                .run()?;
            cmd!("git push origin master").run()?;
        }
        eprintln!("{:#?}", metrics);
        Ok(())
    }
}

impl Metrics {
    fn measure_build(&mut self) -> Result<()> {
        eprintln!("\nMeasuring build");
        cmd!("cargo fetch").run()?;

        let time = Instant::now();
        cmd!("cargo build --release --package rust-analyzer --bin rust-analyzer").run()?;
        let time = time.elapsed();
        self.report("build", time.as_millis() as u64, "ms".into());
        Ok(())
    }
    fn measure_analysis_stats_self(&mut self) -> Result<()> {
        self.measure_analysis_stats_path("self", &".")
    }
    fn measure_analysis_stats(&mut self, bench: &str) -> Result<()> {
        self.measure_analysis_stats_path(
            bench,
            &format!("./target/rustc-perf/collector/benchmarks/{}", bench),
        )
    }
    fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> {
        eprintln!("\nMeasuring analysis-stats/{}", name);
        let output = Command::new("./target/release/rust-analyzer")
            .args(&["analysis-stats", "--quiet", "--memory-usage", path])
            .stdout(Stdio::inherit())
            .output()?;
        let output = String::from_utf8(output.stdout)?;
        for (metric, value, unit) in parse_metrics(&output) {
            self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into());
        }
        Ok(())
    }
}

fn parse_metrics(output: &str) -> Vec<(&str, u64, &str)> {
    output
        .lines()
        .filter_map(|it| {
            let entry = it.split(':').collect::<Vec<_>>();
            match entry.as_slice() {
                ["METRIC", name, value, unit] => Some((*name, value.parse().unwrap(), *unit)),
                _ => None,
            }
        })
        .collect()
}

#[derive(Debug)]
struct Metrics {
    host: Host,
    timestamp: SystemTime,
    revision: String,
    metrics: BTreeMap<String, (u64, Unit)>,
}

#[derive(Debug)]
struct Host {
    os: String,
    cpu: String,
    mem: String,
}

impl Metrics {
    fn new() -> Result<Metrics> {
        let host = Host::new()?;
        let timestamp = SystemTime::now();
        let revision = cmd!("git rev-parse HEAD").read()?;
        Ok(Metrics { host, timestamp, revision, metrics: BTreeMap::new() })
    }

    fn report(&mut self, name: &str, value: u64, unit: Unit) {
        self.metrics.insert(name.into(), (value, unit));
    }

    fn json(&self) -> String {
        let mut buf = String::new();
        self.to_json(write_json::object(&mut buf));
        buf
    }

    fn to_json(&self, mut obj: write_json::Object<'_>) {
        self.host.to_json(obj.object("host"));
        let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap();
        obj.number("timestamp", timestamp.as_secs() as f64);
        obj.string("revision", &self.revision);
        let mut metrics = obj.object("metrics");
        for (k, (value, unit)) in &self.metrics {
            metrics.array(k).number(*value as f64).string(unit);
        }
    }
}

impl Host {
    fn new() -> Result<Host> {
        if cfg!(not(target_os = "linux")) {
            bail!("can only collect metrics on Linux ");
        }

        let os = read_field("/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();

        let cpu =
            read_field("/proc/cpuinfo", "model name")?.trim_start_matches(':').trim().to_string();

        let mem = read_field("/proc/meminfo", "MemTotal:")?;

        return Ok(Host { os, cpu, mem });

        fn read_field<'a>(path: &str, field: &str) -> Result<String> {
            let text = read_file(path)?;

            let line = text
                .lines()
                .find(|it| it.starts_with(field))
                .ok_or_else(|| format_err!("can't parse {}", path))?;
            Ok(line[field.len()..].trim().to_string())
        }
    }
    fn to_json(&self, mut obj: write_json::Object<'_>) {
        obj.string("os", &self.os).string("cpu", &self.cpu).string("mem", &self.mem);
    }
}
<|endoftext|>


<commit_before>use crate::{
    codegen, is_release_tag,
    not_bash::{date_iso, fs2, pushd, run},
    project_root, Mode, Result,
};

pub struct ReleaseCmd {
    pub dry_run: bool,
}

impl ReleaseCmd {
    pub fn run(self) -> Result<()> {
        if !self.dry_run {
            run!("git switch release")?;
            run!("git fetch upstream --tags --force")?;
            run!("git reset --hard tags/nightly")?;
            run!("git push")?;
        }
        codegen::generate_assists_docs(Mode::Overwrite)?;
        codegen::generate_feature_docs(Mode::Overwrite)?;

        let website_root = project_root().join("../rust-analyzer.github.io");
        let changelog_dir = website_root.join("./thisweek/_posts");

        let today = date_iso()?;
        let commit = run!("git rev-parse HEAD")?;
        let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count();

        let contents = format!(
            "\
= Changelog #{}
:sectanchors:
:page-layout: post

Commit: commit:{}[] +
Release: release:{}[]

== Sponsors

**Become a sponsor:** https://opencollective.com/rust-analyzer/[opecollective.com/rust-analyzer]

== New Features

* pr:[] .

== Fixes

== Internal Improvements
",
            changelog_n, commit, today
        );

        let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
        fs2::write(&path, &contents)?;

        for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() {
            let src = project_root().join("./docs/user/").join(adoc);
            let dst = website_root.join(adoc);
            fs2::copy(src, dst)?;
        }

        let tags = run!("git tag --list"; echo = false)?;
        let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();

        let git_log = run!("git log {}..HEAD --merges --reverse", prev_tag; echo = false)?;
        let git_log_dst = website_root.join("git.log");
        fs2::write(git_log_dst, &git_log)?;

        Ok(())
    }
}

pub struct PromoteCmd {
    pub dry_run: bool,
}

impl PromoteCmd {
    pub fn run(self) -> Result<()> {
        let _dir = pushd("../rust-rust-analyzer");
        run!("git switch master")?;
        run!("git fetch upstream")?;
        run!("git reset --hard upstream/master")?;
        run!("git submodule update --recursive")?;

        let branch = format!("rust-analyzer-{}", date_iso()?);
        run!("git switch -c {}", branch)?;
        {
            let _dir = pushd("src/tools/rust-analyzer");
            run!("git fetch origin")?;
            run!("git reset --hard origin/release")?;
        }
        run!("git add src/tools/rust-analyzer")?;
        run!("git commit -m':arrow_up: rust-analyzer'")?;
        if !self.dry_run {
            run!("git push")?;
            run!(
                "xdg-open https://github.com/matklad/rust/pull/new/{}?body=r%3F%20%40ghost",
                branch
            )?;
        }
        Ok(())
    }
}
<commit_msg>Fix typo<commit_after>use crate::{
    codegen, is_release_tag,
    not_bash::{date_iso, fs2, pushd, run},
    project_root, Mode, Result,
};

pub struct ReleaseCmd {
    pub dry_run: bool,
}

impl ReleaseCmd {
    pub fn run(self) -> Result<()> {
        if !self.dry_run {
            run!("git switch release")?;
            run!("git fetch upstream --tags --force")?;
            run!("git reset --hard tags/nightly")?;
            run!("git push")?;
        }
        codegen::generate_assists_docs(Mode::Overwrite)?;
        codegen::generate_feature_docs(Mode::Overwrite)?;

        let website_root = project_root().join("../rust-analyzer.github.io");
        let changelog_dir = website_root.join("./thisweek/_posts");

        let today = date_iso()?;
        let commit = run!("git rev-parse HEAD")?;
        let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count();

        let contents = format!(
            "\
= Changelog #{}
:sectanchors:
:page-layout: post

Commit: commit:{}[] +
Release: release:{}[]

== Sponsors

**Become a sponsor:** https://opencollective.com/rust-analyzer/[opencollective.com/rust-analyzer]

== New Features

* pr:[] .

== Fixes

== Internal Improvements
",
            changelog_n, commit, today
        );

        let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
        fs2::write(&path, &contents)?;

        for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() {
            let src = project_root().join("./docs/user/").join(adoc);
            let dst = website_root.join(adoc);
            fs2::copy(src, dst)?;
        }

        let tags = run!("git tag --list"; echo = false)?;
        let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();

        let git_log = run!("git log {}..HEAD --merges --reverse", prev_tag; echo = false)?;
        let git_log_dst = website_root.join("git.log");
        fs2::write(git_log_dst, &git_log)?;

        Ok(())
    }
}

pub struct PromoteCmd {
    pub dry_run: bool,
}

impl PromoteCmd {
    pub fn run(self) -> Result<()> {
        let _dir = pushd("../rust-rust-analyzer");
        run!("git switch master")?;
        run!("git fetch upstream")?;
        run!("git reset --hard upstream/master")?;
        run!("git submodule update --recursive")?;

        let branch = format!("rust-analyzer-{}", date_iso()?);
        run!("git switch -c {}", branch)?;
        {
            let _dir = pushd("src/tools/rust-analyzer");
            run!("git fetch origin")?;
            run!("git reset --hard origin/release")?;
        }
        run!("git add src/tools/rust-analyzer")?;
        run!("git commit -m':arrow_up: rust-analyzer'")?;
        if !self.dry_run {
            run!("git push")?;
            run!(
                "xdg-open https://github.com/matklad/rust/pull/new/{}?body=r%3F%20%40ghost",
                branch
            )?;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![crate_type = "proc-macro"]
#![recursion_limit = "192"]
#![feature(trace_macros)]
#![feature(log_syntax)]

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

use proc_macro::TokenStream;

enum Kind {
    Module,
    Parameter,
    ModIntf,
}

#[proc_macro_derive(ModParse, attributes(ignore))]
pub fn parse(input: TokenStream) -> TokenStream {
    let source = input.to_string();
    let mut ast = syn::parse_derive_input(&source).expect("failed to parse rust syntax");
    let gen = impl_parse(&mut ast);
    gen.parse().expect("failed to serialize into rust syntax")
}
fn is_type(ty: &syn::Ty, name: &'static str) -> bool {
    if let syn::Ty::Path(_, ref path) = *ty {
        if path.segments.iter().any(|seg| seg.ident.as_ref() == name) {
            true
        } else {
            false
        }
    } else {
        false
    }
}

fn option_type(ty: &syn::Ty) -> &syn::Ty {
    if let syn::Ty::Path(_, ref path) = *ty {
        if let Some(seg) = path.segments
               .iter()
               .find(|seg| seg.ident.as_ref() == "Option") {
            if let syn::PathParameters::AngleBracketed(ref data) = seg.parameters {
                // assume simple nesting for now
                &data.types[0]
            } else {
                panic!("can't parse Option segment parameters {:?}", seg.parameters);
            }
        } else {
            panic!("Option not found!")
        }
    } else {
        panic!("not path")
    }
}

fn get_type(ty: &syn::Ty) -> Kind {
    if is_type(&ty, "Option") {
        get_type(option_type(ty))
    } else if is_type(&ty, "Module") {
        Kind::Module
    } else if is_type(&ty, "Parameter") {
        Kind::Parameter
    } else {
        Kind::ModIntf
    }
}

fn impl_parse(ast: &mut syn::DeriveInput) -> quote::Tokens {
    use syn::{Body, VariantData};

    let ref mut variants = match ast.body {
        Body::Struct(VariantData::Struct(ref vars)) => vars,
        _ => panic!("#[derive(Parse)] is only defined for braced structs"),
    };

    let name = &ast.ident;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    let atmatch = variants.iter()
        .filter_map(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") ||
                is_type(& field.ty, "Module")
            { return None;}
            let field_name = field.ident.as_ref().clone();
            let is_option = is_type(&field.ty, "Option");
            get_type(&field.ty);
            match get_type(&field.ty) {
                Kind::Parameter if is_option =>
                    Some( quote! {
                        if let Some(ref mut param) = self. #field_name {
                            self.delegate.add_param(stringify!(#field_name));
                        };
                    } ),
                Kind::Parameter =>
                    Some( quote! { self.delegate.add_param(stringify!(#field_name))  } ),
                Kind::ModIntf if is_option =>
                Some ( quote! {
                    if let Some(ref module) = self. #field_name {
                        self.delegate.add_module(stringify!(#field_name));
                    };
                } ),
                Kind::ModIntf =>
                    Some ( quote! { self.delegate.add_module(stringify!(#field_name) ); } ),
                _ => panic!("bad match {:?}", field.ty),
            }
        });
    let param_match = variants.iter()
        .filter_map(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") ||
                is_type(& field.ty, "Module")
            { return None;}
            let field_name = field.ident.as_ref().clone();
            let is_option = is_type(&field.ty, "Option");
            get_type(&field.ty);
            match get_type(&field.ty) {
                Kind::Parameter if is_option =>
                    Some( quote! {
                        stringify!(#field_name) => {
                        if let Some(ref mut param) = self. #field_name {
                            Some(param.v.id)
                        } else { None }},
                    } ),
                Kind::Parameter =>
                    Some( quote! { stringify!(#field_name) => Some(self. #field_name . v.id), } ),
                Kind::ModIntf =>  None,
                _ => panic!("bad match {:?}", field.ty),
            }

        });
    let mut module_match =  variants.iter()
        .filter_map(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") ||
                is_type(& field.ty, "Module")
            { return None;}
            let field_name = field.ident.as_ref().clone();
            get_type(&field.ty);
            match get_type(&field.ty) {
                Kind::Parameter => None,
                Kind::ModIntf =>
                    Some( quote! { stringify!(#field_name) => &mut self. #field_name,  } ),
                _ => panic!("bad match {:?}", field.ty),
            }
        });
    let foo = if module_match.any(|_| true) == false {

    quote! {
        impl #impl_generics InitModuleStruct for #name  #ty_generics  #where_clause {
            fn init_module(mut self) -> Self {
                self.delegate()._name = stringify!(#name).into();
                #(#atmatch);*
                ;
                self
            }
        }
        impl #impl_generics GetFieldStruct<T> for #name  #ty_generics  #where_clause {
            fn get_param(&mut self, name: &str) -> Option<i32> {
                match name {
                    #(#param_match)*
                    _ => panic!("unknown Parameter {}", name),
                }
            }
            fn get_module(&mut self, name: &str) -> &mut ModIntf<T> {
                unreachable!()
            }
        }
    }
    } else {
    quote! {
        impl #impl_generics InitModuleStruct for #name  #ty_generics  #where_clause {
            fn init_module(mut self) -> Self {
                self.delegate()._name = stringify!(#name).into();
                #(#atmatch);*
                ;
                self
            }
        }
        impl #impl_generics GetFieldStruct<T> for #name  #ty_generics  #where_clause {
            fn get_param(&mut self, name: &str) -> Option<i32> {
                match name {
                    #(#param_match)*
                    _ => panic!("unknown Parameter {}", name),
                }
            }
            fn get_module(&mut self, name: &str) -> &mut ModIntf<T> {
                match name {
                    #(#module_match)*
                    _ => {panic!("not found {}", name); },
                }
            }
        }
    }

    };
    println!("parse is {}", foo);
    foo
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>fix bug consuming a match in get_module<commit_after>#![crate_type = "proc-macro"]
#![recursion_limit = "192"]
#![feature(trace_macros)]
#![feature(log_syntax)]

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

use proc_macro::TokenStream;

enum Kind {
    Module,
    Parameter,
    ModIntf,
}

#[proc_macro_derive(ModParse, attributes(ignore))]
pub fn parse(input: TokenStream) -> TokenStream {
    let source = input.to_string();
    let mut ast = syn::parse_derive_input(&source).expect("failed to parse rust syntax");
    let gen = impl_parse(&mut ast);
    gen.parse().expect("failed to serialize into rust syntax")
}
fn is_type(ty: &syn::Ty, name: &'static str) -> bool {
    if let syn::Ty::Path(_, ref path) = *ty {
        if path.segments.iter().any(|seg| seg.ident.as_ref() == name) {
            true
        } else {
            false
        }
    } else {
        false
    }
}

fn option_type(ty: &syn::Ty) -> &syn::Ty {
    if let syn::Ty::Path(_, ref path) = *ty {
        if let Some(seg) = path.segments
               .iter()
               .find(|seg| seg.ident.as_ref() == "Option") {
            if let syn::PathParameters::AngleBracketed(ref data) = seg.parameters {
                // assume simple nesting for now
                &data.types[0]
            } else {
                panic!("can't parse Option segment parameters {:?}", seg.parameters);
            }
        } else {
            panic!("Option not found!")
        }
    } else {
        panic!("not path")
    }
}

fn get_type(ty: &syn::Ty) -> Kind {
    if is_type(&ty, "Option") {
        get_type(option_type(ty))
    } else if is_type(&ty, "Module") {
        Kind::Module
    } else if is_type(&ty, "Parameter") {
        Kind::Parameter
    } else {
        Kind::ModIntf
    }
}

fn impl_parse(ast: &mut syn::DeriveInput) -> quote::Tokens {
    use syn::{Body, VariantData};

    let ref mut variants = match ast.body {
        Body::Struct(VariantData::Struct(ref vars)) => vars,
        _ => panic!("#[derive(Parse)] is only defined for braced structs"),
    };

    let name = &ast.ident;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    // XXX figure out how to avoid this
    let used_variants0 = variants.iter().filter(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") { false}
            else if is_type(& field.ty, "Module") {false}
            else {true}
    });
    let used_variants1 = variants.iter().filter(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") { false}
            else if is_type(& field.ty, "Module") {false}
            else {true}
    });
    let used_variants2 = variants.iter().filter(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") { false}
            else if is_type(& field.ty, "Module") {false}
            else {true}
    });
    let atmatch = used_variants0
        .filter_map(|field| {
            let field_name = field.ident.as_ref().clone();
            let is_option = is_type(&field.ty, "Option");
            match get_type(&field.ty) {
                Kind::Parameter if is_option =>
                    Some( quote! {
                        if let Some(ref mut param) = self. #field_name {
                            self.delegate.add_param(stringify!(#field_name));
                        };
                    } ),
                Kind::Parameter =>
                    Some( quote! { self.delegate.add_param(stringify!(#field_name))  } ),
                Kind::ModIntf if is_option =>
                Some ( quote! {
                    if let Some(ref module) = self. #field_name {
                        self.delegate.add_module(stringify!(#field_name));
                    };
                } ),
                Kind::ModIntf =>
                    Some ( quote! { self.delegate.add_module(stringify!(#field_name) ); } ),
                _ => panic!("bad match {:?}", field.ty),
            }
        });
    let param_match = used_variants1
        .filter_map(|field| {
            let field_name = field.ident.as_ref().clone();
            let is_option = is_type(&field.ty, "Option");
            match get_type(&field.ty) {
                Kind::Parameter if is_option =>
                    Some( quote! {
                        stringify!(#field_name) => {
                        if let Some(ref mut param) = self. #field_name {
                            Some(param.v.id)
                        } else { None }},
                    } ),
                Kind::Parameter =>
                    Some( quote! { stringify!(#field_name) => Some(self. #field_name . v.id), } ),
                Kind::ModIntf =>  None,
                _ => panic!("bad match {:?}", field.ty),
            }

        });
    let module_match = used_variants2
        .filter_map(|field| {
            let field_name = field.ident.as_ref().clone();
            match get_type(&field.ty) {
                Kind::Parameter => {println!("{:?}", field.ty); None},
                Kind::ModIntf =>
                    Some( quote! { stringify!(#field_name) => &mut self. #field_name,  } ),
                _ => panic!("bad match {:?}", field.ty),
            }
        });
    let foo = quote! {
        impl #impl_generics InitModuleStruct for #name  #ty_generics  #where_clause {
            fn init_module(mut self) -> Self {
                self.delegate()._name = stringify!(#name).into();
                #(#atmatch);*
                ;
                self
            }
        }
        impl #impl_generics GetFieldStruct<T> for #name  #ty_generics  #where_clause {
            fn get_param(&mut self, name: &str) -> Option<i32> {
                match name {
                    #(#param_match)*
                    _ => panic!("unknown Parameter {}", name),
                }
            }
            fn get_module(&mut self, name: &str) -> &mut ModIntf<T> {
                match name {
                    #(#module_match)*
                    _ => {panic!("not found {}", name); },
                }
            }
        }

    };
    println!("parse is {}", foo);
    foo
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>use std::fmt::{Debug, Formatter, Error};

extern crate clap;
use clap::{App, ArgMatches};

pub struct ModuleConfig {
    pub load : bool,
}

impl ModuleConfig {
    pub fn new() -> ModuleConfig {
        ModuleConfig {
            load: false,
        }
    }
}

pub struct CliConfig<'a> {
    pub module_configs  : Vec<ModuleConfig>,
    pub cli_matches     : ArgMatches<'a, 'a>,
}

impl<'a> CliConfig<'a> {
    pub fn new(app : clap::App<'a, 'a, 'a, 'a, 'a, 'a>) -> CliConfig<'a> {
        CliConfig {
            module_configs: vec![],
            cli_matches: app.get_matches(),
        }
    }

    /**
     * Check whether the CLI says we should run verbose
     */
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbose") || self.is_debugging()
    }

    /**
     * Check whether the CLI says we should run in debugging
     */
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debug")
    }

    /**
     * Get the runtime path the CLI configured
     */
    pub fn get_rtp(&self) -> Option<String> {
        self.cli_matches.value_of("rtp").and_then(|s| Some(String::from(s)))
    }

    /**
     * Get the store path the CLI configured
     *
     * TODO: Implement properly. Not working by now.
     */
    pub fn store_path(&self) -> Option<String> {
        self.get_rtp().and_then(|rtp| {
            self.cli_matches
                .value_of("storepath")
                .and_then(|s| Some(rtp + s))
        })
    }

    pub fn editor(&self) -> Option<String> {
        self.cli_matches.value_of("editor").and_then(|s| Some(String::from(s)))
    }

    pub fn editor_opts(&self) -> String {
        self.cli_matches
            .value_of("editor_opts")
            .map(|s| String::from(s))
            .unwrap_or(String::from(""))
    }
}

impl<'a> Debug for CliConfig<'a> {

    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "CliConfig (verbose: {}, debugging: {}, rtp: {})",
            self.is_verbose(),
            self.is_debugging(),
            self.get_rtp().or(Some(String::from("NONE"))).unwrap())
    }

}
<commit_msg>Add CLI implementation for reporting<commit_after>use std::fmt::{Debug, Formatter, Error};

extern crate clap;
use clap::{App, ArgMatches};

pub struct ModuleConfig {
    pub load : bool,
}

impl ModuleConfig {
    pub fn new() -> ModuleConfig {
        ModuleConfig {
            load: false,
        }
    }
}

pub struct CliConfig<'a> {
    pub module_configs  : Vec<ModuleConfig>,
    pub cli_matches     : ArgMatches<'a, 'a>,
}

impl<'a> CliConfig<'a> {
    pub fn new(app : clap::App<'a, 'a, 'a, 'a, 'a, 'a>) -> CliConfig<'a> {
        CliConfig {
            module_configs: vec![],
            cli_matches: app.get_matches(),
        }
    }

    /**
     * Check whether the CLI says we should run verbose
     */
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbose") || self.is_debugging()
    }

    /**
     * Check whether the CLI says we should run in debugging
     */
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debug")
    }

    /**
     * Check whether the CLI says we should run with reporting
     */
    pub fn report_exit(&self) -> bool {
        self.cli_matches.is_present("report")
    }

    /**
     * Get the runtime path the CLI configured
     */
    pub fn get_rtp(&self) -> Option<String> {
        self.cli_matches.value_of("rtp").and_then(|s| Some(String::from(s)))
    }

    /**
     * Get the store path the CLI configured
     *
     * TODO: Implement properly. Not working by now.
     */
    pub fn store_path(&self) -> Option<String> {
        self.get_rtp().and_then(|rtp| {
            self.cli_matches
                .value_of("storepath")
                .and_then(|s| Some(rtp + s))
        })
    }

    pub fn editor(&self) -> Option<String> {
        self.cli_matches.value_of("editor").and_then(|s| Some(String::from(s)))
    }

    pub fn editor_opts(&self) -> String {
        self.cli_matches
            .value_of("editor_opts")
            .map(|s| String::from(s))
            .unwrap_or(String::from(""))
    }
}

impl<'a> Debug for CliConfig<'a> {

    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "CliConfig (verbose: {}, debugging: {}, rtp: {})",
            self.is_verbose(),
            self.is_debugging(),
            self.get_rtp().or(Some(String::from("NONE"))).unwrap())
    }

}
<|endoftext|>


<commit_before>//
// Copyright (c) 2016, Boris Popov <popov@whitekefir.ru>
//
// 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/.
//

extern crate libc;

use logger;
use self::libc::getenv;

use std::ffi::CString;

pub struct Env {
    device: String,
    dir:    String,
    script: String
}

impl Env {
    pub fn new() -> Env {
        return Env{device: "".to_string(),
                   dir:    "".to_string(),
                   script: "".to_string()}
    }

    pub fn load(&mut self, l: &logger::Logger) {
        self.load_device(l);
        self.load_dir(l);
        self.load_script(l);
        self.load_label(l);
    }

    pub fn getDir(&self) -> &str {
        return &self.dir;
    }

    pub fn getScript(&self) -> &str {
        return &self.script;
    }

    fn load_device(&mut self, l: &logger::Logger) {
        self.device = self.load_("AMAE_DEVICE", l);
    }

    fn load_dir(&mut self, l: &logger::Logger) {
        self.dir = self.load_("AMAE_MOUNT_DIR", l);
    }

    fn load_script(&mut self, l: &logger::Logger) {
        self.script = self.load_("AMAE_SCRIPT", l);
    }

    fn load_label(&mut self, l: &logger::Logger) {
        self.script = self.load_("AMAE_LABEL", l);
    }

    fn load_(&self, name: &str, l: &logger::Logger) -> String {
        let cname = CString::new(name).unwrap();
        let cname_ptr = cname.as_ptr();
        unsafe {
            let out = getenv(cname_ptr);
            if out.is_null() { self.error_(name, l); }
            let cstring = CString::from_raw(out);
            let res = cstring.into_string();
            match res {
                Ok(v)  => return v,
                Err(e) => {
                    let mut ss = self.ef(name);
                    ss += " ";
                    ss += &(format!("{}", e));
                    self.error__(ss, l);
                    return "".to_string();
                }
            }
        }
    }

    fn error_(&self, name: &str, l: &logger::Logger) {
        self.error__(self.ef(name), l);
    }

    fn ef(&self, name: &str) -> String {
        let em = "Can't get env: ".to_string() +
            name + "!";
        return em;
    }

    fn error__(&self, s: String, l: &logger::Logger) {
        l.error(s.as_str());
        panic!(s);
    }
}
/*
#[test]
fn hello() {
    let x = Err("test");
    assert_eq!("test", x.unwrap());
}
 */
<commit_msg>add Env::getLabel<commit_after>//
// Copyright (c) 2016, Boris Popov <popov@whitekefir.ru>
//
// 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/.
//

extern crate libc;

use logger;
use self::libc::getenv;

use std::ffi::CString;

pub struct Env {
    device: String,
    dir:    String,
    script: String,
    label: String
}

impl Env {
    pub fn new() -> Env {
        return Env{device: "".to_string(),
                   dir:    "".to_string(),
                   label:  "".to_string(),
                   script: "".to_string()}
    }

    pub fn load(&mut self, l: &logger::Logger) {
        self.load_device(l);
        self.load_dir(l);
        self.load_script(l);
        self.load_label(l);
    }

    pub fn getDir(&self) -> &str {
        return &self.dir;
    }

    pub fn getScript(&self) -> &str {
        return &self.script;
    }

    pub fn getLabel(&self) -> &str {
        return &self.label;
    }

    fn load_device(&mut self, l: &logger::Logger) {
        self.device = self.load_("AMAE_DEVICE", l);
    }

    fn load_dir(&mut self, l: &logger::Logger) {
        self.dir = self.load_("AMAE_MOUNT_DIR", l);
    }

    fn load_script(&mut self, l: &logger::Logger) {
        self.script = self.load_("AMAE_SCRIPT", l);
    }

    fn load_label(&mut self, l: &logger::Logger) {
        self.label = self.load_("AMAE_LABEL", l);
    }

    fn load_(&self, name: &str, l: &logger::Logger) -> String {
        let cname = CString::new(name).unwrap();
        let cname_ptr = cname.as_ptr();
        unsafe {
            let out = getenv(cname_ptr);
            if out.is_null() { self.error_(name, l); }
            let cstring = CString::from_raw(out);
            let res = cstring.into_string();
            match res {
                Ok(v)  => return v,
                Err(e) => {
                    let mut ss = self.ef(name);
                    ss += " ";
                    ss += &(format!("{}", e));
                    self.error__(ss, l);
                    return "".to_string();
                }
            }
        }
    }

    fn error_(&self, name: &str, l: &logger::Logger) {
        self.error__(self.ef(name), l);
    }

    fn ef(&self, name: &str) -> String {
        let em = "Can't get env: ".to_string() +
            name + "!";
        return em;
    }

    fn error__(&self, s: String, l: &logger::Logger) {
        l.error(s.as_str());
        panic!(s);
    }
}
/*
#[test]
fn hello() {
    let x = Err("test");
    assert_eq!("test", x.unwrap());
}
 */
<|endoftext|>


<commit_before>use std::fmt::{self, Display};

pub(crate) fn display(fmt: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl Display {
    DisplayInvoke(fmt)
}

struct DisplayInvoke<T>(T);

impl<T> Display for DisplayInvoke<T>
where
    T: Fn(&mut fmt::Formatter) -> fmt::Result,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        (self.0)(formatter)
    }
}
<commit_msg>Remove spurious use of libstd from type name formatter<commit_after>use core::fmt::{self, Display};

pub(crate) fn display(fmt: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl Display {
    DisplayInvoke(fmt)
}

struct DisplayInvoke<T>(T);

impl<T> Display for DisplayInvoke<T>
where
    T: Fn(&mut fmt::Formatter) -> fmt::Result,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        (self.0)(formatter)
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use semver::Version;
use std::env;
use git2::{self, Repository, Commit, Signature, PushOptions, RemoteCallbacks, Cred};

use commit_analyzer::{self, CommitType};
use error::Error;
use config::Config;

pub fn get_signature(repo: &Repository) -> Result<Signature, Error> {
    let author = {
        let mut author = env::var("GIT_COMMITTER_NAME").map_err(Error::from);

        if author.is_err() {
            let config = try!(repo.config());
            author = config.get_string("user.name").map_err(Error::from);
        }
        try!(author)
    };

    let email = {
        let mut email = env::var("GIT_COMMITTER_EMAIL").map_err(Error::from);

        if email.is_err() {
            let config = try!(repo.config());
            email = config.get_string("user.email").map_err(Error::from);
        }
        try!(email)
    };

    Signature::now(&author, &email).map_err(From::from)
}

fn range_to_head(commit: &str) -> String {
    format!("{}..HEAD", commit)
}

fn format_commit(commit: Commit) -> String {
    format!("{}\n{}", commit.id(), commit.message().unwrap_or(""))
}

fn add<P: AsRef<Path>>(repo: &Repository, files: &[P]) -> Result<(), git2::Error> {
    let mut index = try!(repo.index());

    for path in files {
        try!(index.add_path(path.as_ref()));
    }

    index.write()
}

fn commit(config: &Config, message: &str) -> Result<(), git2::Error> {
    let update_ref = format!("refs/heads/{}", config.branch);
    let repo = &config.repository;

    let oid = try!(repo.refname_to_id("HEAD"));
    let parent_commit = try!(repo.find_commit(oid));
    let parents = vec![&parent_commit];

    let mut index = try!(repo.index());
    let tree_oid = try!(index.write_tree());
    let tree = try!(repo.find_tree(tree_oid));

    repo
        .commit(Some(&update_ref), &config.signature, &config.signature, message, &tree, &parents)
        .map(|_| ())
}

fn create_tag(config: &Config, tag_name: &str, message: &str) -> Result<(), git2::Error> {
    let repo = &config.repository;

    let rev = format!("refs/heads/{}", config.branch);
    let obj = try!(repo.revparse_single(&rev));

    repo.tag(tag_name, &obj, &config.signature, message, false)
        .map(|_| ())
}

pub fn latest_tag(repo: &Repository) -> Option<Version> {
    let tags = match repo.tag_names(None) {
        Ok(tags) => tags,
        Err(_) => return None
    };

    tags.iter()
        .map(|tag| tag.unwrap())
        .filter_map(|tag| Version::parse(&tag[1..]).ok())
        .max()
}

pub fn version_bump_since_latest(repo: &Repository) -> CommitType {
    match latest_tag(repo) {
        Some(t) => {
            let tag = format!("v{}", t.to_string());
            version_bump_since_tag(repo, &tag)
        },
        None => CommitType::Major
    }
}

pub fn version_bump_since_tag(repo: &Repository, tag: &str) -> CommitType {
    let tag = range_to_head(tag);

    let mut walker = repo.revwalk().expect("Creating a revwalk failed");
    walker.push_range(&tag).expect("Adding a range failed");

    walker.map(|c| repo.find_commit(c.expect("Not a valid commit")).expect("No commit found"))
        .map(format_commit)
        .map(|c| commit_analyzer::analyze_single(&c).expect("Analyzing commit failed"))
        .max().unwrap_or(CommitType::Unknown)
}

pub fn generate_commit_message(new_version: &str) -> String {
    format!("Bump version to {}", new_version).into()
}

pub fn commit_files(config: &Config, new_version: &str) -> Result<(), Error> {
    let repo = &config.repository;
    let files = ["Cargo.toml", "Cargo.lock", "Changelog.md"];
    let files = files.iter().filter(|filename| {
        let path = Path::new(filename);
        !repo.status_should_ignore(path).expect("Determining ignore status of file failed")
    }).collect::<Vec<_>>();

    try!(add(&config.repository, &files[..]));

    commit(config, &generate_commit_message(new_version)).map_err(Error::from)
}

pub fn tag(config: &Config, tag_name: &str, tag_message: &str) -> Result<(), Error> {
    create_tag(config, &tag_name, &tag_message)
        .map_err(Error::from)
}

pub fn push(config: &Config, tag_name: &str) -> Result<(), Error> {
    let repo      = &config.repository;

    let branch    = &config.branch;
    let token     = config.gh_token.as_ref();
    let email     = config.signature.email().unwrap();

    // We need to push both the branch we just committed as well as the tag we created.
    let branch_ref = format!("refs/heads/{}", branch);
    let tag_ref    = format!("refs/tags/{}", tag_name);
    let refs = [&branch_ref[..], &tag_ref[..]];

    let mut remote = try!(repo.find_remote("origin"));
    let mut cbs = RemoteCallbacks::new();
    let mut opts = PushOptions::new();

    if config.gh_token.as_ref().is_some() {
        cbs.credentials(|_url, _username, _allowed| {
            Cred::userpass_plaintext(&token.unwrap(), "")
        });
        opts.remote_callbacks(cbs);
    } else {
        cbs.credentials(|_url, _username, _allowed| {
            Cred::ssh_key_from_agent(&email)
        });
        opts.remote_callbacks(cbs);
    }

    remote
        .push(&refs, Some(&mut opts))
        .map(|_| ())
        .map_err(Error::from)
}
<commit_msg>feat: use callback username to fetch ssh key<commit_after>use std::path::Path;
use semver::Version;
use std::env;
use git2::{self, Repository, Commit, Signature, PushOptions, RemoteCallbacks, Cred};

use commit_analyzer::{self, CommitType};
use error::Error;
use config::Config;

pub fn get_signature(repo: &Repository) -> Result<Signature, Error> {
    let author = {
        let mut author = env::var("GIT_COMMITTER_NAME").map_err(Error::from);

        if author.is_err() {
            let config = try!(repo.config());
            author = config.get_string("user.name").map_err(Error::from);
        }
        try!(author)
    };

    let email = {
        let mut email = env::var("GIT_COMMITTER_EMAIL").map_err(Error::from);

        if email.is_err() {
            let config = try!(repo.config());
            email = config.get_string("user.email").map_err(Error::from);
        }
        try!(email)
    };

    Signature::now(&author, &email).map_err(From::from)
}

fn range_to_head(commit: &str) -> String {
    format!("{}..HEAD", commit)
}

fn format_commit(commit: Commit) -> String {
    format!("{}\n{}", commit.id(), commit.message().unwrap_or(""))
}

fn add<P: AsRef<Path>>(repo: &Repository, files: &[P]) -> Result<(), git2::Error> {
    let mut index = try!(repo.index());

    for path in files {
        try!(index.add_path(path.as_ref()));
    }

    index.write()
}

fn commit(config: &Config, message: &str) -> Result<(), git2::Error> {
    let update_ref = format!("refs/heads/{}", config.branch);
    let repo = &config.repository;

    let oid = try!(repo.refname_to_id("HEAD"));
    let parent_commit = try!(repo.find_commit(oid));
    let parents = vec![&parent_commit];

    let mut index = try!(repo.index());
    let tree_oid = try!(index.write_tree());
    let tree = try!(repo.find_tree(tree_oid));

    repo
        .commit(Some(&update_ref), &config.signature, &config.signature, message, &tree, &parents)
        .map(|_| ())
}

fn create_tag(config: &Config, tag_name: &str, message: &str) -> Result<(), git2::Error> {
    let repo = &config.repository;

    let rev = format!("refs/heads/{}", config.branch);
    let obj = try!(repo.revparse_single(&rev));

    repo.tag(tag_name, &obj, &config.signature, message, false)
        .map(|_| ())
}

pub fn latest_tag(repo: &Repository) -> Option<Version> {
    let tags = match repo.tag_names(None) {
        Ok(tags) => tags,
        Err(_) => return None
    };

    tags.iter()
        .map(|tag| tag.unwrap())
        .filter_map(|tag| Version::parse(&tag[1..]).ok())
        .max()
}

pub fn version_bump_since_latest(repo: &Repository) -> CommitType {
    match latest_tag(repo) {
        Some(t) => {
            let tag = format!("v{}", t.to_string());
            version_bump_since_tag(repo, &tag)
        },
        None => CommitType::Major
    }
}

pub fn version_bump_since_tag(repo: &Repository, tag: &str) -> CommitType {
    let tag = range_to_head(tag);

    let mut walker = repo.revwalk().expect("Creating a revwalk failed");
    walker.push_range(&tag).expect("Adding a range failed");

    walker.map(|c| repo.find_commit(c.expect("Not a valid commit")).expect("No commit found"))
        .map(format_commit)
        .map(|c| commit_analyzer::analyze_single(&c).expect("Analyzing commit failed"))
        .max().unwrap_or(CommitType::Unknown)
}

pub fn generate_commit_message(new_version: &str) -> String {
    format!("Bump version to {}", new_version).into()
}

pub fn commit_files(config: &Config, new_version: &str) -> Result<(), Error> {
    let repo = &config.repository;
    let files = ["Cargo.toml", "Cargo.lock", "Changelog.md"];
    let files = files.iter().filter(|filename| {
        let path = Path::new(filename);
        !repo.status_should_ignore(path).expect("Determining ignore status of file failed")
    }).collect::<Vec<_>>();

    try!(add(&config.repository, &files[..]));

    commit(config, &generate_commit_message(new_version)).map_err(Error::from)
}

pub fn tag(config: &Config, tag_name: &str, tag_message: &str) -> Result<(), Error> {
    create_tag(config, &tag_name, &tag_message)
        .map_err(Error::from)
}

pub fn push(config: &Config, tag_name: &str) -> Result<(), Error> {
    let repo      = &config.repository;

    let branch    = &config.branch;
    let token     = config.gh_token.as_ref();

    // We need to push both the branch we just committed as well as the tag we created.
    let branch_ref = format!("refs/heads/{}", branch);
    let tag_ref    = format!("refs/tags/{}", tag_name);
    let refs = [&branch_ref[..], &tag_ref[..]];

    let mut remote = try!(repo.find_remote("origin"));
    let mut cbs = RemoteCallbacks::new();
    let mut opts = PushOptions::new();

    if config.gh_token.as_ref().is_some() {
        cbs.credentials(|_url, _username, _allowed| {
            Cred::userpass_plaintext(&token.unwrap(), "")
        });
        opts.remote_callbacks(cbs);
    } else {
        cbs.credentials(|_url, username, _allowed| {
            Cred::ssh_key_from_agent(&username.unwrap())
        });
        opts.remote_callbacks(cbs);
    }

    remote
        .push(&refs, Some(&mut opts))
        .map(|_| ())
        .map_err(Error::from)
}
<|endoftext|>