<commit_before>// This defines the amd64 target for UEFI systems as described in the UEFI specification. See the
// uefi-base module for generic UEFI options. On x86_64 systems (mostly called "x64" in the spec)
// UEFI systems always run in long-mode, have the interrupt-controller pre-configured and force a
// single-CPU execution.
// The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.

use crate::spec::{CodeModel, Target};

pub fn target() -> Target {
    let mut base = super::uefi_msvc_base::opts();
    base.cpu = "x86-64".to_string();
    base.max_atomic_width = Some(64);

    // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to
    // enable these CPU features explicitly before their first use, otherwise their instructions
    // will trigger an exception. Rust does not inject any code that enables AVX/MMX/SSE
    // instruction sets, so this must be done by the firmware. However, existing firmware is known
    // to leave these uninitialized, thus triggering exceptions if we make use of them. Which is
    // why we avoid them and instead use soft-floats. This is also what GRUB and friends did so
    // far.
    // If you initialize FP units yourself, you can override these flags with custom linker
    // arguments, thus giving you access to full MMX/SSE acceleration.
    base.features = "-mmx,-sse,+soft-float".to_string();

    // UEFI systems run without a host OS, hence we cannot assume any code locality. We must tell
    // LLVM to expect code to reference any address in the address-space. The "large" code-model
    // places no locality-restrictions, so it fits well here.
    base.code_model = Some(CodeModel::Large);

    Target {
        llvm_target: "x86_64-unknown-windows".to_string(),
        pointer_width: 64,
        data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
            .to_string(),
        arch: "x86_64".to_string(),

        options: base,
    }
}
<commit_msg>Auto merge of #87124 - Andy-Python-Programmer:code_model_uefi_patch, r=petrochenkov<commit_after>// This defines the amd64 target for UEFI systems as described in the UEFI specification. See the
// uefi-base module for generic UEFI options. On x86_64 systems (mostly called "x64" in the spec)
// UEFI systems always run in long-mode, have the interrupt-controller pre-configured and force a
// single-CPU execution.
// The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.

use crate::spec::Target;

pub fn target() -> Target {
    let mut base = super::uefi_msvc_base::opts();
    base.cpu = "x86-64".to_string();
    base.max_atomic_width = Some(64);

    // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to
    // enable these CPU features explicitly before their first use, otherwise their instructions
    // will trigger an exception. Rust does not inject any code that enables AVX/MMX/SSE
    // instruction sets, so this must be done by the firmware. However, existing firmware is known
    // to leave these uninitialized, thus triggering exceptions if we make use of them. Which is
    // why we avoid them and instead use soft-floats. This is also what GRUB and friends did so
    // far.
    //
    // If you initialize FP units yourself, you can override these flags with custom linker
    // arguments, thus giving you access to full MMX/SSE acceleration.
    base.features = "-mmx,-sse,+soft-float".to_string();

    Target {
        llvm_target: "x86_64-unknown-windows".to_string(),
        pointer_width: 64,
        data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
            .to_string(),
        arch: "x86_64".to_string(),

        options: base,
    }
}
<|endoftext|>


<commit_before>// Tifflin OS - Userland loader
// - By John Hodge (thePowersGang)
//
// This program is both the initial entrypoint for the userland, and the default dynamic linker.
#![feature(result_expect)]	// my feature, i'm using it
#![feature(core)]	// needed for core's SliceExt
#![crate_type="lib"]
#[macro_use]
extern crate tifflin_syscalls;

extern crate byteorder;
extern crate cmdline_words_parser;

macro_rules! impl_from {
	($(From<$src:ty>($v:ident) for $t:ty { $($code:stmt)*} )+) => {
		$(
			impl ::std::convert::From<$src> for $t {
				fn from($v: $src) -> $t {
					$($code)*
				}
			}
		)+
	}
}

use cmdline_words_parser::StrExt;

mod elf;

// Main: This is the initial boot entrypoint
#[no_mangle]
pub extern "C" fn loader_main(cmdline: *mut u8, cmdline_len: usize) -> !
{
	kernel_log!("loader_main({:p}, {})", cmdline, cmdline_len);
	// (maybe) SAFE: Need to actually check UTF-8 ness?
	let cmdline: &mut str = unsafe { ::std::mem::transmute( ::std::slice::from_raw_parts_mut(cmdline, cmdline_len) ) };
	// 1. Print the INIT parameter from the kernel
	kernel_log!("- cmdline={:?}", cmdline);

	// 2. Parse 'cmdline' into the init path and arguments.
	// TODO: Parse path as an escaped string. Should be able to use a parser that takes &mut str and returns reborrows
	//       - Such a parser would be able to clobber the string as escaping is undone, using the assumption that esc.len >= real.len
	let mut arg_iter = cmdline.parse_cmdline_words();
	let init_path = arg_iter.next().expect("Init path is empty");
	kernel_log!("- init_path={:?}", init_path);
	// 3. Spin up init
	// - Open the init path passed in `cmdline`
	let mut handle = match ::elf::load_executable(init_path)
		{
		Ok(v) => v,
		Err(e) => {
			kernel_log!("ERROR: Init binary '{}' cannot be loaded: {:?}", init_path, e);
			::tifflin_syscalls::exit(0);
			},
		};

	let entrypoint = handle.get_entrypoint();

	let mut found_segment_for_entry = false;
	// I would love to use a for loop here, but getting access the file is hard using that
	{
		let mut segments_it = handle.load_segments();
		while let Some(segment) = segments_it.next()
		{
			use tifflin_syscalls::vfs::MemoryMapMode;
			use tifflin_syscalls::memory::ProtectionMode;
			const PAGE_SIZE: usize = 0x1000;
			kernel_log!("segment = {:?}", segment);

			if segment.load_addr <= entrypoint && entrypoint < segment.load_addr + segment.mem_size {
				found_segment_for_entry = true;
			}

			assert!(segment.file_size <= segment.mem_size);
			// Split the segment into three regions: (reverse)
			// - Page-aligned resident data
			// - Non-resident data
			// - Tailing resident data
			let extra = segment.mem_size - segment.file_size;
			let tail    = segment.file_size % PAGE_SIZE;
			let aligned = segment.file_size - tail;
			let map_mode = match segment.protection
				{
				elf::SegmentProt::Execute   => MemoryMapMode::Execute,
				elf::SegmentProt::ReadWrite => MemoryMapMode::COW,
				elf::SegmentProt::ReadOnly  => MemoryMapMode::ReadOnly,
				};
			let alloc_mode = match segment.protection
				{
				elf::SegmentProt::Execute   => ProtectionMode::Executable,
				elf::SegmentProt::ReadWrite => ProtectionMode::ReadWrite,	// Allocates as read-write
				elf::SegmentProt::ReadOnly  => ProtectionMode::ReadOnly,
				};
			let fp = segments_it.get_file();
			if aligned > 0 {
				fp.memory_map(segment.file_addr, aligned, segment.load_addr, map_mode);
			}
			if tail > 0 {
				unsafe {
					let destslice = ::std::slice::from_raw_parts_mut((segment.load_addr + aligned) as *mut u8, tail);
					// - Allocate space
					::tifflin_syscalls::memory::allocate(destslice.as_ptr() as usize, ProtectionMode::ReadWrite);
					// - Read data
					fp.read_at(segment.file_addr + aligned as u64, destslice).expect("Failure reading file data for end of .segment");
					// - Reprotect to the real mode, not bothering if the desired is Read-Write
					if alloc_mode != ProtectionMode::ReadWrite {
						::tifflin_syscalls::memory::reprotect(destslice.as_ptr() as usize, alloc_mode);
					}
				}
			}
			if extra > PAGE_SIZE - tail {
				panic!("TODO: Allocate extra pages for BSS");
			}
		}
	}

	if !found_segment_for_entry {
		panic!("Entrypoint {:#x} is not located in a loaded segment", entrypoint);
	}

	// Populate arguments
	// SAFE: We will be writing to this before reading from it
	let mut args_buf: [&str; 16] = unsafe { ::std::mem::uninitialized() };
	let mut argc = 0;
	for arg in arg_iter {
		args_buf[argc] = arg;
		argc += 1;
	}
	let args = &args_buf[..argc];
	kernel_log!("args = {:?}", args);

	// TODO: Switch stacks into a larger dynamically-allocated stack
	let ep: fn(&[&str]) -> ! = unsafe { ::std::mem::transmute(entrypoint) };
	kernel_log!("Calling entry {:p}", ep as *const ());
	ep(args);

	::tifflin_syscalls::exit(0);
}
<commit_msg>Usermode/loader - Add feature flag required for SliceExt<commit_after>// Tifflin OS - Userland loader
// - By John Hodge (thePowersGang)
//
// This program is both the initial entrypoint for the userland, and the default dynamic linker.
#![feature(result_expect)]	// my feature, i'm using it
#![feature(core,core_slice_ext)]	// needed for core's SliceExt
#![crate_type="lib"]
#[macro_use]
extern crate tifflin_syscalls;

extern crate byteorder;
extern crate cmdline_words_parser;

macro_rules! impl_from {
	($(From<$src:ty>($v:ident) for $t:ty { $($code:stmt)*} )+) => {
		$(
			impl ::std::convert::From<$src> for $t {
				fn from($v: $src) -> $t {
					$($code)*
				}
			}
		)+
	}
}

use cmdline_words_parser::StrExt;

mod elf;

// Main: This is the initial boot entrypoint
#[no_mangle]
pub extern "C" fn loader_main(cmdline: *mut u8, cmdline_len: usize) -> !
{
	kernel_log!("loader_main({:p}, {})", cmdline, cmdline_len);
	// (maybe) SAFE: Need to actually check UTF-8 ness?
	let cmdline: &mut str = unsafe { ::std::mem::transmute( ::std::slice::from_raw_parts_mut(cmdline, cmdline_len) ) };
	// 1. Print the INIT parameter from the kernel
	kernel_log!("- cmdline={:?}", cmdline);

	// 2. Parse 'cmdline' into the init path and arguments.
	// TODO: Parse path as an escaped string. Should be able to use a parser that takes &mut str and returns reborrows
	//       - Such a parser would be able to clobber the string as escaping is undone, using the assumption that esc.len >= real.len
	let mut arg_iter = cmdline.parse_cmdline_words();
	let init_path = arg_iter.next().expect("Init path is empty");
	kernel_log!("- init_path={:?}", init_path);
	// 3. Spin up init
	// - Open the init path passed in `cmdline`
	let mut handle = match ::elf::load_executable(init_path)
		{
		Ok(v) => v,
		Err(e) => {
			kernel_log!("ERROR: Init binary '{}' cannot be loaded: {:?}", init_path, e);
			::tifflin_syscalls::exit(0);
			},
		};

	let entrypoint = handle.get_entrypoint();

	let mut found_segment_for_entry = false;
	// I would love to use a for loop here, but getting access the file is hard using that
	{
		let mut segments_it = handle.load_segments();
		while let Some(segment) = segments_it.next()
		{
			use tifflin_syscalls::vfs::MemoryMapMode;
			use tifflin_syscalls::memory::ProtectionMode;
			const PAGE_SIZE: usize = 0x1000;
			kernel_log!("segment = {:?}", segment);

			if segment.load_addr <= entrypoint && entrypoint < segment.load_addr + segment.mem_size {
				found_segment_for_entry = true;
			}

			assert!(segment.file_size <= segment.mem_size);
			// Split the segment into three regions: (reverse)
			// - Page-aligned resident data
			// - Non-resident data
			// - Tailing resident data
			let extra = segment.mem_size - segment.file_size;
			let tail    = segment.file_size % PAGE_SIZE;
			let aligned = segment.file_size - tail;
			let map_mode = match segment.protection
				{
				elf::SegmentProt::Execute   => MemoryMapMode::Execute,
				elf::SegmentProt::ReadWrite => MemoryMapMode::COW,
				elf::SegmentProt::ReadOnly  => MemoryMapMode::ReadOnly,
				};
			let alloc_mode = match segment.protection
				{
				elf::SegmentProt::Execute   => ProtectionMode::Executable,
				elf::SegmentProt::ReadWrite => ProtectionMode::ReadWrite,	// Allocates as read-write
				elf::SegmentProt::ReadOnly  => ProtectionMode::ReadOnly,
				};
			let fp = segments_it.get_file();
			if aligned > 0 {
				fp.memory_map(segment.file_addr, aligned, segment.load_addr, map_mode);
			}
			if tail > 0 {
				unsafe {
					let destslice = ::std::slice::from_raw_parts_mut((segment.load_addr + aligned) as *mut u8, tail);
					// - Allocate space
					::tifflin_syscalls::memory::allocate(destslice.as_ptr() as usize, ProtectionMode::ReadWrite);
					// - Read data
					fp.read_at(segment.file_addr + aligned as u64, destslice).expect("Failure reading file data for end of .segment");
					// - Reprotect to the real mode, not bothering if the desired is Read-Write
					if alloc_mode != ProtectionMode::ReadWrite {
						::tifflin_syscalls::memory::reprotect(destslice.as_ptr() as usize, alloc_mode);
					}
				}
			}
			if extra > PAGE_SIZE - tail {
				panic!("TODO: Allocate extra pages for BSS");
			}
		}
	}

	if !found_segment_for_entry {
		panic!("Entrypoint {:#x} is not located in a loaded segment", entrypoint);
	}

	// Populate arguments
	// SAFE: We will be writing to this before reading from it
	let mut args_buf: [&str; 16] = unsafe { ::std::mem::uninitialized() };
	let mut argc = 0;
	for arg in arg_iter {
		args_buf[argc] = arg;
		argc += 1;
	}
	let args = &args_buf[..argc];
	kernel_log!("args = {:?}", args);

	// TODO: Switch stacks into a larger dynamically-allocated stack
	let ep: fn(&[&str]) -> ! = unsafe { ::std::mem::transmute(entrypoint) };
	kernel_log!("Calling entry {:p}", ep as *const ());
	ep(args);

	::tifflin_syscalls::exit(0);
}
<|endoftext|>


<commit_before>extern crate buffering;
extern crate neli;

use buffering::StreamReadBuffer;
use neli::consts::*;
use neli::nl::NlEmpty;
use neli::nl::Nlmsghdr;
use neli::rtnl::*;
use neli::socket::*;
use neli::Nl;
use neli::MAX_NL_LENGTH;
use std::net::IpAddr;

///
/// This sample is a simple imitation of the `ip route` command, to demonstrate interaction with the rtnetlink subsystem.
///
fn main() {
    let mut socket = NlSocket::connect(NlFamily::Route, None, None, true).unwrap();

    let rtmsg = Rtgenmsg {
        rtgen_family: libc::AF_INET as u8, // Only ask about Ipv4, as it's simpler to display below.
    };
    let nlhdr = {
        let len = None;
        let nl_type = Rtm::Getroute;
        let flags = vec![NlmF::Request, NlmF::Root, NlmF::Match];
        let seq = None;
        let pid = None;
        let payload = rtmsg;
        Nlmsghdr::new(len, nl_type, flags, seq, pid, payload)
    };
    socket.send_nl(nlhdr).unwrap();

    'socket_read: loop {
        let mut mem = vec![0u8; MAX_NL_LENGTH];
        match socket.recv(&mut mem, 0) {
            Err(e) => {
                println!("Error: could not read from netlink socket: {}", e);
                break;
            }
            Ok(x) if x <= 0 => {
                println!("Error: could not read from netlink socket: {}", x);
                break;
            }
            Ok(read_len) => mem.truncate(read_len as usize),
        }
        let mut buf = StreamReadBuffer::new(&mem[..]);

        while !buf.at_end() {
            // Provisionally deserialize as a Nlmsg first.
            let mut nl_reader = StreamReadBuffer::new(buf.as_ref());
            let nl = Nlmsghdr::<Nlmsg, NlEmpty>::deserialize(&mut nl_reader)
                .expect("Error deserializing Nlmsghdr");
            match nl.nl_type {
                Nlmsg::Done => break 'socket_read,
                Nlmsg::Error => {
                    println!("rtnetlink error.");
                    break 'socket_read;
                }
                _ => {
                    // Some other message type, so let's try to deserialize as a Rtm.
                    let rtm = Nlmsghdr::<Rtm, Rtmsg<Rta>>::deserialize(&mut buf)
                        .expect("Error deserializing Rtmsg");

                    // This sample is only interested in the main table.
                    if rtm.nl_payload.rtm_table == RtTable::Main {
                        let mut src = None;
                        let mut dst = None;
                        let mut gateway = None;

                        for attr in &rtm.nl_payload.rtattrs {
                            fn to_addr(b: &[u8]) -> Option<IpAddr> {
                                use std::convert::TryFrom;
                                if let Ok(tup) = <&[u8; 4]>::try_from(b) {
                                    Some(IpAddr::from(tup.clone()))
                                } else if let Ok(tup) = <&[u8; 16]>::try_from(b) {
                                    Some(IpAddr::from(tup.clone()))
                                } else {
                                    None
                                }
                            }

                            match attr.rta_type {
                                Rta::Dst => dst = to_addr(&attr.rta_payload),
                                Rta::Prefsrc => src = to_addr(&attr.rta_payload),
                                Rta::Gateway => gateway = to_addr(&attr.rta_payload),
                                _ => (),
                            }
                        }

                        if let Some(dst) = dst {
                            print!("{}/{} ", dst, rtm.nl_payload.rtm_dst_len);
                        } else {
                            print!("default ");
                            if let Some(gateway) = gateway {
                                print!("via {} ", gateway);
                            }
                        }

                        if rtm.nl_payload.rtm_scope != RtScope::Universe {
                            print!(
                                " proto {:?}  scope {:?} ",
                                rtm.nl_payload.rtm_protocol, rtm.nl_payload.rtm_scope
                            )
                        }
                        if let Some(src) = src {
                            print!(" src {} ", src);
                        }
                        println!();
                    }
                }
            }
        }
    }
}
<commit_msg>implement route-list via a Rtmsg rather than Rtgenmsg<commit_after>extern crate buffering;
extern crate neli;

use buffering::StreamReadBuffer;
use neli::consts::*;
use neli::nl::NlEmpty;
use neli::nl::Nlmsghdr;
use neli::rtnl::*;
use neli::socket::*;
use neli::Nl;
use neli::MAX_NL_LENGTH;
use std::net::IpAddr;

///
/// This sample is a simple imitation of the `ip route` command, to demonstrate interaction with the rtnetlink subsystem.
///
fn main() {
    let mut socket = NlSocket::connect(NlFamily::Route, None, None, true).unwrap();

    let rtmsg : Rtmsg<Rta> = Rtmsg {
        rtm_family: libc::AF_INET as u8,
        rtm_dst_len: 0,
        rtm_src_len: 0,
        rtm_tos: 0,
        rtm_table: RtTable::Unspec,
        rtm_protocol: Rtprot::Unspec,
        rtm_scope: RtScope::Universe,
        rtm_type: Rtn::Unspec,
        rtm_flags: vec![],
        rtattrs: vec![],
    };
    let nlhdr = {
        let len = None;
        let nl_type = Rtm::Getroute;
        let flags = vec![NlmF::Request, NlmF::Root, NlmF::Match];
        let seq = None;
        let pid = None;
        let payload = rtmsg;
        Nlmsghdr::new(len, nl_type, flags, seq, pid, payload)
    };
    socket.send_nl(nlhdr).unwrap();

    'socket_read: loop {
        let mut mem = vec![0u8; MAX_NL_LENGTH];
        match socket.recv(&mut mem, 0) {
            Err(e) => {
                println!("Error: could not read from netlink socket: {}", e);
                break;
            }
            Ok(x) if x <= 0 => {
                println!("Error: could not read from netlink socket: {}", x);
                break;
            }
            Ok(read_len) => mem.truncate(read_len as usize),
        }
        let mut buf = StreamReadBuffer::new(&mem[..]);

        while !buf.at_end() {
            // Provisionally deserialize as a Nlmsg first.
            let mut nl_reader = StreamReadBuffer::new(buf.as_ref());
            let nl = Nlmsghdr::<Nlmsg, NlEmpty>::deserialize(&mut nl_reader)
                .expect("Error deserializing Nlmsghdr");
            match nl.nl_type {
                Nlmsg::Done => break 'socket_read,
                Nlmsg::Error => {
                    println!("rtnetlink error.");
                    break 'socket_read;
                }
                _ => {
                    // Some other message type, so let's try to deserialize as a Rtm.
                    let rtm = Nlmsghdr::<Rtm, Rtmsg<Rta>>::deserialize(&mut buf)
                        .expect("Error deserializing Rtmsg");

                    // This sample is only interested in the main table.
                    if rtm.nl_payload.rtm_table == RtTable::Main {
                        let mut src = None;
                        let mut dst = None;
                        let mut gateway = None;

                        for attr in &rtm.nl_payload.rtattrs {
                            fn to_addr(b: &[u8]) -> Option<IpAddr> {
                                use std::convert::TryFrom;
                                if let Ok(tup) = <&[u8; 4]>::try_from(b) {
                                    Some(IpAddr::from(tup.clone()))
                                } else if let Ok(tup) = <&[u8; 16]>::try_from(b) {
                                    Some(IpAddr::from(tup.clone()))
                                } else {
                                    None
                                }
                            }

                            match attr.rta_type {
                                Rta::Dst => dst = to_addr(&attr.rta_payload),
                                Rta::Prefsrc => src = to_addr(&attr.rta_payload),
                                Rta::Gateway => gateway = to_addr(&attr.rta_payload),
                                _ => (),
                            }
                        }

                        if let Some(dst) = dst {
                            print!("{}/{} ", dst, rtm.nl_payload.rtm_dst_len);
                        } else {
                            print!("default ");
                            if let Some(gateway) = gateway {
                                print!("via {} ", gateway);
                            }
                        }

                        if rtm.nl_payload.rtm_scope != RtScope::Universe {
                            print!(
                                " proto {:?}  scope {:?} ",
                                rtm.nl_payload.rtm_protocol, rtm.nl_payload.rtm_scope
                            )
                        }
                        if let Some(src) = src {
                            print!(" src {} ", src);
                        }
                        println!();
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{get_parent_expr, span_lint, span_note_and_lint};
use if_chain::if_chain;
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use syntax::ast;

declare_clippy_lint! {
    /// **What it does:** Checks for a read and a write to the same variable where
    /// whether the read occurs before or after the write depends on the evaluation
    /// order of sub-expressions.
    ///
    /// **Why is this bad?** It is often confusing to read. In addition, the
    /// sub-expression evaluation order for Rust is not well documented.
    ///
    /// **Known problems:** Code which intentionally depends on the evaluation
    /// order, or which is correct for any evaluation order.
    ///
    /// **Example:**
    /// ```rust
    /// let mut x = 0;
    /// let a = {
    ///     x = 1;
    ///     1
    /// } + x;
    /// // Unclear whether a is 1 or 2.
    /// ```
    pub EVAL_ORDER_DEPENDENCE,
    complexity,
    "whether a variable read occurs before a write depends on sub-expression evaluation order"
}

declare_clippy_lint! {
    /// **What it does:** Checks for diverging calls that are not match arms or
    /// statements.
    ///
    /// **Why is this bad?** It is often confusing to read. In addition, the
    /// sub-expression evaluation order for Rust is not well documented.
    ///
    /// **Known problems:** Someone might want to use `some_bool || panic!()` as a
    /// shorthand.
    ///
    /// **Example:**
    /// ```rust
    /// let a = b() || panic!() || c();
    /// // `c()` is dead, `panic!()` is only called if `b()` returns `false`
    /// let x = (a, b, c, panic!());
    /// // can simply be replaced by `panic!()`
    /// ```
    pub DIVERGING_SUB_EXPRESSION,
    complexity,
    "whether an expression contains a diverging sub expression"
}

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

impl LintPass for EvalOrderDependence {
    fn get_lints(&self) -> LintArray {
        lint_array!(EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION)
    }

    fn name(&self) -> &'static str {
        "EvalOrderDependence"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        // Find a write to a local variable.
        match expr.node {
            ExprKind::Assign(ref lhs, _) | ExprKind::AssignOp(_, ref lhs, _) => {
                if let ExprKind::Path(ref qpath) = lhs.node {
                    if let QPath::Resolved(_, ref path) = *qpath {
                        if path.segments.len() == 1 {
                            if let def::Def::Local(var) = cx.tables.qpath_def(qpath, lhs.hir_id) {
                                let mut visitor = ReadVisitor {
                                    cx,
                                    var,
                                    write_expr: expr,
                                    last_expr: expr,
                                };
                                check_for_unsequenced_reads(&mut visitor);
                            }
                        }
                    }
                }
            },
            _ => {},
        }
    }
    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
        match stmt.node {
            StmtKind::Local(ref local) => {
                if let Local { init: Some(ref e), .. } = **local {
                    DivergenceVisitor { cx }.visit_expr(e);
                }
            },
            StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => DivergenceVisitor { cx }.maybe_walk_expr(e),
            StmtKind::Item(..) => {},
        }
    }
}

struct DivergenceVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
    fn maybe_walk_expr(&mut self, e: &'tcx Expr) {
        match e.node {
            ExprKind::Closure(.., _) => {},
            ExprKind::Match(ref e, ref arms, _) => {
                self.visit_expr(e);
                for arm in arms {
                    if let Some(ref guard) = arm.guard {
                        match guard {
                            Guard::If(if_expr) => self.visit_expr(if_expr),
                        }
                    }
                    // make sure top level arm expressions aren't linted
                    self.maybe_walk_expr(&*arm.body);
                }
            },
            _ => walk_expr(self, e),
        }
    }
    fn report_diverging_sub_expr(&mut self, e: &Expr) {
        span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges");
    }
}

impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, e: &'tcx Expr) {
        match e.node {
            ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
            ExprKind::Call(ref func, _) => {
                let typ = self.cx.tables.expr_ty(func);
                match typ.sty {
                    ty::FnDef(..) | ty::FnPtr(_) => {
                        let sig = typ.fn_sig(self.cx.tcx);
                        if let ty::Never = self.cx.tcx.erase_late_bound_regions(&sig).output().sty {
                            self.report_diverging_sub_expr(e);
                        }
                    },
                    _ => {},
                }
            },
            ExprKind::MethodCall(..) => {
                let borrowed_table = self.cx.tables;
                if borrowed_table.expr_ty(e).is_never() {
                    self.report_diverging_sub_expr(e);
                }
            },
            _ => {
                // do not lint expressions referencing objects of type `!`, as that required a
                // diverging expression
                // to begin with
            },
        }
        self.maybe_walk_expr(e);
    }
    fn visit_block(&mut self, _: &'tcx Block) {
        // don't continue over blocks, LateLintPass already does that
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

/// Walks up the AST from the given write expression (`vis.write_expr`) looking
/// for reads to the same variable that are unsequenced relative to the write.
///
/// This means reads for which there is a common ancestor between the read and
/// the write such that
///
/// * evaluating the ancestor necessarily evaluates both the read and the write (for example, `&x`
///   and `|| x = 1` don't necessarily evaluate `x`), and
///
/// * which one is evaluated first depends on the order of sub-expression evaluation. Blocks, `if`s,
///   loops, `match`es, and the short-circuiting logical operators are considered to have a defined
///   evaluation order.
///
/// When such a read is found, the lint is triggered.
fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
    let map = &vis.cx.tcx.hir();
    let mut cur_id = vis.write_expr.hir_id;
    loop {
        let parent_id = map.get_parent_node_by_hir_id(cur_id);
        if parent_id == cur_id {
            break;
        }
        let parent_node = match map.find_by_hir_id(parent_id) {
            Some(parent) => parent,
            None => break,
        };

        let stop_early = match parent_node {
            Node::Expr(expr) => check_expr(vis, expr),
            Node::Stmt(stmt) => check_stmt(vis, stmt),
            Node::Item(_) => {
                // We reached the top of the function, stop.
                break;
            },
            _ => StopEarly::KeepGoing,
        };
        match stop_early {
            StopEarly::Stop => break,
            StopEarly::KeepGoing => {},
        }

        cur_id = parent_id;
    }
}

/// Whether to stop early for the loop in `check_for_unsequenced_reads`. (If
/// `check_expr` weren't an independent function, this would be unnecessary and
/// we could just use `break`).
enum StopEarly {
    KeepGoing,
    Stop,
}

fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> StopEarly {
    if expr.hir_id == vis.last_expr.hir_id {
        return StopEarly::KeepGoing;
    }

    match expr.node {
        ExprKind::Array(_)
        | ExprKind::Tup(_)
        | ExprKind::MethodCall(..)
        | ExprKind::Call(_, _)
        | ExprKind::Assign(_, _)
        | ExprKind::Index(_, _)
        | ExprKind::Repeat(_, _)
        | ExprKind::Struct(_, _, _) => {
            walk_expr(vis, expr);
        },
        ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
            if op.node == BinOpKind::And || op.node == BinOpKind::Or {
                // x && y and x || y always evaluate x first, so these are
                // strictly sequenced.
            } else {
                walk_expr(vis, expr);
            }
        },
        ExprKind::Closure(_, _, _, _, _) => {
            // Either
            //
            // * `var` is defined in the closure body, in which case we've reached the top of the enclosing
            //   function and can stop, or
            //
            // * `var` is captured by the closure, in which case, because evaluating a closure does not evaluate
            //   its body, we don't necessarily have a write, so we need to stop to avoid generating false
            //   positives.
            //
            // This is also the only place we need to stop early (grrr).
            return StopEarly::Stop;
        },
        // All other expressions either have only one child or strictly
        // sequence the evaluation order of their sub-expressions.
        _ => {},
    }

    vis.last_expr = expr;

    StopEarly::KeepGoing
}

fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt) -> StopEarly {
    match stmt.node {
        StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => check_expr(vis, expr),
        // If the declaration is of a local variable, check its initializer
        // expression if it has one. Otherwise, keep going.
        StmtKind::Local(ref local) => local
            .init
            .as_ref()
            .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)),
        _ => StopEarly::KeepGoing,
    }
}

/// A visitor that looks for reads from a variable.
struct ReadVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    /// The ID of the variable we're looking for.
    var: ast::NodeId,
    /// The expressions where the write to the variable occurred (for reporting
    /// in the lint).
    write_expr: &'tcx Expr,
    /// The last (highest in the AST) expression we've checked, so we know not
    /// to recheck it.
    last_expr: &'tcx Expr,
}

impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx Expr) {
        if expr.hir_id == self.last_expr.hir_id {
            return;
        }

        match expr.node {
            ExprKind::Path(ref qpath) => {
                if_chain! {
                    if let QPath::Resolved(None, ref path) = *qpath;
                    if path.segments.len() == 1;
                    if let def::Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id);
                    if local_id == self.var;
                    // Check that this is a read, not a write.
                    if !is_in_assignment_position(self.cx, expr);
                    then {
                        span_note_and_lint(
                            self.cx,
                            EVAL_ORDER_DEPENDENCE,
                            expr.span,
                            "unsequenced read of a variable",
                            self.write_expr.span,
                            "whether read occurs before this write depends on evaluation order"
                        );
                    }
                }
            }
            // We're about to descend a closure. Since we don't know when (or
            // if) the closure will be evaluated, any reads in it might not
            // occur here (or ever). Like above, bail to avoid false positives.
            ExprKind::Closure(_, _, _, _, _) |

            // We want to avoid a false positive when a variable name occurs
            // only to have its address taken, so we stop here. Technically,
            // this misses some weird cases, eg.
            //
            // ```rust
            // let mut x = 0;
            // let a = foo(&{x = 1; x}, x);
            // ```
            //
            // TODO: fix this
            ExprKind::AddrOf(_, _) => {
                return;
            }
            _ => {}
        }

        walk_expr(self, expr);
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

/// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`.
fn is_in_assignment_position(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    if let Some(parent) = get_parent_expr(cx, expr) {
        if let ExprKind::Assign(ref lhs, _) = parent.node {
            return lhs.hir_id == expr.hir_id;
        }
    }
    false
}
<commit_msg>HirIdify ReadVisitor<commit_after>use crate::utils::{get_parent_expr, span_lint, span_note_and_lint};
use if_chain::if_chain;
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};

declare_clippy_lint! {
    /// **What it does:** Checks for a read and a write to the same variable where
    /// whether the read occurs before or after the write depends on the evaluation
    /// order of sub-expressions.
    ///
    /// **Why is this bad?** It is often confusing to read. In addition, the
    /// sub-expression evaluation order for Rust is not well documented.
    ///
    /// **Known problems:** Code which intentionally depends on the evaluation
    /// order, or which is correct for any evaluation order.
    ///
    /// **Example:**
    /// ```rust
    /// let mut x = 0;
    /// let a = {
    ///     x = 1;
    ///     1
    /// } + x;
    /// // Unclear whether a is 1 or 2.
    /// ```
    pub EVAL_ORDER_DEPENDENCE,
    complexity,
    "whether a variable read occurs before a write depends on sub-expression evaluation order"
}

declare_clippy_lint! {
    /// **What it does:** Checks for diverging calls that are not match arms or
    /// statements.
    ///
    /// **Why is this bad?** It is often confusing to read. In addition, the
    /// sub-expression evaluation order for Rust is not well documented.
    ///
    /// **Known problems:** Someone might want to use `some_bool || panic!()` as a
    /// shorthand.
    ///
    /// **Example:**
    /// ```rust
    /// let a = b() || panic!() || c();
    /// // `c()` is dead, `panic!()` is only called if `b()` returns `false`
    /// let x = (a, b, c, panic!());
    /// // can simply be replaced by `panic!()`
    /// ```
    pub DIVERGING_SUB_EXPRESSION,
    complexity,
    "whether an expression contains a diverging sub expression"
}

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

impl LintPass for EvalOrderDependence {
    fn get_lints(&self) -> LintArray {
        lint_array!(EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION)
    }

    fn name(&self) -> &'static str {
        "EvalOrderDependence"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        // Find a write to a local variable.
        match expr.node {
            ExprKind::Assign(ref lhs, _) | ExprKind::AssignOp(_, ref lhs, _) => {
                if let ExprKind::Path(ref qpath) = lhs.node {
                    if let QPath::Resolved(_, ref path) = *qpath {
                        if path.segments.len() == 1 {
                            if let def::Def::Local(var) = cx.tables.qpath_def(qpath, lhs.hir_id) {
                                let mut visitor = ReadVisitor {
                                    cx,
                                    var,
                                    write_expr: expr,
                                    last_expr: expr,
                                };
                                check_for_unsequenced_reads(&mut visitor);
                            }
                        }
                    }
                }
            },
            _ => {},
        }
    }
    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
        match stmt.node {
            StmtKind::Local(ref local) => {
                if let Local { init: Some(ref e), .. } = **local {
                    DivergenceVisitor { cx }.visit_expr(e);
                }
            },
            StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => DivergenceVisitor { cx }.maybe_walk_expr(e),
            StmtKind::Item(..) => {},
        }
    }
}

struct DivergenceVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
    fn maybe_walk_expr(&mut self, e: &'tcx Expr) {
        match e.node {
            ExprKind::Closure(.., _) => {},
            ExprKind::Match(ref e, ref arms, _) => {
                self.visit_expr(e);
                for arm in arms {
                    if let Some(ref guard) = arm.guard {
                        match guard {
                            Guard::If(if_expr) => self.visit_expr(if_expr),
                        }
                    }
                    // make sure top level arm expressions aren't linted
                    self.maybe_walk_expr(&*arm.body);
                }
            },
            _ => walk_expr(self, e),
        }
    }
    fn report_diverging_sub_expr(&mut self, e: &Expr) {
        span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges");
    }
}

impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, e: &'tcx Expr) {
        match e.node {
            ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
            ExprKind::Call(ref func, _) => {
                let typ = self.cx.tables.expr_ty(func);
                match typ.sty {
                    ty::FnDef(..) | ty::FnPtr(_) => {
                        let sig = typ.fn_sig(self.cx.tcx);
                        if let ty::Never = self.cx.tcx.erase_late_bound_regions(&sig).output().sty {
                            self.report_diverging_sub_expr(e);
                        }
                    },
                    _ => {},
                }
            },
            ExprKind::MethodCall(..) => {
                let borrowed_table = self.cx.tables;
                if borrowed_table.expr_ty(e).is_never() {
                    self.report_diverging_sub_expr(e);
                }
            },
            _ => {
                // do not lint expressions referencing objects of type `!`, as that required a
                // diverging expression
                // to begin with
            },
        }
        self.maybe_walk_expr(e);
    }
    fn visit_block(&mut self, _: &'tcx Block) {
        // don't continue over blocks, LateLintPass already does that
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

/// Walks up the AST from the given write expression (`vis.write_expr`) looking
/// for reads to the same variable that are unsequenced relative to the write.
///
/// This means reads for which there is a common ancestor between the read and
/// the write such that
///
/// * evaluating the ancestor necessarily evaluates both the read and the write (for example, `&x`
///   and `|| x = 1` don't necessarily evaluate `x`), and
///
/// * which one is evaluated first depends on the order of sub-expression evaluation. Blocks, `if`s,
///   loops, `match`es, and the short-circuiting logical operators are considered to have a defined
///   evaluation order.
///
/// When such a read is found, the lint is triggered.
fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
    let map = &vis.cx.tcx.hir();
    let mut cur_id = vis.write_expr.hir_id;
    loop {
        let parent_id = map.get_parent_node_by_hir_id(cur_id);
        if parent_id == cur_id {
            break;
        }
        let parent_node = match map.find_by_hir_id(parent_id) {
            Some(parent) => parent,
            None => break,
        };

        let stop_early = match parent_node {
            Node::Expr(expr) => check_expr(vis, expr),
            Node::Stmt(stmt) => check_stmt(vis, stmt),
            Node::Item(_) => {
                // We reached the top of the function, stop.
                break;
            },
            _ => StopEarly::KeepGoing,
        };
        match stop_early {
            StopEarly::Stop => break,
            StopEarly::KeepGoing => {},
        }

        cur_id = parent_id;
    }
}

/// Whether to stop early for the loop in `check_for_unsequenced_reads`. (If
/// `check_expr` weren't an independent function, this would be unnecessary and
/// we could just use `break`).
enum StopEarly {
    KeepGoing,
    Stop,
}

fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> StopEarly {
    if expr.hir_id == vis.last_expr.hir_id {
        return StopEarly::KeepGoing;
    }

    match expr.node {
        ExprKind::Array(_)
        | ExprKind::Tup(_)
        | ExprKind::MethodCall(..)
        | ExprKind::Call(_, _)
        | ExprKind::Assign(_, _)
        | ExprKind::Index(_, _)
        | ExprKind::Repeat(_, _)
        | ExprKind::Struct(_, _, _) => {
            walk_expr(vis, expr);
        },
        ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
            if op.node == BinOpKind::And || op.node == BinOpKind::Or {
                // x && y and x || y always evaluate x first, so these are
                // strictly sequenced.
            } else {
                walk_expr(vis, expr);
            }
        },
        ExprKind::Closure(_, _, _, _, _) => {
            // Either
            //
            // * `var` is defined in the closure body, in which case we've reached the top of the enclosing
            //   function and can stop, or
            //
            // * `var` is captured by the closure, in which case, because evaluating a closure does not evaluate
            //   its body, we don't necessarily have a write, so we need to stop to avoid generating false
            //   positives.
            //
            // This is also the only place we need to stop early (grrr).
            return StopEarly::Stop;
        },
        // All other expressions either have only one child or strictly
        // sequence the evaluation order of their sub-expressions.
        _ => {},
    }

    vis.last_expr = expr;

    StopEarly::KeepGoing
}

fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt) -> StopEarly {
    match stmt.node {
        StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => check_expr(vis, expr),
        // If the declaration is of a local variable, check its initializer
        // expression if it has one. Otherwise, keep going.
        StmtKind::Local(ref local) => local
            .init
            .as_ref()
            .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)),
        _ => StopEarly::KeepGoing,
    }
}

/// A visitor that looks for reads from a variable.
struct ReadVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    /// The ID of the variable we're looking for.
    var: HirId,
    /// The expressions where the write to the variable occurred (for reporting
    /// in the lint).
    write_expr: &'tcx Expr,
    /// The last (highest in the AST) expression we've checked, so we know not
    /// to recheck it.
    last_expr: &'tcx Expr,
}

impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx Expr) {
        if expr.hir_id == self.last_expr.hir_id {
            return;
        }

        match expr.node {
            ExprKind::Path(ref qpath) => {
                if_chain! {
                    if let QPath::Resolved(None, ref path) = *qpath;
                    if path.segments.len() == 1;
                    if let def::Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id);
                    if local_id == self.var;
                    // Check that this is a read, not a write.
                    if !is_in_assignment_position(self.cx, expr);
                    then {
                        span_note_and_lint(
                            self.cx,
                            EVAL_ORDER_DEPENDENCE,
                            expr.span,
                            "unsequenced read of a variable",
                            self.write_expr.span,
                            "whether read occurs before this write depends on evaluation order"
                        );
                    }
                }
            }
            // We're about to descend a closure. Since we don't know when (or
            // if) the closure will be evaluated, any reads in it might not
            // occur here (or ever). Like above, bail to avoid false positives.
            ExprKind::Closure(_, _, _, _, _) |

            // We want to avoid a false positive when a variable name occurs
            // only to have its address taken, so we stop here. Technically,
            // this misses some weird cases, eg.
            //
            // ```rust
            // let mut x = 0;
            // let a = foo(&{x = 1; x}, x);
            // ```
            //
            // TODO: fix this
            ExprKind::AddrOf(_, _) => {
                return;
            }
            _ => {}
        }

        walk_expr(self, expr);
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

/// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`.
fn is_in_assignment_position(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    if let Some(parent) = get_parent_expr(cx, expr) {
        if let ExprKind::Assign(ref lhs, _) = parent.node {
            return lhs.hir_id == expr.hir_id;
        }
    }
    false
}
<|endoftext|>


<commit_before>
extern crate clap;
extern crate intcode;

// Time Start: Wed, 11 Dec 2019 12:22:14 -0500
// Time Finish 1: Wed, 11 Dec 2019 13:44:04 -0500 (1 hour, 21 minutes, 50 seconds)
// Time Finish 2: Wed, 11 Dec 2019 13:46:13 -0500 (2 minutes, 9 seconds)
// Time Total: 1 hour, 23 minutes, 59 seconds

use clap::{Arg, App};

use intcode::Intcode;

use std::collections::HashMap;
use std::fmt;

enum Color { Black, White }
enum Direction { Up, Down, Left, Right }
enum Turn { Left, Right }

#[derive(Hash, Eq, PartialEq, Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}
impl Point {
    pub fn new(x: i32, y: i32) -> Point {
        Point { x: x, y: y }
    }

    fn step(&mut self, dx: i32, dy: i32) {
        if let (Some(x), Some(y)) = (self.x.checked_add(dx), self.y.checked_add(dy)) {
            self.x = x;
            self.y = y;
        } else {
            panic!("Point overflow!");
        }
    }
}
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

#[derive(Copy, Clone)]
struct BBox(i32,i32,i32,i32);// xmin, xmax, ymin, ymax
impl BBox {
    pub fn new() -> BBox {
        BBox(0,0,0,0)
    }

    pub fn xmin(&self) -> i32 { self.0 }
    pub fn xmax(&self) -> i32 { self.1 }
    pub fn ymin(&self) -> i32 { self.2 }
    pub fn ymax(&self) -> i32 { self.3 }

    pub fn update(&mut self, pt: &Point) {
        if pt.x < self.0 { self.0 = pt.x; }
        if pt.x > self.1 { self.1 = pt.x; }
        if pt.y < self.2 { self.2 = pt.y; }
        if pt.y > self.3 { self.3 = pt.y; }
    }
}
impl fmt::Display for BBox {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "BBox: {}, {}, {}, {}", self.0, self.1, self.2, self.3)
    }
}

struct Hull {
    paint: HashMap<Point, Color>,
    pub bbox: BBox,
}
impl Hull {
    pub fn new() -> Hull {
        Hull {
            paint: HashMap::new(),
            bbox: BBox::new(),
        }
    }

    pub fn color_at(&self, pt: &Point) -> Color {
        match self.paint.get(&pt) {
            Some(Color::White) => Color::White,
            _                  => Color::Black,
        }
    }

    pub fn paint(&mut self, pt: &Point, color: Color) {
        self.bbox.update(&pt);
        self.paint.insert(pt.clone(), color);
    }

    pub fn count_painted(&self) -> usize { self.paint.len() }
}
impl fmt::Display for Hull {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for y in (self.bbox.ymin()..=self.bbox.ymax()).rev() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                if let Err(err) = match self.color_at(&Point::new(x, y)) {
                    Color::Black => write!(f, "{}", " "),
                    Color::White => write!(f, "{}", "#"),
                } {
                    return Err(err);
                }
            }
            if let Err(err) = write!(f, "{}", "\n") {
                return Err(err);
            }
        }
        Ok(())
    }
}

struct Robot {
    pos: Point,
    dir: Direction,
}
impl Robot {
    pub fn new() -> Robot {
        Robot { pos: Point::new(0,0), dir: Direction::Up }
    }

    pub fn turn(&mut self, to: Turn) {
        match to {
            Turn::Left => match self.dir {
                Direction::Up    => { self.dir = Direction::Left },
                Direction::Down  => { self.dir = Direction::Right },
                Direction::Left  => { self.dir = Direction::Down },
                Direction::Right => { self.dir = Direction::Up },
            },
            Turn::Right => match self.dir {
                Direction::Up    => { self.dir = Direction::Right },
                Direction::Down  => { self.dir = Direction::Left },
                Direction::Left  => { self.dir = Direction::Up },
                Direction::Right => { self.dir = Direction::Down },
            },
        }
    }

    pub fn step(&mut self) {
        match self.dir {
            Direction::Up    => { self.pos.step(0, 1) },
            Direction::Down  => { self.pos.step(0, -1) },
            Direction::Left  => { self.pos.step(-1, 0) },
            Direction::Right => { self.pos.step(1, 0) },
        };
    }

    pub fn run_code(&mut self, ic: &mut Intcode, hull: &mut Hull) {
        loop {
            // Assumption: always needs exactly 1 input per position!
            ic.pipe(match hull.color_at(&self.pos) {
                Color::Black => 0,
                Color::White => 1,
            });

            while ic.output_len() < 2 && ic.step() { }

            if ic.is_halted() { break; }

            hull.paint(&self.pos, match ic.shift_output() {
                Some(0) => Color::Black,
                Some(1) => Color::White,
                _ => panic!("Color error!"),
            });

            self.turn(match ic.shift_output() {
                Some(0) => Turn::Left,
                Some(1) => Turn::Right,
                _ => panic!("Color error!"),
            });

            self.step();
        }
    }
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 11")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("11.in"));

    let mut ic = Intcode::load(&fname);
    let mut hull = Hull::new();
    let mut robot = Robot::new();

    robot.run_code(&mut ic, &mut hull);

    println!("Step 1: Painted {} panels", hull.count_painted());

    let mut ic = Intcode::load(&fname);
    let mut hull = Hull::new();
    let mut robot = Robot::new();

    hull.paint(&Point::new(0,0), Color::White);
    robot.run_code(&mut ic, &mut hull);

    println!("Step 2: Painted {} panels", hull.count_painted());
    println!("{}", hull);
}
<commit_msg>Day 11: enumes should Copy<commit_after>
extern crate clap;
extern crate intcode;

// Time Start: Wed, 11 Dec 2019 12:22:14 -0500
// Time Finish 1: Wed, 11 Dec 2019 13:44:04 -0500 (1 hour, 21 minutes, 50 seconds)
// Time Finish 2: Wed, 11 Dec 2019 13:46:13 -0500 (2 minutes, 9 seconds)
// Time Total: 1 hour, 23 minutes, 59 seconds

use clap::{Arg, App};

use intcode::Intcode;

use std::collections::HashMap;
use std::fmt;

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

#[derive(Clone, Copy)]
enum Direction { Up, Down, Left, Right }

#[derive(Clone, Copy)]
enum Turn { Left, Right }

#[derive(Hash, Eq, PartialEq, Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}
impl Point {
    pub fn new(x: i32, y: i32) -> Point {
        Point { x: x, y: y }
    }

    fn step(&mut self, dx: i32, dy: i32) {
        if let (Some(x), Some(y)) = (self.x.checked_add(dx), self.y.checked_add(dy)) {
            self.x = x;
            self.y = y;
        } else {
            panic!("Point overflow!");
        }
    }
}
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

#[derive(Copy, Clone)]
struct BBox(i32,i32,i32,i32);// xmin, xmax, ymin, ymax
impl BBox {
    pub fn new() -> BBox {
        BBox(0,0,0,0)
    }

    pub fn xmin(&self) -> i32 { self.0 }
    pub fn xmax(&self) -> i32 { self.1 }
    pub fn ymin(&self) -> i32 { self.2 }
    pub fn ymax(&self) -> i32 { self.3 }

    pub fn update(&mut self, pt: &Point) {
        if pt.x < self.0 { self.0 = pt.x; }
        if pt.x > self.1 { self.1 = pt.x; }
        if pt.y < self.2 { self.2 = pt.y; }
        if pt.y > self.3 { self.3 = pt.y; }
    }
}
impl fmt::Display for BBox {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "BBox: {}, {}, {}, {}", self.0, self.1, self.2, self.3)
    }
}

struct Hull {
    paint: HashMap<Point, Color>,
    pub bbox: BBox,
}
impl Hull {
    pub fn new() -> Hull {
        Hull {
            paint: HashMap::new(),
            bbox: BBox::new(),
        }
    }

    pub fn color_at(&self, pt: &Point) -> Color {
        match self.paint.get(&pt) {
            Some(x) => *x,
            _       => Color::Black,
        }
    }

    pub fn paint(&mut self, pt: &Point, color: Color) {
        self.bbox.update(&pt);
        self.paint.insert(pt.clone(), color);
    }

    pub fn count_painted(&self) -> usize { self.paint.len() }
}
impl fmt::Display for Hull {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for y in (self.bbox.ymin()..=self.bbox.ymax()).rev() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                if let Err(err) = match self.color_at(&Point::new(x, y)) {
                    Color::Black => write!(f, "{}", " "),
                    Color::White => write!(f, "{}", "#"),
                } {
                    return Err(err);
                }
            }
            if let Err(err) = write!(f, "{}", "\n") {
                return Err(err);
            }
        }
        Ok(())
    }
}

struct Robot {
    pos: Point,
    dir: Direction,
}
impl Robot {
    pub fn new() -> Robot {
        Robot { pos: Point::new(0,0), dir: Direction::Up }
    }

    pub fn turn(&mut self, to: Turn) {
        match to {
            Turn::Left => match self.dir {
                Direction::Up    => { self.dir = Direction::Left },
                Direction::Down  => { self.dir = Direction::Right },
                Direction::Left  => { self.dir = Direction::Down },
                Direction::Right => { self.dir = Direction::Up },
            },
            Turn::Right => match self.dir {
                Direction::Up    => { self.dir = Direction::Right },
                Direction::Down  => { self.dir = Direction::Left },
                Direction::Left  => { self.dir = Direction::Up },
                Direction::Right => { self.dir = Direction::Down },
            },
        }
    }

    pub fn step(&mut self) {
        match self.dir {
            Direction::Up    => { self.pos.step(0, 1) },
            Direction::Down  => { self.pos.step(0, -1) },
            Direction::Left  => { self.pos.step(-1, 0) },
            Direction::Right => { self.pos.step(1, 0) },
        };
    }

    pub fn run_code(&mut self, ic: &mut Intcode, hull: &mut Hull) {
        loop {
            // Assumption: always needs exactly 1 input per position!
            ic.pipe(match hull.color_at(&self.pos) {
                Color::Black => 0,
                Color::White => 1,
            });

            while ic.output_len() < 2 && ic.step() { }

            if ic.is_halted() { break; }

            hull.paint(&self.pos, match ic.shift_output() {
                Some(0) => Color::Black,
                Some(1) => Color::White,
                _ => panic!("Color error!"),
            });

            self.turn(match ic.shift_output() {
                Some(0) => Turn::Left,
                Some(1) => Turn::Right,
                _ => panic!("Color error!"),
            });

            self.step();
        }
    }
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 11")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("11.in"));

    let mut ic = Intcode::load(&fname);
    let mut hull = Hull::new();
    let mut robot = Robot::new();

    robot.run_code(&mut ic, &mut hull);

    println!("Step 1: Painted {} panels", hull.count_painted());

    let mut ic = Intcode::load(&fname);
    let mut hull = Hull::new();
    let mut robot = Robot::new();

    hull.paint(&Point::new(0,0), Color::White);
    robot.run_code(&mut ic, &mut hull);

    println!("Step 2: Painted {} panels", hull.count_painted());
    println!("{}", hull);
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]
#![warn(write_literal)]

use std::io::Write;

fn main() {
    let mut v = Vec::new();

    // these should be fine
    write!(&mut v, "Hello");
    writeln!(&mut v, "Hello");
    let world = "world";
    writeln!(&mut v, "Hello {}", world);
    writeln!(&mut v, "Hello {world}", world);
    writeln!(&mut v, "3 in hex is {:X}", 3);
    writeln!(&mut v, "2 + 1 = {:.4}", 3);
    writeln!(&mut v, "2 + 1 = {:5.4}", 3);
    writeln!(&mut v, "Debug test {:?}", "hello, world");
    writeln!(&mut v, "{0:8} {1:>8}", "hello", "world");
    writeln!(&mut v, "{1:8} {0:>8}", "hello", "world");
    writeln!(&mut v, "{foo:8} {bar:>8}", foo="hello", bar="world");
    writeln!(&mut v, "{bar:8} {foo:>8}", foo="hello", bar="world");
    writeln!(&mut v, "{number:>width$}", number=1, width=6);
    writeln!(&mut v, "{number:>0width$}", number=1, width=6);

    // these should throw warnings
    writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
    write!(&mut v, "Hello {}", "world");
    writeln!(&mut v, "Hello {} {}", world, "world");
    writeln!(&mut v, "Hello {}", "world");
    writeln!(&mut v, "10 / 4 is {}", 2.5);
    writeln!(&mut v, "2 + 1 = {}", 3);

    // positional args don't change the fact
    // that we're using a literal -- this should
    // throw a warning
    writeln!(&mut v, "{0} {1}", "hello", "world");
    writeln!(&mut v, "{1} {0}", "hello", "world");

    // named args shouldn't change anything either
    writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world");
    writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world");
}
<commit_msg>Fix copy-paste error<commit_after>#![allow(unused_must_use)]
#![warn(write_literal)]

use std::io::Write;

fn main() {
    let mut v = Vec::new();

    // these should be fine
    write!(&mut v, "Hello");
    writeln!(&mut v, "Hello");
    let world = "world";
    writeln!(&mut v, "Hello {}", world);
    writeln!(&mut v, "Hello {world}", world=world);
    writeln!(&mut v, "3 in hex is {:X}", 3);
    writeln!(&mut v, "2 + 1 = {:.4}", 3);
    writeln!(&mut v, "2 + 1 = {:5.4}", 3);
    writeln!(&mut v, "Debug test {:?}", "hello, world");
    writeln!(&mut v, "{0:8} {1:>8}", "hello", "world");
    writeln!(&mut v, "{1:8} {0:>8}", "hello", "world");
    writeln!(&mut v, "{foo:8} {bar:>8}", foo="hello", bar="world");
    writeln!(&mut v, "{bar:8} {foo:>8}", foo="hello", bar="world");
    writeln!(&mut v, "{number:>width$}", number=1, width=6);
    writeln!(&mut v, "{number:>0width$}", number=1, width=6);

    // these should throw warnings
    writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
    write!(&mut v, "Hello {}", "world");
    writeln!(&mut v, "Hello {} {}", world, "world");
    writeln!(&mut v, "Hello {}", "world");
    writeln!(&mut v, "10 / 4 is {}", 2.5);
    writeln!(&mut v, "2 + 1 = {}", 3);

    // positional args don't change the fact
    // that we're using a literal -- this should
    // throw a warning
    writeln!(&mut v, "{0} {1}", "hello", "world");
    writeln!(&mut v, "{1} {0}", "hello", "world");

    // named args shouldn't change anything either
    writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world");
    writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world");
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! `list` specified values.

use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use servo_arc::Arc;
use style_traits::{ParseError, StyleParseErrorKind};
#[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone;
#[cfg(feature = "gecko")]
use values::CustomIdent;

/// Specified and computed `list-style-type` property.
#[cfg(feature = "gecko")]
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum ListStyleType {
    /// <counter-style> | none
    CounterStyle(CounterStyleOrNone),
    /// <string>
    String(String),
}

#[cfg(feature = "gecko")]
impl ListStyleType {
    /// Initial specified value for `list-style-type`.
    #[inline]
    pub fn disc() -> Self {
        ListStyleType::CounterStyle(CounterStyleOrNone::disc())
    }

    /// Convert from gecko keyword to list-style-type.
    ///
    /// This should only be used for mapping type attribute to
    /// list-style-type, and thus only values possible in that
    /// attribute is considered here.
    pub fn from_gecko_keyword(value: u32) -> Self {
        use gecko_bindings::structs;

        if value == structs::NS_STYLE_LIST_STYLE_NONE {
            return ListStyleType::CounterStyle(CounterStyleOrNone::None);
        }

        ListStyleType::CounterStyle(CounterStyleOrNone::Name(CustomIdent(match value {
            structs::NS_STYLE_LIST_STYLE_DISC => atom!("disc"),
            structs::NS_STYLE_LIST_STYLE_CIRCLE => atom!("circle"),
            structs::NS_STYLE_LIST_STYLE_SQUARE => atom!("square"),
            structs::NS_STYLE_LIST_STYLE_DECIMAL => atom!("decimal"),
            structs::NS_STYLE_LIST_STYLE_LOWER_ROMAN => atom!("lower-roman"),
            structs::NS_STYLE_LIST_STYLE_UPPER_ROMAN => atom!("upper-roman"),
            structs::NS_STYLE_LIST_STYLE_LOWER_ALPHA => atom!("lower-alpha"),
            structs::NS_STYLE_LIST_STYLE_UPPER_ALPHA => atom!("upper-alpha"),
            _ => unreachable!("Unknown counter style keyword value"),
        })))
    }
}

#[cfg(feature = "gecko")]
impl Parse for ListStyleType {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        if let Ok(style) = input.try(|i| CounterStyleOrNone::parse(context, i)) {
            return Ok(ListStyleType::CounterStyle(style));
        }

        Ok(ListStyleType::String(
            input.expect_string()?.as_ref().to_owned(),
        ))
    }
}

/// A quote pair.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub struct QuotePair {
    /// The opening quote.
    pub opening: Box<str>,

    /// The closing quote.
    pub closing: Box<str>,
}

/// Specified and computed `quotes` property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub struct Quotes(
    #[css(if_empty = "none")]
    #[css(iterable)]
    #[ignore_malloc_size_of = "Arc"]
    pub Arc<Box<[QuotePair]>>
);

impl Parse for Quotes {
    fn parse<'i, 't>(
        _: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Quotes, ParseError<'i>> {
        if input
            .try(|input| input.expect_ident_matching("none"))
            .is_ok()
        {
            return Ok(Quotes(Arc::new(Box::new([]))));
        }

        let mut quotes = Vec::new();
        loop {
            let location = input.current_source_location();
            let opening = match input.next() {
                Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into_boxed_str(),
                Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
                Err(_) => break,
            };

            let closing = input.expect_string()?.as_ref().to_owned().into_boxed_str();
            quotes.push(QuotePair { opening, closing });
        }

        if !quotes.is_empty() {
            Ok(Quotes(Arc::new(quotes.into_boxed_slice())))
        } else {
            Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
        }
    }
}
<commit_msg>style: followup post-review nit.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! `list` specified values.

use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use servo_arc::Arc;
use style_traits::{ParseError, StyleParseErrorKind};
#[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone;
#[cfg(feature = "gecko")]
use values::CustomIdent;

/// Specified and computed `list-style-type` property.
#[cfg(feature = "gecko")]
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum ListStyleType {
    /// <counter-style> | none
    CounterStyle(CounterStyleOrNone),
    /// <string>
    String(String),
}

#[cfg(feature = "gecko")]
impl ListStyleType {
    /// Initial specified value for `list-style-type`.
    #[inline]
    pub fn disc() -> Self {
        ListStyleType::CounterStyle(CounterStyleOrNone::disc())
    }

    /// Convert from gecko keyword to list-style-type.
    ///
    /// This should only be used for mapping type attribute to
    /// list-style-type, and thus only values possible in that
    /// attribute is considered here.
    pub fn from_gecko_keyword(value: u32) -> Self {
        use gecko_bindings::structs;

        if value == structs::NS_STYLE_LIST_STYLE_NONE {
            return ListStyleType::CounterStyle(CounterStyleOrNone::None);
        }

        ListStyleType::CounterStyle(CounterStyleOrNone::Name(CustomIdent(match value {
            structs::NS_STYLE_LIST_STYLE_DISC => atom!("disc"),
            structs::NS_STYLE_LIST_STYLE_CIRCLE => atom!("circle"),
            structs::NS_STYLE_LIST_STYLE_SQUARE => atom!("square"),
            structs::NS_STYLE_LIST_STYLE_DECIMAL => atom!("decimal"),
            structs::NS_STYLE_LIST_STYLE_LOWER_ROMAN => atom!("lower-roman"),
            structs::NS_STYLE_LIST_STYLE_UPPER_ROMAN => atom!("upper-roman"),
            structs::NS_STYLE_LIST_STYLE_LOWER_ALPHA => atom!("lower-alpha"),
            structs::NS_STYLE_LIST_STYLE_UPPER_ALPHA => atom!("upper-alpha"),
            _ => unreachable!("Unknown counter style keyword value"),
        })))
    }
}

#[cfg(feature = "gecko")]
impl Parse for ListStyleType {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        if let Ok(style) = input.try(|i| CounterStyleOrNone::parse(context, i)) {
            return Ok(ListStyleType::CounterStyle(style));
        }

        Ok(ListStyleType::String(
            input.expect_string()?.as_ref().to_owned(),
        ))
    }
}

/// A quote pair.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub struct QuotePair {
    /// The opening quote.
    pub opening: Box<str>,

    /// The closing quote.
    pub closing: Box<str>,
}

/// Specified and computed `quotes` property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub struct Quotes(
    #[css(iterable, if_empty = "none")]
    #[ignore_malloc_size_of = "Arc"]
    pub Arc<Box<[QuotePair]>>
);

impl Parse for Quotes {
    fn parse<'i, 't>(
        _: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Quotes, ParseError<'i>> {
        if input
            .try(|input| input.expect_ident_matching("none"))
            .is_ok()
        {
            return Ok(Quotes(Arc::new(Box::new([]))));
        }

        let mut quotes = Vec::new();
        loop {
            let location = input.current_source_location();
            let opening = match input.next() {
                Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into_boxed_str(),
                Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
                Err(_) => break,
            };

            let closing = input.expect_string()?.as_ref().to_owned().into_boxed_str();
            quotes.push(QuotePair { opening, closing });
        }

        if !quotes.is_empty() {
            Ok(Quotes(Arc::new(quotes.into_boxed_slice())))
        } else {
            Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
        }
    }
}
<|endoftext|>


<commit_before>extern crate core;
extern crate minifb;
extern crate prodbg_api;
extern crate bgfx_rs;
extern crate imgui_sys;

pub mod windows;
pub mod menu;

use bgfx_rs::Bgfx;
use core::session::Sessions;
use windows::Windows;
use core::{DynamicReload, Search};
use core::view_plugins::{ViewPlugins};
use core::backend_plugin::{BackendPlugins};
use std::cell::RefCell;
use std::rc::Rc;

use core::plugins::*;

fn main() {
    let bgfx = Bgfx::new();
    let mut sessions = Sessions::new();
    let mut windows = Windows::new();

    let mut lib_handler = DynamicReload::new(None, Some("t2-output"), Search::Backwards);
    let mut plugins = Plugins::new();

    let view_plugins = Rc::new(RefCell::new(ViewPlugins::new()));
    let backend_plugins = Rc::new(RefCell::new(BackendPlugins::new()));

    let session = sessions.create_instance();

    plugins.add_handler(&view_plugins);
    plugins.add_handler(&backend_plugins);
    plugins.search_load_plugins(&mut lib_handler);

    if let Some(backend) = backend_plugins.borrow_mut().create_instance(&"Dummy Backend".to_owned()) {
        if let Some(session) = sessions.get_session(session) {
            session.set_backend(Some(backend));
            println!("set backend");
        }
    }

    windows.create_default();

    loop {
        bgfx.pre_update();

        plugins.update(&mut lib_handler);
        sessions.update(&mut backend_plugins.borrow_mut());
        windows.update(&mut sessions, &mut view_plugins.borrow_mut(), &mut backend_plugins.borrow_mut());

        if windows.should_exit() {
            break;
        }

        bgfx.post_update();
    }
}

// dummy
#[no_mangle]
pub fn init_plugin() {
}
<commit_msg>Started with adding settings<commit_after>extern crate core;
extern crate minifb;
extern crate prodbg_api;
extern crate bgfx_rs;
extern crate imgui_sys;
extern crate settings;

pub mod windows;
pub mod menu;

use bgfx_rs::Bgfx;
use core::session::Sessions;
use windows::Windows;
use settings::Settings;
use core::{DynamicReload, Search};
use core::view_plugins::{ViewPlugins};
use core::backend_plugin::{BackendPlugins};
use std::cell::RefCell;
use std::rc::Rc;

use core::plugins::*;

fn main() {
    let bgfx = Bgfx::new();
    let mut sessions = Sessions::new();
    let mut windows = Windows::new();
    let mut _settings = Settings::new();

    let mut lib_handler = DynamicReload::new(None, Some("t2-output"), Search::Backwards);
    let mut plugins = Plugins::new();

    let view_plugins = Rc::new(RefCell::new(ViewPlugins::new()));
    let backend_plugins = Rc::new(RefCell::new(BackendPlugins::new()));

    let session = sessions.create_instance();

    plugins.add_handler(&view_plugins);
    plugins.add_handler(&backend_plugins);
    plugins.search_load_plugins(&mut lib_handler);

    if let Some(backend) = backend_plugins.borrow_mut().create_instance(&"Dummy Backend".to_owned()) {
        if let Some(session) = sessions.get_session(session) {
            session.set_backend(Some(backend));
            println!("set backend");
        }
    }

    windows.create_default();

    loop {
        bgfx.pre_update();

        plugins.update(&mut lib_handler);
        sessions.update(&mut backend_plugins.borrow_mut());
        windows.update(&mut sessions, &mut view_plugins.borrow_mut(), &mut backend_plugins.borrow_mut());

        if windows.should_exit() {
            break;
        }

        bgfx.post_update();
    }
}

// dummy
#[no_mangle]
pub fn init_plugin() {
}
<|endoftext|>


<commit_before>// run-pass
// ignore-wasm32-bare compiled with panic=abort by default

// This test checks panic emitted from `mem::{uninitialized,zeroed}`.

#![feature(never_type, arbitrary_enum_discriminant)]
#![allow(deprecated, invalid_value)]

use std::{
    mem::{self, MaybeUninit, ManuallyDrop},
    panic,
    ptr::NonNull,
    num,
};

#[allow(dead_code)]
struct Foo {
    x: u8,
    y: !,
}

enum Bar {}

#[allow(dead_code)]
enum OneVariant { Variant(i32) }

#[allow(dead_code, non_camel_case_types)]
enum OneVariant_NonZero {
    Variant(i32, i32, num::NonZeroI32),
    DeadVariant(Bar),
}

// An `Aggregate` abi enum where 0 is not a valid discriminant.
#[allow(dead_code)]
#[repr(i32)]
enum NoNullVariant {
    Variant1(i32, i32) = 1,
    Variant2(i32, i32) = 2,
}

// An enum with ScalarPair layout
#[allow(dead_code)]
enum LR {
    Left(i64),
    Right(i64),
}
#[allow(dead_code, non_camel_case_types)]
enum LR_NonZero {
    Left(num::NonZeroI64),
    Right(num::NonZeroI64),
}

fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
    let err = panic::catch_unwind(op).err();
    assert_eq!(
        err.as_ref().and_then(|a| a.downcast_ref::<String>()).map(|s| &**s),
        Some(msg)
    );
}

fn main() {
    unsafe {
        // Uninhabited types
        test_panic_msg(
            || mem::uninitialized::<!>(),
            "attempted to instantiate uninhabited type `!`"
        );
        test_panic_msg(
            || mem::zeroed::<!>(),
            "attempted to instantiate uninhabited type `!`"
        );
        test_panic_msg(
            || MaybeUninit::<!>::uninit().assume_init(),
            "attempted to instantiate uninhabited type `!`"
        );

        test_panic_msg(
            || mem::uninitialized::<Foo>(),
            "attempted to instantiate uninhabited type `Foo`"
        );
        test_panic_msg(
            || mem::zeroed::<Foo>(),
            "attempted to instantiate uninhabited type `Foo`"
        );
        test_panic_msg(
            || MaybeUninit::<Foo>::uninit().assume_init(),
            "attempted to instantiate uninhabited type `Foo`"
        );

        test_panic_msg(
            || mem::uninitialized::<Bar>(),
            "attempted to instantiate uninhabited type `Bar`"
        );
        test_panic_msg(
            || mem::zeroed::<Bar>(),
            "attempted to instantiate uninhabited type `Bar`"
        );
        test_panic_msg(
            || MaybeUninit::<Bar>::uninit().assume_init(),
            "attempted to instantiate uninhabited type `Bar`"
        );

        // Types that do not like zero-initialziation
        test_panic_msg(
            || mem::uninitialized::<fn()>(),
            "attempted to leave type `fn()` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<fn()>(),
            "attempted to zero-initialize type `fn()`, which is invalid"
        );

        test_panic_msg(
            || mem::uninitialized::<*const dyn Send>(),
            "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<*const dyn Send>(),
            "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid"
        );

        /* FIXME(#66151) we conservatively do not error here yet.
        test_panic_msg(
            || mem::uninitialized::<LR_NonZero>(),
            "attempted to leave type `LR_NonZero` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<LR_NonZero>(),
            "attempted to zero-initialize type `LR_NonZero`, which is invalid"
        );

        test_panic_msg(
            || mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
            "attempted to leave type `std::mem::ManuallyDrop<LR_NonZero>` uninitialized, \
             which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
            "attempted to zero-initialize type `std::mem::ManuallyDrop<LR_NonZero>`, \
             which is invalid"
        );
        */

        test_panic_msg(
            || mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
            "attempted to leave type `(std::ptr::NonNull<u32>, u32, u32)` uninitialized, \
                which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<(NonNull<u32>, u32, u32)>(),
            "attempted to zero-initialize type `(std::ptr::NonNull<u32>, u32, u32)`, \
                which is invalid"
        );

        test_panic_msg(
            || mem::uninitialized::<OneVariant_NonZero>(),
            "attempted to leave type `OneVariant_NonZero` uninitialized, \
                which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<OneVariant_NonZero>(),
            "attempted to zero-initialize type `OneVariant_NonZero`, \
                which is invalid"
        );

        test_panic_msg(
            || mem::uninitialized::<NoNullVariant>(),
            "attempted to leave type `NoNullVariant` uninitialized, \
                which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<NoNullVariant>(),
            "attempted to zero-initialize type `NoNullVariant`, \
                which is invalid"
        );

        // Types that can be zero, but not uninit.
        test_panic_msg(
            || mem::uninitialized::<bool>(),
            "attempted to leave type `bool` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::uninitialized::<LR>(),
            "attempted to leave type `LR` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::uninitialized::<ManuallyDrop<LR>>(),
            "attempted to leave type `std::mem::ManuallyDrop<LR>` uninitialized, which is invalid"
        );

        // Some things that should work.
        let _val = mem::zeroed::<bool>();
        let _val = mem::zeroed::<LR>();
        let _val = mem::zeroed::<ManuallyDrop<LR>>();
        let _val = mem::zeroed::<OneVariant>();
        let _val = mem::zeroed::<Option<&'static i32>>();
        let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
        let _val = mem::uninitialized::<MaybeUninit<bool>>();

        // These are UB because they have not been officially blessed, but we await the resolution
        // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
        // anything about that.
        let _val = mem::uninitialized::<i32>();
        let _val = mem::uninitialized::<*const ()>();
    }
}
<commit_msg>Fix ui test for updated core::panic behaviour.<commit_after>// run-pass
// ignore-wasm32-bare compiled with panic=abort by default

// This test checks panic emitted from `mem::{uninitialized,zeroed}`.

#![feature(never_type, arbitrary_enum_discriminant)]
#![allow(deprecated, invalid_value)]

use std::{
    mem::{self, MaybeUninit, ManuallyDrop},
    panic,
    ptr::NonNull,
    num,
};

#[allow(dead_code)]
struct Foo {
    x: u8,
    y: !,
}

enum Bar {}

#[allow(dead_code)]
enum OneVariant { Variant(i32) }

#[allow(dead_code, non_camel_case_types)]
enum OneVariant_NonZero {
    Variant(i32, i32, num::NonZeroI32),
    DeadVariant(Bar),
}

// An `Aggregate` abi enum where 0 is not a valid discriminant.
#[allow(dead_code)]
#[repr(i32)]
enum NoNullVariant {
    Variant1(i32, i32) = 1,
    Variant2(i32, i32) = 2,
}

// An enum with ScalarPair layout
#[allow(dead_code)]
enum LR {
    Left(i64),
    Right(i64),
}
#[allow(dead_code, non_camel_case_types)]
enum LR_NonZero {
    Left(num::NonZeroI64),
    Right(num::NonZeroI64),
}

fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
    let err = panic::catch_unwind(op).err();
    assert_eq!(
        err.as_ref().and_then(|a| a.downcast_ref::<&str>()),
        Some(&msg)
    );
}

fn main() {
    unsafe {
        // Uninhabited types
        test_panic_msg(
            || mem::uninitialized::<!>(),
            "attempted to instantiate uninhabited type `!`"
        );
        test_panic_msg(
            || mem::zeroed::<!>(),
            "attempted to instantiate uninhabited type `!`"
        );
        test_panic_msg(
            || MaybeUninit::<!>::uninit().assume_init(),
            "attempted to instantiate uninhabited type `!`"
        );

        test_panic_msg(
            || mem::uninitialized::<Foo>(),
            "attempted to instantiate uninhabited type `Foo`"
        );
        test_panic_msg(
            || mem::zeroed::<Foo>(),
            "attempted to instantiate uninhabited type `Foo`"
        );
        test_panic_msg(
            || MaybeUninit::<Foo>::uninit().assume_init(),
            "attempted to instantiate uninhabited type `Foo`"
        );

        test_panic_msg(
            || mem::uninitialized::<Bar>(),
            "attempted to instantiate uninhabited type `Bar`"
        );
        test_panic_msg(
            || mem::zeroed::<Bar>(),
            "attempted to instantiate uninhabited type `Bar`"
        );
        test_panic_msg(
            || MaybeUninit::<Bar>::uninit().assume_init(),
            "attempted to instantiate uninhabited type `Bar`"
        );

        // Types that do not like zero-initialziation
        test_panic_msg(
            || mem::uninitialized::<fn()>(),
            "attempted to leave type `fn()` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<fn()>(),
            "attempted to zero-initialize type `fn()`, which is invalid"
        );

        test_panic_msg(
            || mem::uninitialized::<*const dyn Send>(),
            "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<*const dyn Send>(),
            "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid"
        );

        /* FIXME(#66151) we conservatively do not error here yet.
        test_panic_msg(
            || mem::uninitialized::<LR_NonZero>(),
            "attempted to leave type `LR_NonZero` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<LR_NonZero>(),
            "attempted to zero-initialize type `LR_NonZero`, which is invalid"
        );

        test_panic_msg(
            || mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
            "attempted to leave type `std::mem::ManuallyDrop<LR_NonZero>` uninitialized, \
             which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
            "attempted to zero-initialize type `std::mem::ManuallyDrop<LR_NonZero>`, \
             which is invalid"
        );
        */

        test_panic_msg(
            || mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
            "attempted to leave type `(std::ptr::NonNull<u32>, u32, u32)` uninitialized, \
                which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<(NonNull<u32>, u32, u32)>(),
            "attempted to zero-initialize type `(std::ptr::NonNull<u32>, u32, u32)`, \
                which is invalid"
        );

        test_panic_msg(
            || mem::uninitialized::<OneVariant_NonZero>(),
            "attempted to leave type `OneVariant_NonZero` uninitialized, \
                which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<OneVariant_NonZero>(),
            "attempted to zero-initialize type `OneVariant_NonZero`, \
                which is invalid"
        );

        test_panic_msg(
            || mem::uninitialized::<NoNullVariant>(),
            "attempted to leave type `NoNullVariant` uninitialized, \
                which is invalid"
        );
        test_panic_msg(
            || mem::zeroed::<NoNullVariant>(),
            "attempted to zero-initialize type `NoNullVariant`, \
                which is invalid"
        );

        // Types that can be zero, but not uninit.
        test_panic_msg(
            || mem::uninitialized::<bool>(),
            "attempted to leave type `bool` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::uninitialized::<LR>(),
            "attempted to leave type `LR` uninitialized, which is invalid"
        );
        test_panic_msg(
            || mem::uninitialized::<ManuallyDrop<LR>>(),
            "attempted to leave type `std::mem::ManuallyDrop<LR>` uninitialized, which is invalid"
        );

        // Some things that should work.
        let _val = mem::zeroed::<bool>();
        let _val = mem::zeroed::<LR>();
        let _val = mem::zeroed::<ManuallyDrop<LR>>();
        let _val = mem::zeroed::<OneVariant>();
        let _val = mem::zeroed::<Option<&'static i32>>();
        let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
        let _val = mem::uninitialized::<MaybeUninit<bool>>();

        // These are UB because they have not been officially blessed, but we await the resolution
        // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
        // anything about that.
        let _val = mem::uninitialized::<i32>();
        let _val = mem::uninitialized::<*const ()>();
    }
}
<|endoftext|>


<commit_before>use api_client::ApiClient;
use serde_json;
use serde_json::Value;
use std::collections::HashMap;
use std::io;
use std::io::{Cursor, Read};
use std::io::ErrorKind as IoErrorKind;
use utils::decode_list;
use errors::*;

chef_json_type!(EnvironmentJsonClass, "Chef::Environment");
chef_json_type!(EnvironmentChefType, "environment");

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Environment {
    #[serde(default)]
    pub name: Option<String>,
    #[serde(default)]
    pub description: Option<String>,
    #[serde(default)]
    chef_type: EnvironmentChefType,
    #[serde(default)]
    json_class: EnvironmentJsonClass,
    #[serde(default)]
    pub cookbook_versions: HashMap<String, String>,
    #[serde(default)]
    pub default_attributes: HashMap<String, Value>,
    #[serde(default, rename = "override")]
    pub override_attributes: HashMap<String, Value>,
}

impl Read for Environment {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if let Ok(environment) = serde_json::to_vec(self) {
            let mut environment = Cursor::new(environment.as_ref() as &[u8]);
            Read::read(&mut environment, buf)
        } else {
            Err(io::Error::new(
                IoErrorKind::InvalidData,
                "Failed to convert environment to JSON",
            ))
        }
    }
}

impl Environment {
    pub fn new<S>(name: S) -> Environment
    where
        S: Into<String>,
    {
        Environment {
            name: Some(name.into()),
            ..Default::default()
        }
    }

    pub fn fetch<S: Into<String>>(client: &ApiClient, name: S) -> Result<Environment> {
        let org = &client.config.organization_path();
        let path = format!("{}/environments/{}", org, name.into());
        client.get(path.as_ref()).and_then(
            |r| r.from_json::<Environment>(),
        )
    }

    pub fn save(&self, client: &ApiClient) -> Result<Environment> {
        let name = &self.name.clone().unwrap();
        let org = &client.config.organization_path();
        let path = format!("{}/environments/{}", org, name);
        client.put(path.as_ref(), self).and_then(|r| {
            r.from_json::<Environment>()
        })
    }

    pub fn delete(&self, client: &ApiClient) -> Result<Environment> {
        let name = &self.name.clone().unwrap();
        let org = &client.config.organization_path();
        let path = format!("{}/environments/{}", org, name);
        client.delete(path.as_ref()).and_then(
            |r| r.from_json::<Environment>(),
        )
    }

    pub fn from_json<R>(r: R) -> Result<Environment>
    where
        R: Read,
    {
        Ok(try!(serde_json::from_reader::<R, Environment>(r)))
    }
}

pub fn delete_environment(client: &ApiClient, name: &str) -> Result<Environment> {
    let org = &client.config.organization_path();
    let path = format!("{}/environments/{}", org, name);
    client.delete(path.as_ref()).and_then(
        |r| r.from_json::<Environment>(),
    )
}

#[derive(Debug)]
pub struct EnvironmentList {
    count: usize,
    environments: Vec<String>,
    client: ApiClient,
}

impl EnvironmentList {
    pub fn new(client: &ApiClient) -> EnvironmentList {
        let org = &client.config.organization_path();
        let path = format!("{}/environments", org);
        client
            .get(path.as_ref())
            .and_then(decode_list)
            .and_then(|list| {
                Ok(EnvironmentList {
                    environments: list,
                    count: 0,
                    client: client.clone(),
                })
            })
            .unwrap()
    }
}

impl Iterator for EnvironmentList {
    type Item = Result<Environment>;

    fn count(self) -> usize {
        self.environments.len()
    }

    fn next(&mut self) -> Option<Result<Environment>> {
        if self.environments.len() >= 1 {
            Some(Environment::fetch(
                &self.client,
                self.environments.remove(0),
            ))
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Environment;
    use std::fs::File;

    #[test]
    fn test_environment_from_file() {
        let fh = File::open("fixtures/environment.json").unwrap();
        let environment = Environment::from_json(fh).unwrap();
        assert_eq!(environment.name.unwrap(), "test")
    }
}
<commit_msg>Remove rename<commit_after>use api_client::ApiClient;
use serde_json;
use serde_json::Value;
use std::collections::HashMap;
use std::io;
use std::io::{Cursor, Read};
use std::io::ErrorKind as IoErrorKind;
use utils::decode_list;
use errors::*;

chef_json_type!(EnvironmentJsonClass, "Chef::Environment");
chef_json_type!(EnvironmentChefType, "environment");

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Environment {
    #[serde(default)]
    pub name: Option<String>,
    #[serde(default)]
    pub description: Option<String>,
    #[serde(default)]
    chef_type: EnvironmentChefType,
    #[serde(default)]
    json_class: EnvironmentJsonClass,
    #[serde(default)]
    pub cookbook_versions: HashMap<String, String>,
    #[serde(default)]
    pub default_attributes: HashMap<String, Value>,
    #[serde(default)]
    pub override_attributes: HashMap<String, Value>,
}

impl Read for Environment {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if let Ok(environment) = serde_json::to_vec(self) {
            let mut environment = Cursor::new(environment.as_ref() as &[u8]);
            Read::read(&mut environment, buf)
        } else {
            Err(io::Error::new(
                IoErrorKind::InvalidData,
                "Failed to convert environment to JSON",
            ))
        }
    }
}

impl Environment {
    pub fn new<S>(name: S) -> Environment
    where
        S: Into<String>,
    {
        Environment {
            name: Some(name.into()),
            ..Default::default()
        }
    }

    pub fn fetch<S: Into<String>>(client: &ApiClient, name: S) -> Result<Environment> {
        let org = &client.config.organization_path();
        let path = format!("{}/environments/{}", org, name.into());
        client.get(path.as_ref()).and_then(
            |r| r.from_json::<Environment>(),
        )
    }

    pub fn save(&self, client: &ApiClient) -> Result<Environment> {
        let name = &self.name.clone().unwrap();
        let org = &client.config.organization_path();
        let path = format!("{}/environments/{}", org, name);
        client.put(path.as_ref(), self).and_then(|r| {
            r.from_json::<Environment>()
        })
    }

    pub fn delete(&self, client: &ApiClient) -> Result<Environment> {
        let name = &self.name.clone().unwrap();
        let org = &client.config.organization_path();
        let path = format!("{}/environments/{}", org, name);
        client.delete(path.as_ref()).and_then(
            |r| r.from_json::<Environment>(),
        )
    }

    pub fn from_json<R>(r: R) -> Result<Environment>
    where
        R: Read,
    {
        Ok(try!(serde_json::from_reader::<R, Environment>(r)))
    }
}

pub fn delete_environment(client: &ApiClient, name: &str) -> Result<Environment> {
    let org = &client.config.organization_path();
    let path = format!("{}/environments/{}", org, name);
    client.delete(path.as_ref()).and_then(
        |r| r.from_json::<Environment>(),
    )
}

#[derive(Debug)]
pub struct EnvironmentList {
    count: usize,
    environments: Vec<String>,
    client: ApiClient,
}

impl EnvironmentList {
    pub fn new(client: &ApiClient) -> EnvironmentList {
        let org = &client.config.organization_path();
        let path = format!("{}/environments", org);
        client
            .get(path.as_ref())
            .and_then(decode_list)
            .and_then(|list| {
                Ok(EnvironmentList {
                    environments: list,
                    count: 0,
                    client: client.clone(),
                })
            })
            .unwrap()
    }
}

impl Iterator for EnvironmentList {
    type Item = Result<Environment>;

    fn count(self) -> usize {
        self.environments.len()
    }

    fn next(&mut self) -> Option<Result<Environment>> {
        if self.environments.len() >= 1 {
            Some(Environment::fetch(
                &self.client,
                self.environments.remove(0),
            ))
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Environment;
    use std::fs::File;

    #[test]
    fn test_environment_from_file() {
        let fh = File::open("fixtures/environment.json").unwrap();
        let environment = Environment::from_json(fh).unwrap();
        assert_eq!(environment.name.unwrap(), "test")
    }
}
<|endoftext|>