<commit_before>#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "clippy", allow(used_underscore_binding))]
#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]

// The `quote!` macro requires deep recursion.
#![recursion_limit = "192"]

extern crate serde_codegen_internals as internals;

#[cfg(feature = "with-syntex")]
extern crate syntex;

#[cfg(feature = "with-syntex")]
#[macro_use]
extern crate syntex_syntax as syntax;

#[cfg(not(feature = "with-syntex"))]
#[macro_use]
extern crate syntax;

#[cfg(not(feature = "with-syntex"))]
extern crate rustc_plugin;

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

#[cfg(feature = "with-syntex")]
use std::path::Path;

#[cfg(not(feature = "with-syntex"))]
use syntax::feature_gate::AttributeType;

mod bound;
mod de;
mod ser;

#[cfg(feature = "with-syntex")]
fn syntex_registry() -> syntex::Registry {
    use syntax::{ast, fold};

    /// Strip the serde attributes from the crate.
    #[cfg(feature = "with-syntex")]
    fn strip_attributes(krate: ast::Crate) -> ast::Crate {
        /// Helper folder that strips the serde attributes after the extensions have been expanded.
        struct StripAttributeFolder;

        impl fold::Folder for StripAttributeFolder {
            fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
                match attr.node.value.node {
                    ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
                    _ => {}
                }

                Some(attr)
            }

            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
                fold::noop_fold_mac(mac, self)
            }
        }

        fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
    }

    let mut reg = syntex::Registry::new();

    reg.add_attr("feature(custom_derive)");
    reg.add_attr("feature(custom_attribute)");

    reg.add_decorator("derive_Serialize", shim::expand_derive_serialize);
    reg.add_decorator("derive_Deserialize", shim::expand_derive_deserialize);

    reg.add_post_expansion_pass(strip_attributes);

    reg
}

#[cfg(feature = "with-syntex")]
pub fn expand_str(src: &str) -> Result<String, syntex::Error> {
    let src = src.to_owned();

    let expand_thread = move || {
        syntex_registry().expand_str("", "", &src)
    };

    syntex::with_extra_stack(expand_thread)
}

#[cfg(feature = "with-syntex")]
pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
    where S: AsRef<Path>,
          D: AsRef<Path>,
{
    let src = src.as_ref().to_owned();
    let dst = dst.as_ref().to_owned();

    let expand_thread = move || {
        syntex_registry().expand("", src, dst)
    };

    syntex::with_extra_stack(expand_thread)
}

#[cfg(not(feature = "with-syntex"))]
pub fn register(reg: &mut rustc_plugin::Registry) {
    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Serialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(shim::expand_derive_serialize)));

    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_Deserialize"),
        syntax::ext::base::MultiDecorator(
            Box::new(shim::expand_derive_deserialize)));

    reg.register_attribute("serde".to_owned(), AttributeType::Normal);
}

macro_rules! shim {
    ($name:ident $pkg:ident :: $func:ident) => {
        pub fn $func(
            cx: &mut ::syntax::ext::base::ExtCtxt,
            span: ::syntax::codemap::Span,
            meta_item: &::syntax::ast::MetaItem,
            annotatable: &::syntax::ext::base::Annotatable,
            push: &mut FnMut(::syntax::ext::base::Annotatable)
        ) {
            let item = match *annotatable {
                ::syntax::ext::base::Annotatable::Item(ref item) => item,
                _ => {
                    cx.span_err(
                        meta_item.span,
                        concat!("`#[derive(",
                                stringify!($name),
                                ")]` may only be applied to structs and enums"));
                    return;
                }
            };

            use syntax::{attr, ast, visit};
            struct MarkSerdeAttributesUsed;
            impl visit::Visitor for MarkSerdeAttributesUsed {
                fn visit_attribute(&mut self, attr: &ast::Attribute) {
                    match attr.node.value.node {
                        ast::MetaItemKind::List(ref name, _) if name == "serde" => {
                            attr::mark_used(attr);
                        }
                        _ => {}
                    }
                }
            }
            visit::walk_item(&mut MarkSerdeAttributesUsed, item);

            use syntax::print::pprust;
            let s = pprust::item_to_string(item);

            use {syn, $pkg};
            let syn_item = syn::parse_macro_input(&s).unwrap();
            let expanded = match $pkg::$func(&syn_item) {
                Ok(expanded) => expanded.to_string(),
                Err(msg) => {
                    cx.span_err(span, &msg);
                    return;
                }
            };

            use syntax::parse;
            let name = stringify!($name).to_string();
            let sess = cx.parse_sess;
            let impl_item = parse::parse_item_from_source_str(name, expanded, sess);
            push(::syntax::ext::base::Annotatable::Item(impl_item.unwrap().unwrap()));
        }
    };
}

mod shim {
    shim!(Serialize ser::expand_derive_serialize);
    shim!(Deserialize de::expand_derive_deserialize);
}

#[cfg(feature = "with-syn")]
#[doc(hidden)]
/// Not public API. Use the serde_derive crate.
pub fn expand_derive_serialize(item: &str) -> Result<String, String> {
    let syn_item = syn::parse_macro_input(item).unwrap();
    ser::expand_derive_serialize(&syn_item).map(|derive| derive.to_string())
}

#[cfg(feature = "with-syn")]
#[doc(hidden)]
/// Not public API. Use the serde_derive crate.
pub fn expand_derive_deserialize(item: &str) -> Result<String, String> {
    let syn_item = syn::parse_macro_input(item).unwrap();
    de::expand_derive_deserialize(&syn_item).map(|derive| derive.to_string())
}
<commit_msg>Drop libsyntax<commit_after>#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "clippy", allow(used_underscore_binding))]

// The `quote!` macro requires deep recursion.
#![recursion_limit = "192"]

extern crate serde_codegen_internals as internals;

#[cfg(feature = "with-syntex")]
extern crate syntex;

#[cfg(feature = "with-syntex")]
#[macro_use]
extern crate syntex_syntax as syntax;

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

#[cfg(feature = "with-syntex")]
use std::path::Path;

mod bound;
mod de;
mod ser;

#[cfg(feature = "with-syntex")]
fn syntex_registry() -> syntex::Registry {
    use syntax::{ast, fold};

    /// Strip the serde attributes from the crate.
    #[cfg(feature = "with-syntex")]
    fn strip_attributes(krate: ast::Crate) -> ast::Crate {
        /// Helper folder that strips the serde attributes after the extensions have been expanded.
        struct StripAttributeFolder;

        impl fold::Folder for StripAttributeFolder {
            fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
                match attr.node.value.node {
                    ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
                    _ => {}
                }

                Some(attr)
            }

            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
                fold::noop_fold_mac(mac, self)
            }
        }

        fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
    }

    let mut reg = syntex::Registry::new();

    reg.add_attr("feature(custom_derive)");
    reg.add_attr("feature(custom_attribute)");

    reg.add_decorator("derive_Serialize", shim::expand_derive_serialize);
    reg.add_decorator("derive_Deserialize", shim::expand_derive_deserialize);

    reg.add_post_expansion_pass(strip_attributes);

    reg
}

#[cfg(feature = "with-syntex")]
pub fn expand_str(src: &str) -> Result<String, syntex::Error> {
    let src = src.to_owned();

    let expand_thread = move || {
        syntex_registry().expand_str("", "", &src)
    };

    syntex::with_extra_stack(expand_thread)
}

#[cfg(feature = "with-syntex")]
pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
    where S: AsRef<Path>,
          D: AsRef<Path>,
{
    let src = src.as_ref().to_owned();
    let dst = dst.as_ref().to_owned();

    let expand_thread = move || {
        syntex_registry().expand("", src, dst)
    };

    syntex::with_extra_stack(expand_thread)
}

macro_rules! shim {
    ($name:ident $pkg:ident :: $func:ident) => {
        pub fn $func(
            cx: &mut ::syntax::ext::base::ExtCtxt,
            span: ::syntax::codemap::Span,
            meta_item: &::syntax::ast::MetaItem,
            annotatable: &::syntax::ext::base::Annotatable,
            push: &mut FnMut(::syntax::ext::base::Annotatable)
        ) {
            let item = match *annotatable {
                ::syntax::ext::base::Annotatable::Item(ref item) => item,
                _ => {
                    cx.span_err(
                        meta_item.span,
                        concat!("`#[derive(",
                                stringify!($name),
                                ")]` may only be applied to structs and enums"));
                    return;
                }
            };

            use syntax::{attr, ast, visit};
            struct MarkSerdeAttributesUsed;
            impl visit::Visitor for MarkSerdeAttributesUsed {
                fn visit_attribute(&mut self, attr: &ast::Attribute) {
                    match attr.node.value.node {
                        ast::MetaItemKind::List(ref name, _) if name == "serde" => {
                            attr::mark_used(attr);
                        }
                        _ => {}
                    }
                }
            }
            visit::walk_item(&mut MarkSerdeAttributesUsed, item);

            use syntax::print::pprust;
            let s = pprust::item_to_string(item);

            use {syn, $pkg};
            let syn_item = syn::parse_macro_input(&s).unwrap();
            let expanded = match $pkg::$func(&syn_item) {
                Ok(expanded) => expanded.to_string(),
                Err(msg) => {
                    cx.span_err(span, &msg);
                    return;
                }
            };

            use syntax::parse;
            let name = stringify!($name).to_string();
            let sess = cx.parse_sess;
            let impl_item = parse::parse_item_from_source_str(name, expanded, sess);
            push(::syntax::ext::base::Annotatable::Item(impl_item.unwrap().unwrap()));
        }
    };
}

#[cfg(feature = "with-syntex")]
mod shim {
    shim!(Serialize ser::expand_derive_serialize);
    shim!(Deserialize de::expand_derive_deserialize);
}

#[cfg(feature = "with-syn")]
#[doc(hidden)]
/// Not public API. Use the serde_derive crate.
pub fn expand_derive_serialize(item: &str) -> Result<String, String> {
    let syn_item = syn::parse_macro_input(item).unwrap();
    ser::expand_derive_serialize(&syn_item).map(|derive| derive.to_string())
}

#[cfg(feature = "with-syn")]
#[doc(hidden)]
/// Not public API. Use the serde_derive crate.
pub fn expand_derive_deserialize(item: &str) -> Result<String, String> {
    let syn_item = syn::parse_macro_input(item).unwrap();
    de::expand_derive_deserialize(&syn_item).map(|derive| derive.to_string())
}
<|endoftext|>


<commit_before>/// Define a type that supports parsing and printing a multi-character symbol
/// as if it were a token.
///
/// # Usage
///
/// As a convention, it is recommended that this macro be invoked within a
/// module called `punct` or `punctuation` and that the resulting parser be invoked
/// with a `punct::` or `punctuation::` prefix.
///
/// ```edition2018
/// mod punct {
///     syn::custom_punctuation!(LeftRightArrow, <=>);
/// }
/// ```
///
/// The generated syntax tree node supports the following operations just like
/// any built-in punctuation token.
///
/// - [Peeking] — `input.peek(punct::LeftRightArrow)`
///
/// - [Parsing] — `input.parse::<punct::LeftRightArrow>()?`
///
/// - [Printing] — `quote!( ... #left_right_arrow ... )`
///
/// - Construction from a [`Span`] — `let left_right_arrow = punct::LeftRightArrow(sp)`
///
/// - Construction from multiple [`Span`] — `let left_right_arrow = punct::LeftRightArrow([sp, sp, sp])`
///
/// - Field access to its spans — `let spans = left_right_arrow.spans`
///
/// [Peeking]: parse/struct.ParseBuffer.html#method.peek
/// [Parsing]: parse/struct.ParseBuffer.html#method.parse
/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
/// [`Span`]: struct.Span.html
///
/// # Example
///
/// ```edition2018
/// use syn::{Expr, ExprParen, parenthesized};
/// use syn::punctuated::Punctuated;
/// use syn::parse::{Parse, ParseStream, Result};
/// use syn::token::Paren;
///
/// mod punct {
///     syn::custom_punctuation!(PathSeparator, </>);
/// }
///
/// // (expr) </> (expr) </> (expr) ...
/// struct PathSegments {
///     segments: Punctuated<Expr, punct::PathSeparator>,
/// }
///
/// impl Parse for PathSegments {
///     fn parse(input: ParseStream) -> Result<Self> {
///         let mut segments = Punctuated::new();
///
///         let la = input.lookahead1();
///         if la.peek(Paren) {
///             let content;
///             let paren_token = parenthesized!(content in input);
///             let expr = Box::new(content.parse()?);
///             segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
///         } else {
///             return Err(la.error());
///         }
///
///         while input.peek(punct::PathSeparator) {
///             segments.push_punct(input.parse()?);
///             let content;
///             let paren_token = parenthesized!(content in input);
///             let expr = Box::new(content.parse()?);
///             segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
///         }
///
///         Ok(PathSegments { segments })
///     }
/// }
///
/// let _: PathSegments = syn::parse_str(r#"("five") </> ("hundred")"#).unwrap();
/// ```
///
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        pub struct $ident {
            pub spans: [$crate::export::Span; punct_len!(lenient, $($tt)+)],
        }

        #[doc(hidden)]
        #[allow(non_snake_case)]
        pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; punct_len!(lenient, $($tt)+)]>>(
            spans: __S,
        ) -> $ident {
            let _punct_len = punct_len!(strict, $($tt)+);
            $ident {
                spans: $crate::export::IntoSpans::into_spans(spans)
            }
        }

        impl $crate::export::Default for $ident {
            fn default() -> Self {
                $ident($crate::export::Span::call_site())
            }
        }

        impl_parse_for_custom_punctuation!($ident, $($tt)+);
        impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
        impl_clone_for_custom_punctuation!($ident, $($tt)+);
        impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
    };
}

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::token::CustomToken for $ident {
            fn peek(cursor: $crate::buffer::Cursor) -> bool {
                $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+))
            }

            fn display() -> &'static $crate::export::str {
                my_concat!("`", stringify_punct!($($tt)+), "`")
            }
        }

        impl $crate::parse::Parse for $ident {
            fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
                let spans: [$crate::export::Span; punct_len!(lenient, $($tt)+)] =
                    $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?;
                Ok($ident(spans))
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "parsing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "printing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::ToTokens for $ident {
            fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
                $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens)
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "printing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "clone-impls")]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Copy for $ident {}

        impl $crate::export::Clone for $ident {
            fn clone(&self) -> Self {
                *self
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "clone-impls"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "extra-traits")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Debug for $ident {
            fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
                $crate::export::Formatter::write_str(f, stringify_punct!($($tt)+))
            }
        }

        impl $crate::export::Eq for $ident {}

        impl $crate::export::PartialEq for $ident {
            fn eq(&self, _other: &Self) -> $crate::export::bool {
                true
            }
        }

        impl $crate::export::Hash for $ident {
            fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
        }
    };
}

// Not public API.
#[cfg(not(feature = "extra-traits"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! punct_len {
    ($mode:ident, +)     => { 1 };
    ($mode:ident, +=)    => { 2 };
    ($mode:ident, &)     => { 1 };
    ($mode:ident, &&)    => { 2 };
    ($mode:ident, &=)    => { 2 };
    ($mode:ident, @)     => { 1 };
    ($mode:ident, !)     => { 1 };
    ($mode:ident, ^)     => { 1 };
    ($mode:ident, ^=)    => { 2 };
    ($mode:ident, :)     => { 1 };
    ($mode:ident, ::)    => { 2 };
    ($mode:ident, ,)     => { 1 };
    ($mode:ident, /)     => { 1 };
    ($mode:ident, /=)    => { 2 };
    ($mode:ident, .)     => { 1 };
    ($mode:ident, ..)    => { 2 };
    ($mode:ident, ...)   => { 3 };
    ($mode:ident, ..=)   => { 3 };
    ($mode:ident, =)     => { 1 };
    ($mode:ident, ==)    => { 2 };
    ($mode:ident, >=)    => { 2 };
    ($mode:ident, >)     => { 1 };
    ($mode:ident, <=)    => { 2 };
    ($mode:ident, <)     => { 1 };
    ($mode:ident, *=)    => { 2 };
    ($mode:ident, !=)    => { 2 };
    ($mode:ident, |)     => { 1 };
    ($mode:ident, |=)    => { 2 };
    ($mode:ident, ||)    => { 2 };
    ($mode:ident, #)     => { 1 };
    ($mode:ident, ?)     => { 1 };
    ($mode:ident, ->)    => { 2 };
    ($mode:ident, <-)    => { 2 };
    ($mode:ident, %)     => { 1 };
    ($mode:ident, %=)    => { 2 };
    ($mode:ident, =>)    => { 2 };
    ($mode:ident, ;)     => { 1 };
    ($mode:ident, <<)    => { 2 };
    ($mode:ident, <<=)   => { 3 };
    ($mode:ident, >>)    => { 2 };
    ($mode:ident, >>=)   => { 3 };
    ($mode:ident, *)     => { 1 };
    ($mode:ident, -)     => { 1 };
    ($mode:ident, -=)    => { 2 };
    ($mode:ident, ~)     => { 1 };
    (lenient, $tt:tt)    => { 0 };
    (strict, $tt:tt)     => {{ unexpected!($tt); 0 }};
    ($mode:ident, $head:tt $($tail:tt)+) => {
        punct_len!($mode, $head) $(+ punct_len!($mode, $tail))+
    };
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! unexpected {
    () => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! stringify_punct {
    ($($tt:tt)+) => {
        concat!($(stringify!($tt)),+)
    };
}

// Not public API.
// Without this, local_inner_macros breaks when looking for concat!
#[doc(hidden)]
#[macro_export]
macro_rules! my_concat {
    ($($tt:tt)*) => {
        concat!($($tt)*)
    };
}
<commit_msg>Factor out custom_punctuation array type<commit_after>/// Define a type that supports parsing and printing a multi-character symbol
/// as if it were a token.
///
/// # Usage
///
/// As a convention, it is recommended that this macro be invoked within a
/// module called `punct` or `punctuation` and that the resulting parser be invoked
/// with a `punct::` or `punctuation::` prefix.
///
/// ```edition2018
/// mod punct {
///     syn::custom_punctuation!(LeftRightArrow, <=>);
/// }
/// ```
///
/// The generated syntax tree node supports the following operations just like
/// any built-in punctuation token.
///
/// - [Peeking] — `input.peek(punct::LeftRightArrow)`
///
/// - [Parsing] — `input.parse::<punct::LeftRightArrow>()?`
///
/// - [Printing] — `quote!( ... #left_right_arrow ... )`
///
/// - Construction from a [`Span`] — `let left_right_arrow = punct::LeftRightArrow(sp)`
///
/// - Construction from multiple [`Span`] — `let left_right_arrow = punct::LeftRightArrow([sp, sp, sp])`
///
/// - Field access to its spans — `let spans = left_right_arrow.spans`
///
/// [Peeking]: parse/struct.ParseBuffer.html#method.peek
/// [Parsing]: parse/struct.ParseBuffer.html#method.parse
/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
/// [`Span`]: struct.Span.html
///
/// # Example
///
/// ```edition2018
/// use syn::{Expr, ExprParen, parenthesized};
/// use syn::punctuated::Punctuated;
/// use syn::parse::{Parse, ParseStream, Result};
/// use syn::token::Paren;
///
/// mod punct {
///     syn::custom_punctuation!(PathSeparator, </>);
/// }
///
/// // (expr) </> (expr) </> (expr) ...
/// struct PathSegments {
///     segments: Punctuated<Expr, punct::PathSeparator>,
/// }
///
/// impl Parse for PathSegments {
///     fn parse(input: ParseStream) -> Result<Self> {
///         let mut segments = Punctuated::new();
///
///         let la = input.lookahead1();
///         if la.peek(Paren) {
///             let content;
///             let paren_token = parenthesized!(content in input);
///             let expr = Box::new(content.parse()?);
///             segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
///         } else {
///             return Err(la.error());
///         }
///
///         while input.peek(punct::PathSeparator) {
///             segments.push_punct(input.parse()?);
///             let content;
///             let paren_token = parenthesized!(content in input);
///             let expr = Box::new(content.parse()?);
///             segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
///         }
///
///         Ok(PathSegments { segments })
///     }
/// }
///
/// let _: PathSegments = syn::parse_str(r#"("five") </> ("hundred")"#).unwrap();
/// ```
///
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        pub struct $ident {
            pub spans: custom_punctuation_repr!($($tt)+),
        }

        #[doc(hidden)]
        #[allow(non_snake_case)]
        pub fn $ident<__S: $crate::export::IntoSpans<custom_punctuation_repr!($($tt)+)>>(
            spans: __S,
        ) -> $ident {
            let _validate_len = 0 $(+ custom_punctuation_len!(strict, $tt))*;
            $ident {
                spans: $crate::export::IntoSpans::into_spans(spans)
            }
        }

        impl $crate::export::Default for $ident {
            fn default() -> Self {
                $ident($crate::export::Span::call_site())
            }
        }

        impl_parse_for_custom_punctuation!($ident, $($tt)+);
        impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
        impl_clone_for_custom_punctuation!($ident, $($tt)+);
        impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
    };
}

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::token::CustomToken for $ident {
            fn peek(cursor: $crate::buffer::Cursor) -> bool {
                $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+))
            }

            fn display() -> &'static $crate::export::str {
                my_concat!("`", stringify_punct!($($tt)+), "`")
            }
        }

        impl $crate::parse::Parse for $ident {
            fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
                let spans: custom_punctuation_repr!($($tt)+) =
                    $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?;
                Ok($ident(spans))
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "parsing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "printing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::ToTokens for $ident {
            fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
                $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens)
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "printing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "clone-impls")]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Copy for $ident {}

        impl $crate::export::Clone for $ident {
            fn clone(&self) -> Self {
                *self
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "clone-impls"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "extra-traits")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Debug for $ident {
            fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
                $crate::export::Formatter::write_str(f, stringify_punct!($($tt)+))
            }
        }

        impl $crate::export::Eq for $ident {}

        impl $crate::export::PartialEq for $ident {
            fn eq(&self, _other: &Self) -> $crate::export::bool {
                true
            }
        }

        impl $crate::export::Hash for $ident {
            fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
        }
    };
}

// Not public API.
#[cfg(not(feature = "extra-traits"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation_repr {
    ($($tt:tt)+) => {
        [$crate::export::Span; 0 $(+ custom_punctuation_len!(lenient, $tt))+]
    };
}

// Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation_len {
    ($mode:ident, +)     => { 1 };
    ($mode:ident, +=)    => { 2 };
    ($mode:ident, &)     => { 1 };
    ($mode:ident, &&)    => { 2 };
    ($mode:ident, &=)    => { 2 };
    ($mode:ident, @)     => { 1 };
    ($mode:ident, !)     => { 1 };
    ($mode:ident, ^)     => { 1 };
    ($mode:ident, ^=)    => { 2 };
    ($mode:ident, :)     => { 1 };
    ($mode:ident, ::)    => { 2 };
    ($mode:ident, ,)     => { 1 };
    ($mode:ident, /)     => { 1 };
    ($mode:ident, /=)    => { 2 };
    ($mode:ident, .)     => { 1 };
    ($mode:ident, ..)    => { 2 };
    ($mode:ident, ...)   => { 3 };
    ($mode:ident, ..=)   => { 3 };
    ($mode:ident, =)     => { 1 };
    ($mode:ident, ==)    => { 2 };
    ($mode:ident, >=)    => { 2 };
    ($mode:ident, >)     => { 1 };
    ($mode:ident, <=)    => { 2 };
    ($mode:ident, <)     => { 1 };
    ($mode:ident, *=)    => { 2 };
    ($mode:ident, !=)    => { 2 };
    ($mode:ident, |)     => { 1 };
    ($mode:ident, |=)    => { 2 };
    ($mode:ident, ||)    => { 2 };
    ($mode:ident, #)     => { 1 };
    ($mode:ident, ?)     => { 1 };
    ($mode:ident, ->)    => { 2 };
    ($mode:ident, <-)    => { 2 };
    ($mode:ident, %)     => { 1 };
    ($mode:ident, %=)    => { 2 };
    ($mode:ident, =>)    => { 2 };
    ($mode:ident, ;)     => { 1 };
    ($mode:ident, <<)    => { 2 };
    ($mode:ident, <<=)   => { 3 };
    ($mode:ident, >>)    => { 2 };
    ($mode:ident, >>=)   => { 3 };
    ($mode:ident, *)     => { 1 };
    ($mode:ident, -)     => { 1 };
    ($mode:ident, -=)    => { 2 };
    ($mode:ident, ~)     => { 1 };
    (lenient, $tt:tt)    => { 0 };
    (strict, $tt:tt)     => {{ unexpected!($tt); 0 }};
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! unexpected {
    () => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! stringify_punct {
    ($($tt:tt)+) => {
        concat!($(stringify!($tt)),+)
    };
}

// Not public API.
// Without this, local_inner_macros breaks when looking for concat!
#[doc(hidden)]
#[macro_export]
macro_rules! my_concat {
    ($($tt:tt)*) => {
        concat!($($tt)*)
    };
}
<|endoftext|>


<commit_before>// Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! punct_len {
    ($mode:ident, +)      => ( 1usize );
    ($mode:ident, +=)     => ( 2usize );
    ($mode:ident, &)      => ( 1usize );
    ($mode:ident, &&)     => ( 2usize );
    ($mode:ident, &=)     => ( 2usize );
    ($mode:ident, @)      => ( 1usize );
    ($mode:ident, !)      => ( 1usize );
    ($mode:ident, ^)      => ( 1usize );
    ($mode:ident, ^=)     => ( 2usize );
    ($mode:ident, :)      => ( 1usize );
    ($mode:ident, ::)     => ( 2usize );
    ($mode:ident, ,)      => ( 1usize );
    ($mode:ident, /)      => ( 1usize );
    ($mode:ident, /=)     => ( 2usize );
    ($mode:ident, .)      => ( 1usize );
    ($mode:ident, ..)     => ( 2usize );
    ($mode:ident, ...)    => ( 3usize );
    ($mode:ident, ..=)    => ( 3usize );
    ($mode:ident, =)      => ( 1usize );
    ($mode:ident, ==)     => ( 2usize );
    ($mode:ident, >=)     => ( 2usize );
    ($mode:ident, >)      => ( 1usize );
    ($mode:ident, <=)     => ( 2usize );
    ($mode:ident, <)      => ( 1usize );
    ($mode:ident, *=)     => ( 2usize );
    ($mode:ident, !=)     => ( 2usize );
    ($mode:ident, |)      => ( 1usize );
    ($mode:ident, |=)     => ( 2usize );
    ($mode:ident, ||)     => ( 2usize );
    ($mode:ident, #)      => ( 1usize );
    ($mode:ident, ?)      => ( 1usize );
    ($mode:ident, ->)     => ( 2usize );
    ($mode:ident, <-)     => ( 2usize );
    ($mode:ident, %)      => ( 1usize );
    ($mode:ident, %=)     => ( 2usize );
    ($mode:ident, =>)     => ( 2usize );
    ($mode:ident, ;)      => ( 1usize );
    ($mode:ident, <<)     => ( 2usize );
    ($mode:ident, <<=)    => ( 3usize );
    ($mode:ident, >>)     => ( 2usize );
    ($mode:ident, >>=)    => ( 3usize );
    ($mode:ident, *)      => ( 1usize );
    ($mode:ident, -)      => ( 1usize );
    ($mode:ident, -=)     => ( 2usize );
    ($mode:ident, ~)      => ( 1usize );
    (lenient, $tt:tt)     => ( 0usize );
    (strict, $tt:tt)      => ({ unexpected!($tt); 0usize });
    ($mode:ident, $head:tt $($tail:tt)+) => ( punct_len!($mode, $head) $(+ punct_len!($mode, $tail))+ );
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! unexpected {
    () => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! stringify_punct {
    ($($tt:tt)+) => ( concat!($(stringify!($tt)),+) );
}

// Not public API.
// Without this, local_inner_macros breaks when looking for concat!
#[doc(hidden)]
#[macro_export]
macro_rules! my_concat {
    ($($tt:tt)*) => ( concat!($($tt)*) );
}

/// Define a type that supports parsing and printing a multi-character symbol
/// as if it were a token.
///
/// # Usage
///
/// As a convention, it is recommended that this macro be invoked within a
/// module called `punct` or `punctuation` and that the resulting parser be invoked
/// with a `punct::` or `punctuation::` prefix.
///
/// ```edition2018
/// mod punct {
///     syn::custom_punctuation!(LeftRightArrow, <=>);
/// }
/// ```
///
/// The generated syntax tree node supports the following operations just like
/// any built-in punctuation token.
///
/// - [Peeking] — `input.peek(punct::LeftRightArrow)`
///
/// - [Parsing] — `input.parse::<punct::LeftRightArrow>()?`
///
/// - [Printing] — `quote!( ... #left_right_arrow ... )`
///
/// - Construction from a [`Span`] — `let left_right_arrow = punct::LeftRightArrow(sp)`
///
/// - Construction from multiple [`Span`] — `let left_right_arrow = punct::LeftRightArrow([sp, sp, sp])`
///
/// - Field access to its spans — `let spans = left_right_arrow.spans`
///
/// [Peeking]: parse/struct.ParseBuffer.html#method.peek
/// [Parsing]: parse/struct.ParseBuffer.html#method.parse
/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
/// [`Span`]: struct.Span.html
///
/// # Example
///
/// ```edition2018
/// use syn::{Expr, ExprParen, parenthesized};
/// use syn::punctuated::Punctuated;
/// use syn::parse::{Parse, ParseStream, Result};
/// use syn::token::Paren;
///
/// mod punct {
///     syn::custom_punctuation!(PathSeparator, </>);
/// }
///
/// // (expr) </> (expr) </> (expr) ...
/// struct PathSegments {
///     segments: Punctuated<Expr, punct::PathSeparator>,
/// }
///
/// impl Parse for PathSegments {
///     fn parse(input: ParseStream) -> Result<Self> {
///         let mut segments = Punctuated::new();
///
///         let la = input.lookahead1();
///         if la.peek(Paren) {
///             let content;
///             let paren_token = parenthesized!(content in input);
///             let expr = Box::new(content.parse()?);
///             segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
///         } else {
///             return Err(la.error());
///         }
///
///         while input.peek(punct::PathSeparator) {
///             segments.push_punct(input.parse()?);
///             let content;
///             let paren_token = parenthesized!(content in input);
///             let expr = Box::new(content.parse()?);
///             segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
///         }
///
///         Ok(PathSegments { segments })
///     }
/// }
///
/// let _: PathSegments = syn::parse_str(r#"("five") </> ("hundred")"#).unwrap();
/// ```
///
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        pub struct $ident {
            pub spans: [$crate::export::Span; punct_len!(lenient, $($tt)+)],
        }

        #[doc(hidden)]
        #[allow(non_snake_case)]
        pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; punct_len!(lenient, $($tt)+)]>>(
            spans: __S,
        ) -> $ident {
            let _punct_len = punct_len!(strict, $($tt)+);
            $ident {
                spans: $crate::export::IntoSpans::into_spans(spans)
            }
        }

        impl $crate::export::Default for $ident {
            fn default() -> Self {
                $ident($crate::export::Span::call_site())
            }
        }

        impl_parse_for_custom_punctuation!($ident, $($tt)+);
        impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
        impl_clone_for_custom_punctuation!($ident, $($tt)+);
        impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
    };
}

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident: ident, $($tt:tt)+) => {
        impl $crate::token::CustomToken for $ident {
            fn peek(cursor: $crate::buffer::Cursor) -> bool {
                $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+))
            }

            fn display() -> &'static $crate::export::str {
                my_concat!("`", stringify_punct!($($tt)+), "`")
            }
        }

        impl $crate::parse::Parse for $ident {
            fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
                let spans: [$crate::export::Span; punct_len!(lenient, $($tt)+)] =
                    $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?;
                Ok($ident(spans))
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "parsing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident: ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "printing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident: ident, $($tt:tt)+) => {
        impl $crate::export::ToTokens for $ident {
            fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
                $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens)
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "printing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident: ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "clone-impls")]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident: ident, $($tt:tt)+) => {
        impl $crate::export::Copy for $ident {}

        impl $crate::export::Clone for $ident {
            fn clone(&self) -> Self {
                *self
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "clone-impls"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident: ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "extra-traits")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident: ident, $($tt:tt)+) => {
        impl $crate::export::Debug for $ident {
            fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
                $crate::export::Formatter::write_str(f, stringify_punct!($($tt)+))
            }
        }

        impl $crate::export::Eq for $ident {}

        impl $crate::export::PartialEq for $ident {
            fn eq(&self, _other: &Self) -> $crate::export::bool {
                true
            }
        }

        impl $crate::export::Hash for $ident {
            fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
        }
    };
}

// Not public API.
#[cfg(not(feature = "extra-traits"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident: ident, $($tt:tt)+) => {};
}
<commit_msg>Formatting of helper macros in custom_puncutation<commit_after>// Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! punct_len {
    ($mode:ident, +)     => { 1 };
    ($mode:ident, +=)    => { 2 };
    ($mode:ident, &)     => { 1 };
    ($mode:ident, &&)    => { 2 };
    ($mode:ident, &=)    => { 2 };
    ($mode:ident, @)     => { 1 };
    ($mode:ident, !)     => { 1 };
    ($mode:ident, ^)     => { 1 };
    ($mode:ident, ^=)    => { 2 };
    ($mode:ident, :)     => { 1 };
    ($mode:ident, ::)    => { 2 };
    ($mode:ident, ,)     => { 1 };
    ($mode:ident, /)     => { 1 };
    ($mode:ident, /=)    => { 2 };
    ($mode:ident, .)     => { 1 };
    ($mode:ident, ..)    => { 2 };
    ($mode:ident, ...)   => { 3 };
    ($mode:ident, ..=)   => { 3 };
    ($mode:ident, =)     => { 1 };
    ($mode:ident, ==)    => { 2 };
    ($mode:ident, >=)    => { 2 };
    ($mode:ident, >)     => { 1 };
    ($mode:ident, <=)    => { 2 };
    ($mode:ident, <)     => { 1 };
    ($mode:ident, *=)    => { 2 };
    ($mode:ident, !=)    => { 2 };
    ($mode:ident, |)     => { 1 };
    ($mode:ident, |=)    => { 2 };
    ($mode:ident, ||)    => { 2 };
    ($mode:ident, #)     => { 1 };
    ($mode:ident, ?)     => { 1 };
    ($mode:ident, ->)    => { 2 };
    ($mode:ident, <-)    => { 2 };
    ($mode:ident, %)     => { 1 };
    ($mode:ident, %=)    => { 2 };
    ($mode:ident, =>)    => { 2 };
    ($mode:ident, ;)     => { 1 };
    ($mode:ident, <<)    => { 2 };
    ($mode:ident, <<=)   => { 3 };
    ($mode:ident, >>)    => { 2 };
    ($mode:ident, >>=)   => { 3 };
    ($mode:ident, *)     => { 1 };
    ($mode:ident, -)     => { 1 };
    ($mode:ident, -=)    => { 2 };
    ($mode:ident, ~)     => { 1 };
    (lenient, $tt:tt)    => { 0 };
    (strict, $tt:tt)     => {{ unexpected!($tt); 0 }};
    ($mode:ident, $head:tt $($tail:tt)+) => {
        punct_len!($mode, $head) $(+ punct_len!($mode, $tail))+
    };
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! unexpected {
    () => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! stringify_punct {
    ($($tt:tt)+) => {
        concat!($(stringify!($tt)),+)
    };
}

// Not public API.
// Without this, local_inner_macros breaks when looking for concat!
#[doc(hidden)]
#[macro_export]
macro_rules! my_concat {
    ($($tt:tt)*) => {
        concat!($($tt)*)
    };
}

/// Define a type that supports parsing and printing a multi-character symbol
/// as if it were a token.
///
/// # Usage
///
/// As a convention, it is recommended that this macro be invoked within a
/// module called `punct` or `punctuation` and that the resulting parser be invoked
/// with a `punct::` or `punctuation::` prefix.
///
/// ```edition2018
/// mod punct {
///     syn::custom_punctuation!(LeftRightArrow, <=>);
/// }
/// ```
///
/// The generated syntax tree node supports the following operations just like
/// any built-in punctuation token.
///
/// - [Peeking] — `input.peek(punct::LeftRightArrow)`
///
/// - [Parsing] — `input.parse::<punct::LeftRightArrow>()?`
///
/// - [Printing] — `quote!( ... #left_right_arrow ... )`
///
/// - Construction from a [`Span`] — `let left_right_arrow = punct::LeftRightArrow(sp)`
///
/// - Construction from multiple [`Span`] — `let left_right_arrow = punct::LeftRightArrow([sp, sp, sp])`
///
/// - Field access to its spans — `let spans = left_right_arrow.spans`
///
/// [Peeking]: parse/struct.ParseBuffer.html#method.peek
/// [Parsing]: parse/struct.ParseBuffer.html#method.parse
/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
/// [`Span`]: struct.Span.html
///
/// # Example
///
/// ```edition2018
/// use syn::{Expr, ExprParen, parenthesized};
/// use syn::punctuated::Punctuated;
/// use syn::parse::{Parse, ParseStream, Result};
/// use syn::token::Paren;
///
/// mod punct {
///     syn::custom_punctuation!(PathSeparator, </>);
/// }
///
/// // (expr) </> (expr) </> (expr) ...
/// struct PathSegments {
///     segments: Punctuated<Expr, punct::PathSeparator>,
/// }
///
/// impl Parse for PathSegments {
///     fn parse(input: ParseStream) -> Result<Self> {
///         let mut segments = Punctuated::new();
///
///         let la = input.lookahead1();
///         if la.peek(Paren) {
///             let content;
///             let paren_token = parenthesized!(content in input);
///             let expr = Box::new(content.parse()?);
///             segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
///         } else {
///             return Err(la.error());
///         }
///
///         while input.peek(punct::PathSeparator) {
///             segments.push_punct(input.parse()?);
///             let content;
///             let paren_token = parenthesized!(content in input);
///             let expr = Box::new(content.parse()?);
///             segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
///         }
///
///         Ok(PathSegments { segments })
///     }
/// }
///
/// let _: PathSegments = syn::parse_str(r#"("five") </> ("hundred")"#).unwrap();
/// ```
///
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        pub struct $ident {
            pub spans: [$crate::export::Span; punct_len!(lenient, $($tt)+)],
        }

        #[doc(hidden)]
        #[allow(non_snake_case)]
        pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; punct_len!(lenient, $($tt)+)]>>(
            spans: __S,
        ) -> $ident {
            let _punct_len = punct_len!(strict, $($tt)+);
            $ident {
                spans: $crate::export::IntoSpans::into_spans(spans)
            }
        }

        impl $crate::export::Default for $ident {
            fn default() -> Self {
                $ident($crate::export::Span::call_site())
            }
        }

        impl_parse_for_custom_punctuation!($ident, $($tt)+);
        impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
        impl_clone_for_custom_punctuation!($ident, $($tt)+);
        impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
    };
}

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::token::CustomToken for $ident {
            fn peek(cursor: $crate::buffer::Cursor) -> bool {
                $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+))
            }

            fn display() -> &'static $crate::export::str {
                my_concat!("`", stringify_punct!($($tt)+), "`")
            }
        }

        impl $crate::parse::Parse for $ident {
            fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
                let spans: [$crate::export::Span; punct_len!(lenient, $($tt)+)] =
                    $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?;
                Ok($ident(spans))
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "parsing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "printing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::ToTokens for $ident {
            fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
                $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens)
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "printing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "clone-impls")]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Copy for $ident {}

        impl $crate::export::Clone for $ident {
            fn clone(&self) -> Self {
                *self
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "clone-impls"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "extra-traits")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Debug for $ident {
            fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
                $crate::export::Formatter::write_str(f, stringify_punct!($($tt)+))
            }
        }

        impl $crate::export::Eq for $ident {}

        impl $crate::export::PartialEq for $ident {
            fn eq(&self, _other: &Self) -> $crate::export::bool {
                true
            }
        }

        impl $crate::export::Hash for $ident {
            fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
        }
    };
}

// Not public API.
#[cfg(not(feature = "extra-traits"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}
<|endoftext|>


<commit_before>use crypto::ed25519;
use openssl::hash::MessageDigest;
use openssl::pkey::PKey;
use openssl::rsa::{Rsa, Padding};
use openssl::sign::Verifier;
use ring::rand::SystemRandom;
use ring::signature::{RSAKeyPair, RSASigningState, RSA_PSS_SHA256};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::Error as SerdeError;
use serde_json as json;
use std::os::raw::c_int;
use std::str::{self, FromStr};
use std::sync::Arc;
use untrusted::Input;

use datatype::Error;

const RSA_PKCS1_PSS_PADDING: c_int = 6;

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Signature {
    pub keyid:  String,
    pub method: SignatureType,
    pub sig:    String,
}

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum SignatureType {
    Ed25519,
    RsaSsaPss,
}

impl<'de> Deserialize<'de> for SignatureType {
    fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
        if let json::Value::String(ref s) = Deserialize::deserialize(de)? {
            s.parse().map_err(|err| SerdeError::custom(format!("unknown SignatureType: {}", err)))
        } else {
            Err(SerdeError::custom("unknown SignatureType"))
        }
    }
}

impl Serialize for SignatureType {
    fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
        ser.serialize_str(match *self {
            SignatureType::Ed25519   => "ed25519",
            SignatureType::RsaSsaPss => "rsassa-pss"
        })
    }
}

impl FromStr for SignatureType {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "ed25519"    => Ok(SignatureType::Ed25519),
            "rsassa-pss" => Ok(SignatureType::RsaSsaPss),
            _ => Err(Error::TufSigType(s.to_string()))
        }
    }
}

impl SignatureType {
    pub fn sign_msg(&self, msg: &[u8], der_key: &[u8]) -> Result<Vec<u8>, Error> {
        match *self {
            SignatureType::Ed25519 => Ok(ed25519::signature(msg, der_key).as_ref().into()),

            SignatureType::RsaSsaPss => {
                let pair = RSAKeyPair::from_der(Input::from(der_key))?;
                let mut state = RSASigningState::new(Arc::new(pair))?;
                let mut sig = vec![0; state.key_pair().public_modulus_len()];
                state.sign(&RSA_PSS_SHA256, &SystemRandom::new(), msg, &mut sig)?;
                Ok(sig)
            }
        }
    }

    pub fn verify_msg(&self, msg: &[u8], der_key: &[u8], sig: &[u8]) -> bool {
        match *self {
            SignatureType::Ed25519 => ed25519::verify(msg, der_key, sig),

            SignatureType::RsaSsaPss => {
                let verify = || -> Result<bool, Error> {
                    let pub_key = PKey::from_rsa(Rsa::public_key_from_der(der_key)?)?;
                    let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key)?;
                    verifier.pkey_ctx_mut().set_rsa_padding(Padding::from_raw(RSA_PKCS1_PSS_PADDING))?;
                    verifier.update(msg)?;
                    Ok(verifier.finish(sig)?)
                };
                verify().unwrap_or_else(|err| { trace!("RSA SSA-PSS verification failed: {}", err); false })
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use base64;
    use pem;

    use datatype::Util;

    fn test_msg() -> Vec<u8> { "hello".as_bytes().into() }
    fn flip_bit(data: &mut [u8]) -> &[u8] { data[0] ^= 1; data }

    fn sign_and_verify(sig_type: SignatureType, priv_key: &[u8], pub_key: &[u8]) {
        let mut sig = sig_type.sign_msg(&test_msg(), &priv_key).expect("sign_msg");
        assert!(sig_type.verify_msg(&test_msg(), &pub_key, &sig));
        assert_eq!(false, sig_type.verify_msg(flip_bit(&mut test_msg()), &pub_key, &sig));
        assert_eq!(false, sig_type.verify_msg(&test_msg(), &pub_key, flip_bit(&mut sig)));
    }

    #[test]
    fn test_rsa_sign_and_verify() {
        let priv_key = Util::read_file("tests/keys/rsa.der").expect("read priv");
        let pub_key  = Util::read_file("tests/keys/rsa.pub").expect("read pub");
        sign_and_verify(SignatureType::RsaSsaPss, &priv_key, &pem::parse(pub_key).expect("pem").contents);
    }

    #[test]
    fn test_ed25519_sign_and_verify() {
        let priv_key = base64::decode("0wm+qYNKH2v7VUMy0lEz0ZfOEtEbdbDNwklW5PPLs4WpCLVDpXuapnO3XZQ9i1wV3aiIxi1b5TxVeVeulbyUyw==").expect("priv_key");
        let pub_key  = base64::decode("qQi1Q6V7mqZzt12UPYtcFd2oiMYtW+U8VXlXrpW8lMs=").expect("parse key");
        sign_and_verify(SignatureType::Ed25519, &priv_key, &pub_key);
    }
}
<commit_msg>Minor test refactor for readability<commit_after>use crypto::ed25519;
use openssl::hash::MessageDigest;
use openssl::pkey::PKey;
use openssl::rsa::{Rsa, Padding};
use openssl::sign::Verifier;
use ring::rand::SystemRandom;
use ring::signature::{RSAKeyPair, RSASigningState, RSA_PSS_SHA256};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::Error as SerdeError;
use serde_json as json;
use std::os::raw::c_int;
use std::str::{self, FromStr};
use std::sync::Arc;
use untrusted::Input;

use datatype::Error;

const RSA_PKCS1_PSS_PADDING: c_int = 6;

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Signature {
    pub keyid:  String,
    pub method: SignatureType,
    pub sig:    String,
}

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum SignatureType {
    Ed25519,
    RsaSsaPss,
}

impl<'de> Deserialize<'de> for SignatureType {
    fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
        if let json::Value::String(ref s) = Deserialize::deserialize(de)? {
            s.parse().map_err(|err| SerdeError::custom(format!("unknown SignatureType: {}", err)))
        } else {
            Err(SerdeError::custom("unknown SignatureType"))
        }
    }
}

impl Serialize for SignatureType {
    fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
        ser.serialize_str(match *self {
            SignatureType::Ed25519   => "ed25519",
            SignatureType::RsaSsaPss => "rsassa-pss"
        })
    }
}

impl FromStr for SignatureType {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "ed25519"    => Ok(SignatureType::Ed25519),
            "rsassa-pss" => Ok(SignatureType::RsaSsaPss),
            _ => Err(Error::TufSigType(s.to_string()))
        }
    }
}

impl SignatureType {
    pub fn sign_msg(&self, msg: &[u8], der_key: &[u8]) -> Result<Vec<u8>, Error> {
        match *self {
            SignatureType::Ed25519 => Ok(ed25519::signature(msg, der_key).as_ref().into()),

            SignatureType::RsaSsaPss => {
                let pair = RSAKeyPair::from_der(Input::from(der_key))?;
                let mut state = RSASigningState::new(Arc::new(pair))?;
                let mut sig = vec![0; state.key_pair().public_modulus_len()];
                state.sign(&RSA_PSS_SHA256, &SystemRandom::new(), msg, &mut sig)?;
                Ok(sig)
            }
        }
    }

    pub fn verify_msg(&self, msg: &[u8], der_key: &[u8], sig: &[u8]) -> bool {
        match *self {
            SignatureType::Ed25519 => ed25519::verify(msg, der_key, sig),

            SignatureType::RsaSsaPss => {
                let verify = || -> Result<bool, Error> {
                    let pub_key = PKey::from_rsa(Rsa::public_key_from_der(der_key)?)?;
                    let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key)?;
                    verifier.pkey_ctx_mut().set_rsa_padding(Padding::from_raw(RSA_PKCS1_PSS_PADDING))?;
                    verifier.update(msg)?;
                    Ok(verifier.finish(sig)?)
                };
                verify().unwrap_or_else(|err| { trace!("RSA SSA-PSS verification failed: {}", err); false })
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use base64;
    use pem;

    use datatype::Util;

    fn flip_bit(mut data: Vec<u8>) -> Vec<u8> { data[0] ^= 1; data }

    fn sign_and_verify(sig_type: SignatureType, priv_key: &[u8], pub_key: &[u8]) {
        let msg = b"hello";
        let sig = sig_type.sign_msg(msg, &priv_key).expect("sign_msg");
        let bad_msg = flip_bit(msg.as_ref().into());
        let bad_sig = flip_bit(sig.clone());

        assert!(sig_type.verify_msg(msg, &pub_key, &sig));
        assert!(!sig_type.verify_msg(&bad_msg, &pub_key, &sig));
        assert!(!sig_type.verify_msg(msg, &pub_key, &bad_sig));
    }

    #[test]
    fn test_rsa_sign_and_verify() {
        let pri_key = Util::read_file("tests/keys/rsa.der").expect("rsa.der");
        let pub_pem = Util::read_file("tests/keys/rsa.pub").expect("rsa.pub");
        let pub_key = pem::parse(pub_pem).expect("pem").contents;
        sign_and_verify(SignatureType::RsaSsaPss, &pri_key, &pub_key);
    }

    #[test]
    fn test_ed25519_sign_and_verify() {
        let pri_key = base64::decode("0wm+qYNKH2v7VUMy0lEz0ZfOEtEbdbDNwklW5PPLs4WpCLVDpXuapnO3XZQ9i1wV3aiIxi1b5TxVeVeulbyUyw==").expect("pri_key");
        let pub_key = base64::decode("qQi1Q6V7mqZzt12UPYtcFd2oiMYtW+U8VXlXrpW8lMs=").expect("pub_key");
        sign_and_verify(SignatureType::Ed25519, &pri_key, &pub_key);
    }
}
<|endoftext|>


<commit_before>extern crate rumblebars;
extern crate rustc_serialize;

use std::env;
use std::path::Path;
use std::fs::{self, File};
use std::io::Read;
use std::collections::BTreeMap;

use rumblebars::{Template, EvalContext};
use rustc_serialize::json::Json;

static UNITS_DIR: &'static str = "units";

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let output = Path::new(&*out_dir);

    let data = build_render_data();
    let ctx = EvalContext::new();

    let mut consts = File::create(output + "/consts.rs").unwrap();
    writeln!(consts, "static CRONTAB_DIR: &'static str = {:?};", data["statedir"]).unwrap();
    writeln!(consts, "static USERS_CRONTAB_DIR: &'static str = {:?};", data["statedir"]).unwrap();

    let data = Json::Object(data);

    for entry in fs::read_dir(UNITS_DIR).unwrap() {
        let entry = entry.unwrap();
        let name = entry.file_name().into_string().unwrap();
        let target = output.join(&name[..name.len()-3]);
        let tmpl = File::open(entry.path()).and_then(|mut file| {
            let mut buf = String::new();
            file.read_to_string(&mut buf).map(|_| Template::new(&*buf).unwrap())
        }).unwrap();

        println!("generating unit: {:?} -> {:?}...", entry.path(), target);
        tmpl.eval(&data, &mut File::create(target).unwrap(), &ctx).unwrap();
    }
}

fn build_render_data() -> BTreeMap<String, Json> {
    let mut ctx = BTreeMap::new();

    let prefix = env::var("PREFIX").unwrap_or_else(|_| "/usr/local".to_owned());
    let package = "systemd-cron";

    ctx.insert("package".to_owned(), Json::String(package.to_owned()));

    ctx.insert("bindir".to_owned(), Json::String(env::var("BIN_DIR").unwrap_or_else(|_| prefix.clone() + "/bin")));
    ctx.insert("confdir".to_owned(), Json::String(env::var("CONF_DIR").unwrap_or_else(|_| prefix.clone() + "/etc")));

    let datadir = env::var("DATA_DIR").unwrap_or_else(|_| prefix.clone() + "/share");
    let libdir = env::var("LIB_DIR").unwrap_or_else(|_| prefix.clone() + "/lib");

    ctx.insert("mandir".to_owned(), Json::String(env::var("MAN_DIR").unwrap_or_else(|_| datadir.clone() + "/man")));
    ctx.insert("docdir".to_owned(), Json::String(env::var("DOC_DIR").unwrap_or_else(|_| datadir.clone() + "/doc/" + package)));
    ctx.insert("unitdir".to_owned(), Json::String(env::var("UNIT_DIR").unwrap_or_else(|_| libdir.clone() + "/systemd/system")));

    ctx.insert("stale_stamps".to_owned(), Json::String(env::var("STALE_STAMPS").unwrap_or_else(|_| libdir.clone() + package + "remove-stale-stamps")));

    ctx.insert("libdir".to_owned(), Json::String(libdir));
    ctx.insert("datadir".to_owned(), Json::String(datadir));
    ctx.insert("prefix".to_owned(), Json::String(prefix));

    ctx.insert("statedir".to_owned(), Json::String(env::var("STATE_DIR").unwrap_or_else(|_| "/var/spool/cron".to_owned())));

    ctx.insert("runparts".to_owned(), Json::String(env::var("RUN_PARTS").unwrap_or_else(|_| "/usr/bin/run-parts".to_owned())));

    let mut schedules = Vec::new();
    if env::var("CARGO_FEATURE_SCHED_BOOT").is_ok() {
        schedules.push(Json::String("boot".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_HOURLY").is_ok() {
        schedules.push(Json::String("hourly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_DAILY").is_ok() {
        schedules.push(Json::String("daily".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_WEEKLY").is_ok() {
        schedules.push(Json::String("weekly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_MONTHLY").is_ok() {
        schedules.push(Json::String("monthly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_YEARLY").is_ok() {
        schedules.push(Json::String("yearly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_MINUTELY").is_ok() {
        schedules.push(Json::String("minutely".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_QUARTERLY").is_ok() {
        schedules.push(Json::String("quarterly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_SEMI_ANNUALLY").is_ok() {
        schedules.push(Json::String("semi-annually".to_owned()));
    }

    ctx.insert("schedules".to_owned(), Json::Array(schedules));

    ctx.insert("persistent".to_owned(), Json::Boolean(env::var("CARGO_FEATURE_PERSISTENT").is_ok()));

    ctx
}
<commit_msg>build: consts<commit_after>extern crate rumblebars;
extern crate rustc_serialize;

use std::env;
use std::path::Path;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::collections::BTreeMap;

use rumblebars::{Template, EvalContext};
use rustc_serialize::json::Json;

static UNITS_DIR: &'static str = "units";

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let output = Path::new(&*out_dir);

    let data = build_render_data();
    let ctx = EvalContext::new();

    let mut consts = File::create(out_dir.clone() + "/consts.rs").unwrap();
    writeln!(consts, "static CRONTAB_DIR: &'static str = {:?};", data["statedir"]).unwrap();
    writeln!(consts, "static USERS_CRONTAB_DIR: &'static str = {:?};", data["statedir"]).unwrap();

    let data = Json::Object(data);

    for entry in fs::read_dir(UNITS_DIR).unwrap() {
        let entry = entry.unwrap();
        let name = entry.file_name().into_string().unwrap();
        let target = output.join(&name[..name.len()-3]);
        let tmpl = File::open(entry.path()).and_then(|mut file| {
            let mut buf = String::new();
            file.read_to_string(&mut buf).map(|_| Template::new(&*buf).unwrap())
        }).unwrap();

        println!("generating unit: {:?} -> {:?}...", entry.path(), target);
        tmpl.eval(&data, &mut File::create(target).unwrap(), &ctx).unwrap();
    }
}

fn build_render_data() -> BTreeMap<String, Json> {
    let mut ctx = BTreeMap::new();

    let prefix = env::var("PREFIX").unwrap_or_else(|_| "/usr/local".to_owned());
    let package = "systemd-cron";

    ctx.insert("package".to_owned(), Json::String(package.to_owned()));

    ctx.insert("bindir".to_owned(), Json::String(env::var("BIN_DIR").unwrap_or_else(|_| prefix.clone() + "/bin")));
    ctx.insert("confdir".to_owned(), Json::String(env::var("CONF_DIR").unwrap_or_else(|_| prefix.clone() + "/etc")));

    let datadir = env::var("DATA_DIR").unwrap_or_else(|_| prefix.clone() + "/share");
    let libdir = env::var("LIB_DIR").unwrap_or_else(|_| prefix.clone() + "/lib");

    ctx.insert("mandir".to_owned(), Json::String(env::var("MAN_DIR").unwrap_or_else(|_| datadir.clone() + "/man")));
    ctx.insert("docdir".to_owned(), Json::String(env::var("DOC_DIR").unwrap_or_else(|_| datadir.clone() + "/doc/" + package)));
    ctx.insert("unitdir".to_owned(), Json::String(env::var("UNIT_DIR").unwrap_or_else(|_| libdir.clone() + "/systemd/system")));

    ctx.insert("stale_stamps".to_owned(), Json::String(env::var("STALE_STAMPS").unwrap_or_else(|_| libdir.clone() + package + "remove-stale-stamps")));

    ctx.insert("libdir".to_owned(), Json::String(libdir));
    ctx.insert("datadir".to_owned(), Json::String(datadir));
    ctx.insert("prefix".to_owned(), Json::String(prefix));

    ctx.insert("statedir".to_owned(), Json::String(env::var("STATE_DIR").unwrap_or_else(|_| "/var/spool/cron".to_owned())));

    ctx.insert("runparts".to_owned(), Json::String(env::var("RUN_PARTS").unwrap_or_else(|_| "/usr/bin/run-parts".to_owned())));

    let mut schedules = Vec::new();
    if env::var("CARGO_FEATURE_SCHED_BOOT").is_ok() {
        schedules.push(Json::String("boot".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_HOURLY").is_ok() {
        schedules.push(Json::String("hourly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_DAILY").is_ok() {
        schedules.push(Json::String("daily".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_WEEKLY").is_ok() {
        schedules.push(Json::String("weekly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_MONTHLY").is_ok() {
        schedules.push(Json::String("monthly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_YEARLY").is_ok() {
        schedules.push(Json::String("yearly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_MINUTELY").is_ok() {
        schedules.push(Json::String("minutely".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_QUARTERLY").is_ok() {
        schedules.push(Json::String("quarterly".to_owned()));
    }
    if env::var("CARGO_FEATURE_SCHED_SEMI_ANNUALLY").is_ok() {
        schedules.push(Json::String("semi-annually".to_owned()));
    }

    ctx.insert("schedules".to_owned(), Json::Array(schedules));

    ctx.insert("persistent".to_owned(), Json::Boolean(env::var("CARGO_FEATURE_PERSISTENT").is_ok()));

    ctx
}
<|endoftext|>


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

fn main() {
    Command::new("./bindgen/target/release/bindgen").args(
        &[
            "-lvulkan-1",
            "-o", "src/vulkan.rs",
            "/usr/include/vulkan/vulkan.h",
        ]).status().unwrap();
}
<commit_msg>Update to vulkan 1.0.2.0<commit_after>use std::process::Command;

fn main() {
    Command::new("./bindgen/target/release/bindgen").args(
        &[
            "-lvulkan",
            "-o", "src/vulkan.rs",
            "/usr/include/vulkan/vulkan.h",
        ]).status().unwrap();
}
<|endoftext|>


<commit_before>
// types and type aliases

pub type R = f64;

#[deriving(Eq, IterBytes, TotalOrd, TotalEq, Clone, Ord)]
pub struct Deg(u8);

#[deriving(Eq, IterBytes, TotalOrd, TotalEq, Clone, Ord)]
pub struct Dim(uint);

// constants

pub static DEFAULT_INTEGRATION_REL_ERR: R = 1e-12;
pub static DEFAULT_INTEGRATION_ABS_ERR: R = 1e-12;

#[inline]
pub fn pow(radix: R, exp: uint) -> R {
  if exp == 0u { return 1 as R; }
  if radix == 0. { return 0 as R; }
  let mut prod = 1 as R;
  let mut _exp = exp;
  let mut multiplier = radix;
  while (_exp > 0u) {
    if _exp % 2u == 1u {
      prod *= multiplier;
    }
    _exp /= 2u;
    multiplier *= multiplier;
  }
 prod
}

pub fn sq(x: uint) -> uint {
  x * x
}
<commit_msg>Add cumulative sums function and additional tests.<commit_after>use std::libc::{c_int};
use std::num::{Num,Zero};
use std::vec;

// types and type aliases

pub type R = f64;

#[deriving(Eq, IterBytes, TotalOrd, TotalEq, Clone, Ord)]
pub struct Deg(u8);

#[deriving(Eq, IterBytes, TotalOrd, TotalEq, Clone, Ord)]
pub struct Dim(uint);

pub type lapack_int = c_int; // Adjust according to whether LP64 or ILP64 libraries are being linked

// constants

pub static DEFAULT_INTEGRATION_REL_ERR: R = 1e-12;
pub static DEFAULT_INTEGRATION_ABS_ERR: R = 1e-12;

#[inline]
pub fn pow(radix: R, exp: uint) -> R {
  if exp == 0u { return 1 as R; }
  if radix == 0. { return 0 as R; }
  let mut prod = 1 as R;
  let mut _exp = exp;
  let mut multiplier = radix;
  while (_exp > 0u) {
    if _exp % 2u == 1u {
      prod *= multiplier;
    }
    _exp /= 2u;
    multiplier *= multiplier;
  }
 prod
}

#[inline(always)]
pub fn sq<T:Mul<T,T>>(x: T) -> T {
  x.mul(&x)
}

pub fn cumulative_sums_prev_elems<T:Num+Clone>(xs: &[T]) -> ~[T] {
  let mut cum_sums = vec::with_capacity(xs.len());
  let mut sum: T =  Zero::zero();
  for x in xs.iter() {
    cum_sums.push(sum.clone());
    sum = sum.add(x);
  }
  cum_sums
}

#[test]
fn test_pow() {
  assert_eq!(pow(2.,2), 4.);
  assert_eq!(pow(2.,3), 8.);
  assert_eq!(pow(0.,3), 0.);
  assert_eq!(pow(1.,3), 1.);
  assert_eq!(pow(0.,0), 1.); // In context of integral exponents and continuous radix, this def is most appropriate.
}

#[test]
fn test_sq() {
  assert_eq!(sq(0.), 0.);
  assert_eq!(sq(1.), 1.);
  assert_eq!(sq(2.), 4.);
  assert_eq!(sq(2.2), 2.2*2.2);
}

#[test]
fn test_cum_sums_prev() {
  let xs =  ~[1u, 2u, 3u];
  assert_eq!(cumulative_sums_prev_elems(xs), ~[0u, 1u, 3u]);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate rocket;

mod database;
mod domain;

use std::path::Path;

use aws_sdk_s3::types::ByteStream;
use aws_sdk_s3::Client;
use chrono::{DateTime, Datelike, SecondsFormat, Utc};
use dotenv::dotenv;
use rocket::data::ToByteUnit;
use rocket::http::ContentType;
use rocket::outcome::{try_outcome, Outcome};
use rocket::request::FromRequest;
use rocket::request::{self, FromParam};
use rocket::serde::json::Json;
use rocket::serde::Serialize;
use rocket::{Data, Request};
use rocket_db_pools::{Connection, Database};

use database::Db;
use domain::entities::{ApiKeyId, DropId, User, UserId};
use domain::ApiKeyValue;

impl<'a> FromParam<'a> for DropId {
    type Error = String;

    fn from_param(param: &'a str) -> Result<Self, Self::Error> {
        DropId::try_from(param)
            .map_err(|err| format!("failed to parse '{}' as a drop ID: {}", param, err))
    }
}

impl<'a> FromParam<'a> for UserId {
    type Error = String;

    fn from_param(param: &'a str) -> Result<Self, Self::Error> {
        UserId::try_from(param)
            .map_err(|err| format!("failed to parse '{}' as a user ID: {}", param, err))
    }
}

pub struct ApiKeyBearer {
    user: User,
}

struct ApiKeyLookup {
    pub id: String,
    pub username: String,
    pub full_name: Option<String>,
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for ApiKeyBearer {
    type Error = String;

    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
        let mut db = try_outcome!(req
            .guard::<Connection<Db>>()
            .await
            .map_failure(|f| (f.0, "failed to acquire database connection".to_string())));

        match req.headers().get_one("Authorization") {
            Some(authorization) => {
                let token = authorization.replace("Bearer ", "");

                let api_key = sqlx::query_as!(
                    ApiKeyLookup,
                    "
                    select user.id, user.username, user.full_name from api_key
                    inner join user on user.id = api_key.user_id
                    where api_key.value = $1
                    ",
                    token
                )
                .fetch_one(&mut *db)
                .await
                .unwrap();

                Outcome::Success(ApiKeyBearer {
                    user: User {
                        id: UserId::try_from(api_key.id).unwrap(),
                        username: api_key.username,
                        full_name: api_key.full_name,
                    },
                })
            }
            _ => Outcome::Forward(()),
        }
    }
}

#[get("/")]
async fn index() -> &'static str {
    "滴"
}

#[post("/drops", data = "<drop>")]
async fn upload_drop(_bearer: ApiKeyBearer, drop: Data<'_>) -> std::io::Result<String> {
    let id = DropId::new();

    let temp_filepath = Path::new("temp").join(id.to_string());

    drop.open(2.mebibytes()).into_file(&temp_filepath).await?;

    let s3_config = aws_config::load_from_env().await;
    let client = Client::new(&s3_config);

    let body = ByteStream::from_path(&temp_filepath).await?;

    client
        .put_object()
        .bucket(env!("AWS_S3_BUCKET"))
        .key(format!(
            "drops/{}/{}",
            id.created_at().date().year(),
            id.unprefixed()
        ))
        .body(body)
        .send()
        .await
        .expect("failed to upload to S3");

    tokio::fs::remove_file(temp_filepath).await.ok();

    Ok(id.to_string())
}

#[get("/drops/<id>")]
async fn get_drop(id: DropId) -> (ContentType, Vec<u8>) {
    let s3_config = aws_config::load_from_env().await;
    let client = Client::new(&s3_config);

    let object = client
        .get_object()
        .bucket(env!("AWS_S3_BUCKET"))
        .key(format!(
            "drops/{}/{}",
            id.created_at().date().year(),
            id.unprefixed()
        ))
        .send()
        .await
        .expect("failed to retrieve object from S3");

    let bytes = object
        .body
        .collect()
        .await
        .map(|data| data.into_bytes())
        .unwrap()
        .to_vec();

    let mime_type = tree_magic_mini::from_u8(&bytes);

    let content_type = ContentType::parse_flexible(mime_type).unwrap_or(ContentType::Binary);

    (content_type, bytes)
}

#[derive(Debug, Serialize)]
pub struct DropMetadata {
    pub created_at: DateTime<Utc>,
    pub size_in_bytes: i64,
}

#[get("/drops/<id>/meta")]
async fn get_drop_metadata(id: DropId) -> Json<DropMetadata> {
    let s3_config = aws_config::load_from_env().await;
    let client = Client::new(&s3_config);

    let object = client
        .get_object()
        .bucket(env!("AWS_S3_BUCKET"))
        .key(format!(
            "drops/{}/{}",
            id.created_at().date().year(),
            id.unprefixed()
        ))
        .send()
        .await
        .expect("failed to retrieve object from S3");

    Json(DropMetadata {
        created_at: id.created_at(),
        size_in_bytes: object.content_length,
    })
}

#[derive(Debug, Serialize)]
pub struct UserJson {
    pub id: String,
    pub username: String,
    pub full_name: Option<String>,
}

#[post("/users")]
async fn create_user(
    _bearer: ApiKeyBearer,
    mut db: Connection<Db>,
) -> database::Result<Json<UserJson>> {
    let id = UserId::new();

    let username = "maxdeviant";
    let full_name = "Marshall Bowers";

    let unprefixed_id = id.unprefixed();
    let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);

    sqlx::query!(
        "
        insert into user (id, created_at, updated_at, username, full_name)
        values (?, ?, ?, ?, ?)
        ",
        unprefixed_id,
        now,
        now,
        username,
        full_name
    )
    .execute(&mut *db)
    .await?;

    Ok(Json(UserJson {
        id: id.to_string(),
        username: username.to_string(),
        full_name: Some(full_name.to_string()),
    }))
}

#[derive(Debug, Serialize)]
pub struct ApiKeyJson {
    pub id: String,
    pub value: String,
}

#[post("/keys")]
async fn generate_api_key(
    bearer: ApiKeyBearer,
    mut db: Connection<Db>,
) -> database::Result<Json<ApiKeyJson>> {
    let id = ApiKeyId::new();
    let value = ApiKeyValue::new();

    let unprefixed_id = id.unprefixed();
    let unprefixed_user_id = bearer.user.id.unprefixed();
    let key_value = value.to_string();
    let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);

    sqlx::query!(
        "
        insert into api_key (id, created_at, updated_at, user_id, value)
        values (?, ?, ?, ?, ?)
        ",
        unprefixed_id,
        now,
        now,
        unprefixed_user_id,
        key_value
    )
    .execute(&mut *db)
    .await?;

    Ok(Json(ApiKeyJson {
        id: id.to_string(),
        value: value.to_string(),
    }))
}

async fn ensure_root_user_exists() {
    use sqlx::{Connection, SqliteConnection};

    let root_username = env!("ROOT_USERNAME");
    let root_api_key = env!("ROOT_API_KEY");

    let database_url = env!("DATABASE_URL");
    let mut connection = SqliteConnection::connect(database_url).await.unwrap();

    let user_id = UserId::new();
    let unprefixed_user_id = user_id.unprefixed();
    let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);

    #[derive(Debug)]
    struct RootUser {
        id: String,
    }

    let root_user = sqlx::query_as!(
        RootUser,
        "
        insert into user (id, created_at, updated_at, username)
        values (?, ?, ?, ?)
        -- This is a no-op update just so we can get the `id` returned.
        on conflict (username) do update set updated_at = updated_at
        returning id
        ",
        unprefixed_user_id,
        now,
        now,
        root_username
    )
    .fetch_one(&mut connection)
    .await
    .expect("failed to insert root user");

    println!("Root user: {:?}", root_user);

    let key_id = ApiKeyId::new();
    let unprefixed_key_id = key_id.unprefixed();
    let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);

    sqlx::query!(
        "
        insert into api_key (id, created_at, updated_at, user_id, value)
        values (?, ?, ?, ?, ?)
        on conflict (value) do nothing
        ",
        unprefixed_key_id,
        now,
        now,
        root_user.id,
        root_api_key
    )
    .execute(&mut connection)
    .await
    .unwrap();
}

#[rocket::main]
async fn main() -> Result<(), rocket::Error> {
    dotenv().ok();

    ensure_root_user_exists().await;

    let rocket = rocket::build()
        .mount(
            "/",
            routes![index, upload_drop, get_drop, get_drop_metadata,],
        )
        .mount("/x/", routes![create_user, generate_api_key])
        .attach(Db::init())
        .ignite()
        .await?;

    let _ = rocket.launch().await?;

    Ok(())
}
<commit_msg>Use `env::var` instead of `env!`<commit_after>#[macro_use]
extern crate rocket;

mod database;
mod domain;

use std::env;
use std::path::Path;

use aws_sdk_s3::types::ByteStream;
use aws_sdk_s3::Client;
use chrono::{DateTime, Datelike, SecondsFormat, Utc};
use dotenv::dotenv;
use rocket::data::ToByteUnit;
use rocket::http::ContentType;
use rocket::outcome::{try_outcome, Outcome};
use rocket::request::FromRequest;
use rocket::request::{self, FromParam};
use rocket::serde::json::Json;
use rocket::serde::Serialize;
use rocket::{Data, Request};
use rocket_db_pools::{Connection, Database};

use database::Db;
use domain::entities::{ApiKeyId, DropId, User, UserId};
use domain::ApiKeyValue;

impl<'a> FromParam<'a> for DropId {
    type Error = String;

    fn from_param(param: &'a str) -> Result<Self, Self::Error> {
        DropId::try_from(param)
            .map_err(|err| format!("failed to parse '{}' as a drop ID: {}", param, err))
    }
}

impl<'a> FromParam<'a> for UserId {
    type Error = String;

    fn from_param(param: &'a str) -> Result<Self, Self::Error> {
        UserId::try_from(param)
            .map_err(|err| format!("failed to parse '{}' as a user ID: {}", param, err))
    }
}

pub struct ApiKeyBearer {
    user: User,
}

struct ApiKeyLookup {
    pub id: String,
    pub username: String,
    pub full_name: Option<String>,
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for ApiKeyBearer {
    type Error = String;

    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
        let mut db = try_outcome!(req
            .guard::<Connection<Db>>()
            .await
            .map_failure(|f| (f.0, "failed to acquire database connection".to_string())));

        match req.headers().get_one("Authorization") {
            Some(authorization) => {
                let token = authorization.replace("Bearer ", "");

                let api_key = sqlx::query_as!(
                    ApiKeyLookup,
                    "
                    select user.id, user.username, user.full_name from api_key
                    inner join user on user.id = api_key.user_id
                    where api_key.value = $1
                    ",
                    token
                )
                .fetch_one(&mut *db)
                .await
                .unwrap();

                Outcome::Success(ApiKeyBearer {
                    user: User {
                        id: UserId::try_from(api_key.id).unwrap(),
                        username: api_key.username,
                        full_name: api_key.full_name,
                    },
                })
            }
            _ => Outcome::Forward(()),
        }
    }
}

#[get("/")]
async fn index() -> &'static str {
    "滴"
}

#[post("/drops", data = "<drop>")]
async fn upload_drop(_bearer: ApiKeyBearer, drop: Data<'_>) -> std::io::Result<String> {
    let id = DropId::new();

    let temp_filepath = Path::new("temp").join(id.to_string());

    drop.open(2.mebibytes()).into_file(&temp_filepath).await?;

    let s3_config = aws_config::load_from_env().await;
    let client = Client::new(&s3_config);

    let body = ByteStream::from_path(&temp_filepath).await?;

    client
        .put_object()
        .bucket(env::var("AWS_S3_BUCKET").unwrap())
        .key(format!(
            "drops/{}/{}",
            id.created_at().date().year(),
            id.unprefixed()
        ))
        .body(body)
        .send()
        .await
        .expect("failed to upload to S3");

    tokio::fs::remove_file(temp_filepath).await.ok();

    Ok(id.to_string())
}

#[get("/drops/<id>")]
async fn get_drop(id: DropId) -> (ContentType, Vec<u8>) {
    let s3_config = aws_config::load_from_env().await;
    let client = Client::new(&s3_config);

    let object = client
        .get_object()
        .bucket(env::var("AWS_S3_BUCKET").unwrap())
        .key(format!(
            "drops/{}/{}",
            id.created_at().date().year(),
            id.unprefixed()
        ))
        .send()
        .await
        .expect("failed to retrieve object from S3");

    let bytes = object
        .body
        .collect()
        .await
        .map(|data| data.into_bytes())
        .unwrap()
        .to_vec();

    let mime_type = tree_magic_mini::from_u8(&bytes);

    let content_type = ContentType::parse_flexible(mime_type).unwrap_or(ContentType::Binary);

    (content_type, bytes)
}

#[derive(Debug, Serialize)]
pub struct DropMetadata {
    pub created_at: DateTime<Utc>,
    pub size_in_bytes: i64,
}

#[get("/drops/<id>/meta")]
async fn get_drop_metadata(id: DropId) -> Json<DropMetadata> {
    let s3_config = aws_config::load_from_env().await;
    let client = Client::new(&s3_config);

    let object = client
        .get_object()
        .bucket(env::var("AWS_S3_BUCKET").unwrap())
        .key(format!(
            "drops/{}/{}",
            id.created_at().date().year(),
            id.unprefixed()
        ))
        .send()
        .await
        .expect("failed to retrieve object from S3");

    Json(DropMetadata {
        created_at: id.created_at(),
        size_in_bytes: object.content_length,
    })
}

#[derive(Debug, Serialize)]
pub struct UserJson {
    pub id: String,
    pub username: String,
    pub full_name: Option<String>,
}

#[post("/users")]
async fn create_user(
    _bearer: ApiKeyBearer,
    mut db: Connection<Db>,
) -> database::Result<Json<UserJson>> {
    let id = UserId::new();

    let username = "maxdeviant";
    let full_name = "Marshall Bowers";

    let unprefixed_id = id.unprefixed();
    let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);

    sqlx::query!(
        "
        insert into user (id, created_at, updated_at, username, full_name)
        values (?, ?, ?, ?, ?)
        ",
        unprefixed_id,
        now,
        now,
        username,
        full_name
    )
    .execute(&mut *db)
    .await?;

    Ok(Json(UserJson {
        id: id.to_string(),
        username: username.to_string(),
        full_name: Some(full_name.to_string()),
    }))
}

#[derive(Debug, Serialize)]
pub struct ApiKeyJson {
    pub id: String,
    pub value: String,
}

#[post("/keys")]
async fn generate_api_key(
    bearer: ApiKeyBearer,
    mut db: Connection<Db>,
) -> database::Result<Json<ApiKeyJson>> {
    let id = ApiKeyId::new();
    let value = ApiKeyValue::new();

    let unprefixed_id = id.unprefixed();
    let unprefixed_user_id = bearer.user.id.unprefixed();
    let key_value = value.to_string();
    let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);

    sqlx::query!(
        "
        insert into api_key (id, created_at, updated_at, user_id, value)
        values (?, ?, ?, ?, ?)
        ",
        unprefixed_id,
        now,
        now,
        unprefixed_user_id,
        key_value
    )
    .execute(&mut *db)
    .await?;

    Ok(Json(ApiKeyJson {
        id: id.to_string(),
        value: value.to_string(),
    }))
}

async fn ensure_root_user_exists() {
    use sqlx::{Connection, SqliteConnection};

    let root_username = env::var("ROOT_USERNAME").unwrap();
    let root_api_key = env::var("ROOT_API_KEY").unwrap();

    let database_url = env::var("DATABASE_URL").unwrap();
    let mut connection = SqliteConnection::connect(&database_url).await.unwrap();

    let user_id = UserId::new();
    let unprefixed_user_id = user_id.unprefixed();
    let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);

    #[derive(Debug)]
    struct RootUser {
        id: String,
    }

    let root_user = sqlx::query_as!(
        RootUser,
        "
        insert into user (id, created_at, updated_at, username)
        values (?, ?, ?, ?)
        -- This is a no-op update just so we can get the `id` returned.
        on conflict (username) do update set updated_at = updated_at
        returning id
        ",
        unprefixed_user_id,
        now,
        now,
        root_username
    )
    .fetch_one(&mut connection)
    .await
    .expect("failed to insert root user");

    println!("Root user: {:?}", root_user);

    let key_id = ApiKeyId::new();
    let unprefixed_key_id = key_id.unprefixed();
    let now = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);

    sqlx::query!(
        "
        insert into api_key (id, created_at, updated_at, user_id, value)
        values (?, ?, ?, ?, ?)
        on conflict (value) do nothing
        ",
        unprefixed_key_id,
        now,
        now,
        root_user.id,
        root_api_key
    )
    .execute(&mut connection)
    .await
    .unwrap();
}

#[rocket::main]
async fn main() -> Result<(), rocket::Error> {
    dotenv().ok();

    ensure_root_user_exists().await;

    let rocket = rocket::build()
        .mount(
            "/",
            routes![index, upload_drop, get_drop, get_drop_metadata,],
        )
        .mount("/x/", routes![create_user, generate_api_key])
        .attach(Db::init())
        .ignite()
        .await?;

    let _ = rocket.launch().await?;

    Ok(())
}
<|endoftext|>