<commit_before>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{File, remove_file, rename};
use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

fn main() {
    test_file();
    test_file_clone();
    test_seek();
    test_metadata();
    test_symlink();
    test_errors();
    test_rename();
}

fn test_file() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_file.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_file_clone.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_seek() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_seek.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_metadata.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(&tmp).unwrap();
    check_metadata(bytes, &filename).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_symlink() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_link_target.txt");
    let path = tmp.join(&filename);
    let symlink_path = tmp.join("miri_test_fs_symlink.txt");
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();
    remove_file(&symlink_path).ok();

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    // Creating a symbolic link should succeed.
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_errors.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    let tmp = std::env::temp_dir();
    // Renaming a file should succeed.
    let path1 = tmp.join("miri_test_fs_rename_source.txt");
    let path2 = tmp.join("miri_test_fs_rename_destination.txt");
    // Clean files for robustness.
    remove_file(&path1).ok();
    remove_file(&path2).ok();
    let file = File::create(&path1).unwrap();
    drop(file);
    rename(&path1, &path2).unwrap();
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    assert!(path2.metadata().unwrap().is_file());
    remove_file(&path2).unwrap();
}
<commit_msg>fs test: factor some common code<commit_after>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{File, remove_file, rename};
use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

fn main() {
    test_file();
    test_file_clone();
    test_seek();
    test_metadata();
    test_symlink();
    test_errors();
    test_rename();
}

/// Prepare: compute filename and make sure the file does not exist.
fn prepare(filename: &str) -> PathBuf {
    let tmp = std::env::temp_dir();
    let path = tmp.join(filename);
    // Clean the paths for robustness.
    remove_file(&path).ok();
    path
}

fn test_file() {
    let path = prepare("miri_test_fs_file.txt");
    let bytes = b"Hello, World!\n";

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let path = prepare("miri_test_fs_file_clone.txt");
    let bytes = b"Hello, World!\n";

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_seek() {
    let path = prepare("miri_test_fs_seek.txt");
    let bytes = b"Hello, World!\n";

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let path = prepare("miri_test_fs_metadata.txt");
    let bytes = b"Hello, World!\n";

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(path.parent().unwrap()).unwrap();
    check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_symlink() {
    let path = prepare("miri_test_fs_link_target.txt");
    let symlink_path = prepare("miri_test_fs_symlink.txt");
    let bytes = b"Hello, World!\n";

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    // Creating a symbolic link should succeed.
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let path = prepare("miri_test_fs_errors.txt");
    let bytes = b"Hello, World!\n";

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    // Renaming a file should succeed.
    let path1 = prepare("miri_test_fs_rename_source.txt");
    let path2 = prepare("miri_test_fs_rename_destination.txt");

    let file = File::create(&path1).unwrap();
    drop(file);
    rename(&path1, &path2).unwrap();
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    assert!(path2.metadata().unwrap().is_file());
    remove_file(&path2).unwrap();
}
<|endoftext|>


<commit_before>///! Generate a base bitmap for drawing an overland map with a paint program.

extern crate world;
extern crate image;

use image::Pixel;
use world::{Sector, Location};

const COLS: i16 = 8;
const ROWS: i16 = 12;

fn overland_locs() -> Vec<Location> {
    let mut ret = Vec::new();
    for y in 0..ROWS {
        for x in 0..COLS {
            let sec = Sector::new(x, y, 0);
            for loc in sec.iter() {
                ret.push(loc);
            }
        }
    }
    ret
}

fn main() {
    let locs = overland_locs();
    let (mut min_x, mut min_y) = locs.iter().fold(
        (0, 0),
        |(x, y), loc| (x.min(loc.x), y.min(loc.y)),
    );
    min_x -= 1;
    min_y -= 1;

    let (max_x, max_y) = locs.iter().fold(
        (0, 0),
        |(x, y), loc| (x.max(loc.x), y.max(loc.y)),
    );
    println!("{} {} - {} {}", min_x, min_y, max_x, max_y);

    let mut buf = image::ImageBuffer::new((max_x - min_x + 1) as u32, (max_y - min_y + 1) as u32);

    for (x, y, p) in buf.enumerate_pixels_mut() {
        let loc = Location::new(x as i16 + min_x, y as i16 + min_y, 0);
        let sec = loc.sector();
        if sec.x < 0 || sec.y < 0 || sec.x >= COLS || sec.y >= ROWS {
            *p = image::Rgb::from_channels(0x00, 0x00, 0x00, 0xff);
            continue;
        }
        if (sec.x + sec.y) % 2 == 0 {
            *p = image::Rgb::from_channels(0x00, 0xaa, 0xaa, 0xff);
        } else {
            *p = image::Rgb::from_channels(0x88, 0x88, 0x88, 0xff);
        }
    }

    image::save_buffer(
        "overland_base.png",
        &buf,
        buf.width(),
        buf.height(),
        image::ColorType::RGB(8),
    ).unwrap();
}
<commit_msg>Overland base gen uses terrain color data<commit_after>///! Generate a base bitmap for drawing an overland map with a paint program.

extern crate calx;
extern crate world;
extern crate image;

use image::Pixel;
use world::{Sector, Location, Terrain};
use calx::hex_disc;

const COLS: i16 = 8;
const ROWS: i16 = 12;

fn overland_locs() -> Vec<Location> {
    let mut ret = Vec::new();
    for y in 0..ROWS {
        for x in 0..COLS {
            let sec = Sector::new(x, y, 0);
            for loc in sec.iter() {
                ret.push(loc);
            }
        }
    }
    ret
}

fn valid_sector(sec: Sector) -> bool {
    sec.x >= 0 && sec.y >= 0 && sec.x < COLS && sec.y < ROWS
}

fn main() {
    let locs = overland_locs();
    let (mut min_x, mut min_y) = locs.iter().fold(
        (0, 0),
        |(x, y), loc| (x.min(loc.x), y.min(loc.y)),
    );
    min_x -= 1;
    min_y -= 1;

    let (max_x, max_y) = locs.iter().fold(
        (0, 0),
        |(x, y), loc| (x.max(loc.x), y.max(loc.y)),
    );
    println!("{} {} - {} {}", min_x, min_y, max_x, max_y);

    let mut buf = image::ImageBuffer::new((max_x - min_x + 2) as u32, (max_y - min_y + 2) as u32);

    for (x, y, p) in buf.enumerate_pixels_mut() {
        let loc = Location::new(x as i16 + min_x, y as i16 + min_y, 0);
        let sec = loc.sector();
        let terrain = if valid_sector(sec) {
            Terrain::Grass
        } else if hex_disc(loc, 1).any(|loc| valid_sector(loc.sector())) {
            // Not a valid sector, but touching one.
            Terrain::Water
        } else {
            *p = image::Rgb::from_channels(0x00, 0x00, 0x00, 0xff);
            continue;
        };

        let color = if (sec.x + sec.y) % 2 == 0 {
            terrain.color()
        } else {
            terrain.dark_color()
        };

        *p = image::Rgb::from_channels(color.r, color.g, color.b, 0xff);
    }

    // XXX: Hacky way to force terrain colors into image palette
    // Didn't find direct indexed palette manipulation in piston-image.
    for (x, t) in Terrain::iter().filter(|t| t.is_regular()).enumerate() {
        let light = t.color();
        let dark = t.dark_color();
        buf.put_pixel(x as u32, 0, image::Rgb::from_channels(light.r, light.g, light.b, 0xff));
        buf.put_pixel(x as u32, 1, image::Rgb::from_channels(dark.r, dark.g, dark.b, 0xff));
    }

    image::save_buffer(
        "overland_base.png",
        &buf,
        buf.width(),
        buf.height(),
        image::ColorType::RGB(8),
    ).unwrap();
}
<|endoftext|>


<commit_before>// requires nightly toolchain!
//
// compile-flags:-C panic=abort
#![no_std]
#![feature(alloc, lang_items, start, core_intrinsics)]
#![allow(dead_code)]
use core::intrinsics;

// Pull in the system libc library for what crt0.o likely requires.
// extern crate libc;

#[macro_use]
extern crate derive_builder;
extern crate alloc;

#[derive(Builder)]
#[builder(no_std)]
struct IgnoreEmptyStruct {}

#[derive(Builder, PartialEq, Debug)]
#[builder(no_std)]
struct Foo {
    #[builder(default)]
    defaulted: u32,
    #[builder(setter(skip), try_setter)]
    skipped: u32,
}

fn main() {
    let foo = FooBuilder::default()
        .build()
        .unwrap();

    assert_eq!(foo, Foo {
        defaulted: 0,
        skipped: 0,
    })
}

///////////////////////////////////////////////////////////////
// some no_std-boilerplate
// from https://doc.rust-lang.org/book/no-stdlib.html
///////////////////////////////////////////////////////////////

// These functions and traits are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "eh_personality"]
#[no_mangle]
pub extern  fn eh_personality() {}

// This function may be needed based on the compilation target.
#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern fn rust_eh_unwind_resume() {
}

#[lang = "panic_fmt"]
#[no_mangle]
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
                               _file: &'static str,
                               _line: u32) -> ! {
    unsafe { intrinsics::abort() }
}

#[lang = "oom"]
#[no_mangle]
pub extern fn rust_oom() {
    unsafe { intrinsics::abort() }
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
    unsafe { intrinsics::abort() }
}

// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    main();
    0
}
<commit_msg>Update nightly test to use new panic struct<commit_after>// requires nightly toolchain!
//
// compile-flags:-C panic=abort
#![no_std]
#![feature(alloc, lang_items, start, core_intrinsics, oom, panic_implementation)]
#![allow(dead_code)]
use core::intrinsics;
use core::panic::PanicInfo;

// Pull in the system libc library for what crt0.o likely requires.
// extern crate libc;

#[macro_use]
extern crate derive_builder;
extern crate alloc;

#[derive(Builder)]
#[builder(no_std)]
struct IgnoreEmptyStruct {}

#[derive(Builder, PartialEq, Debug)]
#[builder(no_std)]
struct Foo {
    #[builder(default)]
    defaulted: u32,
    #[builder(setter(skip), try_setter)]
    skipped: u32,
}

fn main() {
    let foo = FooBuilder::default()
        .build()
        .unwrap();

    assert_eq!(foo, Foo {
        defaulted: 0,
        skipped: 0,
    })
}

///////////////////////////////////////////////////////////////
// some no_std-boilerplate
// from https://doc.rust-lang.org/book/no-stdlib.html
///////////////////////////////////////////////////////////////

// These functions and traits are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "eh_personality"]
#[no_mangle]
pub extern  fn eh_personality() {}

// This function may be needed based on the compilation target.
#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern fn rust_eh_unwind_resume() {
}

#[panic_implementation]
#[no_mangle]
fn panic(_info: &PanicInfo) -> ! {
    unsafe { intrinsics::abort() }
}

#[lang = "oom"]
#[no_mangle]
pub extern fn rust_oom() {
    unsafe { intrinsics::abort() }
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
    unsafe { intrinsics::abort() }
}

// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    main();
    0
}
<|endoftext|>


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

use std::cmp::Ordering;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};

use proc_macro2::{Ident, Span};
use unicode_xid::UnicodeXID;

#[cfg(feature = "parsing")]
use lookahead;

/// A Rust lifetime: `'a`.
///
/// Lifetime names must conform to the following rules:
///
/// - Must start with an apostrophe.
/// - Must not consist of just an apostrophe: `'`.
/// - Character after the apostrophe must be `_` or a Unicode code point with
///   the XID_Start property.
/// - All following characters must be Unicode code points with the XID_Continue
///   property.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct Lifetime {
    pub apostrophe: Span,
    pub ident: Ident,
}

impl Lifetime {
    pub fn new(s: &str, span: Span) -> Self {
        if !s.starts_with('\'') {
            panic!(
                "lifetime name must start with apostrophe as in \"'a\", got {:?}",
                s
            );
        }

        if s == "'" {
            panic!("lifetime name must not be empty");
        }

        fn xid_ok(s: &str) -> bool {
            let mut chars = s.chars();
            let first = chars.next().unwrap();
            if !(UnicodeXID::is_xid_start(first) || first == '_') {
                return false;
            }
            for ch in chars {
                if !UnicodeXID::is_xid_continue(ch) {
                    return false;
                }
            }
            true
        }

        if !xid_ok(&s[1..]) {
            panic!("{:?} is not a valid lifetime name", s);
        }

        Lifetime {
            apostrophe: span,
            ident: Ident::new(&s[1..], span),
        }
    }
}

impl Display for Lifetime {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        "'".fmt(formatter)?;
        self.ident.fmt(formatter)
    }
}

impl PartialEq for Lifetime {
    fn eq(&self, other: &Lifetime) -> bool {
        self.ident.eq(&other.ident)
    }
}

impl Eq for Lifetime {}

impl PartialOrd for Lifetime {
    fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Lifetime {
    fn cmp(&self, other: &Lifetime) -> Ordering {
        self.ident.cmp(&other.ident)
    }
}

impl Hash for Lifetime {
    fn hash<H: Hasher>(&self, h: &mut H) {
        self.ident.hash(h)
    }
}

#[cfg(feature = "parsing")]
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
    match marker {}
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use parse::{Parse, ParseStream, Result};

    impl Parse for Lifetime {
        fn parse(input: ParseStream) -> Result<Self> {
            input.step(|cursor| {
                cursor
                    .lifetime()
                    .ok_or_else(|| cursor.error("expected lifetime"))
            })
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;

    use proc_macro2::{Punct, Spacing, TokenStream};
    use quote::{ToTokens, TokenStreamExt};

    impl ToTokens for Lifetime {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            let mut apostrophe = Punct::new('\'', Spacing::Joint);
            apostrophe.set_span(self.apostrophe);
            tokens.append(apostrophe);
            self.ident.to_tokens(tokens);
        }
    }
}
<commit_msg>Document Lifetime::new<commit_after>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cmp::Ordering;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};

use proc_macro2::{Ident, Span};
use unicode_xid::UnicodeXID;

#[cfg(feature = "parsing")]
use lookahead;

/// A Rust lifetime: `'a`.
///
/// Lifetime names must conform to the following rules:
///
/// - Must start with an apostrophe.
/// - Must not consist of just an apostrophe: `'`.
/// - Character after the apostrophe must be `_` or a Unicode code point with
///   the XID_Start property.
/// - All following characters must be Unicode code points with the XID_Continue
///   property.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct Lifetime {
    pub apostrophe: Span,
    pub ident: Ident,
}

impl Lifetime {
    /// # Panics
    ///
    /// Panics if the lifetime does not conform to the bulleted rules above.
    ///
    /// # Invocation
    ///
    /// ```
    /// # extern crate proc_macro2;
    /// # extern crate syn;
    /// #
    /// # use proc_macro2::Span;
    /// # use syn::Lifetime;
    /// #
    /// # fn f() -> Lifetime {
    /// Lifetime::new("'a", Span::call_site())
    /// # }
    /// ```
    pub fn new(symbol: &str, span: Span) -> Self {
        if !symbol.starts_with('\'') {
            panic!(
                "lifetime name must start with apostrophe as in \"'a\", got {:?}",
                symbol
            );
        }

        if symbol == "'" {
            panic!("lifetime name must not be empty");
        }

        fn xid_ok(symbol: &str) -> bool {
            let mut chars = symbol.chars();
            let first = chars.next().unwrap();
            if !(UnicodeXID::is_xid_start(first) || first == '_') {
                return false;
            }
            for ch in chars {
                if !UnicodeXID::is_xid_continue(ch) {
                    return false;
                }
            }
            true
        }

        if !xid_ok(&symbol[1..]) {
            panic!("{:?} is not a valid lifetime name", symbol);
        }

        Lifetime {
            apostrophe: span,
            ident: Ident::new(&symbol[1..], span),
        }
    }
}

impl Display for Lifetime {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        "'".fmt(formatter)?;
        self.ident.fmt(formatter)
    }
}

impl PartialEq for Lifetime {
    fn eq(&self, other: &Lifetime) -> bool {
        self.ident.eq(&other.ident)
    }
}

impl Eq for Lifetime {}

impl PartialOrd for Lifetime {
    fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Lifetime {
    fn cmp(&self, other: &Lifetime) -> Ordering {
        self.ident.cmp(&other.ident)
    }
}

impl Hash for Lifetime {
    fn hash<H: Hasher>(&self, h: &mut H) {
        self.ident.hash(h)
    }
}

#[cfg(feature = "parsing")]
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
    match marker {}
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use parse::{Parse, ParseStream, Result};

    impl Parse for Lifetime {
        fn parse(input: ParseStream) -> Result<Self> {
            input.step(|cursor| {
                cursor
                    .lifetime()
                    .ok_or_else(|| cursor.error("expected lifetime"))
            })
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;

    use proc_macro2::{Punct, Spacing, TokenStream};
    use quote::{ToTokens, TokenStreamExt};

    impl ToTokens for Lifetime {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            let mut apostrophe = Punct::new('\'', Spacing::Joint);
            apostrophe.set_span(self.apostrophe);
            tokens.append(apostrophe);
            self.ident.to_tokens(tokens);
        }
    }
}
<|endoftext|>


<commit_before>/*!
Test supports module.

*/
use glutin;
use glium::{mod, DisplayBuild};

use std::os;

/// Builds a headless display for tests.
pub fn build_display() -> glium::Display {
    if os::getenv("HEADLESS_TESTS").is_some() {
        glutin::HeadlessRendererBuilder::new(1024, 768).build_glium().unwrap()
    } else {
        glutin::WindowBuilder::new().with_visibility(false).build_glium().unwrap()
    }
}

/// Builds a 2x2 unicolor texture.
pub fn build_unicolor_texture2d(display: &glium::Display, red: f32, green: f32, blue: f32)
    -> glium::Texture2d
{
    let color = ((red * 255.0) as u8, (green * 255.0) as u8, (blue * 255.0) as u8);

    glium::texture::Texture2d::new(display, vec![
        vec![color, color],
        vec![color, color],
    ])
}
<commit_msg>Allow dead_code in tests support module<commit_after>/*!
Test supports module.

*/

#![allow(dead_code)]

use glutin;
use glium::{mod, DisplayBuild};

use std::os;

/// Builds a headless display for tests.
pub fn build_display() -> glium::Display {
    if os::getenv("HEADLESS_TESTS").is_some() {
        glutin::HeadlessRendererBuilder::new(1024, 768).build_glium().unwrap()
    } else {
        glutin::WindowBuilder::new().with_visibility(false).build_glium().unwrap()
    }
}

/// Builds a 2x2 unicolor texture.
pub fn build_unicolor_texture2d(display: &glium::Display, red: f32, green: f32, blue: f32)
    -> glium::Texture2d
{
    let color = ((red * 255.0) as u8, (green * 255.0) as u8, (blue * 255.0) as u8);

    glium::texture::Texture2d::new(display, vec![
        vec![color, color],
        vec![color, color],
    ])
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::{env, str};
use std::error::Error;
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf};
use toml;

/// A Crate Dependency
pub type Dependency = (String, toml::Value);

/// Enumeration of errors which can occur when working with a rust manifest.
quick_error! {
    #[derive(Debug)]
    pub enum ManifestError {
        /// Cargo.toml could not be found.
        MissingManifest {
            description("missing manifest")
            display("Your Cargo.toml is missing.")
        }
        /// The TOML table could not be found.
        NonExistentTable(table: String) {
            description("non existent table")
            display("The table `{}` could not be found.", table)
        }
        /// The dependency could not be found.
        NonExistentDependency(name: String, table: String) {
            description("non existent dependency")
            display("The dependency `{}` could not be found in `{}`.", name, table)
        }
    }
}

enum CargoFile {
    Config,
    Lock,
}

/// A Cargo Manifest
#[derive(Debug, PartialEq)]
pub struct Manifest {
    /// Manifest contents as TOML data
    pub data: toml::Table,
}

/// If a manifest is specified, return that one, otherise perform a manifest search starting from
/// the current directory.
/// If a manifest is specified, return that one. If a path is specified, perform a manifest search
/// starting from there. If nothing is specified, start searching from the current directory
/// (`cwd`).
fn find(specified: &Option<&str>, file: CargoFile) -> Result<PathBuf, Box<Error>> {
    let file_path = specified.map(PathBuf::from);

    if let Some(path) = file_path {
        if try!(fs::metadata(&path)).is_file() {
            Ok(path)
        } else {
            search(&path, file).map_err(From::from)
        }
    } else {
        env::current_dir()
            .map_err(From::from)
            .and_then(|ref dir| search(dir, file).map_err(From::from))
    }
}

/// Search for Cargo.toml in this directory and recursively up the tree until one is found.
fn search(dir: &Path, file: CargoFile) -> Result<PathBuf, ManifestError> {
    let manifest = match file {
        CargoFile::Config => dir.join("Cargo.toml"),
        CargoFile::Lock => dir.join("Cargo.lock"),
    };

    fs::metadata(&manifest)
        .map(|_| manifest)
        .or(dir.parent().ok_or(ManifestError::MissingManifest).and_then(|dir| search(dir, file)))
}

impl Manifest {
    /// Look for a `Cargo.toml` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process's working directory is used as a starting point.
    pub fn find_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Config).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Look for a `Cargo.lock` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process' working directory is used as a starting point.
    pub fn find_lock_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Lock).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Open the `Cargo.toml` for a path (or the process' `cwd`)
    pub fn open(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Open the `Cargo.lock` for a path (or the process' `cwd`)
    pub fn open_lock_file(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_lock_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Overwrite a file with TOML data.
    pub fn write_to_file<T: Seek + Write>(&self, file: &mut T) -> Result<(), Box<Error>> {
        try!(file.seek(SeekFrom::Start(0)));
        let mut toml = self.data.clone();

        let (proj_header, proj_data) = try!(toml.remove("package")
                                                .map(|data| ("package", data))
                                                .or_else(|| {
                                                    toml.remove("project")
                                                        .map(|data| ("project", data))
                                                })
                                                .ok_or(ManifestError::MissingManifest));
        write!(file,
               "[{}]\n{}{}",
               proj_header,
               proj_data,
               toml::Value::Table(toml))
            .map_err(From::from)
    }

    /// Add entry to a Cargo.toml.
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn insert_into_table(&mut self,
                             table: &str,
                             &(ref name, ref data): &Dependency)
                             -> Result<(), ManifestError> {
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table))
                            .or_insert(toml::Value::Table(BTreeMap::new()));
        match *entry {
            toml::Value::Table(ref mut deps) => {
                deps.insert(name.clone(), data.clone());
                Ok(())
            }
            _ => Err(ManifestError::NonExistentTable(table.into())),
        }
    }

    /// Remove entry from a Cargo.toml.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate cargo_edit;
    /// # extern crate toml;
    /// # fn main() {
    ///     use cargo_edit::Manifest;
    ///     use toml;
    ///
    ///     let mut manifest = Manifest { data: toml::Table::new() };
    ///     let dep = ("cargo-edit".to_owned(), toml::Value::String("0.1.0".to_owned()));
    ///     let _ = manifest.insert_into_table("dependencies", &dep);
    ///     assert!(manifest.remove_from_table("dependencies", &dep.0).is_ok());
    ///     assert!(manifest.remove_from_table("dependencies", &dep.0).is_err());
    /// # }
    /// ```
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn remove_from_table(&mut self, table: &str, name: &str) -> Result<(), ManifestError> {
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table));

        match entry {
            Entry::Vacant(_) => Err(ManifestError::NonExistentTable(table.into())),
            Entry::Occupied(entry) => {
                match *entry.into_mut() {
                    toml::Value::Table(ref mut deps) => {
                        deps.remove(name)
                            .map(|_| ())
                            .ok_or(ManifestError::NonExistentDependency(name.into(), table.into()))
                    }
                    _ => Err(ManifestError::NonExistentTable(table.into())),
                }
            }
        }
    }

    /// Add multiple dependencies to manifest
    pub fn add_deps(&mut self, table: &str, deps: &[Dependency]) -> Result<(), Box<Error>> {
        deps.iter()
            .map(|dep| self.insert_into_table(table, &dep))
            .collect::<Result<Vec<_>, _>>()
            .map_err(From::from)
            .map(|_| ())
    }
}

impl str::FromStr for Manifest {
    type Err = Box<Error>;

    /// Read manifest data from string
    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = toml::Parser::new(&input);

        parser.parse()
              .ok_or(parser.errors.pop())
              .map_err(Option::unwrap)
              .map_err(From::from)
              .map(|data| Manifest { data: data })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::BTreeMap;
    use toml;

    #[test]
    fn add_remove_dependency() {
        let mut manifest = Manifest { data: toml::Table::new() };
        // Create a copy containing empty "dependencies" table because removing
        //   the last entry in a table does not remove the section.
        let mut copy = Manifest { data: toml::Table::new() };
        copy.data.insert("dependencies".to_owned(),
                         toml::Value::Table(BTreeMap::new()));
        let dep = ("cargo-edit".to_owned(),
                   toml::Value::String("0.1.0".to_owned()));
        let _ = manifest.insert_into_table("dependencies", &dep);
        assert!(manifest.remove_from_table("dependencies", &dep.0).is_ok());
        assert_eq!(manifest, copy);
    }

    #[test]
    fn remove_dependency_no_section() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = ("cargo-edit".to_owned(),
                   toml::Value::String("0.1.0".to_owned()));
        assert!(manifest.remove_from_table("dependencies", &dep.0).is_err());
    }

    #[test]
    fn remove_dependency_non_existent() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = ("cargo-edit".to_owned(),
                   toml::Value::String("0.1.0".to_owned()));
        let other_dep = ("other-dep".to_owned(),
                         toml::Value::String("0.1.0".to_owned()));
        let _ = manifest.insert_into_table("dependencies", &other_dep);
        assert!(manifest.remove_from_table("dependencies", &dep.0).is_err());

    }
}
<commit_msg>do not partially overwrite the old manifest file<commit_after>use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::{env, str};
use std::error::Error;
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf};
use toml;

/// A Crate Dependency
pub type Dependency = (String, toml::Value);

/// Enumeration of errors which can occur when working with a rust manifest.
quick_error! {
    #[derive(Debug)]
    pub enum ManifestError {
        /// Cargo.toml could not be found.
        MissingManifest {
            description("missing manifest")
            display("Your Cargo.toml is missing.")
        }
        /// The TOML table could not be found.
        NonExistentTable(table: String) {
            description("non existent table")
            display("The table `{}` could not be found.", table)
        }
        /// The dependency could not be found.
        NonExistentDependency(name: String, table: String) {
            description("non existent dependency")
            display("The dependency `{}` could not be found in `{}`.", name, table)
        }
    }
}

enum CargoFile {
    Config,
    Lock,
}

/// A Cargo Manifest
#[derive(Debug, PartialEq)]
pub struct Manifest {
    /// Manifest contents as TOML data
    pub data: toml::Table,
}

/// If a manifest is specified, return that one, otherise perform a manifest search starting from
/// the current directory.
/// If a manifest is specified, return that one. If a path is specified, perform a manifest search
/// starting from there. If nothing is specified, start searching from the current directory
/// (`cwd`).
fn find(specified: &Option<&str>, file: CargoFile) -> Result<PathBuf, Box<Error>> {
    let file_path = specified.map(PathBuf::from);

    if let Some(path) = file_path {
        if try!(fs::metadata(&path)).is_file() {
            Ok(path)
        } else {
            search(&path, file).map_err(From::from)
        }
    } else {
        env::current_dir()
            .map_err(From::from)
            .and_then(|ref dir| search(dir, file).map_err(From::from))
    }
}

/// Search for Cargo.toml in this directory and recursively up the tree until one is found.
fn search(dir: &Path, file: CargoFile) -> Result<PathBuf, ManifestError> {
    let manifest = match file {
        CargoFile::Config => dir.join("Cargo.toml"),
        CargoFile::Lock => dir.join("Cargo.lock"),
    };

    fs::metadata(&manifest)
        .map(|_| manifest)
        .or(dir.parent().ok_or(ManifestError::MissingManifest).and_then(|dir| search(dir, file)))
}

impl Manifest {
    /// Look for a `Cargo.toml` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process's working directory is used as a starting point.
    pub fn find_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Config).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Look for a `Cargo.lock` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process' working directory is used as a starting point.
    pub fn find_lock_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Lock).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Open the `Cargo.toml` for a path (or the process' `cwd`)
    pub fn open(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Open the `Cargo.lock` for a path (or the process' `cwd`)
    pub fn open_lock_file(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_lock_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Overwrite a file with TOML data.
    pub fn write_to_file(&self, file: &mut File) -> Result<(), Box<Error>> {
        let mut toml = self.data.clone();

        let (proj_header, proj_data) = try!(toml.remove("package")
                                                .map(|data| ("package", data))
                                                .or_else(|| {
                                                    toml.remove("project")
                                                        .map(|data| ("project", data))
                                                })
                                                .ok_or(ManifestError::MissingManifest));

        let new_contents = format!(
          "[{}]\n{}{}",
          proj_header,
          proj_data,
          toml::Value::Table(toml)
        );
        let new_contents_bytes = new_contents.as_bytes();

        // We need to truncate the file, otherwise the new contents
        // will be mixed up with the old ones.
        file.set_len(new_contents_bytes.len() as u64).unwrap();
        file.write_all(new_contents_bytes)
            .map_err(From::from)
    }

    /// Add entry to a Cargo.toml.
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn insert_into_table(&mut self,
                             table: &str,
                             &(ref name, ref data): &Dependency)
                             -> Result<(), ManifestError> {
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table))
                            .or_insert(toml::Value::Table(BTreeMap::new()));
        match *entry {
            toml::Value::Table(ref mut deps) => {
                deps.insert(name.clone(), data.clone());
                Ok(())
            }
            _ => Err(ManifestError::NonExistentTable(table.into())),
        }
    }

    /// Remove entry from a Cargo.toml.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate cargo_edit;
    /// # extern crate toml;
    /// # fn main() {
    ///     use cargo_edit::Manifest;
    ///     use toml;
    ///
    ///     let mut manifest = Manifest { data: toml::Table::new() };
    ///     let dep = ("cargo-edit".to_owned(), toml::Value::String("0.1.0".to_owned()));
    ///     let _ = manifest.insert_into_table("dependencies", &dep);
    ///     assert!(manifest.remove_from_table("dependencies", &dep.0).is_ok());
    ///     assert!(manifest.remove_from_table("dependencies", &dep.0).is_err());
    /// # }
    /// ```
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn remove_from_table(&mut self, table: &str, name: &str) -> Result<(), ManifestError> {
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table));

        match entry {
            Entry::Vacant(_) => Err(ManifestError::NonExistentTable(table.into())),
            Entry::Occupied(entry) => {
                match *entry.into_mut() {
                    toml::Value::Table(ref mut deps) => {
                        deps.remove(name)
                            .map(|_| ())
                            .ok_or(ManifestError::NonExistentDependency(name.into(), table.into()))
                    }
                    _ => Err(ManifestError::NonExistentTable(table.into())),
                }
            }
        }
    }

    /// Add multiple dependencies to manifest
    pub fn add_deps(&mut self, table: &str, deps: &[Dependency]) -> Result<(), Box<Error>> {
        deps.iter()
            .map(|dep| self.insert_into_table(table, &dep))
            .collect::<Result<Vec<_>, _>>()
            .map_err(From::from)
            .map(|_| ())
    }
}

impl str::FromStr for Manifest {
    type Err = Box<Error>;

    /// Read manifest data from string
    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = toml::Parser::new(&input);

        parser.parse()
              .ok_or(parser.errors.pop())
              .map_err(Option::unwrap)
              .map_err(From::from)
              .map(|data| Manifest { data: data })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::BTreeMap;
    use toml;

    #[test]
    fn add_remove_dependency() {
        let mut manifest = Manifest { data: toml::Table::new() };
        // Create a copy containing empty "dependencies" table because removing
        //   the last entry in a table does not remove the section.
        let mut copy = Manifest { data: toml::Table::new() };
        copy.data.insert("dependencies".to_owned(),
                         toml::Value::Table(BTreeMap::new()));
        let dep = ("cargo-edit".to_owned(),
                   toml::Value::String("0.1.0".to_owned()));
        let _ = manifest.insert_into_table("dependencies", &dep);
        assert!(manifest.remove_from_table("dependencies", &dep.0).is_ok());
        assert_eq!(manifest, copy);
    }

    #[test]
    fn remove_dependency_no_section() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = ("cargo-edit".to_owned(),
                   toml::Value::String("0.1.0".to_owned()));
        assert!(manifest.remove_from_table("dependencies", &dep.0).is_err());
    }

    #[test]
    fn remove_dependency_non_existent() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = ("cargo-edit".to_owned(),
                   toml::Value::String("0.1.0".to_owned()));
        let other_dep = ("other-dep".to_owned(),
                         toml::Value::String("0.1.0".to_owned()));
        let _ = manifest.insert_into_table("dependencies", &other_dep);
        assert!(manifest.remove_from_table("dependencies", &dep.0).is_err());

    }
}
<|endoftext|>


<commit_before>#![allow(unused)]

use std;
use tokio_core::reactor::{Handle};
use futures;
use futures::future::Future;
use futures::{oneshot,Complete,Oneshot};
use futures::unsync::oneshot::{Receiver,Sender,channel};
use futures::sink::Sink;
use futures::stream::Stream;
use tokio_io::{self,AsyncRead,AsyncWrite};
use std::io::{Read,Write};
use std::io::Result as IoResult;
use std::net::SocketAddr;

use std::rc::Rc;
use std::cell::RefCell;

use futures::Async::{Ready, NotReady};

use tokio_core::net::{TcpStream, TcpListener, UdpSocket};

use super::{Peer, io_other_error, brokenpipe, wouldblock, BoxedNewPeerFuture, BoxedNewPeerStream, peer_err, peer_err_s, box_up_err};
use super::{once,multi,Specifier,ProgramState,PeerConstructor,Options};

#[derive(Debug,Clone)]
pub struct TcpConnect(pub SocketAddr);
impl Specifier for TcpConnect {
    fn construct(&self, h:&Handle, _: &mut ProgramState, _opts: &Options) -> PeerConstructor {
        once(tcp_connect_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

#[derive(Debug,Clone)]
pub struct TcpListen(pub SocketAddr);
impl Specifier for TcpListen {
    fn construct(&self, h:&Handle, _: &mut ProgramState, _opts: &Options) -> PeerConstructor {
        multi(tcp_listen_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate multiconnect no_subspec typ=Other);
}

#[derive(Debug,Clone)]
pub struct UdpConnect(pub SocketAddr);
impl Specifier for UdpConnect {
    fn construct(&self, h:&Handle, _: &mut ProgramState, _opts: &Options) -> PeerConstructor {
        once(udp_connect_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

#[derive(Debug,Clone)]
pub struct UdpListen(pub SocketAddr);
impl Specifier for UdpListen {
    fn construct(&self, h:&Handle, _: &mut ProgramState, _opts: &Options) -> PeerConstructor {
        once(udp_listen_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

/*
struct RcReadProxy<R>(Rc<R>) where for<'a> &'a R : AsyncRead;

impl<R> AsyncRead for RcReadProxy<R> where for<'a> &'a R : AsyncRead{}
impl<R> Read for RcReadProxy<R> where for<'a> &'a R : AsyncRead {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        (&*self.0).read(buf)
    }
}

struct RcWriteProxy<W>(Rc<W>) where for<'a> &'a W : AsyncWrite;

impl<W> AsyncWrite for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        (&*self.0).shutdown()
    }
}
impl<W> Write for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }
    fn flush(&mut self) -> IoResult<()> {
        (&*self.0).flush()
    }
}
*/

// based on https://github.com/tokio-rs/tokio-core/blob/master/examples/proxy.rs
#[derive(Clone)]
struct MyTcpStream(Rc<TcpStream>, bool);

impl Read for MyTcpStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for MyTcpStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for MyTcpStream {}

impl AsyncWrite for MyTcpStream {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        try!(self.0.shutdown(std::net::Shutdown::Write));
        Ok(().into())
    }
}

impl Drop for MyTcpStream {
    fn drop(&mut self) {
        let i_am_read_part = self.1;
        if i_am_read_part {
            let _ = self.0.shutdown(std::net::Shutdown::Read);
        }
    }
}

pub fn tcp_connect_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerFuture {
    Box::new(
        TcpStream::connect(&addr, handle).map(|x| {
            info!("Connected to TCP");
            let x = Rc::new(x);
            Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
        }).map_err(box_up_err)
    ) as BoxedNewPeerFuture
}

pub fn tcp_listen_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerStream {
    let bound = match TcpListener::bind(&addr, handle) {
        Ok(x) => x,
        Err(e) => return peer_err_s(e),
    };
    Box::new(
        bound
        .incoming()
        .map(|(x, _addr)| {
            info!("Incoming TCP connection");
            let x = Rc::new(x);
            Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
        })
        .map_err(|e|box_up_err(e))
    ) as BoxedNewPeerStream
}

#[derive(Debug)]
enum UdpPeerState {
    ConnectMode,
    WaitingForAddress((Sender<()>,Receiver<()>)),
    HasAddress(SocketAddr),
}

struct UdpPeer {
    s : UdpSocket,
    state: Option<UdpPeerState>,
}

#[derive(Clone)]
struct UdpPeerHandle(Rc<RefCell<UdpPeer>>);

fn get_zero_address(addr:&SocketAddr) -> SocketAddr {
    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
    let ip = match addr.ip() {
        IpAddr::V4(_) => IpAddr::V4(Ipv4Addr::new(0,0,0,0)),
        IpAddr::V6(_) => IpAddr::V6(Ipv6Addr::new(0,0,0,0,0,0,0,0)),
    };
    SocketAddr::new(ip, 0)
}

pub fn udp_connect_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerFuture {
    let za = get_zero_address(addr);

    Box::new(
        futures::future::result(
            UdpSocket::bind(&za, handle).and_then(|x| {
                x.connect(addr)?;

                let h1 = UdpPeerHandle(Rc::new(RefCell::new(
                UdpPeer {
                    s: x,
                    state: Some(UdpPeerState::ConnectMode),
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            }).map_err(box_up_err)
        )
    ) as BoxedNewPeerFuture
}

pub fn udp_listen_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerFuture {
    Box::new(
        futures::future::result(
            UdpSocket::bind(addr, handle).and_then(|x| {
                let h1 = UdpPeerHandle(Rc::new(RefCell::new(
                UdpPeer {
                    s: x,
                    state: Some(UdpPeerState::WaitingForAddress(channel())),
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            }).map_err(box_up_err)
        )
    ) as BoxedNewPeerFuture
}

impl Read for UdpPeerHandle {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        eprintln!("read {:?}", p.state);
        match p.state.take().expect("Assertion failed 193912") {
            UdpPeerState::ConnectMode => {
                p.state = Some(UdpPeerState::ConnectMode);
                p.s.recv(buf)
            },
            UdpPeerState::HasAddress(oldaddr) => p.s.recv_from(buf).map(|(ret,addr)| {
                warn!("New client for the same listening UDP socket");
                p.state = Some(UdpPeerState::HasAddress(addr));
                ret
            }).map_err(|e| {
                p.state = Some(UdpPeerState::HasAddress(oldaddr));
                e
            }),
            UdpPeerState::WaitingForAddress((cmpl,pollster)) =>
                match p.s.recv_from(buf)
                {
                    Ok((ret,addr)) => {
                        p.state = Some(UdpPeerState::HasAddress(addr));
                        cmpl.send(());
                        Ok(ret)
                    },
                    Err(e) => {
                        p.state = Some(UdpPeerState::WaitingForAddress((cmpl,pollster)));
                        Err(e)
                    },
                },
        }
    }
}

impl Write for UdpPeerHandle {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        eprintln!("write {:?}", p.state);
        match p.state.take().expect("Assertion failed 193913") {
            UdpPeerState::ConnectMode => {
                p.state = Some(UdpPeerState::ConnectMode);
                p.s.send(buf)
            },
            UdpPeerState::HasAddress(a) => {
                p.state = Some(UdpPeerState::HasAddress(a));
                p.s.send_to(buf, &a)
            },
            UdpPeerState::WaitingForAddress((cmpl,mut pollster)) => {
                pollster.poll(); // register wakeup
                p.state = Some(UdpPeerState::WaitingForAddress((cmpl,pollster)));
                wouldblock()
            },
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for UdpPeerHandle {}

impl AsyncWrite for UdpPeerHandle {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        Ok(().into())
    }
}

<commit_msg>cleanup net_peer<commit_after>use std;
use tokio_core::reactor::{Handle};
use futures;
use futures::future::Future;
use futures::unsync::oneshot::{Receiver,Sender,channel};
use futures::stream::Stream;
use tokio_io::{AsyncRead,AsyncWrite};
use std::io::{Read,Write};
use std::io::Result as IoResult;
use std::net::SocketAddr;

use std::rc::Rc;
use std::cell::RefCell;

use tokio_core::net::{TcpStream, TcpListener, UdpSocket};

use super::{Peer, wouldblock, BoxedNewPeerFuture, BoxedNewPeerStream, peer_err_s, box_up_err};
use super::{once,multi,Specifier,ProgramState,PeerConstructor,Options};

#[derive(Debug,Clone)]
pub struct TcpConnect(pub SocketAddr);
impl Specifier for TcpConnect {
    fn construct(&self, h:&Handle, _: &mut ProgramState, _opts: &Options) -> PeerConstructor {
        once(tcp_connect_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

#[derive(Debug,Clone)]
pub struct TcpListen(pub SocketAddr);
impl Specifier for TcpListen {
    fn construct(&self, h:&Handle, _: &mut ProgramState, _opts: &Options) -> PeerConstructor {
        multi(tcp_listen_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate multiconnect no_subspec typ=Other);
}

#[derive(Debug,Clone)]
pub struct UdpConnect(pub SocketAddr);
impl Specifier for UdpConnect {
    fn construct(&self, h:&Handle, _: &mut ProgramState, _opts: &Options) -> PeerConstructor {
        once(udp_connect_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

#[derive(Debug,Clone)]
pub struct UdpListen(pub SocketAddr);
impl Specifier for UdpListen {
    fn construct(&self, h:&Handle, _: &mut ProgramState, _opts: &Options) -> PeerConstructor {
        once(udp_listen_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

/*
struct RcReadProxy<R>(Rc<R>) where for<'a> &'a R : AsyncRead;

impl<R> AsyncRead for RcReadProxy<R> where for<'a> &'a R : AsyncRead{}
impl<R> Read for RcReadProxy<R> where for<'a> &'a R : AsyncRead {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        (&*self.0).read(buf)
    }
}

struct RcWriteProxy<W>(Rc<W>) where for<'a> &'a W : AsyncWrite;

impl<W> AsyncWrite for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        (&*self.0).shutdown()
    }
}
impl<W> Write for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }
    fn flush(&mut self) -> IoResult<()> {
        (&*self.0).flush()
    }
}
*/

// based on https://github.com/tokio-rs/tokio-core/blob/master/examples/proxy.rs
#[derive(Clone)]
struct MyTcpStream(Rc<TcpStream>, bool);

impl Read for MyTcpStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for MyTcpStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for MyTcpStream {}

impl AsyncWrite for MyTcpStream {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        try!(self.0.shutdown(std::net::Shutdown::Write));
        Ok(().into())
    }
}

impl Drop for MyTcpStream {
    fn drop(&mut self) {
        let i_am_read_part = self.1;
        if i_am_read_part {
            let _ = self.0.shutdown(std::net::Shutdown::Read);
        }
    }
}

pub fn tcp_connect_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerFuture {
    Box::new(
        TcpStream::connect(&addr, handle).map(|x| {
            info!("Connected to TCP");
            let x = Rc::new(x);
            Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
        }).map_err(box_up_err)
    ) as BoxedNewPeerFuture
}

pub fn tcp_listen_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerStream {
    let bound = match TcpListener::bind(&addr, handle) {
        Ok(x) => x,
        Err(e) => return peer_err_s(e),
    };
    Box::new(
        bound
        .incoming()
        .map(|(x, _addr)| {
            info!("Incoming TCP connection");
            let x = Rc::new(x);
            Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
        })
        .map_err(|e|box_up_err(e))
    ) as BoxedNewPeerStream
}

#[derive(Debug)]
enum UdpPeerState {
    ConnectMode,
    WaitingForAddress((Sender<()>,Receiver<()>)),
    HasAddress(SocketAddr),
}

struct UdpPeer {
    s : UdpSocket,
    state: Option<UdpPeerState>,
}

#[derive(Clone)]
struct UdpPeerHandle(Rc<RefCell<UdpPeer>>);

fn get_zero_address(addr:&SocketAddr) -> SocketAddr {
    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
    let ip = match addr.ip() {
        IpAddr::V4(_) => IpAddr::V4(Ipv4Addr::new(0,0,0,0)),
        IpAddr::V6(_) => IpAddr::V6(Ipv6Addr::new(0,0,0,0,0,0,0,0)),
    };
    SocketAddr::new(ip, 0)
}

pub fn udp_connect_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerFuture {
    let za = get_zero_address(addr);

    Box::new(
        futures::future::result(
            UdpSocket::bind(&za, handle).and_then(|x| {
                x.connect(addr)?;

                let h1 = UdpPeerHandle(Rc::new(RefCell::new(
                UdpPeer {
                    s: x,
                    state: Some(UdpPeerState::ConnectMode),
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            }).map_err(box_up_err)
        )
    ) as BoxedNewPeerFuture
}

pub fn udp_listen_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerFuture {
    Box::new(
        futures::future::result(
            UdpSocket::bind(addr, handle).and_then(|x| {
                let h1 = UdpPeerHandle(Rc::new(RefCell::new(
                UdpPeer {
                    s: x,
                    state: Some(UdpPeerState::WaitingForAddress(channel())),
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            }).map_err(box_up_err)
        )
    ) as BoxedNewPeerFuture
}

impl Read for UdpPeerHandle {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        eprintln!("read {:?}", p.state);
        match p.state.take().expect("Assertion failed 193912") {
            UdpPeerState::ConnectMode => {
                p.state = Some(UdpPeerState::ConnectMode);
                p.s.recv(buf)
            },
            UdpPeerState::HasAddress(oldaddr) => p.s.recv_from(buf).map(|(ret,addr)| {
                warn!("New client for the same listening UDP socket");
                p.state = Some(UdpPeerState::HasAddress(addr));
                ret
            }).map_err(|e| {
                p.state = Some(UdpPeerState::HasAddress(oldaddr));
                e
            }),
            UdpPeerState::WaitingForAddress((cmpl,pollster)) =>
                match p.s.recv_from(buf)
                {
                    Ok((ret,addr)) => {
                        p.state = Some(UdpPeerState::HasAddress(addr));
                        let _ = cmpl.send(());
                        Ok(ret)
                    },
                    Err(e) => {
                        p.state = Some(UdpPeerState::WaitingForAddress((cmpl,pollster)));
                        Err(e)
                    },
                },
        }
    }
}

impl Write for UdpPeerHandle {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        eprintln!("write {:?}", p.state);
        match p.state.take().expect("Assertion failed 193913") {
            UdpPeerState::ConnectMode => {
                p.state = Some(UdpPeerState::ConnectMode);
                p.s.send(buf)
            },
            UdpPeerState::HasAddress(a) => {
                p.state = Some(UdpPeerState::HasAddress(a));
                p.s.send_to(buf, &a)
            },
            UdpPeerState::WaitingForAddress((cmpl,mut pollster)) => {
                let _ = pollster.poll(); // register wakeup
                p.state = Some(UdpPeerState::WaitingForAddress((cmpl,pollster)));
                wouldblock()
            },
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for UdpPeerHandle {}

impl AsyncWrite for UdpPeerHandle {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        Ok(().into())
    }
}

<|endoftext|>


<commit_before>use util::{
    bitfields,
    bits::Bits,
    fixedpoint::{FixedPoint16, FixedPoint32},
    mem::read_u16,
    primitive_enum,
};

use super::line::LineBuffer;
use crate::{
    memory::{
        io::{IoRegisters, ObjCharVramMapping},
        OAM_SIZE, VRAM_SIZE,
    },
    video::line::{PixelAttrs, OBJ},
};

pub fn render(
    line: u16,
    buf: &mut LineBuffer,
    ioregs: &IoRegisters,
    oam: &[u8; OAM_SIZE as usize],
    vram: &[u8; VRAM_SIZE as usize],
) {
    let mut cycles = if ioregs.dispcnt.hblank_interval_free() {
        954
    } else {
        1210
    };

    let mut objects = [0u8; 128];
    let mut visible_objects = 0;
    let mut disabled_idx = 128;
    (0..128).rev().for_each(|obj_idx| {
        let attrs_index = obj_idx as usize * 8;
        let attr0 = ObjAttr0::new(read_u16(oam, attrs_index));
        if attr0.disabled() && !attr0.rotscale() {
            disabled_idx -= 1;
            objects[disabled_idx] = 0xFF;
            return;
        }
        objects[visible_objects] = obj_idx as u8;
        visible_objects += 1;
    });
    let objects = &mut objects[..visible_objects];
    objects.sort_unstable_by(|&ol, &or| {
        let attrs_index_lhs = ol as usize * 8;
        let attr2_lhs = ObjAttr2::new(read_u16(oam, attrs_index_lhs + 4));
        let attrs_index_rhs = or as usize * 8;
        let attr2_rhs = ObjAttr2::new(read_u16(oam, attrs_index_rhs + 4));

        attr2_rhs
            .priority()
            .cmp(&attr2_lhs.priority())
            .then(or.cmp(&ol))
    });

    for &mut obj_idx in objects {
        if cycles == 0 {
            break;
        }

        let attrs_index = obj_idx as usize * 8;
        let attr0 = ObjAttr0::new(read_u16(oam, attrs_index));
        if attr0.disabled() && !attr0.rotscale() {
            continue;
        }
        let attr1 = ObjAttr1::new(read_u16(oam, attrs_index + 2));
        let attr2 = ObjAttr2::new(read_u16(oam, attrs_index + 4));

        let (width, height) = attr1.size(attr0.shape());
        let (display_width, display_height) = if attr0.rotscale() && attr0.double_size() {
            (width * 2, height * 2)
        } else {
            (width, height)
        };

        let mut left = attr1.x();
        let top = attr0.y();
        let bottom = (top + display_height - 1) % 256;

        let in_bounds_vertical = top <= bottom && top <= line && bottom >= line;
        let in_bounds_vertical_wrapped = top > bottom && (top <= line || bottom >= line);
        if !in_bounds_vertical && !in_bounds_vertical_wrapped {
            continue;
        }

        let mut right = if let Some(right) =
            consume_obj_cycles(&mut cycles, attr0.rotscale(), display_width, left)
        {
            right
        } else {
            break;
        };

        let in_bounds_horizontal = left < 240 || right < 240;
        if !in_bounds_horizontal {
            continue;
        }

        let origin_x = FixedPoint32::from(display_width / 2);
        let origin_y = FixedPoint32::from(display_height / 2);
        let xdraw_start;
        if left < right {
            xdraw_start = FixedPoint32::from(0u32);
            right = right.min(239);
        } else {
            // we have wrapped here so we need to start drawing farther to the right
            // of the object, but there will always be enough space on screen to draw the
            // object to the end.
            left = 0;
            xdraw_start = FixedPoint32::from(display_width - right - 1);
        }
        let ydraw_start = FixedPoint32::from(if line > bottom {
            line - top
        } else {
            display_height - (bottom - line) - 1
        });

        let mut xdraw_start_distance = xdraw_start - origin_x;
        let mut ydraw_start_distance = ydraw_start - origin_y;

        let (dx, dmx, dy, dmy);

        if attr0.rotscale() {
            let params_idx = attr1.rotscale_param() as usize;
            dx = FixedPoint32::from(FixedPoint16::raw(
                (read_u16(oam, 0x06 + (params_idx * 32))) as i16,
            ));
            dmx = FixedPoint32::from(FixedPoint16::raw(
                (read_u16(oam, 0x0E + (params_idx * 32))) as i16,
            ));
            dy = FixedPoint32::from(FixedPoint16::raw(
                (read_u16(oam, 0x16 + (params_idx * 32))) as i16,
            ));
            dmy = FixedPoint32::from(FixedPoint16::raw(
                (read_u16(oam, 0x1E + (params_idx * 32))) as i16,
            ));
        } else {
            dy = FixedPoint32::from(0u32);
            dmx = FixedPoint32::from(0u32);
            dmy = FixedPoint32::from(1u32);

            if attr1.horizontal_flip() {
                dx = FixedPoint32::from(-1i32);
                // NOTE: add 1 so that we start on the other side of the center line.
                xdraw_start_distance += FixedPoint32::from(1u32);
            } else {
                dx = FixedPoint32::from(1u32);
            }

            if attr1.vertical_flip() {
                ydraw_start_distance = -ydraw_start_distance;
            }
        }

        // Down here we use the real width and height for the origin instead of the double sized
        // because I randomly wrote it and it works. Maybe one day I'll actually do the math and
        // come up with an exact reason as to why. For now I just had a feeling and I was right.
        let mut x = FixedPoint32::from(width / 2)
            + (ydraw_start_distance * dmx)
            + (xdraw_start_distance * dx);
        let mut y = FixedPoint32::from(height / 2)
            + (ydraw_start_distance * dmy)
            + (xdraw_start_distance * dy);

        let tile_data = &vram[0x10000..];

        // The number of characters (tiles) we have to jump to reach the next
        // line of the object.
        let char_stride: usize =
            if ioregs.dispcnt.obj_char_vram_mapping() == ObjCharVramMapping::OneDimensional {
                width as usize / 8
            } else if attr0.palette256() {
                16
            } else {
                32
            };
        let first_tile_index = attr2.character_name() as usize;
        let mode = attr0.mode();

        let mut attrs = PixelAttrs::default();
        if ioregs.bldcnt.is_first_target(OBJ) {
            attrs.set_first_target();
        }
        if ioregs.bldcnt.is_second_target(OBJ) {
            attrs.set_second_target();
        }
        if mode == ObjMode::SemiTransparent {
            attrs.set_semi_transparent();
        }

        let mut mosaic_x = 0usize;
        let mut mosaic_y = 0usize;

        if attr0.mosaic() {
            mosaic_x = ioregs.mosaic.obj_h() as usize + 1;
            mosaic_y = ioregs.mosaic.obj_v() as usize + 1;
        }

        if attr0.palette256() {
            const BYTES_PER_LINE: usize = 8;
            const BYTES_PER_TILE: usize = 64;

            let width = width as usize;
            let height = height as usize;

            attrs.set_8bpp();
            attrs.set_priority(attr2.priority());

            for screen_x in left as usize..=right as usize {
                let mut xi = x.integer() as usize;
                let mut yi = y.integer() as usize;
                if xi < width && yi < height {
                    if mosaic_x > 0 {
                        xi -= xi % mosaic_x;
                    }

                    if mosaic_y > 0 {
                        yi -= yi % mosaic_y;
                    }

                    // FIXME Lower bit of the tile should be ignored. From GBATEK:
                    //
                    //     When using the 256 Colors/1 Palette mode, only each second tile may be used,
                    //     the lower bit of the tile number should be zero (in 2-dimensional mapping mode,
                    //     the bit is completely ignored).
                    let tile =
                        (((first_tile_index / 2) as usize) + ((yi / 8) * char_stride) + (xi / 8))
                            & 0x3FF;

                    // When using BG Mode 3-5 (Bitmap Modes), only tile numbers 512-1023 may be used.
                    // That is because lower 16K of OBJ memory are used for BG. Attempts to use tiles 0-511 are ignored (not displayed).
                    if tile < 512 && ioregs.dispcnt.is_bitmap_mode() {
                        continue;
                    }

                    let pixel_offset =
                        (tile * BYTES_PER_TILE) + ((yi % 8) * BYTES_PER_LINE) + (xi % 8);
                    let entry = tile_data[pixel_offset as usize];

                    if mode != ObjMode::ObjWindow {
                        buf.put_obj_8bpp(attrs, screen_x, entry);
                    } else if entry != 0 {
                        buf.put_obj_window(screen_x);
                    }
                }

                x += dx;
                y += dy;
            }
        } else {
            const BYTES_PER_LINE: usize = 4;
            const BYTES_PER_TILE: usize = 32;

            let width = width as usize;
            let height = height as usize;

            attrs.set_4bpp();
            attrs.set_priority(attr2.priority());

            for screen_x in left as usize..=right as usize {
                let mut xi = x.integer() as usize;
                let mut yi = y.integer() as usize;
                if xi < width && yi < height {
                    if mosaic_x > 0 {
                        xi -= xi % mosaic_x;
                    }

                    if mosaic_y > 0 {
                        yi -= yi % mosaic_y;
                    }

                    let tile = (first_tile_index + ((yi / 8) * char_stride) + (xi / 8)) & 0x3FF;
                    let pixel_offset =
                        (tile * BYTES_PER_TILE) + ((yi % 8) * BYTES_PER_LINE) + (xi % 8) / 2;
                    let entry = (tile_data[pixel_offset] >> ((xi % 2) << 2)) & 0xF;

                    if mode != ObjMode::ObjWindow {
                        buf.put_obj_4bpp(attrs, screen_x, attr2.palette() as _, entry);
                    } else if entry != 0 {
                        buf.put_obj_window(screen_x);
                    }
                }

                x += dx;
                y += dy;
            }
        }
    }
}

/// Consumes the cycles required to render and object line and returns the rightmost pixel's
/// x position if there were enough cycles to render an object at all.
fn consume_obj_cycles(cycles: &mut u16, rs: bool, width: u16, left: u16) -> Option<u16> {
    let right;
    if rs {
        // affine objects require 10 cycles to start
        *cycles = cycles.saturating_sub(10);
        if *cycles == 0 {
            return None;
        }

        if width * 2 > *cycles {
            right = (left + (*cycles / 2)) % 512;
            *cycles = 0;
        } else {
            right = (left + width) % 512;
            *cycles -= width * 2;
        }
    } else if width > *cycles {
        right = (left + *cycles - 1) % 512;
        *cycles = 0;
    } else {
        right = (left + width - 1) % 512;
        *cycles -= width;
    }

    Some(right)
}

bitfields! {
    struct ObjAttr0: u16 {
        [0,7]   y, set_y: u16,
        [8]     rotscale, set_rotscale: bool,

        // When rotscale flag is set:
        [9]     double_size, set_double_size: bool,

        // When rotscale flag is clear:
        [9]     disabled, set_disabled: bool,

        [10,11] mode, set_mode: ObjMode,
        [12]    mosaic, set_mosaic: bool,
        [13]    palette256, set_palette256: bool,
        [14,15] shape, set_shape: ObjShape,
    }
}

bitfields! {
    struct ObjAttr1: u16 {
        [0,8]   x, set_x: u16,

        // When rotsccale flag is set in attr0:
        [9,13]  rotscale_param, set_rotscale_param: u16,

        // When rotscale flag is clear in attr0:
        [12]    horizontal_flip, set_horizontal: bool,
        [13]    vertical_flip, set_vertical_flip: bool,
    }
}

impl ObjAttr1 {
    pub fn size(&self, shape: ObjShape) -> (u16, u16) {
        //  Size  Square   Horizontal  Vertical
        //  0     8x8      16x8        8x16
        //  1     16x16    32x8        8x32
        //  2     32x32    32x16       16x32
        //  3     64x64    64x32       32x64
        match (self.value.bits(14, 15), shape) {
            (0, ObjShape::Square) => (8, 8),
            (1, ObjShape::Square) => (16, 16),
            (2, ObjShape::Square) => (32, 32),
            (3, ObjShape::Square) => (64, 64),

            (0, ObjShape::Horizontal) => (16, 8),
            (1, ObjShape::Horizontal) => (32, 8),
            (2, ObjShape::Horizontal) => (32, 16),
            (3, ObjShape::Horizontal) => (64, 32),

            (0, ObjShape::Vertical) => (8, 16),
            (1, ObjShape::Vertical) => (8, 32),
            (2, ObjShape::Vertical) => (16, 32),
            (3, ObjShape::Vertical) => (32, 64),

            _ => (8, 8),
        }
    }
}

bitfields! {
    struct ObjAttr2: u16 {
        [0,9]   character_name, set_character_name: u16,
        [10,11] priority, set_priority: u16,
        [12,15] palette, set_palette: u16,
    }
}

primitive_enum! {
    pub enum ObjMode: u16 {
        Normal,
        SemiTransparent,
        ObjWindow,
        Invalid,
    }
}

primitive_enum! {
    pub enum ObjShape: u16 {
        Square,
        Horizontal,
        Vertical,
        Prohibited,
    }
}
<commit_msg>Remove unnecessary enabled check at the start of object loop.<commit_after>use util::{
    bitfields,
    bits::Bits,
    fixedpoint::{FixedPoint16, FixedPoint32},
    mem::read_u16,
    primitive_enum,
};

use super::line::LineBuffer;
use crate::{
    memory::{
        io::{IoRegisters, ObjCharVramMapping},
        OAM_SIZE, VRAM_SIZE,
    },
    video::line::{PixelAttrs, OBJ},
};

pub fn render(
    line: u16,
    buf: &mut LineBuffer,
    ioregs: &IoRegisters,
    oam: &[u8; OAM_SIZE as usize],
    vram: &[u8; VRAM_SIZE as usize],
) {
    let mut cycles = if ioregs.dispcnt.hblank_interval_free() {
        954
    } else {
        1210
    };

    let mut objects = [0u8; 128];
    let mut visible_objects = 0;
    let mut disabled_idx = 128;
    (0..128).rev().for_each(|obj_idx| {
        let attrs_index = obj_idx as usize * 8;
        let attr0 = ObjAttr0::new(read_u16(oam, attrs_index));
        if attr0.disabled() && !attr0.rotscale() {
            disabled_idx -= 1;
            objects[disabled_idx] = 0xFF;
            return;
        }
        objects[visible_objects] = obj_idx as u8;
        visible_objects += 1;
    });
    let objects = &mut objects[..visible_objects];
    objects.sort_unstable_by(|&ol, &or| {
        let attrs_index_lhs = ol as usize * 8;
        let attr2_lhs = ObjAttr2::new(read_u16(oam, attrs_index_lhs + 4));
        let attrs_index_rhs = or as usize * 8;
        let attr2_rhs = ObjAttr2::new(read_u16(oam, attrs_index_rhs + 4));

        attr2_rhs
            .priority()
            .cmp(&attr2_lhs.priority())
            .then(or.cmp(&ol))
    });

    for &mut obj_idx in objects {
        if cycles == 0 {
            break;
        }

        let attrs_index = obj_idx as usize * 8;
        let attr0 = ObjAttr0::new(read_u16(oam, attrs_index));
        let attr1 = ObjAttr1::new(read_u16(oam, attrs_index + 2));
        let attr2 = ObjAttr2::new(read_u16(oam, attrs_index + 4));

        let (width, height) = attr1.size(attr0.shape());
        let (display_width, display_height) = if attr0.rotscale() && attr0.double_size() {
            (width * 2, height * 2)
        } else {
            (width, height)
        };

        let mut left = attr1.x();
        let top = attr0.y();
        let bottom = (top + display_height - 1) % 256;

        let in_bounds_vertical = top <= bottom && top <= line && bottom >= line;
        let in_bounds_vertical_wrapped = top > bottom && (top <= line || bottom >= line);
        if !in_bounds_vertical && !in_bounds_vertical_wrapped {
            continue;
        }

        let mut right = if let Some(right) =
            consume_obj_cycles(&mut cycles, attr0.rotscale(), display_width, left)
        {
            right
        } else {
            break;
        };

        let in_bounds_horizontal = left < 240 || right < 240;
        if !in_bounds_horizontal {
            continue;
        }

        let origin_x = FixedPoint32::from(display_width / 2);
        let origin_y = FixedPoint32::from(display_height / 2);
        let xdraw_start;
        if left < right {
            xdraw_start = FixedPoint32::from(0u32);
            right = right.min(239);
        } else {
            // we have wrapped here so we need to start drawing farther to the right
            // of the object, but there will always be enough space on screen to draw the
            // object to the end.
            left = 0;
            xdraw_start = FixedPoint32::from(display_width - right - 1);
        }
        let ydraw_start = FixedPoint32::from(if line > bottom {
            line - top
        } else {
            display_height - (bottom - line) - 1
        });

        let mut xdraw_start_distance = xdraw_start - origin_x;
        let mut ydraw_start_distance = ydraw_start - origin_y;

        let (dx, dmx, dy, dmy);

        if attr0.rotscale() {
            let params_idx = attr1.rotscale_param() as usize;
            dx = FixedPoint32::from(FixedPoint16::raw(
                (read_u16(oam, 0x06 + (params_idx * 32))) as i16,
            ));
            dmx = FixedPoint32::from(FixedPoint16::raw(
                (read_u16(oam, 0x0E + (params_idx * 32))) as i16,
            ));
            dy = FixedPoint32::from(FixedPoint16::raw(
                (read_u16(oam, 0x16 + (params_idx * 32))) as i16,
            ));
            dmy = FixedPoint32::from(FixedPoint16::raw(
                (read_u16(oam, 0x1E + (params_idx * 32))) as i16,
            ));
        } else {
            dy = FixedPoint32::from(0u32);
            dmx = FixedPoint32::from(0u32);
            dmy = FixedPoint32::from(1u32);

            if attr1.horizontal_flip() {
                dx = FixedPoint32::from(-1i32);
                // NOTE: add 1 so that we start on the other side of the center line.
                xdraw_start_distance += FixedPoint32::from(1u32);
            } else {
                dx = FixedPoint32::from(1u32);
            }

            if attr1.vertical_flip() {
                ydraw_start_distance = -ydraw_start_distance;
            }
        }

        // Down here we use the real width and height for the origin instead of the double sized
        // because I randomly wrote it and it works. Maybe one day I'll actually do the math and
        // come up with an exact reason as to why. For now I just had a feeling and I was right.
        let mut x = FixedPoint32::from(width / 2)
            + (ydraw_start_distance * dmx)
            + (xdraw_start_distance * dx);
        let mut y = FixedPoint32::from(height / 2)
            + (ydraw_start_distance * dmy)
            + (xdraw_start_distance * dy);

        let tile_data = &vram[0x10000..];

        // The number of characters (tiles) we have to jump to reach the next
        // line of the object.
        let char_stride: usize =
            if ioregs.dispcnt.obj_char_vram_mapping() == ObjCharVramMapping::OneDimensional {
                width as usize / 8
            } else if attr0.palette256() {
                16
            } else {
                32
            };
        let first_tile_index = attr2.character_name() as usize;
        let mode = attr0.mode();

        let mut attrs = PixelAttrs::default();
        if ioregs.bldcnt.is_first_target(OBJ) {
            attrs.set_first_target();
        }
        if ioregs.bldcnt.is_second_target(OBJ) {
            attrs.set_second_target();
        }
        if mode == ObjMode::SemiTransparent {
            attrs.set_semi_transparent();
        }

        let mut mosaic_x = 0usize;
        let mut mosaic_y = 0usize;

        if attr0.mosaic() {
            mosaic_x = ioregs.mosaic.obj_h() as usize + 1;
            mosaic_y = ioregs.mosaic.obj_v() as usize + 1;
        }

        if attr0.palette256() {
            const BYTES_PER_LINE: usize = 8;
            const BYTES_PER_TILE: usize = 64;

            let width = width as usize;
            let height = height as usize;

            attrs.set_8bpp();
            attrs.set_priority(attr2.priority());

            for screen_x in left as usize..=right as usize {
                let mut xi = x.integer() as usize;
                let mut yi = y.integer() as usize;
                if xi < width && yi < height {
                    if mosaic_x > 0 {
                        xi -= xi % mosaic_x;
                    }

                    if mosaic_y > 0 {
                        yi -= yi % mosaic_y;
                    }

                    // FIXME Lower bit of the tile should be ignored. From GBATEK:
                    //
                    //     When using the 256 Colors/1 Palette mode, only each second tile may be used,
                    //     the lower bit of the tile number should be zero (in 2-dimensional mapping mode,
                    //     the bit is completely ignored).
                    let tile =
                        (((first_tile_index / 2) as usize) + ((yi / 8) * char_stride) + (xi / 8))
                            & 0x3FF;

                    // When using BG Mode 3-5 (Bitmap Modes), only tile numbers 512-1023 may be used.
                    // That is because lower 16K of OBJ memory are used for BG. Attempts to use tiles 0-511 are ignored (not displayed).
                    if tile < 512 && ioregs.dispcnt.is_bitmap_mode() {
                        continue;
                    }

                    let pixel_offset =
                        (tile * BYTES_PER_TILE) + ((yi % 8) * BYTES_PER_LINE) + (xi % 8);
                    let entry = tile_data[pixel_offset as usize];

                    if mode != ObjMode::ObjWindow {
                        buf.put_obj_8bpp(attrs, screen_x, entry);
                    } else if entry != 0 {
                        buf.put_obj_window(screen_x);
                    }
                }

                x += dx;
                y += dy;
            }
        } else {
            const BYTES_PER_LINE: usize = 4;
            const BYTES_PER_TILE: usize = 32;

            let width = width as usize;
            let height = height as usize;

            attrs.set_4bpp();
            attrs.set_priority(attr2.priority());

            for screen_x in left as usize..=right as usize {
                let mut xi = x.integer() as usize;
                let mut yi = y.integer() as usize;
                if xi < width && yi < height {
                    if mosaic_x > 0 {
                        xi -= xi % mosaic_x;
                    }

                    if mosaic_y > 0 {
                        yi -= yi % mosaic_y;
                    }

                    let tile = (first_tile_index + ((yi / 8) * char_stride) + (xi / 8)) & 0x3FF;
                    let pixel_offset =
                        (tile * BYTES_PER_TILE) + ((yi % 8) * BYTES_PER_LINE) + (xi % 8) / 2;
                    let entry = (tile_data[pixel_offset] >> ((xi % 2) << 2)) & 0xF;

                    if mode != ObjMode::ObjWindow {
                        buf.put_obj_4bpp(attrs, screen_x, attr2.palette() as _, entry);
                    } else if entry != 0 {
                        buf.put_obj_window(screen_x);
                    }
                }

                x += dx;
                y += dy;
            }
        }
    }
}

/// Consumes the cycles required to render and object line and returns the rightmost pixel's
/// x position if there were enough cycles to render an object at all.
fn consume_obj_cycles(cycles: &mut u16, rs: bool, width: u16, left: u16) -> Option<u16> {
    let right;
    if rs {
        // affine objects require 10 cycles to start
        *cycles = cycles.saturating_sub(10);
        if *cycles == 0 {
            return None;
        }

        if width * 2 > *cycles {
            right = (left + (*cycles / 2)) % 512;
            *cycles = 0;
        } else {
            right = (left + width) % 512;
            *cycles -= width * 2;
        }
    } else if width > *cycles {
        right = (left + *cycles - 1) % 512;
        *cycles = 0;
    } else {
        right = (left + width - 1) % 512;
        *cycles -= width;
    }

    Some(right)
}

bitfields! {
    struct ObjAttr0: u16 {
        [0,7]   y, set_y: u16,
        [8]     rotscale, set_rotscale: bool,

        // When rotscale flag is set:
        [9]     double_size, set_double_size: bool,

        // When rotscale flag is clear:
        [9]     disabled, set_disabled: bool,

        [10,11] mode, set_mode: ObjMode,
        [12]    mosaic, set_mosaic: bool,
        [13]    palette256, set_palette256: bool,
        [14,15] shape, set_shape: ObjShape,
    }
}

bitfields! {
    struct ObjAttr1: u16 {
        [0,8]   x, set_x: u16,

        // When rotsccale flag is set in attr0:
        [9,13]  rotscale_param, set_rotscale_param: u16,

        // When rotscale flag is clear in attr0:
        [12]    horizontal_flip, set_horizontal: bool,
        [13]    vertical_flip, set_vertical_flip: bool,
    }
}

impl ObjAttr1 {
    pub fn size(&self, shape: ObjShape) -> (u16, u16) {
        //  Size  Square   Horizontal  Vertical
        //  0     8x8      16x8        8x16
        //  1     16x16    32x8        8x32
        //  2     32x32    32x16       16x32
        //  3     64x64    64x32       32x64
        match (self.value.bits(14, 15), shape) {
            (0, ObjShape::Square) => (8, 8),
            (1, ObjShape::Square) => (16, 16),
            (2, ObjShape::Square) => (32, 32),
            (3, ObjShape::Square) => (64, 64),

            (0, ObjShape::Horizontal) => (16, 8),
            (1, ObjShape::Horizontal) => (32, 8),
            (2, ObjShape::Horizontal) => (32, 16),
            (3, ObjShape::Horizontal) => (64, 32),

            (0, ObjShape::Vertical) => (8, 16),
            (1, ObjShape::Vertical) => (8, 32),
            (2, ObjShape::Vertical) => (16, 32),
            (3, ObjShape::Vertical) => (32, 64),

            _ => (8, 8),
        }
    }
}

bitfields! {
    struct ObjAttr2: u16 {
        [0,9]   character_name, set_character_name: u16,
        [10,11] priority, set_priority: u16,
        [12,15] palette, set_palette: u16,
    }
}

primitive_enum! {
    pub enum ObjMode: u16 {
        Normal,
        SemiTransparent,
        ObjWindow,
        Invalid,
    }
}

primitive_enum! {
    pub enum ObjShape: u16 {
        Square,
        Horizontal,
        Vertical,
        Prohibited,
    }
}
<|endoftext|>