<commit_before>#![feature(trace_macros)]
#![recursion_limit = "10240"]
// trace_macros!(true);

// #![feature(plugin)]
// #![plugin(afl_plugin)]
#![feature(proc_macro)]

#[macro_use]
extern crate asn1_cereal;
#[macro_use]
extern crate asn1_cereal_derive;
extern crate argparse;
#[macro_use] extern crate log;
extern crate env_logger;
// extern crate afl;

use std::io;
use std::io::Read;

use asn1_cereal::{BerSerialize, BerDeserialize, DER, BER, BERAlt};
use argparse::{ArgumentParser, StoreTrue};

// fn main() {
//   afl::handle_bytes(|b| {
//     let a = IntSequence::deserialize_enc(enc, b.iter().map(|b| Ok(b) as std::io::Result<_>));
//     println!("{:?}", a);
//   })
// }

fn main() {
  let opts = parse_args();
  env_logger::init().unwrap();

  let mut buffer: Vec<u8> = Vec::new();
  let mut output = io::BufWriter::new(io::stdout());
  let enc = BER;

  let seq = IntSequence {
    a: 3,
    b: vec![4],
    c: Some(SomeString { a: "Hello".into() }),
    d: Choice::Str("Hi".into()),
    e: C(56),
  };

  if opts.dump {
    let mut writer = io::BufWriter::new(&mut output);
    seq.serialize_enc(enc, &mut writer).unwrap();
    return;
  }

  if opts.input {
  }

  {
    let mut writer = io::BufWriter::new(&mut buffer);
    seq.serialize_enc(enc, &mut writer).unwrap();
  }
  println!("Before: {:?}", buffer);
  {
    let mut reader = buffer.iter().map(|x| Ok(*x) as Result<u8, std::io::Error>);
    let seq = IntSequence::deserialize_enc(enc, &mut reader).unwrap();
    println!("{:?}", seq);
  }
}

#[derive(Asn1Info, BerSerialize, BerDeserialize, Debug, PartialEq)]
#[asn1(tag="[PRIVATE 69]", asn1_type="SEQUENCE", log, form="alias")]
struct C(u64);

#[derive(Asn1Info, BerSerialize, BerDeserialize, Debug, PartialEq)]
#[asn1(asn1_type="Choice", log)]
enum Choice {
  A(i32),
  Str(String),
}

#[derive(Asn1Info, BerSerialize, BerDeserialize, Debug, PartialEq)]
#[asn1(asn1_type="SOMESTRING", tag="[APPLICATION 15]", log, form="sequence")]
struct SomeString {
  a: String
}

#[derive(Debug, PartialEq)]
struct IntSequence {
  a: u64,
  b: Vec<i32>,
  c: Option<SomeString>,
  d: Choice,
  e: C,
}

ber_sequence!(
  IntSequence,
  "INTSEQ",
  a (DEFAULT 4);
  b;
  c (OPTIONAL);
  d;
  e;
);

struct ProgOpts {
  dump: bool,
  input: bool,
}

fn parse_args() -> ProgOpts {
  let mut opts = ProgOpts {
    dump: false,
    input: false,
  };
  {
    let mut ap = ArgumentParser::new();
    ap.refer(&mut opts.dump)
      .add_option(&["-d", "--dump"], StoreTrue, "Dump asn.1 packet");
    ap.refer(&mut opts.input)
      .add_option(&["-i", "--input"], StoreTrue, "Decode asn.1 data from stdin");
    ap.parse_args_or_exit();
  }
  opts
}
<commit_msg>Remove unstable attributes<commit_after>// #![feature(trace_macros)]
#![recursion_limit = "10240"]
// trace_macros!(true);

// #![feature(plugin)]
// #![plugin(afl_plugin)]
// #![feature(proc_macro)]

#[macro_use]
extern crate asn1_cereal;
#[macro_use]
extern crate asn1_cereal_derive;
extern crate argparse;
#[macro_use] extern crate log;
extern crate env_logger;
// extern crate afl;

use std::io;
use std::io::Read;

use asn1_cereal::{BerSerialize, BerDeserialize, DER, BER, BERAlt};
use argparse::{ArgumentParser, StoreTrue};

// fn main() {
//   afl::handle_bytes(|b| {
//     let a = IntSequence::deserialize_enc(enc, b.iter().map(|b| Ok(b) as std::io::Result<_>));
//     println!("{:?}", a);
//   })
// }

fn main() {
  let opts = parse_args();
  env_logger::init().unwrap();

  let mut buffer: Vec<u8> = Vec::new();
  let mut output = io::BufWriter::new(io::stdout());
  let enc = BER;

  let seq = IntSequence {
    a: 3,
    b: vec![4],
    c: Some(SomeString { a: "Hello".into() }),
    d: Choice::Str("Hi".into()),
    e: C(56),
  };

  if opts.dump {
    let mut writer = io::BufWriter::new(&mut output);
    seq.serialize_enc(enc, &mut writer).unwrap();
    return;
  }

  if opts.input {
  }

  {
    let mut writer = io::BufWriter::new(&mut buffer);
    seq.serialize_enc(enc, &mut writer).unwrap();
  }
  println!("Before: {:?}", buffer);
  {
    let mut reader = buffer.iter().map(|x| Ok(*x) as Result<u8, std::io::Error>);
    let seq = IntSequence::deserialize_enc(enc, &mut reader).unwrap();
    println!("{:?}", seq);
  }
}

#[derive(Asn1Info, BerSerialize, BerDeserialize, Debug, PartialEq)]
#[asn1(tag="[PRIVATE 69]", asn1_type="SEQUENCE", log, form="alias")]
struct C(u64);

#[derive(Asn1Info, BerSerialize, BerDeserialize, Debug, PartialEq)]
#[asn1(asn1_type="Choice", log)]
enum Choice {
  A(i32),
  Str(String),
}

#[derive(Asn1Info, BerSerialize, BerDeserialize, Debug, PartialEq)]
#[asn1(asn1_type="SOMESTRING", tag="[APPLICATION 15]", log, form="sequence")]
struct SomeString {
  a: String
}

#[derive(Debug, PartialEq)]
struct IntSequence {
  a: u64,
  b: Vec<i32>,
  c: Option<SomeString>,
  d: Choice,
  e: C,
}

ber_sequence!(
  IntSequence,
  "INTSEQ",
  a (DEFAULT 4);
  b;
  c (OPTIONAL);
  d;
  e;
);

struct ProgOpts {
  dump: bool,
  input: bool,
}

fn parse_args() -> ProgOpts {
  let mut opts = ProgOpts {
    dump: false,
    input: false,
  };
  {
    let mut ap = ArgumentParser::new();
    ap.refer(&mut opts.dump)
      .add_option(&["-d", "--dump"], StoreTrue, "Dump asn.1 packet");
    ap.refer(&mut opts.input)
      .add_option(&["-i", "--input"], StoreTrue, "Decode asn.1 data from stdin");
    ap.parse_args_or_exit();
  }
  opts
}
<|endoftext|>


<commit_before>// This is a part of rust-encoding.
// Copyright (c) 2013-2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

/*!

# Rust-encoding

Character encoding support for Rust.
It is based on [WHATWG Encoding Standard](http://encoding.spec.whatwg.org/),
and also provides an advanced interface for error detection and recovery.

## Simple Usage

To encode a string:

~~~~ {.rust}
use encoding::{Encoding, EncodeStrict};
use encoding::all::ISO_8859_1;

assert_eq!(ISO_8859_1.encode("caf\xe9", EncodeStrict),
           Ok(vec!(99,97,102,233)));
~~~~

To encode a string with unrepresentable characters:

~~~~ {.rust}
use encoding::{Encoding, EncodeStrict, EncodeReplace, EncodeIgnore, EncodeNcrEscape};
use encoding::all::ISO_8859_2;

assert!(ISO_8859_2.encode("Acme\xa9", EncodeStrict).is_err());
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeReplace),
           Ok(vec!(65,99,109,101,63)));
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeIgnore),
           Ok(vec!(65,99,109,101)));
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeNcrEscape),
           Ok(vec!(65,99,109,101,38,35,49,54,57,59)));
~~~~

To decode a byte sequence:

~~~~ {.rust}
use encoding::{Encoding, DecodeStrict};
use encoding::all::ISO_8859_1;

assert_eq!(ISO_8859_1.decode([99,97,102,233], DecodeStrict),
           Ok("caf\xe9".to_string()));
~~~~

To decode a byte sequence with invalid sequences:

~~~~ {.rust}
use encoding::{Encoding, DecodeStrict, DecodeReplace, DecodeIgnore};
use encoding::all::ISO_8859_6;

assert!(ISO_8859_6.decode([65,99,109,101,169], DecodeStrict).is_err());
assert_eq!(ISO_8859_6.decode([65,99,109,101,169], DecodeReplace),
           Ok("Acme\ufffd".to_string()));
assert_eq!(ISO_8859_6.decode([65,99,109,101,169], DecodeIgnore),
           Ok("Acme".to_string()));
~~~~

A practical example of custom encoder traps:

~~~~ {.rust}
use encoding::{Encoding, Encoder, ByteWriter, EncoderTrap, DecodeStrict};
use encoding::all::ASCII;

// hexadecimal numeric character reference replacement
fn hex_ncr_escape(_encoder: &mut Encoder, input: &str, output: &mut ByteWriter) -> bool {
    let escapes: Vec<String> =
        input.chars().map(|ch| format!("&#x{:x};", ch as int)).collect();
    let escapes = escapes.concat();
    output.write_bytes(escapes.as_bytes());
    true
}
static HexNcrEscape: EncoderTrap = EncoderTrap(hex_ncr_escape);

let orig = "Hello, 世界!".to_string();
let encoded = ASCII.encode(orig.as_slice(), HexNcrEscape).unwrap();
assert_eq!(ASCII.decode(encoded.as_slice(), DecodeStrict),
           Ok("Hello, 世界!".to_string()));
~~~~

Getting the encoding from the string label, as specified in WHATWG Encoding standard:

~~~~ {.rust}
use encoding::{Encoding, DecodeReplace};
use encoding::label::encoding_from_whatwg_label;
use encoding::all::WINDOWS_949;

let euckr = encoding_from_whatwg_label("euc-kr").unwrap();
assert_eq!(euckr.name(), "windows-949");
assert_eq!(euckr.whatwg_name(), Some("euc-kr")); // for the sake of compatibility
let broken = &[0xbf, 0xec, 0xbf, 0xcd, 0xff, 0xbe, 0xd3];
assert_eq!(euckr.decode(broken, DecodeReplace),
           Ok("\uc6b0\uc640\ufffd\uc559".to_string()));

// corresponding rust-encoding native API:
assert_eq!(WINDOWS_949.decode(broken, DecodeReplace),
           Ok("\uc6b0\uc640\ufffd\uc559".to_string()));
~~~~

## Detailed Usage

There are three main entry points to rust-encoding.

**`Encoding`** is a single character encoding.
It contains `encode` and `decode` methods for converting `String` to `Vec<u8>` and vice versa.
For the error handling, they receive **traps** (`EncoderTrap` and `DecoderTrap` respectively)
which replace any error with some string (e.g. `U+FFFD`) or sequence (e.g. `?`).
You can also use `EncodeStrict` and `DecodeStrict` traps to stop on an error.

There are two ways to get `Encoding`:

* `encoding::all` has static items for every supported encoding.
  You should use them when the encoding would not change or only handful of them are required.
  Combined with link-time optimization, any unused encoding would be discarded from the binary.
* `encoding::label` has functions to dynamically get an encoding from given string ("label").
  They will return a static reference to the encoding, which type is also known as `EncodingRef`.
  It is useful when a list of required encodings is not available in advance,
  but it will result in the larger binary and missed optimization opportunities.

**`Encoder`** is an experimental incremental encoder.
At each step of `raw_feed`, it receives a slice of string
and emits any encoded bytes to a generic `ByteWriter` (normally `Vec<u8>`).
It will stop at the first error if any, and would return a `CodecError` struct in that case.
The caller is responsible for calling `raw_finish` at the end of encoding process.

**`Decoder`** is an experimental incremental decoder.
At each step of `raw_feed`, it receives a slice of byte sequence
and emits any decoded characters to a generic `StringWriter` (normally `String`).
Otherwise it is identical to `Encoder`s.

One should prefer `Encoding::{encode,decode}` as a primary interface.
`Encoder` and `Decoder` is experimental and can change substantially.
See the additional documents on `encoding::types` module for more information on them.

## Supported Encodings

Rust-encoding covers all encodings specified by WHATWG Encoding Standard and some more:

* 7-bit strict ASCII (`ascii`)
* UTF-8 (`utf-8`)
* UTF-16 in little endian (`utf-16` or `utf-16le`) and big endian (`utf-16be`)
* All single byte encoding in WHATWG Encoding Standard:
    * IBM code page 866
    * ISO 8859-{2,3,4,5,6,7,8,10,13,14,15,16}
    * KOI8-R, KOI8-U
    * MacRoman (`macintosh`), Macintosh Cyrillic encoding (`x-mac-cyrillic`)
    * Windows code pages 874, 1250, 1251, 1252 (instead of ISO 8859-1), 1253,
      1254 (instead of ISO 8859-9), 1255, 1256, 1257, 1258
* All multi byte encodings in WHATWG Encoding Standard:
    * Windows code page 949 (`euc-kr`, since the strict EUC-KR is hardly used)
    * EUC-JP and Windows code page 932 (`shift_jis`,
      since it's the most widespread extension to Shift_JIS)
    * ISO-2022-JP with asymmetric JIS X 0212 support
    * GB 18030
    * HZ
    * Big5-2003 with HKSCS-2008 extensions
* ISO 8859-1 (distinct from Windows code page 1252)

Parenthesized names refer to the encoding's primary name assigned by WHATWG Encoding Standard.

Many legacy character encodings lack the proper specification,
and even those that have a specification are highly dependent of the actual implementation.
Consequently one should be careful when picking a desired character encoding.
The only standards reliable in this regard are WHATWG Encoding Standard and
[vendor-provided mappings from the Unicode consortium](http://www.unicode.org/Public/MAPPINGS/).
Whenever in doubt, look at the source code and specifications for detailed explanations.

*/

#![crate_name = "encoding"]
#![crate_type = "lib"]
#![comment = "Character encoding support for Rust"]
#![license = "MIT"]

#![feature(globs, macro_rules)]

#![allow(experimental)]

#[cfg(test)] extern crate test;

pub use self::types::{CodecError, ByteWriter, StringWriter,
                      Encoder, Decoder, EncodingRef, Encoding,
                      EncoderTrapFunc, DecoderTrapFunc, DecoderTrap,
                      DecodeStrict, DecodeReplace, DecodeIgnore,
                      EncoderTrap, EncodeStrict, EncodeReplace,
                      EncodeIgnore, EncodeNcrEscape, decode}; // reexport

mod util;
#[cfg(test)] mod testutils;

pub mod types;

/// Indices used for character encoding implementation. Semi-internal.
#[unstable]
pub mod index {
    pub mod ibm866;
    pub mod iso_8859_2;
    pub mod iso_8859_3;
    pub mod iso_8859_4;
    pub mod iso_8859_5;
    pub mod iso_8859_6;
    pub mod iso_8859_7;
    pub mod iso_8859_8;
    pub mod iso_8859_10;
    pub mod iso_8859_13;
    pub mod iso_8859_14;
    pub mod iso_8859_15;
    pub mod iso_8859_16;
    pub mod koi8_r;
    pub mod koi8_u;
    pub mod macintosh;
    pub mod windows_874;
    pub mod windows_1250;
    pub mod windows_1251;
    pub mod windows_1252;
    pub mod windows_1253;
    pub mod windows_1254;
    pub mod windows_1255;
    pub mod windows_1256;
    pub mod windows_1257;
    pub mod windows_1258;
    pub mod x_mac_cyrillic;
    pub mod big5;
    pub mod euc_kr;
    pub mod gb18030;
    pub mod gb18030_ranges;
    pub mod jis0208;
    pub mod jis0212;
}

/// Codec implementations.
#[unstable]
pub mod codec {
    pub mod error;
    pub mod ascii;
    pub mod singlebyte;
    pub mod utf_8;
    pub mod utf_16;
    pub mod korean;
    pub mod japanese;
    pub mod simpchinese;
    pub mod tradchinese;
    pub mod whatwg;
}

pub mod all;
pub mod label;

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

    #[test]
    fn test_decode() {
        fn test_one(input: &[u8], expected_result: &str, expected_encoding: &str) {
            let (result, used_encoding) = decode(
                input, DecodeStrict, all::ISO_8859_1 as EncodingRef);
            let result = result.unwrap();
            assert_eq!(used_encoding.name(), expected_encoding);
            assert_eq!(result.as_slice(), expected_result);
        }

        test_one([0xEF, 0xBB, 0xBF, 0xC3, 0xA9], "é", "utf-8");
        test_one([0xC3, 0xA9], "Ã©", "iso-8859-1");

        test_one([0xFE, 0xFF, 0x00, 0xE9], "é", "utf-16be");
        test_one([0x00, 0xE9], "\x00é", "iso-8859-1");

        test_one([0xFF, 0xFE, 0xE9, 0x00], "é", "utf-16le");
        test_one([0xE9, 0x00], "é\x00", "iso-8859-1");
    }
}

<commit_msg>added an workaround for rust-lang/rust#16597.<commit_after>// This is a part of rust-encoding.
// Copyright (c) 2013-2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

/*!

# Rust-encoding

Character encoding support for Rust.
It is based on [WHATWG Encoding Standard](http://encoding.spec.whatwg.org/),
and also provides an advanced interface for error detection and recovery.

## Simple Usage

To encode a string:

~~~~ {.rust}
use encoding::{Encoding, EncodeStrict};
use encoding::all::ISO_8859_1;

assert_eq!(ISO_8859_1.encode("caf\xe9", EncodeStrict),
           Ok(vec!(99,97,102,233)));
~~~~

To encode a string with unrepresentable characters:

~~~~ {.rust}
use encoding::{Encoding, EncodeStrict, EncodeReplace, EncodeIgnore, EncodeNcrEscape};
use encoding::all::ISO_8859_2;

assert!(ISO_8859_2.encode("Acme\xa9", EncodeStrict).is_err());
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeReplace),
           Ok(vec!(65,99,109,101,63)));
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeIgnore),
           Ok(vec!(65,99,109,101)));
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeNcrEscape),
           Ok(vec!(65,99,109,101,38,35,49,54,57,59)));
~~~~

To decode a byte sequence:

~~~~ {.rust}
use encoding::{Encoding, DecodeStrict};
use encoding::all::ISO_8859_1;

assert_eq!(ISO_8859_1.decode([99,97,102,233], DecodeStrict),
           Ok("caf\xe9".to_string()));
~~~~

To decode a byte sequence with invalid sequences:

~~~~ {.rust}
use encoding::{Encoding, DecodeStrict, DecodeReplace, DecodeIgnore};
use encoding::all::ISO_8859_6;

assert!(ISO_8859_6.decode([65,99,109,101,169], DecodeStrict).is_err());
assert_eq!(ISO_8859_6.decode([65,99,109,101,169], DecodeReplace),
           Ok("Acme\ufffd".to_string()));
assert_eq!(ISO_8859_6.decode([65,99,109,101,169], DecodeIgnore),
           Ok("Acme".to_string()));
~~~~

A practical example of custom encoder traps:

~~~~ {.rust}
use encoding::{Encoding, Encoder, ByteWriter, EncoderTrap, DecodeStrict};
use encoding::all::ASCII;

// hexadecimal numeric character reference replacement
fn hex_ncr_escape(_encoder: &mut Encoder, input: &str, output: &mut ByteWriter) -> bool {
    let escapes: Vec<String> =
        input.chars().map(|ch| format!("&#x{:x};", ch as int)).collect();
    let escapes = escapes.concat();
    output.write_bytes(escapes.as_bytes());
    true
}
static HexNcrEscape: EncoderTrap = EncoderTrap(hex_ncr_escape);

let orig = "Hello, 世界!".to_string();
let encoded = ASCII.encode(orig.as_slice(), HexNcrEscape).unwrap();
assert_eq!(ASCII.decode(encoded.as_slice(), DecodeStrict),
           Ok("Hello, 世界!".to_string()));
~~~~

Getting the encoding from the string label, as specified in WHATWG Encoding standard:

~~~~ {.rust}
use encoding::{Encoding, DecodeReplace};
use encoding::label::encoding_from_whatwg_label;
use encoding::all::WINDOWS_949;

let euckr = encoding_from_whatwg_label("euc-kr").unwrap();
assert_eq!(euckr.name(), "windows-949");
assert_eq!(euckr.whatwg_name(), Some("euc-kr")); // for the sake of compatibility
let broken = &[0xbf, 0xec, 0xbf, 0xcd, 0xff, 0xbe, 0xd3];
assert_eq!(euckr.decode(broken, DecodeReplace),
           Ok("\uc6b0\uc640\ufffd\uc559".to_string()));

// corresponding rust-encoding native API:
assert_eq!(WINDOWS_949.decode(broken, DecodeReplace),
           Ok("\uc6b0\uc640\ufffd\uc559".to_string()));
~~~~

## Detailed Usage

There are three main entry points to rust-encoding.

**`Encoding`** is a single character encoding.
It contains `encode` and `decode` methods for converting `String` to `Vec<u8>` and vice versa.
For the error handling, they receive **traps** (`EncoderTrap` and `DecoderTrap` respectively)
which replace any error with some string (e.g. `U+FFFD`) or sequence (e.g. `?`).
You can also use `EncodeStrict` and `DecodeStrict` traps to stop on an error.

There are two ways to get `Encoding`:

* `encoding::all` has static items for every supported encoding.
  You should use them when the encoding would not change or only handful of them are required.
  Combined with link-time optimization, any unused encoding would be discarded from the binary.
* `encoding::label` has functions to dynamically get an encoding from given string ("label").
  They will return a static reference to the encoding, which type is also known as `EncodingRef`.
  It is useful when a list of required encodings is not available in advance,
  but it will result in the larger binary and missed optimization opportunities.

**`Encoder`** is an experimental incremental encoder.
At each step of `raw_feed`, it receives a slice of string
and emits any encoded bytes to a generic `ByteWriter` (normally `Vec<u8>`).
It will stop at the first error if any, and would return a `CodecError` struct in that case.
The caller is responsible for calling `raw_finish` at the end of encoding process.

**`Decoder`** is an experimental incremental decoder.
At each step of `raw_feed`, it receives a slice of byte sequence
and emits any decoded characters to a generic `StringWriter` (normally `String`).
Otherwise it is identical to `Encoder`s.

One should prefer `Encoding::{encode,decode}` as a primary interface.
`Encoder` and `Decoder` is experimental and can change substantially.
See the additional documents on `encoding::types` module for more information on them.

## Supported Encodings

Rust-encoding covers all encodings specified by WHATWG Encoding Standard and some more:

* 7-bit strict ASCII (`ascii`)
* UTF-8 (`utf-8`)
* UTF-16 in little endian (`utf-16` or `utf-16le`) and big endian (`utf-16be`)
* All single byte encoding in WHATWG Encoding Standard:
    * IBM code page 866
    * ISO 8859-{2,3,4,5,6,7,8,10,13,14,15,16}
    * KOI8-R, KOI8-U
    * MacRoman (`macintosh`), Macintosh Cyrillic encoding (`x-mac-cyrillic`)
    * Windows code pages 874, 1250, 1251, 1252 (instead of ISO 8859-1), 1253,
      1254 (instead of ISO 8859-9), 1255, 1256, 1257, 1258
* All multi byte encodings in WHATWG Encoding Standard:
    * Windows code page 949 (`euc-kr`, since the strict EUC-KR is hardly used)
    * EUC-JP and Windows code page 932 (`shift_jis`,
      since it's the most widespread extension to Shift_JIS)
    * ISO-2022-JP with asymmetric JIS X 0212 support
    * GB 18030
    * HZ
    * Big5-2003 with HKSCS-2008 extensions
* ISO 8859-1 (distinct from Windows code page 1252)

Parenthesized names refer to the encoding's primary name assigned by WHATWG Encoding Standard.

Many legacy character encodings lack the proper specification,
and even those that have a specification are highly dependent of the actual implementation.
Consequently one should be careful when picking a desired character encoding.
The only standards reliable in this regard are WHATWG Encoding Standard and
[vendor-provided mappings from the Unicode consortium](http://www.unicode.org/Public/MAPPINGS/).
Whenever in doubt, look at the source code and specifications for detailed explanations.

*/

#![crate_name = "encoding"]
#![crate_type = "lib"]
#![comment = "Character encoding support for Rust"]
#![license = "MIT"]

#![feature(globs, macro_rules)]
#![feature(import_shadowing)] // XXX Rust issue #16597

#![allow(experimental)]

#[cfg(test)] extern crate test;

pub use self::types::{CodecError, ByteWriter, StringWriter,
                      Encoder, Decoder, EncodingRef, Encoding,
                      EncoderTrapFunc, DecoderTrapFunc, DecoderTrap,
                      DecodeStrict, DecodeReplace, DecodeIgnore,
                      EncoderTrap, EncodeStrict, EncodeReplace,
                      EncodeIgnore, EncodeNcrEscape, decode}; // reexport

mod util;
#[cfg(test)] mod testutils;

pub mod types;

/// Indices used for character encoding implementation. Semi-internal.
#[unstable]
pub mod index {
    pub mod ibm866;
    pub mod iso_8859_2;
    pub mod iso_8859_3;
    pub mod iso_8859_4;
    pub mod iso_8859_5;
    pub mod iso_8859_6;
    pub mod iso_8859_7;
    pub mod iso_8859_8;
    pub mod iso_8859_10;
    pub mod iso_8859_13;
    pub mod iso_8859_14;
    pub mod iso_8859_15;
    pub mod iso_8859_16;
    pub mod koi8_r;
    pub mod koi8_u;
    pub mod macintosh;
    pub mod windows_874;
    pub mod windows_1250;
    pub mod windows_1251;
    pub mod windows_1252;
    pub mod windows_1253;
    pub mod windows_1254;
    pub mod windows_1255;
    pub mod windows_1256;
    pub mod windows_1257;
    pub mod windows_1258;
    pub mod x_mac_cyrillic;
    pub mod big5;
    pub mod euc_kr;
    pub mod gb18030;
    pub mod gb18030_ranges;
    pub mod jis0208;
    pub mod jis0212;
}

/// Codec implementations.
#[unstable]
pub mod codec {
    pub mod error;
    pub mod ascii;
    pub mod singlebyte;
    pub mod utf_8;
    pub mod utf_16;
    pub mod korean;
    pub mod japanese;
    pub mod simpchinese;
    pub mod tradchinese;
    pub mod whatwg;
}

pub mod all;
pub mod label;

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

    #[test]
    fn test_decode() {
        fn test_one(input: &[u8], expected_result: &str, expected_encoding: &str) {
            let (result, used_encoding) = decode(
                input, DecodeStrict, all::ISO_8859_1 as EncodingRef);
            let result = result.unwrap();
            assert_eq!(used_encoding.name(), expected_encoding);
            assert_eq!(result.as_slice(), expected_result);
        }

        test_one([0xEF, 0xBB, 0xBF, 0xC3, 0xA9], "é", "utf-8");
        test_one([0xC3, 0xA9], "Ã©", "iso-8859-1");

        test_one([0xFE, 0xFF, 0x00, 0xE9], "é", "utf-16be");
        test_one([0x00, 0xE9], "\x00é", "iso-8859-1");

        test_one([0xFF, 0xFE, 0xE9, 0x00], "é", "utf-16le");
        test_one([0xE9, 0x00], "é\x00", "iso-8859-1");
    }
}

<|endoftext|>


<commit_before>//! SemanticEngine implementation for [the racer library](https://github.com/phildawes/racer)
//!
use engine::{SemanticEngine, Definition, Context, CursorPosition, Completion};

use racer::core::Session;
use racer::scopes::{coords_to_point, point_to_coords};

use std::path::Path;

use std::sync::Mutex;

pub struct Racer<'a> {
    session: Mutex<&'a Session<'a>>
}

impl<'a> Racer<'a> {
    pub fn new() -> Racer<'a> {
        let path = &Path::new("hopefully/never/a/real/path/as/long/as/this/hack/exists/.com");

        // The unsafe block in the constructor is taking ownership of the Session allocated by this
        // box. It is later freed in the drop impl. Having a Session reference with the same
        // lifetime as Racer solves a concrete self lifetime problem in the SemanticEngine
        // implementation.
        //
        // The following unsafe block should be fine since the memory is known to be valid. The
        // reference will have the same value for the lifetime of the Racer object, so there is no
        // need to worry about stale references wandering around. However, I am not certain that
        // MutexGuard will save us from references escaping a critical section since you normally
        // cannot store references in a Mutex. At this time, that's not a problem, but it would be
        // good to have a static guarantee about not leaking references.
        let session = Box::new(Session::from_path(path, path));
        let session_ptr = Box::into_raw(session);
        Racer {
            session: Mutex::new(unsafe { &*session_ptr })
        }
    }

    pub fn build_racer_args<'b>(&self, ctx: &'b Context) -> (&'a str, usize, &'b Path) {
        let path = ctx.query_path();
        let session = self.session.lock().unwrap();

        for buffer in &ctx.buffers {
            session.cache_file_contents(buffer.path(), &buffer.contents[..]);
        }

        let query_src = &session.load_file(path).src.code[..];
        let pos = coords_to_point(query_src, ctx.query_cursor.line, ctx.query_cursor.col);

        (query_src, pos, path)
    }
}

impl<'a> Drop for Racer<'a> {
    fn drop(&mut self) {
        let session_ref = *self.session.lock().unwrap();
        // At this point, nobody has a reference to the session because it is locked behind the
        // mutex and the lock is held here. Nobody has a reference to the mutex because its holder
        // is being dropped. Thus, casting a non mutable reference to a raw *mut pointer to
        // reconstitute the box should be fine.
        let _session: Box<Session> = unsafe { Box::from_raw(::std::mem::transmute(session_ref)) };
    }
}

use ::Config;
use super::Result;

impl<'a> SemanticEngine for Racer<'a> {
    fn initialize(&self, config: &Config) -> Result<()> {
        if let Some(ref src_path) = config.rust_src_path {
            ::std::env::set_var("RUST_SRC_PATH", &src_path[..]);
        }

        Ok(())
    }

    fn find_definition(&self, ctx: &Context) -> Result<Option<Definition>> {
        let (query_src, pos, path) = self.build_racer_args(ctx);
        let session = self.session.lock().unwrap();

        // TODO catch_panic: apparently this can panic! in a string operation. Something about pos
        // not landing on a character boundary.
        Ok(match ::racer::core::find_definition(query_src, path, pos, *session) {
            Some(m) => {
                // TODO modify racer Match to return line, col. For now, read the file it found a
                // match in to translate the Match position into line, col.
                let (line, col) = {
                    let found_src = &session.load_file(m.filepath.as_path());
                    let found_src_str = &found_src.src.code[..];
                    // TODO This can panic if the position is out of bounds :(
                    point_to_coords(found_src_str, m.point)
                };

                let match_type = format!("{:?}", m.mtype);
                Some(Definition {
                    position: CursorPosition {
                        line: line,
                        col: col
                    },
                    dtype: match_type,
                    file_path: m.filepath.to_str().unwrap().to_string(),
                    text: m.matchstr.clone(),
                    text_context: m.contextstr.clone(),
                })
            },
            None => None
        })
    }

    fn list_completions(&self, ctx: &Context) -> Result<Option<Vec<Completion>>> {
        let (query_src, pos, path) = self.build_racer_args(ctx);
        let session = self.session.lock().unwrap();

        let matches = ::racer::core::complete_from_file(query_src, path, pos, *session);

        let completions = matches.map(|m| {
            let (line, col) = {
                let found_src = &session.load_file(m.filepath.as_path());
                let found_src_str = &found_src.src.code[..];
                // TODO This can panic if the position is out of bounds :(
                point_to_coords(found_src_str, m.point)
            };

            Completion {
                position: CursorPosition {
                    line: line,
                    col: col
                },
                text: m.matchstr,
                context: m.contextstr,
                kind: format!("{:?}", m.mtype),
                file_path: m.filepath.to_str().unwrap().to_string()
            }
        }).collect::<Vec<_>>();

        if completions.len() != 0 {
            Ok(Some(completions))
        } else {
            Ok(None)
        }
    }
}

unsafe impl<'a> Sync for Racer<'a> {}
unsafe impl<'a> Send for Racer<'a> {}

#[cfg(test)]
mod tests {
    use super::*;
    use engine::{Context, CursorPosition, SemanticEngine, Buffer};

    use ::util::fs::TmpFile;

    #[test]
    #[allow(unused_variables)]
    fn find_definition() {
        // FIXME this is just here for side effects.
        let src2 = TmpFile::with_name("src2.rs", "
            pub fn myfn() {}
            pub fn foo() {}
            ");

        let src = "
            use src2::*;
            mod src2;
            fn main() {
                myfn();
            }";

        let buffers = vec![Buffer {
            contents: src.to_string(),
            file_path: "src.rs".to_string()
        }];

        let ctx = Context::new(buffers, CursorPosition { line: 5, col: 17 }, "src.rs");
        let racer = Racer::new();
        let def = racer.find_definition(&ctx).unwrap().unwrap();

        assert_eq!(def.text, "myfn");
    }

    #[test]
    #[allow(unused_variables)]
    fn find_completion() {
        let src = "
            mod mymod {
                /// myfn is a thing
                pub fn myfn<T>(reader: T) where T: ::std::io::Read {}
            }

            fn main() {
                mymod::my
            }";

        let buffers = vec![Buffer {
            contents: src.to_string(),
            file_path: "src.rs".to_string()
        }];

        let ctx = Context::new(buffers, CursorPosition { line: 8, col: 25 }, "src.rs");
        let racer = Racer::new();

        let completions = racer.list_completions(&ctx).unwrap().unwrap();
        assert_eq!(completions.len(), 1);

        let completion = &completions[0];
        assert_eq!(completion.text, "myfn");
        assert_eq!(completion.position.line, 4);
        assert_eq!(completion.file_path, "src.rs");
    }
}
<commit_msg>Handle PoisonError when locking session<commit_after>//! SemanticEngine implementation for [the racer library](https://github.com/phildawes/racer)
//!
use engine::{SemanticEngine, Definition, Context, CursorPosition, Completion};

use racer::core::Session;
use racer::scopes::{coords_to_point, point_to_coords};

use std::path::Path;

use std::sync::Mutex;

pub struct Racer<'a> {
    session: Mutex<&'a Session<'a>>
}

impl<'a> Racer<'a> {
    pub fn new() -> Racer<'a> {
        let path = &Path::new("hopefully/never/a/real/path/as/long/as/this/hack/exists/.com");

        // The unsafe block in the constructor is taking ownership of the Session allocated by this
        // box. It is later freed in the drop impl. Having a Session reference with the same
        // lifetime as Racer solves a concrete self lifetime problem in the SemanticEngine
        // implementation.
        //
        // The following unsafe block should be fine since the memory is known to be valid. The
        // reference will have the same value for the lifetime of the Racer object, so there is no
        // need to worry about stale references wandering around. However, I am not certain that
        // MutexGuard will save us from references escaping a critical section since you normally
        // cannot store references in a Mutex. At this time, that's not a problem, but it would be
        // good to have a static guarantee about not leaking references.
        let session = Box::new(Session::from_path(path, path));
        let session_ptr = Box::into_raw(session);
        Racer {
            session: Mutex::new(unsafe { &*session_ptr })
        }
    }

    pub fn build_racer_args<'b>(&self, ctx: &'b Context) -> (&'a str, usize, &'b Path) {
        let path = ctx.query_path();
        let session = self.session.lock().unwrap();

        for buffer in &ctx.buffers {
            session.cache_file_contents(buffer.path(), &buffer.contents[..]);
        }

        let query_src = &session.load_file(path).src.code[..];
        let pos = coords_to_point(query_src, ctx.query_cursor.line, ctx.query_cursor.col);

        (query_src, pos, path)
    }
}

impl<'a> Drop for Racer<'a> {
    fn drop(&mut self) {
        let session_ref = *self.session.lock().unwrap();
        // At this point, nobody has a reference to the session because it is locked behind the
        // mutex and the lock is held here. Nobody has a reference to the mutex because its holder
        // is being dropped. Thus, casting a non mutable reference to a raw *mut pointer to
        // reconstitute the box should be fine.
        let _session: Box<Session> = unsafe { Box::from_raw(::std::mem::transmute(session_ref)) };
    }
}

use ::Config;
use super::Result;

impl<'a> SemanticEngine for Racer<'a> {
    fn initialize(&self, config: &Config) -> Result<()> {
        if let Some(ref src_path) = config.rust_src_path {
            ::std::env::set_var("RUST_SRC_PATH", &src_path[..]);
        }

        Ok(())
    }

    fn find_definition(&self, ctx: &Context) -> Result<Option<Definition>> {
        let (query_src, pos, path) = self.build_racer_args(ctx);
        let session = match self.session.lock() {
            Ok(guard) => guard,
            Err(poisoned) => poisoned.into_inner()
        };

        // TODO catch_panic: apparently this can panic! in a string operation. Something about pos
        // not landing on a character boundary.
        Ok(match ::racer::core::find_definition(query_src, path, pos, *session) {
            Some(m) => {
                // TODO modify racer Match to return line, col. For now, read the file it found a
                // match in to translate the Match position into line, col.
                let (line, col) = {
                    let found_src = &session.load_file(m.filepath.as_path());
                    let found_src_str = &found_src.src.code[..];
                    // TODO This can panic if the position is out of bounds :(
                    point_to_coords(found_src_str, m.point)
                };

                let match_type = format!("{:?}", m.mtype);
                Some(Definition {
                    position: CursorPosition {
                        line: line,
                        col: col
                    },
                    dtype: match_type,
                    file_path: m.filepath.to_str().unwrap().to_string(),
                    text: m.matchstr.clone(),
                    text_context: m.contextstr.clone(),
                })
            },
            None => None
        })
    }

    fn list_completions(&self, ctx: &Context) -> Result<Option<Vec<Completion>>> {
        let (query_src, pos, path) = self.build_racer_args(ctx);
        let session = match self.session.lock() {
            Ok(guard) => guard,
            Err(poisoned) => poisoned.into_inner()
        };

        let matches = ::racer::core::complete_from_file(query_src, path, pos, *session);

        let completions = matches.map(|m| {
            let (line, col) = {
                let found_src = &session.load_file(m.filepath.as_path());
                let found_src_str = &found_src.src.code[..];
                // TODO This can panic if the position is out of bounds :(
                point_to_coords(found_src_str, m.point)
            };

            Completion {
                position: CursorPosition {
                    line: line,
                    col: col
                },
                text: m.matchstr,
                context: m.contextstr,
                kind: format!("{:?}", m.mtype),
                file_path: m.filepath.to_str().unwrap().to_string()
            }
        }).collect::<Vec<_>>();

        if completions.len() != 0 {
            Ok(Some(completions))
        } else {
            Ok(None)
        }
    }
}

unsafe impl<'a> Sync for Racer<'a> {}
unsafe impl<'a> Send for Racer<'a> {}

#[cfg(test)]
mod tests {
    use super::*;
    use engine::{Context, CursorPosition, SemanticEngine, Buffer};

    use ::util::fs::TmpFile;

    #[test]
    #[allow(unused_variables)]
    fn find_definition() {
        // FIXME this is just here for side effects.
        let src2 = TmpFile::with_name("src2.rs", "
            pub fn myfn() {}
            pub fn foo() {}
            ");

        let src = "
            use src2::*;
            mod src2;
            fn main() {
                myfn();
            }";

        let buffers = vec![Buffer {
            contents: src.to_string(),
            file_path: "src.rs".to_string()
        }];

        let ctx = Context::new(buffers, CursorPosition { line: 5, col: 17 }, "src.rs");
        let racer = Racer::new();
        let def = racer.find_definition(&ctx).unwrap().unwrap();

        assert_eq!(def.text, "myfn");
    }

    #[test]
    #[allow(unused_variables)]
    fn find_completion() {
        let src = "
            mod mymod {
                /// myfn is a thing
                pub fn myfn<T>(reader: T) where T: ::std::io::Read {}
            }

            fn main() {
                mymod::my
            }";

        let buffers = vec![Buffer {
            contents: src.to_string(),
            file_path: "src.rs".to_string()
        }];

        let ctx = Context::new(buffers, CursorPosition { line: 8, col: 25 }, "src.rs");
        let racer = Racer::new();

        let completions = racer.list_completions(&ctx).unwrap().unwrap();
        assert_eq!(completions.len(), 1);

        let completion = &completions[0];
        assert_eq!(completion.text, "myfn");
        assert_eq!(completion.position.line, 4);
        assert_eq!(completion.file_path, "src.rs");
    }
}
<|endoftext|>


<commit_before>use anyhow::{anyhow, Result};
use std::fs;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct OwnerFilter {
    uid: Option<u32>,
    gid: Option<u32>,
}

impl OwnerFilter {
    pub fn from_string(input: &str) -> Result<Self> {
        let mut it = input.split(':');
        let (fst, snd) = (it.next(), it.next());

        let uid = match fst {
            Some("") | None => None,
            Some(s) => {
                let maybe_uid = s
                    .parse()
                    .ok()
                    .or_else(|| users::get_user_by_name(s).map(|user| user.uid()));
                match maybe_uid {
                    Some(uid) => Some(uid),
                    _ => return Err(anyhow!("'{}' is not a recognized user name", s)),
                }
            }
        };
        let gid = match snd {
            Some("") | None => None,
            Some(s) => {
                let maybe_gid = s
                    .parse()
                    .ok()
                    .or_else(|| users::get_group_by_name(s).map(|group| group.gid()));
                match maybe_gid {
                    Some(gid) => Some(gid),
                    _ => return Err(anyhow!("'{}' is not a recognized group name", s)),
                }
            }
        };

        if uid.is_none() && gid.is_none() {
            Err(anyhow!(
                "'{}' is not a valid user/group specifier. See 'fd --help'.",
                input
            ))
        } else {
            Ok(OwnerFilter { uid, gid })
        }
    }

    pub fn matches(&self, md: &fs::Metadata) -> bool {
        use std::os::unix::fs::MetadataExt;

        let uid_ok = self.uid.map(|u| u == md.uid()).unwrap_or(true);
        let gid_ok = self.gid.map(|g| g == md.gid()).unwrap_or(true);

        uid_ok && gid_ok
    }
}

#[cfg(test)]
mod owner_parsing {
    use super::OwnerFilter;

    macro_rules! owner_tests {
        ($($name:ident: $value:expr => $result:pat,)*) => {
            $(
                #[test]
                fn $name() {
                    let o = OwnerFilter::from_string($value);
                    match o {
                        $result => {},
                        _ => panic!("{:?} does not match {}", o, stringify!($result)),
                    }
                }
            )*
        };
    }

    owner_tests! {
        empty:      ""      => Err(_),
        uid_only:   "5"     => Ok(OwnerFilter { uid: Some(5), gid: None   }),
        uid_gid:    "9:3"   => Ok(OwnerFilter { uid: Some(9), gid: Some(3)}),
        gid_only:   ":8"    => Ok(OwnerFilter { uid: None,    gid: Some(8)}),
        colon_only: ":"     => Err(_),
        trailing:   "5:"    => Ok(OwnerFilter { uid: Some(5), gid: None   }),
    }
}
<commit_msg>[ownership] change uid/gid storage to tristate enum for negation<commit_after>use anyhow::{anyhow, Result};
use std::fs;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct OwnerFilter {
    uid: Check<u32>,
    gid: Check<u32>,
}

#[derive(Clone, Copy, Debug, PartialEq)]
enum Check<T> {
    Equal(T),
    NotEq(T),
    Ignore,
}

impl OwnerFilter {
    pub fn from_string(input: &str) -> Result<Self> {
        let mut it = input.split(':');
        let (fst, snd) = (it.next(), it.next());

        let uid = match fst {
            Some("") | None => None,
            Some(s) => {
                let maybe_uid = s
                    .parse()
                    .ok()
                    .or_else(|| users::get_user_by_name(s).map(|user| user.uid()));
                match maybe_uid {
                    Some(uid) => Some(uid),
                    _ => return Err(anyhow!("'{}' is not a recognized user name", s)),
                }
            }
        };
        let gid = match snd {
            Some("") | None => None,
            Some(s) => {
                let maybe_gid = s
                    .parse()
                    .ok()
                    .or_else(|| users::get_group_by_name(s).map(|group| group.gid()));
                match maybe_gid {
                    Some(gid) => Some(gid),
                    _ => return Err(anyhow!("'{}' is not a recognized group name", s)),
                }
            }
        };

        use self::Check::*;
        let uid = match uid {
            Some(u) => Equal(u),
            _ => Ignore,
        };
        let gid = match gid {
            Some(g) => Equal(g),
            _ => Ignore,
        };

        if let (Ignore, Ignore) = (uid, gid) {
            Err(anyhow!(
                "'{}' is not a valid user/group specifier. See 'fd --help'.",
                input
            ))
        } else {
            Ok(OwnerFilter { uid, gid })
        }
    }

    pub fn matches(&self, md: &fs::Metadata) -> bool {
        use std::os::unix::fs::MetadataExt;

        self.uid.check(md.uid()) && self.gid.check(md.gid())
    }
}

impl<T: PartialEq> Check<T> {
    fn check(&self, v: T) -> bool {
        match self {
            Check::Equal(x) => v == *x,
            Check::NotEq(x) => v != *x,
            Check::Ignore => true,
        }
    }
}

#[cfg(test)]
mod owner_parsing {
    use super::OwnerFilter;

    macro_rules! owner_tests {
        ($($name:ident: $value:expr => $result:pat,)*) => {
            $(
                #[test]
                fn $name() {
                    let o = OwnerFilter::from_string($value);
                    match o {
                        $result => {},
                        _ => panic!("{:?} does not match {}", o, stringify!($result)),
                    }
                }
            )*
        };
    }

    use super::Check::*;
    owner_tests! {
        empty:      ""      => Err(_),
        uid_only:   "5"     => Ok(OwnerFilter { uid: Equal(5), gid: Ignore    }),
        uid_gid:    "9:3"   => Ok(OwnerFilter { uid: Equal(9), gid: Equal(3)  }),
        gid_only:   ":8"    => Ok(OwnerFilter { uid: Ignore,   gid: Equal(8)  }),
        colon_only: ":"     => Err(_),
        trailing:   "5:"    => Ok(OwnerFilter { uid: Equal(5), gid: Ignore    }),
    }
}
<|endoftext|>


<commit_before>use parser::{parse};
use expr::Expr::*;
use expr::UnOp::*;
use expr::BinOp::*;
use std::collections::HashMap;

#[derive(Clone, Debug, PartialEq)]
pub enum UnOp {
  Not,
  Neg,
}

#[derive(Clone, Debug, PartialEq)]
pub enum BinOp {
  Plus,
  Minus,
  Times,
  Div,
  Eq,
  Ne,
  Leq,
  Geq,
  Lt,
  Gt,
  And,
  Or,
  Mod,
  Seq,
}

#[derive(Clone, Debug)]
pub struct State {
  mem: HashMap<String, String>,
  expr: Expr,
}

impl State {
  fn wrap(e: Expr) -> State {
    return State {
      mem: HashMap::new(),
      expr: e,
    }
  }

  fn with(&mut self, e1: Expr) -> State {
    let mem = self.mem.clone();

    return State {
      mem: mem,
      expr: e1,
    }
  }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
  Int(isize),
  Bool(bool),
  Var(String),
  Bop(BinOp, Box<Expr>, Box<Expr>),
  Uop(UnOp, Box<Expr>),
  Ternary(Box<Expr>, Box<Expr>, Box<Expr>),
  Let(Box<Expr>, Box<Expr>, Box<Expr>),
  Func(Option<Box<Expr>>, Box<Expr>, Vec<Expr>),
  FnCall(Box<Expr>, Vec<Expr>),
}

fn is_int(e: &Expr) -> bool {
  match *e {
    Int(_) => true,
    _ => false,
  }
}

fn is_bool(e: &Expr) -> bool {
  match *e {
    Bool(_) => true,
    _ => false,
  }
}

fn is_func(e: &Expr) -> bool {
  match *e {
    Func(_, _, _) => true,
    _ => false,
  }
}

fn is_value(e: &Expr) -> bool {
  match *e {
    Int(_) | Bool(_) | Var(_) | Func(_, _, _) => true,
    _ => false,
  }
}

fn to_int(e: &Expr) -> isize {
  match *e {
    Int(n) => n,
    _ => {
      debug!("cant turn into int: {:?}", e);
      panic!()
    }
  }
}

fn to_bool(e: &Expr) -> bool {
  match *e {
    Bool(b) => b,
    _ => {
      debug!("cant turn into bool: {:?}", e);
      panic!()
    }
  }
}

fn subst(e: Expr, x: Expr, v: Expr) -> Expr {
  let sub = |e1: Expr| subst(e1.clone(), x.clone(), v.clone());

  match (e.clone(), x.clone()) {
    (Var(ref s1), Var(ref s2)) if s1 == s2 => v.clone(),
    (FnCall(v1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();

      if *v1 == x {
        FnCall(Box::new(v.clone()), xs2)
      } else {
        FnCall(v1, xs2)
      }
    },
    (Var(_), _) => e,
    (Int(_), _) => e,
    (Bool(_), _) => e,
    (Bop(op, e1, e2), _) => {
      Bop(
        op,
        Box::new(sub(*e1)),
        Box::new(sub(*e2))
      )
    },
    (Uop(op, e1), _) => Uop(op, Box::new(sub(*e1))),
    (Ternary(e1, e2, e3), _) => {
      Ternary(
        Box::new(sub(*e1)),
        Box::new(sub(*e2)),
        Box::new(sub(*e3))
      )
    },
    (Let(e1, e2, e3), _) => {
      let e3s = if *e1 == x {
        *e3
      } else {
        sub(*e3)
      };

      Let(
        Box::new(*e1),
        Box::new(sub(*e2)),
        Box::new(e3s)
      )
    },
    (Func(name, e1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();
      Func(name, Box::new(sub(*e1)), xs2)
    },
  }
}

pub fn step(mut state: State) -> State {
  let st_step = |s: &mut State, e1: &Expr| step(s.with(e1.clone())).expr;

  //debug!("step(e) : {:?}", e);
  let e1 = match state.expr.clone() {
    /**
     * Values are ineligible for step
     */
    Int(_) | Bool(_) | Func(_, _, _) | Var(_) => {
      debug!("stepping on a value {:?}", state.expr);
      panic!("stepping on a value");
    },
    /**
     * Base cases
     */
    Uop(Not, ref e1) if is_bool(e1) => {
      Bool(!to_bool(e1))
    },
    Uop(Neg, ref e1) if is_int(e1) => {
      Int(-1 * to_int(e1))
    },
    Bop(And, ref e1, ref e2) if is_bool(e1) && is_bool(e2) => {
      Bool(to_bool(e1) && to_bool(e2))
    },
    Bop(Or, ref e1, ref e2) if is_bool(e1) && is_bool(e2) => {
      Bool(to_bool(e1) || to_bool(e2))
    },
    Bop(Eq, ref e1, ref e2) if is_value(e1) && is_value(e2) => {
      Bool(*e1 == *e2)
    },
    Bop(Ne, ref e1, ref e2) if is_value(e1) && is_value(e2) => {
      Bool(*e1 != *e2)
    },
    Bop(Mod, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      let n1 = to_int(e1);
      let n2 = to_int(e2);

      // rust % gives the remainder, not modulus
      let result = ((n1 % n2) + n2) % n2;

      Int(result)
    },
    Bop(Lt, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) < to_int(e2))
    },
    Bop(Gt, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) > to_int(e2))
    },
    Bop(Leq, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) <= to_int(e2))
    },
    Bop(Geq, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) >= to_int(e2))
    },
    Bop(Plus, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) + to_int(e2))
    },
    Bop(Minus, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) - to_int(e2))
    },
    Bop(Times, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) * to_int(e2))
    },
    Bop(Div, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) / to_int(e2))
    },
    Bop(Seq, ref e1, ref e2) if is_value(e1) => {
      *e2.clone()
    },
    Ternary(ref e1, ref e2, ref e3) if is_value(e1) => {
      match to_bool(e1) {
        true => *e2.clone(),
        false => *e3.clone(),
      }
    },
    Let(ref x, ref e1, ref e2) if is_value(e1) => {
      subst(*e2.clone(), *x.clone(), *e1.clone())
    },
    FnCall(ref v1, ref es) if is_func(v1) => {
      match **v1 {
        Func(ref name, ref e1, ref xs) => {
          // sub the params
          let exp = xs.iter().zip(es.iter())
            .fold(*e1.clone(), |exp, (xn, en)| subst(exp, xn.clone(), en.clone()));

          // sub the fn body for named functions
          match *name {
            None => exp,
            Some(ref s) => subst(exp, *s.clone(), *v1.clone())
          }
        },
        _ => {
          debug!("expected a Func, got {:?}", v1);
          panic!()
        },
      }
    },
    /**
     * Search Cases
     */
    Bop(ref op, ref v1, ref e2) if is_value(v1) => {
      Bop(
        op.clone(),
        Box::new(*v1.clone()),
        Box::new(st_step(&mut state, e2))
      )
    },
    Bop(op, e1, e2) => {
      Bop(op, Box::new(step(state.with(*e1)).expr), e2)
    },
    Uop(op, e1) => {
      Uop(op, Box::new(step(state.with(*e1)).expr))
    },
    Ternary(e1, e2, e3) => {
      Ternary(Box::new(step(state.with(*e1)).expr), e2, e3)
    },
    Let(ref e1, ref e2, ref e3) if is_value(e1) => {
      Let(
        Box::new(*e1.clone()),
        Box::new(step(state.with(*e2.clone())).expr),
        Box::new(*e3.clone())
      )
    },
    Let(e1, e2, e3) => {
      Let(Box::new(step(state.with(*e1)).expr), e2, e3)
    },
    FnCall(e1, mut xs) => {
      let mut found_first = true;

      for x in xs.iter_mut() {
        if is_value(x) && found_first == true {
          found_first = false;
          *x = step(state.with(x.clone())).expr;
        }
      }

      FnCall(e1, xs)
    }
  };

  state.with(e1)
}

pub fn boxx(input: &str) -> Expr {
  let mut state = State::wrap(parse(input));

  let mut num_iterations = 0;

  loop {
    num_iterations += 1;
    if is_value(&state.expr) {
      debug!("--- iterations: {}", num_iterations);
      return state.expr
    } else {
      state = step(state);
    }
  }
}
<commit_msg>use st_step closure<commit_after>use parser::{parse};
use expr::Expr::*;
use expr::UnOp::*;
use expr::BinOp::*;
use std::collections::HashMap;

#[derive(Clone, Debug, PartialEq)]
pub enum UnOp {
  Not,
  Neg,
}

#[derive(Clone, Debug, PartialEq)]
pub enum BinOp {
  Plus,
  Minus,
  Times,
  Div,
  Eq,
  Ne,
  Leq,
  Geq,
  Lt,
  Gt,
  And,
  Or,
  Mod,
  Seq,
}

#[derive(Clone, Debug)]
pub struct State {
  mem: HashMap<String, String>,
  expr: Expr,
}

impl State {
  fn from(e: Expr) -> State {
    return State {
      mem: HashMap::new(),
      expr: e,
    }
  }

  fn with(&mut self, e1: Expr) -> State {
    let mem = self.mem.clone();

    return State {
      mem: mem,
      expr: e1,
    }
  }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
  Int(isize),
  Bool(bool),
  Var(String),
  Bop(BinOp, Box<Expr>, Box<Expr>),
  Uop(UnOp, Box<Expr>),
  Ternary(Box<Expr>, Box<Expr>, Box<Expr>),
  Let(Box<Expr>, Box<Expr>, Box<Expr>),
  Func(Option<Box<Expr>>, Box<Expr>, Vec<Expr>),
  FnCall(Box<Expr>, Vec<Expr>),
}

fn is_int(e: &Expr) -> bool {
  match *e {
    Int(_) => true,
    _ => false,
  }
}

fn is_bool(e: &Expr) -> bool {
  match *e {
    Bool(_) => true,
    _ => false,
  }
}

fn is_func(e: &Expr) -> bool {
  match *e {
    Func(_, _, _) => true,
    _ => false,
  }
}

fn is_value(e: &Expr) -> bool {
  match *e {
    Int(_) | Bool(_) | Var(_) | Func(_, _, _) => true,
    _ => false,
  }
}

fn to_int(e: &Expr) -> isize {
  match *e {
    Int(n) => n,
    _ => {
      debug!("cant turn into int: {:?}", e);
      panic!()
    }
  }
}

fn to_bool(e: &Expr) -> bool {
  match *e {
    Bool(b) => b,
    _ => {
      debug!("cant turn into bool: {:?}", e);
      panic!()
    }
  }
}

fn subst(e: Expr, x: Expr, v: Expr) -> Expr {
  let sub = |e1: Expr| subst(e1.clone(), x.clone(), v.clone());

  match (e.clone(), x.clone()) {
    (Var(ref s1), Var(ref s2)) if s1 == s2 => v.clone(),
    (FnCall(v1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();

      if *v1 == x {
        FnCall(Box::new(v.clone()), xs2)
      } else {
        FnCall(v1, xs2)
      }
    },
    (Var(_), _) => e,
    (Int(_), _) => e,
    (Bool(_), _) => e,
    (Bop(op, e1, e2), _) => {
      Bop(
        op,
        Box::new(sub(*e1)),
        Box::new(sub(*e2))
      )
    },
    (Uop(op, e1), _) => Uop(op, Box::new(sub(*e1))),
    (Ternary(e1, e2, e3), _) => {
      Ternary(
        Box::new(sub(*e1)),
        Box::new(sub(*e2)),
        Box::new(sub(*e3))
      )
    },
    (Let(e1, e2, e3), _) => {
      let e3s = if *e1 == x {
        *e3
      } else {
        sub(*e3)
      };

      Let(
        Box::new(*e1),
        Box::new(sub(*e2)),
        Box::new(e3s)
      )
    },
    (Func(name, e1, xs), _) => {
      let xs2 = xs.iter().map(|xn| sub(xn.clone())).collect();
      Func(name, Box::new(sub(*e1)), xs2)
    },
  }
}

pub fn step(mut state: State) -> State {
  let st_step = |s: &mut State, e1: &Expr| step(s.with(e1.clone())).expr;

  //debug!("step(e) : {:?}", e);
  let e1 = match state.expr.clone() {
    /**
     * Values are ineligible for step
     */
    Int(_) | Bool(_) | Func(_, _, _) | Var(_) => {
      debug!("stepping on a value {:?}", state.expr);
      panic!("stepping on a value");
    },
    /**
     * Base cases
     */
    Uop(Not, ref e1) if is_bool(e1) => {
      Bool(!to_bool(e1))
    },
    Uop(Neg, ref e1) if is_int(e1) => {
      Int(-1 * to_int(e1))
    },
    Bop(And, ref e1, ref e2) if is_bool(e1) && is_bool(e2) => {
      Bool(to_bool(e1) && to_bool(e2))
    },
    Bop(Or, ref e1, ref e2) if is_bool(e1) && is_bool(e2) => {
      Bool(to_bool(e1) || to_bool(e2))
    },
    Bop(Eq, ref e1, ref e2) if is_value(e1) && is_value(e2) => {
      Bool(*e1 == *e2)
    },
    Bop(Ne, ref e1, ref e2) if is_value(e1) && is_value(e2) => {
      Bool(*e1 != *e2)
    },
    Bop(Mod, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      let n1 = to_int(e1);
      let n2 = to_int(e2);

      // rust % gives the remainder, not modulus
      let result = ((n1 % n2) + n2) % n2;

      Int(result)
    },
    Bop(Lt, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) < to_int(e2))
    },
    Bop(Gt, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) > to_int(e2))
    },
    Bop(Leq, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) <= to_int(e2))
    },
    Bop(Geq, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Bool(to_int(e1) >= to_int(e2))
    },
    Bop(Plus, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) + to_int(e2))
    },
    Bop(Minus, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) - to_int(e2))
    },
    Bop(Times, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) * to_int(e2))
    },
    Bop(Div, ref e1, ref e2) if is_int(e1) && is_int(e2) => {
      Int(to_int(e1) / to_int(e2))
    },
    Bop(Seq, ref e1, ref e2) if is_value(e1) => {
      *e2.clone()
    },
    Ternary(ref e1, ref e2, ref e3) if is_value(e1) => {
      match to_bool(e1) {
        true => *e2.clone(),
        false => *e3.clone(),
      }
    },
    Let(ref x, ref e1, ref e2) if is_value(e1) => {
      subst(*e2.clone(), *x.clone(), *e1.clone())
    },
    FnCall(ref v1, ref es) if is_func(v1) => {
      match **v1 {
        Func(ref name, ref e1, ref xs) => {
          // sub the params
          let exp = xs.iter().zip(es.iter())
            .fold(*e1.clone(), |exp, (xn, en)| subst(exp, xn.clone(), en.clone()));

          // sub the fn body for named functions
          match *name {
            None => exp,
            Some(ref s) => subst(exp, *s.clone(), *v1.clone())
          }
        },
        _ => {
          debug!("expected a Func, got {:?}", v1);
          panic!()
        },
      }
    },
    /**
     * Search Cases
     */
    Bop(ref op, ref v1, ref e2) if is_value(v1) => {
      Bop(
        op.clone(),
        Box::new(*v1.clone()),
        Box::new(st_step(&mut state, e2))
      )
    },
    Bop(op, e1, e2) => {
      Bop(op, Box::new(st_step(&mut state, &*e1)), e2)
    },
    Uop(op, e1) => {
      Uop(op, Box::new(st_step(&mut state, &*e1)))
    },
    Ternary(e1, e2, e3) => {
      Ternary(Box::new(st_step(&mut state, &*e1)), e2, e3)
    },
    Let(ref e1, ref e2, ref e3) if is_value(e1) => {
      Let(
        Box::new(*e1.clone()),
        Box::new(st_step(&mut state, e2)),
        Box::new(*e3.clone())
      )
    },
    Let(e1, e2, e3) => {
      Let(Box::new(st_step(&mut state, &*e1)), e2, e3)
    },
    FnCall(e1, mut xs) => {
      let mut found_first = true;

      for x in xs.iter_mut() {
        if is_value(x) && found_first == true {
          found_first = false;
          *x = st_step(&mut state, x);
        }
      }

      FnCall(e1, xs)
    }
  };

  state.with(e1)
}

pub fn boxx(input: &str) -> Expr {
  let mut state = State::from(parse(input));

  let mut num_iterations = 0;

  loop {
    num_iterations += 1;
    if is_value(&state.expr) {
      debug!("--- iterations: {}", num_iterations);
      return state.expr
    } else {
      state = step(state);
    }
  }
}
<|endoftext|>


<commit_before>//!Defines the game state and logic

use crate::dictionary::CONF_LINE_WORD_MODIFIER__VISIBLE;
use std::fmt;

/// Defines the linebreak position when displaying the secret string.
const LINE_WIDTH: usize = 20;

/// One character of the secret string.
#[derive(Debug)]
struct HangmanChar {
    char_: char,
    visible: bool,
}

/// Format HangmanChar.
impl fmt::Display for HangmanChar {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if self.visible {
            write!(f, "{}", self.char_)
        } else {
            write!(f, "_")
        }
    }
}

/// A subset of the game state. Can be derived from `Game` struct.
pub enum State {
    /// The game is ongoing.
    Ongoing,
    /// The player won.
    Victory,
    /// The player lost.
    Defeat,
}

/// The game state.
#[derive(Debug)]
pub struct Game {
    word: Vec<HangmanChar>,
    pub lives: u8,
    pub last_guess: char,
}

impl Game {
    /// Derive State from Game data.
    pub fn get_state(&self) -> State {
        if self.lives == 0 {
            State::Defeat
        } else if self.word.iter().all(|c| c.visible) {
            State::Victory
        } else {
            State::Ongoing
        }
    }

    /// Constructor.
    pub fn new(wordstr: &str, l: u8) -> Self {
        // parse wordsstr, filp 'visible' every CONF_LINE_WORD_MODIFIER__VISIBLE
        let w = wordstr
            .chars()
            // for every * found flip v_acc
            .scan(false, |v_acc, c| {
                *v_acc ^= c == CONF_LINE_WORD_MODIFIER__VISIBLE;
                if c == CONF_LINE_WORD_MODIFIER__VISIBLE {
                    Some(None)
                } else {
                    Some(Some(HangmanChar {
                        char_: c,
                        visible: *v_acc,
                    }))
                }
            })
            // ommit None and unwrap
            .filter_map(|s| s)
            //.inspect(|ref x| println!("after scan:\t{:?}", x))
            .collect();

        Self {
            word: w,
            lives: l,
            last_guess: ' ',
        }
    }

    /// Process a guess and modify the game state.
    pub fn guess(&mut self, char_: char) {
        if char_ == '\n' {
            return;
        };
        self.last_guess = char_;
        let mut found = false;
        for h_char in &mut self.word {
            if h_char.char_.eq_ignore_ascii_case(&char_) {
                h_char.visible = true;
                found = true;
            }
        }

        if !found {
            self.lives -= 1;
        }

        if self.lives == 0 {
            for hc in &mut self.word {
                hc.visible = true;
            }
        }
    }

    /// The number of disclosed characters of the secret.
    pub fn visible_chars(&self) -> usize {
        self.word.iter().filter(|hc| !hc.visible).count()
    }
}

impl fmt::Display for Game {
    /// Graphical representation of the game state.
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        writeln!(
            f,
            "Lives:\t{}\tLast guess: {}\n",
            self.lives, self.last_guess
        )?;

        let mut linebreak = false;
        for (n, c) in self.word.iter().enumerate() {
            if n % LINE_WIDTH == 0 {
                linebreak = true
            };
            if n == 0 {
                linebreak = false
            };
            if linebreak && (c.char_ == ' ') {
                linebreak = false;
                writeln!(f, " {}", c)?
            } else {
                write!(f, " {}", c)?
            }
        }
        writeln!(f)
    }
}
<commit_msg>add game simulation test<commit_after>//!Defines the game state and logic

use crate::dictionary::CONF_LINE_WORD_MODIFIER__VISIBLE;
use std::fmt;

/// Defines the linebreak position when displaying the secret string.
const LINE_WIDTH: usize = 20;

/// One character of the secret string.
#[derive(Debug, Clone, PartialEq)]
struct HangmanChar {
    char_: char,
    visible: bool,
}

/// Format HangmanChar.
impl fmt::Display for HangmanChar {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if self.visible {
            write!(f, "{}", self.char_)
        } else {
            write!(f, "_")
        }
    }
}

/// A subset of the game state. Can be derived from `Game` struct.
#[derive(PartialEq)]
pub enum State {
    /// The game is ongoing.
    Ongoing,
    /// The player won.
    Victory,
    /// The player lost.
    Defeat,
}

/// The game state.
#[derive(Debug, PartialEq)]
pub struct Game {
    word: Vec<HangmanChar>,
    pub lives: u8,
    pub last_guess: char,
}

impl Game {
    /// Derive State from Game data.
    pub fn get_state(&self) -> State {
        if self.lives == 0 {
            State::Defeat
        } else if self.word.iter().all(|c| c.visible) {
            State::Victory
        } else {
            State::Ongoing
        }
    }

    /// Constructor.
    pub fn new(wordstr: &str, lives: u8) -> Self {
        // parse wordsstr, filp 'visible' every CONF_LINE_WORD_MODIFIER__VISIBLE
        let w = wordstr
            .chars()
            // for every * found flip v_acc
            .scan(false, |v_acc, c| {
                *v_acc ^= c == CONF_LINE_WORD_MODIFIER__VISIBLE;
                if c == CONF_LINE_WORD_MODIFIER__VISIBLE {
                    Some(None)
                } else {
                    Some(Some(HangmanChar {
                        char_: c,
                        visible: *v_acc,
                    }))
                }
            })
            // ommit None and unwrap
            .filter_map(|s| s)
            //.inspect(|ref x| println!("after scan:\t{:?}", x))
            .collect();

        Self {
            word: w,
            lives,
            last_guess: ' ',
        }
    }

    /// Process a guess and modify the game state.
    pub fn guess(&mut self, char_: char) {
        if char_ == '\n' {
            return;
        };
        self.last_guess = char_;
        let mut found = false;
        for h_char in &mut self.word {
            if h_char.char_.eq_ignore_ascii_case(&char_) {
                h_char.visible = true;
                found = true;
            }
        }

        if !found {
            self.lives -= 1;
        }

        if self.lives == 0 {
            for hc in &mut self.word {
                hc.visible = true;
            }
        }
    }

    /// The number of disclosed characters of the secret.
    pub fn visible_chars(&self) -> usize {
        self.word.iter().filter(|hc| !hc.visible).count()
    }
}

impl fmt::Display for Game {
    /// Graphical representation of the game state.
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        writeln!(
            f,
            "Lives:\t{}\tLast guess: {}\n",
            self.lives, self.last_guess
        )?;

        let mut linebreak = false;
        for (n, c) in self.word.iter().enumerate() {
            if n % LINE_WIDTH == 0 {
                linebreak = true
            };
            if n == 0 {
                linebreak = false
            };
            if linebreak && (c.char_ == ' ') {
                linebreak = false;
                writeln!(f, " {}", c)?
            } else {
                write!(f, " {}", c)?
            }
        }
        writeln!(f)
    }
}
// ***********************

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

    /// Play simulation
    #[test]
    fn test_game_simulation() {
        let mut game = Game::new("_ab _cd", 2);
        //println!("{:?}",game);
        let expected = Game {
            word: [
                HangmanChar {
                    char_: 'a',
                    visible: true,
                },
                HangmanChar {
                    char_: 'b',
                    visible: true,
                },
                HangmanChar {
                    char_: ' ',
                    visible: true,
                },
                HangmanChar {
                    char_: 'c',
                    visible: false,
                },
                HangmanChar {
                    char_: 'd',
                    visible: false,
                },
            ]
            .to_vec(),
            lives: 2,
            last_guess: ' ',
        };

        assert!(game == expected);
        assert!(game.get_state() == State::Ongoing);

        // now we guess right
        game.guess('c');
        //println!("{:?}",game);
        let expected = Game {
            word: [
                HangmanChar {
                    char_: 'a',
                    visible: true,
                },
                HangmanChar {
                    char_: 'b',
                    visible: true,
                },
                HangmanChar {
                    char_: ' ',
                    visible: true,
                },
                HangmanChar {
                    char_: 'c',
                    visible: true,
                },
                HangmanChar {
                    char_: 'd',
                    visible: false,
                },
            ]
            .to_vec(),
            lives: 2,
            last_guess: 'c',
        };

        assert!(game == expected);
        assert!(game.get_state() == State::Ongoing);

        // now we guess wrong
        game.guess('x');
        //println!("{:?}",game);
        let expected = Game {
            word: [
                HangmanChar {
                    char_: 'a',
                    visible: true,
                },
                HangmanChar {
                    char_: 'b',
                    visible: true,
                },
                HangmanChar {
                    char_: ' ',
                    visible: true,
                },
                HangmanChar {
                    char_: 'c',
                    visible: true,
                },
                HangmanChar {
                    char_: 'd',
                    visible: false,
                },
            ]
            .to_vec(),
            lives: 1,
            last_guess: 'x',
        };

        assert!(game == expected);
        assert!(game.get_state() == State::Ongoing);

        // we guess wrong again and we loose
        game.guess('y');
        //println!("{:?}",game);
        let expected = Game {
            word: [
                HangmanChar {
                    char_: 'a',
                    visible: true,
                },
                HangmanChar {
                    char_: 'b',
                    visible: true,
                },
                HangmanChar {
                    char_: ' ',
                    visible: true,
                },
                HangmanChar {
                    char_: 'c',
                    visible: true,
                },
                HangmanChar {
                    char_: 'd',
                    visible: true,
                },
            ]
            .to_vec(),
            lives: 0,
            last_guess: 'y',
        };

        assert!(game == expected);
        assert!(game.get_state() == State::Defeat);
    }
}
<|endoftext|>


<commit_before>
use std::error::Error;
use std::fmt::{self,Display,Formatter};
use std::default::Default;

use libc::{c_int,c_ulong};

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult,DeviceError};

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

pub mod caps;

#[allow(dead_code,non_camel_case_types,non_snake_case)]
pub mod properties {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/frontend-properties.rs"));
}

pub struct Frontend {
    device: DeviceFileDescriptor
}

impl Frontend {
    pub fn open(filename: &str, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Frontend> {
        let device = try!(DeviceFileDescriptor::open(filename, rw_mode, block_mode));
        Ok(Frontend { device: device })
    }

    pub fn get_info(&self) -> DeviceResult<FrontendInfo> {
        unimplemented!();
    }
    pub fn read_status(&self) -> DeviceResult<FrontendStatus> {
        let mut ffi_status: ffi::Enum_fe_status = 0;
        try!(self.device.ioctl_pointer(ffi::FE_READ_STATUS as c_ulong, &mut ffi_status));
        Ok(FrontendStatus {
            has_signal: ffi_status & ffi::FE_HAS_SIGNAL != 0,
            has_carrier: ffi_status & ffi::FE_HAS_CARRIER != 0,
            has_viterbi: ffi_status & ffi::FE_HAS_VITERBI != 0,
            has_sync: ffi_status & ffi::FE_HAS_SYNC != 0,
            has_lock: ffi_status & ffi::FE_HAS_LOCK != 0,
            timedout: ffi_status & ffi::FE_TIMEDOUT != 0,
            reinit: ffi_status & ffi::FE_REINIT != 0,
        })
    }
    pub fn set_properties(&self, properties: &[properties::SetPropertyValue]) -> DeviceResult<()> {
        unimplemented!();
    }
    pub fn get_properties(&self, properties: &[properties::GetProperty]) -> PropertyResult<Vec<properties::GetPropertyValue>> {
        unimplemented!();
    }

    pub fn diseqc_reset_overload(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::FE_DISEQC_RESET_OVERLOAD as c_ulong)
    }

    pub fn diseqc_send_master_cmd(&self, command: DiseqcMasterCommand) -> DeviceResult<()> {
        let mut ffi_cmd = ffi::Struct_dvb_diseqc_master_cmd {
            msg: command.msg,
            msg_len: command.msg_len
        };
        self.device.ioctl_pointer(ffi::FE_DISEQC_SEND_MASTER_CMD as c_ulong, &mut ffi_cmd)
    }

    /// The timeout parameter is not used by most drivers. (2015-06-17)
    pub fn diseqc_recv_slave_reply(&self, timeout: u32) -> DeviceResult<DiseqcSlaveReply> {
        let mut ffi_reply: ffi::Struct_dvb_diseqc_slave_reply = Default::default();
        ffi_reply.timeout = timeout as c_int;
        try!(self.device.ioctl_pointer(ffi::FE_DISEQC_RECV_SLAVE_REPLY as c_ulong, &mut ffi_reply));
        Ok(DiseqcSlaveReply {
            msg: ffi_reply.msg,
            msg_len: ffi_reply.msg_len
        })
    }

    pub fn diseqc_send_burst(&self, command: SecMiniCmd) -> DeviceResult<()> {
        let mut command = match command {
            SecMiniCmd::A => ffi::SEC_MINI_A,
            SecMiniCmd::B => ffi::SEC_MINI_B
        };
        self.device.ioctl_pointer(ffi::FE_DISEQC_SEND_BURST as c_ulong, &mut command)
    }

    pub fn set_tone(&self, tone: SecToneMode) -> DeviceResult<()> {
        let mut tone = match tone {
            SecToneMode::On => ffi::SEC_TONE_ON,
            SecToneMode::Off => ffi::SEC_TONE_OFF
        };
        self.device.ioctl_pointer(ffi::FE_SET_TONE as c_ulong, &mut tone)
    }

    pub fn set_voltage(&self, voltage: properties::Voltage) -> DeviceResult<()> {
        let voltage = match voltage {
            properties::Voltage::SecVoltage13 => ffi::SEC_VOLTAGE_13,
            properties::Voltage::SecVoltage18 => ffi::SEC_VOLTAGE_18,
            properties::Voltage::SecVoltageOff => ffi::SEC_VOLTAGE_OFF,
        };
        self.device.ioctl_value(ffi::FE_SET_VOLTAGE as c_ulong, voltage)
    }

    pub fn enable_high_lnb_voltage(&self, high: u32) -> DeviceResult<()> {
        self.device.ioctl_value(ffi::FE_ENABLE_HIGH_LNB_VOLTAGE as c_ulong, high)
    }

    pub fn set_frontend_tune_mode(&self, tune_mode: TuneMode) -> DeviceResult<()> {
        let value = match tune_mode {
            TuneMode::Normal => 0,
            TuneMode::OneShot => ffi::FE_TUNE_MODE_ONESHOT
        };
        self.device.ioctl_value(ffi::FE_SET_FRONTEND_TUNE_MODE as c_ulong, value)
    }
}

#[derive(Clone,Debug)]
pub struct FrontendInfo {
    pub name: String,
    pub frequency_min: u32,
    pub frequency_max: u32,
    pub frequency_stepsize: u32,
    pub frequency_tolerance: u32,
    pub symbol_rate_min: u32,
    pub symbol_rate_max: u32,
    pub symbol_rate_tolerance: u32,
    pub caps: caps::FrontendCaps,
}

pub struct FrontendStatus {
    pub has_signal: bool,
    pub has_carrier: bool,
    pub has_viterbi: bool,
    pub has_sync: bool,
    pub has_lock: bool,
    pub timedout: bool,
    pub reinit: bool
}

pub struct DiseqcSlaveReply {
    pub msg: [u8; 4],
    pub msg_len: u8
}

pub struct DiseqcMasterCommand {
    pub msg: [u8; 6],
    pub msg_len: u8
}

pub enum SecMiniCmd {
    A,
    B
}

pub enum SecToneMode {
    On,
    Off
}

pub enum TuneMode {
    Normal,
    OneShot
}

pub type PropertyResult<T> = Result<T, PropertyError>;

#[derive(Clone,Debug)]
pub enum PropertyError {
    DeviceError(DeviceError),
    PropertyMappingError(properties::PropertyMappingError)
}

impl Error for PropertyError {
    fn description(&self) -> &str {
        match *self {
            PropertyError::DeviceError(ref err) => err.description(),
            PropertyError::PropertyMappingError(ref err) => err.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            PropertyError::DeviceError(ref err) => Some(err),
            PropertyError::PropertyMappingError(ref err) => Some(err)
        }
    }
}

impl Display for PropertyError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "PropertyError: {}", self.description())
    }
}<commit_msg>Add several derive(Copy,Clone,Debug) annotations.<commit_after>
use std::error::Error;
use std::fmt::{self,Display,Formatter};
use std::default::Default;

use libc::{c_int,c_ulong};

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult,DeviceError};

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

pub mod caps;

#[allow(dead_code,non_camel_case_types,non_snake_case)]
pub mod properties {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/frontend-properties.rs"));
}

pub struct Frontend {
    device: DeviceFileDescriptor
}

impl Frontend {
    pub fn open(filename: &str, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Frontend> {
        let device = try!(DeviceFileDescriptor::open(filename, rw_mode, block_mode));
        Ok(Frontend { device: device })
    }

    pub fn get_info(&self) -> DeviceResult<FrontendInfo> {
        unimplemented!();
    }
    pub fn read_status(&self) -> DeviceResult<FrontendStatus> {
        let mut ffi_status: ffi::Enum_fe_status = 0;
        try!(self.device.ioctl_pointer(ffi::FE_READ_STATUS as c_ulong, &mut ffi_status));
        Ok(FrontendStatus {
            has_signal: ffi_status & ffi::FE_HAS_SIGNAL != 0,
            has_carrier: ffi_status & ffi::FE_HAS_CARRIER != 0,
            has_viterbi: ffi_status & ffi::FE_HAS_VITERBI != 0,
            has_sync: ffi_status & ffi::FE_HAS_SYNC != 0,
            has_lock: ffi_status & ffi::FE_HAS_LOCK != 0,
            timedout: ffi_status & ffi::FE_TIMEDOUT != 0,
            reinit: ffi_status & ffi::FE_REINIT != 0,
        })
    }
    pub fn set_properties(&self, properties: &[properties::SetPropertyValue]) -> DeviceResult<()> {
        unimplemented!();
    }
    pub fn get_properties(&self, properties: &[properties::GetProperty]) -> PropertyResult<Vec<properties::GetPropertyValue>> {
        unimplemented!();
    }

    pub fn diseqc_reset_overload(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::FE_DISEQC_RESET_OVERLOAD as c_ulong)
    }

    pub fn diseqc_send_master_cmd(&self, command: DiseqcMasterCommand) -> DeviceResult<()> {
        let mut ffi_cmd = ffi::Struct_dvb_diseqc_master_cmd {
            msg: command.msg,
            msg_len: command.msg_len
        };
        self.device.ioctl_pointer(ffi::FE_DISEQC_SEND_MASTER_CMD as c_ulong, &mut ffi_cmd)
    }

    /// The timeout parameter is not used by most drivers. (2015-06-17)
    pub fn diseqc_recv_slave_reply(&self, timeout: u32) -> DeviceResult<DiseqcSlaveReply> {
        let mut ffi_reply: ffi::Struct_dvb_diseqc_slave_reply = Default::default();
        ffi_reply.timeout = timeout as c_int;
        try!(self.device.ioctl_pointer(ffi::FE_DISEQC_RECV_SLAVE_REPLY as c_ulong, &mut ffi_reply));
        Ok(DiseqcSlaveReply {
            msg: ffi_reply.msg,
            msg_len: ffi_reply.msg_len
        })
    }

    pub fn diseqc_send_burst(&self, command: SecMiniCmd) -> DeviceResult<()> {
        let mut command = match command {
            SecMiniCmd::A => ffi::SEC_MINI_A,
            SecMiniCmd::B => ffi::SEC_MINI_B
        };
        self.device.ioctl_pointer(ffi::FE_DISEQC_SEND_BURST as c_ulong, &mut command)
    }

    pub fn set_tone(&self, tone: SecToneMode) -> DeviceResult<()> {
        let mut tone = match tone {
            SecToneMode::On => ffi::SEC_TONE_ON,
            SecToneMode::Off => ffi::SEC_TONE_OFF
        };
        self.device.ioctl_pointer(ffi::FE_SET_TONE as c_ulong, &mut tone)
    }

    pub fn set_voltage(&self, voltage: properties::Voltage) -> DeviceResult<()> {
        let voltage = match voltage {
            properties::Voltage::SecVoltage13 => ffi::SEC_VOLTAGE_13,
            properties::Voltage::SecVoltage18 => ffi::SEC_VOLTAGE_18,
            properties::Voltage::SecVoltageOff => ffi::SEC_VOLTAGE_OFF,
        };
        self.device.ioctl_value(ffi::FE_SET_VOLTAGE as c_ulong, voltage)
    }

    pub fn enable_high_lnb_voltage(&self, high: u32) -> DeviceResult<()> {
        self.device.ioctl_value(ffi::FE_ENABLE_HIGH_LNB_VOLTAGE as c_ulong, high)
    }

    pub fn set_frontend_tune_mode(&self, tune_mode: TuneMode) -> DeviceResult<()> {
        let value = match tune_mode {
            TuneMode::Normal => 0,
            TuneMode::OneShot => ffi::FE_TUNE_MODE_ONESHOT
        };
        self.device.ioctl_value(ffi::FE_SET_FRONTEND_TUNE_MODE as c_ulong, value)
    }
}

#[derive(Clone,Debug)]
pub struct FrontendInfo {
    pub name: String,
    pub frequency_min: u32,
    pub frequency_max: u32,
    pub frequency_stepsize: u32,
    pub frequency_tolerance: u32,
    pub symbol_rate_min: u32,
    pub symbol_rate_max: u32,
    pub symbol_rate_tolerance: u32,
    pub caps: caps::FrontendCaps,
}

#[derive(Copy,Clone,Debug)]
pub struct FrontendStatus {
    pub has_signal: bool,
    pub has_carrier: bool,
    pub has_viterbi: bool,
    pub has_sync: bool,
    pub has_lock: bool,
    pub timedout: bool,
    pub reinit: bool
}

#[derive(Copy,Clone,Debug)]
pub struct DiseqcSlaveReply {
    pub msg: [u8; 4],
    pub msg_len: u8
}

#[derive(Copy,Clone,Debug)]
pub struct DiseqcMasterCommand {
    pub msg: [u8; 6],
    pub msg_len: u8
}

#[derive(Copy,Clone,Debug)]
pub enum SecMiniCmd {
    A,
    B
}

#[derive(Copy,Clone,Debug)]
pub enum SecToneMode {
    On,
    Off
}

#[derive(Copy,Clone,Debug)]
pub enum TuneMode {
    Normal,
    OneShot
}

pub type PropertyResult<T> = Result<T, PropertyError>;

#[derive(Clone,Debug)]
pub enum PropertyError {
    DeviceError(DeviceError),
    PropertyMappingError(properties::PropertyMappingError)
}

impl Error for PropertyError {
    fn description(&self) -> &str {
        match *self {
            PropertyError::DeviceError(ref err) => err.description(),
            PropertyError::PropertyMappingError(ref err) => err.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            PropertyError::DeviceError(ref err) => Some(err),
            PropertyError::PropertyMappingError(ref err) => Some(err)
        }
    }
}

impl Display for PropertyError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "PropertyError: {}", self.description())
    }
}<|endoftext|>


<commit_before>use time::Timespec;

pub const DEFAULT_BLOCKS_COUNT: u64 = 1;

pub const DEFAULT_CREATE_TIME: Timespec = Timespec {
    sec: 1381237736,
    nsec: 0,
};

pub const FEATURE_FLAGS_JSON_FILENAME: &'static str = "featureFlags.json";
pub const PERMISSIONS_JSON_FILENAME: &'static str = "permissions.json";
pub const PROJECT_JSON_FILENAME: &'static str = "project.json";
pub const PROJECTS_JSON_FILENAME: &'static str = "projects.json";
pub const ROLES_JSON_FILENAME: &'static str = "roles.json";

pub const DEFAULT_DIRECTORY_PERMISSIONS: u16 = 0o755;

pub const DEFAULT_FILE_PERMISSIONS: u16 = 0o444;

pub const DEFAULT_FLAGS: u32 = 0;

pub const DEFAULT_NLINKE_COUNT: u32 = 0;

pub const DEFAULT_RDEV: u32 = 0;

pub const DEFAULT_SIZE: u64 = 0;

pub const DEFAULT_TTL: Timespec = Timespec { sec: 1, nsec: 0 };
<commit_msg>Remove empty line<commit_after>use time::Timespec;

pub const DEFAULT_BLOCKS_COUNT: u64 = 1;

pub const DEFAULT_CREATE_TIME: Timespec = Timespec {
    sec: 1381237736,
    nsec: 0,
};

pub const FEATURE_FLAGS_JSON_FILENAME: &'static str = "featureFlags.json";
pub const PERMISSIONS_JSON_FILENAME: &'static str = "permissions.json";
pub const PROJECT_JSON_FILENAME: &'static str = "project.json";
pub const PROJECTS_JSON_FILENAME: &'static str = "projects.json";
pub const ROLES_JSON_FILENAME: &'static str = "roles.json";

pub const DEFAULT_DIRECTORY_PERMISSIONS: u16 = 0o755;

pub const DEFAULT_FILE_PERMISSIONS: u16 = 0o444;

pub const DEFAULT_FLAGS: u32 = 0;

pub const DEFAULT_NLINKE_COUNT: u32 = 0;

pub const DEFAULT_RDEV: u32 = 0;

pub const DEFAULT_SIZE: u64 = 0;

pub const DEFAULT_TTL: Timespec = Timespec { sec: 1, nsec: 0 };
<|endoftext|>


<commit_before>use curl;
use oauth2::*;
use app::App;
use util::{CargoResult, internal, ChainError, human};
use rustc_serialize::{json, Decodable};
use std::str;

/// Does all the nonsense for sending a GET to Github. Doesn't handle parsing
/// because custom error-code handling may be desirable. Use
/// parse_github_response to handle the "common" processing of responses.
pub fn github(app: &App, url: &str, auth: &Token)
              -> Result<curl::http::Response, curl::ErrCode>
{
    let url = format!("{}://api.github.com{}", app.config.api_protocol(), url);
    info!("GITHUB HTTP: {}", url);

    app.handle()
       .get(url)
       .header("Accept", "application/vnd.github.v3+json")
       .header("User-Agent", "hello!")
       .auth_with(auth)
       .exec()
}

/// Checks for normal responses
pub fn parse_github_response<T: Decodable>(resp: curl::http::Response)
                                            -> CargoResult<T> {
    match resp.get_code() {
        200 => {} // Ok!
        403 => {
            return Err(human("It looks like you don't have permission \
                              to query a necessary property from Github
                              to complete this request. \
                              You may need to re-authenticate on \
                              crates.io to grant permission to read \
                              github org memberships. Just go to \
                              https://crates.io/login"));
        }
        _ => {
            return Err(internal(format!("didn't get a 200 result from
                                        github: {}", resp)));
        }
    }

    let json = try!(str::from_utf8(resp.get_body()).ok().chain_error(||{
        internal("github didn't send a utf8-response")
    }));

    json::decode(json).chain_error(|| {
        internal("github didn't send a valid json response")
    })
}

/// Gets a token with the given string as the access token, but all
/// other info null'd out. Generally, just to be fed to the `github` fn.
pub fn token(token: String) -> Token {
    Token {
        access_token: token,
        scopes: Vec::new(),
        token_type: String::new(),
    }
}
<commit_msg>fix missing escape<commit_after>use curl;
use oauth2::*;
use app::App;
use util::{CargoResult, internal, ChainError, human};
use rustc_serialize::{json, Decodable};
use std::str;

/// Does all the nonsense for sending a GET to Github. Doesn't handle parsing
/// because custom error-code handling may be desirable. Use
/// parse_github_response to handle the "common" processing of responses.
pub fn github(app: &App, url: &str, auth: &Token)
              -> Result<curl::http::Response, curl::ErrCode>
{
    let url = format!("{}://api.github.com{}", app.config.api_protocol(), url);
    info!("GITHUB HTTP: {}", url);

    app.handle()
       .get(url)
       .header("Accept", "application/vnd.github.v3+json")
       .header("User-Agent", "hello!")
       .auth_with(auth)
       .exec()
}

/// Checks for normal responses
pub fn parse_github_response<T: Decodable>(resp: curl::http::Response)
                                            -> CargoResult<T> {
    match resp.get_code() {
        200 => {} // Ok!
        403 => {
            return Err(human("It looks like you don't have permission \
                              to query a necessary property from Github \
                              to complete this request. \
                              You may need to re-authenticate on \
                              crates.io to grant permission to read \
                              github org memberships. Just go to \
                              https://crates.io/login"));
        }
        _ => {
            return Err(internal(format!("didn't get a 200 result from
                                        github: {}", resp)));
        }
    }

    let json = try!(str::from_utf8(resp.get_body()).ok().chain_error(||{
        internal("github didn't send a utf8-response")
    }));

    json::decode(json).chain_error(|| {
        internal("github didn't send a valid json response")
    })
}

/// Gets a token with the given string as the access token, but all
/// other info null'd out. Generally, just to be fed to the `github` fn.
pub fn token(token: String) -> Token {
    Token {
        access_token: token,
        scopes: Vec::new(),
        token_type: String::new(),
    }
}
<|endoftext|>


<commit_before>use conduit::{Request, Response};
use conduit_middleware::Middleware;
use curl;
use curl::easy::{Easy, List};
use oauth2::*;
use app::App;
use util::{CargoResult, internal, ChainError, human};
use serde_json;
use serde::Deserialize;
use std::str;
use std::error::Error;

/// Does all the nonsense for sending a GET to Github. Doesn't handle parsing
/// because custom error-code handling may be desirable. Use
/// `parse_github_response` to handle the "common" processing of responses.
pub fn github(app: &App, url: &str, auth: &Token) -> Result<(Easy, Vec<u8>), curl::Error> {
    let url = format!("{}://api.github.com{}", app.config.api_protocol, url);
    info!("GITHUB HTTP: {}", url);

    let mut headers = List::new();
    headers
        .append("Accept: application/vnd.github.v3+json")
        .unwrap();
    headers.append("User-Agent: hello!").unwrap();
    headers
        .append(&format!("Authorization: token {}", auth.access_token))
        .unwrap();

    let mut handle = app.handle();
    handle.url(&url).unwrap();
    handle.get(true).unwrap();
    handle.http_headers(headers).unwrap();

    let mut data = Vec::new();
    {
        let mut transfer = handle.transfer();
        transfer
            .write_function(|buf| {
                data.extend_from_slice(buf);
                Ok(buf.len())
            })
            .unwrap();
        transfer.perform()?;
    }
    Ok((handle, data))
}

/// Checks for normal responses
pub fn parse_github_response<'de, 'a: 'de, T: Deserialize<'de>>(
    mut resp: Easy,
    data: &'a [u8],
) -> CargoResult<T> {
    match resp.response_code().unwrap() {
        200 => {} // Ok!
        403 => {
            return Err(human(
                "It looks like you don't have permission \
                 to query a necessary property from Github \
                 to complete this request. \
                 You may need to re-authenticate on \
                 crates.io to grant permission to read \
                 github org memberships. Just go to \
                 https://crates.io/login",
            ));
        }
        n => {
            let resp = String::from_utf8_lossy(data);
            return Err(internal(&format_args!(
                "didn't get a 200 result from \
                 github, got {} with: {}",
                n,
                resp
            )));
        }
    }

    let json = str::from_utf8(data).ok().chain_error(|| {
        internal("github didn't send a utf8-response")
    })?;

    serde_json::from_str(json).chain_error(|| internal("github didn't send a valid json response"))
}

/// Gets a token with the given string as the access token, but all
/// other info null'd out. Generally, just to be fed to the `github` fn.
pub fn token(token: String) -> Token {
    Token {
        access_token: token,
        scopes: Vec::new(),
        token_type: String::new(),
    }
}

#[derive(Clone, Copy, Debug)]
pub struct SecurityHeadersMiddleware;

impl Middleware for SecurityHeadersMiddleware {
    fn after(
        &self,
        _: &mut Request,
        mut res: Result<Response, Box<Error + Send>>,
    ) -> Result<Response, Box<Error + Send>> {
        if let Ok(ref mut response) = res {
            response.headers.insert(
                "Content-Security-Policy".into(),
                vec![
                    "default-src 'self'; \
                      script-src 'self' https://www.google-analytics.com https://www.google.com; \
                      style-src 'self' https://www.google.com; \
                      img-src *; \
                      object-src 'none'"
                        .into(),
                ],
            );
            response.headers.insert(
                "X-Content-Type-Options".into(),
                vec!["nosniff".into()],
            );
            response.headers.insert(
                "X-Frame-Options".into(),
                vec!["SAMEORIGIN".into()],
            );
            response.headers.insert(
                "X-XSS-Protection".into(),
                vec!["1; mode=block".into()],
            );
        }
        res
    }
}
<commit_msg>Allow docs.rs to make ajax requests<commit_after>use conduit::{Request, Response};
use conduit_middleware::Middleware;
use curl;
use curl::easy::{Easy, List};
use oauth2::*;
use app::App;
use util::{CargoResult, internal, ChainError, human};
use serde_json;
use serde::Deserialize;
use std::str;
use std::error::Error;

/// Does all the nonsense for sending a GET to Github. Doesn't handle parsing
/// because custom error-code handling may be desirable. Use
/// `parse_github_response` to handle the "common" processing of responses.
pub fn github(app: &App, url: &str, auth: &Token) -> Result<(Easy, Vec<u8>), curl::Error> {
    let url = format!("{}://api.github.com{}", app.config.api_protocol, url);
    info!("GITHUB HTTP: {}", url);

    let mut headers = List::new();
    headers
        .append("Accept: application/vnd.github.v3+json")
        .unwrap();
    headers.append("User-Agent: hello!").unwrap();
    headers
        .append(&format!("Authorization: token {}", auth.access_token))
        .unwrap();

    let mut handle = app.handle();
    handle.url(&url).unwrap();
    handle.get(true).unwrap();
    handle.http_headers(headers).unwrap();

    let mut data = Vec::new();
    {
        let mut transfer = handle.transfer();
        transfer
            .write_function(|buf| {
                data.extend_from_slice(buf);
                Ok(buf.len())
            })
            .unwrap();
        transfer.perform()?;
    }
    Ok((handle, data))
}

/// Checks for normal responses
pub fn parse_github_response<'de, 'a: 'de, T: Deserialize<'de>>(
    mut resp: Easy,
    data: &'a [u8],
) -> CargoResult<T> {
    match resp.response_code().unwrap() {
        200 => {} // Ok!
        403 => {
            return Err(human(
                "It looks like you don't have permission \
                 to query a necessary property from Github \
                 to complete this request. \
                 You may need to re-authenticate on \
                 crates.io to grant permission to read \
                 github org memberships. Just go to \
                 https://crates.io/login",
            ));
        }
        n => {
            let resp = String::from_utf8_lossy(data);
            return Err(internal(&format_args!(
                "didn't get a 200 result from \
                 github, got {} with: {}",
                n,
                resp
            )));
        }
    }

    let json = str::from_utf8(data).ok().chain_error(|| {
        internal("github didn't send a utf8-response")
    })?;

    serde_json::from_str(json).chain_error(|| internal("github didn't send a valid json response"))
}

/// Gets a token with the given string as the access token, but all
/// other info null'd out. Generally, just to be fed to the `github` fn.
pub fn token(token: String) -> Token {
    Token {
        access_token: token,
        scopes: Vec::new(),
        token_type: String::new(),
    }
}

#[derive(Clone, Copy, Debug)]
pub struct SecurityHeadersMiddleware;

impl Middleware for SecurityHeadersMiddleware {
    fn after(
        &self,
        _: &mut Request,
        mut res: Result<Response, Box<Error + Send>>,
    ) -> Result<Response, Box<Error + Send>> {
        if let Ok(ref mut response) = res {
            response.headers.insert(
                "Content-Security-Policy".into(),
                vec![
                    "default-src 'self'; \
                      connect-src 'self' https://docs.rs; \
                      script-src 'self' https://www.google-analytics.com https://www.google.com; \
                      style-src 'self' https://www.google.com; \
                      img-src *; \
                      object-src 'none'"
                        .into(),
                ],
            );
            response.headers.insert(
                "X-Content-Type-Options".into(),
                vec!["nosniff".into()],
            );
            response.headers.insert(
                "X-Frame-Options".into(),
                vec!["SAMEORIGIN".into()],
            );
            response.headers.insert(
                "X-XSS-Protection".into(),
                vec!["1; mode=block".into()],
            );
        }
        res
    }
}
<|endoftext|>