<commit_before>//! Functions to aid the `Api::to_tokens` method.

use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::Ident;

use crate::api::{metadata::Metadata, request::Request};

/// The first item in the tuple generates code for the request path from
/// the `Metadata` and `Request` structs. The second item in the returned tuple
/// is the code to generate a Request struct field created from any segments
/// of the path that start with ":".
///
/// The first `TokenStream` returned is the constructed url path. The second `TokenStream` is
/// used for implementing `TryFrom<http::Request<Vec<u8>>>`, from path strings deserialized to Ruma
/// types.
pub(crate) fn request_path_string_and_parse(
    request: &Request,
    metadata: &Metadata,
) -> (TokenStream, TokenStream) {
    if request.has_path_fields() {
        let path_string = metadata.path.value();

        assert!(path_string.starts_with('/'), "path needs to start with '/'");
        assert!(
            path_string.chars().filter(|c| *c == ':').count() == request.path_field_count(),
            "number of declared path parameters needs to match amount of placeholders in path"
        );

        let format_call = {
            let mut format_string = path_string.clone();
            let mut format_args = Vec::new();

            while let Some(start_of_segment) = format_string.find(':') {
                // ':' should only ever appear at the start of a segment
                assert_eq!(&format_string[start_of_segment - 1..start_of_segment], "/");

                let end_of_segment = match format_string[start_of_segment..].find('/') {
                    Some(rel_pos) => start_of_segment + rel_pos,
                    None => format_string.len(),
                };

                let path_var = Ident::new(
                    &format_string[start_of_segment + 1..end_of_segment],
                    Span::call_site(),
                );
                format_args.push(quote! {
                    ::ruma_api::exports::percent_encoding::utf8_percent_encode(
                        &self.#path_var.to_string(),
                        ::ruma_api::exports::percent_encoding::NON_ALPHANUMERIC,
                    )
                });
                format_string.replace_range(start_of_segment..end_of_segment, "{}");
            }

            quote! {
                format_args!(#format_string, #(#format_args),*)
            }
        };

        let path_fields =
            path_string[1..].split('/').enumerate().filter(|(_, s)| s.starts_with(':')).map(
                |(i, segment)| {
                    let path_var = &segment[1..];
                    let path_var_ident = Ident::new(path_var, Span::call_site());
                    quote! {
                        #path_var_ident: {
                            use ::ruma_api::error::RequestDeserializationError;

                            let segment = path_segments.get(#i).unwrap().as_bytes();
                            let decoded = ::ruma_api::try_deserialize!(
                                request,
                                ::ruma_api::exports::percent_encoding::percent_decode(segment)
                                    .decode_utf8(),
                            );

                            ::ruma_api::try_deserialize!(request, ::std::convert::TryFrom::try_from(&*decoded))
                        }
                    }
                },
            );

        (format_call, quote! { #(#path_fields,)* })
    } else {
        (quote! { metadata.path.to_owned() }, TokenStream::new())
    }
}

/// The function determines the type of query string that needs to be built
/// and then builds it using `ruma_serde::urlencoded::to_string`.
pub(crate) fn build_query_string(request: &Request) -> TokenStream {
    if let Some(field) = request.query_map_field() {
        let field_name = field.ident.as_ref().expect("expected field to have identifier");
        let field_type = &field.ty;

        quote!({
            // This function exists so that the compiler will throw an
            // error when the type of the field with the query_map
            // attribute doesn't implement IntoIterator<Item = (String, String)>
            //
            // This is necessary because the ruma_serde::urlencoded::to_string
            // call will result in a runtime error when the type cannot be
            // encoded as a list key-value pairs (?key1=value1&key2=value2)
            //
            // By asserting that it implements the iterator trait, we can
            // ensure that it won't fail.
            fn assert_trait_impl<T>()
            where
                T: ::std::iter::IntoIterator<Item = (::std::string::String, ::std::string::String)>,
            {}
            assert_trait_impl::<#field_type>();

            let request_query = RequestQuery(self.#field_name);
            format_args!(
                "?{}",
                ::ruma_api::exports::ruma_serde::urlencoded::to_string(request_query)?
            )
        })
    } else if request.has_query_fields() {
        let request_query_init_fields = request.request_query_init_fields();

        quote!({
            let request_query = RequestQuery {
                #request_query_init_fields
            };

            format_args!(
                "?{}",
                ::ruma_api::exports::ruma_serde::urlencoded::to_string(request_query)?
            )
        })
    } else {
        quote! { "" }
    }
}

/// Deserialize the query string.
pub(crate) fn extract_request_query(request: &Request) -> TokenStream {
    if request.query_map_field().is_some() {
        quote! {
            let request_query = ::ruma_api::try_deserialize!(
                request,
                ::ruma_api::exports::ruma_serde::urlencoded::from_str(
                    &request.uri().query().unwrap_or("")
                ),
            );
        }
    } else if request.has_query_fields() {
        quote! {
            let request_query: RequestQuery = ::ruma_api::try_deserialize!(
                request,
                ::ruma_api::exports::ruma_serde::urlencoded::from_str(
                    &request.uri().query().unwrap_or("")
                ),
            );
        }
    } else {
        TokenStream::new()
    }
}

/// Generates the code to initialize a `Request`.
///
/// Used to construct an `http::Request`s body.
pub(crate) fn build_request_body(request: &Request) -> TokenStream {
    if let Some(field) = request.newtype_raw_body_field() {
        let field_name = field.ident.as_ref().expect("expected field to have an identifier");
        quote!(self.#field_name)
    } else if request.has_body_fields() || request.newtype_body_field().is_some() {
        let request_body_initializers = if let Some(field) = request.newtype_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            quote! { (self.#field_name) }
        } else {
            let initializers = request.request_body_init_fields();
            quote! { { #initializers } }
        };

        quote! {
            {
                let request_body = RequestBody #request_body_initializers;
                ::ruma_api::exports::serde_json::to_vec(&request_body)?
            }
        }
    } else {
        quote!(Vec::new())
    }
}

pub(crate) fn parse_request_body(request: &Request) -> TokenStream {
    if let Some(field) = request.newtype_body_field() {
        let field_name = field.ident.as_ref().expect("expected field to have an identifier");
        quote! {
            #field_name: request_body.0,
        }
    } else if let Some(field) = request.newtype_raw_body_field() {
        let field_name = field.ident.as_ref().expect("expected field to have an identifier");
        quote! {
            #field_name: request.into_body(),
        }
    } else {
        request.request_init_body_fields()
    }
}

pub(crate) fn req_res_meta_word<T>(
    attr_kind: &str,
    field: &syn::Field,
    newtype_body_field: &mut Option<syn::Field>,
    body_field_kind: T,
    raw_field_kind: T,
) -> syn::Result<T> {
    if let Some(f) = &newtype_body_field {
        let mut error = syn::Error::new_spanned(field, "There can only be one newtype body field");
        error.combine(syn::Error::new_spanned(f, "Previous newtype body field"));
        return Err(error);
    }

    *newtype_body_field = Some(field.clone());
    Ok(match attr_kind {
        "body" => body_field_kind,
        "raw_body" => raw_field_kind,
        _ => unreachable!(),
    })
}

pub(crate) fn req_res_name_value<T>(
    name: Ident,
    value: Ident,
    header: &mut Option<Ident>,
    field_kind: T,
) -> syn::Result<T> {
    if name != "header" {
        return Err(syn::Error::new_spanned(
            name,
            "Invalid #[ruma_api] argument with value, expected `header`",
        ));
    }

    *header = Some(value);
    Ok(field_kind)
}

pub(crate) fn is_valid_endpoint_path(string: &str) -> bool {
    string.as_bytes().iter().all(|b| (0x21..=0x7E).contains(b))
}
<commit_msg>Add lifetime discovery and collection functions to ruma-api-macro<commit_after>//! Functions to aid the `Api::to_tokens` method.

use proc_macro2::{Span, TokenStream};
use quote::quote;
use std::collections::BTreeSet;
use syn::{
    AngleBracketedGenericArguments, GenericArgument, Ident, Lifetime,
    ParenthesizedGenericArguments, PathArguments, Type, TypePath, TypeReference,
};

use crate::api::{metadata::Metadata, request::Request};

/// Whether or not the request field has a lifetime.
pub fn has_lifetime(ty: &Type) -> bool {
    let mut found_lifetime = false;
    if let Type::Path(TypePath { path, .. }) = ty {
        for seg in &path.segments {
            #[allow(clippy::blocks_in_if_conditions)] // TODO
            if match &seg.arguments {
                PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }) => {
                    args.clone().iter().any(|gen| {
                        if let GenericArgument::Type(ty) = gen {
                            has_lifetime(ty)
                        } else {
                            matches!(gen, GenericArgument::Lifetime(_))
                        }
                    })
                }
                PathArguments::Parenthesized(ParenthesizedGenericArguments { inputs, .. }) => {
                    inputs.iter().any(|ty| has_lifetime(ty))
                }
                _ => false,
            } {
                found_lifetime = true;
            }
        }
    }

    matches!(ty, Type::Reference(_) | Type::Slice(_)) || found_lifetime
}

pub fn copy_lifetime_ident(lifetimes: &mut BTreeSet<Lifetime>, ty: &Type) {
    match ty {
        Type::Path(TypePath { path, .. }) => {
            for seg in &path.segments {
                match &seg.arguments {
                    PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                        args, ..
                    }) => {
                        for gen in args {
                            if let GenericArgument::Type(ty) = gen {
                                copy_lifetime_ident(lifetimes, &ty)
                            } else if let GenericArgument::Lifetime(lt) = gen {
                                lifetimes.insert(lt.clone());
                            }
                        }
                    }
                    PathArguments::Parenthesized(ParenthesizedGenericArguments {
                        inputs, ..
                    }) => {
                        for ty in inputs {
                            copy_lifetime_ident(lifetimes, ty)
                        }
                    }
                    _ => {}
                }
            }
        }
        Type::Reference(TypeReference { elem, lifetime, .. }) => {
            copy_lifetime_ident(lifetimes, &*elem);
            if let Some(lt) = lifetime {
                lifetimes.insert(lt.clone());
            }
        }
        _ => {}
    }
}

/// Collects the unique lifetime identifiers from the struct declaration.
pub fn collect_generic_idents<'a, I: Iterator<Item = &'a Type>>(iter: I) -> TokenStream {
    let mut lifetimes = BTreeSet::new();

    for ty in iter {
        copy_lifetime_ident(&mut lifetimes, &ty);
    }
    generics_to_tokens(lifetimes.iter())
}

/// Generates a `TokenStream` of lifetime identifiers `<'lifetime>`.
pub fn generics_to_tokens<'a, I: Iterator<Item = &'a Lifetime>>(lifetimes: I) -> TokenStream {
    let lifetimes = lifetimes.collect::<Vec<_>>();
    if lifetimes.is_empty() {
        TokenStream::new()
    } else {
        let lifetimes = quote! { #( #lifetimes ),* };
        quote! { < #lifetimes > }
    }
}

/// The first item in the tuple generates code for the request path from
/// the `Metadata` and `Request` structs. The second item in the returned tuple
/// is the code to generate a Request struct field created from any segments
/// of the path that start with ":".
///
/// The first `TokenStream` returned is the constructed url path. The second `TokenStream` is
/// used for implementing `TryFrom<http::Request<Vec<u8>>>`, from path strings deserialized to Ruma
/// types.
pub(crate) fn request_path_string_and_parse(
    request: &Request,
    metadata: &Metadata,
) -> (TokenStream, TokenStream) {
    if request.has_path_fields() {
        let path_string = metadata.path.value();

        assert!(path_string.starts_with('/'), "path needs to start with '/'");
        assert!(
            path_string.chars().filter(|c| *c == ':').count() == request.path_field_count(),
            "number of declared path parameters needs to match amount of placeholders in path"
        );

        let format_call = {
            let mut format_string = path_string.clone();
            let mut format_args = Vec::new();

            while let Some(start_of_segment) = format_string.find(':') {
                // ':' should only ever appear at the start of a segment
                assert_eq!(&format_string[start_of_segment - 1..start_of_segment], "/");

                let end_of_segment = match format_string[start_of_segment..].find('/') {
                    Some(rel_pos) => start_of_segment + rel_pos,
                    None => format_string.len(),
                };

                let path_var = Ident::new(
                    &format_string[start_of_segment + 1..end_of_segment],
                    Span::call_site(),
                );
                format_args.push(quote! {
                    ::ruma_api::exports::percent_encoding::utf8_percent_encode(
                        &self.#path_var.to_string(),
                        ::ruma_api::exports::percent_encoding::NON_ALPHANUMERIC,
                    )
                });
                format_string.replace_range(start_of_segment..end_of_segment, "{}");
            }

            quote! {
                format_args!(#format_string, #(#format_args),*)
            }
        };

        let path_fields =
            path_string[1..].split('/').enumerate().filter(|(_, s)| s.starts_with(':')).map(
                |(i, segment)| {
                    let path_var = &segment[1..];
                    let path_var_ident = Ident::new(path_var, Span::call_site());
                    quote! {
                        #path_var_ident: {
                            use ::ruma_api::error::RequestDeserializationError;

                            let segment = path_segments.get(#i).unwrap().as_bytes();
                            let decoded = ::ruma_api::try_deserialize!(
                                request,
                                ::ruma_api::exports::percent_encoding::percent_decode(segment)
                                    .decode_utf8(),
                            );

                            ::ruma_api::try_deserialize!(request, ::std::convert::TryFrom::try_from(&*decoded))
                        }
                    }
                },
            );

        (format_call, quote! { #(#path_fields,)* })
    } else {
        (quote! { metadata.path.to_owned() }, TokenStream::new())
    }
}

/// The function determines the type of query string that needs to be built
/// and then builds it using `ruma_serde::urlencoded::to_string`.
pub(crate) fn build_query_string(request: &Request) -> TokenStream {
    if let Some(field) = request.query_map_field() {
        let field_name = field.ident.as_ref().expect("expected field to have identifier");
        let field_type = &field.ty;

        quote!({
            // This function exists so that the compiler will throw an
            // error when the type of the field with the query_map
            // attribute doesn't implement IntoIterator<Item = (String, String)>
            //
            // This is necessary because the ruma_serde::urlencoded::to_string
            // call will result in a runtime error when the type cannot be
            // encoded as a list key-value pairs (?key1=value1&key2=value2)
            //
            // By asserting that it implements the iterator trait, we can
            // ensure that it won't fail.
            fn assert_trait_impl<T>()
            where
                T: ::std::iter::IntoIterator<Item = (::std::string::String, ::std::string::String)>,
            {}
            assert_trait_impl::<#field_type>();

            let request_query = RequestQuery(self.#field_name);
            format_args!(
                "?{}",
                ::ruma_api::exports::ruma_serde::urlencoded::to_string(request_query)?
            )
        })
    } else if request.has_query_fields() {
        let request_query_init_fields = request.request_query_init_fields();

        quote!({
            let request_query = RequestQuery {
                #request_query_init_fields
            };

            format_args!(
                "?{}",
                ::ruma_api::exports::ruma_serde::urlencoded::to_string(request_query)?
            )
        })
    } else {
        quote! { "" }
    }
}

/// Deserialize the query string.
pub(crate) fn extract_request_query(request: &Request) -> TokenStream {
    if request.query_map_field().is_some() {
        quote! {
            let request_query = ::ruma_api::try_deserialize!(
                request,
                ::ruma_api::exports::ruma_serde::urlencoded::from_str(
                    &request.uri().query().unwrap_or("")
                ),
            );
        }
    } else if request.has_query_fields() {
        quote! {
            let request_query: RequestQuery = ::ruma_api::try_deserialize!(
                request,
                ::ruma_api::exports::ruma_serde::urlencoded::from_str(
                    &request.uri().query().unwrap_or("")
                ),
            );
        }
    } else {
        TokenStream::new()
    }
}

/// Generates the code to initialize a `Request`.
///
/// Used to construct an `http::Request`s body.
pub(crate) fn build_request_body(request: &Request) -> TokenStream {
    if let Some(field) = request.newtype_raw_body_field() {
        let field_name = field.ident.as_ref().expect("expected field to have an identifier");
        quote!(self.#field_name)
    } else if request.has_body_fields() || request.newtype_body_field().is_some() {
        let request_body_initializers = if let Some(field) = request.newtype_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            quote! { (self.#field_name) }
        } else {
            let initializers = request.request_body_init_fields();
            quote! { { #initializers } }
        };

        quote! {
            {
                let request_body = RequestBody #request_body_initializers;
                ::ruma_api::exports::serde_json::to_vec(&request_body)?
            }
        }
    } else {
        quote!(Vec::new())
    }
}

pub(crate) fn parse_request_body(request: &Request) -> TokenStream {
    if let Some(field) = request.newtype_body_field() {
        let field_name = field.ident.as_ref().expect("expected field to have an identifier");
        quote! {
            #field_name: request_body.0,
        }
    } else if let Some(field) = request.newtype_raw_body_field() {
        let field_name = field.ident.as_ref().expect("expected field to have an identifier");
        quote! {
            #field_name: request.into_body(),
        }
    } else {
        request.request_init_body_fields()
    }
}

pub(crate) fn req_res_meta_word<T>(
    attr_kind: &str,
    field: &syn::Field,
    newtype_body_field: &mut Option<syn::Field>,
    body_field_kind: T,
    raw_field_kind: T,
) -> syn::Result<T> {
    if let Some(f) = &newtype_body_field {
        let mut error = syn::Error::new_spanned(field, "There can only be one newtype body field");
        error.combine(syn::Error::new_spanned(f, "Previous newtype body field"));
        return Err(error);
    }

    *newtype_body_field = Some(field.clone());
    Ok(match attr_kind {
        "body" => body_field_kind,
        "raw_body" => raw_field_kind,
        _ => unreachable!(),
    })
}

pub(crate) fn req_res_name_value<T>(
    name: Ident,
    value: Ident,
    header: &mut Option<Ident>,
    field_kind: T,
) -> syn::Result<T> {
    if name != "header" {
        return Err(syn::Error::new_spanned(
            name,
            "Invalid #[ruma_api] argument with value, expected `header`",
        ));
    }

    *header = Some(value);
    Ok(field_kind)
}

pub(crate) fn is_valid_endpoint_path(string: &str) -> bool {
    string.as_bytes().iter().all(|b| (0x21..=0x7E).contains(b))
}
<|endoftext|>


<commit_before>use std::io::Read;

use crate::common::Lines;
use crate::Solution;

#[derive(Clone, Copy)]
enum Op {
    Addition,
    Multiplication,
}

fn extract_brackets(with_brackets: &str) -> (&str, &str) {
    let mut brackets = 1;

    let mut end = None;

    for (i, c) in with_brackets.chars().enumerate().skip(1) {
        match c {
            '(' => brackets += 1,
            ')' => brackets -= 1,
            _ => {}
        }

        if brackets == 0 {
            end = Some(i);
            break;
        }
    }

    let end = end.expect("Unmatched brackets");
    let next_start = with_brackets.len().min(end + 2);

    (&with_brackets[1..end], &with_brackets[next_start..])
}

fn compute_value(expression: &str) -> u64 {
    let mut remainder = expression;
    let mut value = 0;
    let mut op = None;

    let mut apply_value = |n, op| match op {
        Some(Op::Addition) => value += n,
        Some(Op::Multiplication) => value *= n,
        None => value = n,
    };

    while !remainder.is_empty() {
        let pos = remainder.find(' ');

        let part = if let Some(pos) = pos {
            &remainder[..pos]
        } else {
            remainder
        };

        match part.chars().next().unwrap() {
            '+' => op = Some(Op::Addition),
            '*' => op = Some(Op::Multiplication),
            '(' => {
                let (in_brackets, rest) = extract_brackets(remainder);
                remainder = rest;
                let n = compute_value(in_brackets);

                apply_value(n, op);
                // Skip the remainder update
                continue;
            }
            c if c.is_ascii_digit() => {
                let n = part.parse().unwrap();
                apply_value(n, op);
            }
            _ => panic!("Not a valid expression part {}", part),
        }

        let pos = pos.map(|n| n + 1).unwrap_or_else(|| remainder.len());
        remainder = &remainder[pos..];
    }

    value
}

fn compute_value2(expression: &str) -> u64 {
    let mut remainder = expression;
    let mut value = 0;
    let mut result = 1;
    let mut op = None;

    let mut apply_value = |n, op| match op {
        Some(Op::Addition) => value += n,
        Some(Op::Multiplication) => {
            result *= value;
            value = n;
        }
        None => value = n,
    };

    while !remainder.is_empty() {
        let pos = remainder.find(' ');

        let part = if let Some(pos) = pos {
            &remainder[..pos]
        } else {
            remainder
        };

        match part.chars().next().unwrap() {
            '+' => op = Some(Op::Addition),
            '*' => op = Some(Op::Multiplication),
            '(' => {
                let (in_brackets, rest) = extract_brackets(remainder);
                remainder = rest;
                let n = compute_value2(in_brackets);

                apply_value(n, op);
                // Skip the remainder update
                continue;
            }
            c if c.is_ascii_digit() => {
                let n = part.parse().unwrap();

                apply_value(n, op);
            }
            _ => panic!("Not a valid expression part {}", part),
        }

        let pos = pos.map(|n| n + 1).unwrap_or_else(|| remainder.len());
        remainder = &remainder[pos..];
    }

    result * value
}

#[derive(Default)]
pub struct Day18;

impl Solution for Day18 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        Lines::new(input)
            .map(|l| compute_value(&l))
            .sum::<u64>()
            .to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        Lines::new(input)
            .map(|l| compute_value2(&l))
            .sum::<u64>()
            .to_string()
    }
}

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

    #[test]
    fn sample_part1() {
        assert_eq!(71, compute_value("1 + 2 * 3 + 4 * 5 + 6"));
        assert_eq!(51, compute_value("1 + (2 * 3) + (4 * (5 + 6))"));
        assert_eq!(26, compute_value("2 * 3 + (4 * 5)"));
        assert_eq!(437, compute_value("5 + (8 * 3 + 9 + 3 * 4 * 3)"));
        assert_eq!(
            12240,
            compute_value("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))")
        );
        assert_eq!(
            13632,
            compute_value("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2")
        );
    }

    #[test]
    fn sample_part2() {
        assert_eq!(231, compute_value2("1 + 2 * 3 + 4 * 5 + 6"));
        assert_eq!(51, compute_value2("1 + (2 * 3) + (4 * (5 + 6))"));
        assert_eq!(46, compute_value2("2 * 3 + (4 * 5)"));
        assert_eq!(1445, compute_value2("5 + (8 * 3 + 9 + 3 * 4 * 3)"));
        assert_eq!(
            669060,
            compute_value2("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))")
        );
        assert_eq!(
            23340,
            compute_value2("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2")
        );
    }
}
<commit_msg>Improve code reuse<commit_after>use std::io::Read;

use crate::common::Lines;
use crate::Solution;
#[derive(Clone, Copy)]
enum Op {
    Addition,
    Multiplication,
}

fn extract_part(expression: &str) -> (&str, &str) {
    if expression.starts_with('(') {
        let mut brackets = 1;

        for (end, c) in expression.chars().enumerate().skip(1) {
            match c {
                '(' => brackets += 1,
                ')' => brackets -= 1,
                _ => {}
            }

            if brackets == 0 {
                return (
                    // Include the opening bracket for easier detection
                    &expression[..end],
                    expression.get((end + 2)..).unwrap_or(""),
                );
            }
        }

        panic!("Unmatched brackets: {}", expression);
    } else if let Some(pos) = expression.find(' ') {
        (
            &expression[..pos],
            expression.get((pos + 1)..).unwrap_or(""),
        )
    } else {
        (expression, "")
    }
}

fn compute_value(expression: &str) -> u64 {
    let mut remainder = expression;
    let mut value = 0;
    let mut op = None;

    while !remainder.is_empty() {
        let (part, rest) = extract_part(remainder);
        remainder = rest;

        let n = match part.chars().next().unwrap() {
            '+' => {
                op = Some(Op::Addition);
                continue;
            }
            '*' => {
                op = Some(Op::Multiplication);
                continue;
            }
            '(' => compute_value(&part[1..]),
            _ => part.parse().unwrap(),
        };

        match op {
            Some(Op::Addition) => value += n,
            Some(Op::Multiplication) => value *= n,
            None => value = n,
        }
    }

    value
}

fn compute_value2(expression: &str) -> u64 {
    let mut remainder = expression;
    let mut value = 0;
    let mut result = 1;
    let mut op = None;

    while !remainder.is_empty() {
        let (part, rest) = extract_part(remainder);
        remainder = rest;

        let n = match part.chars().next().unwrap() {
            '+' => {
                op = Some(Op::Addition);
                continue;
            }
            '*' => {
                op = Some(Op::Multiplication);
                continue;
            }
            '(' => compute_value2(&part[1..]),
            _ => part.parse().unwrap(),
        };

        match op {
            Some(Op::Addition) => value += n,
            Some(Op::Multiplication) => {
                result *= value;
                value = n;
            }
            None => value = n,
        }
    }

    result * value
}

#[derive(Default)]
pub struct Day18;

impl Solution for Day18 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        Lines::new(input)
            .map(|l| compute_value(&l))
            .sum::<u64>()
            .to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        Lines::new(input)
            .map(|l| compute_value2(&l))
            .sum::<u64>()
            .to_string()
    }
}

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

    #[test]
    fn sample_part1() {
        assert_eq!(71, compute_value("1 + 2 * 3 + 4 * 5 + 6"));
        assert_eq!(51, compute_value("1 + (2 * 3) + (4 * (5 + 6))"));
        assert_eq!(26, compute_value("2 * 3 + (4 * 5)"));
        assert_eq!(437, compute_value("5 + (8 * 3 + 9 + 3 * 4 * 3)"));
        assert_eq!(
            12240,
            compute_value("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))")
        );
        assert_eq!(
            13632,
            compute_value("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2")
        );
    }

    #[test]
    fn sample_part2() {
        assert_eq!(231, compute_value2("1 + 2 * 3 + 4 * 5 + 6"));
        assert_eq!(51, compute_value2("1 + (2 * 3) + (4 * (5 + 6))"));
        assert_eq!(46, compute_value2("2 * 3 + (4 * 5)"));
        assert_eq!(1445, compute_value2("5 + (8 * 3 + 9 + 3 * 4 * 3)"));
        assert_eq!(
            669060,
            compute_value2("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))")
        );
        assert_eq!(
            23340,
            compute_value2("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2")
        );
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::ops::RangeInclusive;

use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::IResult;

use crate::common::read_input;

#[inline]
fn solve_quadratic(a: f64, b: f64, c: f64) -> Option<f64> {
    let d = b * b - 4. * a * c;

    if d < 0. {
        None
    } else {
        // Don't care about the smaller solution due to problem statement
        if a > 0. {
            Some((-b + d.sqrt()) / 2. / a)
        } else {
            Some((-b - d.sqrt()) / 2. / a)
        }
    }
}

fn position(initial: i32, time: i32) -> i32 {
    time * (2 * initial - time + 1) / 2
}

fn find_hit(initial: i32, range: &RangeInclusive<i32>) -> impl Iterator<Item = i32> + '_ {
    // y position at time x: f(x) = x * (1 + initial + initial - x) / 2
    //                            = -1/2x^2 + (initial + 0.5)x
    //
    // to hit, find x := (max(box) + min(box)) / 2 = f(x)
    //                                             = -1/2x^2 + (initial + 0.5)x
    // -1/2x^2 + (initial + 0.5)x - (max(box) + min(box)) / 2 = 0
    let middle = (*range.start() + *range.end()) as f64 / 2.;
    let b = initial as f64 + 0.5;
    let hit = if let Some(hit) = solve_quadratic(-0.5, b, -middle) {
        hit as i32
    } else {
        -1
    };

    (0..=hit)
        .rev()
        .take_while(move |&n| range.contains(&position(initial, n)))
        .chain(((hit + 1)..).take_while(move |&n| range.contains(&position(initial, n))))
}

fn find_speed(x: i32, range: &RangeInclusive<i32>) -> Option<(i32, i32)> {
    if *range.end() <= position(x, x) {
        // Can and should come to a full stop
        let max = solve_quadratic(0.5, 0.5, -*range.end() as f64)? as i32;

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n)))
            .last()?;

        Some((min, max))
    } else {
        // Might hit the target at speed
        let max = (x * x + 2 * *range.end() - x) / (2 * x);

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n.min(x))))
            .last()?;

        Some((min, max))
    }
}

fn parse_range(input: &[u8]) -> IResult<&[u8], RangeInclusive<i32>> {
    use nom::character::complete::i32;

    map(separated_pair(i32, tag(".."), i32), |(start, end)| {
        start..=end
    })(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], (RangeInclusive<i32>, RangeInclusive<i32>)> {
    preceded(
        tag("target area: x="),
        separated_pair(parse_range, tag(", y="), parse_range),
    )(input)
}

pub fn part1(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let check_value =
        |y_speed| find_hit(y_speed, &y_range).any(|time| find_speed(time, &x_range).is_some());

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (0..y_max)
        .rev()
        .find(|&speed| check_value(speed))
        .map(|speed| position(speed, speed))
        .unwrap()
        .to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let num_options = |y_speed| {
        find_hit(y_speed, &y_range)
            .filter_map(|time| find_speed(time, &x_range))
            .reduce(|(a_min, a_max), (b_min, b_max)| (a_min.min(b_min), a_max.max(b_max)))
            .map(|(min, max)| max - min + 1)
            .unwrap_or(0)
    };

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (-y_max..y_max).map(num_options).sum::<i32>().to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"target area: x=20..30, y=-10..-5";

    #[test]
    fn test_find_hit() {
        assert_eq!(find_hit(2, &(-10..=-5)).collect::<Vec<_>>(), vec![7]);
        assert_eq!(find_hit(3, &(-10..=-5)).collect::<Vec<_>>(), vec![9]);
        assert_eq!(find_hit(0, &(-10..=-5)).collect::<Vec<_>>(), vec![4, 5]);
    }

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 45);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 112);
    }
}
<commit_msg>Simplify y-hit iterator<commit_after>use std::io::Read;
use std::ops::RangeInclusive;

use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::IResult;

use crate::common::read_input;

#[inline]
fn solve_quadratic(a: f64, b: f64, c: f64) -> Option<f64> {
    let d = b * b - 4. * a * c;

    if d < 0. {
        None
    } else {
        // Don't care about the smaller solution due to problem statement
        if a > 0. {
            Some((-b + d.sqrt()) / 2. / a)
        } else {
            Some((-b - d.sqrt()) / 2. / a)
        }
    }
}

fn position(initial: i32, time: i32) -> i32 {
    time * (2 * initial - time + 1) / 2
}

fn find_hit(initial: i32, range: &RangeInclusive<i32>) -> impl Iterator<Item = i32> + '_ {
    // y position at time x: f(x) = x * (1 + initial + initial - x) / 2
    //                            = -1/2x^2 + (initial + 0.5)x
    //
    // to hit, find x := (max(box) + min(box)) / 2 = f(x)
    //                                             = -1/2x^2 + (initial + 0.5)x
    // -1/2x^2 + (initial + 0.5)x - (max(box) + min(box)) / 2 = 0
    let middle = *range.start() as f64;
    let b = initial as f64 + 0.5;
    let hit = if let Some(hit) = solve_quadratic(-0.5, b, -middle) {
        hit as i32
    } else {
        // Cause an empty range
        -1
    };

    (0..=hit)
        .rev()
        .take_while(move |&n| range.contains(&position(initial, n)))
}

fn find_speed(x: i32, range: &RangeInclusive<i32>) -> Option<(i32, i32)> {
    if *range.end() <= position(x, x) {
        // Can and should come to a full stop
        let max = solve_quadratic(0.5, 0.5, -*range.end() as f64)? as i32;

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n)))
            .last()?;

        Some((min, max))
    } else {
        // Might hit the target at speed
        let max = (x * x + 2 * *range.end() - x) / (2 * x);

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n.min(x))))
            .last()?;

        Some((min, max))
    }
}

fn parse_range(input: &[u8]) -> IResult<&[u8], RangeInclusive<i32>> {
    use nom::character::complete::i32;

    map(separated_pair(i32, tag(".."), i32), |(start, end)| {
        start..=end
    })(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], (RangeInclusive<i32>, RangeInclusive<i32>)> {
    preceded(
        tag("target area: x="),
        separated_pair(parse_range, tag(", y="), parse_range),
    )(input)
}

pub fn part1(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let check_value =
        |y_speed| find_hit(y_speed, &y_range).any(|time| find_speed(time, &x_range).is_some());

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (0..y_max)
        .rev()
        .find(|&speed| check_value(speed))
        .map(|speed| position(speed, speed))
        .unwrap()
        .to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let num_options = |y_speed| {
        find_hit(y_speed, &y_range)
            .filter_map(|time| find_speed(time, &x_range))
            .reduce(|(a_min, a_max), (b_min, b_max)| (a_min.min(b_min), a_max.max(b_max)))
            .map(|(min, max)| max - min + 1)
            .unwrap_or(0)
    };

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (-y_max..y_max).map(num_options).sum::<i32>().to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"target area: x=20..30, y=-10..-5";

    #[test]
    fn test_find_hit() {
        assert_eq!(find_hit(2, &(-10..=-5)).collect::<Vec<_>>(), vec![7]);
        assert_eq!(find_hit(3, &(-10..=-5)).collect::<Vec<_>>(), vec![9]);
        assert_eq!(find_hit(0, &(-10..=-5)).collect::<Vec<_>>(), vec![5, 4]);
    }

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 45);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 112);
    }
}
<|endoftext|>


<commit_before>macro_rules! quote {
    () => (::proc_macro::TokenStream::new());
    ($($x:tt)*) => (quote_internal!([] $($x)*));
}

macro_rules! quote_internal {
    // Base case
    ([]) => (::proc_macro::TokenStream::new());
    ([$($expanded:tt)*]) => {
        [$($expanded)*].iter().cloned().collect::<::proc_macro::TokenStream>()
    };

    // Symbols and symbol pairs
    ([$($expanded:tt)*] :: $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] .. $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('.', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('.', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] : $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] = $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('=', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] ; $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] , $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(',', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] . $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('.', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] & $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('&', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] << $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('<', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('<', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] < $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('<', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] >> $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('>', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('>', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] > $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('>', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] -> $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('-', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('>', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] ? $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('?', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] '_' $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('_', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] | $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('|', ::proc_macro::Spacing::Alone)
        )),
    ] $($tail)*));

    // Identifier
    ([$($expanded:tt)*] $i:ident $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Ident::new(stringify!($i), ::proc_macro::Span::mixed_site())
        )),
    ] $($tail)*));

    // Literal
    ([$($expanded:tt)*] $l:literal $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Literal::string($l)
        )),
    ] $($tail)*));

    // Lifetime
    ([$($expanded:tt)*] $l:lifetime $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('\'', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Ident::new(
                stringify!($l).trim_start_matches(|c: char| c == '\''),
                ::proc_macro::Span::mixed_site())
        )),
    ] $($tail)*));

    // Groups
    ([$($expanded:tt)*] ($($inner:tt)*) $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(::proc_macro::Group::new(
            ::proc_macro::Delimiter::Parenthesis,
            quote_internal!([] $($inner)*))
        )),
    ] $($tail)*));
    ([$($expanded:tt)*] {$($inner:tt)*} $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(::proc_macro::Group::new(
            ::proc_macro::Delimiter::Brace,
            quote_internal!([] $($inner)*)
        ))),
    ] $($tail)*));
    ([$($expanded:tt)*] [$($inner:tt)*] $($tail:tt)*) => (quote_internal!([$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(::proc_macro::Group::new(
            ::proc_macro::Delimiter::Bracket,
            quote_internal!([] $($inner)*)
        ))),
    ] $($tail)*));

    // Interpolated values
    ([$($expanded:tt)*] #($e:expr) $($tail:tt)*) => (quote_internal!([$($expanded)*
        $crate::to_tokens::ToTokens::into_token_stream($e),
    ] $($tail)*));
}
<commit_msg>Put `quote_internal`'s accumulator at the end. (#453)<commit_after>macro_rules! quote {
    () => (::proc_macro::TokenStream::new());
    ($($x:tt)*) => (quote_inner!([$($x)*] -> []));
}

macro_rules! quote_inner {
    // Base case
    ([] -> []) => (::proc_macro::TokenStream::new());
    ([] -> [$($accum:tt)*]) => {
        [$($accum)*].iter().cloned().collect::<::proc_macro::TokenStream>()
    };

    // Symbols and symbol pairs
    ([:: $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([.. $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('.', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('.', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([: $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([= $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('=', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([; $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([, $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new(',', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([. $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('.', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([& $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('&', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([<< $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('<', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('<', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([< $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('<', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([>> $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('>', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('>', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([> $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('>', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([-> $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('-', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('>', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([? $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('?', ::proc_macro::Spacing::Alone)
        )),
    ]));
    ([| $($tail:tt)*] -> [$($accum:tt)*] ) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('|', ::proc_macro::Spacing::Alone)
        )),
    ]));

    // Identifier
    ([$i:ident $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Ident::new(stringify!($i), ::proc_macro::Span::mixed_site())
        )),
    ]));

    // Literal
    ([$l:literal $($tail:tt)*] -> [$($expanded:tt)*]) => (quote_inner!([$($tail)*] -> [$($expanded)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Literal::string($l)
        )),
    ]));

    // Lifetime
    ([$l:lifetime $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Punct::new('\'', ::proc_macro::Spacing::Joint)
        )),
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(
            ::proc_macro::Ident::new(
                stringify!($l).trim_start_matches(|c: char| c == '\''),
                ::proc_macro::Span::mixed_site())
        )),
    ]));

    // Groups
    ([($($inner:tt)*) $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(::proc_macro::Group::new(
            ::proc_macro::Delimiter::Parenthesis,
            quote_inner!([$($inner)*] -> []))
        )),
    ]));
    ([{$($inner:tt)*} $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(::proc_macro::Group::new(
            ::proc_macro::Delimiter::Brace,
            quote_inner!([$($inner)*] -> [])
        ))),
    ]));
    ([[$($inner:tt)*] $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        ::proc_macro::TokenStream::from(::proc_macro::TokenTree::from(::proc_macro::Group::new(
            ::proc_macro::Delimiter::Bracket,
            quote_inner!([$($inner)*] -> [])
        ))),
    ]));

    // Interpolated values
    ([#($e:expr) $($tail:tt)*] -> [$($accum:tt)*]) => (quote_inner!([$($tail)*] -> [$($accum)*
        $crate::to_tokens::ToTokens::into_token_stream($e),
    ]));
}
<|endoftext|>


<commit_before>extern crate translator;

extern crate piston;
extern crate piston_window;
#[macro_use]
extern crate conrod;
extern crate find_folder;

use translator::Translator;

use piston_window::{PistonWindow, WindowSettings, Glyphs, UpdateEvent};
use piston::event_loop::EventLoop;
use conrod::{Theme, Ui, Canvas, TextBox, Widget, Sizeable, Positionable};
use conrod::color::{self, Colorable};

fn main() {
    let window: PistonWindow = WindowSettings::new("Hello Conrod", [800, 600])
                                   .exit_on_esc(true)
                                   .vsync(true)
                                   .build()
                                   .unwrap();

    let mut ui = {
        let assets_path = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
        let font_path = assets_path.join("NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
        Ui::new(glyph_cache.unwrap(), theme)
    };

    let mut original_text = "".to_owned();
    let mut translated_text = "".to_owned();

    let translator = translator::Translator::new();

    for w in window.ups(60) {
        ui.handle_event(&w);

        w.update(|_| {
            ui.set_widgets(|ui| {
                let background_color = color::rgb(0.2, 0.35, 0.45);

                // TODO: Use frame width for text boxes.
                Canvas::new()
                    .pad(30.)
                    .color(background_color)
                    .scroll_kids()
                    .set(CANVAS, ui);

                TextBox::new(&mut original_text)
                    .font_size(20)
                    .w_h(420.0, 40.0)
                    .mid_left_of(CANVAS)
                    .color(background_color.invert())
                    .react(|_string: &mut String| {})
                    .set(INPUT_TEXT, ui);

                TextBox::new(&mut translated_text)
                    .font_size(20)
                    .w_h(420.0, 40.0)
                    .down_from(INPUT_TEXT, 45.0)
                    .color(background_color.invert())
                    .react(|_string: &mut String| {})
                    .set(OUTPUT_TEXT, ui);
            })
        });

        w.draw_2d(|context, graphic| ui.draw_if_changed(context, graphic));

        translated_text = translator.translate(&original_text);
    }
}

widget_ids! {
    CANVAS,
    INPUT_TEXT,
    OUTPUT_TEXT,
}
<commit_msg>Unused import (now used)<commit_after>extern crate translator;

extern crate piston;
extern crate piston_window;
#[macro_use]
extern crate conrod;
extern crate find_folder;

use translator::Translator;

use piston_window::{PistonWindow, WindowSettings, Glyphs, UpdateEvent};
use piston::event_loop::EventLoop;
use conrod::{Theme, Ui, Canvas, TextBox, Widget, Sizeable, Positionable};
use conrod::color::{self, Colorable};

fn main() {
    let window: PistonWindow = WindowSettings::new("Hello Conrod", [800, 600])
                                   .exit_on_esc(true)
                                   .vsync(true)
                                   .build()
                                   .unwrap();

    let mut ui = {
        let assets_path = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
        let font_path = assets_path.join("NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
        Ui::new(glyph_cache.unwrap(), theme)
    };

    let mut original_text = "".to_owned();
    let mut translated_text = "".to_owned();

    let translator = Translator::new();

    for w in window.ups(60) {
        ui.handle_event(&w);

        w.update(|_| {
            ui.set_widgets(|ui| {
                let background_color = color::rgb(0.2, 0.35, 0.45);

                // TODO: Use frame width for text boxes.
                Canvas::new()
                    .pad(30.)
                    .color(background_color)
                    .scroll_kids()
                    .set(CANVAS, ui);

                TextBox::new(&mut original_text)
                    .font_size(20)
                    .w_h(420.0, 40.0)
                    .mid_left_of(CANVAS)
                    .color(background_color.invert())
                    .react(|_string: &mut String| {})
                    .set(INPUT_TEXT, ui);

                TextBox::new(&mut translated_text)
                    .font_size(20)
                    .w_h(420.0, 40.0)
                    .down_from(INPUT_TEXT, 45.0)
                    .color(background_color.invert())
                    .react(|_string: &mut String| {})
                    .set(OUTPUT_TEXT, ui);
            })
        });

        w.draw_2d(|context, graphic| ui.draw_if_changed(context, graphic));

        translated_text = translator.translate(&original_text);
    }
}

widget_ids! {
    CANVAS,
    INPUT_TEXT,
    OUTPUT_TEXT,
}
<|endoftext|>


<commit_before>use std::ptr;

use super::{ByteBuf, Block};

enum Off {
    Left(usize),
    Right(usize),
}

pub struct Window<'a> {
    blocks: &'a [Block],
    off: Off,
    size: usize,
}

impl<'a> Window<'a> {
    pub fn as_bytes(&self) -> Option<&[u8]> {
        if self.size == 0 {
            return Some(&[]);
        }
        match self.blocks.len() == 1 {
            true => {
                let b = unsafe { self.blocks.get_unchecked(0) };
                let bytes = match self.off {
                    Off::Left(off) => b.as_bytes_range(b.read_pos() + off, self.size),
                    Off::Right(off) => b.as_bytes_range(b.write_pos() - off - self.size, self.size),
                };
                Some(bytes)
            }
            false => None,
        }
    }

    #[inline]
    pub fn to_bytes(self) -> Vec<u8> {
        match self.off {
            Off::Left(off) => Self::to_bytes_left(self.blocks, off, self.size),
            Off::Right(off) => Self::to_bytes_right(self.blocks, off, self.size),
        }
    }

    fn to_bytes_left(blocks: &'a [Block], mut off: usize, mut size: usize) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(size);
        unsafe { bytes.set_len(size) }
        let mut p_dst = bytes.as_mut_ptr();
        for block in blocks {
            off = block.read_pos() + off;
            let len = block.write_pos() - off;
            let p_src = block.ptr_at(off);
            if len >= size {
                unsafe {
                    ptr::copy_nonoverlapping(p_src, p_dst, size);
                }
                break;
            } else {
                unsafe {
                    ptr::copy_nonoverlapping(p_src, p_dst, len);
                    p_dst = p_dst.offset(len as isize);
                }
                size -= len;
                off = 0;
            }
        }
        bytes
    }

    fn to_bytes_right(blocks: &'a [Block], mut off: usize, mut size: usize) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(size);
        unsafe { bytes.set_len(size) }
        let mut p_dst = unsafe { bytes.as_mut_ptr().offset(size as isize) };
        for block in blocks.iter().rev() {
            off = block.write_pos() - off;
            let len = off - block.read_pos();
            if len >= size {
                let p_src = block.ptr_at(off - size);
                unsafe {
                    p_dst = p_dst.offset(-(size as isize));
                    ptr::copy_nonoverlapping(p_src, p_dst, size);
                }
                break;
            } else {
                let p_src = block.ptr_at(block.read_pos());
                unsafe {
                    p_dst = p_dst.offset(-(len as isize));
                    ptr::copy_nonoverlapping(p_src, p_dst, len);
                }
                size -= len;
                off = 0;
            }
        }
        bytes
    }

    #[inline]
    fn from_left(blocks: &'a [Block], off: usize, size: usize) -> Self {
        Window {
            blocks,
            off: Off::Left(off),
            size,
        }
    }

    #[inline]
    fn from_right(blocks: &'a [Block], off: usize, size: usize) -> Self {
        Window {
            blocks,
            off: Off::Right(off),
            size,
        }
    }

    #[inline]
    fn eq_left(&self, mut off: usize, mut other: &[u8]) -> bool {
        if self.size == other.len() {
            for block in self.blocks {
                off += block.read_pos();
                let len = block.write_pos() - off;
                if len >= other.len() {
                    let bytes = block.as_bytes_range(off, other.len());
                    return bytes == other;
                }
                let (left, right) = other.split_at(len);
                if block.as_bytes_range(off, len) != left {
                    return false;
                }
                other = right;
                off = 0;
            }
        }
        false
    }

    #[inline]
    fn eq_right(&self, mut off: usize, mut other: &[u8]) -> bool {
        if self.size == other.len() {
            for block in self.blocks.iter().rev() {
                off = block.write_pos() - off;
                let len = off - block.read_pos();
                if len >= other.len() {
                    let bytes = block.as_bytes_range(off - other.len(), other.len());
                    return bytes == other;
                }
                let (left, right) = other.split_at(other.len() - len);
                if block.as_bytes_range(block.read_pos(), len) != right {
                    return false;
                }
                other = left;
                off = 0;
            }
        }
        false
    }
}

impl<'a> PartialEq<&'a [u8]> for Window<'a> {
    fn eq(&self, other: &&[u8]) -> bool {
        match self.off {
            Off::Left(off) => self.eq_left(off, *other),
            Off::Right(off) => self.eq_right(off, *other),
        }
    }
}

impl<'a> PartialEq<Window<'a>> for &'a [u8] {
    fn eq(&self, other: &Window) -> bool {
        match other.off {
            Off::Left(off) => other.eq_left(off, self),
            Off::Right(off) => other.eq_right(off, self),
        }
    }
}

pub struct Windows<'a> {
    blocks: &'a [Block],
    off: usize,
    roff: usize,
    len: usize,
    size: usize, // window size
}

pub fn windows<'a>(buf: &'a ByteBuf, size: usize) -> Windows<'a> {
    let blocks: &[Block] = &buf.blocks[buf.idx..];
    let mut len = blocks.iter().fold(0, |n, b| n + b.len());
    len = if len >= size { len - size + 1 } else { 0 };
    Windows {
        blocks,
        off: 0,
        roff: 0,
        len,
        size,
    }
}

impl<'a> Iterator for Windows<'a> {
    type Item = Window<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.len == 0 {
            return None;
        }
        self.len -= 1;
        loop {
            match self.blocks.first() {
                Some(block) => {
                    if block.len() > self.off {
                        let window = Window::from_left(self.blocks, self.off, self.size);
                        self.off += 1;
                        return Some(window);
                    }
                }
                None => ::unreachable(),
            }
            self.blocks = &self.blocks[1..];
            self.off = 0;
        }
    }

    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
        if n >= self.len {
            self.len = 0;
            return None;
        }
        let mut i = 0;
        for block in self.blocks {
            if n < block.len() {
                break;
            }
            n -= block.len();
            i += 1;
        }
        self.blocks = &self.blocks[i..];
        self.off = n;
        self.len -= n;
        self.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len, Some(self.len))
    }
}

impl<'a> DoubleEndedIterator for Windows<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.len == 0 {
            return None;
        }
        self.len -= 1;
        loop {
            match self.blocks.last() {
                Some(block) => {
                    if block.len() > self.roff {
                        let window = Window::from_right(self.blocks, self.roff, self.size);
                        self.roff += 1;
                        return Some(window);
                    }
                }
                None => ::unreachable(),
            }
            self.blocks = &self.blocks[..self.blocks.len() - 1];
            self.roff = 0;
        }
    }
}

impl<'a> ExactSizeIterator for Windows<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.len
    }
}
<commit_msg>Don't consume self for Window.to_bytes<commit_after>use std::ptr;

use super::{ByteBuf, Block};

enum Off {
    Left(usize),
    Right(usize),
}

pub struct Window<'a> {
    blocks: &'a [Block],
    off: Off,
    size: usize,
}

impl<'a> Window<'a> {
    pub fn as_bytes(&self) -> Option<&[u8]> {
        if self.size == 0 {
            return Some(&[]);
        }
        match self.blocks.len() == 1 {
            true => {
                let b = unsafe { self.blocks.get_unchecked(0) };
                let bytes = match self.off {
                    Off::Left(off) => b.as_bytes_range(b.read_pos() + off, self.size),
                    Off::Right(off) => b.as_bytes_range(b.write_pos() - off - self.size, self.size),
                };
                Some(bytes)
            }
            false => None,
        }
    }

    #[inline]
    pub fn to_bytes(&self) -> Vec<u8> {
        match self.off {
            Off::Left(off) => Self::to_bytes_left(self.blocks, off, self.size),
            Off::Right(off) => Self::to_bytes_right(self.blocks, off, self.size),
        }
    }

    fn to_bytes_left(blocks: &'a [Block], mut off: usize, mut size: usize) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(size);
        unsafe { bytes.set_len(size) }
        let mut p_dst = bytes.as_mut_ptr();
        for block in blocks {
            off = block.read_pos() + off;
            let len = block.write_pos() - off;
            let p_src = block.ptr_at(off);
            if len >= size {
                unsafe {
                    ptr::copy_nonoverlapping(p_src, p_dst, size);
                }
                break;
            } else {
                unsafe {
                    ptr::copy_nonoverlapping(p_src, p_dst, len);
                    p_dst = p_dst.offset(len as isize);
                }
                size -= len;
                off = 0;
            }
        }
        bytes
    }

    fn to_bytes_right(blocks: &'a [Block], mut off: usize, mut size: usize) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(size);
        unsafe { bytes.set_len(size) }
        let mut p_dst = unsafe { bytes.as_mut_ptr().offset(size as isize) };
        for block in blocks.iter().rev() {
            off = block.write_pos() - off;
            let len = off - block.read_pos();
            if len >= size {
                let p_src = block.ptr_at(off - size);
                unsafe {
                    p_dst = p_dst.offset(-(size as isize));
                    ptr::copy_nonoverlapping(p_src, p_dst, size);
                }
                break;
            } else {
                let p_src = block.ptr_at(block.read_pos());
                unsafe {
                    p_dst = p_dst.offset(-(len as isize));
                    ptr::copy_nonoverlapping(p_src, p_dst, len);
                }
                size -= len;
                off = 0;
            }
        }
        bytes
    }

    #[inline]
    fn from_left(blocks: &'a [Block], off: usize, size: usize) -> Self {
        Window {
            blocks,
            off: Off::Left(off),
            size,
        }
    }

    #[inline]
    fn from_right(blocks: &'a [Block], off: usize, size: usize) -> Self {
        Window {
            blocks,
            off: Off::Right(off),
            size,
        }
    }

    #[inline]
    fn eq_left(&self, mut off: usize, mut other: &[u8]) -> bool {
        if self.size == other.len() {
            for block in self.blocks {
                off += block.read_pos();
                let len = block.write_pos() - off;
                if len >= other.len() {
                    let bytes = block.as_bytes_range(off, other.len());
                    return bytes == other;
                }
                let (left, right) = other.split_at(len);
                if block.as_bytes_range(off, len) != left {
                    return false;
                }
                other = right;
                off = 0;
            }
        }
        false
    }

    #[inline]
    fn eq_right(&self, mut off: usize, mut other: &[u8]) -> bool {
        if self.size == other.len() {
            for block in self.blocks.iter().rev() {
                off = block.write_pos() - off;
                let len = off - block.read_pos();
                if len >= other.len() {
                    let bytes = block.as_bytes_range(off - other.len(), other.len());
                    return bytes == other;
                }
                let (left, right) = other.split_at(other.len() - len);
                if block.as_bytes_range(block.read_pos(), len) != right {
                    return false;
                }
                other = left;
                off = 0;
            }
        }
        false
    }
}

impl<'a> PartialEq<&'a [u8]> for Window<'a> {
    fn eq(&self, other: &&[u8]) -> bool {
        match self.off {
            Off::Left(off) => self.eq_left(off, *other),
            Off::Right(off) => self.eq_right(off, *other),
        }
    }
}

impl<'a> PartialEq<Window<'a>> for &'a [u8] {
    fn eq(&self, other: &Window) -> bool {
        match other.off {
            Off::Left(off) => other.eq_left(off, self),
            Off::Right(off) => other.eq_right(off, self),
        }
    }
}

pub struct Windows<'a> {
    blocks: &'a [Block],
    off: usize,
    roff: usize,
    len: usize,
    size: usize, // window size
}

pub fn windows<'a>(buf: &'a ByteBuf, size: usize) -> Windows<'a> {
    let blocks: &[Block] = &buf.blocks[buf.idx..];
    let mut len = blocks.iter().fold(0, |n, b| n + b.len());
    len = if len >= size { len - size + 1 } else { 0 };
    Windows {
        blocks,
        off: 0,
        roff: 0,
        len,
        size,
    }
}

impl<'a> Iterator for Windows<'a> {
    type Item = Window<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.len == 0 {
            return None;
        }
        self.len -= 1;
        loop {
            match self.blocks.first() {
                Some(block) => {
                    if block.len() > self.off {
                        let window = Window::from_left(self.blocks, self.off, self.size);
                        self.off += 1;
                        return Some(window);
                    }
                }
                None => ::unreachable(),
            }
            self.blocks = &self.blocks[1..];
            self.off = 0;
        }
    }

    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
        if n >= self.len {
            self.len = 0;
            return None;
        }
        let mut i = 0;
        for block in self.blocks {
            if n < block.len() {
                break;
            }
            n -= block.len();
            i += 1;
        }
        self.blocks = &self.blocks[i..];
        self.off = n;
        self.len -= n;
        self.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len, Some(self.len))
    }
}

impl<'a> DoubleEndedIterator for Windows<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.len == 0 {
            return None;
        }
        self.len -= 1;
        loop {
            match self.blocks.last() {
                Some(block) => {
                    if block.len() > self.roff {
                        let window = Window::from_right(self.blocks, self.roff, self.size);
                        self.roff += 1;
                        return Some(window);
                    }
                }
                None => ::unreachable(),
            }
            self.blocks = &self.blocks[..self.blocks.len() - 1];
            self.roff = 0;
        }
    }
}

impl<'a> ExactSizeIterator for Windows<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.len
    }
}
<|endoftext|>


<commit_before>//! HTTP Client
//!
//! There are two levels of APIs provided for construct HTTP clients:
//!
//! - The higher-level [`Client`](Client) type.
//! - The lower-level [`conn`](conn) module.
//!
//! # Client
//!
//! The [`Client`](Client) is the main way to send HTTP requests to a server.
//! The default `Client` provides these things on top of the lower-level API:
//!
//! - A default **connector**, able to resolve hostnames and connect to
//!   destinations over plain-text TCP.
//! - A **pool** of existing connections, allowing better performance when
//!   making multiple requests to the same hostname.
//! - Automatic setting of the `Host` header, based on the request `Uri`.
//! - Automatic request **retries** when a pooled connection is closed by the
//!   server before any bytes have been written.
//!
//! Many of these features can configured, by making use of
//! [`Client::builder`](Client::builder).
//!
//! ## Example
//!
//! For a small example program simply fetching a URL, take a look at the
//! [full client example](https://github.com/hyperium/hyper/blob/master/examples/client.rs).
//!
//! ```
//! use hyper::{body::HttpBody as _, Client, Uri};
//!
//! # #[cfg(feature = "tcp")]
//! # async fn fetch_httpbin() -> hyper::Result<()> {
//! let client = Client::new();
//!
//! // Make a GET /ip to 'http://httpbin.org'
//! let res = client.get(Uri::from_static("http://httpbin.org/ip")).await?;
//!
//! // And then, if the request gets a response...
//! println!("status: {}", res.status());
//!
//! // Concatenate the body stream into a single buffer...
//! let buf = hyper::body::to_bytes(res).await?;
//!
//! println!("body: {:?}", buf);
//! # Ok(())
//! # }
//! # fn main () {}
//! ```

#[cfg(feature = "tcp")]
pub use self::connect::HttpConnector;

pub mod connect;
#[cfg(all(test, feature = "runtime"))]
mod tests;

cfg_feature! {
    #![any(feature = "http1", feature = "http2")]

    pub use self::client::{Builder, Client, ResponseFuture};

    mod client;
    pub mod conn;
    pub(super) mod dispatch;
    mod pool;
    pub mod service;
}
<commit_msg>docs(client): fix missing feature attrs in another doctest<commit_after>//! HTTP Client
//!
//! There are two levels of APIs provided for construct HTTP clients:
//!
//! - The higher-level [`Client`](Client) type.
//! - The lower-level [`conn`](conn) module.
//!
//! # Client
//!
//! The [`Client`](Client) is the main way to send HTTP requests to a server.
//! The default `Client` provides these things on top of the lower-level API:
//!
//! - A default **connector**, able to resolve hostnames and connect to
//!   destinations over plain-text TCP.
//! - A **pool** of existing connections, allowing better performance when
//!   making multiple requests to the same hostname.
//! - Automatic setting of the `Host` header, based on the request `Uri`.
//! - Automatic request **retries** when a pooled connection is closed by the
//!   server before any bytes have been written.
//!
//! Many of these features can configured, by making use of
//! [`Client::builder`](Client::builder).
//!
//! ## Example
//!
//! For a small example program simply fetching a URL, take a look at the
//! [full client example](https://github.com/hyperium/hyper/blob/master/examples/client.rs).
//!
//! ```
//! # #[cfg(all(feature = "tcp", feature = "client", any(feature = "http1", feature = "http2")))]
//! # async fn fetch_httpbin() -> hyper::Result<()> {
//! use hyper::{body::HttpBody as _, Client, Uri};
//!
//! let client = Client::new();
//!
//! // Make a GET /ip to 'http://httpbin.org'
//! let res = client.get(Uri::from_static("http://httpbin.org/ip")).await?;
//!
//! // And then, if the request gets a response...
//! println!("status: {}", res.status());
//!
//! // Concatenate the body stream into a single buffer...
//! let buf = hyper::body::to_bytes(res).await?;
//!
//! println!("body: {:?}", buf);
//! # Ok(())
//! # }
//! # fn main () {}
//! ```

#[cfg(feature = "tcp")]
pub use self::connect::HttpConnector;

pub mod connect;
#[cfg(all(test, feature = "runtime"))]
mod tests;

cfg_feature! {
    #![any(feature = "http1", feature = "http2")]

    pub use self::client::{Builder, Client, ResponseFuture};

    mod client;
    pub mod conn;
    pub(super) mod dispatch;
    mod pool;
    pub mod service;
}
<|endoftext|>


<commit_before>extern crate syn;

use std::env;
use std::fs::{File, create_dir};
use std::io::BufWriter;
use syn::DeriveInput;
use super::representation::Representation;
use super::elm::Module;

pub fn generate_elm(ast: &DeriveInput) {
    let mut path = env::current_dir().unwrap();
    path.push("generated");
    if path.exists() && path.is_file() { panic!("expecting \"generated\" to be a directory"); }
    if !path.exists() { create_dir(path.clone()).expect("problem creating \"generated\" directory") }
    let name = &ast.ident;
    path.push(format!("{}.elm", name));

    let file = File::create(path).unwrap();
    let ref mut w = BufWriter::new(file);

    let m = module_from(ast);

    m.write_representation(w).unwrap();
}

fn module_from(ast: &DeriveInput) -> Module {
    let name = &ast.ident;
    Module::new(name.to_string())
}
<commit_msg>Remove superfluous extern crate definition in submodule<commit_after>use std::env;
use std::fs::{File, create_dir};
use std::io::BufWriter;
use syn::DeriveInput;
use super::representation::Representation;
use super::elm::Module;

pub fn generate_elm(ast: &DeriveInput) {
    let mut path = env::current_dir().unwrap();
    path.push("generated");
    if path.exists() && path.is_file() { panic!("expecting \"generated\" to be a directory"); }
    if !path.exists() { create_dir(path.clone()).expect("problem creating \"generated\" directory") }
    let name = &ast.ident;
    path.push(format!("{}.elm", name));

    let file = File::create(path).unwrap();
    let ref mut w = BufWriter::new(file);

    let m = module_from(ast);

    m.write_representation(w).unwrap();
}

fn module_from(ast: &DeriveInput) -> Module {
    let name = &ast.ident;
    Module::new(name.to_string())
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Rouille developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Evaluates each parameter until one of them evaluates to something else
/// than a 404 error code.
///
/// This macro supposes that each route returns a `Response`.
///
/// # Example
///
/// ```no_run
/// # #[macro_use] extern crate rouille;
/// # fn main() {
/// use rouille::{Request, Response};
///
/// fn handle_request_a(_: &Request) -> Response {
/// # panic!()
///    // ...
/// }
///
/// fn handle_request_b(_: &Request) -> Response {
/// # panic!()
///    // ...
/// }
///
/// fn handle_request_c(_: &Request) -> Response {
/// # panic!()
///    // ...
/// }
///
/// # let request = unsafe { ::std::mem::uninitialized() };
/// // First calls `handle_request_a`. If it returns anything else than a 404 error, then the
/// // `response` will contain the return value.
/// //
/// // Instead if `handle_request_a` returned a 404 error, then `handle_request_b` is tried.
/// // If `handle_request_b` also returns a 404 error, then `handle_request_c` is tried.
/// let response = find_route!(
///     handle_request_a(request),
///     handle_request_b(request),
///     handle_request_c(request)
/// );
/// # }
/// ```
///
#[macro_export]
macro_rules! find_route {
    ($($handler:expr),+) => ({
        let mut response = $crate::Response::empty_404();
        $(
            if response.status_code == 404 {
                response = $handler;
            }
        )+
        response
    });
}
<commit_msg>Unignore the test of find_route!<commit_after>// Copyright (c) 2016 The Rouille developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Evaluates each parameter until one of them evaluates to something else
/// than a 404 error code.
///
/// This macro supposes that each route returns a `Response`.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate rouille;
/// # fn main() {
/// use rouille::{Request, Response};
///
/// fn handle_request_a(_: &Request) -> Response {
/// # panic!()
///    // ...
/// }
///
/// fn handle_request_b(_: &Request) -> Response {
/// # panic!()
///    // ...
/// }
///
/// fn handle_request_c(_: &Request) -> Response {
/// # panic!()
///    // ...
/// }
///
/// # let request = return;
/// // First calls `handle_request_a`. If it returns anything else than a 404 error, then the
/// // `response` will contain the return value.
/// //
/// // Instead if `handle_request_a` returned a 404 error, then `handle_request_b` is tried.
/// // If `handle_request_b` also returns a 404 error, then `handle_request_c` is tried.
/// let response = find_route!(
///     handle_request_a(request),
///     handle_request_b(request),
///     handle_request_c(request)
/// );
/// # }
/// ```
///
#[macro_export]
macro_rules! find_route {
    ($($handler:expr),+) => ({
        let mut response = $crate::Response::empty_404();
        $(
            if response.status_code == 404 {
                response = $handler;
            }
        )+
        response
    });
}
<|endoftext|>


<commit_before>use std::fmt;
use std::cell::Cell;

/// The Memory Management Unit.
/// Provides access to all mapped memory in the system, including I/O and graphics.
pub struct MMU {
    pub loading_bios: Cell<bool>,
    data: [u8; 65536],
}

impl fmt::Debug for MMU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MMU 64k")
    }
}

impl MMU {
    pub fn new() -> MMU {
        MMU {
            loading_bios: Cell::new(true),
            data: [1; 65536],
        }
    }

    /// reads a byte at the memory address specified
    pub fn read_b(&self, addr: u16) -> u8 {
        // when PC first reaches 0x100, the BIOS data is not addressable anymore.
        // using Cell sucks, but this is one of the few cases mentioned by official docs where
        // it is an option. Read is logically an immutable operation, but we need to make the
        // bios unaddressable after its first read.
        if self.loading_bios.get() && addr == 0x0100 {
            self.loading_bios.set(false);
        }

        match addr {
            // bios area, 256B long for regular gameboy.
            0...0x00FF if self.loading_bios.get() => 0,
            // ROM0 area, this is banked memory, it will swap according to selected bank
            0x0000...0x3FFF if !self.loading_bios.get() => 0,
            // ROM1 area, 16kB unbanked data
            0x4000...0x7FFF => 0,
            // Graphics, 8kB VRAM
            0x8000...0x9FFF => 0,
            // Switchable RAM bank, 8kB
            0xA000...0xBFFF => {
                // TODO: handle RAM banks
                self.data[addr as usize]
            }
            // Internal RAM, 8kB
            0xC000...0xDFFF => self.data[addr as usize],
            // Echo of internal RAM, this is less than 8k, up to 0xFDFF,
            0xE000...0xFDFF => self.data[(addr - 0x2000) as usize],
            // Sprite attribute memory, 160B
            0xFE00...0xFE9F => 0,
            // empty
            0xFEA0...0xFEFF | 0xFF4C...0xFF7F => 0,
            // I/O ports
            0xFF00...0xFF4B => 0,
            // More internal RAM
            0xFF80...0xFFFE => 0,
            // Interrupt Enable register
            0xFFFF => 0,

            _ => panic!("tried to write at unkown address: {:4X}", addr)
        }
    }

    pub fn write_b(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }
}
<commit_msg>Changed comment in memory.rs<commit_after>use std::fmt;
use std::cell::Cell;

/// The Memory Management Unit.
/// Provides access to all mapped memory in the system, including I/O and graphics.
pub struct MMU {
    pub loading_bios: Cell<bool>,
    data: [u8; 65536],
}

impl fmt::Debug for MMU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MMU 64k")
    }
}

impl MMU {
    pub fn new() -> MMU {
        MMU {
            loading_bios: Cell::new(true),
            data: [1; 65536],
        }
    }

    /// reads a byte at the memory address specified
    pub fn read_b(&self, addr: u16) -> u8 {
        // when PC first reaches 0x100, the BIOS data is not addressable anymore.
        // using Cell sucks, but this is one of the few cases mentioned by official docs where
        // it is an option. Read is logically an immutable operation, but we need to make the
        // bios unaddressable after its first read.
        if self.loading_bios.get() && addr == 0x0100 {
            self.loading_bios.set(false);
        }

        match addr {
            // bios area, 256B long for regular gameboy.
            0...0x00FF if self.loading_bios.get() => 0,
            // ROM0 area, this is banked memory, it will swap according to selected bank
            0x0000...0x3FFF if !self.loading_bios.get() => 0,
            // ROM1 area, 16kB unbanked data
            0x4000...0x7FFF => 0,
            // Graphics, 8kB VRAM
            0x8000...0x9FFF => 0,
            // Switchable RAM bank, 8kB
            0xA000...0xBFFF => {
                // TODO: handle RAM banks
                self.data[addr as usize]
            }
            // Internal RAM, 8kB
            0xC000...0xDFFF => self.data[addr as usize],
            // Echo of internal RAM, this is less than 8k, up to 0xFDFF,
            0xE000...0xFDFF => self.data[(addr - 0x2000) as usize],
            // Sprite attribute memory, 160B
            0xFE00...0xFE9F => 0,
            // empty
            0xFEA0...0xFEFF | 0xFF4C...0xFF7F => 0,
            // I/O ports
            0xFF00...0xFF4B => 0,
            // High RAM (zero page), used with LDH instructions
            0xFF80...0xFFFE => 0,
            // Interrupt Enable register
            0xFFFF => 0,

            _ => panic!("tried to write at unkown address: {:4X}", addr)
        }
    }

    pub fn write_b(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }
}
<|endoftext|>