<commit_before>use nom::IResult;
use nom::IResult::*;
use nom::{be_u8, be_u16, Err, ErrorKind};

use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::convert::AsMut;
use std::convert::From;

use network::protocol::proxy_protocol::header::*;

pub const UNKNOWN_FAMILY: u32 = 1;
pub const INCORRECT_VERSION: u32 = 2;

const PROTOCOL_SIGNATURE_V2: [u8; 12] = [0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A];

//NOTE: Only support the V2 for the moment
pub fn parse(buf: &[u8]) -> IResult<&[u8], ProxyProtocolHeader> {
  match tag!(buf, &PROTOCOL_SIGNATURE_V2) {
    Done(rest, _) => {
      match parse_v2_header(rest) {
        Done(rest, header) => Done(rest, ProxyProtocolHeader::V2(header)),
        Incomplete(i) => Incomplete(i),
        Error(e) => Error(e),
      }
    },
    Incomplete(i) => Incomplete(i),
    Error(e) => Error(e),
  }
}

//TODO: Refactor this method using cond! parser if it's possible
fn read_and_verify_ver_and_command(input: &[u8]) -> IResult<&[u8], u8> {
  match be_u8(input) {
    Done(rest, ver_and_cmd) => {
      // Verify if it's the version 2
      if (ver_and_cmd >> 4) & 0x0f == 0x02 {
        return Done(rest, ver_and_cmd)
      }
      Error(ErrorKind::Custom(INCORRECT_VERSION))
    },
    Error(e)      => Error(e),
    Incomplete(e) => Incomplete(e)
  }
}

fn parse_v2_header(input: &[u8]) -> IResult<&[u8], HeaderV2> {
  do_parse!(
    input,
    ver_and_cmd: read_and_verify_ver_and_command >>
    family: be_u8 >>
    len: be_u16 >>
    addr: apply!(parse_addr_v2, family) >>
    (
      HeaderV2 {
        signature: PROTOCOL_SIGNATURE_V2,
        ver_and_cmd,
        family,
        len,
        addr
      }
    )
  )
}

fn parse_addr_v2(input: &[u8], family: u8) -> IResult<&[u8], ProxyAddr> {
  // family: 4 bits for address family and 4 bits for transport protocol
  match (family >> 4) & 0x0f {
    0x00 => Done(input, ProxyAddr::AfUnspec),
    0x01 => parse_ipv4_on_v2(input),
    0x02 => parse_ipv6_on_v2(input),
    _ => Error(ErrorKind::Custom(UNKNOWN_FAMILY)),
  }
}

//TODO: Maybe we can refactor: e.g. count_fixed!(u8, take!(2), 3)
named!(take_4_bytes, take!(4));

fn parse_ipv4_on_v2(input: &[u8]) -> IResult<&[u8], ProxyAddr> {
  do_parse!(
    input,
    src_ip: take_4_bytes >>
    dest_ip: take_4_bytes >>
    src_port: be_u16 >>
    dest_port: be_u16 >>
    (
      ProxyAddr::Ipv4Addr {
        src_addr: SocketAddrV4::new(Ipv4Addr::new(src_ip[0], src_ip[1], src_ip[2], src_ip[3]), src_port),
        dst_addr: SocketAddrV4::new(Ipv4Addr::new(dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3]), dest_port)
      }
    )
  )
}

named!(take_16_bytes, take!(16));

// Transform a slice to an array
fn clone_into_array<A, T>(slice: &[T]) -> A where A: Sized + Default + AsMut<[T]>, T: Clone {
  let mut a = Default::default();
  <A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
  a
}

fn parse_ipv6_on_v2(input: &[u8]) -> IResult<&[u8], ProxyAddr> {
  do_parse!(
    input,
    src_ip: take_16_bytes >>
    dest_ip: take_16_bytes >>
    src_port: be_u16 >>
    dest_port: be_u16 >>
    (
      ProxyAddr::Ipv6Addr {
        src_addr: SocketAddrV6::new(Ipv6Addr::from(clone_into_array::<[u8; 16], u8>(&src_ip[..])), src_port, 0 ,0),
        dst_addr: SocketAddrV6::new(Ipv6Addr::from(clone_into_array::<[u8; 16], u8>(&dest_ip[..])), dest_port, 0 ,0),
      }
    )
  )
}

#[cfg(test)]
mod test {

  use super::*;
  use std::net::{IpAddr, SocketAddr};
  use nom::Needed::Size;

  #[test]
  fn test_parse_proxy_protocol_v2_ipv4_addr_header() {
    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      0x20,                                                                   // Version 2 and command LOCAL
      0x11,                                                                   // family AF_UNIX with IPv4
      0x00, 0x0C,                                                             // address sizes = 12
      0x7D, 0x19, 0x0A, 0x01,                                                 // source address
      0x0A, 0x04, 0x05, 0x08,                                                 // destination address
      0x1F, 0x90,                                                             // source port
      0x10, 0x68,                                                             // destination port
    ];

    let src_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(125, 25, 10, 1)), 8080);
    let dst_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 4, 5, 8)), 4200);
    let expected = ProxyProtocolHeader::V2(HeaderV2::new(Some((src_addr, dst_addr))));

    assert_eq!(Done(&[][..], expected), parse(input));
  }

  #[test]
  fn it_should_parse_proxy_protocol_v2_ipv6_addr_header() {
    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,                         // MAGIC header
      0x20,                                                                                // Version 2 and command LOCAL
      0x21,                                                                                // family AF_UNIX with IPv6
      0x00, 0x24,                                                                                // address sizes = 36
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // source address
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // destination address
      0x1F, 0x90,                                                                                // source port
      0x10, 0x68,                                                                                // destination port
    ];

    let src_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
    let dst_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2)), 4200);
    let expected = ProxyProtocolHeader::V2(HeaderV2::new(Some((src_addr, dst_addr))));

    assert_eq!(Done(&[][..], expected), parse(input));
  }

  #[test]
  fn it_should_parse_proxy_protocol_v2_afunspec_header() {
    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      0x20,                                                                   // Version 2 and command LOCAL
      0x00,                                                                   // family AF_UNSPEC and transport protocol unknow
      0x00, 0x00,                                                             // address sizes = 0
    ];

    let expected = ProxyProtocolHeader::V2(HeaderV2::new(None));

    assert_eq!(Done(&[][..], expected), parse(input));
  }

  #[test]
  fn it_should_not_parse_proxy_protocol_v2_with_unknown_version() {
    let unknow_version = 0x30;

    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      unknow_version,                                                         // Version 2 and command LOCAL
    ];

    assert_eq!(Error(ErrorKind::Custom(INCORRECT_VERSION)), parse(input));
  }

  #[test]
  fn it_should_not_parse_proxy_protocol_with_unknown_family() {
    let unknow_family = 0x30;

    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      0x20,                                                                   // Version 2 and command LOCAL
      unknow_family,                                                          // family
      0x00, 0x00,                                                             // address sizes = 0
    ];

    assert_eq!(Error(ErrorKind::Custom(UNKNOWN_FAMILY)), parse(input));
  }

  #[test]
  fn it_should_not_parse_request_without_magic_header() {

    let input = &[
      0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, // INCORRECT MAGIC header
    ];

    assert_eq!(Error(ErrorKind::Tag), parse(input));
  }

  #[test]
  fn it_should_not_parse_proxy_protocol_v2_ipv4_addr_header_with_missing_data() {
    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      0x20,                                                                   // Version 2 and command LOCAL
      0x11,                                                                   // family AF_UNIX with IPv4
    ];

    assert_eq!(Incomplete(Size(4)), parse(input));
  }
}<commit_msg>Add error_code! to fix the build issue relative to Custom error in the proxy protocol parser<commit_after>use nom::IResult;
use nom::IResult::*;
use nom::{be_u8, be_u16, ErrorKind};

use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::convert::AsMut;
use std::convert::From;

use network::protocol::proxy_protocol::header::*;

pub const UNKNOWN_FAMILY: u32 = 1;
pub const INCORRECT_VERSION: u32 = 2;

const PROTOCOL_SIGNATURE_V2: [u8; 12] = [0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A];

//NOTE: Only support the V2 for the moment
pub fn parse(buf: &[u8]) -> IResult<&[u8], ProxyProtocolHeader> {
  match tag!(buf, &PROTOCOL_SIGNATURE_V2) {
    Done(rest, _) => {
      match parse_v2_header(rest) {
        Done(rest, header) => Done(rest, ProxyProtocolHeader::V2(header)),
        Incomplete(i) => Incomplete(i),
        Error(e) => Error(e),
      }
    },
    Incomplete(i) => Incomplete(i),
    Error(e) => Error(e),
  }
}

//TODO: Refactor this method using cond! parser if it's possible
fn read_and_verify_ver_and_command(input: &[u8]) -> IResult<&[u8], u8> {
  match be_u8(input) {
    Done(rest, ver_and_cmd) => {
      // Verify if it's the version 2
      if (ver_and_cmd >> 4) & 0x0f == 0x02 {
        return Done(rest, ver_and_cmd)
      }
      Error(error_code!(ErrorKind::Custom(INCORRECT_VERSION)))
    },
    Error(e)      => Error(e),
    Incomplete(e) => Incomplete(e)
  }
}

fn parse_v2_header(input: &[u8]) -> IResult<&[u8], HeaderV2> {
  do_parse!(
    input,
    ver_and_cmd: read_and_verify_ver_and_command >>
    family: be_u8 >>
    len: be_u16 >>
    addr: apply!(parse_addr_v2, family) >>
    (
      HeaderV2 {
        signature: PROTOCOL_SIGNATURE_V2,
        ver_and_cmd,
        family,
        len,
        addr
      }
    )
  )
}

fn parse_addr_v2(input: &[u8], family: u8) -> IResult<&[u8], ProxyAddr> {
  // family: 4 bits for address family and 4 bits for transport protocol
  match (family >> 4) & 0x0f {
    0x00 => Done(input, ProxyAddr::AfUnspec),
    0x01 => parse_ipv4_on_v2(input),
    0x02 => parse_ipv6_on_v2(input),
    _ => Error(error_code!(ErrorKind::Custom(UNKNOWN_FAMILY))),
  }
}

//TODO: Maybe we can refactor: e.g. count_fixed!(u8, take!(2), 3)
named!(take_4_bytes, take!(4));

fn parse_ipv4_on_v2(input: &[u8]) -> IResult<&[u8], ProxyAddr> {
  do_parse!(
    input,
    src_ip: take_4_bytes >>
    dest_ip: take_4_bytes >>
    src_port: be_u16 >>
    dest_port: be_u16 >>
    (
      ProxyAddr::Ipv4Addr {
        src_addr: SocketAddrV4::new(Ipv4Addr::new(src_ip[0], src_ip[1], src_ip[2], src_ip[3]), src_port),
        dst_addr: SocketAddrV4::new(Ipv4Addr::new(dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3]), dest_port)
      }
    )
  )
}

named!(take_16_bytes, take!(16));

// Transform a slice to an array
fn clone_into_array<A, T>(slice: &[T]) -> A where A: Sized + Default + AsMut<[T]>, T: Clone {
  let mut a = Default::default();
  <A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
  a
}

fn parse_ipv6_on_v2(input: &[u8]) -> IResult<&[u8], ProxyAddr> {
  do_parse!(
    input,
    src_ip: take_16_bytes >>
    dest_ip: take_16_bytes >>
    src_port: be_u16 >>
    dest_port: be_u16 >>
    (
      ProxyAddr::Ipv6Addr {
        src_addr: SocketAddrV6::new(Ipv6Addr::from(clone_into_array::<[u8; 16], u8>(&src_ip[..])), src_port, 0 ,0),
        dst_addr: SocketAddrV6::new(Ipv6Addr::from(clone_into_array::<[u8; 16], u8>(&dest_ip[..])), dest_port, 0 ,0),
      }
    )
  )
}

#[cfg(test)]
mod test {

  use super::*;
  use std::net::{IpAddr, SocketAddr};
  use nom::Needed::Size;

  #[test]
  fn test_parse_proxy_protocol_v2_ipv4_addr_header() {
    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      0x20,                                                                   // Version 2 and command LOCAL
      0x11,                                                                   // family AF_UNIX with IPv4
      0x00, 0x0C,                                                             // address sizes = 12
      0x7D, 0x19, 0x0A, 0x01,                                                 // source address
      0x0A, 0x04, 0x05, 0x08,                                                 // destination address
      0x1F, 0x90,                                                             // source port
      0x10, 0x68,                                                             // destination port
    ];

    let src_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(125, 25, 10, 1)), 8080);
    let dst_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 4, 5, 8)), 4200);
    let expected = ProxyProtocolHeader::V2(HeaderV2::new(Some((src_addr, dst_addr))));

    assert_eq!(Done(&[][..], expected), parse(input));
  }

  #[test]
  fn it_should_parse_proxy_protocol_v2_ipv6_addr_header() {
    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,                         // MAGIC header
      0x20,                                                                                // Version 2 and command LOCAL
      0x21,                                                                                // family AF_UNIX with IPv6
      0x00, 0x24,                                                                                // address sizes = 36
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // source address
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // destination address
      0x1F, 0x90,                                                                                // source port
      0x10, 0x68,                                                                                // destination port
    ];

    let src_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
    let dst_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2)), 4200);
    let expected = ProxyProtocolHeader::V2(HeaderV2::new(Some((src_addr, dst_addr))));

    assert_eq!(Done(&[][..], expected), parse(input));
  }

  #[test]
  fn it_should_parse_proxy_protocol_v2_afunspec_header() {
    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      0x20,                                                                   // Version 2 and command LOCAL
      0x00,                                                                   // family AF_UNSPEC and transport protocol unknow
      0x00, 0x00,                                                             // address sizes = 0
    ];

    let expected = ProxyProtocolHeader::V2(HeaderV2::new(None));

    assert_eq!(Done(&[][..], expected), parse(input));
  }

  #[test]
  fn it_should_not_parse_proxy_protocol_v2_with_unknown_version() {
    let unknow_version = 0x30;

    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      unknow_version,                                                         // Version 2 and command LOCAL
    ];

    assert_eq!(Error(ErrorKind::Custom(INCORRECT_VERSION)), parse(input));
  }

  #[test]
  fn it_should_not_parse_proxy_protocol_with_unknown_family() {
    let unknow_family = 0x30;

    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      0x20,                                                                   // Version 2 and command LOCAL
      unknow_family,                                                          // family
      0x00, 0x00,                                                             // address sizes = 0
    ];

    assert_eq!(Error(ErrorKind::Custom(UNKNOWN_FAMILY)), parse(input));
  }

  #[test]
  fn it_should_not_parse_request_without_magic_header() {

    let input = &[
      0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, // INCORRECT MAGIC header
    ];

    assert_eq!(Error(ErrorKind::Tag), parse(input));
  }

  #[test]
  fn it_should_not_parse_proxy_protocol_v2_ipv4_addr_header_with_missing_data() {
    let input = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      0x20,                                                                   // Version 2 and command LOCAL
      0x11,                                                                   // family AF_UNIX with IPv4
    ];

    assert_eq!(Incomplete(Size(4)), parse(input));
  }
}<|endoftext|>


<commit_before>use juniper::{graphql_value, RootNode, Value, GraphQLError};

#[derive(juniper::GraphQLEnum)]
enum UserKind {
    Admin,
    User,
    Guest,
}

struct User {
    id: u64,
    name: String,
    kind: UserKind,
}

#[juniper::graphql_object]
impl User {
    async fn name(&self) -> &str {
        &self.name
    }

    async fn friends(&self) -> Vec<User> {
        (0..10)
            .map(|index| User {
                id: index,
                name: format!("user{}", index),
                kind: UserKind::User,
            })
            .collect()
    }

    async fn kind(&self) -> &UserKind {
        &self.kind
    }

    async fn delayed() -> bool {
        tokio::time::delay_for(std::time::Duration::from_millis(100)).await;
        true
    }
}

struct Query;

#[juniper::graphql_object]
impl Query {
    fn field_sync(&self) -> &'static str {
        "field_sync"
    }

    async fn field_async_plain() -> String {
        "field_async_plain".to_string()
    }

    fn user(id: String) -> User {
        User {
            id: 1,
            name: id,
            kind: UserKind::User,
        }
    }

    async fn delayed() -> bool {
        tokio::time::delay_for(std::time::Duration::from_millis(100)).await;
        true
    }
}

struct Mutation;

#[juniper::graphql_object]
impl Mutation {}

#[tokio::test]
async fn async_simple() {
    let schema = RootNode::new(Query, Mutation);
    let doc = r#"
        query {
            fieldSync
            fieldAsyncPlain
            delayed
            user(id: "user1") {
                kind
                name
                delayed
            }
        }
    "#;

    let vars = Default::default();
    let (res, errs) = juniper::execute_async(doc, None, &schema, &vars, &())
        .await
        .unwrap();

    assert!(errs.is_empty());

    let mut obj = res.into_object().unwrap();
    obj.sort_by_field();
    let value = Value::Object(obj);

    assert_eq!(
        value,
        graphql_value!({
            "delayed": true,
            "fieldAsyncPlain": "field_async_plain",
            "fieldSync": "field_sync",
            "user": {
                "delayed": true,
                "kind": "USER",
                "name": "user1",
            },
        }),
    );
}

#[tokio::test]
async fn async_field_validation_error() {
    let schema = RootNode::new(Query, Mutation);
    let doc = r#"
        query {
            nonExistentField
            fieldSync
            fieldAsyncPlain
            delayed
            user(id: "user1") {
                kind
                name
                delayed
            }
        }
    "#;

    let vars = Default::default();
    let result = juniper::execute_async(doc, None, &schema, &vars, &())
        .await;
    assert!(result.is_err());

    let error = result.err().unwrap();
    let is_validation_error = match error {
        GraphQLError::ValidationError(_) => true,
        _ => false
    };
    assert!(is_validation_error);
}

fn main() {}
<commit_msg>Format code<commit_after>use juniper::{graphql_value, GraphQLError, RootNode, Value};

#[derive(juniper::GraphQLEnum)]
enum UserKind {
    Admin,
    User,
    Guest,
}

struct User {
    id: u64,
    name: String,
    kind: UserKind,
}

#[juniper::graphql_object]
impl User {
    async fn name(&self) -> &str {
        &self.name
    }

    async fn friends(&self) -> Vec<User> {
        (0..10)
            .map(|index| User {
                id: index,
                name: format!("user{}", index),
                kind: UserKind::User,
            })
            .collect()
    }

    async fn kind(&self) -> &UserKind {
        &self.kind
    }

    async fn delayed() -> bool {
        tokio::time::delay_for(std::time::Duration::from_millis(100)).await;
        true
    }
}

struct Query;

#[juniper::graphql_object]
impl Query {
    fn field_sync(&self) -> &'static str {
        "field_sync"
    }

    async fn field_async_plain() -> String {
        "field_async_plain".to_string()
    }

    fn user(id: String) -> User {
        User {
            id: 1,
            name: id,
            kind: UserKind::User,
        }
    }

    async fn delayed() -> bool {
        tokio::time::delay_for(std::time::Duration::from_millis(100)).await;
        true
    }
}

struct Mutation;

#[juniper::graphql_object]
impl Mutation {}

#[tokio::test]
async fn async_simple() {
    let schema = RootNode::new(Query, Mutation);
    let doc = r#"
        query {
            fieldSync
            fieldAsyncPlain
            delayed
            user(id: "user1") {
                kind
                name
                delayed
            }
        }
    "#;

    let vars = Default::default();
    let (res, errs) = juniper::execute_async(doc, None, &schema, &vars, &())
        .await
        .unwrap();

    assert!(errs.is_empty());

    let mut obj = res.into_object().unwrap();
    obj.sort_by_field();
    let value = Value::Object(obj);

    assert_eq!(
        value,
        graphql_value!({
            "delayed": true,
            "fieldAsyncPlain": "field_async_plain",
            "fieldSync": "field_sync",
            "user": {
                "delayed": true,
                "kind": "USER",
                "name": "user1",
            },
        }),
    );
}

#[tokio::test]
async fn async_field_validation_error() {
    let schema = RootNode::new(Query, Mutation);
    let doc = r#"
        query {
            nonExistentField
            fieldSync
            fieldAsyncPlain
            delayed
            user(id: "user1") {
                kind
                name
                delayed
            }
        }
    "#;

    let vars = Default::default();
    let result = juniper::execute_async(doc, None, &schema, &vars, &()).await;
    assert!(result.is_err());

    let error = result.err().unwrap();
    let is_validation_error = match error {
        GraphQLError::ValidationError(_) => true,
        _ => false,
    };
    assert!(is_validation_error);
}

fn main() {}
<|endoftext|>


<commit_before>// # References
//
// "The Content-Disposition Header Field" https://www.ietf.org/rfc/rfc2183.txt
// "The Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)" https://www.ietf.org/rfc/rfc6266.txt
// "Returning Values from Forms: multipart/form-data" https://www.ietf.org/rfc/rfc2388.txt
// Browser conformance tests at: http://greenbytes.de/tech/tc2231/
// IANA assignment: http://www.iana.org/assignments/cont-disp/cont-disp.xhtml

use language_tags::LanguageTag;
use header;
use header::{Header, IntoHeaderValue, Writer};
use header::shared::Charset;

use std::fmt::{self, Write};

/// The implied disposition of the content of the HTTP body.
#[derive(Clone, Debug, PartialEq)]
pub enum DispositionType {
    /// Inline implies default processing
    Inline,
    /// Attachment implies that the recipient should prompt the user to save the response locally,
    /// rather than process it normally (as per its media type).
    Attachment,
    /// Extension type.  Should be handled by recipients the same way as Attachment
    Ext(String)
}

/// A parameter to the disposition type.
#[derive(Clone, Debug, PartialEq)]
pub enum DispositionParam {
    /// A Filename consisting of a Charset, an optional LanguageTag, and finally a sequence of
    /// bytes representing the filename
    Filename(Charset, Option<LanguageTag>, Vec<u8>),
    /// Extension type consisting of token and value.  Recipients should ignore unrecognized
    /// parameters.
    Ext(String, String)
}

/// A `Content-Disposition` header, (re)defined in [RFC6266](https://tools.ietf.org/html/rfc6266).
///
/// The Content-Disposition response header field is used to convey
/// additional information about how to process the response payload, and
/// also can be used to attach additional metadata, such as the filename
/// to use when saving the response payload locally.
///
/// # ABNF

/// ```text
/// content-disposition = "Content-Disposition" ":"
///                       disposition-type *( ";" disposition-parm )
///
/// disposition-type    = "inline" | "attachment" | disp-ext-type
///                       ; case-insensitive
///
/// disp-ext-type       = token
///
/// disposition-parm    = filename-parm | disp-ext-parm
///
/// filename-parm       = "filename" "=" value
///                     | "filename*" "=" ext-value
///
/// disp-ext-parm       = token "=" value
///                     | ext-token "=" ext-value
///
/// ext-token           = <the characters in token, followed by "*">
/// ```
///
/// # Example
///
/// ```
/// use actix_web::http::header::{ContentDisposition, DispositionType, DispositionParam, Charset};
///
/// let cd = ContentDisposition {
///     disposition: DispositionType::Attachment,
///     parameters: vec![DispositionParam::Filename(
///       Charset::Iso_8859_1, // The character set for the bytes of the filename
///       None, // The optional language tag (see `language-tag` crate)
///       b"\xa9 Copyright 1989.txt".to_vec() // the actual bytes of the filename
///     )]
/// };
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct ContentDisposition {
    /// The disposition
    pub disposition: DispositionType,
    /// Disposition parameters
    pub parameters: Vec<DispositionParam>,
}
impl ContentDisposition {
    /// Parse a raw Content-Disposition header value
    pub fn from_raw(hv: &header::HeaderValue) -> Result<Self, ::error::ParseError> {
        header::from_one_raw_str(Some(hv)).and_then(|s: String| {
            let mut sections = s.split(';');
            let disposition = match sections.next() {
                Some(s) => s.trim(),
                None => return Err(::error::ParseError::Header),
            };

            let mut cd = ContentDisposition {
                disposition: if disposition.eq_ignore_ascii_case("inline") {
                    DispositionType::Inline
                } else if disposition.eq_ignore_ascii_case("attachment") {
                    DispositionType::Attachment
                } else {
                    DispositionType::Ext(disposition.to_owned())
                },
                parameters: Vec::new(),
            };

            for section in sections {
                let mut parts = section.splitn(2, '=');

                let key = if let Some(key) = parts.next() {
                    key.trim()
                } else {
                    return Err(::error::ParseError::Header);
                };

                let val = if let Some(val) = parts.next() {
                    val.trim()
                } else {
                    return Err(::error::ParseError::Header);
                };

                cd.parameters.push(
                    if key.eq_ignore_ascii_case("filename") {
                        DispositionParam::Filename(
                            Charset::Ext("UTF-8".to_owned()), None,
                            val.trim_matches('"').as_bytes().to_owned())
                    } else if key.eq_ignore_ascii_case("filename*") {
                        let extended_value = try!(header::parse_extended_value(val));
                        DispositionParam::Filename(extended_value.charset, extended_value.language_tag, extended_value.value)
                    } else {
                        DispositionParam::Ext(key.to_owned(), val.trim_matches('"').to_owned())
                    }
                );
            }

            Ok(cd)
        })
    }
}

impl IntoHeaderValue for ContentDisposition {
    type Error = header::InvalidHeaderValueBytes;

    fn try_into(self) -> Result<header::HeaderValue, Self::Error> {
        let mut writer = Writer::new();
        let _ = write!(&mut writer, "{}", self);
        header::HeaderValue::from_shared(writer.take())
    }
}

impl Header for ContentDisposition {
    fn name() -> header::HeaderName {
        header::CONTENT_DISPOSITION
    }

    fn parse<T: ::HttpMessage>(msg: &T) -> Result<Self, ::error::ParseError> {
        if let Some(h) = msg.headers().get(Self::name()) {
            Self::from_raw(&h)
        } else {
            Err(::error::ParseError::Header)
        }
    }
}

impl fmt::Display for ContentDisposition {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.disposition {
            DispositionType::Inline => try!(write!(f, "inline")),
            DispositionType::Attachment => try!(write!(f, "attachment")),
            DispositionType::Ext(ref s) => try!(write!(f, "{}", s)),
        }
        for param in &self.parameters {
            match *param {
                DispositionParam::Filename(ref charset, ref opt_lang, ref bytes) => {
                    let mut use_simple_format: bool = false;
                    if opt_lang.is_none() {
                        if let Charset::Ext(ref ext) = *charset {
                            if ext.eq_ignore_ascii_case("utf-8") {
                                use_simple_format = true;
                            }
                        }
                    }
                    if use_simple_format {
                        try!(write!(f, "; filename=\"{}\"",
                                    match String::from_utf8(bytes.clone()) {
                                        Ok(s) => s,
                                        Err(_) => return Err(fmt::Error),
                                    }));
                    } else {
                        try!(write!(f, "; filename*={}'", charset));
                        if let Some(ref lang) = *opt_lang {
                            try!(write!(f, "{}", lang));
                        };
                        try!(write!(f, "'"));
                        try!(header::http_percent_encode(f, bytes))
                    }
                },
                DispositionParam::Ext(ref k, ref v) => try!(write!(f, "; {}=\"{}\"", k, v)),
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::{ContentDisposition,DispositionType,DispositionParam};
    use header::HeaderValue;
    use header::shared::Charset;
    #[test]
    fn test_from_raw() {
        assert!(ContentDisposition::from_raw(&HeaderValue::from_static("")).is_err());

        let a = HeaderValue::from_static("form-data; dummy=3; name=upload; filename=\"sample.png\"");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Ext("form-data".to_owned()),
            parameters: vec![
                DispositionParam::Ext("dummy".to_owned(), "3".to_owned()),
                DispositionParam::Ext("name".to_owned(), "upload".to_owned()),
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    "sample.png".bytes().collect()) ]
        };
        assert_eq!(a, b);

        let a = HeaderValue::from_static("attachment; filename=\"image.jpg\"");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Attachment,
            parameters: vec![
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    "image.jpg".bytes().collect()) ]
        };
        assert_eq!(a, b);

        let a = HeaderValue::from_static("attachment; filename*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Attachment,
            parameters: vec![
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    vec![0xc2, 0xa3, 0x20, b'a', b'n', b'd', 0x20,
                         0xe2, 0x82, 0xac, 0x20, b'r', b'a', b't', b'e', b's']) ]
        };
        assert_eq!(a, b);
    }

    #[test]
    fn test_display() {
        let as_string = "attachment; filename*=UTF-8'en'%C2%A3%20and%20%E2%82%AC%20rates";
        let a = HeaderValue::from_static(as_string);
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!(as_string, display_rendered);

        let a = HeaderValue::from_static("attachment; filename*=UTF-8''black%20and%20white.csv");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!("attachment; filename=\"black and white.csv\"".to_owned(), display_rendered);

        let a = HeaderValue::from_static("attachment; filename=colourful.csv");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!("attachment; filename=\"colourful.csv\"".to_owned(), display_rendered);
    }
}
<commit_msg>content_disposition: add doc example<commit_after>// # References
//
// "The Content-Disposition Header Field" https://www.ietf.org/rfc/rfc2183.txt
// "The Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)" https://www.ietf.org/rfc/rfc6266.txt
// "Returning Values from Forms: multipart/form-data" https://www.ietf.org/rfc/rfc2388.txt
// Browser conformance tests at: http://greenbytes.de/tech/tc2231/
// IANA assignment: http://www.iana.org/assignments/cont-disp/cont-disp.xhtml

use language_tags::LanguageTag;
use header;
use header::{Header, IntoHeaderValue, Writer};
use header::shared::Charset;

use std::fmt::{self, Write};

/// The implied disposition of the content of the HTTP body.
#[derive(Clone, Debug, PartialEq)]
pub enum DispositionType {
    /// Inline implies default processing
    Inline,
    /// Attachment implies that the recipient should prompt the user to save the response locally,
    /// rather than process it normally (as per its media type).
    Attachment,
    /// Extension type.  Should be handled by recipients the same way as Attachment
    Ext(String)
}

/// A parameter to the disposition type.
#[derive(Clone, Debug, PartialEq)]
pub enum DispositionParam {
    /// A Filename consisting of a Charset, an optional LanguageTag, and finally a sequence of
    /// bytes representing the filename
    Filename(Charset, Option<LanguageTag>, Vec<u8>),
    /// Extension type consisting of token and value.  Recipients should ignore unrecognized
    /// parameters.
    Ext(String, String)
}

/// A `Content-Disposition` header, (re)defined in [RFC6266](https://tools.ietf.org/html/rfc6266).
///
/// The Content-Disposition response header field is used to convey
/// additional information about how to process the response payload, and
/// also can be used to attach additional metadata, such as the filename
/// to use when saving the response payload locally.
///
/// # ABNF

/// ```text
/// content-disposition = "Content-Disposition" ":"
///                       disposition-type *( ";" disposition-parm )
///
/// disposition-type    = "inline" | "attachment" | disp-ext-type
///                       ; case-insensitive
///
/// disp-ext-type       = token
///
/// disposition-parm    = filename-parm | disp-ext-parm
///
/// filename-parm       = "filename" "=" value
///                     | "filename*" "=" ext-value
///
/// disp-ext-parm       = token "=" value
///                     | ext-token "=" ext-value
///
/// ext-token           = <the characters in token, followed by "*">
/// ```
///
/// # Example
///
/// ```
/// use actix_web::http::header::{ContentDisposition, DispositionType, DispositionParam, Charset};
///
/// let cd1 = ContentDisposition {
///     disposition: DispositionType::Attachment,
///     parameters: vec![DispositionParam::Filename(
///       Charset::Iso_8859_1, // The character set for the bytes of the filename
///       None, // The optional language tag (see `language-tag` crate)
///       b"\xa9 Copyright 1989.txt".to_vec() // the actual bytes of the filename
///     )]
/// };
///
/// let cd2 = ContentDisposition {
///     disposition: DispositionType::Inline,
///     parameters: vec![DispositionParam::Filename(
///       Charset::Ext("UTF-8".to_owned()),
///       None,
///       "\u{2764}".as_bytes().to_vec()
///     )]
/// };
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct ContentDisposition {
    /// The disposition
    pub disposition: DispositionType,
    /// Disposition parameters
    pub parameters: Vec<DispositionParam>,
}
impl ContentDisposition {
    /// Parse a raw Content-Disposition header value
    pub fn from_raw(hv: &header::HeaderValue) -> Result<Self, ::error::ParseError> {
        header::from_one_raw_str(Some(hv)).and_then(|s: String| {
            let mut sections = s.split(';');
            let disposition = match sections.next() {
                Some(s) => s.trim(),
                None => return Err(::error::ParseError::Header),
            };

            let mut cd = ContentDisposition {
                disposition: if disposition.eq_ignore_ascii_case("inline") {
                    DispositionType::Inline
                } else if disposition.eq_ignore_ascii_case("attachment") {
                    DispositionType::Attachment
                } else {
                    DispositionType::Ext(disposition.to_owned())
                },
                parameters: Vec::new(),
            };

            for section in sections {
                let mut parts = section.splitn(2, '=');

                let key = if let Some(key) = parts.next() {
                    key.trim()
                } else {
                    return Err(::error::ParseError::Header);
                };

                let val = if let Some(val) = parts.next() {
                    val.trim()
                } else {
                    return Err(::error::ParseError::Header);
                };

                cd.parameters.push(
                    if key.eq_ignore_ascii_case("filename") {
                        DispositionParam::Filename(
                            Charset::Ext("UTF-8".to_owned()), None,
                            val.trim_matches('"').as_bytes().to_owned())
                    } else if key.eq_ignore_ascii_case("filename*") {
                        let extended_value = try!(header::parse_extended_value(val));
                        DispositionParam::Filename(extended_value.charset, extended_value.language_tag, extended_value.value)
                    } else {
                        DispositionParam::Ext(key.to_owned(), val.trim_matches('"').to_owned())
                    }
                );
            }

            Ok(cd)
        })
    }
}

impl IntoHeaderValue for ContentDisposition {
    type Error = header::InvalidHeaderValueBytes;

    fn try_into(self) -> Result<header::HeaderValue, Self::Error> {
        let mut writer = Writer::new();
        let _ = write!(&mut writer, "{}", self);
        header::HeaderValue::from_shared(writer.take())
    }
}

impl Header for ContentDisposition {
    fn name() -> header::HeaderName {
        header::CONTENT_DISPOSITION
    }

    fn parse<T: ::HttpMessage>(msg: &T) -> Result<Self, ::error::ParseError> {
        if let Some(h) = msg.headers().get(Self::name()) {
            Self::from_raw(&h)
        } else {
            Err(::error::ParseError::Header)
        }
    }
}

impl fmt::Display for ContentDisposition {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.disposition {
            DispositionType::Inline => try!(write!(f, "inline")),
            DispositionType::Attachment => try!(write!(f, "attachment")),
            DispositionType::Ext(ref s) => try!(write!(f, "{}", s)),
        }
        for param in &self.parameters {
            match *param {
                DispositionParam::Filename(ref charset, ref opt_lang, ref bytes) => {
                    let mut use_simple_format: bool = false;
                    if opt_lang.is_none() {
                        if let Charset::Ext(ref ext) = *charset {
                            if ext.eq_ignore_ascii_case("utf-8") {
                                use_simple_format = true;
                            }
                        }
                    }
                    if use_simple_format {
                        try!(write!(f, "; filename=\"{}\"",
                                    match String::from_utf8(bytes.clone()) {
                                        Ok(s) => s,
                                        Err(_) => return Err(fmt::Error),
                                    }));
                    } else {
                        try!(write!(f, "; filename*={}'", charset));
                        if let Some(ref lang) = *opt_lang {
                            try!(write!(f, "{}", lang));
                        };
                        try!(write!(f, "'"));
                        try!(header::http_percent_encode(f, bytes))
                    }
                },
                DispositionParam::Ext(ref k, ref v) => try!(write!(f, "; {}=\"{}\"", k, v)),
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::{ContentDisposition,DispositionType,DispositionParam};
    use header::HeaderValue;
    use header::shared::Charset;
    #[test]
    fn test_from_raw() {
        assert!(ContentDisposition::from_raw(&HeaderValue::from_static("")).is_err());

        let a = HeaderValue::from_static("form-data; dummy=3; name=upload; filename=\"sample.png\"");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Ext("form-data".to_owned()),
            parameters: vec![
                DispositionParam::Ext("dummy".to_owned(), "3".to_owned()),
                DispositionParam::Ext("name".to_owned(), "upload".to_owned()),
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    "sample.png".bytes().collect()) ]
        };
        assert_eq!(a, b);

        let a = HeaderValue::from_static("attachment; filename=\"image.jpg\"");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Attachment,
            parameters: vec![
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    "image.jpg".bytes().collect()) ]
        };
        assert_eq!(a, b);

        let a = HeaderValue::from_static("attachment; filename*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Attachment,
            parameters: vec![
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    vec![0xc2, 0xa3, 0x20, b'a', b'n', b'd', 0x20,
                         0xe2, 0x82, 0xac, 0x20, b'r', b'a', b't', b'e', b's']) ]
        };
        assert_eq!(a, b);
    }

    #[test]
    fn test_display() {
        let as_string = "attachment; filename*=UTF-8'en'%C2%A3%20and%20%E2%82%AC%20rates";
        let a = HeaderValue::from_static(as_string);
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!(as_string, display_rendered);

        let a = HeaderValue::from_static("attachment; filename*=UTF-8''black%20and%20white.csv");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!("attachment; filename=\"black and white.csv\"".to_owned(), display_rendered);

        let a = HeaderValue::from_static("attachment; filename=colourful.csv");
        let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!("attachment; filename=\"colourful.csv\"".to_owned(), display_rendered);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use LinkerFlavor;
use target::{LinkArgs, TargetOptions, RelroLevel};
use std::default::Default;

pub fn opts() -> TargetOptions {
    let mut args = LinkArgs::new();
    args.insert(LinkerFlavor::Gcc, vec![
        // GNU-style linkers will use this to omit linking to libraries
        // which don't actually fulfill any relocations, but only for
        // libraries which follow this flag.  Thus, use it before
        // specifying libraries to link to.
        "-Wl,--as-needed".to_string(),

        // Always enable NX protection when it is available
        "-Wl,-z,noexecstack".to_string(),
    ]);

    TargetOptions {
        dynamic_linking: true,
        executables: true,
        target_family: Some("unix".to_string()),
        linker_is_gnu: true,
        has_rpath: true,
        pre_link_args: args,
        position_independent_executables: true,
        relro_level: RelroLevel::Full,
        exe_allocation_crate: super::maybe_jemalloc(),
        .. Default::default()
    }
}
<commit_msg>Workaround abort(2) on compilation error on FreeBSD.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use LinkerFlavor;
use target::{LinkArgs, TargetOptions, RelroLevel};
use std::default::Default;

pub fn opts() -> TargetOptions {
    let mut args = LinkArgs::new();
    args.insert(LinkerFlavor::Gcc, vec![
        // GNU-style linkers will use this to omit linking to libraries
        // which don't actually fulfill any relocations, but only for
        // libraries which follow this flag.  Thus, use it before
        // specifying libraries to link to.
        "-Wl,--as-needed".to_string(),

        // Always enable NX protection when it is available
        "-Wl,-z,noexecstack".to_string(),
    ]);

    TargetOptions {
        dynamic_linking: true,
        executables: true,
        target_family: Some("unix".to_string()),
        linker_is_gnu: true,
        has_rpath: true,
        pre_link_args: args,
        position_independent_executables: true,
        eliminate_frame_pointer: false, // FIXME 43575
        relro_level: RelroLevel::Full,
        exe_allocation_crate: super::maybe_jemalloc(),
        .. Default::default()
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use context::SharedCrateContext;
use monomorphize::Instance;
use symbol_map::SymbolMap;
use util::nodemap::FxHashMap;
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::session::config;
use syntax::attr;
use trans_item::TransItem;

/// The SymbolExportLevel of a symbols specifies from which kinds of crates
/// the symbol will be exported. `C` symbols will be exported from any
/// kind of crate, including cdylibs which export very few things.
/// `Rust` will only be exported if the crate produced is a Rust
/// dylib.
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum SymbolExportLevel {
    C,
    Rust,
}

/// The set of symbols exported from each crate in the crate graph.
pub struct ExportedSymbols {
    exports: FxHashMap<CrateNum, Vec<(String, SymbolExportLevel)>>,
}

impl ExportedSymbols {

    pub fn empty() -> ExportedSymbols {
        ExportedSymbols {
            exports: FxHashMap(),
        }
    }

    pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                  symbol_map: &SymbolMap<'tcx>)
                                  -> ExportedSymbols {
        let mut local_crate: Vec<_> = scx
            .exported_symbols()
            .iter()
            .map(|&node_id| {
                scx.tcx().map.local_def_id(node_id)
            })
            .map(|def_id| {
                (symbol_for_def_id(scx, def_id, symbol_map),
                 export_level(scx, def_id))
            })
            .collect();

        if scx.sess().entry_fn.borrow().is_some() {
            local_crate.push(("main".to_string(), SymbolExportLevel::C));
        }

        if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) {
            local_crate.push((scx.metadata_symbol_name(),
                              SymbolExportLevel::Rust));
        }

        let mut exports = FxHashMap();
        exports.insert(LOCAL_CRATE, local_crate);

        for cnum in scx.sess().cstore.crates() {
            debug_assert!(cnum != LOCAL_CRATE);

            if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() ||
               scx.sess().cstore.derive_registrar_fn(cnum).is_some() {
                continue;
            }

            let crate_exports = scx
                .sess()
                .cstore
                .exported_symbols(cnum)
                .iter()
                .map(|&def_id| {
                    debug!("EXTERN-SYMBOL: {:?}", def_id);
                    let name = Instance::mono(scx, def_id).symbol_name(scx);
                    (name, export_level(scx, def_id))
                })
                .collect();

            exports.insert(cnum, crate_exports);
        }

        return ExportedSymbols {
            exports: exports
        };

        fn export_level(scx: &SharedCrateContext,
                        sym_def_id: DefId)
                        -> SymbolExportLevel {
            let attrs = scx.tcx().get_attrs(sym_def_id);
            if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) {
                SymbolExportLevel::C
            } else {
                SymbolExportLevel::Rust
            }
        }
    }

    pub fn exported_symbols(&self,
                            cnum: CrateNum)
                            -> &[(String, SymbolExportLevel)] {
        match self.exports.get(&cnum) {
            Some(exports) => &exports[..],
            None => &[]
        }
    }

    pub fn for_each_exported_symbol<F>(&self,
                                       cnum: CrateNum,
                                       export_threshold: SymbolExportLevel,
                                       mut f: F)
        where F: FnMut(&str, SymbolExportLevel)
    {
        for &(ref name, export_level) in self.exported_symbols(cnum) {
            if is_below_threshold(export_level, export_threshold) {
                f(&name[..], export_level)
            }
        }
    }
}

pub fn crate_export_threshold(crate_type: config::CrateType)
                                     -> SymbolExportLevel {
    match crate_type {
        config::CrateTypeExecutable |
        config::CrateTypeStaticlib  |
        config::CrateTypeCdylib     => SymbolExportLevel::C,
        config::CrateTypeProcMacro  |
        config::CrateTypeRlib       |
        config::CrateTypeMetadata   |
        config::CrateTypeDylib      => SymbolExportLevel::Rust,
    }
}

pub fn crates_export_threshold(crate_types: &[config::CrateType])
                                      -> SymbolExportLevel {
    if crate_types.iter().any(|&crate_type| {
        crate_export_threshold(crate_type) == SymbolExportLevel::Rust
    }) {
        SymbolExportLevel::Rust
    } else {
        SymbolExportLevel::C
    }
}

pub fn is_below_threshold(level: SymbolExportLevel,
                          threshold: SymbolExportLevel)
                          -> bool {
    if threshold == SymbolExportLevel::Rust {
        // We export everything from Rust dylibs
        true
    } else {
        level == SymbolExportLevel::C
    }
}

fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                               def_id: DefId,
                               symbol_map: &SymbolMap<'tcx>)
                               -> String {
    // Just try to look things up in the symbol map. If nothing's there, we
    // recompute.
    if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) {
        if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
            return sym.to_owned();
        }
    }

    let instance = Instance::mono(scx, def_id);

    symbol_map.get(TransItem::Fn(instance))
              .map(str::to_owned)
              .unwrap_or_else(|| instance.symbol_name(scx))
}
<commit_msg>Export the plugin registrar from proc-macro crates (and not much else)<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use context::SharedCrateContext;
use monomorphize::Instance;
use symbol_map::SymbolMap;
use util::nodemap::FxHashMap;
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::session::config;
use syntax::attr;
use trans_item::TransItem;

/// The SymbolExportLevel of a symbols specifies from which kinds of crates
/// the symbol will be exported. `C` symbols will be exported from any
/// kind of crate, including cdylibs which export very few things.
/// `Rust` will only be exported if the crate produced is a Rust
/// dylib.
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum SymbolExportLevel {
    C,
    Rust,
}

/// The set of symbols exported from each crate in the crate graph.
pub struct ExportedSymbols {
    exports: FxHashMap<CrateNum, Vec<(String, SymbolExportLevel)>>,
}

impl ExportedSymbols {

    pub fn empty() -> ExportedSymbols {
        ExportedSymbols {
            exports: FxHashMap(),
        }
    }

    pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                  symbol_map: &SymbolMap<'tcx>)
                                  -> ExportedSymbols {
        let mut local_crate: Vec<_> = scx
            .exported_symbols()
            .iter()
            .map(|&node_id| {
                scx.tcx().map.local_def_id(node_id)
            })
            .map(|def_id| {
                (symbol_for_def_id(scx, def_id, symbol_map),
                 export_level(scx, def_id))
            })
            .collect();

        if scx.sess().entry_fn.borrow().is_some() {
            local_crate.push(("main".to_string(), SymbolExportLevel::C));
        }

        if let Some(id) = scx.sess().derive_registrar_fn.get() {
            let svh = &scx.link_meta().crate_hash;
            let def_id = scx.tcx().map.local_def_id(id);
            let idx = def_id.index;
            let registrar = scx.sess().generate_derive_registrar_symbol(svh, idx);
            local_crate.push((registrar, SymbolExportLevel::C));
        }

        if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) {
            local_crate.push((scx.metadata_symbol_name(),
                              SymbolExportLevel::Rust));
        }

        let mut exports = FxHashMap();
        exports.insert(LOCAL_CRATE, local_crate);

        for cnum in scx.sess().cstore.crates() {
            debug_assert!(cnum != LOCAL_CRATE);

            if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() ||
               scx.sess().cstore.derive_registrar_fn(cnum).is_some() {
                continue;
            }

            let crate_exports = scx
                .sess()
                .cstore
                .exported_symbols(cnum)
                .iter()
                .map(|&def_id| {
                    debug!("EXTERN-SYMBOL: {:?}", def_id);
                    let name = Instance::mono(scx, def_id).symbol_name(scx);
                    (name, export_level(scx, def_id))
                })
                .collect();

            exports.insert(cnum, crate_exports);
        }

        return ExportedSymbols {
            exports: exports
        };

        fn export_level(scx: &SharedCrateContext,
                        sym_def_id: DefId)
                        -> SymbolExportLevel {
            let attrs = scx.tcx().get_attrs(sym_def_id);
            if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) {
                SymbolExportLevel::C
            } else {
                SymbolExportLevel::Rust
            }
        }
    }

    pub fn exported_symbols(&self,
                            cnum: CrateNum)
                            -> &[(String, SymbolExportLevel)] {
        match self.exports.get(&cnum) {
            Some(exports) => &exports[..],
            None => &[]
        }
    }

    pub fn for_each_exported_symbol<F>(&self,
                                       cnum: CrateNum,
                                       export_threshold: SymbolExportLevel,
                                       mut f: F)
        where F: FnMut(&str, SymbolExportLevel)
    {
        for &(ref name, export_level) in self.exported_symbols(cnum) {
            if is_below_threshold(export_level, export_threshold) {
                f(&name[..], export_level)
            }
        }
    }
}

pub fn crate_export_threshold(crate_type: config::CrateType)
                                     -> SymbolExportLevel {
    match crate_type {
        config::CrateTypeExecutable |
        config::CrateTypeStaticlib  |
        config::CrateTypeProcMacro  |
        config::CrateTypeCdylib     => SymbolExportLevel::C,
        config::CrateTypeRlib       |
        config::CrateTypeMetadata   |
        config::CrateTypeDylib      => SymbolExportLevel::Rust,
    }
}

pub fn crates_export_threshold(crate_types: &[config::CrateType])
                                      -> SymbolExportLevel {
    if crate_types.iter().any(|&crate_type| {
        crate_export_threshold(crate_type) == SymbolExportLevel::Rust
    }) {
        SymbolExportLevel::Rust
    } else {
        SymbolExportLevel::C
    }
}

pub fn is_below_threshold(level: SymbolExportLevel,
                          threshold: SymbolExportLevel)
                          -> bool {
    if threshold == SymbolExportLevel::Rust {
        // We export everything from Rust dylibs
        true
    } else {
        level == SymbolExportLevel::C
    }
}

fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                               def_id: DefId,
                               symbol_map: &SymbolMap<'tcx>)
                               -> String {
    // Just try to look things up in the symbol map. If nothing's there, we
    // recompute.
    if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) {
        if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
            return sym.to_owned();
        }
    }

    let instance = Instance::mono(scx, def_id);

    symbol_map.get(TransItem::Fn(instance))
              .map(str::to_owned)
              .unwrap_or_else(|| instance.symbol_name(scx))
}
<|endoftext|>


<commit_before>#![allow(dead_code)] // not used on all platforms

use crate::fs;
use crate::io::{self, Error, ErrorKind};
use crate::path::Path;

pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
    if !from.is_file() {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "the source path is not an existing regular file",
        ));
    }

    let mut reader = fs::File::open(from)?;
    let mut writer = fs::File::create(to)?;
    let perm = reader.metadata()?.permissions();

    let ret = io::copy(&mut reader, &mut writer)?;
    fs::set_permissions(to, perm)?;
    Ok(ret)
}

pub fn remove_dir_all(path: &Path) -> io::Result<()> {
    let filetype = fs::symlink_metadata(path)?.file_type();
    if filetype.is_symlink() { fs::remove_file(path) } else { remove_dir_all_recursive(path) }
}

fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
    for child in fs::read_dir(path)? {
        let child = child?;
        if child.file_type()?.is_dir() {
            remove_dir_all_recursive(&child.path())?;
        } else {
            fs::remove_file(&child.path())?;
        }
    }
    fs::remove_dir(path)
}
<commit_msg>Optimize away some path lookups in the generic `fs::copy` implementation.<commit_after>#![allow(dead_code)] // not used on all platforms

use crate::fs;
use crate::io::{self, Error, ErrorKind};
use crate::path::Path;

pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
    let mut reader = fs::File::open(from)?;
    let metadata = reader.metadata()?;

    if !metadata.is_file() {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "the source path is not an existing regular file",
        ));
    }

    let mut writer = fs::File::create(to)?;
    let perm = metadata.permissions();

    let ret = io::copy(&mut reader, &mut writer)?;
    writer.set_permissions(perm)?;
    Ok(ret)
}

pub fn remove_dir_all(path: &Path) -> io::Result<()> {
    let filetype = fs::symlink_metadata(path)?.file_type();
    if filetype.is_symlink() { fs::remove_file(path) } else { remove_dir_all_recursive(path) }
}

fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
    for child in fs::read_dir(path)? {
        let child = child?;
        if child.file_type()?.is_dir() {
            remove_dir_all_recursive(&child.path())?;
        } else {
            fs::remove_file(&child.path())?;
        }
    }
    fs::remove_dir(path)
}
<|endoftext|>


<commit_before>pub use quickcheck::quickcheck;

pub use schema::connection;
pub use diesel::*;
pub use diesel::result::Error;
pub use diesel::data_types::*;
pub use diesel::types::{NativeSqlType, ToSql, Nullable, Array};

pub fn test_type_round_trips<ST, T>(value: T, type_name: &str) -> bool where
    ST: NativeSqlType,
    T: ToSql<ST> + Queriable<ST> + PartialEq,
{
    let connection = connection();
    let query = format!("SELECT $1::{}", type_name);
    let result = connection.query_sql_params::<ST, T, ST, T>(&query, &value);
    match result {
        Ok(mut val) => value == val.nth(0).unwrap(),
        Err(Error::DatabaseError(msg)) =>
            &msg == "ERROR:  invalid byte sequence for encoding \"UTF8\": 0x00\n",
        Err(e) => panic!("Query failed: {:?}", e),
    }
}

pub fn id<A>(a: A) -> A { a }

macro_rules! test_round_trip {
    ($test_name:ident, $sql_type:ident, $tpe:ty, $sql_type_name:expr) => {
        test_round_trip!($test_name, $sql_type, $tpe, id, $sql_type_name);
    };

    ($test_name:ident, $sql_type:ident, $tpe:ty, $map_fn:ident, $sql_type_name:expr) => {
        #[test]
        fn $test_name() {
            fn round_trip(val: $tpe) -> bool {
                test_type_round_trips::<types::$sql_type, _>($map_fn(val), $sql_type_name)
            }

            fn option_round_trip(val: Option<$tpe>) -> bool {
                let val = val.map($map_fn);
                test_type_round_trips::<Nullable<types::$sql_type>, _>(val, $sql_type_name)
            }

            fn vec_round_trip(val: Vec<$tpe>) -> bool {
                let val: Vec<_> = val.into_iter().map($map_fn).collect();
                test_type_round_trips::<Array<types::$sql_type>, _>(val, concat!($sql_type_name, "[]"))
            }

            quickcheck(round_trip as fn($tpe) -> bool);
            quickcheck(option_round_trip as fn(Option<$tpe>) -> bool);
            quickcheck(vec_round_trip as fn(Vec<$tpe>) -> bool);
        }
    }
}

test_round_trip!(bool_roundtrips, Bool, bool, "boolean");
test_round_trip!(i16_roundtrips, SmallInt, i16, "int2");
test_round_trip!(i32_roundtrips, Integer, i32, "int4");
test_round_trip!(i64_roundtrips, BigInt, i64, "int8");
test_round_trip!(f32_roundtrips, Float, f32, "real");
test_round_trip!(f64_roundtrips, Double, f64, "double precision");
test_round_trip!(string_roundtrips, VarChar, String, "varchar");
test_round_trip!(text_roundtrips, Text, String, "text");
test_round_trip!(binary_roundtrips, Binary, Vec<u8>, "bytea");
test_round_trip!(date_roundtrips, Date, PgDate, "date");
test_round_trip!(time_roundtrips, Time, PgTime, "time");
test_round_trip!(timestamp_roundtrips, Timestamp, PgTimestamp, "timestamp");
test_round_trip!(interval_roundtrips, Interval, PgInterval, "interval");
test_round_trip!(numeric_roundtrips, Numeric, PgNumeric, "numeric");

#[cfg(feature = "unstable")]
mod unstable_types {
    use super::*;
    use std::time::*;

    fn strip_nanosecond_precision(time: SystemTime) -> SystemTime {
        match time.duration_from_earlier(UNIX_EPOCH) {
            Ok(duration) => time - Duration::new(0, duration.subsec_nanos() % 1000),
            Err(e) => time + Duration::new(0, e.duration().subsec_nanos() % 1000),
        }
    }

    test_round_trip!(systemtime_roundtrips, Timestamp, SystemTime, strip_nanosecond_precision, "timestamp");
}
<commit_msg>Work around https://github.com/rust-lang/rust/pull/30173<commit_after>pub use quickcheck::quickcheck;

pub use schema::connection;
pub use diesel::*;
pub use diesel::result::Error;
pub use diesel::data_types::*;
pub use diesel::types::{NativeSqlType, ToSql, Nullable, Array};

pub fn test_type_round_trips<ST, T>(value: T, type_name: &str) -> bool where
    ST: NativeSqlType,
    T: ToSql<ST> + Queriable<ST> + PartialEq + ::std::fmt::Debug,
{
    let connection = connection();
    let query = format!("SELECT $1::{}", type_name);
    let result = connection.query_sql_params::<ST, T, ST, T>(&query, &value);
    match result {
        Ok(mut val) => {
            let res = val.nth(0).unwrap();
            if value != res {
                println!("{:?}, {:?}", value, res);
                false
            } else {
                true
            }
        }
        Err(Error::DatabaseError(msg)) =>
            &msg == "ERROR:  invalid byte sequence for encoding \"UTF8\": 0x00\n",
        Err(e) => panic!("Query failed: {:?}", e),
    }
}

pub fn id<A>(a: A) -> A { a }

macro_rules! test_round_trip {
    ($test_name:ident, $sql_type:ident, $tpe:ty, $sql_type_name:expr) => {
        test_round_trip!($test_name, $sql_type, $tpe, id, $sql_type_name);
    };

    ($test_name:ident, $sql_type:ident, $tpe:ty, $map_fn:ident, $sql_type_name:expr) => {
        #[test]
        fn $test_name() {
            fn round_trip(val: $tpe) -> bool {
                test_type_round_trips::<types::$sql_type, _>($map_fn(val), $sql_type_name)
            }

            fn option_round_trip(val: Option<$tpe>) -> bool {
                let val = val.map($map_fn);
                test_type_round_trips::<Nullable<types::$sql_type>, _>(val, $sql_type_name)
            }

            fn vec_round_trip(val: Vec<$tpe>) -> bool {
                let val: Vec<_> = val.into_iter().map($map_fn).collect();
                test_type_round_trips::<Array<types::$sql_type>, _>(val, concat!($sql_type_name, "[]"))
            }

            quickcheck(round_trip as fn($tpe) -> bool);
            quickcheck(option_round_trip as fn(Option<$tpe>) -> bool);
            quickcheck(vec_round_trip as fn(Vec<$tpe>) -> bool);
        }
    }
}

test_round_trip!(bool_roundtrips, Bool, bool, "boolean");
test_round_trip!(i16_roundtrips, SmallInt, i16, "int2");
test_round_trip!(i32_roundtrips, Integer, i32, "int4");
test_round_trip!(i64_roundtrips, BigInt, i64, "int8");
test_round_trip!(f32_roundtrips, Float, f32, "real");
test_round_trip!(f64_roundtrips, Double, f64, "double precision");
test_round_trip!(string_roundtrips, VarChar, String, "varchar");
test_round_trip!(text_roundtrips, Text, String, "text");
test_round_trip!(binary_roundtrips, Binary, Vec<u8>, "bytea");
test_round_trip!(date_roundtrips, Date, PgDate, "date");
test_round_trip!(time_roundtrips, Time, PgTime, "time");
test_round_trip!(timestamp_roundtrips, Timestamp, PgTimestamp, "timestamp");
test_round_trip!(interval_roundtrips, Interval, PgInterval, "interval");
test_round_trip!(numeric_roundtrips, Numeric, PgNumeric, "numeric");

#[cfg(feature = "unstable")]
mod unstable_types {
    use super::*;
    use std::time::*;

    fn strip_nanosecond_precision(time: SystemTime) -> SystemTime {
        let res = match time.duration_from_earlier(UNIX_EPOCH) {
            Ok(duration) => time - Duration::new(0, duration.subsec_nanos() % 1000),
            Err(e) => time + Duration::new(0, e.duration().subsec_nanos() % 1000),
        };
        work_around_rust_lang_30173(res)
    }

    fn work_around_rust_lang_30173(time: SystemTime) -> SystemTime {
        time + Duration::new(0, 1) - Duration::new(0, 1)
    }

    test_round_trip!(systemtime_roundtrips, Timestamp, SystemTime, strip_nanosecond_precision, "timestamp");
}
<|endoftext|>


<commit_before>use bytes::{BufMut, BytesMut, BigEndian};
use tokio_io::codec::{Encoder, Decoder};

pub use super::error::IpcError;

pub const MAGIC: i16 = ((b'1' as i16) << 8) as i16 + b'w' as i16;
pub const HEADER_SIZE: usize = 8;

#[derive(Debug, Clone)]
pub enum IpcMessage {
    ClientHello,
    ServerHello,
    ClientBye,
    RequestAuthentication(String, String)
}

#[derive(Debug)]
pub struct IpcMessageCodec;

type DecodeResult = Result<Option<(IpcMessage, usize)>, IpcError>;

impl IpcMessage {
    pub fn message_type(&self) -> &[u8; 2] {
        match *self {
            IpcMessage::ClientHello => b"CH",
            IpcMessage::ServerHello => b"SH",
            IpcMessage::ClientBye => b"CB",
            IpcMessage::RequestAuthentication(ref _a, ref _b) => b"RA"
        }
    }
}

impl Encoder for IpcMessageCodec {
    type Item = IpcMessage;
    type Error = IpcError;

    fn encode(&mut self, msg: Self::Item, buf: &mut BytesMut) -> Result<(), Self::Error> {
        let len = match msg {
            IpcMessage::ClientHello => 0,
            IpcMessage::ServerHello => 0,
            IpcMessage::ClientBye => 0,
            IpcMessage::RequestAuthentication(ref user, ref secret) => user.len() + secret.len(),
            _   => return Err(IpcError::UnknownMessageType)
        };

        buf.reserve(HEADER_SIZE + len);
        buf.put_i16::<BigEndian>(MAGIC);
        buf.extend(msg.message_type());
        buf.put_u32::<BigEndian>(len as u32);

        match msg {
            IpcMessage::RequestAuthentication(ref user, ref secret) => {
                buf.put_u32::<BigEndian>(user.len() as u32);
                buf.extend(user.as_bytes());
                buf.put_u32::<BigEndian>(secret.len() as u32);
                buf.extend(secret.as_bytes());
            },
            _   => ()
        };

        Ok(())
    }
}

impl Decoder for IpcMessageCodec {
    type Item = IpcMessage;
    type Error = IpcError;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        match decode(buf, 0) {
            Ok(None) => Ok(None),
            Ok(Some((item ,pos))) => {
                buf.split_to(pos);
                Ok(Some(item))
            }
            Err(e) => Err(e)
        }
    }
}

fn decode(buf: &mut BytesMut, idx: usize) -> DecodeResult {
    let length = buf.len();
    if length <= idx {
        return Ok(None);
    }

    if length < HEADER_SIZE {
        return Err(IpcError::HeaderTooShort);
    }

    let magic = &buf[idx..idx + 2];
    if magic[0] != b'1' || magic[1] != b'w' {
        return Err(IpcError::InvalidMagic);
    }

    let message_type = &buf[idx + 2..idx + 4];
    match message_type {
        b"CH" => Ok(Some((IpcMessage::ClientHello, idx + HEADER_SIZE))),
        b"SH" => Ok(Some((IpcMessage::ServerHello, idx + HEADER_SIZE))),
        b"CB" => Ok(Some((IpcMessage::ClientBye, idx + HEADER_SIZE))),
        _ => Err(IpcError::UnknownMessageType)
    }
}<commit_msg>[libcommon] Fix invalid length calculation in IpcMessageCodec::encode<commit_after>use bytes::{BufMut, BytesMut, BigEndian};
use tokio_io::codec::{Encoder, Decoder};

pub use super::error::IpcError;

pub const MAGIC: i16 = ((b'1' as i16) << 8) as i16 + b'w' as i16;
pub const HEADER_SIZE: usize = 8;

#[derive(Debug, Clone)]
pub enum IpcMessage {
    ClientHello,
    ServerHello,
    ClientBye,
    RequestAuthentication(String, String)
}

#[derive(Debug)]
pub struct IpcMessageCodec;

type DecodeResult = Result<Option<(IpcMessage, usize)>, IpcError>;

impl IpcMessage {
    pub fn message_type(&self) -> &[u8; 2] {
        match *self {
            IpcMessage::ClientHello => b"CH",
            IpcMessage::ServerHello => b"SH",
            IpcMessage::ClientBye => b"CB",
            IpcMessage::RequestAuthentication(ref _a, ref _b) => b"RA"
        }
    }
}

impl Encoder for IpcMessageCodec {
    type Item = IpcMessage;
    type Error = IpcError;

    fn encode(&mut self, msg: Self::Item, buf: &mut BytesMut) -> Result<(), Self::Error> {
        let len = match msg {
            IpcMessage::ClientHello => 0,
            IpcMessage::ServerHello => 0,
            IpcMessage::ClientBye => 0,
            IpcMessage::RequestAuthentication(ref user, ref secret) => user.len() + secret.len() + 8,
            _   => return Err(IpcError::UnknownMessageType)
        };

        buf.reserve(HEADER_SIZE + len);
        buf.put_i16::<BigEndian>(MAGIC);
        buf.extend(msg.message_type());
        buf.put_u32::<BigEndian>(len as u32);

        match msg {
            IpcMessage::RequestAuthentication(ref user, ref secret) => {
                buf.put_u32::<BigEndian>(user.len() as u32);
                buf.extend(user.as_bytes());
                buf.put_u32::<BigEndian>(secret.len() as u32);
                buf.extend(secret.as_bytes());
            },
            _   => ()
        };

        Ok(())
    }
}

impl Decoder for IpcMessageCodec {
    type Item = IpcMessage;
    type Error = IpcError;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        match decode(buf, 0) {
            Ok(None) => Ok(None),
            Ok(Some((item ,pos))) => {
                buf.split_to(pos);
                Ok(Some(item))
            }
            Err(e) => Err(e)
        }
    }
}

fn decode(buf: &mut BytesMut, idx: usize) -> DecodeResult {
    let length = buf.len();
    if length <= idx {
        return Ok(None);
    }

    if length < HEADER_SIZE {
        return Err(IpcError::HeaderTooShort);
    }

    let magic = &buf[idx..idx + 2];
    if magic[0] != b'1' || magic[1] != b'w' {
        return Err(IpcError::InvalidMagic);
    }

    let message_type = &buf[idx + 2..idx + 4];
    match message_type {
        b"CH" => Ok(Some((IpcMessage::ClientHello, idx + HEADER_SIZE))),
        b"SH" => Ok(Some((IpcMessage::ServerHello, idx + HEADER_SIZE))),
        b"CB" => Ok(Some((IpcMessage::ClientBye, idx + HEADER_SIZE))),
        _ => Err(IpcError::UnknownMessageType)
    }
}<|endoftext|>


<commit_before>/// Asserts that types are equal in size.
///
/// When performing operations such as pointer casts or dealing with [`usize`]
/// versus [`u64`] versus [`u32`], the size of your types matter. That is where
/// this macro comes into play.
///
/// # Alternatives
///
/// There also exists [`assert_eq_size_val`](macro.assert_eq_size_val.html) and
/// [`assert_eq_size_ptr`](macro.assert_eq_size_ptr.html). Instead of specifying
/// types to compare, values' sizes can be directly compared against each other.
///
/// # Examples
///
///
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_eq_size!([u8; 4], (u16, u16), u32);
/// ```
///
/// ```
/// ```
///
/// The following example fails to compile because `u32` has 4 times the size of
/// `u8`:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_eq_size!(u32, u8);
/// ```
///
/// [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html
/// [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html
/// [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+ $(,)?) => {
        const _: fn() -> () = || {
            $(let _ = $crate::_core::mem::transmute::<$x, $xs>;)+
        };
    };
}

/// Asserts that values pointed to are equal in size.
///
/// # Examples
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// fn operation(x: &(u32, u32), y: &[u16; 4]) {
///     assert_eq_size_ptr!(x, y);
///     // ...
/// }
/// ```
///
/// The following example fails to compile because byte arrays of different
/// lengths have different sizes:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {
/// static BYTES: &[u8; 4] = &[
///     /* ... */
///     # 0; 4
/// ];
///
/// static TABLE: &[u8; 16] = &[
///     /* ... */
///     # 0; 16
/// ];
///
/// assert_eq_size_ptr!(BYTES, TABLE);
/// ```
#[macro_export]
macro_rules! assert_eq_size_ptr {
    ($x:expr, $($xs:expr),+ $(,)?) => {
        #[allow(unknown_lints, unsafe_code, forget_copy, useless_transmute)]
        let _ = || unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read($x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read($xs)));)+
            mem::forget(copy);
        };
    }
}

/// Asserts that values are equal in size.
///
/// This macro doesn't consume its arguments and thus works for
/// non-[`Clone`]able values.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {
/// struct Byte(u8);
///
/// let x = 10u8;
/// let y = Byte(42); // Works for non-cloneable types
///
/// assert_eq_size_val!(x, y);
/// assert_eq_size_val!(x, y, 0u8);
/// # }
/// ```
///
/// Even though both values are 0, they are of types with different sizes:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {
/// assert_eq_size_val!(0u8, 0u32);
/// # }
/// ```
///
/// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+ $(,)?) => {
        assert_eq_size_ptr!(&$x, $(&$xs),+);
    }
}
<commit_msg>Improve docs for `assert_eq_size!`<commit_after>/// Asserts that types are equal in size.
///
/// When performing operations such as pointer casts or dealing with [`usize`]
/// versus [`u64`] versus [`u32`], the size of your types matter. That is where
/// this macro comes into play.
///
/// # Alternatives
///
/// There also exists [`assert_eq_size_val`](macro.assert_eq_size_val.html) and
/// [`assert_eq_size_ptr`](macro.assert_eq_size_ptr.html). Instead of specifying
/// types to compare, values' sizes can be directly compared against each other.
///
/// # Examples
///
/// These three types, despite being very different, all have the same size:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_eq_size!([u8; 4], (u16, u16), u32);
/// ```
///
/// The following example fails to compile because `u32` has 4 times the size of
/// `u8`:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_eq_size!(u32, u8);
/// ```
///
/// [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html
/// [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html
/// [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+ $(,)?) => {
        const _: fn() -> () = || {
            $(let _ = $crate::_core::mem::transmute::<$x, $xs>;)+
        };
    };
}

/// Asserts that values pointed to are equal in size.
///
/// # Examples
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// fn operation(x: &(u32, u32), y: &[u16; 4]) {
///     assert_eq_size_ptr!(x, y);
///     // ...
/// }
/// ```
///
/// The following example fails to compile because byte arrays of different
/// lengths have different sizes:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {
/// static BYTES: &[u8; 4] = &[
///     /* ... */
///     # 0; 4
/// ];
///
/// static TABLE: &[u8; 16] = &[
///     /* ... */
///     # 0; 16
/// ];
///
/// assert_eq_size_ptr!(BYTES, TABLE);
/// ```
#[macro_export]
macro_rules! assert_eq_size_ptr {
    ($x:expr, $($xs:expr),+ $(,)?) => {
        #[allow(unknown_lints, unsafe_code, forget_copy, useless_transmute)]
        let _ = || unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read($x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read($xs)));)+
            mem::forget(copy);
        };
    }
}

/// Asserts that values are equal in size.
///
/// This macro doesn't consume its arguments and thus works for
/// non-[`Clone`]able values.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {
/// struct Byte(u8);
///
/// let x = 10u8;
/// let y = Byte(42); // Works for non-cloneable types
///
/// assert_eq_size_val!(x, y);
/// assert_eq_size_val!(x, y, 0u8);
/// # }
/// ```
///
/// Even though both values are 0, they are of types with different sizes:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {
/// assert_eq_size_val!(0u8, 0u32);
/// # }
/// ```
///
/// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+ $(,)?) => {
        assert_eq_size_ptr!(&$x, $(&$xs),+);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::iter::FromIterator;

use redis;
use redis::Commands;
use r2d2;
use r2d2_redis::RedisConnectionManager;
use iron;
use rand;
use rand::Rng;

use RawSession;
use SessionBackend;

use errors::*;
use iron::prelude::*;

const COOKIE_NAME: &'static str = "iron_session_id";

type RedisPool = r2d2::Pool<RedisConnectionManager>;

pub struct RedisSession {
    session_id: String,
    pool: RedisPool,
}

impl RawSession for RedisSession {
    fn get_raw(&self, key: &str) -> IronResult<Option<String>> {
        let conn = itry!(self.pool.get());

        Ok(itry!(conn.hget(self.session_id, key)))
    }

    fn set_raw(&mut self, key: &str, value: String) -> IronResult<()> {
        itry!(self.pool.get().unwrap().hset(self.session_id, key, value));
        Ok(())
    }

    fn clear(&mut self) -> IronResult<()> {
        itry!(self.pool.get().unwrap().del(self.session_id).unwrap());
        self.session_id = "".to_owned();
        Ok(())
    }

    fn write(&self, res: &mut Response) -> IronResult<()> {
        let cookie = iron::headers::CookiePair::new(
            COOKIE_NAME.to_owned(),
            self.session_id
        );
        if let Some(mut cookies) = res.headers.get_mut::<iron::headers::SetCookie>() {
            debug_assert!(cookies.iter().all(|cookie| cookie.name != COOKIE_NAME));
            cookies.push(cookie);
            return;
        }
        res.headers.set(iron::headers::SetCookie(vec![cookie]));
        Ok(())
    }
}

pub struct RedisBackend {
    pool: RedisPool
}

impl RedisBackend {
    pub fn new<T: redis::IntoConnectionInfo>(params: T) -> Result<Self> {
        let config = Default::default();
        let manager = try!(RedisConnectionManager::new(params).chain_err(|| "Couldn't create redis connection manager"));
        let pool = try!(r2d2::Pool::new(config, manager).chain_err(|| "Couldn't create redis connection pool"));

        Ok(RedisBackend { pool: pool })
    }
}

impl SessionBackend for RedisBackend {
    type S = RedisSession;

    fn from_request(&self, req: &mut Request) -> Self::S {
        let session_id = req.headers.get::<iron::headers::Cookie>()
            .map(|header| header.to_cookie_jar(b""))  // FIXME: Our cookies are unsigned. Why do I need to specify a key?
            .and_then(|jar| jar.find(COOKIE_NAME))
            .map(|cookie| cookie.value)
            .unwrap_or_else(|| {
                let mut rng = rand::OsRng::new().unwrap();
                String::from_iter(rng.gen_ascii_chars())
            });

        RedisSession {
            session_id: session_id,
            pool: self.pool.clone(),
        }
    }
}
<commit_msg>Fix redis backend<commit_after>use std::iter::FromIterator;

use redis;
use redis::Commands;
use r2d2;
use r2d2_redis::RedisConnectionManager;
use iron;
use rand;
use rand::Rng;

use RawSession;
use SessionBackend;

use errors::*;
use iron::prelude::*;

const COOKIE_NAME: &'static str = "iron_session_id";

type RedisPool = r2d2::Pool<RedisConnectionManager>;

pub struct RedisSession {
    session_id: String,
    pool: RedisPool,
}

impl RawSession for RedisSession {
    fn get_raw(&self, key: &str) -> IronResult<Option<String>> {
        let conn = itry!(self.pool.get());
        Ok(itry!(conn.hget(&self.session_id, key)))
    }

    fn set_raw(&mut self, key: &str, value: String) -> IronResult<()> {
        let conn = itry!(self.pool.get());
        itry!(conn.hset(&self.session_id, key, value));
        Ok(())
    }

    fn clear(&mut self) -> IronResult<()> {
        let conn = itry!(self.pool.get());
        itry!(conn.del(&self.session_id));
        self.session_id = "".to_owned();
        Ok(())
    }

    fn write(&self, res: &mut Response) -> IronResult<()> {
        let cookie = iron::headers::CookiePair::new(
            COOKIE_NAME.to_owned(),
            self.session_id.clone()
        );
        if let Some(mut cookies) = res.headers.get_mut::<iron::headers::SetCookie>() {
            debug_assert!(cookies.iter().all(|cookie| cookie.name != COOKIE_NAME));
            cookies.push(cookie);
            return Ok(());
        }
        res.headers.set(iron::headers::SetCookie(vec![cookie]));
        Ok(())
    }
}

pub struct RedisBackend {
    pool: RedisPool
}

impl RedisBackend {
    pub fn new<T: redis::IntoConnectionInfo>(params: T) -> Result<Self> {
        let config = Default::default();
        let manager = try!(RedisConnectionManager::new(params).chain_err(|| "Couldn't create redis connection manager"));
        let pool = try!(r2d2::Pool::new(config, manager).chain_err(|| "Couldn't create redis connection pool"));

        Ok(RedisBackend { pool: pool })
    }
}

impl SessionBackend for RedisBackend {
    type S = RedisSession;

    fn from_request(&self, req: &mut Request) -> Self::S {
        let session_id = req.headers.get::<iron::headers::Cookie>()
            .map(|header| header.to_cookie_jar(b""))  // FIXME: Our cookies are unsigned. Why do I need to specify a key?
            .and_then(|jar| jar.find(COOKIE_NAME))
            .map(|cookie| cookie.value)
            .unwrap_or_else(|| {
                let mut rng = rand::OsRng::new().unwrap();
                String::from_iter(rng.gen_ascii_chars())
            });

        RedisSession {
            session_id: session_id,
            pool: self.pool.clone(),
        }
    }
}
<|endoftext|>