<commit_before>use std::mem;

use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens};
use syn::{
    parse_quote, punctuated::Pair, spanned::Spanned, Attribute, Data, DeriveInput, Fields,
    GenericArgument, Path, PathArguments, Type, TypePath,
};

mod wrap_incoming;

use wrap_incoming::Meta;

pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result<TokenStream> {
    let derive_deserialize = if no_deserialize_in_attrs(&input.attrs) {
        TokenStream::new()
    } else {
        quote!(#[derive(ruma_api::exports::serde::Deserialize)])
    };

    let mut fields: Vec<_> = match input.data {
        Data::Enum(_) | Data::Union(_) => {
            panic!("#[derive(Outgoing)] is only supported for structs")
        }
        Data::Struct(s) => match s.fields {
            Fields::Named(fs) => fs.named.into_pairs().map(Pair::into_value).collect(),
            Fields::Unnamed(fs) => fs.unnamed.into_pairs().map(Pair::into_value).collect(),
            Fields::Unit => return Ok(impl_send_recv_incoming_self(input.ident)),
        },
    };

    let mut any_attribute = false;

    for field in &mut fields {
        let mut field_meta = None;

        let mut remaining_attrs = Vec::new();
        for attr in mem::replace(&mut field.attrs, Vec::new()) {
            if let Some(meta) = Meta::from_attribute(&attr)? {
                if field_meta.is_some() {
                    return Err(syn::Error::new_spanned(
                        attr,
                        "duplicate #[wrap_incoming] attribute",
                    ));
                }
                field_meta = Some(meta);
                any_attribute = true;
            } else {
                remaining_attrs.push(attr);
            }
        }
        field.attrs = remaining_attrs;

        if let Some(attr) = field_meta {
            if let Some(type_to_wrap) = attr.type_to_wrap {
                wrap_generic_arg(&type_to_wrap, &mut field.ty, attr.wrapper_type.as_ref())?;
            } else {
                wrap_ty(&mut field.ty, attr.wrapper_type)?;
            }
        }
    }

    if !any_attribute {
        return Ok(impl_send_recv_incoming_self(input.ident));
    }

    let vis = input.vis;
    let doc = format!("'Incoming' variant of [{ty}](struct.{ty}.html).", ty = input.ident);
    let original_ident = input.ident;
    let incoming_ident = Ident::new(&format!("Incoming{}", original_ident), Span::call_site());

    Ok(quote! {
        #[doc = #doc]
        #derive_deserialize
        #vis struct #incoming_ident {
            #(#fields,)*
        }

        impl ruma_api::Outgoing for #original_ident {
            type Incoming = #incoming_ident;
        }
    })
}

fn no_deserialize_in_attrs(attrs: &[Attribute]) -> bool {
    for attr in attrs {
        match &attr.path {
            Path { leading_colon: None, segments }
                if segments.len() == 1 && segments[0].ident == "incoming_no_deserialize" =>
            {
                return true
            }
            _ => {}
        }
    }

    false
}

fn impl_send_recv_incoming_self(ident: Ident) -> TokenStream {
    quote! {
        impl ruma_api::Outgoing for #ident {
            type Incoming = Self;
        }
    }
}

fn wrap_ty(ty: &mut Type, path: Option<Path>) -> syn::Result<()> {
    if let Some(wrap_ty) = path {
        *ty = parse_quote!(#wrap_ty<#ty>);
    } else {
        match ty {
            Type::Path(TypePath { path, .. }) => {
                let ty_ident = &mut path.segments.last_mut().unwrap().ident;
                let ident = Ident::new(&format!("Incoming{}", ty_ident), Span::call_site());
                *ty_ident = parse_quote!(#ident);
            }
            _ => return Err(syn::Error::new_spanned(ty, "Can't wrap this type")),
        }
    }

    Ok(())
}

fn wrap_generic_arg(type_to_wrap: &Type, of: &mut Type, with: Option<&Path>) -> syn::Result<()> {
    let mut span = None;
    wrap_generic_arg_impl(type_to_wrap, of, with, &mut span)?;

    if span.is_some() {
        Ok(())
    } else {
        Err(syn::Error::new_spanned(
            of,
            format!(
                "Couldn't find generic argument `{}` in this type",
                type_to_wrap.to_token_stream()
            ),
        ))
    }
}

fn wrap_generic_arg_impl(
    type_to_wrap: &Type,
    of: &mut Type,
    with: Option<&Path>,
    span: &mut Option<Span>,
) -> syn::Result<()> {
    // TODO: Support things like array types?
    let ty_path = match of {
        Type::Path(TypePath { path, .. }) => path,
        _ => return Ok(()),
    };

    let args = match &mut ty_path.segments.last_mut().unwrap().arguments {
        PathArguments::AngleBracketed(ab) => &mut ab.args,
        _ => return Ok(()),
    };

    for arg in args.iter_mut() {
        let ty = match arg {
            GenericArgument::Type(ty) => ty,
            _ => continue,
        };

        if ty == type_to_wrap {
            if let Some(s) = span {
                let mut error = syn::Error::new(
                    *s,
                    format!(
                        "`{}` found multiple times, this is not currently supported",
                        type_to_wrap.to_token_stream()
                    ),
                );
                error.combine(syn::Error::new_spanned(ty, "second occurrence"));
                return Err(error);
            }

            *span = Some(ty.span());

            if let Some(wrapper_type) = with {
                *ty = parse_quote!(#wrapper_type<#ty>);
            } else if let Type::Path(TypePath { path, .. }) = ty {
                let ty_ident = &mut path.segments.last_mut().unwrap().ident;
                let ident = Ident::new(&format!("Incoming{}", ty_ident), Span::call_site());
                *ty_ident = parse_quote!(#ident);
            } else {
                return Err(syn::Error::new_spanned(ty, "Can't wrap this type"));
            }
        } else {
            wrap_generic_arg_impl(type_to_wrap, ty, with, span)?;
        }
    }

    Ok(())
}
<commit_msg>Error when derive(Outgoing) is used on a type with generics<commit_after>use std::mem;

use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens};
use syn::{
    parse_quote, punctuated::Pair, spanned::Spanned, Attribute, Data, DeriveInput, Fields,
    GenericArgument, Path, PathArguments, Type, TypePath,
};

mod wrap_incoming;

use wrap_incoming::Meta;

pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result<TokenStream> {
    if !input.generics.params.is_empty() {
        return Err(syn::Error::new_spanned(
            input.generics,
            "derive(Outgoing) doesn't currently support types with generics!",
        ));
    }

    let derive_deserialize = if no_deserialize_in_attrs(&input.attrs) {
        TokenStream::new()
    } else {
        quote!(#[derive(ruma_api::exports::serde::Deserialize)])
    };

    let mut fields: Vec<_> = match input.data {
        Data::Enum(_) | Data::Union(_) => {
            panic!("#[derive(Outgoing)] is only supported for structs")
        }
        Data::Struct(s) => match s.fields {
            Fields::Named(fs) => fs.named.into_pairs().map(Pair::into_value).collect(),
            Fields::Unnamed(fs) => fs.unnamed.into_pairs().map(Pair::into_value).collect(),
            Fields::Unit => return Ok(impl_send_recv_incoming_self(input.ident)),
        },
    };

    let mut any_attribute = false;

    for field in &mut fields {
        let mut field_meta = None;

        let mut remaining_attrs = Vec::new();
        for attr in mem::replace(&mut field.attrs, Vec::new()) {
            if let Some(meta) = Meta::from_attribute(&attr)? {
                if field_meta.is_some() {
                    return Err(syn::Error::new_spanned(
                        attr,
                        "duplicate #[wrap_incoming] attribute",
                    ));
                }
                field_meta = Some(meta);
                any_attribute = true;
            } else {
                remaining_attrs.push(attr);
            }
        }
        field.attrs = remaining_attrs;

        if let Some(attr) = field_meta {
            if let Some(type_to_wrap) = attr.type_to_wrap {
                wrap_generic_arg(&type_to_wrap, &mut field.ty, attr.wrapper_type.as_ref())?;
            } else {
                wrap_ty(&mut field.ty, attr.wrapper_type)?;
            }
        }
    }

    if !any_attribute {
        return Ok(impl_send_recv_incoming_self(input.ident));
    }

    let vis = input.vis;
    let doc = format!("'Incoming' variant of [{ty}](struct.{ty}.html).", ty = input.ident);
    let original_ident = input.ident;
    let incoming_ident = Ident::new(&format!("Incoming{}", original_ident), Span::call_site());

    Ok(quote! {
        #[doc = #doc]
        #derive_deserialize
        #vis struct #incoming_ident {
            #(#fields,)*
        }

        impl ruma_api::Outgoing for #original_ident {
            type Incoming = #incoming_ident;
        }
    })
}

fn no_deserialize_in_attrs(attrs: &[Attribute]) -> bool {
    for attr in attrs {
        match &attr.path {
            Path { leading_colon: None, segments }
                if segments.len() == 1 && segments[0].ident == "incoming_no_deserialize" =>
            {
                return true
            }
            _ => {}
        }
    }

    false
}

fn impl_send_recv_incoming_self(ident: Ident) -> TokenStream {
    quote! {
        impl ruma_api::Outgoing for #ident {
            type Incoming = Self;
        }
    }
}

fn wrap_ty(ty: &mut Type, path: Option<Path>) -> syn::Result<()> {
    if let Some(wrap_ty) = path {
        *ty = parse_quote!(#wrap_ty<#ty>);
    } else {
        match ty {
            Type::Path(TypePath { path, .. }) => {
                let ty_ident = &mut path.segments.last_mut().unwrap().ident;
                let ident = Ident::new(&format!("Incoming{}", ty_ident), Span::call_site());
                *ty_ident = parse_quote!(#ident);
            }
            _ => return Err(syn::Error::new_spanned(ty, "Can't wrap this type")),
        }
    }

    Ok(())
}

fn wrap_generic_arg(type_to_wrap: &Type, of: &mut Type, with: Option<&Path>) -> syn::Result<()> {
    let mut span = None;
    wrap_generic_arg_impl(type_to_wrap, of, with, &mut span)?;

    if span.is_some() {
        Ok(())
    } else {
        Err(syn::Error::new_spanned(
            of,
            format!(
                "Couldn't find generic argument `{}` in this type",
                type_to_wrap.to_token_stream()
            ),
        ))
    }
}

fn wrap_generic_arg_impl(
    type_to_wrap: &Type,
    of: &mut Type,
    with: Option<&Path>,
    span: &mut Option<Span>,
) -> syn::Result<()> {
    // TODO: Support things like array types?
    let ty_path = match of {
        Type::Path(TypePath { path, .. }) => path,
        _ => return Ok(()),
    };

    let args = match &mut ty_path.segments.last_mut().unwrap().arguments {
        PathArguments::AngleBracketed(ab) => &mut ab.args,
        _ => return Ok(()),
    };

    for arg in args.iter_mut() {
        let ty = match arg {
            GenericArgument::Type(ty) => ty,
            _ => continue,
        };

        if ty == type_to_wrap {
            if let Some(s) = span {
                let mut error = syn::Error::new(
                    *s,
                    format!(
                        "`{}` found multiple times, this is not currently supported",
                        type_to_wrap.to_token_stream()
                    ),
                );
                error.combine(syn::Error::new_spanned(ty, "second occurrence"));
                return Err(error);
            }

            *span = Some(ty.span());

            if let Some(wrapper_type) = with {
                *ty = parse_quote!(#wrapper_type<#ty>);
            } else if let Type::Path(TypePath { path, .. }) = ty {
                let ty_ident = &mut path.segments.last_mut().unwrap().ident;
                let ident = Ident::new(&format!("Incoming{}", ty_ident), Span::call_site());
                *ty_ident = parse_quote!(#ident);
            } else {
                return Err(syn::Error::new_spanned(ty, "Can't wrap this type"));
            }
        } else {
            wrap_generic_arg_impl(type_to_wrap, ty, with, span)?;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Environment variables resource detector
//!
//! Implementation of `ResourceDetector` to extract a `Resource` from environment
//! variables.
use crate::sdk::{resource::ResourceDetector, Resource};
use crate::KeyValue;
use std::env;
use std::time::Duration;

const OTEL_RESOURCE_ATTRIBUTES: &str = "OTEL_RESOURCE_ATTRIBUTES";
const OTEL_SERVICE_NAME: &str = "OTEL_SERVICE_NAME";

/// Resource detector implements ResourceDetector and is used to extract
/// general SDK configuration from environment.
///
/// See
/// [semantic conventions](https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/resource/semantic_conventions#telemetry-sdk)
/// for details.
#[derive(Debug)]
pub struct EnvResourceDetector {
    _private: (),
}

impl ResourceDetector for EnvResourceDetector {
    fn detect(&self, _timeout: Duration) -> Resource {
        match env::var(OTEL_RESOURCE_ATTRIBUTES) {
            Ok(s) if !s.is_empty() => construct_otel_resources(s),
            Ok(_) | Err(_) => Resource::new(vec![]), // return empty resource
        }
    }
}

impl EnvResourceDetector {
    /// Create `EnvResourceDetector` instance.
    pub fn new() -> Self {
        EnvResourceDetector { _private: () }
    }
}

impl Default for EnvResourceDetector {
    fn default() -> Self {
        EnvResourceDetector::new()
    }
}

/// Extract key value pairs and construct a resource from resources string like
/// key1=value1,key2=value2,...
fn construct_otel_resources(s: String) -> Resource {
    Resource::new(s.split_terminator(',').filter_map(|entry| {
        let mut parts = entry.splitn(2, '=');
        let key = parts.next()?.trim();
        let value = parts.next()?.trim();
        if value.find('=').is_some() {
            return None;
        }

        Some(KeyValue::new(key.to_owned(), value.to_owned()))
    }))
}

/// There are the attributes which MUST be provided by the SDK as specified in
/// [the Resource SDK specification]. This detector detect those attributes and
/// if the attribute cannot be detected, use the default value.
///
/// [the Resource SDK specification]:https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#sdk-provided-resource-attributes
#[derive(Debug)]
pub struct SdkProvidedResourceDetector;

impl ResourceDetector for SdkProvidedResourceDetector {
    fn detect(&self, _timeout: Duration) -> Resource {
        Resource::new(vec![KeyValue::new(
            "service.name",
            env::var(OTEL_SERVICE_NAME)
                .ok()
                .filter(|s| !s.is_empty())
                .unwrap_or_else(|| "unknown_service".to_string()),
        )])
    }
}

#[cfg(test)]
mod tests {
    use crate::sdk::resource::env::{
        SdkProvidedResourceDetector, OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME,
    };
    use crate::sdk::resource::{EnvResourceDetector, Resource, ResourceDetector};
    use crate::{Key, KeyValue, Value};
    use std::time::Duration;
    use std::{env, time};

    #[test]
    fn test_read_from_env() {
        env::set_var(OTEL_RESOURCE_ATTRIBUTES, "key=value, k = v , a= x, a=z");
        env::set_var("irrelevant".to_uppercase(), "20200810");

        let detector = EnvResourceDetector::new();
        let resource = detector.detect(time::Duration::from_secs(5));
        assert_eq!(
            resource,
            Resource::new(vec![
                KeyValue::new("key", "value"),
                KeyValue::new("k", "v"),
                KeyValue::new("a", "x"),
                KeyValue::new("a", "z"),
            ])
        );

        // Test this case in same test to avoid race condition when running tests in parallel.
        env::set_var(OTEL_RESOURCE_ATTRIBUTES, "");

        let detector = EnvResourceDetector::new();
        let resource = detector.detect(time::Duration::from_secs(5));
        assert!(resource.is_empty());
    }

    #[test]
    fn test_sdk_provided_resource_detector() {
        const SERVICE_NAME: &str = "service.name";
        let no_env = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
        assert_eq!(
            no_env.get(Key::from_static_str(SERVICE_NAME)),
            Some(Value::from("unknown_service")),
        );

        env::set_var(OTEL_SERVICE_NAME, "test service");
        let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
        assert_eq!(
            with_service.get(Key::from_static_str(SERVICE_NAME)),
            Some(Value::from("test service")),
        );
        env::set_var(OTEL_SERVICE_NAME, ""); // clear the env var
    }
}
<commit_msg>fix: detect service.name from OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES. (#662)<commit_after>//! Environment variables resource detector
//!
//! Implementation of `ResourceDetector` to extract a `Resource` from environment
//! variables.
use crate::sdk::{resource::ResourceDetector, Resource};
use crate::{Key, KeyValue};
use std::env;
use std::time::Duration;

const OTEL_RESOURCE_ATTRIBUTES: &str = "OTEL_RESOURCE_ATTRIBUTES";
const OTEL_SERVICE_NAME: &str = "OTEL_SERVICE_NAME";

/// Resource detector implements ResourceDetector and is used to extract
/// general SDK configuration from environment.
///
/// See
/// [semantic conventions](https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/resource/semantic_conventions#telemetry-sdk)
/// for details.
#[derive(Debug)]
pub struct EnvResourceDetector {
    _private: (),
}

impl ResourceDetector for EnvResourceDetector {
    fn detect(&self, _timeout: Duration) -> Resource {
        match env::var(OTEL_RESOURCE_ATTRIBUTES) {
            Ok(s) if !s.is_empty() => construct_otel_resources(s),
            Ok(_) | Err(_) => Resource::new(vec![]), // return empty resource
        }
    }
}

impl EnvResourceDetector {
    /// Create `EnvResourceDetector` instance.
    pub fn new() -> Self {
        EnvResourceDetector { _private: () }
    }
}

impl Default for EnvResourceDetector {
    fn default() -> Self {
        EnvResourceDetector::new()
    }
}

/// Extract key value pairs and construct a resource from resources string like
/// key1=value1,key2=value2,...
fn construct_otel_resources(s: String) -> Resource {
    Resource::new(s.split_terminator(',').filter_map(|entry| {
        let mut parts = entry.splitn(2, '=');
        let key = parts.next()?.trim();
        let value = parts.next()?.trim();
        if value.find('=').is_some() {
            return None;
        }

        Some(KeyValue::new(key.to_owned(), value.to_owned()))
    }))
}

/// There are the attributes which MUST be provided by the SDK as specified in
/// [the Resource SDK specification]. This detector detect those attributes and
/// if the attribute cannot be detected, use the default value.
///
/// This detector will first try `OTEL_SERVICE_NAME` env. If it's not available.
/// Then it will check the `OTEL_RESOURCE_ATTRIBUTES` env and see if it contains
/// `service.name` resource. If it's also not available. Then it will use
/// `unknown_service`.
///
/// Note that if `service.name` is empty. It will be ignore and the service name will
/// be `unknown_service`. If users want to set an empty service name. They can provide
/// a resource with empty value and `service.name` key.
///
/// [the Resource SDK specification]:https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#sdk-provided-resource-attributes
#[derive(Debug)]
pub struct SdkProvidedResourceDetector;

impl ResourceDetector for SdkProvidedResourceDetector {
    fn detect(&self, _timeout: Duration) -> Resource {
        Resource::new(vec![KeyValue::new(
            "service.name",
            env::var(OTEL_SERVICE_NAME)
                .ok()
                .filter(|s| !s.is_empty())
                .unwrap_or_else(|| {
                    EnvResourceDetector::new()
                        .detect(Duration::from_secs(0))
                        .get(Key::new("service.name"))
                        .map(|v| v.to_string())
                        .filter(|s| !s.is_empty())
                        .unwrap_or_else(|| "unknown_service".to_string())
                }),
        )])
    }
}

#[cfg(test)]
mod tests {
    use crate::sdk::resource::env::{
        SdkProvidedResourceDetector, OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME,
    };
    use crate::sdk::resource::{EnvResourceDetector, Resource, ResourceDetector};
    use crate::{Key, KeyValue, Value};
    use std::time::Duration;
    use std::{env, time};

    #[test]
    fn test_read_from_env() {
        env::set_var(OTEL_RESOURCE_ATTRIBUTES, "key=value, k = v , a= x, a=z");
        env::set_var("irrelevant".to_uppercase(), "20200810");

        let detector = EnvResourceDetector::new();
        let resource = detector.detect(time::Duration::from_secs(5));
        assert_eq!(
            resource,
            Resource::new(vec![
                KeyValue::new("key", "value"),
                KeyValue::new("k", "v"),
                KeyValue::new("a", "x"),
                KeyValue::new("a", "z"),
            ])
        );

        // Test this case in same test to avoid race condition when running tests in parallel.
        env::set_var(OTEL_RESOURCE_ATTRIBUTES, "");

        let detector = EnvResourceDetector::new();
        let resource = detector.detect(time::Duration::from_secs(5));
        assert!(resource.is_empty());
    }

    #[test]
    fn test_sdk_provided_resource_detector() {
        const SERVICE_NAME: &str = "service.name";
        let no_env = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
        assert_eq!(
            no_env.get(Key::from_static_str(SERVICE_NAME)),
            Some(Value::from("unknown_service")),
        );

        env::set_var(OTEL_SERVICE_NAME, "test service");
        let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
        assert_eq!(
            with_service.get(Key::from_static_str(SERVICE_NAME)),
            Some(Value::from("test service")),
        );
        env::set_var(OTEL_SERVICE_NAME, ""); // clear the env var

        // Fall back to OTEL_RESOURCE_ATTRIBUTES
        env::set_var(OTEL_RESOURCE_ATTRIBUTES, "service.name=test service1");
        let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
        assert_eq!(
            with_service.get(Key::from_static_str(SERVICE_NAME)),
            Some(Value::from("test service1"))
        );

        // OTEL_SERVICE_NAME takes priority
        env::set_var(OTEL_SERVICE_NAME, "test service");
        let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
        assert_eq!(
            with_service.get(Key::from_static_str(SERVICE_NAME)),
            Some(Value::from("test service"))
        );
        env::set_var(OTEL_RESOURCE_ATTRIBUTES, "");
        env::set_var(OTEL_SERVICE_NAME, ""); // clear the env var
    }
}
<|endoftext|>


<commit_before>use std::mem;

use bytes::{Bytes, BytesMut};
use futures::{Async, Poll};
use http::header::{self, HeaderName, HeaderValue};
use http::{HeaderMap, StatusCode, Version};
use httparse;

use error::{ParseError, PayloadError};

use server::h1decoder::{EncodingDecoder, HeaderIndex};
use server::IoStream;

use super::response::ClientMessage;
use super::ClientResponse;

const MAX_BUFFER_SIZE: usize = 131_072;
const MAX_HEADERS: usize = 96;

#[derive(Default)]
pub struct HttpResponseParser {
    decoder: Option<EncodingDecoder>,
}

#[derive(Debug, Fail)]
pub enum HttpResponseParserError {
    /// Server disconnected
    #[fail(display = "Server disconnected")]
    Disconnect,
    #[fail(display = "{}", _0)]
    Error(#[cause] ParseError),
}

impl HttpResponseParser {
    pub fn parse<T>(
        &mut self, io: &mut T, buf: &mut BytesMut,
    ) -> Poll<ClientResponse, HttpResponseParserError>
    where
        T: IoStream,
    {
        // if buf is empty parse_message will always return NotReady, let's avoid that
        if buf.is_empty() {
            match io.read_available(buf) {
                Ok(Async::Ready((_, true))) => {
                    return Err(HttpResponseParserError::Disconnect)
                }
                Ok(Async::Ready((_, false))) => (),
                Ok(Async::NotReady) => return Ok(Async::NotReady),
                Err(err) => return Err(HttpResponseParserError::Error(err.into())),
            }
        }

        loop {
            match HttpResponseParser::parse_message(buf)
                .map_err(HttpResponseParserError::Error)?
            {
                Async::Ready((msg, decoder)) => {
                    self.decoder = decoder;
                    return Ok(Async::Ready(msg));
                }
                Async::NotReady => {
                    if buf.capacity() >= MAX_BUFFER_SIZE {
                        return Err(HttpResponseParserError::Error(ParseError::TooLarge));
                    }
                    match io.read_available(buf) {
                        Ok(Async::Ready((_, true))) => {
                            return Err(HttpResponseParserError::Disconnect)
                        }
                        Ok(Async::Ready((_, false))) => (),
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(err) => {
                            return Err(HttpResponseParserError::Error(err.into()))
                        }
                    }
                }
            }
        }
    }

    pub fn parse_payload<T>(
        &mut self, io: &mut T, buf: &mut BytesMut,
    ) -> Poll<Option<Bytes>, PayloadError>
    where
        T: IoStream,
    {
        if self.decoder.is_some() {
            loop {
                // read payload
                let (not_ready, stream_finished) = match io.read_available(buf) {
                    Ok(Async::Ready((_, true))) => (false, true),
                    Ok(Async::Ready((_, false))) => (false, false),
                    Ok(Async::NotReady) => (true, false),
                    Err(err) => return Err(err.into()),
                };

                match self.decoder.as_mut().unwrap().decode(buf) {
                    Ok(Async::Ready(Some(b))) => return Ok(Async::Ready(Some(b))),
                    Ok(Async::Ready(None)) => {
                        self.decoder.take();
                        return Ok(Async::Ready(None));
                    }
                    Ok(Async::NotReady) => {
                        if not_ready {
                            return Ok(Async::NotReady);
                        }
                        if stream_finished {
                            return Err(PayloadError::Incomplete);
                        }
                    }
                    Err(err) => return Err(err.into()),
                }
            }
        } else {
            Ok(Async::Ready(None))
        }
    }

    fn parse_message(
        buf: &mut BytesMut,
    ) -> Poll<(ClientResponse, Option<EncodingDecoder>), ParseError> {
        // Unsafe: we read only this data only after httparse parses headers into.
        // performance bump for pipeline benchmarks.
        let mut headers: [HeaderIndex; MAX_HEADERS] = unsafe { mem::uninitialized() };

        let (len, version, status, headers_len) = {
            let mut parsed: [httparse::Header; MAX_HEADERS] =
                unsafe { mem::uninitialized() };

            let mut resp = httparse::Response::new(&mut parsed);
            match resp.parse(buf)? {
                httparse::Status::Complete(len) => {
                    let version = if resp.version.unwrap_or(1) == 1 {
                        Version::HTTP_11
                    } else {
                        Version::HTTP_10
                    };
                    HeaderIndex::record(buf, resp.headers, &mut headers);
                    let status = StatusCode::from_u16(resp.code.unwrap())
                        .map_err(|_| ParseError::Status)?;

                    (len, version, status, resp.headers.len())
                }
                httparse::Status::Partial => return Ok(Async::NotReady),
            }
        };

        let slice = buf.split_to(len).freeze();

        // convert headers
        let mut hdrs = HeaderMap::new();
        for idx in headers[..headers_len].iter() {
            if let Ok(name) = HeaderName::from_bytes(&slice[idx.name.0..idx.name.1]) {
                // Unsafe: httparse check header value for valid utf-8
                let value = unsafe {
                    HeaderValue::from_shared_unchecked(
                        slice.slice(idx.value.0, idx.value.1),
                    )
                };
                hdrs.append(name, value);
            } else {
                return Err(ParseError::Header);
            }
        }

        let decoder = if status == StatusCode::SWITCHING_PROTOCOLS {
            Some(EncodingDecoder::eof())
        } else if let Some(len) = hdrs.get(header::CONTENT_LENGTH) {
            // Content-Length
            if let Ok(s) = len.to_str() {
                if let Ok(len) = s.parse::<u64>() {
                    Some(EncodingDecoder::length(len))
                } else {
                    debug!("illegal Content-Length: {:?}", len);
                    return Err(ParseError::Header);
                }
            } else {
                debug!("illegal Content-Length: {:?}", len);
                return Err(ParseError::Header);
            }
        } else if chunked(&hdrs)? {
            // Chunked encoding
            Some(EncodingDecoder::chunked())
        } else {
            None
        };

        if let Some(decoder) = decoder {
            Ok(Async::Ready((
                ClientResponse::new(ClientMessage {
                    status,
                    version,
                    headers: hdrs,
                    cookies: None,
                }),
                Some(decoder),
            )))
        } else {
            Ok(Async::Ready((
                ClientResponse::new(ClientMessage {
                    status,
                    version,
                    headers: hdrs,
                    cookies: None,
                }),
                None,
            )))
        }
    }
}

/// Check if request has chunked transfer encoding
pub fn chunked(headers: &HeaderMap) -> Result<bool, ParseError> {
    if let Some(encodings) = headers.get(header::TRANSFER_ENCODING) {
        if let Ok(s) = encodings.to_str() {
            Ok(s.to_lowercase().contains("chunked"))
        } else {
            Err(ParseError::Header)
        }
    } else {
        Ok(false)
    }
}
<commit_msg>Fix issue with 'Connection: close' in ClientRequest<commit_after>use std::mem;

use bytes::{Bytes, BytesMut};
use futures::{Async, Poll};
use http::header::{self, HeaderName, HeaderValue};
use http::{HeaderMap, StatusCode, Version};
use httparse;

use error::{ParseError, PayloadError};

use server::h1decoder::{EncodingDecoder, HeaderIndex};
use server::IoStream;

use super::response::ClientMessage;
use super::ClientResponse;

const MAX_BUFFER_SIZE: usize = 131_072;
const MAX_HEADERS: usize = 96;

#[derive(Default)]
pub struct HttpResponseParser {
    decoder: Option<EncodingDecoder>,
}

#[derive(Debug, Fail)]
pub enum HttpResponseParserError {
    /// Server disconnected
    #[fail(display = "Server disconnected")]
    Disconnect,
    #[fail(display = "{}", _0)]
    Error(#[cause] ParseError),
}

impl HttpResponseParser {
    pub fn parse<T>(
        &mut self, io: &mut T, buf: &mut BytesMut,
    ) -> Poll<ClientResponse, HttpResponseParserError>
    where
        T: IoStream,
    {
        // if buf is empty parse_message will always return NotReady, let's avoid that
        if buf.is_empty() {
            match io.read_available(buf) {
                Ok(Async::Ready((true, true))) => (),
                Ok(Async::Ready((false, true))) => {
                    return Err(HttpResponseParserError::Disconnect)
                }
                Ok(Async::Ready((_, false))) => (),
                Ok(Async::NotReady) => return Ok(Async::NotReady),
                Err(err) => return Err(HttpResponseParserError::Error(err.into())),
            }
        }

        loop {
            match HttpResponseParser::parse_message(buf)
                .map_err(HttpResponseParserError::Error)?
            {
                Async::Ready((msg, decoder)) => {
                    self.decoder = decoder;
                    return Ok(Async::Ready(msg));
                }
                Async::NotReady => {
                    if buf.capacity() >= MAX_BUFFER_SIZE {
                        return Err(HttpResponseParserError::Error(ParseError::TooLarge));
                    }
                    match io.read_available(buf) {
                        Ok(Async::Ready((true, true))) => (),
                        Ok(Async::Ready((false, true))) => {
                            return Err(HttpResponseParserError::Disconnect)
                        }
                        Ok(Async::Ready((_, false))) => (),
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(err) => {
                            return Err(HttpResponseParserError::Error(err.into()))
                        }
                    }
                }
            }
        }
    }

    pub fn parse_payload<T>(
        &mut self, io: &mut T, buf: &mut BytesMut,
    ) -> Poll<Option<Bytes>, PayloadError>
    where
        T: IoStream,
    {
        if self.decoder.is_some() {
            loop {
                // read payload
                let (not_ready, stream_finished) = match io.read_available(buf) {
                    Ok(Async::Ready((_, true))) => (false, true),
                    Ok(Async::Ready((_, false))) => (false, false),
                    Ok(Async::NotReady) => (true, false),
                    Err(err) => return Err(err.into()),
                };

                match self.decoder.as_mut().unwrap().decode(buf) {
                    Ok(Async::Ready(Some(b))) => return Ok(Async::Ready(Some(b))),
                    Ok(Async::Ready(None)) => {
                        self.decoder.take();
                        return Ok(Async::Ready(None));
                    }
                    Ok(Async::NotReady) => {
                        if not_ready {
                            return Ok(Async::NotReady);
                        }
                        if stream_finished {
                            return Err(PayloadError::Incomplete);
                        }
                    }
                    Err(err) => return Err(err.into()),
                }
            }
        } else {
            Ok(Async::Ready(None))
        }
    }

    fn parse_message(
        buf: &mut BytesMut,
    ) -> Poll<(ClientResponse, Option<EncodingDecoder>), ParseError> {
        // Unsafe: we read only this data only after httparse parses headers into.
        // performance bump for pipeline benchmarks.
        let mut headers: [HeaderIndex; MAX_HEADERS] = unsafe { mem::uninitialized() };

        let (len, version, status, headers_len) = {
            let mut parsed: [httparse::Header; MAX_HEADERS] =
                unsafe { mem::uninitialized() };

            let mut resp = httparse::Response::new(&mut parsed);
            match resp.parse(buf)? {
                httparse::Status::Complete(len) => {
                    let version = if resp.version.unwrap_or(1) == 1 {
                        Version::HTTP_11
                    } else {
                        Version::HTTP_10
                    };
                    HeaderIndex::record(buf, resp.headers, &mut headers);
                    let status = StatusCode::from_u16(resp.code.unwrap())
                        .map_err(|_| ParseError::Status)?;

                    (len, version, status, resp.headers.len())
                }
                httparse::Status::Partial => return Ok(Async::NotReady),
            }
        };

        let slice = buf.split_to(len).freeze();

        // convert headers
        let mut hdrs = HeaderMap::new();
        for idx in headers[..headers_len].iter() {
            if let Ok(name) = HeaderName::from_bytes(&slice[idx.name.0..idx.name.1]) {
                // Unsafe: httparse check header value for valid utf-8
                let value = unsafe {
                    HeaderValue::from_shared_unchecked(
                        slice.slice(idx.value.0, idx.value.1),
                    )
                };
                hdrs.append(name, value);
            } else {
                return Err(ParseError::Header);
            }
        }

        let decoder = if status == StatusCode::SWITCHING_PROTOCOLS {
            Some(EncodingDecoder::eof())
        } else if let Some(len) = hdrs.get(header::CONTENT_LENGTH) {
            // Content-Length
            if let Ok(s) = len.to_str() {
                if let Ok(len) = s.parse::<u64>() {
                    Some(EncodingDecoder::length(len))
                } else {
                    debug!("illegal Content-Length: {:?}", len);
                    return Err(ParseError::Header);
                }
            } else {
                debug!("illegal Content-Length: {:?}", len);
                return Err(ParseError::Header);
            }
        } else if chunked(&hdrs)? {
            // Chunked encoding
            Some(EncodingDecoder::chunked())
        } else {
            None
        };

        if let Some(decoder) = decoder {
            Ok(Async::Ready((
                ClientResponse::new(ClientMessage {
                    status,
                    version,
                    headers: hdrs,
                    cookies: None,
                }),
                Some(decoder),
            )))
        } else {
            Ok(Async::Ready((
                ClientResponse::new(ClientMessage {
                    status,
                    version,
                    headers: hdrs,
                    cookies: None,
                }),
                None,
            )))
        }
    }
}

/// Check if request has chunked transfer encoding
pub fn chunked(headers: &HeaderMap) -> Result<bool, ParseError> {
    if let Some(encodings) = headers.get(header::TRANSFER_ENCODING) {
        if let Ok(s) = encodings.to_str() {
            Ok(s.to_lowercase().contains("chunked"))
        } else {
            Err(ParseError::Header)
        }
    } else {
        Ok(false)
    }
}
<|endoftext|>


<commit_before>//! Intrusive reference types.
//!
//! Use of intrusively-reference-counted objects with matching reference types
//! over containers like `std::rc::Rc` or `std::sync::Arc` trades some
//! compile-time safety checks (and likely performance benefits) for greater
//! flexibility in how those objects are allocated and used.
//!
//! `Rc` and `Arc` are themselves references to underlying *containers*; any
//! object passed to either's `::new` will be moved to a newly-allocated block
//! on the heap.  To support weak references the data's reference count is
//! stored in another heap-allocated block, which is freed *only when the last
//! reference, weak *or* strong, is dropped*.  Because these types have
//! a reference count stored separately from the data, it is impossible to
//! create a new `Rc`, `Arc`, or `Weak` pointer thereto without one of
//! the same.
//!
//! In contrast, the types defined here forgo support for weak references and
//! strong guarantees of lifetime-management and memory-safety to allow the
//! developer more flexibility in data storage and manipulation.
//!
//! Since reference counts are stored alongside the data (in types
//! implementing [`RefCountHolder`](trait.RefCountHolder.html)),
//! a stack-allocated value can safely provide references to itself as long as
//! its refcount is non-zero prior to its doing so.  they support references
//! to stack-allocated values and values in memory not managed directly the by
//! [`Reference`](trait.Reference.html) implementation.
use std;
use std::fmt;
use std::mem;
use std::ops::{Deref,DerefMut};
use std::ptr::PtrExt;
use std::clone::Clone;
use std::hash::{Hash, Hasher};
use std::borrow::Borrow;

/// Abstract interface for references to intrusively-refcounted values.
pub trait Reference<T: ?Sized> where T: RefCounted, Self: Sized {
    /// Create a reference from a raw pointer.  The reference-type
    /// implementation should do no management of the referand's refcount for
    /// this operation.
    fn from_obj<U>(obj: *const U) -> Self;

    /// Create an intrusive reference from a trait object.  The reference-type
    /// implementation should do no management of the referand's refcount for
    /// this operation.
    fn from_trait_obj(obj: *const T) -> Self;

    /// Move the given value into the heap, and return a reference to it.  The value
    /// should have a refcount of zero prior to this function.
    ///
    /// # Examples
    ///
    /// ```rust
    /// #[macro_use]
    /// use cripes::util::intrusive;
    /// use cripes::util::intrusive::{Ref,Reference};
    ///
    /// #[derive(Debug)]
    /// struct Dog { refcount: usize }
    /// default_refcounted_impl!(Dog);
    ///
    /// let x: Ref<_> = Reference::new_on_heap(Dog{refcount: 0});   // x is an intrusive reference to the heap
    ///
    /// println!("{:?}", x);
    /// drop(x);                  // dropping the sole reference to that location
    ///                           // will free the memory.
    /// ```
    fn new_on_heap<U>(mut obj: U) -> Self where Self: Sized, U: Sized + RefCounted {
        {
            let rc = obj.as_refcounted_mut();
            // Zero the reference count: we're "taking ownership" of the object.
            while rc.get_refcount() != 0 { rc.remove_ref(); }

            rc.add_ref();
        }

        // Move the object onto the heap using Box, then discard the box in
        // favor of a hot, sticky, unsafe mess.
        let heaped: *const U = unsafe { std::boxed::into_raw(Box::new(obj)) as *const U };

        if std::mem::size_of::<&T>() == std::mem::size_of::<usize>() {
            // standard pointer
            unsafe { Reference::from_obj(heaped) }
        } else {
            // trait object
            unsafe { Reference::from_trait_obj(heaped as *const T) }
        }
    }
}

/// Describes a type that holds a reference count.
pub trait RefCountHolder {
    /// Fetch the object's current reference count.
    fn get_refcount(&self) -> usize;

    /// Increment the object's reference count, returning the new value.
    fn add_ref(&mut self) -> usize;

    /// Decrement the object's reference count, returning the new value.
    fn remove_ref(&mut self) -> usize;
}

pub trait RefCounted {
    // /// Create a reference to the current object.
    // fn ref_to_self<T: ?Sized>(&self) -> Ref<T> where T: RefCounted, Self: T {
    //     Reference::from_raw(unsafe { std::mem::transmute::<_,*const Self>(self) })
    // }

    fn as_refcounted(&self) -> &RefCountHolder;
    fn as_refcounted_mut(&mut self) -> &mut RefCountHolder;
}

impl<T> RefCounted for T where T: RefCountHolder {
    fn as_refcounted(&self) -> &RefCountHolder { self as &RefCountHolder }
    fn as_refcounted_mut(&mut self) -> &mut RefCountHolder { self as &mut RefCountHolder }
}

/// Create a simple implementation of util::intrusive::RefCountHolder for a type.
#[macro_export]
macro_rules! default_refcounted_impl {
    ($target:ident) => (default_refcounted_impl!($target, refcount););

    ($target:ident, $($mbr:ident).*) => (
        impl ::cripes::util::intrusive::RefCountHolder for $target {
            fn get_refcount(&self) -> usize { self.$($mbr).* }
            fn add_ref(&mut self) -> usize { self.$($mbr).* += 1; self.$($mbr).* }
            fn remove_ref(&mut self) -> usize { self.$($mbr).* -= 1; self.$($mbr).* }
        });
}

/* ****************************************************************
 * MutRef<T>
 */
// This is disabled for now -- we'd need a refcounted `RwLock` type or
// something to make this properly intrusive.  Until that happens, we
// (!!unsafely) implement MutDeref for Ref<T>.

/* /// Mutable, RwLock-protected reference to an intrusively-refcounted object.
pub struct MutRef<T: ?Sized + RefCounted + Send + Sync>(std::sync::RwLock<*mut T>);

impl<T> Reference<T> for MutRef<T>
where T: RefCounted + Send + Sync {
    fn new(ptr: *mut T) -> MutRef<T> { MutRef(std::sync::RwLock::new(ptr)) }
}

impl<T> Deref for MutRef<T>
    where T: RefCounted + Send + Sync {
    type Target = T;
    fn deref(&self) -> &T {
        if (*self).is_null() { panic!("tried to deref a null pointer") }
        match *self { Ref(p) =>  { let val_ref: &T = unsafe { &*p };
                                   val_ref }
        }
    }
}
impl<T: RefCounted> DerefMut for Ref<T> {
    fn deref_mut(&mut self) -> &mut T {
        if (*self).is_null() { panic!("tried to deref a null pointer") }
        match *self { Ref(p) =>  unsafe { std::mem::transmute(&*p) }
        }
    }
}*/

/* ****************************************************************
 * Ref<T>
 */
/// Immutable reference to an intrusively-refcounted object.
pub struct Ref<T: ?Sized>(RefImpl<T>) where T: RefCounted;

/// Private data type for Ref<T>.
enum RefImpl<T: ?Sized> where T: RefCounted {
    /// Invalid reference.
    Empty,

    /// Simple pointer to a concrete type.
    Pointer(*const T),

    /// A fat pointer/trait object.
    TraitObject(std::raw::TraitObject)
}

impl<T: ?Sized> Reference<T> for Ref<T> where T: RefCounted {
    fn from_trait_obj(obj: *const T) -> Self {
        assert_eq!(std::mem::size_of::<*const T>(), 16);
        unsafe { Ref(RefImpl::TraitObject(std::mem::transmute(obj))) }
    }

    fn from_obj<U>(obj: *const U) -> Ref<T> {
        let ptr: *const T =  unsafe { std::mem::transmute(obj) };
        if ptr == (0 as *const T) { Ref(RefImpl::Empty) }
        else { Ref(RefImpl::Pointer(ptr)) }
    }
}

// impl<T: ?Sized, U> Reference<U> for Ref<T> where T: RefCounted {
//     fn from_trait_obj(obj: &T) -> Self {
//         Ref(RefImpl::TraitObject(std::mem::transmute(obj)))
//     }

//     fn from_obj<U>(obj: &U) -> Ref<T> {
//         let ptr: *const T =  unsafe { std::mem::transmute(obj) };
//         if ptr == (0 as *const T) { Ref(RefImpl::Empty) }
//         else { Ref(RefImpl::Pointer(ptr)) }
//     }
// }

impl<T: ?Sized> Ref<T> where T: RefCounted {
    /// Fetch the reference's data pointer as a `usize`.  This is intended
    /// primarily for implementing hashes over trait objects (the standard
    /// library's Hash is not object-safe) by simply hashing the instance's
    /// data pointer.
    pub fn data_id(&self) -> usize {
        match self.0 {
            RefImpl::Empty => 0,
            RefImpl::Pointer(p) => p as usize,
            RefImpl::TraitObject(ref to) => to.data as usize
        }
    }

    /// Create a null Ref.  This is probably not very safe.
    pub fn null() -> Ref<T> {
        Ref(RefImpl::Empty)
   }

    /// Check if the ref's internal pointer is NULL.
    pub fn is_null(&self) -> bool {
        match self.0 {
            RefImpl::Empty => true,
            _ => false
        }
    }

    /// Get the reference count from the underlying object.
    pub fn get_refcount(&self) -> usize {
        match self.0 {
            RefImpl::Empty => 0,
            _ => self.deref().as_refcounted().get_refcount()
        }
    }

    /// Check if this refers to the same object as another Ref.
    pub fn is_same(&self, other: &Ref<T>) -> bool {
        match self.0 {
            RefImpl::Empty => match other.0 { RefImpl::Empty => true, _ => false },
            RefImpl::Pointer(x) => match other.0 { RefImpl::Pointer(y) => x == y, _ => false },
            RefImpl::TraitObject(ref x) => match other.0 {
                RefImpl::TraitObject(ref y) => { x.data == y.data && x.vtable == y.vtable },
                _ => false },
        }
    }
}

/* ================================================================
 * impl Deref
 */
impl<T: ?Sized> Deref for Ref<T>
where T: RefCounted {
    type Target = T;
    fn deref(&self) -> &T {
        match self.0 {
            RefImpl::Empty => panic!("tried to deref from an empty reference"),
            RefImpl::Pointer(ptr) => unsafe { &*ptr },
            RefImpl::TraitObject(ref obj) => unsafe { std::mem::transmute(obj) }
        }
    }
}

impl<T: ?Sized> DerefMut for Ref<T>
where T: RefCounted {
    fn deref_mut(&mut self) -> &mut T {
        match self.0 {
            RefImpl::Empty => panic!("tried to mutably deref from an empty reference"),
            RefImpl::Pointer(ptr) => unsafe { &mut *std::mem::transmute::<_,*mut T>(ptr) },
            RefImpl::TraitObject(ref obj) => unsafe { std::mem::transmute(obj) }
        }
    }
}

/* ================================================================
 * impl std::borrow::Borrow
 */
impl<T: ?Sized>  Borrow<T> for ::cripes::util::intrusive::Ref<T>
where T: RefCounted {
    fn borrow(&self) -> &T {
        self.deref()
    }
}

// impl<T: ?Sized>  Borrow<::cripes::util::intrusive::Ref<T>> for ::cripes::util::intrusive::Ref<T>
// where T: RefCounted {
//     fn borrow(&self) -> &T {
//         self
//     }
// }

/* ================================================================
 * impl fmt::Display
 */
impl<T: ?Sized> fmt::Display for Ref<T>
where T: RefCounted + fmt::Display {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            RefImpl::Empty => write!(f, ""),
            RefImpl::Pointer(p) => { assert!(! (p == 0 as *const T));
                                     let val: &T = (*self).deref();
                                     val.fmt(f) },
            RefImpl::TraitObject(to) => { let x: &T = unsafe { std::mem::transmute(to) };
                                          x.fmt(f) }
        }
    }
}

/* ================================================================
 * impl fmt::Debug
 */
impl<T: ?Sized> fmt::Debug for Ref<T>
where T:  RefCounted + fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ptr = match self.0 {
            RefImpl::Empty => { return write!(f, "Ref{{Empty}}"); },
            RefImpl::Pointer(p) => p,
            RefImpl::TraitObject(ref obj) => unsafe { std::mem::transmute(obj.data) }};
        let val = (*self).deref();
        try!(write!(f, "Ref {{ 0x{:X}=>", ptr as usize));
        try!(val.fmt(f));
        write!(f, " }}")

    }
}

/* ================================================================
 * impl Clone
 */
impl<T: ?Sized> Clone for Ref<T>
where T: RefCounted {
    fn clone(&self) -> Self {
        match self.0 {
            RefImpl::Empty => Ref(RefImpl::Empty),
            RefImpl::Pointer(p) => Ref(RefImpl::Pointer(p)),
            RefImpl::TraitObject(to) => Ref(RefImpl::TraitObject(to))
        }
    }
}

/* ================================================================
 * impl Drop
 */
#[unsafe_destructor]
impl<T: ?Sized> Drop for Ref<T>
where T: RefCounted {
    fn drop(&mut self) {
        match self.0 {
            RefImpl::Pointer(x) => { assert!((x as usize) != 0);
                                     unsafe {
                                         let _ref =  self.deref_mut().as_refcounted_mut();
                                         if _ref.remove_ref() == 0 {
                                             let boxed = Box::from_raw(mem::transmute::<_,*mut T>(x));
                                             drop(boxed); } } },
            _ => {}
        }
    }
}

/* ================================================================
 * impl Eq, PartialEq<T>, PartialEq<Ref<T>>
 */
impl<T: ?Sized> Eq for Ref<T>
where T: RefCounted + Eq {}

impl<T: ?Sized> PartialEq<T> for Ref<T>
where T: RefCounted + PartialEq<T> {
    fn eq(&self, other: &T) -> bool {
        self.deref() == other
    }
}

impl<T: ?Sized> PartialEq<Ref<T>> for Ref<T>
where T: RefCounted + PartialEq<T> {
    fn eq(&self, other: &Ref<T>) -> bool {
        *self == *other
    }
}

/* ================================================================
 * impl Hash<H>
 */
impl<T: ?Sized> Hash for Ref<T>
where T: RefCounted + Hash {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (*self).deref().hash(state)
    }
}
<commit_msg>REMOVING: util/intrusive<commit_after><|endoftext|>


<commit_before>// Copyright 2018 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This library provides type-safe and fully-featured `Mutex` and `RwLock`
//! types which wrap a simple raw mutex or rwlock type. This has several
//! benefits: not only does it eliminate a large portion of the work in
//! implementing custom lock types, it also allows users to write code which is
//! generic with regards to different lock implementations.
//!
//! Basic usage of this crate is very straightfoward:
//!
//! 1. Create a raw lock type. This should only contain the lock state, not any
//!    data protected by the lock.
//! 2. Implement the `RawMutex` trait for your custom lock type.
//! 3. Export your mutex as a type alias for `lock_api::Mutex`, and
//!    your mutex guard as a type alias for `lock_api::MutexGuard`.
//!    See the [example](#example) below for details.
//!
//! This process is similar for RwLocks, except that two guards need to be
//! exported instead of one. (Or 3 guards if your type supports upgradable read
//! locks, see [extension traits](#extension-traits) below for details)
//!
//! # Example
//!
//! ```
//! use lock_api::{RawMutex, Mutex};
//! use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
//!
//! // 1. Define our raw lock type
//! pub struct RawSpinlock(AtomicBool);
//!
//! // 2. Implement RawMutex for this type
//! unsafe impl RawMutex for RawSpinlock {
//!     const INIT: RawSpinlock = RawSpinlock(ATOMIC_BOOL_INIT);
//!
//!     fn lock(&self) {
//!         // Note: This isn't the best way of implementing a spinlock, but it
//!         // suffices for the sake of this example.
//!         while !self.try_lock() {}
//!     }
//!
//!     fn try_lock(&self) -> bool {
//!         self.0.swap(true, Ordering::Acquire)
//!     }
//!
//!     fn unlock(&self) {
//!         self.0.store(false, Ordering::Release);
//!     }
//! }
//!
//! // 3. Export the wrappers. This are the types that your users will actually use.
//! pub type Spinlock<T> = lock_api::Mutex<RawSpinlock, T>;
//! pub type SpinlockGuard<'a, T> = lock_api::MutexGuard<'a, RawSpinlock, T>;
//! ```
//!
//! # Extension traits
//!
//! In addition to basic locking & unlocking functionality, you have the option
//! of exposing additional functionality in your lock types by implementing
//! additional traits for it. Examples of extension features include:
//!
//! - Fair unlocking (`RawMutexFair`, `RawRwLockFair`)
//! - Lock timeouts (`RawMutexTimed`, `RawRwLockTimed`)
//! - Downgradable write locks (`RawRwLockDowngradable`)
//! - Recursive read locks (`RawRwLockRecursive`)
//! - Upgradable read locks (`RawRwLockUpgrade`)
//!
//! The `Mutex` and `RwLock` wrappers will automatically expose this additional
//! functionality if the raw lock type implements these extension traits.
//!
//! # Cargo features
//!
//! This crate supports two cargo features:
//!
//! - `owning_ref`: Allows your lock types to be used with the `owning_ref` crate.
//! - `nightly`: Enables nightly-only features. At the moment the only such
//!   feature is `const fn` constructors for lock types.

#![no_std]
#![warn(missing_docs)]
#![cfg_attr(feature = "nightly", feature(const_fn))]

#[macro_use]
extern crate scopeguard;

#[cfg(feature = "owning_ref")]
extern crate owning_ref;

/// Marker type which indicates that the Guard type for a lock is `Send`.
pub struct GuardSend(());

/// Marker type which indicates that the Guard type for a lock is not `Send`.
pub struct GuardNoSend(*mut ());

mod mutex;
pub use mutex::*;

mod remutex;
pub use remutex::*;

mod rwlock;
pub use rwlock::*;
<commit_msg>Fix lock_api doctest<commit_after>// Copyright 2018 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This library provides type-safe and fully-featured `Mutex` and `RwLock`
//! types which wrap a simple raw mutex or rwlock type. This has several
//! benefits: not only does it eliminate a large portion of the work in
//! implementing custom lock types, it also allows users to write code which is
//! generic with regards to different lock implementations.
//!
//! Basic usage of this crate is very straightfoward:
//!
//! 1. Create a raw lock type. This should only contain the lock state, not any
//!    data protected by the lock.
//! 2. Implement the `RawMutex` trait for your custom lock type.
//! 3. Export your mutex as a type alias for `lock_api::Mutex`, and
//!    your mutex guard as a type alias for `lock_api::MutexGuard`.
//!    See the [example](#example) below for details.
//!
//! This process is similar for RwLocks, except that two guards need to be
//! exported instead of one. (Or 3 guards if your type supports upgradable read
//! locks, see [extension traits](#extension-traits) below for details)
//!
//! # Example
//!
//! ```
//! use lock_api::{RawMutex, Mutex, GuardSend};
//! use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
//!
//! // 1. Define our raw lock type
//! pub struct RawSpinlock(AtomicBool);
//!
//! // 2. Implement RawMutex for this type
//! unsafe impl RawMutex for RawSpinlock {
//!     const INIT: RawSpinlock = RawSpinlock(ATOMIC_BOOL_INIT);
//!
//!     // A spinlock guard can be sent to another thread and unlocked there
//!     type GuardMarker = GuardSend;
//!
//!     fn lock(&self) {
//!         // Note: This isn't the best way of implementing a spinlock, but it
//!         // suffices for the sake of this example.
//!         while !self.try_lock() {}
//!     }
//!
//!     fn try_lock(&self) -> bool {
//!         self.0.swap(true, Ordering::Acquire)
//!     }
//!
//!     fn unlock(&self) {
//!         self.0.store(false, Ordering::Release);
//!     }
//! }
//!
//! // 3. Export the wrappers. This are the types that your users will actually use.
//! pub type Spinlock<T> = lock_api::Mutex<RawSpinlock, T>;
//! pub type SpinlockGuard<'a, T> = lock_api::MutexGuard<'a, RawSpinlock, T>;
//! ```
//!
//! # Extension traits
//!
//! In addition to basic locking & unlocking functionality, you have the option
//! of exposing additional functionality in your lock types by implementing
//! additional traits for it. Examples of extension features include:
//!
//! - Fair unlocking (`RawMutexFair`, `RawRwLockFair`)
//! - Lock timeouts (`RawMutexTimed`, `RawRwLockTimed`)
//! - Downgradable write locks (`RawRwLockDowngradable`)
//! - Recursive read locks (`RawRwLockRecursive`)
//! - Upgradable read locks (`RawRwLockUpgrade`)
//!
//! The `Mutex` and `RwLock` wrappers will automatically expose this additional
//! functionality if the raw lock type implements these extension traits.
//!
//! # Cargo features
//!
//! This crate supports two cargo features:
//!
//! - `owning_ref`: Allows your lock types to be used with the `owning_ref` crate.
//! - `nightly`: Enables nightly-only features. At the moment the only such
//!   feature is `const fn` constructors for lock types.

#![no_std]
#![warn(missing_docs)]
#![cfg_attr(feature = "nightly", feature(const_fn))]

#[macro_use]
extern crate scopeguard;

#[cfg(feature = "owning_ref")]
extern crate owning_ref;

/// Marker type which indicates that the Guard type for a lock is `Send`.
pub struct GuardSend(());

/// Marker type which indicates that the Guard type for a lock is not `Send`.
pub struct GuardNoSend(*mut ());

mod mutex;
pub use mutex::*;

mod remutex;
pub use remutex::*;

mod rwlock;
pub use rwlock::*;
<|endoftext|>


<commit_before>use std::io::{Listener, Acceptor};
use std::io::net::tcp::{TcpListener, TcpStream};

static EXT_PORT: u16 = 8443;
static SSH_PORT: u16 = 22;
static SSL_PORT: u16 = 9443;

fn keep_copying(mut a: TcpStream, mut b: TcpStream) {
	let mut buf = [0u8,..1024];
	loop {
		let read = match a.read(buf) {
			Err(..) => { drop(a); return; },
			Ok(r) => r
		};
		match b.write(buf.slice_to(read)) {
			Err(..) => { drop(a); return; },
			Ok(..) => ()
		};
	}
}

fn start_pipe(front: TcpStream, port: u16, header: Option<u8>) {
	let mut back = match TcpStream::connect("127.0.0.1", port) {
		Err(e) => { println!("Error connecting: {}", e); return; },
		Ok(b) => b
	};
	if header.is_some() {
		match back.write_u8(header.unwrap()) {
			Err(e) => { println!("Error writing first byte: {}", e); return }
			Ok(..) => ()
		}
	}
	let front_copy = front.clone();
	let back_copy = back.clone();

	spawn(proc() {
		keep_copying(front, back);
	});
	spawn(proc() {
		keep_copying(back_copy, front_copy);
	});
}

fn handle_new_connection(mut stream: TcpStream) {
	let header: Option<u8> = match stream.read_byte() {
		Err(..) => None,
		Ok(b) => Some(b)
	};
	if header.is_some() && header.unwrap() == 22 || header.unwrap() == 128 {
		start_pipe(stream, SSL_PORT, header);
	}
	else {
		start_pipe(stream, SSH_PORT, header);
	}
}

fn main() {
    let mut acceptor = TcpListener::bind("127.0.0.1", EXT_PORT).listen().unwrap();
    println!("listening started, ready to accept");
    for stream in acceptor.incoming() {
		match stream {
			Err(e) => println!("Strange connection broken: {}", e),
			Ok(stream) => spawn(proc() {
					// connection succeeded
					handle_new_connection(stream);
					})
		}
    }
	drop(acceptor);
}
<commit_msg>Some better formatting and dropping connections<commit_after>use std::io::{Listener, Acceptor};
use std::io::net::tcp::{TcpListener, TcpStream};

static EXT_PORT: u16 = 8443;
static SSH_PORT: u16 = 22;
static SSL_PORT: u16 = 9443;

fn keep_copying(mut a: TcpStream, mut b: TcpStream) {
	let mut buf = [0u8,..1024];
	loop {
		let read = match a.read(buf) {
			Err(..) => { drop(a); return; },
			Ok(r) => r
		};
		match b.write(buf.slice_to(read)) {
			Err(..) => { drop(a); return; },
			Ok(..) => ()
		};
	}
}

fn start_pipe(front: TcpStream, port: u16, header: Option<u8>) {
	let mut back = match TcpStream::connect("127.0.0.1", port) {
		Err(e) => {
			println!("Error connecting: {}", e);
			drop(front);
			return;
		},
		Ok(b) => b
	};
	if header.is_some() {
		match back.write_u8(header.unwrap()) {
			Err(e) => {
				println!("Error writing first byte: {}", e);
				drop(back);
				drop(front);
				return;
			},
			Ok(..) => ()
		}
	}
	let front_copy = front.clone();
	let back_copy = back.clone();

	spawn(proc() {
		keep_copying(front, back);
	});
	spawn(proc() {
		keep_copying(back_copy, front_copy);
	});
}

fn handle_new_connection(mut stream: TcpStream) {
	let header: Option<u8> = match stream.read_byte() {
		Err(..) => None,
		Ok(b) => Some(b)
	};
	if header.is_some() && header.unwrap() == 22 || header.unwrap() == 128 {
		start_pipe(stream, SSL_PORT, header);
	}
	else {
		start_pipe(stream, SSH_PORT, header);
	}
}

fn main() {
    let mut acceptor = TcpListener::bind("127.0.0.1", EXT_PORT).listen().unwrap();
    println!("listening started, ready to accept");
    for stream in acceptor.incoming() {
		match stream {
			Err(e) => println!("Strange connection broken: {}", e),
			Ok(stream) => spawn(proc() {
					// connection succeeded
					handle_new_connection(stream);
					})
		}
    }
	drop(acceptor);
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for WASM via wasm-bindgen
extern crate std;

use core::cell::RefCell;
use core::mem;
use std::thread_local;

use wasm_bindgen::prelude::*;

use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
use crate::Error;

#[derive(Clone, Debug)]
enum RngSource {
    Node(NodeCrypto),
    Browser(BrowserCrypto),
}

// JsValues are always per-thread, so we initialize RngSource for each thread.
//   See: https://github.com/rustwasm/wasm-bindgen/pull/955
thread_local!(
    static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    assert_eq!(mem::size_of::<usize>(), 4);

    RNG_SOURCE.with(|f| {
        let mut source = f.borrow_mut();
        if source.is_none() {
            *source = Some(getrandom_init()?);
        }

        match source.as_ref().unwrap() {
            RngSource::Node(n) => n.random_fill_sync(dest),
            RngSource::Browser(n) => {
                // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
                //
                // where it says:
                //
                // > A QuotaExceededError DOMException is thrown if the
                // > requested length is greater than 65536 bytes.
                for chunk in dest.chunks_mut(65536) {
                    n.get_random_values(chunk)
                }
            }
        };
        Ok(())
    })
}

fn getrandom_init() -> Result<RngSource, Error> {
    if let Ok(self_) = Global::get_self() {
        // If `self` is defined then we're in a browser somehow (main window
        // or web worker). Here we want to try to use
        // `crypto.getRandomValues`, but if `crypto` isn't defined we assume
        // we're in an older web browser and the OS RNG isn't available.

        let crypto = self_.crypto();
        if crypto.is_undefined() {
            return Err(BINDGEN_CRYPTO_UNDEF);
        }

        // Test if `crypto.getRandomValues` is undefined as well
        let crypto: BrowserCrypto = crypto.into();
        if crypto.get_random_values_fn().is_undefined() {
            return Err(BINDGEN_GRV_UNDEF);
        }

        return Ok(RngSource::Browser(crypto));
    }

    return Ok(RngSource::Node(node_require("crypto")));
}

#[wasm_bindgen]
extern "C" {
    type Global;
    #[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)]
    fn get_self() -> Result<Self_, JsValue>;

    type Self_;
    #[wasm_bindgen(method, getter, structural)]
    fn crypto(me: &Self_) -> JsValue;

    #[derive(Clone, Debug)]
    type BrowserCrypto;

    // TODO: these `structural` annotations here ideally wouldn't be here to
    // avoid a JS shim, but for now with feature detection they're
    // unavoidable.
    #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
    fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
    #[wasm_bindgen(method, js_name = getRandomValues, structural)]
    fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);

    #[wasm_bindgen(js_name = require)]
    fn node_require(s: &str) -> NodeCrypto;

    #[derive(Clone, Debug)]
    type NodeCrypto;

    #[wasm_bindgen(method, js_name = randomFillSync, structural)]
    fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
}
<commit_msg>Fixing Webpack require warning<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for WASM via wasm-bindgen
extern crate std;

use core::cell::RefCell;
use core::mem;
use std::thread_local;

use wasm_bindgen::prelude::*;

use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
use crate::Error;

#[derive(Clone, Debug)]
enum RngSource {
    Node(NodeCrypto),
    Browser(BrowserCrypto),
}

// JsValues are always per-thread, so we initialize RngSource for each thread.
//   See: https://github.com/rustwasm/wasm-bindgen/pull/955
thread_local!(
    static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    assert_eq!(mem::size_of::<usize>(), 4);

    RNG_SOURCE.with(|f| {
        let mut source = f.borrow_mut();
        if source.is_none() {
            *source = Some(getrandom_init()?);
        }

        match source.as_ref().unwrap() {
            RngSource::Node(n) => n.random_fill_sync(dest),
            RngSource::Browser(n) => {
                // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
                //
                // where it says:
                //
                // > A QuotaExceededError DOMException is thrown if the
                // > requested length is greater than 65536 bytes.
                for chunk in dest.chunks_mut(65536) {
                    n.get_random_values(chunk)
                }
            }
        };
        Ok(())
    })
}

fn getrandom_init() -> Result<RngSource, Error> {
    if let Ok(self_) = Global::get_self() {
        // If `self` is defined then we're in a browser somehow (main window
        // or web worker). Here we want to try to use
        // `crypto.getRandomValues`, but if `crypto` isn't defined we assume
        // we're in an older web browser and the OS RNG isn't available.

        let crypto = self_.crypto();
        if crypto.is_undefined() {
            return Err(BINDGEN_CRYPTO_UNDEF);
        }

        // Test if `crypto.getRandomValues` is undefined as well
        let crypto: BrowserCrypto = crypto.into();
        if crypto.get_random_values_fn().is_undefined() {
            return Err(BINDGEN_GRV_UNDEF);
        }

        return Ok(RngSource::Browser(crypto));
    }

    return Ok(RngSource::Node(MODULE.require("crypto")));
}

#[wasm_bindgen]
extern "C" {
    type Global;
    #[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)]
    fn get_self() -> Result<Self_, JsValue>;

    type Self_;
    #[wasm_bindgen(method, getter, structural)]
    fn crypto(me: &Self_) -> JsValue;

    #[derive(Clone, Debug)]
    type BrowserCrypto;

    // TODO: these `structural` annotations here ideally wouldn't be here to
    // avoid a JS shim, but for now with feature detection they're
    // unavoidable.
    #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
    fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
    #[wasm_bindgen(method, js_name = getRandomValues, structural)]
    fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);

    #[derive(Clone, Debug)]
    type NodeCrypto;

    #[wasm_bindgen(method, js_name = randomFillSync, structural)]
    fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);

    type NodeModule;

    #[wasm_bindgen(js_name = module)]
    static MODULE: NodeModule;

    #[wasm_bindgen(method)]
    fn require(this: &NodeModule, s: &str) -> NodeCrypto;
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let minor = match rustc_minor_version() {
        Some(minor) => minor,
        None => return,
    };

    let target = env::var("TARGET").unwrap();
    let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";

    // std::collections::Bound was stabilized in Rust 1.17
    // but it was moved to core::ops later in Rust 1.26:
    // https://doc.rust-lang.org/core/ops/enum.Bound.html
    if minor >= 26 {
        println!("cargo:rustc-cfg=ops_bound");
    } else if minor >= 17 && cfg!(feature = "std") {
        println!("cargo:rustc-cfg=collections_bound");
    }

    // core::cmp::Reverse stabilized in Rust 1.19:
    // https://doc.rust-lang.org/stable/core/cmp/struct.Reverse.html
    if minor >= 19 {
        println!("cargo:rustc-cfg=core_reverse");
    }

    // CString::into_boxed_c_str and PathBuf::into_boxed_path stabilized in Rust 1.20:
    // https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
    // https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.into_boxed_path
    if minor >= 20 {
        println!("cargo:rustc-cfg=de_boxed_c_str");
        println!("cargo:rustc-cfg=de_boxed_path");
    }

    // From<Box<T>> for Rc<T> / Arc<T> stabilized in Rust 1.21:
    // https://doc.rust-lang.org/std/rc/struct.Rc.html#impl-From<Box<T>>
    // https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-From<Box<T>>
    if minor >= 21 {
        println!("cargo:rustc-cfg=de_rc_dst");
    }

    // Duration available in core since Rust 1.25:
    // https://blog.rust-lang.org/2018/03/29/Rust-1.25.html#library-stabilizations
    if minor >= 25 {
        println!("cargo:rustc-cfg=core_duration");
    }

    // 128-bit integers stabilized in Rust 1.26:
    // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
    //
    // Disabled on Emscripten targets before Rust 1.40 since
    // Emscripten did not support 128-bit integers until Rust 1.40
    // (https://github.com/rust-lang/rust/pull/65251)
    if minor >= 26 && (!emscripten || minor >= 40) {
        println!("cargo:rustc-cfg=integer128");
    }

    // Inclusive ranges methods stabilized in Rust 1.27:
    // https://github.com/rust-lang/rust/pull/50758
    // Also Iterator::try_for_each:
    // https://blog.rust-lang.org/2018/06/21/Rust-1.27.html#library-stabilizations
    if minor >= 27 {
        println!("cargo:rustc-cfg=range_inclusive");
        println!("cargo:rustc-cfg=iterator_try_fold");
    }

    // Non-zero integers stabilized in Rust 1.28:
    // https://blog.rust-lang.org/2018/08/02/Rust-1.28.html#library-stabilizations
    if minor >= 28 {
        println!("cargo:rustc-cfg=num_nonzero");
    }

    // Current minimum supported version of serde_derive crate is Rust 1.31.
    if minor >= 31 {
        println!("cargo:rustc-cfg=serde_derive");
    }

    // TryFrom, Atomic types, non-zero signed integers, and SystemTime::checked_add
    // stabilized in Rust 1.34:
    // https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto
    // https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations
    if minor >= 34 {
        println!("cargo:rustc-cfg=core_try_from");
        println!("cargo:rustc-cfg=num_nonzero_signed");
        println!("cargo:rustc-cfg=systemtime_checked_add");

        // Whitelist of archs that support std::sync::atomic module. Ideally we
        // would use #[cfg(target_has_atomic = "...")] but it is not stable yet.
        // Instead this is based on rustc's src/librustc_target/spec/*.rs.
        let has_atomic64 = target.starts_with("x86_64")
            || target.starts_with("i686")
            || target.starts_with("aarch64")
            || target.starts_with("powerpc64")
            || target.starts_with("sparc64")
            || target.starts_with("mips64el")
            || target.starts_with("riscv64");
        let has_atomic32 = has_atomic64 || emscripten;
        if has_atomic64 {
            println!("cargo:rustc-cfg=std_atomic64");
        }
        if has_atomic32 {
            println!("cargo:rustc-cfg=std_atomic");
        }
    }
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = match env::var_os("RUSTC") {
        Some(rustc) => rustc,
        None => return None,
    };

    let output = match Command::new(rustc).arg("--version").output() {
        Ok(output) => output,
        Err(_) => return None,
    };

    let version = match str::from_utf8(&output.stdout) {
        Ok(version) => version,
        Err(_) => return None,
    };

    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let next = match pieces.next() {
        Some(next) => next,
        None => return None,
    };

    u32::from_str(next).ok()
}
<commit_msg>Update path to rustc target spec files<commit_after>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let minor = match rustc_minor_version() {
        Some(minor) => minor,
        None => return,
    };

    let target = env::var("TARGET").unwrap();
    let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";

    // std::collections::Bound was stabilized in Rust 1.17
    // but it was moved to core::ops later in Rust 1.26:
    // https://doc.rust-lang.org/core/ops/enum.Bound.html
    if minor >= 26 {
        println!("cargo:rustc-cfg=ops_bound");
    } else if minor >= 17 && cfg!(feature = "std") {
        println!("cargo:rustc-cfg=collections_bound");
    }

    // core::cmp::Reverse stabilized in Rust 1.19:
    // https://doc.rust-lang.org/stable/core/cmp/struct.Reverse.html
    if minor >= 19 {
        println!("cargo:rustc-cfg=core_reverse");
    }

    // CString::into_boxed_c_str and PathBuf::into_boxed_path stabilized in Rust 1.20:
    // https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
    // https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.into_boxed_path
    if minor >= 20 {
        println!("cargo:rustc-cfg=de_boxed_c_str");
        println!("cargo:rustc-cfg=de_boxed_path");
    }

    // From<Box<T>> for Rc<T> / Arc<T> stabilized in Rust 1.21:
    // https://doc.rust-lang.org/std/rc/struct.Rc.html#impl-From<Box<T>>
    // https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-From<Box<T>>
    if minor >= 21 {
        println!("cargo:rustc-cfg=de_rc_dst");
    }

    // Duration available in core since Rust 1.25:
    // https://blog.rust-lang.org/2018/03/29/Rust-1.25.html#library-stabilizations
    if minor >= 25 {
        println!("cargo:rustc-cfg=core_duration");
    }

    // 128-bit integers stabilized in Rust 1.26:
    // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
    //
    // Disabled on Emscripten targets before Rust 1.40 since
    // Emscripten did not support 128-bit integers until Rust 1.40
    // (https://github.com/rust-lang/rust/pull/65251)
    if minor >= 26 && (!emscripten || minor >= 40) {
        println!("cargo:rustc-cfg=integer128");
    }

    // Inclusive ranges methods stabilized in Rust 1.27:
    // https://github.com/rust-lang/rust/pull/50758
    // Also Iterator::try_for_each:
    // https://blog.rust-lang.org/2018/06/21/Rust-1.27.html#library-stabilizations
    if minor >= 27 {
        println!("cargo:rustc-cfg=range_inclusive");
        println!("cargo:rustc-cfg=iterator_try_fold");
    }

    // Non-zero integers stabilized in Rust 1.28:
    // https://blog.rust-lang.org/2018/08/02/Rust-1.28.html#library-stabilizations
    if minor >= 28 {
        println!("cargo:rustc-cfg=num_nonzero");
    }

    // Current minimum supported version of serde_derive crate is Rust 1.31.
    if minor >= 31 {
        println!("cargo:rustc-cfg=serde_derive");
    }

    // TryFrom, Atomic types, non-zero signed integers, and SystemTime::checked_add
    // stabilized in Rust 1.34:
    // https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto
    // https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations
    if minor >= 34 {
        println!("cargo:rustc-cfg=core_try_from");
        println!("cargo:rustc-cfg=num_nonzero_signed");
        println!("cargo:rustc-cfg=systemtime_checked_add");

        // Whitelist of archs that support std::sync::atomic module. Ideally we
        // would use #[cfg(target_has_atomic = "...")] but it is not stable yet.
        // Instead this is based on rustc's compiler/rustc_target/src/spec/*.rs.
        let has_atomic64 = target.starts_with("x86_64")
            || target.starts_with("i686")
            || target.starts_with("aarch64")
            || target.starts_with("powerpc64")
            || target.starts_with("sparc64")
            || target.starts_with("mips64el")
            || target.starts_with("riscv64");
        let has_atomic32 = has_atomic64 || emscripten;
        if has_atomic64 {
            println!("cargo:rustc-cfg=std_atomic64");
        }
        if has_atomic32 {
            println!("cargo:rustc-cfg=std_atomic");
        }
    }
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = match env::var_os("RUSTC") {
        Some(rustc) => rustc,
        None => return None,
    };

    let output = match Command::new(rustc).arg("--version").output() {
        Ok(output) => output,
        Err(_) => return None,
    };

    let version = match str::from_utf8(&output.stdout) {
        Ok(version) => version,
        Err(_) => return None,
    };

    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let next = match pieces.next() {
        Some(next) => next,
        None => return None,
    };

    u32::from_str(next).ok()
}
<|endoftext|>