<commit_before>use core::hashmap::linear::LinearMap;
use core::str::raw::from_c_str;
use core::str::from_bytes;
use core::vec::const_slice;
use core::cast::transmute;

// Available Result values
enum Result {
  Document(~BsonElement),
  ParseError(bool)
}

// Available Bson Element types
enum BsonElement {
  Int32(i32),
  Int64(i64),
  String(@str),
  Object(@mut LinearMap<~str, ~BsonElement>),
}

struct BsonParser;
struct ParserState {
  index: u32,
  document: @BsonElement
}

impl BsonParser {
  fn deserialize(&self, data: &[u8]) -> @Result {
    // Get the initial state of the parsing
    let size = data[0] as u32;
    // Return an error if we the sizes of the message are not the same
    if size != data.len() as u32 {
      // return @ParseError {error: true} as @Result;
      return @ParseError(true);
    }

    // If we have zero elements (special case)
    if(size == 5) {
      return @Document(~Object(@mut LinearMap::new()));
    }

    // Parse the document
    let object = BsonParser::deserialize_loop(data, @mut 0i64);
    // return the document
    @Document(object)
  }

  fn deserialize_loop(data: &[u8], index: &mut i64) -> ~BsonElement {
    // Create an empty object
    let object: ~BsonElement = ~Object(@mut LinearMap::new());
    // Decode the document size
    let size = data[*index] as u32;
    // Adjust the location of the index
    *index = *index + 4;
    // Loop until we are done
    loop {
      // Get bson type
      let bson_type = data[*index];
      // Adjust to name of the field
      *index += 1;
      // If type is 0x00 we are done
      if bson_type == 0x00 {
        break;
      }

      // Decode the name from the cstring
      let name = BsonParser::extract_string(*index, data);
      // Adjust the index to point to the data
      *index += name.len() as i64 + 1;

      // Access the internal map
      match object {
        ~Object(map) => {
          match bson_type as u8 {
            0x02 => {
                map.insert(name, BsonParser::parseString(index, data));
              },
            0x10 => {
                map.insert(name, BsonParser::parseInt32(index, data));
              },
            0x12 => {
                map.insert(name, BsonParser::parseInt64(index, data));
              },
            0x03 => {
                // Create a new object
                let new_object = BsonParser::deserialize_loop(data, index);
                // Add to the map
                map.insert(name, new_object);
              }
            _ => ()
          }
        }
        _ => ()
      };
    }

    object
  }

  fn extract_string(index:i64, data: &[u8]) -> ~str {
    unsafe {
      let data2: &[i8] = transmute(data);
      // Unpack the name of the field
      from_c_str(&data2[index])
    }
  }

  fn parseString(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // unpack the string size
    let size:u32 = data[*index] as u32;
    // Adjust the index
    *index = *index + 4;
    // unpack the data as a string
    let string = from_bytes(const_slice(data, *index as uint, (*index + (size - 1) as i64) as uint)).to_managed();
    // return string
    ~String(string)
  }

  fn parseInt32(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // Unpack the i32 value
    let value = ~Int32(data[*index] as i32);
    // Adjust index
    *index += 4;
    // Return the value
    value
  }

  fn parseInt64(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // Unpack the i32 value
    let value = ~Int64(data[*index] as i64);
    // Adjust index
    *index += 8;
    // Return the value
    value
  }
}

/**
 * Tests
 */
#[test]
fn simple_int32_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int32(number)) => {
        assert_eq!(number, 1);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn simple_string_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x18, 0x00, 0x00, 0x00, 0x02, 0x61, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~String(final)) => {
        assert_eq!(final, @"hello world");
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn simple_int64_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x10, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int64(number)) => {
        assert_eq!(number, 2);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn two_value_document_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x17, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int64(number)) => assert_eq!(number, 2),
      _ => ()
    }

    match map.find(&~"b") {
      Some(&~Int32(number)) => assert_eq!(number, 1),
      _ => ()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn sub_document_test() {
  // {a:{b:1}, c:2}
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x1b, 0x00, 0x00, 0x00, 0x03, 0x61, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00]);

  // Validate the result
  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Object(object_map)) => {

        // Locate the internal object
        match object_map.find(&~"b") {
          Some(&~Int32(number)) => {
            assert_eq!(number, 1);
          },
          _ => fail!()
        }
      }
      _ => fail!()
    }

    match map.find(&~"c") {
      Some(&~Int32(number)) => {
        assert_eq!(number, 2);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}<commit_msg>Serialized int32 value<commit_after>use core::hashmap::linear::LinearMap;
use core::str::raw::from_c_str;
use core::str::from_bytes;
use core::vec::const_slice;
use core::cast::transmute;
use core::vec::bytes::copy_memory;
use core::vec::mut_slice;

// Available Result values
enum Result {
  Document(~BsonElement),
  ParseError(bool)
}

// BsonTypes
enum BsonTypes {
  BsonInt32 = 0x10
}

// Available Bson Element types
enum BsonElement {
  Int32(i32),
  Int64(i64),
  String(@str),
  Object(@mut LinearMap<~str, ~BsonElement>),
}

struct BsonParser;
struct ParserState {
  index: u32,
  document: @BsonElement
}

impl BsonParser {
  fn serialize(&self, object: &BsonElement) -> ~[u8] {
    // Calculate size of final object
    let size = BsonParser::calculateSize(object);
    // Allocate a vector
    let mut data:~[u8] = vec::from_elem(size, 0);
    // Write the data to the vector
    data[3] = ((size >> 24) & 0xff) as u8;
    data[2] = ((size >> 16) & 0xff) as u8;
    data[1] = ((size >> 8) & 0xff) as u8;
    data[0] = (size & 0xff) as u8;
    // Starting index
    let mut index = 4;
    // io::println(fmt!("==== vector :: %?", data));

    // Current index
    // Unpack the object
    match object {
      &Object(map) => {
        // io::println("deserialize Object");

        // Get each key
        for map.each_key |k| {
          // Let's figure out what type of object we have
          match map.find(k) {
            Some(&~Int32(number)) => {
              // Set the data type
              data[index] = BsonInt32 as u8;
              // Adjust index
              index += 1;

              // Copy the field value name to the vector
              copy_memory(mut_slice(data, index, size), k.to_bytes(), k.len());

              // Adjust the index position
              index += k.len() + 1;

              // io::println("========= INT32");
              data[index + 3] = ((number >> 24) & 0xff) as u8;
              data[index + 2] = ((number >> 16) & 0xff) as u8;
              data[index + 1] = ((number >> 8) & 0xff) as u8;
              data[index] = (number & 0xff) as u8;
              index += 4;
            }
            _ => ()
          }
        }

        // io::println(fmt!("==== vector :: %?", data));
      }
      _ => ()
    }

    data
  }

  fn serialize_object(object: &BsonElement) {

  }

  fn calculateSize(object: &BsonElement) -> uint {
    let mut size:uint = 0;

    // Unpack the object
    match object {
      &Object(map) => {
        // Add the header and tail of the document
        size += 5;
        // Iterate over all the fields
        for map.each_key |k| {
          // String length + 0 terminating byte + type
          size += k.len() as uint + 1 + 1;
          // Match the key
          size += match map.find(k) {
            Some(&~Int32(_)) => 4,
            Some(&~Int64(_)) => 8,
            _ => 0
          };
        };
      },
      _ => ()
    }

    size
  }

  fn deserialize(&self, data: &[u8]) -> @Result {
    // Get the initial state of the parsing
    let size = data[0] as u32;
    // Return an error if we the sizes of the message are not the same
    if size != data.len() as u32 {
      // return @ParseError {error: true} as @Result;
      return @ParseError(true);
    }

    // If we have zero elements (special case)
    if(size == 5) {
      return @Document(~Object(@mut LinearMap::new()));
    }

    // Parse the document
    let object = BsonParser::deserialize_loop(data, @mut 0i64);
    // return the document
    @Document(object)
  }

  fn deserialize_loop(data: &[u8], index: &mut i64) -> ~BsonElement {
    // Create an empty object
    let object: ~BsonElement = ~Object(@mut LinearMap::new());
    // Decode the document size
    let size = data[*index] as u32;
    // Adjust the location of the index
    *index = *index + 4;
    // Loop until we are done
    loop {
      // Get bson type
      let bson_type = data[*index];
      // Adjust to name of the field
      *index += 1;
      // If type is 0x00 we are done
      if bson_type == 0x00 {
        break;
      }

      // Decode the name from the cstring
      let name = BsonParser::extract_string(*index, data);
      // Adjust the index to point to the data
      *index += name.len() as i64 + 1;

      // Access the internal map
      match object {
        ~Object(map) => {
          match bson_type as u8 {
            0x02 => {
                map.insert(name, BsonParser::parseString(index, data));
              },
            0x10 => {
                map.insert(name, BsonParser::parseInt32(index, data));
              },
            0x12 => {
                map.insert(name, BsonParser::parseInt64(index, data));
              },
            0x03 => {
                // Create a new object
                let new_object = BsonParser::deserialize_loop(data, index);
                // Add to the map
                map.insert(name, new_object);
              }
            _ => ()
          }
        }
        _ => ()
      };
    }

    object
  }

  fn extract_string(index:i64, data: &[u8]) -> ~str {
    unsafe {
      let data2: &[i8] = transmute(data);
      // Unpack the name of the field
      from_c_str(&data2[index])
    }
  }

  fn parseString(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // unpack the string size
    let size:u32 = data[*index] as u32;
    // Adjust the index
    *index = *index + 4;
    // unpack the data as a string
    let string = from_bytes(const_slice(data, *index as uint, (*index + (size - 1) as i64) as uint)).to_managed();
    // return string
    ~String(string)
  }

  fn parseInt32(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // Unpack the i32 value
    let value = ~Int32(data[*index] as i32);
    // Adjust index
    *index += 4;
    // Return the value
    value
  }

  fn parseInt64(index: &mut i64, data: &[u8]) -> ~BsonElement {
    // Unpack the i32 value
    let value = ~Int64(data[*index] as i64);
    // Adjust index
    *index += 8;
    // Return the value
    value
  }
}

/**
 * Tests
 */
#[test]
fn simple_int32_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int32(number)) => {
        assert_eq!(number, 1);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn simple_int32_serialize_test() {
  let parser:BsonParser = BsonParser;
  // Build a BSON object
  let map = @mut LinearMap::new();
  map.insert(~"a", ~Int32(1));
  let object:~BsonElement = ~Object(map);
  // Serialize the object
  let data = parser.serialize(object);
  // io::println(fmt!("================ data :: %?", data));
  let expectedData = ~[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00];
  assert_eq!(data, expectedData);
  // io::println(fmt!("================ data :: %?", expectedData));
  // io::println(fmt!("================ data size :: %?", expectedData.len()));
  // let o = parser.deserialize(data);

  // let result = parser.deserialize(@[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  // fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
  //   match map.find(&~"a") {
  //     Some(&~Int32(number)) => {
  //       assert_eq!(number, 1);
  //     },
  //     _ => fail!()
  //   }
  // }

  // match result {
  //   @Document(~Object(map)) => process_map(map),
  //   @Document(_) => (),
  //   @ParseError(_) => ()
  // }
}

#[test]
fn simple_string_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x18, 0x00, 0x00, 0x00, 0x02, 0x61, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~String(final)) => {
        assert_eq!(final, @"hello world");
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn simple_int64_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x10, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int64(number)) => {
        assert_eq!(number, 2);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn two_value_document_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x17, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int64(number)) => assert_eq!(number, 2),
      _ => ()
    }

    match map.find(&~"b") {
      Some(&~Int32(number)) => assert_eq!(number, 1),
      _ => ()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn sub_document_test() {
  // {a:{b:1}, c:2}
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x1b, 0x00, 0x00, 0x00, 0x03, 0x61, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00]);

  // Validate the result
  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Object(object_map)) => {

        // Locate the internal object
        match object_map.find(&~"b") {
          Some(&~Int32(number)) => {
            assert_eq!(number, 1);
          },
          _ => fail!()
        }
      }
      _ => fail!()
    }

    match map.find(&~"c") {
      Some(&~Int32(number)) => {
        assert_eq!(number, 2);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(~Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}<|endoftext|>


<commit_before>extern crate ascii;

use std::marker::PhantomData;

use self::ascii::AsciiChar;

use combinator::{Expected, ParserExt, satisfy, Satisfy, skip_many, SkipMany, token, Token, With};
use primitives::{ConsumedResult, Parser, ParseError, Stream};

/// Parses a u8acter and succeeds if the u8acter is equal to `c`
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::byte::byte;
/// # fn main() {
/// let result = byte(b'!')
///     .parse(&b"!"[..])
///     .map(|x| x.0);
/// assert_eq!(result, Ok(b'!'));
/// # }
/// ```
#[inline(always)]
pub fn byte<I>(c: u8) -> Token<I>
    where I: Stream<Item = u8>
{
    token(c)
}

impl_token_parser! { Digit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

macro_rules! byte_parser {
    ($name: ident, $ty : ident, $f : ident) => ({
        let f = static_fn!((c, u8) -> bool {
            AsciiChar::from(c).map(|c| c.$f()).unwrap_or(false)
        });
        $ty(satisfy(f).expected(stringify!($name)), PhantomData)
    })
}

/// Parses a digit from a stream containing u8acters
#[inline(always)]
pub fn digit<I>() -> Digit<I>
    where I: Stream<Item = u8>
{
    byte_parser!(digit, Digit, is_digit)
}

impl_token_parser! { Space(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

/// Parses whitespace
#[inline(always)]
pub fn space<I>() -> Space<I>
    where I: Stream<Item = u8>
{
    byte_parser!(space, Space, is_whitespace)
}

impl_token_parser! { Spaces(), u8, Expected<SkipMany<Space<I>>> }
/// Skips over zero or more spaces
#[inline(always)]
pub fn spaces<I>() -> Spaces<I>
    where I: Stream<Item = u8>
{
    Spaces(skip_many(space()).expected("whitespaces"), PhantomData)
}

impl_token_parser! { Newline(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

/// Parses a newline character
#[inline(always)]
pub fn newline<I>() -> Newline<I>
    where I: Stream<Item = u8>
{
    Newline(satisfy(static_fn!((ch, u8) -> bool { ch == b'\n' })).expected("lf newline"),
            PhantomData)
}

impl_token_parser! { CrLf(), u8, Expected<With<Satisfy<I, fn (u8) -> bool>, Newline<I>>> }

/// Parses carriage return and newline, returning the newline character.
#[inline(always)]
pub fn crlf<I>() -> CrLf<I>
    where I: Stream<Item = u8>
{
    CrLf(satisfy(static_fn!((ch, u8) -> bool { ch == b'\r' }))
             .with(newline())
             .expected("crlf newline"),
         PhantomData)
}

impl_token_parser! { Tab(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses a tab u8acter
#[inline(always)]
pub fn tab<I>() -> Tab<I>
    where I: Stream<Item = u8>
{
    Tab(satisfy(static_fn!((ch, u8) -> bool { ch == b'\t' })).expected("tab"),
        PhantomData)
}

impl_token_parser! { Upper(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an uppercase letter
#[inline(always)]
pub fn upper<I>() -> Upper<I>
    where I: Stream<Item = u8>
{
    byte_parser!(upper, Upper, is_uppercase)
}

impl_token_parser! { Lower(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an lowercase letter
#[inline(always)]
pub fn lower<I>() -> Lower<I>
    where I: Stream<Item = u8>
{
    byte_parser!(lower, Lower, is_lowercase)
}

impl_token_parser! { AlphaNum(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses either an alphabet letter or digit
#[inline(always)]
pub fn alpha_num<I>() -> AlphaNum<I>
    where I: Stream<Item = u8>
{
    byte_parser!(alpha_num, AlphaNum, is_alphanumeric)
}

impl_token_parser! { Letter(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an alphabet letter
#[inline(always)]
pub fn letter<I>() -> Letter<I>
    where I: Stream<Item = u8>
{
    byte_parser!(letter, Letter, is_alphabetic)
}

impl_token_parser! { HexDigit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses a hexdecimal digit with uppercase and lowercase
#[inline(always)]
pub fn hex_digit<I>() -> HexDigit<I>
    where I: Stream<Item = u8>
{
    byte_parser!(hex_digit, HexDigit, is_hex)
}
<commit_msg>feat: Add the bytes parser<commit_after>extern crate ascii;

use std::marker::PhantomData;

use self::ascii::AsciiChar;

use combinator::{Expected, ParserExt, satisfy, Satisfy, skip_many, SkipMany, token, Token, With};
use primitives::{Consumed, ConsumedResult, Error, Info, Parser, ParseError, Stream};

/// Parses a u8acter and succeeds if the u8acter is equal to `c`
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::byte::byte;
/// # fn main() {
/// let result = byte(b'!')
///     .parse(&b"!"[..])
///     .map(|x| x.0);
/// assert_eq!(result, Ok(b'!'));
/// # }
/// ```
#[inline(always)]
pub fn byte<I>(c: u8) -> Token<I>
    where I: Stream<Item = u8>
{
    token(c)
}

impl_token_parser! { Digit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

macro_rules! byte_parser {
    ($name: ident, $ty : ident, $f : ident) => ({
        let f = static_fn!((c, u8) -> bool {
            AsciiChar::from(c).map(|c| c.$f()).unwrap_or(false)
        });
        $ty(satisfy(f).expected(stringify!($name)), PhantomData)
    })
}

/// Parses a digit from a stream containing u8acters
#[inline(always)]
pub fn digit<I>() -> Digit<I>
    where I: Stream<Item = u8>
{
    byte_parser!(digit, Digit, is_digit)
}

impl_token_parser! { Space(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

/// Parses whitespace
#[inline(always)]
pub fn space<I>() -> Space<I>
    where I: Stream<Item = u8>
{
    byte_parser!(space, Space, is_whitespace)
}

impl_token_parser! { Spaces(), u8, Expected<SkipMany<Space<I>>> }
/// Skips over zero or more spaces
#[inline(always)]
pub fn spaces<I>() -> Spaces<I>
    where I: Stream<Item = u8>
{
    Spaces(skip_many(space()).expected("whitespaces"), PhantomData)
}

impl_token_parser! { Newline(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

/// Parses a newline character
#[inline(always)]
pub fn newline<I>() -> Newline<I>
    where I: Stream<Item = u8>
{
    Newline(satisfy(static_fn!((ch, u8) -> bool { ch == b'\n' })).expected("lf newline"),
            PhantomData)
}

impl_token_parser! { CrLf(), u8, Expected<With<Satisfy<I, fn (u8) -> bool>, Newline<I>>> }

/// Parses carriage return and newline, returning the newline character.
#[inline(always)]
pub fn crlf<I>() -> CrLf<I>
    where I: Stream<Item = u8>
{
    CrLf(satisfy(static_fn!((ch, u8) -> bool { ch == b'\r' }))
             .with(newline())
             .expected("crlf newline"),
         PhantomData)
}

impl_token_parser! { Tab(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses a tab u8acter
#[inline(always)]
pub fn tab<I>() -> Tab<I>
    where I: Stream<Item = u8>
{
    Tab(satisfy(static_fn!((ch, u8) -> bool { ch == b'\t' })).expected("tab"),
        PhantomData)
}

impl_token_parser! { Upper(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an uppercase letter
#[inline(always)]
pub fn upper<I>() -> Upper<I>
    where I: Stream<Item = u8>
{
    byte_parser!(upper, Upper, is_uppercase)
}

impl_token_parser! { Lower(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an lowercase letter
#[inline(always)]
pub fn lower<I>() -> Lower<I>
    where I: Stream<Item = u8>
{
    byte_parser!(lower, Lower, is_lowercase)
}

impl_token_parser! { AlphaNum(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses either an alphabet letter or digit
#[inline(always)]
pub fn alpha_num<I>() -> AlphaNum<I>
    where I: Stream<Item = u8>
{
    byte_parser!(alpha_num, AlphaNum, is_alphanumeric)
}

impl_token_parser! { Letter(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an alphabet letter
#[inline(always)]
pub fn letter<I>() -> Letter<I>
    where I: Stream<Item = u8>
{
    byte_parser!(letter, Letter, is_alphabetic)
}

impl_token_parser! { HexDigit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses a hexdecimal digit with uppercase and lowercase
#[inline(always)]
pub fn hex_digit<I>() -> HexDigit<I>
    where I: Stream<Item = u8>
{
    byte_parser!(hex_digit, HexDigit, is_hex)
}

#[derive(Clone)]
pub struct Bytes<I>(&'static [u8], PhantomData<I>);
impl<'a, I> Parser for Bytes<I>
    where I: Stream<Item = u8, Range = &'a [u8]>
{
    type Input = I;
    type Output = &'static [u8];
    #[inline]
    fn parse_lazy(&mut self, mut input: I) -> ConsumedResult<&'static [u8], I> {
        let start = input.position();
        let mut consumed = false;
        for &c in self.0 {
            match ::primitives::uncons(input) {
                Ok((other, rest)) => {
                    if c != other {
                        return Err(if consumed {
                                let errors = vec![Error::Unexpected(Info::Token(other)),
                                                  Error::Expected(Info::Range(self.0))];
                                let error = ParseError::from_errors(start, errors);
                                Consumed::Consumed(error)
                            } else {
                                Consumed::Empty(ParseError::empty(start))
                            })
                            .into();
                    }
                    consumed = true;
                    input = rest.into_inner();
                }
                Err(error) => {
                    return error.combine_fast(|mut error| {
                        error.position = start;
                        Err(if consumed {
                                Consumed::Consumed(error)
                            } else {
                                Consumed::Empty(error)
                            })
                            .into()
                    })
                }
            }
        }
        Ok((self.0,
            if consumed {
                Consumed::Consumed(input)
            } else {
                Consumed::Empty(input)
            }))
            .into()
    }
    fn add_error(&mut self, errors: &mut ParseError<Self::Input>) {
        errors.add_error(Error::Expected(Info::Range(self.0)));
    }
}

/// Parses the bytes `s`. If you have a stream implementing `RangeStream` such as `&[u8]` you can
/// also use the `range` parser which may be more efficient.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::byte::bytes;
/// # fn main() {
/// let result = bytes(b"rust")
///     .parse(&b"rust"[..])
///     .map(|x| x.0);
/// assert_eq!(result, Ok(&b"rust"[..]));
/// # }
/// ```
#[inline(always)]
pub fn bytes<'a, I>(s: &'static [u8]) -> Bytes<I>
    where I: Stream<Item = u8, Range = &'a [u8]>
{
    Bytes(s, PhantomData)
}
<|endoftext|>


<commit_before>//! The `conf` module contains functions for loading and saving game
//! configurations.
//!
//! A [`Conf`](struct.Conf.html) struct is used to create a config file
//! which specifies hardware setup stuff, mostly video display settings.
//!
//! By default a ggez game will search its resource paths for a `/conf.toml`
//! file and load values from it when the [`Context`](../struct.Context.html) is created.  This file
//! must be complete (ie you cannot just fill in some fields and have the
//! rest be default) and provides a nice way to specify settings that
//! can be tweaked such as window resolution, multisampling options, etc.
//! If no file is found, it will create a `Conf` object from the settings
//! passed to the [`ContextBuilder`](../struct.ContextBuilder.html).

use std::io;
use toml;

use crate::error::GameResult;

/// Possible fullscreen modes.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum FullscreenType {
    /// Windowed mode.
    Windowed,
    /// True fullscreen, which used to be preferred 'cause it can have
    /// small performance benefits over windowed fullscreen.
    True,
    /// Windowed fullscreen, generally preferred over real fullscreen
    /// these days 'cause it plays nicer with multiple monitors.
    Desktop,
}

/// A builder structure containing window settings
/// that can be set at runtime and changed with [`graphics::set_mode()`](../graphics/fn.set_mode.html).
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// WindowMode {
///     width: 800.0,
///     height: 600.0,
///     maximized: false,
///     fullscreen_type: FullscreenType::Windowed,
///     borderless: false,
///     min_width: 0.0,
///     max_width: 0.0,
///     min_height: 0.0,
///     max_height: 0.0,
///     resizable: false,
/// }
/// # , WindowMode::default());}
/// ```
#[derive(Debug, Copy, Clone, SmartDefault, Serialize, Deserialize, PartialEq)]
pub struct WindowMode {
    /// Window width
    #[default = 800.0]
    pub width: f32,
    /// Window height
    #[default = 600.0]
    pub height: f32,
    /// Whether or not to maximize the window
    #[default = false]
    pub maximized: bool,
    /// Fullscreen type
    #[default(FullscreenType::Windowed)]
    pub fullscreen_type: FullscreenType,
    /// Whether or not to show window decorations
    #[default = false]
    pub borderless: bool,
    /// Minimum width for resizable windows; 0 means no limit
    #[default = 0.0]
    pub min_width: f32,
    /// Minimum height for resizable windows; 0 means no limit
    #[default = 0.0]
    pub min_height: f32,
    /// Maximum width for resizable windows; 0 means no limit
    #[default = 0.0]
    pub max_width: f32,
    /// Maximum height for resizable windows; 0 means no limit
    #[default = 0.0]
    pub max_height: f32,
    /// Whether or not the window is resizable
    #[default = false]
    pub resizable: bool,
}

impl WindowMode {
    /// Set default window size, or screen resolution in true fullscreen mode.
    pub fn dimensions(mut self, width: f32, height: f32) -> Self {
        self.width = width;
        self.height = height;
        self
    }

    /// Set whether the window should be maximized.
    pub fn maximized(mut self, maximized: bool) -> Self {
        self.maximized = maximized;
        self
    }

    /// Set the fullscreen type.
    pub fn fullscreen_type(mut self, fullscreen_type: FullscreenType) -> Self {
        self.fullscreen_type = fullscreen_type;
        self
    }

    /// Set whether a window should be borderless in windowed mode.
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Set minimum window dimensions for windowed mode.
    pub fn min_dimensions(mut self, width: f32, height: f32) -> Self {
        self.min_width = width;
        self.min_height = height;
        self
    }

    /// Set maximum window dimensions for windowed mode.
    pub fn max_dimensions(mut self, width: f32, height: f32) -> Self {
        self.max_width = width;
        self.max_height = height;
        self
    }

    /// Set resizable.
    pub fn resizable(mut self, resizable: bool) -> Self {
        self.resizable = resizable;
        self
    }
}

/// A builder structure containing window settings
/// that must be set at init time and cannot be changed afterwards.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// WindowSetup {
///     title: "An easy, good game".to_owned(),
///     samples: NumSamples::Zero,
///     vsync: true,
///     icon: "".to_owned(),
///     srgb: true,
/// }
/// # , WindowSetup::default()); }
/// ```
#[derive(Debug, Clone, SmartDefault, Serialize, Deserialize, PartialEq)]
pub struct WindowSetup {
    /// The window title.
    #[default(String::from("An easy, good game"))]
    pub title: String,
    /// Number of samples to use for multisample anti-aliasing.
    #[default(NumSamples::Zero)]
    pub samples: NumSamples,
    /// Whether or not to enable vsync.
    #[default = true]
    pub vsync: bool,
    /// A file path to the window's icon.
    /// It takes a path rooted in the `resources` directory (see the [`filesystem`](../filesystem/index.html)
    /// module for details), and an empty string results in a blank/default icon.
    #[default(String::new())]
    pub icon: String,
    /// Whether or not to enable sRGB (gamma corrected color)
    /// handling on the display.
    #[default = true]
    pub srgb: bool,
}

impl WindowSetup {
    /// Set window title.
    pub fn title(mut self, title: &str) -> Self {
        self.title = title.to_owned();
        self
    }

    /// Set number of samples to use for multisample anti-aliasing.
    pub fn samples(mut self, samples: NumSamples) -> Self {
        self.samples = samples;
        self
    }

    /// Set whether vsync is enabled.
    pub fn vsync(mut self, vsync: bool) -> Self {
        self.vsync = vsync;
        self
    }

    /// Set the window's icon.
    pub fn icon(mut self, icon: &str) -> Self {
        self.icon = icon.to_owned();
        self
    }

    /// Set sRGB color mode.
    pub fn srgb(mut self, active: bool) -> Self {
        self.srgb = active;
        self
    }
}

/// Possible backends.
/// Currently, only OpenGL and OpenGL ES Core specs are supported,
/// but this lets you specify which to use as well as the version numbers.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// Backend::OpenGL {
///     major: 3,
///     minor: 2,
/// }
/// # , Backend::default()); }
/// ```
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, SmartDefault)]
#[serde(tag = "type")]
pub enum Backend {
    /// Defaults to OpenGL 3.2, which is supported by basically
    /// every machine since 2009 or so (apart from the ones that don't).
    #[default]
    OpenGL {
        /// OpenGL major version
        #[default = 3]
        major: u8,
        /// OpenGL minor version
        #[default = 2]
        minor: u8,
    },
    /// OpenGL ES, defaults to 3.0.  Used for phones and other mobile
    /// devices.  Using something older
    /// than 3.0 starts to running into sticky limitations, particularly
    /// with instanced drawing (used for `SpriteBatch`), but might be
    /// possible.
    OpenGLES {
        /// OpenGL ES major version
        #[default = 3]
        major: u8,
        /// OpenGL ES minor version
        #[default = 0]
        minor: u8,
    },
}

impl Backend {
    /// Set requested OpenGL/OpenGL ES version.
    pub fn version(self, new_major: u8, new_minor: u8) -> Self {
        match self {
            Backend::OpenGL { .. } => Backend::OpenGL {
                major: new_major,
                minor: new_minor,
            },
            Backend::OpenGLES { .. } => Backend::OpenGLES {
                major: new_major,
                minor: new_minor,
            },
        }
    }

    /// Use OpenGL
    pub fn gl(self) -> Self {
        match self {
            Backend::OpenGLES { major, minor } => Backend::OpenGL { major, minor },
            gl => gl,
        }
    }

    /// Use OpenGL ES
    pub fn gles(self) -> Self {
        match self {
            Backend::OpenGL { major, minor } => Backend::OpenGLES { major, minor },
            es => es,
        }
    }
}

/// The possible number of samples for multisample anti-aliasing.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum NumSamples {
    /// Multisampling disabled.
    Zero = 0,
    /// One sample
    One = 1,
    /// Two samples
    Two = 2,
    /// Four samples
    Four = 4,
    /// Eight samples
    Eight = 8,
    /// Sixteen samples
    Sixteen = 16,
}

impl NumSamples {
    /// Create a `NumSamples` from a number.
    /// Returns `None` if `i` is invalid.
    pub fn from_u32(i: u32) -> Option<NumSamples> {
        match i {
            0 => Some(NumSamples::Zero),
            1 => Some(NumSamples::One),
            2 => Some(NumSamples::Two),
            4 => Some(NumSamples::Four),
            8 => Some(NumSamples::Eight),
            16 => Some(NumSamples::Sixteen),
            _ => None,
        }
    }
}

/// Defines which submodules to enable in ggez.
/// If one tries to use a submodule that is not enabled,
/// it will panic.  Currently, not all subsystems can be
/// disabled.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// ModuleConf {
///     gamepad: true,
///     audio: true,
/// }
/// # , ModuleConf::default()); }
/// ```
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, SmartDefault)]
pub struct ModuleConf {
    // Gamepad is disabled by default on OSX
    // See issue #588 in general, #577 for specifics.
    /// The gamepad input module.
    #[cfg(target_os = "macos")]
    #[default = false]
    pub gamepad: bool,

    /// The gamepad input module.
    #[cfg(not(target_os = "macos"))]
    #[default = true]
    pub gamepad: bool,

    /// The audio module.
    #[default = true]
    pub audio: bool,
}

impl ModuleConf {
    /// Sets whether or not to enable the gamepad input module.
    pub fn gamepad(mut self, gamepad: bool) -> Self {
        self.gamepad = gamepad;
        self
    }

    /// Sets whether or not to enable the audio module.
    pub fn audio(mut self, audio: bool) -> Self {
        self.audio = audio;
        self
    }
}

/// A structure containing configuration data
/// for the game engine.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// Conf {
///     window_mode: WindowMode::default(),
///     window_setup: WindowSetup::default(),
///     backend: Backend::default(),
///     modules: ModuleConf::default(),
/// }
/// # , Conf::default()); }
/// ```
#[derive(Serialize, Deserialize, Debug, PartialEq, SmartDefault, Clone)]
pub struct Conf {
    /// Window setting information that can be set at runtime
    pub window_mode: WindowMode,
    /// Window setting information that must be set at init-time
    pub window_setup: WindowSetup,
    /// Graphics backend configuration
    pub backend: Backend,
    /// Which modules to enable.
    pub modules: ModuleConf,
}

impl Conf {
    /// Same as `Conf::default()`
    pub fn new() -> Self {
        Self::default()
    }

    /// Load a TOML file from the given `Read` and attempts to parse
    /// a `Conf` from it.
    pub fn from_toml_file<R: io::Read>(file: &mut R) -> GameResult<Conf> {
        let mut s = String::new();
        let _ = file.read_to_string(&mut s)?;
        let decoded = toml::from_str(&s)?;
        Ok(decoded)
    }

    /// Saves the `Conf` to the given `Write` object,
    /// formatted as TOML.
    pub fn to_toml_file<W: io::Write>(&self, file: &mut W) -> GameResult {
        let s = toml::to_vec(self)?;
        file.write_all(&s)?;
        Ok(())
    }

    /// Sets the window mode
    pub fn window_mode(mut self, window_mode: WindowMode) -> Self {
        self.window_mode = window_mode;
        self
    }

    /// Sets the backend
    pub fn backend(mut self, backend: Backend) -> Self {
        self.backend = backend;
        self
    }

    /// Sets the backend
    pub fn modules(mut self, modules: ModuleConf) -> Self {
        self.modules = modules;
        self
    }
}

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

    /// Tries to encode and decode a `Conf` object
    /// and makes sure it gets the same result it had.
    #[test]
    fn headless_encode_round_trip() {
        let c1 = conf::Conf::new();
        let mut writer = Vec::new();
        let _c = c1.to_toml_file(&mut writer).unwrap();
        let mut reader = writer.as_slice();
        let c2 = conf::Conf::from_toml_file(&mut reader).unwrap();
        assert_eq!(c1, c2);
    }
}
<commit_msg>Make gamepad support in macos on by default<commit_after>//! The `conf` module contains functions for loading and saving game
//! configurations.
//!
//! A [`Conf`](struct.Conf.html) struct is used to create a config file
//! which specifies hardware setup stuff, mostly video display settings.
//!
//! By default a ggez game will search its resource paths for a `/conf.toml`
//! file and load values from it when the [`Context`](../struct.Context.html) is created.  This file
//! must be complete (ie you cannot just fill in some fields and have the
//! rest be default) and provides a nice way to specify settings that
//! can be tweaked such as window resolution, multisampling options, etc.
//! If no file is found, it will create a `Conf` object from the settings
//! passed to the [`ContextBuilder`](../struct.ContextBuilder.html).

use std::io;
use toml;

use crate::error::GameResult;

/// Possible fullscreen modes.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum FullscreenType {
    /// Windowed mode.
    Windowed,
    /// True fullscreen, which used to be preferred 'cause it can have
    /// small performance benefits over windowed fullscreen.
    True,
    /// Windowed fullscreen, generally preferred over real fullscreen
    /// these days 'cause it plays nicer with multiple monitors.
    Desktop,
}

/// A builder structure containing window settings
/// that can be set at runtime and changed with [`graphics::set_mode()`](../graphics/fn.set_mode.html).
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// WindowMode {
///     width: 800.0,
///     height: 600.0,
///     maximized: false,
///     fullscreen_type: FullscreenType::Windowed,
///     borderless: false,
///     min_width: 0.0,
///     max_width: 0.0,
///     min_height: 0.0,
///     max_height: 0.0,
///     resizable: false,
/// }
/// # , WindowMode::default());}
/// ```
#[derive(Debug, Copy, Clone, SmartDefault, Serialize, Deserialize, PartialEq)]
pub struct WindowMode {
    /// Window width
    #[default = 800.0]
    pub width: f32,
    /// Window height
    #[default = 600.0]
    pub height: f32,
    /// Whether or not to maximize the window
    #[default = false]
    pub maximized: bool,
    /// Fullscreen type
    #[default(FullscreenType::Windowed)]
    pub fullscreen_type: FullscreenType,
    /// Whether or not to show window decorations
    #[default = false]
    pub borderless: bool,
    /// Minimum width for resizable windows; 0 means no limit
    #[default = 0.0]
    pub min_width: f32,
    /// Minimum height for resizable windows; 0 means no limit
    #[default = 0.0]
    pub min_height: f32,
    /// Maximum width for resizable windows; 0 means no limit
    #[default = 0.0]
    pub max_width: f32,
    /// Maximum height for resizable windows; 0 means no limit
    #[default = 0.0]
    pub max_height: f32,
    /// Whether or not the window is resizable
    #[default = false]
    pub resizable: bool,
}

impl WindowMode {
    /// Set default window size, or screen resolution in true fullscreen mode.
    pub fn dimensions(mut self, width: f32, height: f32) -> Self {
        self.width = width;
        self.height = height;
        self
    }

    /// Set whether the window should be maximized.
    pub fn maximized(mut self, maximized: bool) -> Self {
        self.maximized = maximized;
        self
    }

    /// Set the fullscreen type.
    pub fn fullscreen_type(mut self, fullscreen_type: FullscreenType) -> Self {
        self.fullscreen_type = fullscreen_type;
        self
    }

    /// Set whether a window should be borderless in windowed mode.
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Set minimum window dimensions for windowed mode.
    pub fn min_dimensions(mut self, width: f32, height: f32) -> Self {
        self.min_width = width;
        self.min_height = height;
        self
    }

    /// Set maximum window dimensions for windowed mode.
    pub fn max_dimensions(mut self, width: f32, height: f32) -> Self {
        self.max_width = width;
        self.max_height = height;
        self
    }

    /// Set resizable.
    pub fn resizable(mut self, resizable: bool) -> Self {
        self.resizable = resizable;
        self
    }
}

/// A builder structure containing window settings
/// that must be set at init time and cannot be changed afterwards.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// WindowSetup {
///     title: "An easy, good game".to_owned(),
///     samples: NumSamples::Zero,
///     vsync: true,
///     icon: "".to_owned(),
///     srgb: true,
/// }
/// # , WindowSetup::default()); }
/// ```
#[derive(Debug, Clone, SmartDefault, Serialize, Deserialize, PartialEq)]
pub struct WindowSetup {
    /// The window title.
    #[default(String::from("An easy, good game"))]
    pub title: String,
    /// Number of samples to use for multisample anti-aliasing.
    #[default(NumSamples::Zero)]
    pub samples: NumSamples,
    /// Whether or not to enable vsync.
    #[default = true]
    pub vsync: bool,
    /// A file path to the window's icon.
    /// It takes a path rooted in the `resources` directory (see the [`filesystem`](../filesystem/index.html)
    /// module for details), and an empty string results in a blank/default icon.
    #[default(String::new())]
    pub icon: String,
    /// Whether or not to enable sRGB (gamma corrected color)
    /// handling on the display.
    #[default = true]
    pub srgb: bool,
}

impl WindowSetup {
    /// Set window title.
    pub fn title(mut self, title: &str) -> Self {
        self.title = title.to_owned();
        self
    }

    /// Set number of samples to use for multisample anti-aliasing.
    pub fn samples(mut self, samples: NumSamples) -> Self {
        self.samples = samples;
        self
    }

    /// Set whether vsync is enabled.
    pub fn vsync(mut self, vsync: bool) -> Self {
        self.vsync = vsync;
        self
    }

    /// Set the window's icon.
    pub fn icon(mut self, icon: &str) -> Self {
        self.icon = icon.to_owned();
        self
    }

    /// Set sRGB color mode.
    pub fn srgb(mut self, active: bool) -> Self {
        self.srgb = active;
        self
    }
}

/// Possible backends.
/// Currently, only OpenGL and OpenGL ES Core specs are supported,
/// but this lets you specify which to use as well as the version numbers.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// Backend::OpenGL {
///     major: 3,
///     minor: 2,
/// }
/// # , Backend::default()); }
/// ```
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, SmartDefault)]
#[serde(tag = "type")]
pub enum Backend {
    /// Defaults to OpenGL 3.2, which is supported by basically
    /// every machine since 2009 or so (apart from the ones that don't).
    #[default]
    OpenGL {
        /// OpenGL major version
        #[default = 3]
        major: u8,
        /// OpenGL minor version
        #[default = 2]
        minor: u8,
    },
    /// OpenGL ES, defaults to 3.0.  Used for phones and other mobile
    /// devices.  Using something older
    /// than 3.0 starts to running into sticky limitations, particularly
    /// with instanced drawing (used for `SpriteBatch`), but might be
    /// possible.
    OpenGLES {
        /// OpenGL ES major version
        #[default = 3]
        major: u8,
        /// OpenGL ES minor version
        #[default = 0]
        minor: u8,
    },
}

impl Backend {
    /// Set requested OpenGL/OpenGL ES version.
    pub fn version(self, new_major: u8, new_minor: u8) -> Self {
        match self {
            Backend::OpenGL { .. } => Backend::OpenGL {
                major: new_major,
                minor: new_minor,
            },
            Backend::OpenGLES { .. } => Backend::OpenGLES {
                major: new_major,
                minor: new_minor,
            },
        }
    }

    /// Use OpenGL
    pub fn gl(self) -> Self {
        match self {
            Backend::OpenGLES { major, minor } => Backend::OpenGL { major, minor },
            gl => gl,
        }
    }

    /// Use OpenGL ES
    pub fn gles(self) -> Self {
        match self {
            Backend::OpenGL { major, minor } => Backend::OpenGLES { major, minor },
            es => es,
        }
    }
}

/// The possible number of samples for multisample anti-aliasing.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum NumSamples {
    /// Multisampling disabled.
    Zero = 0,
    /// One sample
    One = 1,
    /// Two samples
    Two = 2,
    /// Four samples
    Four = 4,
    /// Eight samples
    Eight = 8,
    /// Sixteen samples
    Sixteen = 16,
}

impl NumSamples {
    /// Create a `NumSamples` from a number.
    /// Returns `None` if `i` is invalid.
    pub fn from_u32(i: u32) -> Option<NumSamples> {
        match i {
            0 => Some(NumSamples::Zero),
            1 => Some(NumSamples::One),
            2 => Some(NumSamples::Two),
            4 => Some(NumSamples::Four),
            8 => Some(NumSamples::Eight),
            16 => Some(NumSamples::Sixteen),
            _ => None,
        }
    }
}

/// Defines which submodules to enable in ggez.
/// If one tries to use a submodule that is not enabled,
/// it will panic.  Currently, not all subsystems can be
/// disabled.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// ModuleConf {
///     gamepad: true,
///     audio: true,
/// }
/// # , ModuleConf::default()); }
/// ```
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, SmartDefault)]
pub struct ModuleConf {
    /// The gamepad input module.
    #[default = true]
    pub gamepad: bool,

    /// The audio module.
    #[default = true]
    pub audio: bool,
}

impl ModuleConf {
    /// Sets whether or not to enable the gamepad input module.
    pub fn gamepad(mut self, gamepad: bool) -> Self {
        self.gamepad = gamepad;
        self
    }

    /// Sets whether or not to enable the audio module.
    pub fn audio(mut self, audio: bool) -> Self {
        self.audio = audio;
        self
    }
}

/// A structure containing configuration data
/// for the game engine.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// Conf {
///     window_mode: WindowMode::default(),
///     window_setup: WindowSetup::default(),
///     backend: Backend::default(),
///     modules: ModuleConf::default(),
/// }
/// # , Conf::default()); }
/// ```
#[derive(Serialize, Deserialize, Debug, PartialEq, SmartDefault, Clone)]
pub struct Conf {
    /// Window setting information that can be set at runtime
    pub window_mode: WindowMode,
    /// Window setting information that must be set at init-time
    pub window_setup: WindowSetup,
    /// Graphics backend configuration
    pub backend: Backend,
    /// Which modules to enable.
    pub modules: ModuleConf,
}

impl Conf {
    /// Same as `Conf::default()`
    pub fn new() -> Self {
        Self::default()
    }

    /// Load a TOML file from the given `Read` and attempts to parse
    /// a `Conf` from it.
    pub fn from_toml_file<R: io::Read>(file: &mut R) -> GameResult<Conf> {
        let mut s = String::new();
        let _ = file.read_to_string(&mut s)?;
        let decoded = toml::from_str(&s)?;
        Ok(decoded)
    }

    /// Saves the `Conf` to the given `Write` object,
    /// formatted as TOML.
    pub fn to_toml_file<W: io::Write>(&self, file: &mut W) -> GameResult {
        let s = toml::to_vec(self)?;
        file.write_all(&s)?;
        Ok(())
    }

    /// Sets the window mode
    pub fn window_mode(mut self, window_mode: WindowMode) -> Self {
        self.window_mode = window_mode;
        self
    }

    /// Sets the backend
    pub fn backend(mut self, backend: Backend) -> Self {
        self.backend = backend;
        self
    }

    /// Sets the backend
    pub fn modules(mut self, modules: ModuleConf) -> Self {
        self.modules = modules;
        self
    }
}

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

    /// Tries to encode and decode a `Conf` object
    /// and makes sure it gets the same result it had.
    #[test]
    fn headless_encode_round_trip() {
        let c1 = conf::Conf::new();
        let mut writer = Vec::new();
        let _c = c1.to_toml_file(&mut writer).unwrap();
        let mut reader = writer.as_slice();
        let c2 = conf::Conf::from_toml_file(&mut reader).unwrap();
        assert_eq!(c1, c2);
    }
}
<|endoftext|>


<commit_before>use std::slice::Iter;
use std::str::Chars;

use std::ops::BitAnd;
use std::ops::BitAndAssign;
use std::ops::BitOr;
use std::ops::BitXorAssign;
use std::ops::Sub;
use std::ops::BitXor;

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Bitboard(u64);

impl Bitboard {
    pub const fn new(bb: u64) -> Bitboard { return Bitboard(bb); }

    pub fn bitscan_forward(self) -> Square { return Square(self.0.trailing_zeros()); }
    pub fn bitscan_reverse(self) -> Square { return Square(63 - self.0.leading_zeros()); }
    pub fn nonempty(self) -> bool { return self.0 != 0; }
    pub fn empty(self) -> bool { return self.0 == 0; }

    pub fn shifted_left(self) -> Bitboard { return Bitboard(self.0 >> 1); }
    pub fn shifted_right(self) -> Bitboard { return Bitboard(self.0 << 1); }
    pub fn shifted_down(self) -> Bitboard { return Bitboard(self.0 >> 8); }
    pub fn shifted_up(self) -> Bitboard { return Bitboard(self.0 << 8); }

    // pub fn set_piece_bit(&mut self, sq: Square, color: Color, piece: PieceType) {
}

// fn bitboard_array(data: &[u8], ret: &mut [u8], len: u8) ->

impl BitAnd for Bitboard {
    type Output = Bitboard;
    fn bitand(self, rhs: Bitboard) -> Bitboard {
        Bitboard(self.0 & rhs.0)
    }
}

impl BitAndAssign for Bitboard {
    fn bitand_assign(&mut self, rhs: Bitboard) {
        *self = Bitboard(self.0 & rhs.0)
    }
}

impl BitOr for Bitboard {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        Bitboard(self.0 | rhs.0)
    }
}

impl BitXorAssign for Bitboard {
    fn bitxor_assign(&mut self, rhs: Self) {
        self.0 ^= rhs.0;
    }
}

impl BitXor for Bitboard {
    type Output = Self;

    // rhs is the "right-hand side" of the expression `a ^ b`
    fn bitxor(self, rhs: Self) -> Self {
        Bitboard(self.0 ^ rhs.0)
    }
}

impl Sub for Bitboard {
    type Output = Bitboard;

    fn sub(self, other: Bitboard) -> Bitboard {
        Bitboard(self.0 - other.0)
    }
}

pub struct BitboardIterator {
    bits: Bitboard
}

impl Iterator for BitboardIterator {
    type Item = Square;

    fn next(&mut self) -> Option<Square> {
        if self.bits.nonempty() {
            let sq = self.bits.bitscan_forward();
            self.bits &= self.bits - Bitboard::new(1);
            return Some(sq);
        } else {
            return None;
        }
    }
}

impl IntoIterator for Bitboard {
    type Item = Square;
    type IntoIter = BitboardIterator;

    fn into_iter(self: Bitboard) -> Self::IntoIter {
        return BitboardIterator { bits: self };
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Direction { N, S, E, W, NE, NW, SE, SW }

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Square(u32);

impl Square {
    pub fn new(idx: u32) -> Square {
        assert!(idx < 64, "Attempted to create Square with invalid index!");
        Square(idx)
    }

    pub fn bitrep(self) -> Bitboard { Bitboard(1 << self.0) }
    pub fn idx(self) -> usize { return self.0 as usize; }
    pub fn unwrap(self) -> u32 { return self.0; }

    pub fn from_rank_file(rank: u32, file: u32) -> Option<Square> {
        let idx = (rank - 1) * 8 + file;
        if idx < 64 {
            return Some(Square::new(idx));
        } else {
            return None;
        }
    }

    pub fn from_algebraic(alg: &'static str) -> Option<Square> {
        let mut it: Chars = alg.chars();

        let file_idx = match it.next() {
            Some('h') => Some(0),
            Some('g') => Some(1),
            Some('f') => Some(2),
            Some('e') => Some(3),
            Some('d') => Some(4),
            Some('c') => Some(5),
            Some('b') => Some(6),
            Some('a') => Some(7),
            Some(_) => None,
            None => None
        };

        let rank_idx: Option<u32> = match it.next() {
            Some(x) => x.to_digit(10),
            None => None
        };

        match file_idx {
            None => return None,
            Some(fid) => {
                match rank_idx {
                    None => return None,
                    Some(rid) => return Square::from_rank_file(rid, fid)
                }
            }
        }
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum PieceType {
    Pawn,
    Knight,
    Bishop,
    Rook,
    Queen,
    King
}

impl PieceType {
    pub fn all() -> Iter<'static, PieceType> {
        use self::PieceType::*;
        static PIECETYPES: [PieceType;  6] = [Pawn, Knight, Bishop, Rook, Queen, King];
        PIECETYPES.into_iter()
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Color { White, Black }

use std::ops::Not;
impl Not for Color {
    type Output = Color;
    fn not(self) -> Color {
        match self {
            Color::White => Color::Black,
            Color::Black => Color::White
        }
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Piece {
    pub ptype: PieceType,
    pub color: Color,
}

<commit_msg>removed cruft<commit_after>use std::slice::Iter;
use std::str::Chars;

use std::ops::BitAnd;
use std::ops::BitAndAssign;
use std::ops::BitOr;
use std::ops::BitXorAssign;
use std::ops::Sub;
use std::ops::BitXor;

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Bitboard(u64);

impl Bitboard {
    pub const fn new(bb: u64) -> Bitboard { return Bitboard(bb); }

    pub fn bitscan_forward(self) -> Square { return Square(self.0.trailing_zeros()); }
    pub fn bitscan_reverse(self) -> Square { return Square(63 - self.0.leading_zeros()); }
    pub fn nonempty(self) -> bool { return self.0 != 0; }
    pub fn empty(self) -> bool { return self.0 == 0; }

    pub fn shifted_left(self) -> Bitboard { return Bitboard(self.0 >> 1); }
    pub fn shifted_right(self) -> Bitboard { return Bitboard(self.0 << 1); }
    pub fn shifted_down(self) -> Bitboard { return Bitboard(self.0 >> 8); }
    pub fn shifted_up(self) -> Bitboard { return Bitboard(self.0 << 8); }
}

impl BitAnd for Bitboard {
    type Output = Bitboard;
    fn bitand(self, rhs: Bitboard) -> Bitboard {
        Bitboard(self.0 & rhs.0)
    }
}

impl BitAndAssign for Bitboard {
    fn bitand_assign(&mut self, rhs: Bitboard) {
        *self = Bitboard(self.0 & rhs.0)
    }
}

impl BitOr for Bitboard {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        Bitboard(self.0 | rhs.0)
    }
}

impl BitXorAssign for Bitboard {
    fn bitxor_assign(&mut self, rhs: Self) {
        self.0 ^= rhs.0;
    }
}

impl BitXor for Bitboard {
    type Output = Self;

    // rhs is the "right-hand side" of the expression `a ^ b`
    fn bitxor(self, rhs: Self) -> Self {
        Bitboard(self.0 ^ rhs.0)
    }
}

impl Sub for Bitboard {
    type Output = Bitboard;

    fn sub(self, other: Bitboard) -> Bitboard {
        Bitboard(self.0 - other.0)
    }
}

pub struct BitboardIterator {
    bits: Bitboard
}

impl Iterator for BitboardIterator {
    type Item = Square;

    fn next(&mut self) -> Option<Square> {
        if self.bits.nonempty() {
            let sq = self.bits.bitscan_forward();
            self.bits &= self.bits - Bitboard::new(1);
            return Some(sq);
        } else {
            return None;
        }
    }
}

impl IntoIterator for Bitboard {
    type Item = Square;
    type IntoIter = BitboardIterator;

    fn into_iter(self: Bitboard) -> Self::IntoIter {
        return BitboardIterator { bits: self };
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Direction { N, S, E, W, NE, NW, SE, SW }

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Square(u32);

impl Square {
    pub fn new(idx: u32) -> Square {
        assert!(idx < 64, "Attempted to create Square with invalid index!");
        Square(idx)
    }

    pub fn bitrep(self) -> Bitboard { Bitboard(1 << self.0) }
    pub fn idx(self) -> usize { return self.0 as usize; }
    pub fn unwrap(self) -> u32 { return self.0; }

    pub fn from_rank_file(rank: u32, file: u32) -> Option<Square> {
        let idx = (rank - 1) * 8 + file;
        if idx < 64 {
            return Some(Square::new(idx));
        } else {
            return None;
        }
    }

    pub fn from_algebraic(alg: &'static str) -> Option<Square> {
        let mut it: Chars = alg.chars();

        let file_idx = match it.next() {
            Some('h') => Some(0),
            Some('g') => Some(1),
            Some('f') => Some(2),
            Some('e') => Some(3),
            Some('d') => Some(4),
            Some('c') => Some(5),
            Some('b') => Some(6),
            Some('a') => Some(7),
            Some(_) => None,
            None => None
        };

        let rank_idx: Option<u32> = match it.next() {
            Some(x) => x.to_digit(10),
            None => None
        };

        match file_idx {
            None => return None,
            Some(fid) => {
                match rank_idx {
                    None => return None,
                    Some(rid) => return Square::from_rank_file(rid, fid)
                }
            }
        }
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum PieceType {
    Pawn,
    Knight,
    Bishop,
    Rook,
    Queen,
    King
}

impl PieceType {
    pub fn all() -> Iter<'static, PieceType> {
        use self::PieceType::*;
        static PIECETYPES: [PieceType;  6] = [Pawn, Knight, Bishop, Rook, Queen, King];
        PIECETYPES.into_iter()
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Color { White, Black }

use std::ops::Not;
impl Not for Color {
    type Output = Color;
    fn not(self) -> Color {
        match self {
            Color::White => Color::Black,
            Color::Black => Color::White
        }
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Piece {
    pub ptype: PieceType,
    pub color: Color,
}

<|endoftext|>


<commit_before>use crate::Version;
use clap::{Arg, ArgMatches, Command};
use console::{Emoji, Style};
use convert_case::{Case, Casing};
use ditto_config::{self as config, PackageName};
use miette::{bail, miette, IntoDiagnostic, Result, WrapErr};
use std::{
    env::current_exe,
    fs,
    path::{Path, PathBuf},
    process,
};

pub fn command<'a>(name: &str) -> Command<'a> {
    Command::new(name)
        .about("Bootstrap a new project")
        .arg(
            Arg::new("name")
                .long("name")
                .takes_value(true)
                .validator_regex(config::PACKAGE_NAME_REGEX.clone(), "Bad package name")
                .help("Optional package name (defaults to DIR)"),
        )
        .arg(
            Arg::new("javascript")
                .long("js")
                .help("JavaScript project?"),
        )
        .arg(
            Arg::new("directory")
                .id("DIR")
                .takes_value(true)
                .required(true)
                .help("Directory for the project"),
        )
}

pub fn run(matches: &ArgMatches, ditto_version: &Version) -> Result<()> {
    let project_dir = matches.value_of("DIR").unwrap();
    let package_name = PackageName::new_unchecked(
        matches
            .value_of("name")
            .map_or_else(
                || {
                    if !config::PACKAGE_NAME_REGEX.is_match(project_dir) {
                        bail!("If `--name` isn't specified, DIR must be a valid package name")
                    }
                    Ok(project_dir)
                },
                Ok,
            )?
            .to_owned(),
    );

    let project_dir = PathBuf::from(project_dir);

    if project_dir.exists() {
        return Err(miette!(
            "path {:?} already exists",
            project_dir.to_string_lossy()
        ));
    }

    println!("Writing files...");
    fs::create_dir_all(&project_dir)
        .into_diagnostic()
        .wrap_err(format!(
            "error creating new project directory {:?}",
            project_dir.to_string_lossy()
        ))?;

    let config = write_files(package_name, &project_dir, ditto_version)?;
    if matches.is_present("javascript") {
        write_js_files(&config, &project_dir)?;
    }

    // Run an initial `ditto make` in the new directory to kick things off
    if let Ok(ditto) = current_exe() {
        println!("\nRunning `ditto make`...");
        process::Command::new(ditto)
            .arg("make")
            .current_dir(&project_dir)
            .status()
            .into_diagnostic()
            .wrap_err("error running `make` in new project directory")?;
    }

    Ok(())
}

fn write_files(
    package_name: PackageName,
    project_dir: &Path,
    ditto_version: &Version,
) -> Result<config::Config> {
    let config = write_new_config(package_name, project_dir, ditto_version)?;
    write_empty_ditto_module(&config, project_dir)?;
    write_new_gitignore(&config, project_dir)?;
    Ok(config)
}

fn write_js_files(config: &config::Config, project_dir: &Path) -> Result<()> {
    write_package_json(config, project_dir)
}

fn write_package_json(config: &config::Config, project_dir: &Path) -> Result<()> {
    let mut path = project_dir.to_path_buf();
    path.push("package");
    path.set_extension("json");
    let file = fs::File::create(&path).into_diagnostic().wrap_err(format!(
        "error creating package.json file at {:?}",
        path.to_string_lossy()
    ))?;
    let workspaces = vec![format!(
        "{}/*",
        config.codegen_js_config.packages_dir.to_string_lossy()
    )];
    let value = serde_json::json!({
        "private": true,
        "type": "module",
        "workspaces": workspaces,
    });
    serde_json::to_writer_pretty(file, &value)
        .into_diagnostic()
        .wrap_err(format!(
            "error writing package.json file to {:?}",
            path.to_string_lossy()
        ))?;
    log_path_written(path);
    Ok(())
}

fn write_new_config(
    package_name: PackageName,
    project_dir: &Path,
    ditto_version: &Version,
) -> Result<config::Config> {
    let config = config::Config::new(package_name);

    let mut config_path = project_dir.to_path_buf();
    config_path.push(config::CONFIG_FILE_NAME);
    let config_string = toml::to_string_pretty(&config)
        .into_diagnostic()
        .wrap_err("error serializing new config file")?;

    let preamble = format!(
        "# Welcome to your new ditto project!
#
# Options for this file can be found at:
# https://github.com/ditto-lang/ditto/tree/{rev}/crates/ditto-config#readme",
        rev = ditto_version.git_rev
    );

    fs::write(&config_path, format!("{}\n{}", preamble, config_string))
        .into_diagnostic()
        .wrap_err(format!(
            "error writing new config file to {:?}",
            config_path.to_string_lossy()
        ))?;

    log_path_written(&config_path);
    Ok(config)
}

fn write_new_gitignore(config: &config::Config, project_dir: &Path) -> Result<()> {
    let mut path = project_dir.to_path_buf();
    path.push(".gitignore");

    #[allow(clippy::useless_format)] // there's more logic coming
    fs::write(&path, format!("{}", config.ditto_dir.to_string_lossy()))
        .into_diagnostic()
        .wrap_err(format!(
            "error writing .gitignore to {:?}",
            path.to_string_lossy()
        ))?;

    log_path_written(&path);
    Ok(())
}

fn write_empty_ditto_module(config: &config::Config, project_dir: &Path) -> Result<()> {
    let mut module_path = project_dir.to_path_buf();
    module_path.push(&config.src_dir);
    fs::create_dir_all(&module_path)
        .into_diagnostic()
        .wrap_err(format!(
            "error creating ditto source directory {:?}",
            module_path.to_string_lossy()
        ))?;
    let module_name = config.name.to_case(Case::Pascal);
    module_path.push(&module_name);
    module_path.set_extension("ditto");

    let module_contents = format!("module {} exports (..);", module_name);
    write_ditto_module(module_path, module_contents)
}

fn write_ditto_module<P: AsRef<Path>>(path: P, contents: String) -> Result<()> {
    let module = ditto_cst::Module::parse(&contents).map_err(|_| {
        miette!(
            "Internal error: couldn't parse generated module: {:?}",
            contents
        )
    })?;
    let formatted = ditto_fmt::format_module(module);
    fs::write(&path, formatted)
        .into_diagnostic()
        .wrap_err(format!(
            "error writing ditto module to {}",
            path.as_ref().to_string_lossy()
        ))?;
    log_path_written(path);
    Ok(())
}

fn log_path_written<P: AsRef<Path>>(path: P) {
    let message = format!(
        "  {} {}",
        Emoji("✨", "Wrote"),
        path.as_ref().to_string_lossy()
    );
    println!("{}", Style::new().cyan().apply_to(message));
}
<commit_msg>Improve bootstrap command<commit_after>use crate::Version;
use clap::{Arg, ArgMatches, Command};
use console::{Emoji, Style};
use convert_case::{Case, Casing};
use ditto_config::{self as config, PackageName};
use miette::{bail, miette, IntoDiagnostic, Result, WrapErr};
use std::{
    env::current_exe,
    fs,
    path::{Path, PathBuf},
    process,
};

pub fn command<'a>(name: &str) -> Command<'a> {
    Command::new(name)
        .about("Bootstrap a new project")
        .arg(
            Arg::new("name")
                .long("name")
                .takes_value(true)
                .validator_regex(config::PACKAGE_NAME_REGEX.clone(), "Bad package name")
                .help("Optional package name (defaults to DIR)"),
        )
        .arg(
            Arg::new("javascript")
                .long("js")
                .help("JavaScript project?"),
        )
        .arg(
            Arg::new("directory")
                .id("DIR")
                .takes_value(true)
                .required(true)
                .help("Directory for the project"),
        )
}

pub fn run(matches: &ArgMatches, ditto_version: &Version) -> Result<()> {
    let project_dir = matches.value_of("DIR").unwrap();
    let package_name = PackageName::new_unchecked(
        matches
            .value_of("name")
            .map_or_else(
                || {
                    if !config::PACKAGE_NAME_REGEX.is_match(project_dir) {
                        bail!("If `--name` isn't specified, DIR must be a valid package name")
                    }
                    Ok(project_dir)
                },
                Ok,
            )?
            .to_owned(),
    );

    let project_dir = PathBuf::from(project_dir);

    if project_dir.exists() {
        return Err(miette!(
            "path {:?} already exists",
            project_dir.to_string_lossy()
        ));
    }

    println!("Writing files...");
    fs::create_dir_all(&project_dir)
        .into_diagnostic()
        .wrap_err(format!(
            "error creating new project directory {:?}",
            project_dir.to_string_lossy()
        ))?;

    let flavour = get_flavour(matches)?;

    write_files(package_name, &project_dir, ditto_version, &flavour)?;

    // Run an initial `ditto make` in the new directory to kick things off
    if let Ok(ditto) = current_exe() {
        println!("\nRunning `ditto make`...");
        process::Command::new(ditto)
            .arg("make")
            .current_dir(&project_dir)
            .status()
            .into_diagnostic()
            .wrap_err("error running `make` in new project directory")?;
    }

    Ok(())
}

enum Flavour {
    Bland,
    JavaScript, // `--javascript`
}

fn get_flavour(matches: &ArgMatches) -> Result<Flavour> {
    if matches.is_present("javascript") {
        return Ok(Flavour::JavaScript);
    }
    Ok(Flavour::Bland)
}

fn write_files(
    package_name: PackageName,
    project_dir: &Path,
    ditto_version: &Version,
    flavour: &Flavour,
) -> Result<()> {
    let config = write_new_config(package_name, project_dir, ditto_version, flavour)?;
    write_empty_ditto_module(&config, project_dir)?;
    write_new_gitignore(&config, project_dir, flavour)?;
    match flavour {
        Flavour::Bland => {}
        Flavour::JavaScript => {
            write_js_files(&config, project_dir)?;
        }
    }
    Ok(())
}

fn write_js_files(config: &config::Config, project_dir: &Path) -> Result<()> {
    write_package_json(config, project_dir)
}

fn write_package_json(config: &config::Config, project_dir: &Path) -> Result<()> {
    let mut path = project_dir.to_path_buf();
    path.push("package");
    path.set_extension("json");
    let file = fs::File::create(&path).into_diagnostic().wrap_err(format!(
        "error creating package.json file at {:?}",
        path.to_string_lossy()
    ))?;
    let workspaces = vec![format!(
        "{}/*",
        config.codegen_js_config.packages_dir.to_string_lossy()
    )];
    let value = serde_json::json!({
        "private": true,
        "type": "module",
        "workspaces": workspaces,
    });
    serde_json::to_writer_pretty(file, &value)
        .into_diagnostic()
        .wrap_err(format!(
            "error writing package.json file to {:?}",
            path.to_string_lossy()
        ))?;
    log_path_written(path);
    Ok(())
}

fn write_new_config(
    package_name: PackageName,
    project_dir: &Path,
    ditto_version: &Version,
    flavour: &Flavour,
) -> Result<config::Config> {
    let mut config = config::Config::new(package_name);
    match flavour {
        Flavour::Bland => {}
        Flavour::JavaScript => {
            config.targets =
                std::collections::HashSet::from([config::Target::Web, config::Target::Nodejs]);
        }
    }
    let mut config_path = project_dir.to_path_buf();
    config_path.push(config::CONFIG_FILE_NAME);
    let config_string = toml::to_string(&config)
        .into_diagnostic()
        .wrap_err("error serializing new config file")?;

    let preamble = format!(
        "# Welcome to your new ditto project!
#
# Options for this file can be found at:
# https://github.com/ditto-lang/ditto/tree/{rev}/crates/ditto-config#readme",
        rev = ditto_version.git_rev
    );

    fs::write(&config_path, format!("{}\n{}", preamble, config_string))
        .into_diagnostic()
        .wrap_err(format!(
            "error writing new config file to {:?}",
            config_path.to_string_lossy()
        ))?;

    log_path_written(&config_path);
    Ok(config)
}

fn write_new_gitignore(
    config: &config::Config,
    project_dir: &Path,
    flavour: &Flavour,
) -> Result<()> {
    let mut path = project_dir.to_path_buf();
    path.push(".gitignore");

    let mut ignore_lines = vec![config.ditto_dir.to_string_lossy().into_owned()];
    match flavour {
        Flavour::Bland => {}
        Flavour::JavaScript => {
            ignore_lines.push(String::from("node_modules"));
        }
    }

    fs::write(&path, ignore_lines.join("\n"))
        .into_diagnostic()
        .wrap_err(format!(
            "error writing .gitignore to {:?}",
            path.to_string_lossy()
        ))?;

    log_path_written(&path);
    Ok(())
}

fn write_empty_ditto_module(config: &config::Config, project_dir: &Path) -> Result<()> {
    let mut module_path = project_dir.to_path_buf();
    module_path.push(&config.src_dir);
    fs::create_dir_all(&module_path)
        .into_diagnostic()
        .wrap_err(format!(
            "error creating ditto source directory {:?}",
            module_path.to_string_lossy()
        ))?;
    let module_name = config.name.to_case(Case::Pascal);
    module_path.push(&module_name);
    module_path.set_extension("ditto");

    let module_contents = format!("module {} exports (..);", module_name);
    write_ditto_module(module_path, module_contents)
}

fn write_ditto_module<P: AsRef<Path>>(path: P, contents: String) -> Result<()> {
    let module = ditto_cst::Module::parse(&contents).map_err(|_| {
        miette!(
            "Internal error: couldn't parse generated module: {:?}",
            contents
        )
    })?;
    let formatted = ditto_fmt::format_module(module);
    fs::write(&path, formatted)
        .into_diagnostic()
        .wrap_err(format!(
            "error writing ditto module to {}",
            path.as_ref().to_string_lossy()
        ))?;
    log_path_written(path);
    Ok(())
}

fn log_path_written<P: AsRef<Path>>(path: P) {
    let message = format!(
        "  {} {}",
        Emoji("✨", "Wrote"),
        path.as_ref().to_string_lossy()
    );
    println!("{}", Style::new().cyan().apply_to(message));
}
<|endoftext|>


<commit_before>use std::ops::Deref;

use vertex::{Vertex, VertexProxy};

#[derive(Debug)]
pub struct Edge {
    pub from_vertex: *mut Vertex,
    pub to_vertex: *mut Vertex
}

pub struct EdgeProxy {
    pub edge: *mut Edge
}

impl Deref for EdgeProxy {
    type Target = Edge;
    fn deref<'a>(&'a self) -> &'a Edge {
        unsafe { &*(self.edge) }
    }
}

impl EdgeProxy {
	pub fn inV(&self) -> Vec<VertexProxy> {
		let mut result = Vec::new();
		unsafe {
			let vertex: &Vertex = &*(self.to_vertex);
			let proxy = VertexProxy{id:vertex.id, v:self.to_vertex};
			result.push(proxy);
		}
		result
	}
}

<commit_msg>Traversable edges<commit_after>use std::ops::Deref;

use vertex::{Vertex, VertexProxy};
use graph::Traversable;

#[derive(Debug)]
pub struct Edge {
    pub from_vertex: *mut Vertex,
    pub to_vertex: *mut Vertex
}

pub struct EdgeProxy {
    pub edge: *mut Edge
}

impl Deref for EdgeProxy {
    type Target = Edge;
    fn deref<'a>(&'a self) -> &'a Edge {
        unsafe { &*(self.edge) }
    }
}

impl Traversable for EdgeProxy {
	fn inV(&self) -> Vec<VertexProxy> {
		let mut result = Vec::new();
		unsafe {
			let vertex: &Vertex = &*(self.to_vertex);
			let proxy = VertexProxy{id:vertex.id, v:self.to_vertex};
			result.push(proxy);
		}
		result
	}
	fn outV(&self) -> Vec<VertexProxy> {
		let mut result = Vec::new();
		unsafe {
			let vertex: &Vertex = &*(self.from_vertex);
			let proxy = VertexProxy{id:vertex.id, v:self.from_vertex};
			result.push(proxy);
		}
		result
	}
}

<|endoftext|>


<commit_before>use rustc::ty::{Ty, layout::{Size, LayoutOf}};
use rustc::mir;

use crate::*;

pub trait EvalContextExt<'tcx> {
    fn pointer_inbounds(
        &self,
        ptr: Pointer<Tag>
    ) -> InterpResult<'tcx>;

    fn binary_ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Tag>,
        right: ImmTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool)>;

    fn ptr_int_arithmetic(
        &self,
        bin_op: mir::BinOp,
        left: Pointer<Tag>,
        right: u128,
        signed: bool,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool)>;

    fn ptr_eq(
        &self,
        left: Scalar<Tag>,
        right: Scalar<Tag>,
    ) -> InterpResult<'tcx, bool>;

    fn pointer_offset_inbounds(
        &self,
        ptr: Scalar<Tag>,
        pointee_ty: Ty<'tcx>,
        offset: i64,
    ) -> InterpResult<'tcx, Scalar<Tag>>;
}

impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
    /// Test if the pointer is in-bounds of a live allocation.
    #[inline]
    fn pointer_inbounds(&self, ptr: Pointer<Tag>) -> InterpResult<'tcx> {
        let (size, _align) = self.memory().get_size_and_align(ptr.alloc_id, AllocCheck::Live)?;
        ptr.check_in_alloc(size, CheckInAllocMsg::InboundsTest)
    }

    fn binary_ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Tag>,
        right: ImmTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool)> {
        use rustc::mir::BinOp::*;

        trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);

        // Operations that support fat pointers
        match bin_op {
            Eq | Ne => {
                let eq = match (*left, *right) {
                    (Immediate::Scalar(left), Immediate::Scalar(right)) =>
                        self.ptr_eq(left.not_undef()?, right.not_undef()?)?,
                    (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) =>
                        self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? &&
                        self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?,
                    _ => bug!("Type system should not allow comparing Scalar with ScalarPair"),
                };
                return Ok((Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false));
            }
            _ => {},
        }

        // Now we expect no more fat pointers.
        let left_layout = left.layout;
        let left = left.to_scalar()?;
        let right_layout = right.layout;
        let right = right.to_scalar()?;

        Ok(match bin_op {
            Offset => {
                let pointee_ty = left_layout.ty
                    .builtin_deref(true)
                    .expect("Offset called on non-ptr type")
                    .ty;
                let ptr = self.pointer_offset_inbounds(
                    left,
                    pointee_ty,
                    right.to_isize(self)?,
                )?;
                (ptr, false)
            }
            // These need both to be pointer, and fail if they are not in the same location
            Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => {
                let left = left.assert_ptr();
                let right = right.assert_ptr();
                if left.alloc_id == right.alloc_id {
                    let res = match bin_op {
                        Lt => left.offset < right.offset,
                        Le => left.offset <= right.offset,
                        Gt => left.offset > right.offset,
                        Ge => left.offset >= right.offset,
                        Sub => {
                            // subtract the offsets
                            let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory().pointer_size());
                            let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory().pointer_size());
                            let layout = self.layout_of(self.tcx.types.usize)?;
                            return self.binary_op(
                                Sub,
                                ImmTy::from_scalar(left_offset, layout),
                                ImmTy::from_scalar(right_offset, layout),
                            )
                        }
                        _ => bug!("We already established it has to be one of these operators."),
                    };
                    (Scalar::from_bool(res), false)
                } else {
                    // Both are pointers, but from different allocations.
                    throw_unsup!(InvalidPointerMath)
                }
            }
            Lt | Le | Gt | Ge if left.is_bits() && right.is_bits() => {
                let left = left.assert_bits(self.memory().pointer_size());
                let right = right.assert_bits(self.memory().pointer_size());
                let res = match bin_op {
                    Lt => left < right,
                    Le => left <= right,
                    Gt => left > right,
                    Ge => left >= right,
                    _ => bug!("We already established it has to be one of these operators."),
                };
                Ok((Scalar::from_bool(res), false))
            }
            Gt | Ge if left.is_ptr() && right.is_bits() => {
                // "ptr >[=] integer" can be tested if the integer is small enough.
                let left = left.assert_ptr();
                let right = right.assert_bits(self.memory().pointer_size());
                let (_alloc_size, alloc_align) = self.memory()
                    .get_size_and_align(left.alloc_id, AllocCheck::MaybeDead)
                    .expect("alloc info with MaybeDead cannot fail");
                let min_ptr_val = u128::from(alloc_align.bytes()) + u128::from(left.offset.bytes());
                let result = match bin_op {
                    Gt => min_ptr_val > right,
                    Ge => min_ptr_val >= right,
                    _ => bug!(),
                };
                if result {
                    // Definitely true!
                    (Scalar::from_bool(true), false)
                } else {
                    // Sorry, can't tell.
                    throw_unsup!(InvalidPointerMath)
                }
            }
            // These work if the left operand is a pointer, and the right an integer
            Add | BitAnd | Sub | Rem if left.is_ptr() && right.is_bits() => {
                // Cast to i128 is fine as we checked the kind to be ptr-sized
                self.ptr_int_arithmetic(
                    bin_op,
                    left.assert_ptr(),
                    right.assert_bits(self.memory().pointer_size()),
                    right_layout.abi.is_signed(),
                )?
            }
            // Commutative operators also work if the integer is on the left
            Add | BitAnd if left.is_bits() && right.is_ptr() => {
                // This is a commutative operation, just swap the operands
                self.ptr_int_arithmetic(
                    bin_op,
                    right.assert_ptr(),
                    left.assert_bits(self.memory().pointer_size()),
                    left_layout.abi.is_signed(),
                )?
            }
            // Nothing else works
            _ => throw_unsup!(InvalidPointerMath),
        })
    }

    fn ptr_eq(
        &self,
        left: Scalar<Tag>,
        right: Scalar<Tag>,
    ) -> InterpResult<'tcx, bool> {
        let size = self.pointer_size();
        // Just compare the integers.
        // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
        let left = self.force_bits(left, size)?;
        let right = self.force_bits(right, size)?;
        Ok(left == right)
    }

    fn ptr_int_arithmetic(
        &self,
        bin_op: mir::BinOp,
        left: Pointer<Tag>,
        right: u128,
        signed: bool,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool)> {
        use rustc::mir::BinOp::*;

        fn map_to_primval((res, over): (Pointer<Tag>, bool)) -> (Scalar<Tag>, bool) {
            (Scalar::Ptr(res), over)
        }

        Ok(match bin_op {
            Sub =>
                // The only way this can overflow is by underflowing, so signdeness of the right
                // operands does not matter.
                map_to_primval(left.overflowing_signed_offset(-(right as i128), self)),
            Add if signed =>
                map_to_primval(left.overflowing_signed_offset(right as i128, self)),
            Add if !signed =>
                map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)),

            BitAnd if !signed => {
                let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead)
                    .expect("alloc info with MaybeDead cannot fail")
                    .1.bytes();
                let base_mask = {
                    // FIXME: use `interpret::truncate`, once that takes a `Size` instead of a `Layout`.
                    let shift = 128 - self.memory().pointer_size().bits();
                    let value = !(ptr_base_align as u128 - 1);
                    // Truncate (shift left to drop out leftover values, shift right to fill with zeroes).
                    (value << shift) >> shift
                };
                let ptr_size = self.memory().pointer_size();
                trace!("ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}",
                    ptr_base_align, right, base_mask);
                if right & base_mask == base_mask {
                    // Case 1: the base address bits are all preserved, i.e., right is all-1 there.
                    let offset = (left.offset.bytes() as u128 & right) as u64;
                    (
                        Scalar::Ptr(Pointer::new_with_tag(
                            left.alloc_id,
                            Size::from_bytes(offset),
                            left.tag,
                        )),
                        false,
                    )
                } else if right & base_mask == 0 {
                    // Case 2: the base address bits are all taken away, i.e., right is all-0 there.
                    let v = Scalar::from_uint((left.offset.bytes() as u128) & right, ptr_size);
                    (v, false)
                } else {
                    throw_unsup!(ReadPointerAsBytes);
                }
            }

            Rem if !signed => {
                // Doing modulo a divisor of the alignment is allowed.
                // (Intuition: modulo a divisor leaks less information.)
                let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead)
                    .expect("alloc info with MaybeDead cannot fail")
                    .1.bytes();
                let right = right as u64;
                let ptr_size = self.memory().pointer_size();
                if right == 1 {
                    // Modulo 1 is always 0.
                    (Scalar::from_uint(0u32, ptr_size), false)
                } else if ptr_base_align % right == 0 {
                    // The base address would be cancelled out by the modulo operation, so we can
                    // just take the modulo of the offset.
                    (
                        Scalar::from_uint((left.offset.bytes() % right) as u128, ptr_size),
                        false,
                    )
                } else {
                    throw_unsup!(ReadPointerAsBytes);
                }
            }

            _ => {
                let msg = format!(
                    "unimplemented binary op on pointer {:?}: {:?}, {:?} ({})",
                    bin_op,
                    left,
                    right,
                    if signed { "signed" } else { "unsigned" }
                );
                throw_unsup!(Unimplemented(msg));
            }
        })
    }

    /// Raises an error if the offset moves the pointer outside of its allocation.
    /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing
    /// moves in there because the size is 0). We also consider the NULL pointer its own separate
    /// allocation, and all the remaining integers pointers their own allocation.
    fn pointer_offset_inbounds(
        &self,
        ptr: Scalar<Tag>,
        pointee_ty: Ty<'tcx>,
        offset: i64,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        // FIXME: assuming here that type size is less than `i64::max_value()`.
        let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
        let offset = offset
            .checked_mul(pointee_size)
            .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?;
        // Now let's see what kind of pointer this is.
        let ptr = if offset == 0 {
            match ptr {
                Scalar::Ptr(ptr) => ptr,
                Scalar::Raw { .. } => {
                    // Offset 0 on an integer. We accept that, pretending there is
                    // a little zero-sized allocation here.
                    return Ok(ptr);
                }
            }
        } else {
            // Offset > 0. We *require* a pointer.
            self.force_ptr(ptr)?
        };
        // Both old and new pointer must be in-bounds of a *live* allocation.
        // (Of the same allocation, but that part is trivial with our representation.)
        self.pointer_inbounds(ptr)?;
        let ptr = ptr.signed_offset(offset, self)?;
        self.pointer_inbounds(ptr)?;
        Ok(Scalar::Ptr(ptr))
    }
}
<commit_msg>implement all ptr comparisons through integer casts<commit_after>use rustc::ty::{Ty, layout::LayoutOf};
use rustc::mir;

use crate::*;

pub trait EvalContextExt<'tcx> {
    fn pointer_inbounds(
        &self,
        ptr: Pointer<Tag>
    ) -> InterpResult<'tcx>;

    fn binary_ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Tag>,
        right: ImmTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool)>;

    fn ptr_eq(
        &self,
        left: Scalar<Tag>,
        right: Scalar<Tag>,
    ) -> InterpResult<'tcx, bool>;

    fn pointer_offset_inbounds(
        &self,
        ptr: Scalar<Tag>,
        pointee_ty: Ty<'tcx>,
        offset: i64,
    ) -> InterpResult<'tcx, Scalar<Tag>>;
}

impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
    /// Test if the pointer is in-bounds of a live allocation.
    #[inline]
    fn pointer_inbounds(&self, ptr: Pointer<Tag>) -> InterpResult<'tcx> {
        let (size, _align) = self.memory().get_size_and_align(ptr.alloc_id, AllocCheck::Live)?;
        ptr.check_in_alloc(size, CheckInAllocMsg::InboundsTest)
    }

    fn binary_ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Tag>,
        right: ImmTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, (Scalar<Tag>, bool)> {
        use rustc::mir::BinOp::*;

        trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);

        Ok(match bin_op {
            Eq | Ne => {
                // This supports fat pointers.
                let eq = match (*left, *right) {
                    (Immediate::Scalar(left), Immediate::Scalar(right)) =>
                        self.ptr_eq(left.not_undef()?, right.not_undef()?)?,
                    (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) =>
                        self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? &&
                        self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?,
                    _ => bug!("Type system should not allow comparing Scalar with ScalarPair"),
                };
                (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false)
            }

            Lt | Le | Gt | Ge => {
                // Just compare the integers.
                // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
                let left = self.force_bits(left.to_scalar()?, left.layout.size)?;
                let right = self.force_bits(right.to_scalar()?, right.layout.size)?;
                let res = match bin_op {
                    Lt => left < right,
                    Le => left <= right,
                    Gt => left > right,
                    Ge => left >= right,
                    _ => bug!("We already established it has to be one of these operators."),
                };
                (Scalar::from_bool(res), false)
            }

            Offset => {
                let pointee_ty = left.layout.ty
                    .builtin_deref(true)
                    .expect("Offset called on non-ptr type")
                    .ty;
                let ptr = self.pointer_offset_inbounds(
                    left.to_scalar()?,
                    pointee_ty,
                    right.to_scalar()?.to_isize(self)?,
                )?;
                (ptr, false)
            }

            _ => bug!("Invalid operator on pointers: {:?}", bin_op)
        })
    }

    fn ptr_eq(
        &self,
        left: Scalar<Tag>,
        right: Scalar<Tag>,
    ) -> InterpResult<'tcx, bool> {
        let size = self.pointer_size();
        // Just compare the integers.
        // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
        let left = self.force_bits(left, size)?;
        let right = self.force_bits(right, size)?;
        Ok(left == right)
    }

    /// Raises an error if the offset moves the pointer outside of its allocation.
    /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing
    /// moves in there because the size is 0). We also consider the NULL pointer its own separate
    /// allocation, and all the remaining integers pointers their own allocation.
    fn pointer_offset_inbounds(
        &self,
        ptr: Scalar<Tag>,
        pointee_ty: Ty<'tcx>,
        offset: i64,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        // FIXME: assuming here that type size is less than `i64::max_value()`.
        let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
        let offset = offset
            .checked_mul(pointee_size)
            .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?;
        // Now let's see what kind of pointer this is.
        let ptr = if offset == 0 {
            match ptr {
                Scalar::Ptr(ptr) => ptr,
                Scalar::Raw { .. } => {
                    // Offset 0 on an integer. We accept that, pretending there is
                    // a little zero-sized allocation here.
                    return Ok(ptr);
                }
            }
        } else {
            // Offset > 0. We *require* a pointer.
            self.force_ptr(ptr)?
        };
        // Both old and new pointer must be in-bounds of a *live* allocation.
        // (Of the same allocation, but that part is trivial with our representation.)
        self.pointer_inbounds(ptr)?;
        let ptr = ptr.signed_offset(offset, self)?;
        self.pointer_inbounds(ptr)?;
        Ok(Scalar::Ptr(ptr))
    }
}
<|endoftext|>