<commit_before>use ra_ide_db::imports_locator::ImportsLocator;
use ra_syntax::ast::{self, AstNode};

use crate::{
    assist_ctx::{Assist, AssistCtx},
    insert_use_statement, AssistId,
};
use std::collections::BTreeSet;

// Assist: auto_import
//
// If the name is unresolved, provides all possible imports for it.
//
// ```
// fn main() {
//     let map = HashMap<|>::new();
// }
// # pub mod std { pub mod collections { pub struct HashMap { } } }
// ```
// ->
// ```
// use std::collections::HashMap;
//
// fn main() {
//     let map = HashMap::new();
// }
// # pub mod std { pub mod collections { pub struct HashMap { } } }
// ```
pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
    let path_to_import: ast::Path = ctx.find_node_at_offset()?;
    let path_to_import_syntax = path_to_import.syntax();
    if path_to_import_syntax.ancestors().find_map(ast::UseItem::cast).is_some() {
        return None;
    }
    let name_to_import =
        path_to_import_syntax.descendants().find_map(ast::NameRef::cast)?.syntax().to_string();

    let module = path_to_import_syntax.ancestors().find_map(ast::Module::cast);
    let position = match module.and_then(|it| it.item_list()) {
        Some(item_list) => item_list.syntax().clone(),
        None => {
            let current_file = path_to_import_syntax.ancestors().find_map(ast::SourceFile::cast)?;
            current_file.syntax().clone()
        }
    };
    let source_analyzer = ctx.source_analyzer(&position, None);
    let module_with_name_to_import = source_analyzer.module()?;
    if source_analyzer.resolve_path(ctx.db, &path_to_import).is_some() {
        return None;
    }

    let mut imports_locator = ImportsLocator::new(ctx.db);

    let proposed_imports = imports_locator
        .find_imports(&name_to_import)
        .into_iter()
        .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def))
        .filter(|use_path| !use_path.segments.is_empty())
        .take(20)
        .collect::<BTreeSet<_>>();

    if proposed_imports.is_empty() {
        return None;
    }

    let mut group = ctx.add_assist_group(format!("Import {}", name_to_import));
    for import in proposed_imports {
        group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| {
            insert_use_statement(
                &position,
                path_to_import_syntax,
                &import,
                edit.text_edit_builder(),
            );
        });
    }
    group.finish()
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn applicable_when_found_an_import() {
        check_assist(
            auto_import,
            r"
            <|>PubStruct

            pub mod PubMod {
                pub struct PubStruct;
            }
            ",
            r"
            <|>use PubMod::PubStruct;

            PubStruct

            pub mod PubMod {
                pub struct PubStruct;
            }
            ",
        );
    }

    #[test]
    fn auto_imports_are_merged() {
        check_assist(
            auto_import,
            r"
            use PubMod::PubStruct1;

            struct Test {
                test: Pub<|>Struct2<u8>,
            }

            pub mod PubMod {
                pub struct PubStruct1;
                pub struct PubStruct2<T> {
                    _t: T,
                }
            }
            ",
            r"
            use PubMod::{PubStruct2, PubStruct1};

            struct Test {
                test: Pub<|>Struct2<u8>,
            }

            pub mod PubMod {
                pub struct PubStruct1;
                pub struct PubStruct2<T> {
                    _t: T,
                }
            }
            ",
        );
    }

    #[test]
    fn applicable_when_found_multiple_imports() {
        check_assist(
            auto_import,
            r"
            PubSt<|>ruct

            pub mod PubMod1 {
                pub struct PubStruct;
            }
            pub mod PubMod2 {
                pub struct PubStruct;
            }
            pub mod PubMod3 {
                pub struct PubStruct;
            }
            ",
            r"
            use PubMod1::PubStruct;

            PubSt<|>ruct

            pub mod PubMod1 {
                pub struct PubStruct;
            }
            pub mod PubMod2 {
                pub struct PubStruct;
            }
            pub mod PubMod3 {
                pub struct PubStruct;
            }
            ",
        );
    }

    #[test]
    fn not_applicable_for_already_imported_types() {
        check_assist_not_applicable(
            auto_import,
            r"
            use PubMod::PubStruct;

            PubStruct<|>

            pub mod PubMod {
                pub struct PubStruct;
            }
            ",
        );
    }

    #[test]
    fn not_applicable_for_types_with_private_paths() {
        check_assist_not_applicable(
            auto_import,
            r"
            PrivateStruct<|>

            pub mod PubMod {
                struct PrivateStruct;
            }
            ",
        );
    }

    #[test]
    fn not_applicable_when_no_imports_found() {
        check_assist_not_applicable(
            auto_import,
            "
            PubStruct<|>",
        );
    }

    #[test]
    fn not_applicable_in_import_statements() {
        check_assist_not_applicable(
            auto_import,
            r"
            use PubStruct<|>;

            pub mod PubMod {
                pub struct PubStruct;
            }",
        );
    }

    #[test]
    fn function_import() {
        check_assist(
            auto_import,
            r"
            test_function<|>

            pub mod PubMod {
                pub fn test_function() {};
            }
            ",
            r"
            use PubMod::test_function;

            test_function<|>

            pub mod PubMod {
                pub fn test_function() {};
            }
            ",
        );
    }
}
<commit_msg>Set auto-import target<commit_after>use ra_ide_db::imports_locator::ImportsLocator;
use ra_syntax::ast::{self, AstNode};

use crate::{
    assist_ctx::{Assist, AssistCtx},
    insert_use_statement, AssistId,
};
use std::collections::BTreeSet;

// Assist: auto_import
//
// If the name is unresolved, provides all possible imports for it.
//
// ```
// fn main() {
//     let map = HashMap<|>::new();
// }
// # pub mod std { pub mod collections { pub struct HashMap { } } }
// ```
// ->
// ```
// use std::collections::HashMap;
//
// fn main() {
//     let map = HashMap::new();
// }
// # pub mod std { pub mod collections { pub struct HashMap { } } }
// ```
pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
    let path_to_import: ast::Path = ctx.find_node_at_offset()?;
    let path_to_import_syntax = path_to_import.syntax();
    if path_to_import_syntax.ancestors().find_map(ast::UseItem::cast).is_some() {
        return None;
    }
    let name_to_import =
        path_to_import_syntax.descendants().find_map(ast::NameRef::cast)?.syntax().to_string();

    let module = path_to_import_syntax.ancestors().find_map(ast::Module::cast);
    let position = match module.and_then(|it| it.item_list()) {
        Some(item_list) => item_list.syntax().clone(),
        None => {
            let current_file = path_to_import_syntax.ancestors().find_map(ast::SourceFile::cast)?;
            current_file.syntax().clone()
        }
    };
    let source_analyzer = ctx.source_analyzer(&position, None);
    let module_with_name_to_import = source_analyzer.module()?;
    if source_analyzer.resolve_path(ctx.db, &path_to_import).is_some() {
        return None;
    }

    let mut imports_locator = ImportsLocator::new(ctx.db);

    let proposed_imports = imports_locator
        .find_imports(&name_to_import)
        .into_iter()
        .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def))
        .filter(|use_path| !use_path.segments.is_empty())
        .take(20)
        .collect::<BTreeSet<_>>();

    if proposed_imports.is_empty() {
        return None;
    }

    let mut group = ctx.add_assist_group(format!("Import {}", name_to_import));
    for import in proposed_imports {
        group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| {
            edit.target(path_to_import_syntax.text_range());
            insert_use_statement(
                &position,
                path_to_import_syntax,
                &import,
                edit.text_edit_builder(),
            );
        });
    }
    group.finish()
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn applicable_when_found_an_import() {
        check_assist(
            auto_import,
            r"
            <|>PubStruct

            pub mod PubMod {
                pub struct PubStruct;
            }
            ",
            r"
            <|>use PubMod::PubStruct;

            PubStruct

            pub mod PubMod {
                pub struct PubStruct;
            }
            ",
        );
    }

    #[test]
    fn auto_imports_are_merged() {
        check_assist(
            auto_import,
            r"
            use PubMod::PubStruct1;

            struct Test {
                test: Pub<|>Struct2<u8>,
            }

            pub mod PubMod {
                pub struct PubStruct1;
                pub struct PubStruct2<T> {
                    _t: T,
                }
            }
            ",
            r"
            use PubMod::{PubStruct2, PubStruct1};

            struct Test {
                test: Pub<|>Struct2<u8>,
            }

            pub mod PubMod {
                pub struct PubStruct1;
                pub struct PubStruct2<T> {
                    _t: T,
                }
            }
            ",
        );
    }

    #[test]
    fn applicable_when_found_multiple_imports() {
        check_assist(
            auto_import,
            r"
            PubSt<|>ruct

            pub mod PubMod1 {
                pub struct PubStruct;
            }
            pub mod PubMod2 {
                pub struct PubStruct;
            }
            pub mod PubMod3 {
                pub struct PubStruct;
            }
            ",
            r"
            use PubMod1::PubStruct;

            PubSt<|>ruct

            pub mod PubMod1 {
                pub struct PubStruct;
            }
            pub mod PubMod2 {
                pub struct PubStruct;
            }
            pub mod PubMod3 {
                pub struct PubStruct;
            }
            ",
        );
    }

    #[test]
    fn not_applicable_for_already_imported_types() {
        check_assist_not_applicable(
            auto_import,
            r"
            use PubMod::PubStruct;

            PubStruct<|>

            pub mod PubMod {
                pub struct PubStruct;
            }
            ",
        );
    }

    #[test]
    fn not_applicable_for_types_with_private_paths() {
        check_assist_not_applicable(
            auto_import,
            r"
            PrivateStruct<|>

            pub mod PubMod {
                struct PrivateStruct;
            }
            ",
        );
    }

    #[test]
    fn not_applicable_when_no_imports_found() {
        check_assist_not_applicable(
            auto_import,
            "
            PubStruct<|>",
        );
    }

    #[test]
    fn not_applicable_in_import_statements() {
        check_assist_not_applicable(
            auto_import,
            r"
            use PubStruct<|>;

            pub mod PubMod {
                pub struct PubStruct;
            }",
        );
    }

    #[test]
    fn function_import() {
        check_assist(
            auto_import,
            r"
            test_function<|>

            pub mod PubMod {
                pub fn test_function() {};
            }
            ",
            r"
            use PubMod::test_function;

            test_function<|>

            pub mod PubMod {
                pub fn test_function() {};
            }
            ",
        );
    }

    #[test]
    fn auto_import_target() {
        check_assist_target(
            auto_import,
            r"
            struct AssistInfo {
                group_label: Option<<|>GroupLabel>,
            }

            mod m { pub struct GroupLabel; }
            ",
            "GroupLabel",
        )
    }
}
<|endoftext|>


<commit_before>/* A very simple front end to test agb-core (https://github.com/aHeraud/agb)*/

extern crate agb_core;
extern crate sdl2;
extern crate image;
extern crate clap;

mod debugger;

use std::sync::mpsc::sync_channel;
use std::thread;
use std::time::Duration;
use std::thread::sleep;
use std::collections::HashMap;
use std::fs::File;
use std::io::{stdin, stdout, Read, Write, Error};
use std::path::Path;
use std::num::ParseIntError;
use std::sync::{Arc, Mutex};
use std::ops::DerefMut;
use std::net::{TcpListener, TcpStream, SocketAddr, IpAddr, Ipv4Addr};

use agb_core::gameboy::Gameboy;
use agb_core::gameboy::debugger::DebuggerInterface;

use sdl2::pixels::Color;
use sdl2::pixels::PixelFormatEnum;
use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use clap::{Arg, App};

const DEFAULT_SCALE: usize = 2;

fn main() {
	/* Create and initialize gameboy */

	//Parse command line arguments
	let matches = App::new("agb")
		.version("0.1")
		.author("Achille Heraud <achille@heraud.xyz>")
		.about("A GameBoy Emulator")
		.arg(Arg::with_name("rom")
			.long("rom")
			.takes_value(true)
			.value_name("FILE")
			.required(true))
		.arg(Arg::with_name("ram")
			.long("ram")
			.takes_value(true)
			.value_name("FILE")
			.required(false))
		.arg(Arg::with_name("paused")
			.long("pause")
			.short("p")
			.required(false))
		.arg(Arg::with_name("print_serial")
			.help("print data written to the serial port")
			.long("print_serial")
			.conflicts_with_all(&["listen", "connect"])
			.required(false))
		.arg(Arg::with_name("listen")
			.help("listen for remote connections (for serial communication over tcp/ip)")
			.long("listen")
			.takes_value(true)
			.value_name("PORT")
			.conflicts_with("connect")
			.required(false))
		.arg(Arg::with_name("connect")
			.help("provide to ip:port to connect to a remote host (for serial communication over tcp/ip")
			.long("connect")
			.takes_value(true)
			.value_name("IP:PORT")
			.required(false))
		.get_matches();

	let rom = read_file(matches.value_of("rom").unwrap()).expect("Could not open rom file.");
	let ram: Option<Box<[u8]>> = if let Some(ram_path) = matches.value_of("ram") {
		Some(read_file(ram_path).expect("failed to read ram file"))
	}
	else {
		None
	};

	let start_paused: bool = matches.occurrences_of("paused") > 0;

	let mut gameboy = Gameboy::new(rom, ram).expect("Failed to initialize gameboy");
	let paused: Arc<Mutex<bool>> = Arc::new(Mutex::new(start_paused));
	gameboy.debugger.enable();
	{
		let paused = paused.clone();
		gameboy.register_breakpoint_callback(move |breakpoint| {
			println!("triggered breakpoint access_type: {:?}, address: 0x{:x}", breakpoint.access_type, breakpoint.address);
			let mut paused = paused.lock().unwrap();
			*paused = true;
		});
	}

	if let Some(ref port_str) = matches.value_of("listen") {
		// set up a tcp socket to accept incoming connections
		if let Ok(port) = u16::from_str_radix(port_str, 10) {
			let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127,0,0,1)), port);
			let listener = TcpListener::bind(addr).unwrap();
			let (local_sender, local_receiver) = gameboy.create_serial_channels();

			println!("waiting for connection...");
			let (mut stream, remote_addr) = listener.accept().unwrap();
			println!("connected to {}", remote_addr);

			stream.set_nonblocking(false).expect("failed to set tcp socket to nonblocking mode");
			stream.set_nodelay(true).expect("failed to set tcp socket nodelay mode");

			//create sender thread
			{
				let mut stream = stream.try_clone().unwrap();
				thread::spawn(move || {
					let mut buffer: [u8; 1] = [0;1];
					loop {
						let data = local_receiver.recv().unwrap();
						buffer[0] = data;
						if stream.write(&buffer[..]).is_err() {
							return;
						}
					}
				});
			}

			//create receiver thread
			thread::spawn(move || {
				let mut buffer: [u8; 1] = [0;1];
				loop {
					if stream.read(&mut buffer[..]).is_err() {
						return;
					}
					local_sender.send(buffer[0]).unwrap();
				}
			});
		}
		else {
			println!("Invalid port: port must be an integer in the range 0 to 65535.");
			return;
		}
	}
	else if let Some(ref addr) = matches.value_of("connect") {
		let (local_sender, local_receiver) = gameboy.create_serial_channels();
		let addr: SocketAddr = addr.parse().unwrap();
		println!("attempting to connect...");
		let mut stream = TcpStream::connect(addr).unwrap();
		println!("connected!");

		stream.set_nonblocking(false).expect("failed to set tcp socket to nonblocking mode");
		stream.set_nodelay(true).expect("failed to set tcp socket nodelay mode");

		//create sender thread
		{
			let mut stream = stream.try_clone().unwrap();
			thread::spawn(move || {
				let mut buffer: [u8; 1] = [0;1];
				loop {
					let data = local_receiver.recv().unwrap();
					buffer[0] = data;
					if stream.write(&buffer[..]).is_err() {
						return;
					}
				}
			});
		}

		//create receiver thread
		thread::spawn(move || {
			let mut buffer: [u8; 1] = [0;1];
			loop {
				if stream.read(&mut buffer[..]).is_err() {
					return;
				}
				local_sender.send(buffer[0]).unwrap();
			}
		});
	}
	else if matches.occurrences_of("print_serial") > 0 {
		let (sender, reciever) = gameboy.create_serial_channels();
		thread::spawn(move || {
			loop {
				let data = reciever.recv().unwrap();
				sender.send(0xFF).unwrap();
				print!("{}", data as char);
				stdout().flush().ok().expect("could not flush stdout");
			}
		});
	}

	//debugger text input
	let (tx, rx) = sync_channel(0);
	let main_handle = thread::current();
	thread::spawn(move || {
		println!("debugger enabled - you can type debugger commands here! Type 'help' for more info.");
		loop {
			let mut buf: String = String::new();
			stdin().read_line(&mut buf).unwrap();
			tx.send(buf).unwrap();
			main_handle.unpark();
		}
	});

	//Keys
	let mut keymap: HashMap<Keycode, agb_core::gameboy::Key> = HashMap::new();
	keymap.insert(Keycode::Up, agb_core::gameboy::Key::Up);
	keymap.insert(Keycode::Down, agb_core::gameboy::Key::Down);
	keymap.insert(Keycode::Left, agb_core::gameboy::Key::Left);
	keymap.insert(Keycode::Right, agb_core::gameboy::Key::Right);
	keymap.insert(Keycode::X, agb_core::gameboy::Key::A);
	keymap.insert(Keycode::Z, agb_core::gameboy::Key::B);
	keymap.insert(Keycode::C, agb_core::gameboy::Key::Select);
	keymap.insert(Keycode::V, agb_core::gameboy::Key::Start);

	/* Setup for sdl */
	let sdl_context = sdl2::init().expect("Failed to initialize sdl2");
	let video_subsystem = sdl_context.video().expect("Failed to initialize sdl2 video subsystem");
	let timer_subsystem = sdl_context.timer().expect("Failed to initialize sdl2 timer subsystem");

	//Set resolution
	let width: u32 = (agb_core::WIDTH * DEFAULT_SCALE) as u32;
	let height: u32 = (agb_core::HEIGHT * DEFAULT_SCALE) as u32;

	let window = video_subsystem.window("agb", width, height)
		.position_centered()
		.opengl()
		.build()
		.expect("Failed to create window");

	let mut renderer = window.renderer().build().unwrap();
	let mut event_pump = sdl_context.event_pump().unwrap();
	let mut draw = |gameboy: &mut Gameboy| {
		renderer.set_draw_color(Color::RGB(80, 120, 120));
		renderer.clear();
		const WIDTH: usize = agb_core::WIDTH;
		const HEIGHT: usize = agb_core::HEIGHT;

		let data: &mut[u8] = unsafe {
			//#[allow(mutable_transmutes)]
			//std::mem::transmute::<&[u32], &mut[u8]>(gbc.get_framebuffer())
			let temp: &mut [u32] = gameboy.get_framebuffer_mut();
			std::mem::transmute::<&mut[u32], &mut[u8]>(temp)
		};

		let mut texture = renderer.create_texture_streaming(PixelFormatEnum::RGBA8888, WIDTH as u32, HEIGHT as u32).unwrap();
		let _ = texture.update(None, data, WIDTH * 4);
		let rect: Rect = renderer.viewport();
		let _ = renderer.copy(&texture, None, Some(rect));
		renderer.present();
	};

	//Get timer frequency
	let frequency: u64 = timer_subsystem.performance_frequency();

	'running: loop {
		//wait for input from the debugger, but don't wait forever since
		//we don't want the block the gui thread forever
		{
			let paused = paused.lock().unwrap();
			if *paused {
				std::thread::park_timeout(Duration::new(0, 100000000));
			}
		}

		let frame_start: u64 = timer_subsystem.performance_counter();

		//handle debugger input
		if let Ok(input) = rx.try_recv() {
			if input.trim() == "quit" || input.trim() == "exit" {
				break 'running;
			}
			else {
				let mut paused = paused.lock().unwrap();
				debugger::debug(input, &mut gameboy, paused.deref_mut());
			}
		}

		for event in event_pump.poll_iter() {
			match event {
				Event::KeyDown { keycode, .. } => {
					if keycode.is_some() {
						let key = keymap.get(&keycode.unwrap());
						if key.is_some() {
							gameboy.keydown(*key.unwrap());
						}
					}
				},
				Event::KeyUp { keycode, .. } => {
					if keycode.is_some() {
						let key = keymap.get(&keycode.unwrap());
						if key.is_some() {
							gameboy.keyup(*key.unwrap());
						}
					}
				},
				Event::Quit {..} => {
					break 'running;
				},
				_ => {},
			};
		}

		{
			let paused = paused.lock().unwrap();
			if !*paused {
				gameboy.emulate(Duration::from_millis(1000 / 60));
				draw(&mut gameboy);

				//60hz
				let frame_end: u64 = timer_subsystem.performance_counter();
				let frame_duration: u64 = frame_end - frame_start;
				let ms: u64 = (frame_duration * 1000) / frequency;
				if ms < 1000/60 {
					let duration = Duration::from_millis((1000/60) - ms);
					sleep(duration);
				}
			}
		}
	}
}

pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>, Error> {
	let mut file = try!(File::open(path));
	let mut buffer = Vec::new();
	try!(file.read_to_end(&mut buffer));
	Ok(buffer.into_boxed_slice())
}

///accepts prefixes (none for base 10, 0x for hex, 0b for binary)
///from_str_radix isn't part of a trait so it can't be generic
pub fn parse_u8(s: &str) -> Result<u8, ParseIntError> {
	if s.starts_with("0x") {
		u8::from_str_radix(&s[2..], 16)
	}
	else if s.starts_with("0b") {
		u8::from_str_radix(&s[2..], 2)
	}
	else {
		u8::from_str_radix(s, 10)
	}
}

///accepts prefixes (none for base 10, 0x for hex, 0b for binary)
pub fn parse_u16(s: &str) -> Result<u16, ParseIntError> {
	if s.starts_with("0x") {
		u16::from_str_radix(&s[2..], 16)
	}
	else if s.starts_with("0b") {
		u16::from_str_radix(&s[2..], 2)
	}
	else {
		u16::from_str_radix(s, 10)
	}
}

///accepts prefixes (none for base 10, 0x for hex, 0b for binary)
pub fn parse_usize(s: &str) -> Result<usize, ParseIntError> {
	if s.starts_with("0x") {
		usize::from_str_radix(&s[2..], 16)
	}
	else if s.starts_with("0b") {
		usize::from_str_radix(&s[2..], 2)
	}
	else {
		usize::from_str_radix(s, 10)
	}
}
<commit_msg>Fixed a deadlock triggered by hitting a breakpoint.<commit_after>/* A very simple front end to test agb-core (https://github.com/aHeraud/agb)*/

extern crate agb_core;
extern crate sdl2;
extern crate image;
extern crate clap;

mod debugger;

use std::sync::mpsc::sync_channel;
use std::thread;
use std::time::Duration;
use std::thread::sleep;
use std::collections::HashMap;
use std::fs::File;
use std::io::{stdin, stdout, Read, Write, Error};
use std::path::Path;
use std::num::ParseIntError;
use std::sync::{Arc, Mutex};
use std::ops::DerefMut;
use std::net::{TcpListener, TcpStream, SocketAddr, IpAddr, Ipv4Addr};

use agb_core::gameboy::Gameboy;
use agb_core::gameboy::debugger::DebuggerInterface;

use sdl2::pixels::Color;
use sdl2::pixels::PixelFormatEnum;
use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use clap::{Arg, App};

const DEFAULT_SCALE: usize = 2;

fn main() {
	/* Create and initialize gameboy */

	//Parse command line arguments
	let matches = App::new("agb")
		.version("0.1")
		.author("Achille Heraud <achille@heraud.xyz>")
		.about("A GameBoy Emulator")
		.arg(Arg::with_name("rom")
			.long("rom")
			.takes_value(true)
			.value_name("FILE")
			.required(true))
		.arg(Arg::with_name("ram")
			.long("ram")
			.takes_value(true)
			.value_name("FILE")
			.required(false))
		.arg(Arg::with_name("paused")
			.long("pause")
			.short("p")
			.required(false))
		.arg(Arg::with_name("print_serial")
			.help("print data written to the serial port")
			.long("print_serial")
			.conflicts_with_all(&["listen", "connect"])
			.required(false))
		.arg(Arg::with_name("listen")
			.help("listen for remote connections (for serial communication over tcp/ip)")
			.long("listen")
			.takes_value(true)
			.value_name("PORT")
			.conflicts_with("connect")
			.required(false))
		.arg(Arg::with_name("connect")
			.help("provide to ip:port to connect to a remote host (for serial communication over tcp/ip")
			.long("connect")
			.takes_value(true)
			.value_name("IP:PORT")
			.required(false))
		.get_matches();

	let rom = read_file(matches.value_of("rom").unwrap()).expect("Could not open rom file.");
	let ram: Option<Box<[u8]>> = if let Some(ram_path) = matches.value_of("ram") {
		Some(read_file(ram_path).expect("failed to read ram file"))
	}
	else {
		None
	};

	let start_paused: bool = matches.occurrences_of("paused") > 0;

	let mut gameboy = Gameboy::new(rom, ram).expect("Failed to initialize gameboy");
	let paused: Arc<Mutex<bool>> = Arc::new(Mutex::new(start_paused));
	gameboy.debugger.enable();
	{
		let paused = paused.clone();
		gameboy.register_breakpoint_callback(move |breakpoint| {
			println!("triggered breakpoint access_type: {:?}, address: 0x{:x}", breakpoint.access_type, breakpoint.address);
			let mut paused = paused.lock().unwrap();
			*paused = true;
		});
	}

	if let Some(ref port_str) = matches.value_of("listen") {
		// set up a tcp socket to accept incoming connections
		if let Ok(port) = u16::from_str_radix(port_str, 10) {
			let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127,0,0,1)), port);
			let listener = TcpListener::bind(addr).unwrap();
			let (local_sender, local_receiver) = gameboy.create_serial_channels();

			println!("waiting for connection...");
			let (mut stream, remote_addr) = listener.accept().unwrap();
			println!("connected to {}", remote_addr);

			stream.set_nonblocking(false).expect("failed to set tcp socket to nonblocking mode");
			stream.set_nodelay(true).expect("failed to set tcp socket nodelay mode");

			//create sender thread
			{
				let mut stream = stream.try_clone().unwrap();
				thread::spawn(move || {
					let mut buffer: [u8; 1] = [0;1];
					loop {
						let data = local_receiver.recv().unwrap();
						buffer[0] = data;
						if stream.write(&buffer[..]).is_err() {
							return;
						}
					}
				});
			}

			//create receiver thread
			thread::spawn(move || {
				let mut buffer: [u8; 1] = [0;1];
				loop {
					if stream.read(&mut buffer[..]).is_err() {
						return;
					}
					local_sender.send(buffer[0]).unwrap();
				}
			});
		}
		else {
			println!("Invalid port: port must be an integer in the range 0 to 65535.");
			return;
		}
	}
	else if let Some(ref addr) = matches.value_of("connect") {
		let (local_sender, local_receiver) = gameboy.create_serial_channels();
		let addr: SocketAddr = addr.parse().unwrap();
		println!("attempting to connect...");
		let mut stream = TcpStream::connect(addr).unwrap();
		println!("connected!");

		stream.set_nonblocking(false).expect("failed to set tcp socket to nonblocking mode");
		stream.set_nodelay(true).expect("failed to set tcp socket nodelay mode");

		//create sender thread
		{
			let mut stream = stream.try_clone().unwrap();
			thread::spawn(move || {
				let mut buffer: [u8; 1] = [0;1];
				loop {
					let data = local_receiver.recv().unwrap();
					buffer[0] = data;
					if stream.write(&buffer[..]).is_err() {
						return;
					}
				}
			});
		}

		//create receiver thread
		thread::spawn(move || {
			let mut buffer: [u8; 1] = [0;1];
			loop {
				if stream.read(&mut buffer[..]).is_err() {
					return;
				}
				local_sender.send(buffer[0]).unwrap();
			}
		});
	}
	else if matches.occurrences_of("print_serial") > 0 {
		let (sender, reciever) = gameboy.create_serial_channels();
		thread::spawn(move || {
			loop {
				let data = reciever.recv().unwrap();
				sender.send(0xFF).unwrap();
				print!("{}", data as char);
				stdout().flush().ok().expect("could not flush stdout");
			}
		});
	}

	//debugger text input
	let (tx, rx) = sync_channel(0);
	let main_handle = thread::current();
	thread::spawn(move || {
		println!("debugger enabled - you can type debugger commands here! Type 'help' for more info.");
		loop {
			let mut buf: String = String::new();
			stdin().read_line(&mut buf).unwrap();
			tx.send(buf).unwrap();
			main_handle.unpark();
		}
	});

	//Keys
	let mut keymap: HashMap<Keycode, agb_core::gameboy::Key> = HashMap::new();
	keymap.insert(Keycode::Up, agb_core::gameboy::Key::Up);
	keymap.insert(Keycode::Down, agb_core::gameboy::Key::Down);
	keymap.insert(Keycode::Left, agb_core::gameboy::Key::Left);
	keymap.insert(Keycode::Right, agb_core::gameboy::Key::Right);
	keymap.insert(Keycode::X, agb_core::gameboy::Key::A);
	keymap.insert(Keycode::Z, agb_core::gameboy::Key::B);
	keymap.insert(Keycode::C, agb_core::gameboy::Key::Select);
	keymap.insert(Keycode::V, agb_core::gameboy::Key::Start);

	/* Setup for sdl */
	let sdl_context = sdl2::init().expect("Failed to initialize sdl2");
	let video_subsystem = sdl_context.video().expect("Failed to initialize sdl2 video subsystem");
	let timer_subsystem = sdl_context.timer().expect("Failed to initialize sdl2 timer subsystem");

	//Set resolution
	let width: u32 = (agb_core::WIDTH * DEFAULT_SCALE) as u32;
	let height: u32 = (agb_core::HEIGHT * DEFAULT_SCALE) as u32;

	let window = video_subsystem.window("agb", width, height)
		.position_centered()
		.opengl()
		.build()
		.expect("Failed to create window");

	let mut renderer = window.renderer().build().unwrap();
	let mut event_pump = sdl_context.event_pump().unwrap();
	let mut draw = |gameboy: &mut Gameboy| {
		renderer.set_draw_color(Color::RGB(80, 120, 120));
		renderer.clear();
		const WIDTH: usize = agb_core::WIDTH;
		const HEIGHT: usize = agb_core::HEIGHT;

		let data: &mut[u8] = unsafe {
			//#[allow(mutable_transmutes)]
			//std::mem::transmute::<&[u32], &mut[u8]>(gbc.get_framebuffer())
			let temp: &mut [u32] = gameboy.get_framebuffer_mut();
			std::mem::transmute::<&mut[u32], &mut[u8]>(temp)
		};

		let mut texture = renderer.create_texture_streaming(PixelFormatEnum::RGBA8888, WIDTH as u32, HEIGHT as u32).unwrap();
		let _ = texture.update(None, data, WIDTH * 4);
		let rect: Rect = renderer.viewport();
		let _ = renderer.copy(&texture, None, Some(rect));
		renderer.present();
	};

	//Get timer frequency
	let frequency: u64 = timer_subsystem.performance_frequency();

	'running: loop {
		//wait for input from the debugger, but don't wait forever since
		//we don't want the block the gui thread forever
		{
			let paused = paused.lock().unwrap();
			if *paused {
				std::thread::park_timeout(Duration::new(0, 100000000));
			}
		}

		let frame_start: u64 = timer_subsystem.performance_counter();

		//handle debugger input
		if let Ok(input) = rx.try_recv() {
			if input.trim() == "quit" || input.trim() == "exit" {
				break 'running;
			}
			else {
				let mut paused = paused.lock().unwrap();
				debugger::debug(input, &mut gameboy, paused.deref_mut());
			}
		}

		for event in event_pump.poll_iter() {
			match event {
				Event::KeyDown { keycode, .. } => {
					if keycode.is_some() {
						let key = keymap.get(&keycode.unwrap());
						if key.is_some() {
							gameboy.keydown(*key.unwrap());
						}
					}
				},
				Event::KeyUp { keycode, .. } => {
					if keycode.is_some() {
						let key = keymap.get(&keycode.unwrap());
						if key.is_some() {
							gameboy.keyup(*key.unwrap());
						}
					}
				},
				Event::Quit {..} => {
					break 'running;
				},
				_ => {},
			};
		}

		let paused = {
				*paused.lock().unwrap()
		};
		if !paused {
			gameboy.emulate(Duration::from_millis(1000 / 60));
			draw(&mut gameboy);

			//60hz
			let frame_end: u64 = timer_subsystem.performance_counter();
			let frame_duration: u64 = frame_end - frame_start;
			let ms: u64 = (frame_duration * 1000) / frequency;
			if ms < 1000/60 {
				let duration = Duration::from_millis((1000/60) - ms);
				sleep(duration);
			}
		}
	}
}

pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>, Error> {
	let mut file = try!(File::open(path));
	let mut buffer = Vec::new();
	try!(file.read_to_end(&mut buffer));
	Ok(buffer.into_boxed_slice())
}

///accepts prefixes (none for base 10, 0x for hex, 0b for binary)
///from_str_radix isn't part of a trait so it can't be generic
pub fn parse_u8(s: &str) -> Result<u8, ParseIntError> {
	if s.starts_with("0x") {
		u8::from_str_radix(&s[2..], 16)
	}
	else if s.starts_with("0b") {
		u8::from_str_radix(&s[2..], 2)
	}
	else {
		u8::from_str_radix(s, 10)
	}
}

///accepts prefixes (none for base 10, 0x for hex, 0b for binary)
pub fn parse_u16(s: &str) -> Result<u16, ParseIntError> {
	if s.starts_with("0x") {
		u16::from_str_radix(&s[2..], 16)
	}
	else if s.starts_with("0b") {
		u16::from_str_radix(&s[2..], 2)
	}
	else {
		u16::from_str_radix(s, 10)
	}
}

///accepts prefixes (none for base 10, 0x for hex, 0b for binary)
pub fn parse_usize(s: &str) -> Result<usize, ParseIntError> {
	if s.starts_with("0x") {
		usize::from_str_radix(&s[2..], 16)
	}
	else if s.starts_with("0b") {
		usize::from_str_radix(&s[2..], 2)
	}
	else {
		usize::from_str_radix(s, 10)
	}
}
<|endoftext|>


<commit_before>use crate::syntax::Atom::{self, *};
use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::fmt::{self, Display};
use std::str::FromStr;
use syn::{Error, Expr, Lit, Result, Token, UnOp};

pub struct DiscriminantSet {
    repr: Option<Atom>,
    values: BTreeSet<Discriminant>,
    previous: Option<Discriminant>,
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Discriminant {
    negative: bool,
    magnitude: u32,
}

impl DiscriminantSet {
    pub fn new(repr: Option<Atom>) -> Self {
        DiscriminantSet {
            repr,
            values: BTreeSet::new(),
            previous: None,
        }
    }

    pub fn insert(&mut self, expr: &Expr) -> Result<Discriminant> {
        let (discriminant, repr) = expr_to_discriminant(expr)?;
        self.repr = self.repr.or(repr);
        insert(self, discriminant)
    }

    pub fn insert_next(&mut self) -> Result<Discriminant> {
        let discriminant = match self.previous {
            None => Discriminant::zero(),
            Some(mut discriminant) if discriminant.negative => {
                discriminant.magnitude -= 1;
                if discriminant.magnitude == 0 {
                    discriminant.negative = false;
                }
                discriminant
            }
            Some(mut discriminant) => {
                if discriminant.magnitude == u32::MAX {
                    let msg = format!("discriminant overflow on value after {}", u32::MAX);
                    return Err(Error::new(Span::call_site(), msg));
                }
                discriminant.magnitude += 1;
                discriminant
            }
        };
        insert(self, discriminant)
    }

    pub fn inferred_repr(&self) -> Result<Atom> {
        if let Some(repr) = self.repr {
            return Ok(repr);
        }
        if self.values.is_empty() {
            return Ok(U8);
        }
        let min = *self.values.iter().next().unwrap();
        let max = *self.values.iter().next_back().unwrap();
        for bounds in &BOUNDS {
            if bounds.min <= min && max <= bounds.max {
                return Ok(bounds.repr);
            }
        }
        let msg = "these discriminant values do not fit in any supported enum repr type";
        Err(Error::new(Span::call_site(), msg))
    }
}

fn expr_to_discriminant(expr: &Expr) -> Result<(Discriminant, Option<Atom>)> {
    match expr {
        Expr::Lit(expr) => {
            if let Lit::Int(lit) = &expr.lit {
                let discriminant = lit.base10_parse::<Discriminant>()?;
                let repr = parse_int_suffix(lit.suffix())?;
                return Ok((discriminant, repr));
            }
        }
        Expr::Unary(unary) => {
            if let UnOp::Neg(_) = unary.op {
                let (mut discriminant, repr) = expr_to_discriminant(&unary.expr)?;
                discriminant.negative ^= true;
                return Ok((discriminant, repr));
            }
        }
        _ => {}
    }
    Err(Error::new_spanned(
        expr,
        "enums with non-integer literal discriminants are not supported yet",
    ))
}

fn insert(set: &mut DiscriminantSet, discriminant: Discriminant) -> Result<Discriminant> {
    if set.values.insert(discriminant) {
        set.previous = Some(discriminant);
        Ok(discriminant)
    } else {
        let msg = format!("discriminant value `{}` already exists", discriminant);
        Err(Error::new(Span::call_site(), msg))
    }
}

impl Discriminant {
    const fn zero() -> Self {
        Discriminant {
            negative: false,
            magnitude: 0,
        }
    }

    const fn pos(u: u32) -> Self {
        Discriminant {
            negative: false,
            magnitude: u,
        }
    }

    const fn neg(i: i32) -> Self {
        Discriminant {
            negative: i < 0,
            // This is `i.abs() as u32` but without overflow on MIN. Uses the
            // fact that MIN.wrapping_abs() wraps back to MIN whose binary
            // representation is 1<<31, and thus the `as u32` conversion
            // produces 1<<31 too which happens to be the correct unsigned
            // magnitude.
            magnitude: i.wrapping_abs() as u32,
        }
    }
}

impl Display for Discriminant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.negative {
            f.write_str("-")?;
        }
        Display::fmt(&self.magnitude, f)
    }
}

impl ToTokens for Discriminant {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if self.negative {
            Token![-](Span::call_site()).to_tokens(tokens);
        }
        Literal::u32_unsuffixed(self.magnitude).to_tokens(tokens);
    }
}

impl FromStr for Discriminant {
    type Err = Error;

    fn from_str(mut s: &str) -> Result<Self> {
        let negative = s.starts_with('-');
        if negative {
            s = &s[1..];
        }
        match s.parse::<u32>() {
            Ok(magnitude) => Ok(Discriminant {
                negative,
                magnitude,
            }),
            Err(_) => Err(Error::new(
                Span::call_site(),
                "discriminant value outside of supported range",
            )),
        }
    }
}

impl Ord for Discriminant {
    fn cmp(&self, other: &Self) -> Ordering {
        match (self.negative, other.negative) {
            (true, true) => self.magnitude.cmp(&other.magnitude).reverse(),
            (true, false) => Ordering::Less, // negative < positive
            (false, true) => Ordering::Greater, // positive > negative
            (false, false) => self.magnitude.cmp(&other.magnitude),
        }
    }
}

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

fn parse_int_suffix(suffix: &str) -> Result<Option<Atom>> {
    if suffix.is_empty() {
        return Ok(None);
    }
    if let Some(atom) = Atom::from_str(suffix) {
        match atom {
            U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize => return Ok(Some(atom)),
            _ => {}
        }
    }
    let msg = format!("unrecognized integer suffix: `{}`", suffix);
    Err(Error::new(Span::call_site(), msg))
}

struct Bounds {
    repr: Atom,
    min: Discriminant,
    max: Discriminant,
}

const BOUNDS: [Bounds; 6] = [
    Bounds {
        repr: U8,
        min: Discriminant::zero(),
        max: Discriminant::pos(u8::MAX as u32),
    },
    Bounds {
        repr: I8,
        min: Discriminant::neg(i8::MIN as i32),
        max: Discriminant::pos(i8::MAX as u32),
    },
    Bounds {
        repr: U16,
        min: Discriminant::zero(),
        max: Discriminant::pos(u16::MAX as u32),
    },
    Bounds {
        repr: I16,
        min: Discriminant::neg(i16::MIN as i32),
        max: Discriminant::pos(i16::MAX as u32),
    },
    Bounds {
        repr: U32,
        min: Discriminant::zero(),
        max: Discriminant::pos(u32::MAX),
    },
    Bounds {
        repr: I32,
        min: Discriminant::neg(i32::MIN),
        max: Discriminant::pos(i32::MAX as u32),
    },
];
<commit_msg>Detect out of bounds when inserting discriminant<commit_after>use crate::syntax::Atom::{self, *};
use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::fmt::{self, Display};
use std::str::FromStr;
use syn::{Error, Expr, Lit, Result, Token, UnOp};

pub struct DiscriminantSet {
    repr: Option<Atom>,
    values: BTreeSet<Discriminant>,
    previous: Option<Discriminant>,
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Discriminant {
    negative: bool,
    magnitude: u32,
}

impl DiscriminantSet {
    pub fn new(repr: Option<Atom>) -> Self {
        DiscriminantSet {
            repr,
            values: BTreeSet::new(),
            previous: None,
        }
    }

    pub fn insert(&mut self, expr: &Expr) -> Result<Discriminant> {
        let (discriminant, repr) = expr_to_discriminant(expr)?;
        self.repr = self.repr.or(repr);
        insert(self, discriminant)
    }

    pub fn insert_next(&mut self) -> Result<Discriminant> {
        let discriminant = match self.previous {
            None => Discriminant::zero(),
            Some(mut discriminant) if discriminant.negative => {
                discriminant.magnitude -= 1;
                if discriminant.magnitude == 0 {
                    discriminant.negative = false;
                }
                discriminant
            }
            Some(mut discriminant) => {
                if discriminant.magnitude == u32::MAX {
                    let msg = format!("discriminant overflow on value after {}", u32::MAX);
                    return Err(Error::new(Span::call_site(), msg));
                }
                discriminant.magnitude += 1;
                discriminant
            }
        };
        insert(self, discriminant)
    }

    pub fn inferred_repr(&self) -> Result<Atom> {
        if let Some(repr) = self.repr {
            return Ok(repr);
        }
        if self.values.is_empty() {
            return Ok(U8);
        }
        let min = *self.values.iter().next().unwrap();
        let max = *self.values.iter().next_back().unwrap();
        for bounds in &BOUNDS {
            if bounds.min <= min && max <= bounds.max {
                return Ok(bounds.repr);
            }
        }
        let msg = "these discriminant values do not fit in any supported enum repr type";
        Err(Error::new(Span::call_site(), msg))
    }
}

fn expr_to_discriminant(expr: &Expr) -> Result<(Discriminant, Option<Atom>)> {
    match expr {
        Expr::Lit(expr) => {
            if let Lit::Int(lit) = &expr.lit {
                let discriminant = lit.base10_parse::<Discriminant>()?;
                let repr = parse_int_suffix(lit.suffix())?;
                return Ok((discriminant, repr));
            }
        }
        Expr::Unary(unary) => {
            if let UnOp::Neg(_) = unary.op {
                let (mut discriminant, repr) = expr_to_discriminant(&unary.expr)?;
                discriminant.negative ^= true;
                return Ok((discriminant, repr));
            }
        }
        _ => {}
    }
    Err(Error::new_spanned(
        expr,
        "enums with non-integer literal discriminants are not supported yet",
    ))
}

fn insert(set: &mut DiscriminantSet, discriminant: Discriminant) -> Result<Discriminant> {
    if let Some(expected_repr) = set.repr {
        for bounds in &BOUNDS {
            if bounds.repr != expected_repr {
                continue;
            }
            if bounds.min <= discriminant && discriminant <= bounds.max {
                break;
            }
            let msg = format!(
                "discriminant value `{}` is outside the limits of {}",
                discriminant, expected_repr,
            );
            return Err(Error::new(Span::call_site(), msg));
        }
    }
    if set.values.insert(discriminant) {
        set.previous = Some(discriminant);
        Ok(discriminant)
    } else {
        let msg = format!("discriminant value `{}` already exists", discriminant);
        Err(Error::new(Span::call_site(), msg))
    }
}

impl Discriminant {
    const fn zero() -> Self {
        Discriminant {
            negative: false,
            magnitude: 0,
        }
    }

    const fn pos(u: u32) -> Self {
        Discriminant {
            negative: false,
            magnitude: u,
        }
    }

    const fn neg(i: i32) -> Self {
        Discriminant {
            negative: i < 0,
            // This is `i.abs() as u32` but without overflow on MIN. Uses the
            // fact that MIN.wrapping_abs() wraps back to MIN whose binary
            // representation is 1<<31, and thus the `as u32` conversion
            // produces 1<<31 too which happens to be the correct unsigned
            // magnitude.
            magnitude: i.wrapping_abs() as u32,
        }
    }
}

impl Display for Discriminant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.negative {
            f.write_str("-")?;
        }
        Display::fmt(&self.magnitude, f)
    }
}

impl ToTokens for Discriminant {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if self.negative {
            Token![-](Span::call_site()).to_tokens(tokens);
        }
        Literal::u32_unsuffixed(self.magnitude).to_tokens(tokens);
    }
}

impl FromStr for Discriminant {
    type Err = Error;

    fn from_str(mut s: &str) -> Result<Self> {
        let negative = s.starts_with('-');
        if negative {
            s = &s[1..];
        }
        match s.parse::<u32>() {
            Ok(magnitude) => Ok(Discriminant {
                negative,
                magnitude,
            }),
            Err(_) => Err(Error::new(
                Span::call_site(),
                "discriminant value outside of supported range",
            )),
        }
    }
}

impl Ord for Discriminant {
    fn cmp(&self, other: &Self) -> Ordering {
        match (self.negative, other.negative) {
            (true, true) => self.magnitude.cmp(&other.magnitude).reverse(),
            (true, false) => Ordering::Less, // negative < positive
            (false, true) => Ordering::Greater, // positive > negative
            (false, false) => self.magnitude.cmp(&other.magnitude),
        }
    }
}

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

fn parse_int_suffix(suffix: &str) -> Result<Option<Atom>> {
    if suffix.is_empty() {
        return Ok(None);
    }
    if let Some(atom) = Atom::from_str(suffix) {
        match atom {
            U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize => return Ok(Some(atom)),
            _ => {}
        }
    }
    let msg = format!("unrecognized integer suffix: `{}`", suffix);
    Err(Error::new(Span::call_site(), msg))
}

struct Bounds {
    repr: Atom,
    min: Discriminant,
    max: Discriminant,
}

const BOUNDS: [Bounds; 6] = [
    Bounds {
        repr: U8,
        min: Discriminant::zero(),
        max: Discriminant::pos(u8::MAX as u32),
    },
    Bounds {
        repr: I8,
        min: Discriminant::neg(i8::MIN as i32),
        max: Discriminant::pos(i8::MAX as u32),
    },
    Bounds {
        repr: U16,
        min: Discriminant::zero(),
        max: Discriminant::pos(u16::MAX as u32),
    },
    Bounds {
        repr: I16,
        min: Discriminant::neg(i16::MIN as i32),
        max: Discriminant::pos(i16::MAX as u32),
    },
    Bounds {
        repr: U32,
        min: Discriminant::zero(),
        max: Discriminant::pos(u32::MAX),
    },
    Bounds {
        repr: I32,
        min: Discriminant::neg(i32::MIN),
        max: Discriminant::pos(i32::MAX as u32),
    },
];
<|endoftext|>


<commit_before>#[macro_use]
extern crate kiss_ui;

use kiss_ui::prelude::*;

use kiss_ui::button::Button;
use kiss_ui::container::Horizontal;
use kiss_ui::dialog::{self, AlertPopupBuilder};

fn main() {
    kiss_ui::show_gui(||
        Dialog::new(
            Horizontal::new(
                children![
                    Button::new()
                        .set_label("Message")
                        .set_onclick(show_message_dialog),
                    Button::new()
                        .set_label("Alert")
                        .set_onclick(show_alert_dialog),
                    Button::new()
                        .set_label("Close")
                        .set_onclick(close_dialog),
                ]
            )
            .set_elem_spacing_pixels(10)
        )
        .set_title("Button test!")
    )
}

fn show_message_dialog(_: Button) {
    dialog::message_popup("Good job!", "You clicked the button!");
}

fn show_alert_dialog(_: Button) {
    let res = AlertPopupBuilder::new("Alert!", "You clicked the other button!", "Yes")
        .button2("No")
        .button3("Cancel")
        .popup();

    println!("Alert result = {}", res);
}

fn close_dialog(_: Button) -> CallbackStatus {
    println!("Closing dialog!");
    CallbackStatus::Close
}
<commit_msg>included set/get_name<commit_after>#[macro_use]
extern crate kiss_ui;

use kiss_ui::prelude::*;

use kiss_ui::button::Button;
use kiss_ui::container::{Horizontal, Vertical};
use kiss_ui::dialog::{self, AlertPopupBuilder};

fn main() {
    kiss_ui::show_gui(||
        Dialog::new(
            Vertical::new(children![
	            Horizontal::new(
	                children![
	                    Button::new()
	                        .set_label("Message #1")
	                        .set_name("Message_1")
	                        .set_onclick(show_message_dialog),
	                    Button::new()
	                        .set_label("Message #2")
	                        .set_name("Message_2")
	                        .set_onclick(show_message_dialog),
	                    Button::new()
	                        .set_label("change the name")
	                        .set_name("bar")
	                        .set_onclick(show_change_name),
	                ]
	            )
	            .set_elem_spacing_pixels(10),
	            Horizontal::new(
	                children![
	                    Button::new()
	                        .set_label("Alert")
	                        .set_onclick(show_alert_dialog),
	                    Button::new()
	                        .set_label("Close")
	                        .set_onclick(close_dialog),
	                ]
	            )
	            .set_elem_spacing_pixels(10)
            ])
        )
        .set_title("Button test!")
    )
}

fn show_message_dialog(btn: Button) {
    let name = btn.get_name().unwrap();
    dialog::message_popup("Good job!", format!("You clicked the button {:?}!", name));
}

fn show_change_name(btn: Button) {
    let name = btn.get_name().unwrap();
    dialog::message_popup("Lets try it!", format!("The button's name is '{}'!\n
        Now we try to change it!\n
        You will get a Panic if you still use the 'name'", name));
//    drop(name); // <= uncomment this line
    btn.set_name("foo");
    show_message_dialog(btn);
}

fn show_alert_dialog(_: Button) {
    let res = AlertPopupBuilder::new("Alert!", "You clicked the other button!", "Yes")
        .button2("No")
        .button3("Cancel")
        .popup();

    println!("Alert result = {}", res);
}

fn close_dialog(_: Button) -> CallbackStatus {
    println!("Closing dialog!");
    CallbackStatus::Close
}
<|endoftext|>


<commit_before>fn make_vec() -> Vec<u8> {
    let mut v = Vec::with_capacity(4);
    v.push(1);
    v.push(2);
    v
}

fn make_vec_macro() -> Vec<u8> {
    vec![1, 2]
}

fn make_vec_macro_repeat() -> Vec<u8> {
    vec![42; 5]
}

fn make_vec_macro_repeat_zeroed() -> Vec<u8> {
    vec![0; 7]
}

fn vec_into_iter() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_rev() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_into_iter_rev_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_iter_and_mut() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_iter_and_mut_rev() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut().rev() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_reallocate() -> Vec<u8> {
    let mut v = vec![1, 2];
    v.push(3);
    v.push(4);
    v.push(5);
    v
}

fn vec_push_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.push(1);
    let _val = *v0;
}

fn vec_extend_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.extend(&[1]);
    let _val = *v0;
    v.extend(vec![2]);
    let _val = *v0;
    v.extend(std::iter::once(3));
    let _val = *v0;
}

fn main() {
    assert_eq!(vec_reallocate().len(), 5);

    assert_eq!(vec_into_iter(), 30);
    assert_eq!(vec_into_iter_rev(), 30);
    vec_iter_and_mut();
    assert_eq!(vec_into_iter_zst(), 0);
    assert_eq!(vec_into_iter_rev_zst(), 0);
    vec_iter_and_mut_rev();

    assert_eq!(make_vec().capacity(), 4);
    assert_eq!(make_vec_macro(), [1, 2]);
    assert_eq!(make_vec_macro_repeat(), [42; 5]);
    assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]);

    // Test interesting empty slice comparison
    // (one is a real pointer, one an integer pointer).
    assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);

    vec_push_ptr_stable();
    vec_extend_ptr_stable();
}
<commit_msg>test some more vec ptr invalidation<commit_after>fn make_vec() -> Vec<u8> {
    let mut v = Vec::with_capacity(4);
    v.push(1);
    v.push(2);
    v
}

fn make_vec_macro() -> Vec<u8> {
    vec![1, 2]
}

fn make_vec_macro_repeat() -> Vec<u8> {
    vec![42; 5]
}

fn make_vec_macro_repeat_zeroed() -> Vec<u8> {
    vec![0; 7]
}

fn vec_into_iter() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_rev() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_into_iter_rev_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_iter_and_mut() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_iter_and_mut_rev() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut().rev() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_reallocate() -> Vec<u8> {
    let mut v = vec![1, 2];
    v.push(3);
    v.push(4);
    v.push(5);
    v
}

fn vec_push_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.push(1);
    let _val = *v0;
}

fn vec_extend_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    // `slice::Iter` (with `T: Copy`) specialization
    v.extend(&[1]);
    let _val = *v0;
    // `vec::IntoIter` specialization
    v.extend(vec![2]);
    let _val = *v0;
    // `TrustedLen` specialization
    v.extend(std::iter::once(3));
    let _val = *v0;
    // base case
    v.extend(std::iter::once(3).filter(|_| true));
    let _val = *v0;
}

fn vec_truncate_ptr_stable() {
    let mut v = vec![0; 10];
    let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.truncate(5);
    let _val = *v0;
}

fn main() {
    assert_eq!(vec_reallocate().len(), 5);

    assert_eq!(vec_into_iter(), 30);
    assert_eq!(vec_into_iter_rev(), 30);
    vec_iter_and_mut();
    assert_eq!(vec_into_iter_zst(), 0);
    assert_eq!(vec_into_iter_rev_zst(), 0);
    vec_iter_and_mut_rev();

    assert_eq!(make_vec().capacity(), 4);
    assert_eq!(make_vec_macro(), [1, 2]);
    assert_eq!(make_vec_macro_repeat(), [42; 5]);
    assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]);

    // Test interesting empty slice comparison
    // (one is a real pointer, one an integer pointer).
    assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);

    vec_push_ptr_stable();
    vec_extend_ptr_stable();
    vec_truncate_ptr_stable();
}
<|endoftext|>


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

//! Error types

use core::fmt;

#[cfg(feature="std")]
use std::error::Error as stdError;

/// Error kind which can be matched over.
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum ErrorKind {
    /// Feature is not available; not recoverable.
    ///
    /// This is the most permanent failure type and implies the error cannot be
    /// resolved simply by retrying (e.g. the feature may not exist in this
    /// build of the application or on the current platform).
    Unavailable,
    /// General failure; there may be a chance of recovery on retry.
    ///
    /// This is the catch-all kind for errors from known and unknown sources
    /// which do not have a more specific kind / handling method.
    ///
    /// It is suggested to retry a couple of times or retry later when
    /// handling; some error sources may be able to resolve themselves,
    /// although this is not likely.
    Unexpected,
    /// A transient failure which likely can be resolved or worked around.
    ///
    /// This error kind exists for a few specific cases where it is known that
    /// the error likely can be resolved internally, but is reported anyway.
    Transient,
    /// Not ready yet: recommended to try again a little later.
    ///
    /// This error kind implies the generator needs more time or needs some
    /// other part of the application to do something else first before it is
    /// ready for use; for example this may be used by external generators
    /// which require time for initialization.
    NotReady,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl ErrorKind {
    /// True if this kind of error may resolve itself on retry.
    ///
    /// See also `should_wait()`.
    pub fn should_retry(self) -> bool {
        self != ErrorKind::Unavailable
    }

    /// True if we should retry but wait before retrying
    ///
    /// This implies `should_retry()` is true.
    pub fn should_wait(self) -> bool {
        self == ErrorKind::NotReady
    }

    /// A description of this error kind
    pub fn description(self) -> &'static str {
        match self {
            ErrorKind::Unavailable => "permanently unavailable",
            ErrorKind::Unexpected => "unexpected failure",
            ErrorKind::Transient => "transient failure",
            ErrorKind::NotReady => "not ready yet",
            ErrorKind::__Nonexhaustive => unreachable!(),
        }
    }
}

/// Error type of random number generators
///
/// This is a relatively simple error type, designed for compatibility with and
/// without the Rust `std` library. It embeds a "kind" code, a message (static
/// string only), and an optional chained cause (`std` only). The `kind` and
/// `msg` fields can be accessed directly; cause can be accessed via
/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be
/// done via `Error::new` or `Error::with_cause`.
#[derive(Debug)]
pub struct Error {
    /// The error kind
    pub kind: ErrorKind,
    /// The error message
    pub msg: &'static str,
    #[cfg(feature="std")]
    cause: Option<Box<stdError + Send + Sync>>,
}

impl Error {
    /// Create a new instance, with specified kind and a message.
    pub fn new(kind: ErrorKind, msg: &'static str) -> Self {
        #[cfg(feature="std")] {
            Error { kind, msg, cause: None }
        }
        #[cfg(not(feature="std"))] {
            Error { kind, msg }
        }
    }

    /// Create a new instance, with specified kind, message, and a
    /// chained cause.
    ///
    /// Note: `stdError` is an alias for `std::error::Error`.
    ///
    /// If not targetting `std` (i.e. `no_std`), this function is replaced by
    /// another with the same prototype, except that there are no bounds on the
    /// type `E` (because both `Box` and `stdError` are unavailable), and the
    /// `cause` is ignored.
    #[cfg(feature="std")]
    pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, cause: E) -> Self
        where E: Into<Box<stdError + Send + Sync>>
    {
        Error { kind, msg, cause: Some(cause.into()) }
    }

    /// Create a new instance, with specified kind, message, and a
    /// chained cause.
    ///
    /// In `no_std` mode the *cause* is ignored.
    #[cfg(not(feature="std"))]
    pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, _cause: E) -> Self {
        Error { kind, msg }
    }

    /// Take the cause, if any. This allows the embedded cause to be extracted.
    /// This uses `Option::take`, leaving `self` with no cause.
    #[cfg(feature="std")]
    pub fn take_cause(&mut self) -> Option<Box<stdError + Send + Sync>> {
        self.cause.take()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        #[cfg(feature="std")] {
            if let Some(ref cause) = self.cause {
                return write!(f, "{} ({}); cause: {}",
                        self.msg, self.kind.description(), cause);
            }
        }
        write!(f, "{} ({})", self.msg, self.kind.description())
    }
}

#[cfg(feature="std")]
impl stdError for Error {
    fn description(&self) -> &str {
        self.msg
    }

    fn cause(&self) -> Option<&stdError> {
        self.cause.as_ref().map(|e| e.as_ref() as &stdError)
    }
}
<commit_msg>Implement From<Error> for io::Error<commit_after>// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Error types

use core::fmt;

#[cfg(feature="std")]
use std::error::Error as stdError;
#[cfg(feature="std")]
use std::io;

/// Error kind which can be matched over.
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum ErrorKind {
    /// Feature is not available; not recoverable.
    ///
    /// This is the most permanent failure type and implies the error cannot be
    /// resolved simply by retrying (e.g. the feature may not exist in this
    /// build of the application or on the current platform).
    Unavailable,
    /// General failure; there may be a chance of recovery on retry.
    ///
    /// This is the catch-all kind for errors from known and unknown sources
    /// which do not have a more specific kind / handling method.
    ///
    /// It is suggested to retry a couple of times or retry later when
    /// handling; some error sources may be able to resolve themselves,
    /// although this is not likely.
    Unexpected,
    /// A transient failure which likely can be resolved or worked around.
    ///
    /// This error kind exists for a few specific cases where it is known that
    /// the error likely can be resolved internally, but is reported anyway.
    Transient,
    /// Not ready yet: recommended to try again a little later.
    ///
    /// This error kind implies the generator needs more time or needs some
    /// other part of the application to do something else first before it is
    /// ready for use; for example this may be used by external generators
    /// which require time for initialization.
    NotReady,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl ErrorKind {
    /// True if this kind of error may resolve itself on retry.
    ///
    /// See also `should_wait()`.
    pub fn should_retry(self) -> bool {
        self != ErrorKind::Unavailable
    }

    /// True if we should retry but wait before retrying
    ///
    /// This implies `should_retry()` is true.
    pub fn should_wait(self) -> bool {
        self == ErrorKind::NotReady
    }

    /// A description of this error kind
    pub fn description(self) -> &'static str {
        match self {
            ErrorKind::Unavailable => "permanently unavailable",
            ErrorKind::Unexpected => "unexpected failure",
            ErrorKind::Transient => "transient failure",
            ErrorKind::NotReady => "not ready yet",
            ErrorKind::__Nonexhaustive => unreachable!(),
        }
    }
}

/// Error type of random number generators
///
/// This is a relatively simple error type, designed for compatibility with and
/// without the Rust `std` library. It embeds a "kind" code, a message (static
/// string only), and an optional chained cause (`std` only). The `kind` and
/// `msg` fields can be accessed directly; cause can be accessed via
/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be
/// done via `Error::new` or `Error::with_cause`.
#[derive(Debug)]
pub struct Error {
    /// The error kind
    pub kind: ErrorKind,
    /// The error message
    pub msg: &'static str,
    #[cfg(feature="std")]
    cause: Option<Box<stdError + Send + Sync>>,
}

impl Error {
    /// Create a new instance, with specified kind and a message.
    pub fn new(kind: ErrorKind, msg: &'static str) -> Self {
        #[cfg(feature="std")] {
            Error { kind, msg, cause: None }
        }
        #[cfg(not(feature="std"))] {
            Error { kind, msg }
        }
    }

    /// Create a new instance, with specified kind, message, and a
    /// chained cause.
    ///
    /// Note: `stdError` is an alias for `std::error::Error`.
    ///
    /// If not targetting `std` (i.e. `no_std`), this function is replaced by
    /// another with the same prototype, except that there are no bounds on the
    /// type `E` (because both `Box` and `stdError` are unavailable), and the
    /// `cause` is ignored.
    #[cfg(feature="std")]
    pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, cause: E) -> Self
        where E: Into<Box<stdError + Send + Sync>>
    {
        Error { kind, msg, cause: Some(cause.into()) }
    }

    /// Create a new instance, with specified kind, message, and a
    /// chained cause.
    ///
    /// In `no_std` mode the *cause* is ignored.
    #[cfg(not(feature="std"))]
    pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, _cause: E) -> Self {
        Error { kind, msg }
    }

    /// Take the cause, if any. This allows the embedded cause to be extracted.
    /// This uses `Option::take`, leaving `self` with no cause.
    #[cfg(feature="std")]
    pub fn take_cause(&mut self) -> Option<Box<stdError + Send + Sync>> {
        self.cause.take()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        #[cfg(feature="std")] {
            if let Some(ref cause) = self.cause {
                return write!(f, "{} ({}); cause: {}",
                        self.msg, self.kind.description(), cause);
            }
        }
        write!(f, "{} ({})", self.msg, self.kind.description())
    }
}

#[cfg(feature="std")]
impl stdError for Error {
    fn description(&self) -> &str {
        self.msg
    }

    fn cause(&self) -> Option<&stdError> {
        self.cause.as_ref().map(|e| e.as_ref() as &stdError)
    }
}

#[cfg(feature="std")]
impl From<Error> for io::Error {
    fn from(error: Error) -> Self {
        use std::io::ErrorKind::*;
        match error.kind {
            ErrorKind::Unavailable => io::Error::new(NotFound, error),
            ErrorKind::Unexpected |
            ErrorKind::Transient => io::Error::new(Other, error),
            ErrorKind::NotReady => io::Error::new(WouldBlock, error),
            ErrorKind::__Nonexhaustive => unreachable!(),
        }
    }
}
<|endoftext|>


<commit_before>use nom::{is_digit, types::CompleteStr, IResult};
use std::str;

/// Describes how formats should be padded: on the left, on the right, or not at all.
#[derive(PartialEq, Eq, Debug)]
pub enum Padding {
    /// Do not pad the value.
    None,
    /// Pad the value on the left until it reaches specified width.
    Left(usize),
    /// Pad the value on the right until it reaches specified width.
    Right(usize),
}

/// Describes all the different "format specifiers" we support, plus a chunk of text that would be
/// copied to the output verbatim.
#[derive(PartialEq, Eq, Debug)]
pub enum Specifier<'a> {
    /// Will expand to pad everything that comes next to the right. Given char is used for padding.
    Spacing(char),
    /// A format to be replaced with a value (`%a`, `%t` etc.), padded to the given width on the
    /// left (if it's positive) or on the right (if it's negative).
    Format(char, Padding),
    /// A chunk of text that will be copied to the output verbatim.
    Text(&'a str),
    /// Conditional format that is replaced by one of the sub-formats depending on the value of the
    /// given key. "Else" branch might be missing.
    Conditional(char, Vec<Specifier<'a>>, Option<Vec<Specifier<'a>>>),
}

fn escaped_percent_sign(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    tag!(input, "%%").map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(&s[0..1]))
    })
}

fn spacing(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(input, tag!("%>") >> c: take!(1) >> (c)).map(|result| {
        let CompleteStr(chr) = result.1;
        assert!(chr.len() == 1);
        let chr = chr.chars().next().unwrap();

        (result.0, Specifier::Spacing(chr))
    })
}

fn padded_format(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(
        input,
        tag!("%")
            >> width: take_while!(|chr| is_digit(chr as u8) || chr == '-')
            >> format: take!(1)
            >> (format, width)
    )
    .map(|result| {
        let (c, w) = result.1;

        let CompleteStr(format) = c;
        assert!(format.len() == 1);
        let format = format.chars().next().unwrap();

        let CompleteStr(width) = w;
        let width = width.parse::<isize>().unwrap_or(0);
        let padding = if width == 0isize {
            Padding::None
        } else if width > 0isize {
            Padding::Left(width.abs() as usize)
        } else {
            Padding::Right(width.abs() as usize)
        };

        (result.0, Specifier::Format(format, padding))
    })
}

fn text_outside_conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    take_till!(input, |chr: char| chr == '%').map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(s))
    })
}

fn text_inside_conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    take_till!(input, |chr: char| chr == '%' || chr == '&' || chr == '?').map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(s))
    })
}

fn conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(
        input,
        tag!("%?")
            >> cond: take!(1)
            >> tag!("?")
            >> then: conditional_branch
            >> els: alt!(
            do_parse!(
                tag!("&") >>
                els: conditional_branch >>
                tag!("?") >>

                (Some(els))) |

            tag!("?") => { |_| None})
            >> (cond, then, els)
    )
    .map(|result| {
        let (cond, then, els) = result.1;

        let CompleteStr(cond) = cond;
        assert!(cond.len() == 1);
        let cond = cond.chars().next().unwrap();

        (result.0, Specifier::Conditional(cond, then, els))
    })
}

fn conditional_branch(input: CompleteStr) -> IResult<CompleteStr, Vec<Specifier>> {
    many0!(
        input,
        alt!(escaped_percent_sign | spacing | padded_format | text_inside_conditional)
    )
}

fn parser(input: CompleteStr) -> IResult<CompleteStr, Vec<Specifier>> {
    many0!(
        input,
        alt!(
            conditional | escaped_percent_sign | spacing | padded_format | text_outside_conditional
        )
    )
}

pub fn parse(input: &str) -> Vec<Specifier> {
    match parser(CompleteStr(input)) {
        Ok((_leftovers, ast)) => ast,
        Err(_) => vec![Specifier::Text("")],
    }
}

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

    #[test]
    fn t_parses_formats_without_specifiers() {
        let input = "Hello, world!";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));
        assert_eq!(result, vec![Specifier::Text("Hello, world!")]);
    }

    #[test]
    fn t_replaces_double_percent_with_a_single_percent() {
        let input = "%%";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));
        assert_eq!(result, vec![Specifier::Text("%")]);
    }

    #[test]
    fn t_parses_sequences_of_specifiers() {
        let input = "100%% pure Ceylon tea";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Text("100"),
            Specifier::Text("%"),
            Specifier::Text(" pure Ceylon tea"),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_letters() {
        let input = "%t (%a)";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('t', Padding::None),
            Specifier::Text(" ("),
            Specifier::Format('a', Padding::None),
            Specifier::Text(")"),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_positive_padding() {
        let input = "%8a%4b%13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Left(8)),
            Specifier::Format('b', Padding::Left(4)),
            Specifier::Format('x', Padding::Left(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_negative_padding() {
        let input = "%-8a%-4b%-13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Right(8)),
            Specifier::Format('b', Padding::Right(4)),
            Specifier::Format('x', Padding::Right(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_spacing_format() {
        let input = "%-8a%>m%4b%> %-13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Right(8)),
            Specifier::Spacing('m'),
            Specifier::Format('b', Padding::Left(4)),
            Specifier::Spacing(' '),
            Specifier::Format('x', Padding::Right(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_conditionals() {
        let input = "%?x?success&failure?";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![Specifier::Conditional(
            'x',
            vec![Specifier::Text("success")],
            Some(vec![Specifier::Text("failure")]),
        )];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_conditionals_without_else_branch() {
        let input = "%?x?success?";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![Specifier::Conditional(
            'x',
            vec![Specifier::Text("success")],
            None,
        )];
        assert_eq!(result, expected);
    }
}
<commit_msg>Ignore non-ascii formats<commit_after>use nom::{types::CompleteStr, IResult};
use std::str;

/// Describes how formats should be padded: on the left, on the right, or not at all.
#[derive(PartialEq, Eq, Debug)]
pub enum Padding {
    /// Do not pad the value.
    None,
    /// Pad the value on the left until it reaches specified width.
    Left(usize),
    /// Pad the value on the right until it reaches specified width.
    Right(usize),
}

/// Describes all the different "format specifiers" we support, plus a chunk of text that would be
/// copied to the output verbatim.
#[derive(PartialEq, Eq, Debug)]
pub enum Specifier<'a> {
    /// Will expand to pad everything that comes next to the right. Given char is used for padding.
    Spacing(char),
    /// A format to be replaced with a value (`%a`, `%t` etc.), padded to the given width on the
    /// left (if it's positive) or on the right (if it's negative).
    Format(char, Padding),
    /// A chunk of text that will be copied to the output verbatim.
    Text(&'a str),
    /// Conditional format that is replaced by one of the sub-formats depending on the value of the
    /// given key. "Else" branch might be missing.
    Conditional(char, Vec<Specifier<'a>>, Option<Vec<Specifier<'a>>>),
}

fn escaped_percent_sign(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    tag!(input, "%%").map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(&s[0..1]))
    })
}

fn spacing(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(input, tag!("%>") >> c: take!(1) >> (c)).map(|result| {
        let CompleteStr(chr) = result.1;
        assert!(chr.len() == 1);
        let chr = chr.chars().next().unwrap();

        (result.0, Specifier::Spacing(chr))
    })
}

fn padded_format(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(
        input,
        tag!("%")
            >> width: take_while!(|chr: char| chr.is_ascii() && (chr.is_numeric() || chr == '-'))
            >> format: take!(1)
            >> (format, width)
    )
    .map(|result| {
        let (c, w) = result.1;

        let CompleteStr(format) = c;
        // unwrap() won't fail because parser uses take!(1) to get exactly one character
        let format = format.chars().next().unwrap();

        let CompleteStr(width) = w;
        let width = width.parse::<isize>().unwrap_or(0);
        let padding = if width == 0isize {
            Padding::None
        } else if width > 0isize {
            Padding::Left(width.abs() as usize)
        } else {
            Padding::Right(width.abs() as usize)
        };

        (result.0, Specifier::Format(format, padding))
    })
}

fn text_outside_conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    take_till!(input, |chr: char| chr == '%').map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(s))
    })
}

fn text_inside_conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    take_till!(input, |chr: char| chr == '%' || chr == '&' || chr == '?').map(|result| {
        let CompleteStr(s) = result.1;
        (result.0, Specifier::Text(s))
    })
}

fn conditional(input: CompleteStr) -> IResult<CompleteStr, Specifier> {
    do_parse!(
        input,
        tag!("%?")
            >> cond: take!(1)
            >> tag!("?")
            >> then: conditional_branch
            >> els: alt!(
            do_parse!(
                tag!("&") >>
                els: conditional_branch >>
                tag!("?") >>

                (Some(els))) |

            tag!("?") => { |_| None})
            >> (cond, then, els)
    )
    .map(|result| {
        let (cond, then, els) = result.1;

        let CompleteStr(cond) = cond;
        assert!(cond.len() == 1);
        let cond = cond.chars().next().unwrap();

        (result.0, Specifier::Conditional(cond, then, els))
    })
}

fn conditional_branch(input: CompleteStr) -> IResult<CompleteStr, Vec<Specifier>> {
    many0!(
        input,
        alt!(escaped_percent_sign | spacing | padded_format | text_inside_conditional)
    )
}

fn parser(input: CompleteStr) -> IResult<CompleteStr, Vec<Specifier>> {
    many0!(
        input,
        alt!(
            conditional | escaped_percent_sign | spacing | padded_format | text_outside_conditional
        )
    )
}

fn sanitize(mut input: Vec<Specifier>) -> Vec<Specifier> {
    input.retain(|s| {
        if let Specifier::Format(c, _b) = s {
            c.is_ascii()
        } else {
            true
        }
    });
    input
}

pub fn parse(input: &str) -> Vec<Specifier> {
    match parser(CompleteStr(input)) {
        Ok((_leftovers, ast)) => sanitize(ast),
        Err(_) => vec![Specifier::Text("")],
    }
}

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

    #[test]
    fn t_parses_formats_without_specifiers() {
        let input = "Hello, world!";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));
        assert_eq!(result, vec![Specifier::Text("Hello, world!")]);
    }

    #[test]
    fn t_replaces_double_percent_with_a_single_percent() {
        let input = "%%";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));
        assert_eq!(result, vec![Specifier::Text("%")]);
    }

    #[test]
    fn t_parses_sequences_of_specifiers() {
        let input = "100%% pure Ceylon tea";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();
        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Text("100"),
            Specifier::Text("%"),
            Specifier::Text(" pure Ceylon tea"),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_letters() {
        let input = "%t (%a)";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('t', Padding::None),
            Specifier::Text(" ("),
            Specifier::Format('a', Padding::None),
            Specifier::Text(")"),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_positive_padding() {
        let input = "%8a%4b%13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Left(8)),
            Specifier::Format('b', Padding::Left(4)),
            Specifier::Format('x', Padding::Left(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_formats_with_negative_padding() {
        let input = "%-8a%-4b%-13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Right(8)),
            Specifier::Format('b', Padding::Right(4)),
            Specifier::Format('x', Padding::Right(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_spacing_format() {
        let input = "%-8a%>m%4b%> %-13x";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![
            Specifier::Format('a', Padding::Right(8)),
            Specifier::Spacing('m'),
            Specifier::Format('b', Padding::Left(4)),
            Specifier::Spacing(' '),
            Specifier::Format('x', Padding::Right(13)),
        ];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_conditionals() {
        let input = "%?x?success&failure?";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![Specifier::Conditional(
            'x',
            vec![Specifier::Text("success")],
            Some(vec![Specifier::Text("failure")]),
        )];
        assert_eq!(result, expected);
    }

    #[test]
    fn t_parses_conditionals_without_else_branch() {
        let input = "%?x?success?";
        let (leftovers, result) = parser(CompleteStr(input)).unwrap();

        assert_eq!(leftovers, CompleteStr(""));

        let expected = vec![Specifier::Conditional(
            'x',
            vec![Specifier::Text("success")],
            None,
        )];
        assert_eq!(result, expected);
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

//! Code related to the invalidation of media-query-affected rules.

use crate::context::QuirksMode;
use crate::media_queries::Device;
use crate::shared_lock::SharedRwLockReadGuard;
use crate::stylesheets::{DocumentRule, ImportRule, MediaRule};
use crate::stylesheets::{NestedRuleIterationCondition, Stylesheet, SupportsRule};
use fxhash::FxHashSet;

/// A key for a given media query result.
///
/// NOTE: It happens to be the case that all the media lists we care about
/// happen to have a stable address, so we can just use an opaque pointer to
/// represent them.
///
/// Also, note that right now when a rule or stylesheet is removed, we do a full
/// style flush, so there's no need to worry about other item created with the
/// same pointer address.
///
/// If this changes, though, we may need to remove the item from the cache if
/// present before it goes away.
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct MediaListKey(usize);

impl MediaListKey {
    /// Create a MediaListKey from a raw usize.
    pub fn from_raw(k: usize) -> Self {
        MediaListKey(k)
    }
}

/// A trait to get a given `MediaListKey` for a given item that can hold a
/// `MediaList`.
pub trait ToMediaListKey: Sized {
    /// Get a `MediaListKey` for this item. This key needs to uniquely identify
    /// the item.
    #[allow(unsafe_code)]
    fn to_media_list_key(&self) -> MediaListKey {
        use std::mem;
        MediaListKey(unsafe { mem::transmute(self as *const Self) })
    }
}

impl ToMediaListKey for Stylesheet {}
impl ToMediaListKey for ImportRule {}
impl ToMediaListKey for MediaRule {}

/// A struct that holds the result of a media query evaluation pass for the
/// media queries that evaluated successfully.
#[derive(Debug, MallocSizeOf, PartialEq)]
pub struct EffectiveMediaQueryResults {
    /// The set of media lists that matched last time.
    set: FxHashSet<MediaListKey>,
}

impl EffectiveMediaQueryResults {
    /// Trivially constructs an empty `EffectiveMediaQueryResults`.
    pub fn new() -> Self {
        Self {
            set: FxHashSet::default(),
        }
    }

    /// Resets the results, using an empty key.
    pub fn clear(&mut self) {
        self.set.clear()
    }

    /// Returns whether a given item was known to be effective when the results
    /// were cached.
    pub fn was_effective<T>(&self, item: &T) -> bool
    where
        T: ToMediaListKey,
    {
        self.set.contains(&item.to_media_list_key())
    }

    /// Notices that an effective item has been seen, and caches it as matching.
    pub fn saw_effective<T>(&mut self, item: &T)
    where
        T: ToMediaListKey,
    {
        // NOTE(emilio): We can't assert that we don't cache the same item twice
        // because of stylesheet reusing... shrug.
        self.set.insert(item.to_media_list_key());
    }
}

/// A filter that filters over effective rules, but allowing all potentially
/// effective `@media` rules.
pub struct PotentiallyEffectiveMediaRules;

impl NestedRuleIterationCondition for PotentiallyEffectiveMediaRules {
    fn process_import(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &ImportRule,
    ) -> bool {
        true
    }

    fn process_media(_: &SharedRwLockReadGuard, _: &Device, _: QuirksMode, _: &MediaRule) -> bool {
        true
    }

    /// Whether we should process the nested rules in a given `@-moz-document` rule.
    fn process_document(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &DocumentRule,
    ) -> bool {
        use crate::stylesheets::EffectiveRules;
        EffectiveRules::process_document(guard, device, quirks_mode, rule)
    }

    /// Whether we should process the nested rules in a given `@supports` rule.
    fn process_supports(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &SupportsRule,
    ) -> bool {
        use crate::stylesheets::EffectiveRules;
        EffectiveRules::process_supports(guard, device, quirks_mode, rule)
    }
}
<commit_msg>style: Remove unnecessary mem::transmute in MediaListKey.<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 https://mozilla.org/MPL/2.0/. */

//! Code related to the invalidation of media-query-affected rules.

use crate::context::QuirksMode;
use crate::media_queries::Device;
use crate::shared_lock::SharedRwLockReadGuard;
use crate::stylesheets::{DocumentRule, ImportRule, MediaRule};
use crate::stylesheets::{NestedRuleIterationCondition, Stylesheet, SupportsRule};
use fxhash::FxHashSet;

/// A key for a given media query result.
///
/// NOTE: It happens to be the case that all the media lists we care about
/// happen to have a stable address, so we can just use an opaque pointer to
/// represent them.
///
/// Also, note that right now when a rule or stylesheet is removed, we do a full
/// style flush, so there's no need to worry about other item created with the
/// same pointer address.
///
/// If this changes, though, we may need to remove the item from the cache if
/// present before it goes away.
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct MediaListKey(usize);

impl MediaListKey {
    /// Create a MediaListKey from a raw usize.
    pub fn from_raw(k: usize) -> Self {
        MediaListKey(k)
    }
}

/// A trait to get a given `MediaListKey` for a given item that can hold a
/// `MediaList`.
pub trait ToMediaListKey: Sized {
    /// Get a `MediaListKey` for this item. This key needs to uniquely identify
    /// the item.
    fn to_media_list_key(&self) -> MediaListKey {
        MediaListKey(self as *const Self as usize)
    }
}

impl ToMediaListKey for Stylesheet {}
impl ToMediaListKey for ImportRule {}
impl ToMediaListKey for MediaRule {}

/// A struct that holds the result of a media query evaluation pass for the
/// media queries that evaluated successfully.
#[derive(Debug, MallocSizeOf, PartialEq)]
pub struct EffectiveMediaQueryResults {
    /// The set of media lists that matched last time.
    set: FxHashSet<MediaListKey>,
}

impl EffectiveMediaQueryResults {
    /// Trivially constructs an empty `EffectiveMediaQueryResults`.
    pub fn new() -> Self {
        Self {
            set: FxHashSet::default(),
        }
    }

    /// Resets the results, using an empty key.
    pub fn clear(&mut self) {
        self.set.clear()
    }

    /// Returns whether a given item was known to be effective when the results
    /// were cached.
    pub fn was_effective<T>(&self, item: &T) -> bool
    where
        T: ToMediaListKey,
    {
        self.set.contains(&item.to_media_list_key())
    }

    /// Notices that an effective item has been seen, and caches it as matching.
    pub fn saw_effective<T>(&mut self, item: &T)
    where
        T: ToMediaListKey,
    {
        // NOTE(emilio): We can't assert that we don't cache the same item twice
        // because of stylesheet reusing... shrug.
        self.set.insert(item.to_media_list_key());
    }
}

/// A filter that filters over effective rules, but allowing all potentially
/// effective `@media` rules.
pub struct PotentiallyEffectiveMediaRules;

impl NestedRuleIterationCondition for PotentiallyEffectiveMediaRules {
    fn process_import(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &ImportRule,
    ) -> bool {
        true
    }

    fn process_media(_: &SharedRwLockReadGuard, _: &Device, _: QuirksMode, _: &MediaRule) -> bool {
        true
    }

    /// Whether we should process the nested rules in a given `@-moz-document` rule.
    fn process_document(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &DocumentRule,
    ) -> bool {
        use crate::stylesheets::EffectiveRules;
        EffectiveRules::process_document(guard, device, quirks_mode, rule)
    }

    /// Whether we should process the nested rules in a given `@supports` rule.
    fn process_supports(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &SupportsRule,
    ) -> bool {
        use crate::stylesheets::EffectiveRules;
        EffectiveRules::process_supports(guard, device, quirks_mode, rule)
    }
}
<|endoftext|>


<commit_before>#![allow(mutable_borrow_reservation_conflict)]

trait S: Sized {
    fn tpb(&mut self, _s: Self) {}
}

impl S for i32 {}

fn two_phase1() {
    let mut x = 3;
    x.tpb(x);
}

fn two_phase2() {
    let mut v = vec![];
    v.push(v.len());
}

fn two_phase3(b: bool) {
    let mut x = &mut vec![];
    let mut y = vec![];
    x.push((
        {
            if b { x = &mut y };
            22
        },
        x.len(),
    ));
}

#[allow(unreachable_code)]
fn two_phase_raw() {
    let x: &mut Vec<i32> = &mut vec![];
    x.push(
        {
            // Unfortunately this does not trigger the problem of creating a
            // raw ponter from a pointer that had a two-phase borrow derived from
            // it because of the implicit &mut reborrow.
            let raw = x as *mut _;
            unsafe { *raw = vec![1]; }
            return
        }
    );
}

fn two_phase_overlapping1() {
    let mut x = vec![];
    let p = &x;
    x.push(p.len());
}

fn two_phase_overlapping2() {
    use std::ops::AddAssign;
    let mut x = 1;
    let l = &x;
    x.add_assign(x + *l);
}

fn with_interior_mutability() {
    use std::cell::Cell;

    trait Thing: Sized {
        fn do_the_thing(&mut self, _s: i32) {}
    }

    impl<T> Thing for Cell<T> {}

    let mut x = Cell::new(1);
    let l = &x;

    x
        .do_the_thing({
            x.set(3);
            l.set(4);
            x.get() + l.get()
        })
    ;
}

fn main() {
    two_phase1();
    two_phase2();
    two_phase3(false);
    two_phase3(true);
    two_phase_raw();
    with_interior_mutability();
    two_phase_overlapping1();
    two_phase_overlapping2();
}
<commit_msg>Auto merge of #2080 - RalfJung:2phase, r=RalfJung<commit_after>// compile-flags: -Zmiri-tag-raw-pointers
#![allow(mutable_borrow_reservation_conflict)]

trait S: Sized {
    fn tpb(&mut self, _s: Self) {}
}

impl S for i32 {}

fn two_phase1() {
    let mut x = 3;
    x.tpb(x);
}

fn two_phase2() {
    let mut v = vec![];
    v.push(v.len());
}

fn two_phase3(b: bool) {
    let mut x = &mut vec![];
    let mut y = vec![];
    x.push((
        {
            if b { x = &mut y };
            22
        },
        x.len(),
    ));
}

#[allow(unreachable_code)]
fn two_phase_raw() {
    let x: &mut Vec<i32> = &mut vec![];
    x.push(
        {
            // Unfortunately this does not trigger the problem of creating a
            // raw ponter from a pointer that had a two-phase borrow derived from
            // it because of the implicit &mut reborrow.
            let raw = x as *mut _;
            unsafe { *raw = vec![1]; }
            return
        }
    );
}

fn two_phase_overlapping1() {
    let mut x = vec![];
    let p = &x;
    x.push(p.len());
}

fn two_phase_overlapping2() {
    use std::ops::AddAssign;
    let mut x = 1;
    let l = &x;
    x.add_assign(x + *l);
}

fn with_interior_mutability() {
    use std::cell::Cell;

    trait Thing: Sized {
        fn do_the_thing(&mut self, _s: i32) {}
    }

    impl<T> Thing for Cell<T> {}

    let mut x = Cell::new(1);
    let l = &x;

    x
        .do_the_thing({
            x.set(3);
            l.set(4);
            x.get() + l.get()
        })
    ;
}

fn main() {
    two_phase1();
    two_phase2();
    two_phase3(false);
    two_phase3(true);
    two_phase_raw();
    with_interior_mutability();
    two_phase_overlapping1();
    two_phase_overlapping2();
}
<|endoftext|>